From fcb929f4e6d934476c1930c48740e51918a4a3c2 Mon Sep 17 00:00:00 2001 From: Alessandro Jean Date: Thu, 10 Jun 2021 16:22:18 -0300 Subject: [PATCH] Add deeplinking to MangaPlus and Tsuki. (#7597) --- src/all/mangaplus/AndroidManifest.xml | 27 ++++++++++- src/all/mangaplus/build.gradle | 2 +- .../extension/all/mangaplus/MangaPlus.kt | 45 ++++++++++++++++--- .../all/mangaplus/MangaPlusUrlActivity.kt | 37 +++++++++++++++ src/pt/tsukimangas/AndroidManifest.xml | 27 ++++++++++- src/pt/tsukimangas/build.gradle | 2 +- .../extension/pt/tsukimangas/TsukiMangas.kt | 26 +++++++---- .../pt/tsukimangas/TsukiMangasUrlActivity.kt | 37 +++++++++++++++ 8 files changed, 185 insertions(+), 18 deletions(-) create mode 100644 src/all/mangaplus/src/eu/kanade/tachiyomi/extension/all/mangaplus/MangaPlusUrlActivity.kt create mode 100644 src/pt/tsukimangas/src/eu/kanade/tachiyomi/extension/pt/tsukimangas/TsukiMangasUrlActivity.kt diff --git a/src/all/mangaplus/AndroidManifest.xml b/src/all/mangaplus/AndroidManifest.xml index 30deb7f79..ac5eeea9f 100644 --- a/src/all/mangaplus/AndroidManifest.xml +++ b/src/all/mangaplus/AndroidManifest.xml @@ -1,2 +1,27 @@ - + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/all/mangaplus/build.gradle b/src/all/mangaplus/build.gradle index 983b0c894..7488b64ae 100644 --- a/src/all/mangaplus/build.gradle +++ b/src/all/mangaplus/build.gradle @@ -6,7 +6,7 @@ ext { extName = 'MANGA Plus by SHUEISHA' pkgNameSuffix = 'all.mangaplus' extClass = '.MangaPlusFactory' - extVersionCode = 19 + extVersionCode = 20 libVersion = '1.2' } diff --git a/src/all/mangaplus/src/eu/kanade/tachiyomi/extension/all/mangaplus/MangaPlus.kt b/src/all/mangaplus/src/eu/kanade/tachiyomi/extension/all/mangaplus/MangaPlus.kt index b121a2ea1..a37e2fec1 100644 --- a/src/all/mangaplus/src/eu/kanade/tachiyomi/extension/all/mangaplus/MangaPlus.kt +++ b/src/all/mangaplus/src/eu/kanade/tachiyomi/extension/all/mangaplus/MangaPlus.kt @@ -172,10 +172,21 @@ abstract class MangaPlus( override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable { return super.fetchSearchManga(page, query, filters) - .map { MangasPage(it.mangas.filter { m -> m.title.contains(query, true) }, it.hasNextPage) } + .map { + if (it.mangas.size == 1) { + return@map it + } + + val filteredResult = it.mangas.filter { m -> m.title.contains(query, true) } + MangasPage(filteredResult, it.hasNextPage) + } } override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { + if (query.startsWith(PREFIX_ID_SEARCH) && query.matches(ID_SEARCH_PATTERN)) { + return titleDetailsRequest(query.removePrefix(PREFIX_ID_SEARCH)) + } + val newHeaders = headersBuilder() .set("Referer", "$baseUrl/manga_list/all") .build() @@ -189,6 +200,25 @@ abstract class MangaPlus( if (result.success == null) throw Exception(result.error!!.langPopup.body) + if (result.success.titleDetailView != null) { + val mangaPlusTitle = result.success.titleDetailView.title.let { + val correctLanguage = titlesToFix[it.titleId] + if (correctLanguage != null) it.copy(language = correctLanguage) else it + } + + if (mangaPlusTitle.language == langCode) { + val manga = SManga.create().apply { + title = mangaPlusTitle.name + thumbnail_url = mangaPlusTitle.portraitImageUrl + url = "#/titles/${mangaPlusTitle.titleId}" + } + + return MangasPage(listOf(manga), hasNextPage = false) + } + + return MangasPage(emptyList(), hasNextPage = false) + } + titleList = result.success.allTitlesView!!.titles .fixWrongLanguages() .filter { it.language == langCode } @@ -201,11 +231,11 @@ abstract class MangaPlus( } } - return MangasPage(mangas, false) + return MangasPage(mangas, hasNextPage = false) } - private fun titleDetailsRequest(manga: SManga): Request { - val titleId = manga.url.substringAfterLast("/") + private fun titleDetailsRequest(mangaUrl: String): Request { + val titleId = mangaUrl.substringAfterLast("/") val newHeaders = headersBuilder() .set("Referer", "$baseUrl/titles/$titleId") @@ -216,7 +246,7 @@ abstract class MangaPlus( // Workaround to allow "Open in browser" use the real URL. override fun fetchMangaDetails(manga: SManga): Observable { - return client.newCall(titleDetailsRequest(manga)) + return client.newCall(titleDetailsRequest(manga.url)) .asObservableSuccess() .map { response -> mangaDetailsParse(response).apply { initialized = true } @@ -247,7 +277,7 @@ abstract class MangaPlus( } } - override fun chapterListRequest(manga: SManga): Request = titleDetailsRequest(manga) + override fun chapterListRequest(manga: SManga): Request = titleDetailsRequest(manga.url) override fun chapterListParse(response: Response): List { val result = response.asProto() @@ -474,5 +504,8 @@ abstract class MangaPlus( private val COMPLETE_REGEX = "completado|complete".toRegex() private const val TITLE_THUMBNAIL_PATH = "title_thumbnail_portrait_list" + + const val PREFIX_ID_SEARCH = "id:" + private val ID_SEARCH_PATTERN = "^id:(\\d+)$".toRegex() } } diff --git a/src/all/mangaplus/src/eu/kanade/tachiyomi/extension/all/mangaplus/MangaPlusUrlActivity.kt b/src/all/mangaplus/src/eu/kanade/tachiyomi/extension/all/mangaplus/MangaPlusUrlActivity.kt new file mode 100644 index 000000000..85bac6877 --- /dev/null +++ b/src/all/mangaplus/src/eu/kanade/tachiyomi/extension/all/mangaplus/MangaPlusUrlActivity.kt @@ -0,0 +1,37 @@ +package eu.kanade.tachiyomi.extension.all.mangaplus + +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 MangaPlusUrlActivity : Activity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + val pathSegments = intent?.data?.pathSegments + if (pathSegments != null && pathSegments.size > 1) { + val titleId = pathSegments[1] + + val mainIntent = Intent().apply { + action = "eu.kanade.tachiyomi.SEARCH" + putExtra("query", MangaPlus.PREFIX_ID_SEARCH + titleId) + putExtra("filter", packageName) + } + + try { + startActivity(mainIntent) + } catch (e: ActivityNotFoundException) { + Log.e("MangaPlusUrlActivity", e.toString()) + } + } else { + Log.e("MangaPlusUrlActivity", "Could not parse URI from intent $intent") + } + + finish() + exitProcess(0) + } +} diff --git a/src/pt/tsukimangas/AndroidManifest.xml b/src/pt/tsukimangas/AndroidManifest.xml index 30deb7f79..a7be94fb4 100644 --- a/src/pt/tsukimangas/AndroidManifest.xml +++ b/src/pt/tsukimangas/AndroidManifest.xml @@ -1,2 +1,27 @@ - + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/pt/tsukimangas/build.gradle b/src/pt/tsukimangas/build.gradle index a1cdd99fd..a95e09fd0 100644 --- a/src/pt/tsukimangas/build.gradle +++ b/src/pt/tsukimangas/build.gradle @@ -6,7 +6,7 @@ ext { extName = 'Tsuki Mangás' pkgNameSuffix = 'pt.tsukimangas' extClass = '.TsukiMangas' - extVersionCode = 18 + extVersionCode = 19 libVersion = '1.2' containsNsfw = true } diff --git a/src/pt/tsukimangas/src/eu/kanade/tachiyomi/extension/pt/tsukimangas/TsukiMangas.kt b/src/pt/tsukimangas/src/eu/kanade/tachiyomi/extension/pt/tsukimangas/TsukiMangas.kt index d141a1c48..7e7fcdf1c 100644 --- a/src/pt/tsukimangas/src/eu/kanade/tachiyomi/extension/pt/tsukimangas/TsukiMangas.kt +++ b/src/pt/tsukimangas/src/eu/kanade/tachiyomi/extension/pt/tsukimangas/TsukiMangas.kt @@ -98,6 +98,10 @@ class TsukiMangas : HttpSource() { } override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { + if (query.startsWith(PREFIX_ID_SEARCH) && query.matches(ID_SEARCH_PATTERN)) { + return mangaDetailsApiRequest(query.removePrefix(PREFIX_ID_SEARCH)) + } + val newHeaders = headersBuilder() .set("Referer", "$baseUrl/lista-completa") .build() @@ -156,6 +160,12 @@ class TsukiMangas : HttpSource() { } override fun searchMangaParse(response: Response): MangasPage { + if (response.request.url.toString().contains("/mangas/")) { + val manga = mangaDetailsParse(response) + + return MangasPage(listOf(manga), hasNextPage = false) + } + val result = json.decodeFromString(response.body!!.string()) val searchResults = result.data.map(::searchMangaItemParse) @@ -175,21 +185,17 @@ class TsukiMangas : HttpSource() { // Workaround to allow "Open in browser" use the real URL. override fun fetchMangaDetails(manga: SManga): Observable { - return client.newCall(mangaDetailsApiRequest(manga)) + return client.newCall(mangaDetailsApiRequest(manga.url)) .asObservableSuccess() .map { response -> mangaDetailsParse(response).apply { initialized = true } } } - private fun mangaDetailsApiRequest(manga: SManga): Request { - val newHeaders = headersBuilder() - .set("Referer", baseUrl + manga.url) - .build() + private fun mangaDetailsApiRequest(mangaUrl: String): Request { + val mangaId = mangaUrl.substringAfter("obra/").substringBefore("/") - val mangaId = manga.url.substringAfter("obra/").substringBefore("/") - - return GET("$baseUrl/api/v2/mangas/$mangaId", newHeaders) + return GET("$baseUrl/api/v2/mangas/$mangaId", headers) } override fun mangaDetailsRequest(manga: SManga): Request { @@ -211,6 +217,7 @@ class TsukiMangas : HttpSource() { author = mangaDto.author.orEmpty() artist = mangaDto.artist.orEmpty() genre = mangaDto.genres.joinToString { it.genre } + url = "/obra/${mangaDto.id}/${mangaDto.url}" } override fun chapterListRequest(manga: SManga): Request { @@ -460,5 +467,8 @@ class TsukiMangas : HttpSource() { private const val EMPTY_COVER = "/ext/errorcapa.jpg" private val DATE_FORMATTER by lazy { SimpleDateFormat("yyyy-MM-dd", Locale.ENGLISH) } + + const val PREFIX_ID_SEARCH = "id:" + private val ID_SEARCH_PATTERN = "^id:(\\d+)$".toRegex() } } diff --git a/src/pt/tsukimangas/src/eu/kanade/tachiyomi/extension/pt/tsukimangas/TsukiMangasUrlActivity.kt b/src/pt/tsukimangas/src/eu/kanade/tachiyomi/extension/pt/tsukimangas/TsukiMangasUrlActivity.kt new file mode 100644 index 000000000..247742f62 --- /dev/null +++ b/src/pt/tsukimangas/src/eu/kanade/tachiyomi/extension/pt/tsukimangas/TsukiMangasUrlActivity.kt @@ -0,0 +1,37 @@ +package eu.kanade.tachiyomi.extension.pt.tsukimangas + +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 TsukiMangasUrlActivity : Activity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + val pathSegments = intent?.data?.pathSegments + if (pathSegments != null && pathSegments.size > 1) { + val titleId = pathSegments[1] + + val mainIntent = Intent().apply { + action = "eu.kanade.tachiyomi.SEARCH" + putExtra("query", TsukiMangas.PREFIX_ID_SEARCH + titleId) + putExtra("filter", packageName) + } + + try { + startActivity(mainIntent) + } catch (e: ActivityNotFoundException) { + Log.e("TsukiMangasUrlActivity", e.toString()) + } + } else { + Log.e("TsukiMangasUrlActivity", "Could not parse URI from intent $intent") + } + + finish() + exitProcess(0) + } +}