WPMangaStream: Add deeplinking (#9005)

This commit is contained in:
h-hyuuga 2021-09-07 19:47:07 -04:00 committed by GitHub
parent be4245d291
commit 9e19be80bb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 131 additions and 2 deletions

View File

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="eu.kanade.tachiyomi.extension">
<application>
<activity
android:name="eu.kanade.tachiyomi.multisrc.wpmangastream.WPMangaStreamUrlActivity"
android:excludeFromRecents="true"
android:theme="@android:style/Theme.NoDisplay">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:host="${SOURCEHOST}"
android:pathPattern="/.*/..*"
android:scheme="${SOURCESCHEME}" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:host="${SOURCEHOST}"
android:pathPattern="/..*"
android:scheme="${SOURCESCHEME}" />
</intent-filter>
</activity>
</application>
</manifest>

View File

@ -4,9 +4,11 @@ import android.app.Application
import android.content.SharedPreferences import android.content.SharedPreferences
import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.network.POST import eu.kanade.tachiyomi.network.POST
import eu.kanade.tachiyomi.network.asObservableSuccess
import eu.kanade.tachiyomi.source.ConfigurableSource import eu.kanade.tachiyomi.source.ConfigurableSource
import eu.kanade.tachiyomi.source.model.Filter import eu.kanade.tachiyomi.source.model.Filter
import eu.kanade.tachiyomi.source.model.FilterList import eu.kanade.tachiyomi.source.model.FilterList
import eu.kanade.tachiyomi.source.model.MangasPage
import eu.kanade.tachiyomi.source.model.Page import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
@ -17,6 +19,7 @@ import kotlinx.serialization.json.jsonArray
import kotlinx.serialization.json.jsonPrimitive import kotlinx.serialization.json.jsonPrimitive
import okhttp3.FormBody import okhttp3.FormBody
import okhttp3.Headers import okhttp3.Headers
import okhttp3.HttpUrl
import okhttp3.HttpUrl.Companion.toHttpUrl import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
@ -25,6 +28,8 @@ import okhttp3.Response
import org.jsoup.nodes.Document import org.jsoup.nodes.Document
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import org.jsoup.select.Elements import org.jsoup.select.Elements
import rx.Observable
import rx.Single
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
@ -82,6 +87,60 @@ abstract class WPMangaStream(
return GET("$baseUrl/manga/?page=$page&order=update", headers) return GET("$baseUrl/manga/?page=$page&order=update", headers)
} }
/**
* Given some string which represents an http url, returns the URI path to the corresponding series
* if the original pointed to either a series or a chapter
*
* @param s: String - url
*
* @returns URI path or null
*/
protected open fun mangaPathFromUrl(s: String): Single<String?> {
val baseMangaUrl = baseUrl.toHttpUrlOrNull()!!
// Would be dope if wpmangastream had a mangaUrlDirectory like wpmangareader
val mangaDirectories = listOf("manga", "comics", "komik")
return s.toHttpUrlOrNull()?.let { url ->
fun pathLengthIs(url: HttpUrl, n: Int, strict: Boolean = false) = url.pathSegments.size == n && url.pathSegments[n - 1].isNotEmpty() || (!strict && url.pathSegments.size == n + 1 && url.pathSegments[n].isEmpty())
val potentiallyChapterUrl = pathLengthIs(url, 1)
val isMangaUrl = listOf(
baseMangaUrl.topPrivateDomain() == url.topPrivateDomain(),
pathLengthIs(url, 2),
url.pathSegments[0] in mangaDirectories
).all { it }
if (isMangaUrl)
Single.just(url.encodedPath)
else if (potentiallyChapterUrl)
client.newCall(GET(s, headers)).asObservableSuccess().map {
val links = it.asJsoup().select("a[itemprop=item]")
if (links.size == 3) // near the top of page: home > manga > current chapter
links[1].attr("href").toHttpUrlOrNull()?.encodedPath
else
null
}.toSingle()
else
Single.just(null)
} ?: Single.just(null)
}
override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable<MangasPage> {
if (!query.startsWith(URL_SEARCH_PREFIX))
return super.fetchSearchManga(page, query, filters)
return mangaPathFromUrl(query.substringAfter(URL_SEARCH_PREFIX))
.toObservable()
.concatMap { path ->
if (path == null)
Observable.just(MangasPage(emptyList(), false))
else
fetchMangaDetails(SManga.create().apply { this.url = path })
.map {
it.url = path // isn't set in returned manga
MangasPage(listOf(it), false)
}
}
}
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
var url = "$baseUrl/manga/".toHttpUrlOrNull()!!.newBuilder() var url = "$baseUrl/manga/".toHttpUrlOrNull()!!.newBuilder()
url.addQueryParameter("title", query) url.addQueryParameter("title", query)
@ -218,7 +277,8 @@ abstract class WPMangaStream(
val chapter = SChapter.create() val chapter = SChapter.create()
chapter.setUrlWithoutDomain(urlElement.attr("href")) chapter.setUrlWithoutDomain(urlElement.attr("href"))
chapter.name = if (urlElement.select("span.chapternum").isNotEmpty()) urlElement.select("span.chapternum").text() else urlElement.text() chapter.name = if (urlElement.select("span.chapternum").isNotEmpty()) urlElement.select("span.chapternum").text() else urlElement.text()
chapter.date_upload = element.select("span.rightoff, time, span.chapterdate").firstOrNull()?.text()?.let { parseChapterDate(it) } ?: 0 chapter.date_upload = element.select("span.rightoff, time, span.chapterdate").firstOrNull()?.text()?.let { parseChapterDate(it) }
?: 0
return chapter return chapter
} }
@ -524,6 +584,8 @@ abstract class WPMangaStream(
private const val SHOW_THUMBNAIL_PREF_Title = "Default thumbnail quality" private const val SHOW_THUMBNAIL_PREF_Title = "Default thumbnail quality"
private const val SHOW_THUMBNAIL_PREF = "showThumbnailDefault" private const val SHOW_THUMBNAIL_PREF = "showThumbnailDefault"
const val URL_SEARCH_PREFIX = "url:"
private val MANGA_PAGE_ID_REGEX = "post_id\\s*:\\s*(\\d+)\\}".toRegex() private val MANGA_PAGE_ID_REGEX = "post_id\\s*:\\s*(\\d+)\\}".toRegex()
private val CHAPTER_PAGE_ID_REGEX = "chapter_id\\s*=\\s*(\\d+);?".toRegex() private val CHAPTER_PAGE_ID_REGEX = "chapter_id\\s*=\\s*(\\d+);?".toRegex()
} }

