Mangadex: Add support for MDLists url intent (#11024)
* Update build.gradle * Added list support * Add error message for empty list * Update AndroidManifest.xml
This commit is contained in:
parent
2998330d4e
commit
2b5359ca26
|
@ -15,25 +15,15 @@
|
||||||
<category android:name="android.intent.category.BROWSABLE" />
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
|
|
||||||
<data android:host="mangadex.org" />
|
<data android:host="mangadex.org" />
|
||||||
|
<data android:scheme="https" />
|
||||||
|
|
||||||
<data
|
<data android:pathPattern="/title/..*" />
|
||||||
android:pathPattern="/title/..*"
|
<data android:pathPattern="/manga/..*" />
|
||||||
android:scheme="https" />
|
<data android:pathPattern="/chapter/..*" />
|
||||||
<data
|
<data android:pathPattern="/group/..*" />
|
||||||
android:pathPattern="/manga/..*"
|
<data android:pathPattern="/author/..*" />
|
||||||
android:scheme="https" />
|
<data android:pathPattern="/user/..*" />
|
||||||
<data
|
<data android:pathPattern="/list/..*" />
|
||||||
android:pathPattern="/chapter/..*"
|
|
||||||
android:scheme="https" />
|
|
||||||
<data
|
|
||||||
android:pathPattern="/group/..*"
|
|
||||||
android:scheme="https" />
|
|
||||||
<data
|
|
||||||
android:pathPattern="/author/..*"
|
|
||||||
android:scheme="https" />
|
|
||||||
<data
|
|
||||||
android:pathPattern="/user/..*"
|
|
||||||
android:scheme="https" />
|
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
</application>
|
</application>
|
||||||
|
|
|
@ -6,7 +6,7 @@ ext {
|
||||||
extName = 'MangaDex'
|
extName = 'MangaDex'
|
||||||
pkgNameSuffix = 'all.mangadex'
|
pkgNameSuffix = 'all.mangadex'
|
||||||
extClass = '.MangaDexFactory'
|
extClass = '.MangaDexFactory'
|
||||||
extVersionCode = 156
|
extVersionCode = 157
|
||||||
isNsfw = true
|
isNsfw = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,7 @@ object MDConstants {
|
||||||
const val apiUrl = "https://api.mangadex.org"
|
const val apiUrl = "https://api.mangadex.org"
|
||||||
const val apiMangaUrl = "$apiUrl/manga"
|
const val apiMangaUrl = "$apiUrl/manga"
|
||||||
const val apiChapterUrl = "$apiUrl/chapter"
|
const val apiChapterUrl = "$apiUrl/chapter"
|
||||||
|
const val apiListUrl = "$apiUrl/list"
|
||||||
const val atHomePostUrl = "https://api.mangadex.network/report"
|
const val atHomePostUrl = "https://api.mangadex.network/report"
|
||||||
val whitespaceRegex = "\\s".toRegex()
|
val whitespaceRegex = "\\s".toRegex()
|
||||||
|
|
||||||
|
@ -37,6 +38,7 @@ object MDConstants {
|
||||||
const val prefixGrpSearch = "grp:"
|
const val prefixGrpSearch = "grp:"
|
||||||
const val prefixAuthSearch = "author:"
|
const val prefixAuthSearch = "author:"
|
||||||
const val prefixUsrSearch = "usr:"
|
const val prefixUsrSearch = "usr:"
|
||||||
|
const val prefixListSearch = "list:"
|
||||||
|
|
||||||
const val coverQualityPref = "thumbnailQuality"
|
const val coverQualityPref = "thumbnailQuality"
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@ import eu.kanade.tachiyomi.extension.all.mangadex.dto.AggregateDto
|
||||||
import eu.kanade.tachiyomi.extension.all.mangadex.dto.AtHomeDto
|
import eu.kanade.tachiyomi.extension.all.mangadex.dto.AtHomeDto
|
||||||
import eu.kanade.tachiyomi.extension.all.mangadex.dto.ChapterDto
|
import eu.kanade.tachiyomi.extension.all.mangadex.dto.ChapterDto
|
||||||
import eu.kanade.tachiyomi.extension.all.mangadex.dto.ChapterListDto
|
import eu.kanade.tachiyomi.extension.all.mangadex.dto.ChapterListDto
|
||||||
|
import eu.kanade.tachiyomi.extension.all.mangadex.dto.ListDto
|
||||||
import eu.kanade.tachiyomi.extension.all.mangadex.dto.MangaDto
|
import eu.kanade.tachiyomi.extension.all.mangadex.dto.MangaDto
|
||||||
import eu.kanade.tachiyomi.extension.all.mangadex.dto.MangaListDto
|
import eu.kanade.tachiyomi.extension.all.mangadex.dto.MangaListDto
|
||||||
import eu.kanade.tachiyomi.network.GET
|
import eu.kanade.tachiyomi.network.GET
|
||||||
|
@ -191,18 +192,23 @@ abstract class MangaDex(override val lang: String, val dexLang: String) :
|
||||||
// SEARCH section
|
// SEARCH section
|
||||||
|
|
||||||
override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable<MangasPage> {
|
override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable<MangasPage> {
|
||||||
if (query.startsWith(MDConstants.prefixChSearch)) {
|
when {
|
||||||
|
query.startsWith(MDConstants.prefixChSearch) ->
|
||||||
return getMangaIdFromChapterId(query.removePrefix(MDConstants.prefixChSearch)).flatMap { manga_id ->
|
return getMangaIdFromChapterId(query.removePrefix(MDConstants.prefixChSearch)).flatMap { manga_id ->
|
||||||
super.fetchSearchManga(page, MDConstants.prefixIdSearch + manga_id, filters)
|
super.fetchSearchManga(page, MDConstants.prefixIdSearch + manga_id, filters)
|
||||||
}
|
}
|
||||||
}
|
query.startsWith(MDConstants.prefixUsrSearch) ->
|
||||||
if (query.startsWith(MDConstants.prefixUsrSearch)) {
|
|
||||||
return client.newCall(searchMangaUploaderRequest(page, query.removePrefix(MDConstants.prefixUsrSearch)))
|
return client.newCall(searchMangaUploaderRequest(page, query.removePrefix(MDConstants.prefixUsrSearch)))
|
||||||
.asObservableSuccess()
|
.asObservableSuccess()
|
||||||
.map { latestUpdatesParse(it) }
|
.map { latestUpdatesParse(it) }
|
||||||
}
|
query.startsWith(MDConstants.prefixListSearch) ->
|
||||||
|
return client.newCall(GET(MDConstants.apiListUrl + "/" + query.removePrefix(MDConstants.prefixListSearch), headers, CacheControl.FORCE_NETWORK))
|
||||||
|
.asObservableSuccess()
|
||||||
|
.map { searchMangaListRequest(it, page) }
|
||||||
|
else ->
|
||||||
return super.fetchSearchManga(page, query, filters)
|
return super.fetchSearchManga(page, query, filters)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun getMangaIdFromChapterId(id: String): Observable<String> {
|
private fun getMangaIdFromChapterId(id: String): Observable<String> {
|
||||||
return client.newCall(GET("${MDConstants.apiChapterUrl}/$id", headers))
|
return client.newCall(GET("${MDConstants.apiChapterUrl}/$id", headers))
|
||||||
|
@ -277,6 +283,54 @@ abstract class MangaDex(override val lang: String, val dexLang: String) :
|
||||||
|
|
||||||
override fun searchMangaParse(response: Response): MangasPage = popularMangaParse(response)
|
override fun searchMangaParse(response: Response): MangasPage = popularMangaParse(response)
|
||||||
|
|
||||||
|
private fun searchMangaListRequest(response: Response, page: Int): MangasPage {
|
||||||
|
if (response.isSuccessful.not()) {
|
||||||
|
throw Exception("HTTP ${response.code}")
|
||||||
|
}
|
||||||
|
|
||||||
|
val listDto = helper.json.decodeFromString<ListDto>(response.body!!.string())
|
||||||
|
val listDtoFiltered = listDto.data.relationships.filter { it.type != "Manga" }
|
||||||
|
val amount = listDtoFiltered.count()
|
||||||
|
if (amount < 1){
|
||||||
|
throw Exception("No Manga in List")
|
||||||
|
}
|
||||||
|
val minIndex = (page - 1) * MDConstants.mangaLimit
|
||||||
|
|
||||||
|
val url = MDConstants.apiMangaUrl.toHttpUrl().newBuilder().apply {
|
||||||
|
addQueryParameter("limit", MDConstants.mangaLimit.toString())
|
||||||
|
addQueryParameter("offset", "0")
|
||||||
|
addQueryParameter("includes[]", MDConstants.coverArt)
|
||||||
|
}
|
||||||
|
listDtoFiltered.forEachIndexed() { index, relationshipDto ->
|
||||||
|
if (index >= minIndex && index < (minIndex + MDConstants.mangaLimit)) {
|
||||||
|
url.addQueryParameter("ids[]", relationshipDto.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val request = client.newCall(GET(url.build().toString(), headers, CacheControl.FORCE_NETWORK))
|
||||||
|
val mangaList = searchMangaListParse(request.execute())
|
||||||
|
return MangasPage(mangaList, amount.toFloat() / MDConstants.mangaLimit - (page.toFloat() - 1) > 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun searchMangaListParse(response: Response): List<SManga> {
|
||||||
|
if (response.isSuccessful.not()) {
|
||||||
|
throw Exception("HTTP ${response.code}")
|
||||||
|
}
|
||||||
|
|
||||||
|
val mangaListDto = helper.json.decodeFromString<MangaListDto>(response.body!!.string())
|
||||||
|
|
||||||
|
val coverSuffix = preferences.getString(MDConstants.getCoverQualityPreferenceKey(dexLang), "")
|
||||||
|
|
||||||
|
val mangaList = mangaListDto.data.map { mangaDataDto ->
|
||||||
|
val fileName = mangaDataDto.relationships.firstOrNull { relationshipDto ->
|
||||||
|
relationshipDto.type.equals(MDConstants.coverArt, true)
|
||||||
|
}?.attributes?.fileName
|
||||||
|
helper.createBasicManga(mangaDataDto, fileName, coverSuffix, dexLang)
|
||||||
|
}
|
||||||
|
|
||||||
|
return mangaList
|
||||||
|
}
|
||||||
|
|
||||||
private fun searchMangaUploaderRequest(page: Int, uploader: String): Request {
|
private fun searchMangaUploaderRequest(page: Int, uploader: String): Request {
|
||||||
val url = MDConstants.apiChapterUrl.toHttpUrlOrNull()!!.newBuilder().apply {
|
val url = MDConstants.apiChapterUrl.toHttpUrlOrNull()!!.newBuilder().apply {
|
||||||
addQueryParameter("offset", helper.getLatestChapterOffset(page))
|
addQueryParameter("offset", helper.getLatestChapterOffset(page))
|
||||||
|
|
|
@ -31,6 +31,7 @@ class MangadexUrlActivity : Activity() {
|
||||||
equals("group") -> putExtra("query", "${MDConstants.prefixGrpSearch}$titleid")
|
equals("group") -> putExtra("query", "${MDConstants.prefixGrpSearch}$titleid")
|
||||||
equals("user") -> putExtra("query", "${MDConstants.prefixUsrSearch}$titleid")
|
equals("user") -> putExtra("query", "${MDConstants.prefixUsrSearch}$titleid")
|
||||||
equals("author") -> putExtra("query", "${MDConstants.prefixAuthSearch}$titleid")
|
equals("author") -> putExtra("query", "${MDConstants.prefixAuthSearch}$titleid")
|
||||||
|
equals("list") -> putExtra("query", "${MDConstants.prefixListSearch}$titleid")
|
||||||
else -> putExtra("query", "${MDConstants.prefixIdSearch}$titleid")
|
else -> putExtra("query", "${MDConstants.prefixIdSearch}$titleid")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
package eu.kanade.tachiyomi.extension.all.mangadex.dto
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class ListDto(
|
||||||
|
val result: String,
|
||||||
|
val response: String,
|
||||||
|
val data: ListDataDto,
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class ListDataDto(
|
||||||
|
val id: String,
|
||||||
|
val type: String,
|
||||||
|
val attributes: ListAttributesDto,
|
||||||
|
val relationships: List<RelationshipDto>,
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class ListAttributesDto(
|
||||||
|
val name: String,
|
||||||
|
val visibility: String,
|
||||||
|
val version: Int,
|
||||||
|
)
|
Loading…
Reference in New Issue