From 9e19be80bbb23ff2fcc6e3ca7a12e41d941e898b Mon Sep 17 00:00:00 2001 From: h-hyuuga <83582211+h-hyuuga@users.noreply.github.com> Date: Tue, 7 Sep 2021 19:47:07 -0400 Subject: [PATCH] WPMangaStream: Add deeplinking (#9005) --- .../wpmangastream/default/AndroidManifest.xml | 32 ++++++++++ .../multisrc/wpmangastream/WPMangaStream.kt | 64 ++++++++++++++++++- .../wpmangastream/WPMangaStreamGenerator.kt | 2 +- .../wpmangastream/WPMangaStreamUrlActivity.kt | 35 ++++++++++ 4 files changed, 131 insertions(+), 2 deletions(-) create mode 100644 multisrc/overrides/wpmangastream/default/AndroidManifest.xml create mode 100644 multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/wpmangastream/WPMangaStreamUrlActivity.kt diff --git a/multisrc/overrides/wpmangastream/default/AndroidManifest.xml b/multisrc/overrides/wpmangastream/default/AndroidManifest.xml new file mode 100644 index 000000000..3642d357f --- /dev/null +++ b/multisrc/overrides/wpmangastream/default/AndroidManifest.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/wpmangastream/WPMangaStream.kt b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/wpmangastream/WPMangaStream.kt index 4af6e3051..07df47824 100644 --- a/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/wpmangastream/WPMangaStream.kt +++ b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/wpmangastream/WPMangaStream.kt @@ -4,9 +4,11 @@ import android.app.Application import android.content.SharedPreferences import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.POST +import eu.kanade.tachiyomi.network.asObservableSuccess import eu.kanade.tachiyomi.source.ConfigurableSource import eu.kanade.tachiyomi.source.model.Filter 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.SChapter import eu.kanade.tachiyomi.source.model.SManga @@ -17,6 +19,7 @@ import kotlinx.serialization.json.jsonArray import kotlinx.serialization.json.jsonPrimitive import okhttp3.FormBody import okhttp3.Headers +import okhttp3.HttpUrl import okhttp3.HttpUrl.Companion.toHttpUrl import okhttp3.HttpUrl.Companion.toHttpUrlOrNull import okhttp3.OkHttpClient @@ -25,6 +28,8 @@ import okhttp3.Response import org.jsoup.nodes.Document import org.jsoup.nodes.Element import org.jsoup.select.Elements +import rx.Observable +import rx.Single import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get import uy.kohesive.injekt.injectLazy @@ -82,6 +87,60 @@ abstract class WPMangaStream( 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 { + 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 { + 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 { var url = "$baseUrl/manga/".toHttpUrlOrNull()!!.newBuilder() url.addQueryParameter("title", query) @@ -218,7 +277,8 @@ abstract class WPMangaStream( val chapter = SChapter.create() chapter.setUrlWithoutDomain(urlElement.attr("href")) 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 } @@ -524,6 +584,8 @@ abstract class WPMangaStream( private const val SHOW_THUMBNAIL_PREF_Title = "Default thumbnail quality" 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 CHAPTER_PAGE_ID_REGEX = "chapter_id\\s*=\\s*(\\d+);?".toRegex() } diff --git a/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/wpmangastream/WPMangaStreamGenerator.kt b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/wpmangastream/WPMangaStreamGenerator.kt index 646ef6579..a796f4afe 100644 --- a/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/wpmangastream/WPMangaStreamGenerator.kt +++ b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/wpmangastream/WPMangaStreamGenerator.kt @@ -10,7 +10,7 @@ class WPMangaStreamGenerator : ThemeSourceGenerator { override val themeClass = "WPMangaStream" - override val baseVersionCode: Int = 11 + override val baseVersionCode: Int = 12 override val sources = listOf( MultiLang("Asura Scans", "https://www.asurascans.com", listOf("en", "tr"), className = "AsuraScansFactory", pkgName = "asurascans", overrideVersionCode = 6), diff --git a/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/wpmangastream/WPMangaStreamUrlActivity.kt b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/wpmangastream/WPMangaStreamUrlActivity.kt new file mode 100644 index 000000000..2e145cf09 --- /dev/null +++ b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/wpmangastream/WPMangaStreamUrlActivity.kt @@ -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) + } +}