View File

@ -10,7 +10,7 @@ class WPMangaStreamGenerator : ThemeSourceGenerator {
override val themeClass = "WPMangaStream" override val themeClass = "WPMangaStream"
override val baseVersionCode: Int = 11 override val baseVersionCode: Int = 12
override val sources = listOf( override val sources = listOf(
MultiLang("Asura Scans", "https://www.asurascans.com", listOf("en", "tr"), className = "AsuraScansFactory", pkgName = "asurascans", overrideVersionCode = 6), MultiLang("Asura Scans", "https://www.asurascans.com", listOf("en", "tr"), className = "AsuraScansFactory", pkgName = "asurascans", overrideVersionCode = 6),

View File

@ -0,0 +1,35 @@
package eu.kanade.tachiyomi.multisrc.wpmangastream
import android.app.Activity
import android.content.ActivityNotFoundException
import android.content.Intent
import android.os.Bundle
import android.util.Log
import kotlin.system.exitProcess
class WPMangaStreamUrlActivity : Activity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val pathSegments = intent?.data?.pathSegments
if (pathSegments != null && pathSegments.size >= 1) {
val mainIntent = Intent().apply {
action = "eu.kanade.tachiyomi.SEARCH"
putExtra("query", "${WPMangaStream.URL_SEARCH_PREFIX}${intent?.data?.toString()}")
putExtra("filter", packageName)
}
try {
startActivity(mainIntent)
} catch (e: ActivityNotFoundException) {
Log.e("WPMangaStreamUrl", e.toString())
}
} else {
Log.e("WPMangaStreamUrl", "could not parse uri from intent $intent")
}
finish()
exitProcess(0)
}
}