Add deeplinking to MangaPlus and Tsuki. (#7597)
This commit is contained in:
parent
6fa8cfe804
commit
fcb929f4e6
|
@ -1,2 +1,27 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest package="eu.kanade.tachiyomi.extension" />
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="eu.kanade.tachiyomi.extension">
|
||||
|
||||
<application>
|
||||
<activity
|
||||
android:name=".all.mangaplus.MangaPlusUrlActivity"
|
||||
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="mangaplus.shueisha.co.jp"
|
||||
android:pathPattern="/titles/..*"
|
||||
android:scheme="https" />
|
||||
<data
|
||||
android:host="www.mangaplus.shueisha.co.jp"
|
||||
android:pathPattern="/titles/..*"
|
||||
android:scheme="https" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
</manifest>
|
|
@ -6,7 +6,7 @@ ext {
|
|||
extName = 'MANGA Plus by SHUEISHA'
|
||||
pkgNameSuffix = 'all.mangaplus'
|
||||
extClass = '.MangaPlusFactory'
|
||||
extVersionCode = 19
|
||||
extVersionCode = 20
|
||||
libVersion = '1.2'
|
||||
}
|
||||
|
||||
|
|
|
@ -172,10 +172,21 @@ abstract class MangaPlus(
|
|||
|
||||
override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable<MangasPage> {
|
||||
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<SManga> {
|
||||
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<SChapter> {
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -1,2 +1,27 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest package="eu.kanade.tachiyomi.extension" />
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="eu.kanade.tachiyomi.extension">
|
||||
|
||||
<application>
|
||||
<activity
|
||||
android:name=".pt.tsukimangas.TsukiMangasUrlActivity"
|
||||
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="tsukimangas.com"
|
||||
android:pathPattern="/obra/..*/..*"
|
||||
android:scheme="https" />
|
||||
<data
|
||||
android:host="www.tsukimangas.com"
|
||||
android:pathPattern="/obra/..*/..*"
|
||||
android:scheme="https" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
</manifest>
|
|
@ -6,7 +6,7 @@ ext {
|
|||
extName = 'Tsuki Mangás'
|
||||
pkgNameSuffix = 'pt.tsukimangas'
|
||||
extClass = '.TsukiMangas'
|
||||
extVersionCode = 18
|
||||
extVersionCode = 19
|
||||
libVersion = '1.2'
|
||||
containsNsfw = true
|
||||
}
|
||||
|
|
|
@ -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<TsukiPaginatedDto>(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<SManga> {
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue