Mangadex fixes
This commit is contained in:
parent
bc871cd2ee
commit
33a590d895
@ -59,6 +59,8 @@ class MdList(private val context: Context, id: Int) : TrackService(id) {
|
||||
if (remoteTrack.status != followStatus.int) {
|
||||
if (mdex.updateFollowStatus(MdUtil.getMangaId(track.tracking_url), followStatus)) {
|
||||
remoteTrack.status = followStatus.int
|
||||
} else {
|
||||
track.status = remoteTrack.status
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -84,6 +84,25 @@ class MangaDex(delegate: HttpSource, val context: Context) :
|
||||
|
||||
private fun useLowQualityThumbnail() = false // sourcePreferences.getInt(SHOW_THUMBNAIL_PREF, 0) == LOW_QUALITY
|
||||
|
||||
private val apiMangaParser by lazy {
|
||||
ApiMangaParser(baseHttpClient, mdLang.lang)
|
||||
}
|
||||
private val apiChapterParser by lazy {
|
||||
ApiChapterParser()
|
||||
}
|
||||
private val followsHandler by lazy {
|
||||
FollowsHandler(baseHttpClient, headers, preferences, mdLang.lang, mdList)
|
||||
}
|
||||
private val mangaHandler by lazy {
|
||||
MangaHandler(baseHttpClient, headers, mdLang.lang, apiMangaParser, followsHandler)
|
||||
}
|
||||
private val similarHandler by lazy {
|
||||
SimilarHandler(baseHttpClient, mdLang.lang)
|
||||
}
|
||||
private val mangaPlusHandler by lazy {
|
||||
MangaPlusHandler(network.client)
|
||||
}
|
||||
|
||||
/*override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable<MangasPage> =
|
||||
urlImportFetchSearchManga(context, query) {
|
||||
importIdToMdId(query) {
|
||||
@ -114,28 +133,28 @@ class MangaDex(delegate: HttpSource, val context: Context) :
|
||||
}*/
|
||||
|
||||
override fun fetchMangaDetails(manga: SManga): Observable<SManga> {
|
||||
return MangaHandler(baseHttpClient, headers, mdLang.lang, preferences.mangaDexForceLatestCovers().get()).fetchMangaDetailsObservable(manga, id)
|
||||
return mangaHandler.fetchMangaDetailsObservable(manga, id, preferences.mangaDexForceLatestCovers().get())
|
||||
}
|
||||
|
||||
override suspend fun getMangaDetails(manga: MangaInfo): MangaInfo {
|
||||
return MangaHandler(baseHttpClient, headers, mdLang.lang, preferences.mangaDexForceLatestCovers().get()).getMangaDetails(manga, id)
|
||||
return mangaHandler.getMangaDetails(manga, id, preferences.mangaDexForceLatestCovers().get())
|
||||
}
|
||||
|
||||
override fun fetchChapterList(manga: SManga): Observable<List<SChapter>> {
|
||||
return MangaHandler(baseHttpClient, headers, mdLang.lang, preferences.mangaDexForceLatestCovers().get()).fetchChapterListObservable(manga)
|
||||
return mangaHandler.fetchChapterListObservable(manga)
|
||||
}
|
||||
|
||||
override suspend fun getChapterList(manga: MangaInfo): List<ChapterInfo> {
|
||||
return MangaHandler(baseHttpClient, headers, mdLang.lang, preferences.mangaDexForceLatestCovers().get()).getChapterList(manga)
|
||||
return mangaHandler.getChapterList(manga)
|
||||
}
|
||||
|
||||
override fun fetchPageList(chapter: SChapter): Observable<List<Page>> {
|
||||
return if (chapter.scanlator == "MangaPlus") {
|
||||
baseHttpClient.newCall(mangaPlusPageListRequest(chapter))
|
||||
mangaPlusHandler.client.newCall(mangaPlusPageListRequest(chapter))
|
||||
.asObservableSuccess()
|
||||
.map { response ->
|
||||
val chapterId = ApiChapterParser().externalParse(response)
|
||||
MangaPlusHandler(baseHttpClient).fetchPageList(chapterId)
|
||||
val chapterId = apiChapterParser.externalParse(response)
|
||||
mangaPlusHandler.fetchPageList(chapterId)
|
||||
}
|
||||
} else super.fetchPageList(chapter)
|
||||
}
|
||||
@ -146,7 +165,7 @@ class MangaDex(delegate: HttpSource, val context: Context) :
|
||||
|
||||
override fun fetchImage(page: Page): Observable<Response> {
|
||||
return if (page.imageUrl?.contains("mangaplus", true) == true) {
|
||||
MangaPlusHandler(network.client).client.newCall(GET(page.imageUrl!!, headers))
|
||||
mangaPlusHandler.client.newCall(GET(page.imageUrl!!, headers))
|
||||
.asObservableSuccess()
|
||||
} else super.fetchImage(page)
|
||||
}
|
||||
@ -158,11 +177,11 @@ class MangaDex(delegate: HttpSource, val context: Context) :
|
||||
}
|
||||
|
||||
override suspend fun parseIntoMetadata(metadata: MangaDexSearchMetadata, input: Response) {
|
||||
ApiMangaParser(baseHttpClient, mdLang.lang).parseIntoMetadata(metadata, input, emptyList())
|
||||
apiMangaParser.parseIntoMetadata(metadata, input, emptyList())
|
||||
}
|
||||
|
||||
override suspend fun fetchFollows(page: Int): MangasPage {
|
||||
return FollowsHandler(baseHttpClient, headers, preferences, mdLang.lang, useLowQualityThumbnail(), mdList).fetchFollows(page)
|
||||
return followsHandler.fetchFollows(page)
|
||||
}
|
||||
|
||||
override val requiresLogin: Boolean = false
|
||||
@ -199,6 +218,8 @@ class MangaDex(delegate: HttpSource, val context: Context) :
|
||||
loginHelper.logout(MdUtil.getAuthHeaders(Headers.Builder().build(), preferences, mdList))
|
||||
} catch (e: NoSessionException) {
|
||||
true
|
||||
} catch (e: Exception) {
|
||||
e.message?.equals("HTTP error 405") ?: false
|
||||
}
|
||||
|
||||
return if (result) {
|
||||
@ -208,30 +229,30 @@ class MangaDex(delegate: HttpSource, val context: Context) :
|
||||
}
|
||||
|
||||
override suspend fun fetchAllFollows(): List<Pair<SManga, MangaDexSearchMetadata>> {
|
||||
return FollowsHandler(baseHttpClient, headers, preferences, mdLang.lang, useLowQualityThumbnail(), mdList).fetchAllFollows()
|
||||
return followsHandler.fetchAllFollows()
|
||||
}
|
||||
|
||||
suspend fun updateReadingProgress(track: Track): Boolean {
|
||||
return FollowsHandler(baseHttpClient, headers, preferences, mdLang.lang, useLowQualityThumbnail(), mdList).updateReadingProgress(track)
|
||||
return followsHandler.updateReadingProgress(track)
|
||||
}
|
||||
|
||||
suspend fun updateRating(track: Track): Boolean {
|
||||
return FollowsHandler(baseHttpClient, headers, preferences, mdLang.lang, useLowQualityThumbnail(), mdList).updateRating(track)
|
||||
return followsHandler.updateRating(track)
|
||||
}
|
||||
|
||||
override suspend fun fetchTrackingInfo(url: String): Track {
|
||||
if (!isLogged()) {
|
||||
throw Exception("Not Logged in")
|
||||
}
|
||||
return FollowsHandler(baseHttpClient, headers, preferences, mdLang.lang, useLowQualityThumbnail(), mdList).fetchTrackingInfo(url)
|
||||
return followsHandler.fetchTrackingInfo(url)
|
||||
}
|
||||
|
||||
suspend fun getTrackingAndMangaInfo(track: Track): Pair<Track, MangaDexSearchMetadata?> {
|
||||
return MangaHandler(baseHttpClient, headers, mdLang.lang).getTrackingInfo(track, useLowQualityThumbnail(), mdList)
|
||||
return mangaHandler.getTrackingInfo(track, mdList)
|
||||
}
|
||||
|
||||
override suspend fun updateFollowStatus(mangaID: String, followStatus: FollowStatus): Boolean {
|
||||
return FollowsHandler(baseHttpClient, headers, preferences, mdLang.lang, useLowQualityThumbnail(), mdList).updateFollowStatus(mangaID, followStatus)
|
||||
return followsHandler.updateFollowStatus(mangaID, followStatus)
|
||||
}
|
||||
|
||||
override fun getFilterHeader(controller: BaseController<*>, onClick: () -> Unit): MangaDexFabHeaderAdapter {
|
||||
@ -239,11 +260,11 @@ class MangaDex(delegate: HttpSource, val context: Context) :
|
||||
}
|
||||
|
||||
override suspend fun fetchRandomMangaUrl(): String {
|
||||
return MangaHandler(baseHttpClient, headers, mdLang.lang).fetchRandomMangaId()
|
||||
return mangaHandler.fetchRandomMangaId()
|
||||
}
|
||||
|
||||
suspend fun getMangaSimilar(manga: MangaInfo): MangasPage {
|
||||
return SimilarHandler(baseHttpClient, mdLang.lang, preferences, useLowQualityThumbnail()).getSimilar(manga)
|
||||
return similarHandler.getSimilar(manga)
|
||||
}
|
||||
|
||||
// todo remove when mangadex gets it cover api
|
||||
|
@ -4,7 +4,6 @@ import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.recyclerview.widget.ConcatAdapter
|
||||
@ -21,6 +20,7 @@ import eu.kanade.tachiyomi.widget.SimpleNavigationView
|
||||
import eu.kanade.tachiyomi.widget.sheet.BaseBottomSheetDialog
|
||||
import exh.savedsearches.EXHSavedSearch
|
||||
import exh.source.getMainSource
|
||||
import exh.util.under
|
||||
|
||||
class SourceFilterSheet(
|
||||
activity: Activity,
|
||||
@ -155,22 +155,20 @@ class SourceFilterSheet(
|
||||
|
||||
private fun getSavedSearchesChips(searches: List<EXHSavedSearch>): List<Chip> {
|
||||
recycler.post {
|
||||
binding.saveSearchBtn.visibility = if (searches.size < MAX_SAVED_SEARCHES) View.VISIBLE else View.GONE
|
||||
binding.saveSearchBtn.isVisible = searches.size under MAX_SAVED_SEARCHES
|
||||
}
|
||||
val chips: MutableList<Chip> = mutableListOf()
|
||||
|
||||
searches.withIndex().sortedBy { it.value.name }.forEach { (index, search) ->
|
||||
val chip = Chip(context).apply {
|
||||
text = search.name
|
||||
setOnClickListener { onSavedSearchClicked(index) }
|
||||
setOnLongClickListener {
|
||||
onSavedSearchDeleteClicked(index, search.name); true
|
||||
return searches.withIndex()
|
||||
.sortedBy { it.value.name }
|
||||
.map { (index, search) ->
|
||||
Chip(context).apply {
|
||||
text = search.name
|
||||
setOnClickListener { onSavedSearchClicked(index) }
|
||||
setOnLongClickListener {
|
||||
onSavedSearchDeleteClicked(index, search.name); true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
chips += chip
|
||||
}
|
||||
return chips.sortedBy { it.text.toString().toLowerCase() }
|
||||
.sortedBy { it.text.toString().toLowerCase() }
|
||||
}
|
||||
|
||||
fun hideFilterButton() {
|
||||
|
@ -114,7 +114,11 @@ class ChaptersSettingsSheet(
|
||||
if (item is Item.DrawableSelection) {
|
||||
val scanlators = presenter.allChapterScanlators.toList()
|
||||
val filteredScanlators = presenter.manga.filtered_scanlators?.let { MdUtil.getScanlators(it) }
|
||||
val preselected = if (filteredScanlators.isNullOrEmpty()) scanlators.mapIndexed { index, _ -> index }.toIntArray() else filteredScanlators.map { scanlators.indexOf(it) }.toIntArray()
|
||||
val preselected = if (filteredScanlators.isNullOrEmpty()) {
|
||||
scanlators.mapIndexed { index, _ -> index }
|
||||
} else {
|
||||
filteredScanlators.map { scanlators.indexOf(it) }
|
||||
}.toIntArray()
|
||||
|
||||
MaterialDialog(context)
|
||||
.title(R.string.select_scanlators)
|
||||
|
@ -23,7 +23,6 @@ import okhttp3.Response
|
||||
import tachiyomi.source.model.ChapterInfo
|
||||
import tachiyomi.source.model.MangaInfo
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.util.Date
|
||||
import java.util.Locale
|
||||
|
||||
class ApiMangaParser(val client: OkHttpClient, private val lang: String) {
|
||||
@ -138,7 +137,7 @@ class ApiMangaParser(val client: OkHttpClient, private val lang: String) {
|
||||
cover = "https://coverapi.orell.dev/api/v1/mal/manga/$myAnimeListId/cover"
|
||||
}
|
||||
if (cover == null) {
|
||||
cover = "https://coverapi.orell.dev/api/v1/mdaltimage/manga/$mdUuid/cover"
|
||||
cover = MdUtil.formThumbUrl(mdUuid.toString())
|
||||
}
|
||||
|
||||
// val filteredChapters = filterChapterForChecking(networkApiManga)
|
||||
@ -155,8 +154,11 @@ class ApiMangaParser(val client: OkHttpClient, private val lang: String) {
|
||||
|
||||
// things that will go with the genre tags but aren't actually genre
|
||||
val nonGenres = listOfNotNull(
|
||||
networkManga.publicationDemographic?.let { RaisedTag("Demographic", it.capitalize(Locale.US), MangaDexSearchMetadata.TAG_TYPE_DEFAULT) },
|
||||
networkManga.contentRating?.let { RaisedTag("Content Rating", it.capitalize(Locale.US), MangaDexSearchMetadata.TAG_TYPE_DEFAULT) },
|
||||
networkManga.publicationDemographic
|
||||
?.let { RaisedTag("Demographic", it.capitalize(Locale.US), MangaDexSearchMetadata.TAG_TYPE_DEFAULT) },
|
||||
networkManga.contentRating
|
||||
?.takeUnless { it == "safe" }
|
||||
?.let { RaisedTag("Content Rating", it.capitalize(Locale.US), MangaDexSearchMetadata.TAG_TYPE_DEFAULT) },
|
||||
)
|
||||
|
||||
val genres = nonGenres + networkManga.tags
|
||||
@ -239,7 +241,7 @@ class ApiMangaParser(val client: OkHttpClient, private val lang: String) {
|
||||
}
|
||||
|
||||
fun chapterListParse(chapterListResponse: List<ChapterResponse>, groupMap: Map<String, String>): List<ChapterInfo> {
|
||||
val now = Date().time
|
||||
val now = System.currentTimeMillis()
|
||||
|
||||
return chapterListResponse.asSequence()
|
||||
.map {
|
||||
|
@ -16,6 +16,7 @@ import exh.md.handlers.serializers.MangaListResponse
|
||||
import exh.md.handlers.serializers.MangaResponse
|
||||
import exh.md.handlers.serializers.MangaStatusListResponse
|
||||
import exh.md.handlers.serializers.MangaStatusResponse
|
||||
import exh.md.handlers.serializers.ResultResponse
|
||||
import exh.md.handlers.serializers.UpdateReadingStatus
|
||||
import exh.md.utils.FollowStatus
|
||||
import exh.md.utils.MdUtil
|
||||
@ -38,7 +39,6 @@ class FollowsHandler(
|
||||
val headers: Headers,
|
||||
val preferences: PreferencesHelper,
|
||||
private val lang: String,
|
||||
private val useLowQualityCovers: Boolean,
|
||||
private val mdList: MdList
|
||||
) {
|
||||
|
||||
@ -78,8 +78,7 @@ class FollowsHandler(
|
||||
return response.map {
|
||||
MdUtil.createMangaEntry(
|
||||
it,
|
||||
lang,
|
||||
useLowQualityCovers
|
||||
lang
|
||||
).toSManga() to MangaDexSearchMetadata().apply {
|
||||
followStatus = FollowStatus.fromDex(statuses[it.data.id]).int
|
||||
}
|
||||
@ -135,7 +134,9 @@ class FollowsHandler(
|
||||
jsonString.toRequestBody("application/json".toMediaType())
|
||||
)
|
||||
).await()
|
||||
postResult.isSuccessful
|
||||
|
||||
val body = postResult.parseAs<ResultResponse>(MdUtil.jsonParser)
|
||||
body.result == "ok"
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -25,18 +25,22 @@ import okhttp3.Request
|
||||
import rx.Observable
|
||||
import tachiyomi.source.model.ChapterInfo
|
||||
import tachiyomi.source.model.MangaInfo
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
|
||||
class MangaHandler(val client: OkHttpClient, val headers: Headers, private val lang: String, private val forceLatestCovers: Boolean = false) {
|
||||
class MangaHandler(
|
||||
val client: OkHttpClient,
|
||||
val headers: Headers,
|
||||
private val lang: String,
|
||||
private val apiMangaParser: ApiMangaParser,
|
||||
private val followsHandler: FollowsHandler
|
||||
) {
|
||||
|
||||
suspend fun fetchMangaAndChapterDetails(manga: MangaInfo, sourceId: Long): Pair<MangaInfo, List<ChapterInfo>> {
|
||||
suspend fun fetchMangaAndChapterDetails(manga: MangaInfo, sourceId: Long, forceLatestCovers: Boolean): Pair<MangaInfo, List<ChapterInfo>> {
|
||||
return withIOContext {
|
||||
val response = client.newCall(mangaRequest(manga)).await()
|
||||
val covers = getCovers(manga, forceLatestCovers)
|
||||
val parser = ApiMangaParser(client, lang)
|
||||
|
||||
parser.parseToManga(manga, response, covers, sourceId) to getChapterList(manga)
|
||||
apiMangaParser.parseToManga(manga, response, covers, sourceId) to getChapterList(manga)
|
||||
}
|
||||
}
|
||||
|
||||
@ -45,7 +49,7 @@ class MangaHandler(val client: OkHttpClient, val headers: Headers, private val l
|
||||
val covers = client.newCall(coverRequest(manga)).await().parseAs<ApiCovers>(MdUtil.jsonParser)
|
||||
return covers.data.map { it.url }
|
||||
} else {*/
|
||||
return emptyList<String>()
|
||||
return emptyList()
|
||||
// }
|
||||
}
|
||||
|
||||
@ -53,19 +57,19 @@ class MangaHandler(val client: OkHttpClient, val headers: Headers, private val l
|
||||
return withIOContext {
|
||||
val request = GET(MdUtil.chapterUrl + urlChapterId)
|
||||
val response = client.newCall(request).await()
|
||||
ApiMangaParser(client, lang).chapterParseForMangaId(response)
|
||||
apiMangaParser.chapterParseForMangaId(response)
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun getMangaDetails(manga: MangaInfo, sourceId: Long): MangaInfo {
|
||||
suspend fun getMangaDetails(manga: MangaInfo, sourceId: Long, forceLatestCovers: Boolean): MangaInfo {
|
||||
val response = withIOContext { client.newCall(mangaRequest(manga)).await() }
|
||||
val covers = withIOContext { getCovers(manga, forceLatestCovers) }
|
||||
return ApiMangaParser(client, lang).parseToManga(manga, response, covers, sourceId)
|
||||
return apiMangaParser.parseToManga(manga, response, covers, sourceId)
|
||||
}
|
||||
|
||||
fun fetchMangaDetailsObservable(manga: SManga, sourceId: Long): Observable<SManga> {
|
||||
fun fetchMangaDetailsObservable(manga: SManga, sourceId: Long, forceLatestCovers: Boolean): Observable<SManga> {
|
||||
return runAsObservable({
|
||||
getMangaDetails(manga.toMangaInfo(), sourceId).toSManga()
|
||||
getMangaDetails(manga.toMangaInfo(), sourceId, forceLatestCovers).toSManga()
|
||||
})
|
||||
}
|
||||
|
||||
@ -81,7 +85,7 @@ class MangaHandler(val client: OkHttpClient, val headers: Headers, private val l
|
||||
|
||||
val groupMap = getGroupMap(results)
|
||||
|
||||
ApiMangaParser(client, lang).chapterListParse(results, groupMap)
|
||||
apiMangaParser.chapterListParse(results, groupMap)
|
||||
}
|
||||
}
|
||||
|
||||
@ -109,29 +113,22 @@ class MangaHandler(val client: OkHttpClient, val headers: Headers, private val l
|
||||
suspend fun fetchRandomMangaId(): String {
|
||||
return withIOContext {
|
||||
val response = client.newCall(randomMangaRequest()).await()
|
||||
ApiMangaParser(client, lang).randomMangaIdParse(response)
|
||||
apiMangaParser.randomMangaIdParse(response)
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun getTrackingInfo(track: Track, useLowQualityCovers: Boolean, mdList: MdList): Pair<Track, MangaDexSearchMetadata?> {
|
||||
suspend fun getTrackingInfo(track: Track, mdList: MdList): Pair<Track, MangaDexSearchMetadata?> {
|
||||
return withIOContext {
|
||||
val metadata = async {
|
||||
val mangaUrl = "/manga/" + MdUtil.getMangaId(track.tracking_url)
|
||||
val mangaUrl = MdUtil.buildMangaUrl(MdUtil.getMangaId(track.tracking_url))
|
||||
val manga = MangaInfo(mangaUrl, track.title)
|
||||
val response = client.newCall(mangaRequest(manga)).await()
|
||||
val metadata = MangaDexSearchMetadata()
|
||||
ApiMangaParser(client, lang).parseIntoMetadata(metadata, response, emptyList())
|
||||
apiMangaParser.parseIntoMetadata(metadata, response, emptyList())
|
||||
metadata
|
||||
}
|
||||
val remoteTrack = async {
|
||||
FollowsHandler(
|
||||
client,
|
||||
headers,
|
||||
Injekt.get(),
|
||||
lang,
|
||||
useLowQualityCovers,
|
||||
mdList
|
||||
).fetchTrackingInfo(track.tracking_url)
|
||||
followsHandler.fetchTrackingInfo(track.tracking_url)
|
||||
}
|
||||
remoteTrack.await() to null
|
||||
}
|
||||
|
@ -11,22 +11,28 @@ import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import rx.Observable
|
||||
|
||||
class PageHandler(val client: OkHttpClient, val headers: Headers, private val dataSaver: Boolean) {
|
||||
class PageHandler(
|
||||
val client: OkHttpClient,
|
||||
val headers: Headers,
|
||||
private val dataSaver: Boolean,
|
||||
private val apiChapterParser: ApiChapterParser,
|
||||
private val mangaPlusHandler: MangaPlusHandler
|
||||
) {
|
||||
|
||||
fun fetchPageList(chapter: SChapter): Observable<List<Page>> {
|
||||
if (chapter.scanlator.equals("MangaPlus")) {
|
||||
return client.newCall(pageListRequest(chapter))
|
||||
.asObservableSuccess()
|
||||
.map { response ->
|
||||
val chapterId = ApiChapterParser().externalParse(response)
|
||||
MangaPlusHandler(client).fetchPageList(chapterId)
|
||||
val chapterId = apiChapterParser.externalParse(response)
|
||||
mangaPlusHandler.fetchPageList(chapterId)
|
||||
}
|
||||
}
|
||||
return client.newCall(pageListRequest(chapter))
|
||||
.asObservableSuccess()
|
||||
.map { response ->
|
||||
val host = MdUtil.atHomeUrlHostUrl("${MdUtil.atHomeUrl}/${MdUtil.getChapterId(chapter.url)}", client)
|
||||
ApiChapterParser().pageListParse(response, host, dataSaver)
|
||||
apiChapterParser.pageListParse(response, host, dataSaver)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -18,7 +18,7 @@ import rx.Observable
|
||||
/**
|
||||
* Returns the latest manga from the updates url since it actually respects the users settings
|
||||
*/
|
||||
class PopularHandler(val client: OkHttpClient, private val headers: Headers, private val lang: String, private val useLowQualityCovers: Boolean) {
|
||||
class PopularHandler(val client: OkHttpClient, private val headers: Headers, private val lang: String) {
|
||||
|
||||
fun fetchPopularManga(page: Int): Observable<MangasPage> {
|
||||
return client.newCall(popularMangaRequest(page))
|
||||
@ -42,7 +42,7 @@ class PopularHandler(val client: OkHttpClient, private val headers: Headers, pri
|
||||
private fun popularMangaParse(response: Response): MangasPage {
|
||||
val mlResponse = response.parseAs<MangaListResponse>(MdUtil.jsonParser)
|
||||
val hasMoreResults = mlResponse.limit + mlResponse.offset < mlResponse.total
|
||||
val mangaList = mlResponse.results.map { MdUtil.createMangaEntry(it, lang, useLowQualityCovers).toSManga() }
|
||||
val mangaList = mlResponse.results.map { MdUtil.createMangaEntry(it, lang).toSManga() }
|
||||
return MangasPage(mangaList, hasMoreResults)
|
||||
}
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ import okhttp3.Request
|
||||
import okhttp3.Response
|
||||
import rx.Observable
|
||||
|
||||
class SearchHandler(val client: OkHttpClient, private val headers: Headers, val lang: String, val filterHandler: FilterHandler, private val useLowQualityCovers: Boolean) {
|
||||
class SearchHandler(val client: OkHttpClient, private val headers: Headers, val lang: String, val filterHandler: FilterHandler, private val apiMangaParser: ApiMangaParser) {
|
||||
|
||||
fun fetchSearchManga(page: Int, query: String, filters: FilterList, sourceId: Long): Observable<MangasPage> {
|
||||
return if (query.startsWith(PREFIX_ID_SEARCH)) {
|
||||
@ -28,8 +28,8 @@ class SearchHandler(val client: OkHttpClient, private val headers: Headers, val
|
||||
.flatMap { response ->
|
||||
runAsObservable({
|
||||
val mangaResponse = response.parseAs<MangaResponse>(MdUtil.jsonParser)
|
||||
val details = ApiMangaParser(client, lang)
|
||||
.parseToManga(MdUtil.createMangaEntry(mangaResponse, lang, useLowQualityCovers), response, emptyList(), sourceId).toSManga()
|
||||
val details = apiMangaParser
|
||||
.parseToManga(MdUtil.createMangaEntry(mangaResponse, lang), response, emptyList(), sourceId).toSManga()
|
||||
MangasPage(listOf(details), false)
|
||||
})
|
||||
}
|
||||
@ -45,7 +45,7 @@ class SearchHandler(val client: OkHttpClient, private val headers: Headers, val
|
||||
private fun searchMangaParse(response: Response): MangasPage {
|
||||
val mlResponse = response.parseAs<MangaListResponse>(MdUtil.jsonParser)
|
||||
val hasMoreResults = mlResponse.limit + mlResponse.offset < mlResponse.total
|
||||
val mangaList = mlResponse.results.map { MdUtil.createMangaEntry(it, lang, useLowQualityCovers).toSManga() }
|
||||
val mangaList = mlResponse.results.map { MdUtil.createMangaEntry(it, lang).toSManga() }
|
||||
return MangasPage(mangaList, hasMoreResults)
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,5 @@
|
||||
package exh.md.handlers
|
||||
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.network.await
|
||||
import eu.kanade.tachiyomi.network.parseAs
|
||||
@ -15,7 +14,7 @@ import okhttp3.Request
|
||||
import okhttp3.Response
|
||||
import tachiyomi.source.model.MangaInfo
|
||||
|
||||
class SimilarHandler(val client: OkHttpClient, val lang: String, val preferences: PreferencesHelper, private val useLowQualityCovers: Boolean) {
|
||||
class SimilarHandler(val client: OkHttpClient, val lang: String) {
|
||||
|
||||
suspend fun getSimilar(manga: MangaInfo): MangasPage {
|
||||
val response = client.newCall(similarMangaRequest(manga)).await()
|
||||
@ -30,9 +29,9 @@ class SimilarHandler(val client: OkHttpClient, val lang: String, val preferences
|
||||
private fun similarMangaParse(response: Response): MangasPage {
|
||||
val mangaList = response.parseAs<SimilarMangaResponse>().matches.map {
|
||||
SManga.create().apply {
|
||||
url = "/manga/" + it.id
|
||||
url = MdUtil.buildMangaUrl(it.id)
|
||||
title = MdUtil.cleanString(it.title[lang] ?: it.title["en"]!!)
|
||||
thumbnail_url = "https://coverapi.orell.dev/api/v1/mdaltimage/manga/${it.id}/cover"
|
||||
thumbnail_url = MdUtil.formThumbUrl(url)
|
||||
}
|
||||
}
|
||||
return MangasPage(mangaList, false)
|
||||
|
@ -24,7 +24,7 @@ data class LoginBodyToken(val session: String, val refresh: String)
|
||||
* Response after logout
|
||||
*/
|
||||
@Serializable
|
||||
data class LogoutResponse(val result: String)
|
||||
data class ResultResponse(val result: String)
|
||||
|
||||
/**
|
||||
* Check if session token is valid
|
||||
|
@ -12,8 +12,8 @@ import exh.md.handlers.serializers.CheckTokenResponse
|
||||
import exh.md.handlers.serializers.LoginBodyToken
|
||||
import exh.md.handlers.serializers.LoginRequest
|
||||
import exh.md.handlers.serializers.LoginResponse
|
||||
import exh.md.handlers.serializers.LogoutResponse
|
||||
import exh.md.handlers.serializers.RefreshTokenRequest
|
||||
import exh.md.handlers.serializers.ResultResponse
|
||||
import exh.md.utils.MdUtil
|
||||
import kotlinx.serialization.SerializationException
|
||||
import kotlinx.serialization.encodeToString
|
||||
@ -78,7 +78,7 @@ class MangaDexLoginHelper(val client: OkHttpClient, val preferences: Preferences
|
||||
null
|
||||
}
|
||||
|
||||
if (response.code == 200 && loginResponse != null) {
|
||||
if (response.code == 200 && loginResponse != null && loginResponse.result == "ok") {
|
||||
LoginResult.Success(loginResponse.token)
|
||||
} else {
|
||||
LoginResult.Failure()
|
||||
@ -103,7 +103,7 @@ class MangaDexLoginHelper(val client: OkHttpClient, val preferences: Preferences
|
||||
|
||||
suspend fun logout(authHeaders: Headers): Boolean {
|
||||
val response = client.newCall(GET(MdUtil.logoutUrl, authHeaders, CacheControl.FORCE_NETWORK)).await()
|
||||
val body = response.parseAs<LogoutResponse>(MdUtil.jsonParser)
|
||||
val body = response.parseAs<ResultResponse>(MdUtil.jsonParser)
|
||||
return body.result == "ok"
|
||||
}
|
||||
}
|
||||
|
@ -202,13 +202,12 @@ class MdUtil {
|
||||
"(zh-Hant)",
|
||||
)
|
||||
|
||||
// guess the thumbnail url is .jpg this has a ~80% success rate
|
||||
fun formThumbUrl(mangaUrl: String, lowQuality: Boolean): String {
|
||||
var ext = ".jpg"
|
||||
if (lowQuality) {
|
||||
ext = ".thumb$ext"
|
||||
}
|
||||
return cdnUrl + "/images/manga/" + getMangaId(mangaUrl) + ext
|
||||
fun buildMangaUrl(mangaUuid: String): String {
|
||||
return "/manga/$mangaUuid"
|
||||
}
|
||||
|
||||
fun formThumbUrl(mangaUrl: String): String {
|
||||
return "https://coverapi.orell.dev/api/v1/mdaltimage/manga/${getMangaId(mangaUrl)}/cover"
|
||||
}
|
||||
|
||||
// Get the ID from the manga url
|
||||
@ -255,9 +254,9 @@ class MdUtil {
|
||||
return baseUrl + attr
|
||||
}
|
||||
|
||||
fun getScanlators(scanlators: String?): List<String> {
|
||||
if (scanlators.isNullOrBlank()) return emptyList()
|
||||
return scanlators.split(scanlatorSeparator).distinct()
|
||||
fun getScanlators(scanlators: String?): Set<String> {
|
||||
if (scanlators.isNullOrBlank()) return emptySet()
|
||||
return scanlators.split(scanlatorSeparator).toSet()
|
||||
}
|
||||
|
||||
fun getScanlatorString(scanlators: Set<String>): String {
|
||||
@ -301,32 +300,27 @@ class MdUtil {
|
||||
fun parseDate(dateAsString: String): Long =
|
||||
dateFormatter.parse(dateAsString)?.time ?: 0
|
||||
|
||||
fun createMangaEntry(json: MangaResponse, lang: String, lowQualityCovers: Boolean): MangaInfo {
|
||||
val key = "/manga/" + json.data.id
|
||||
fun createMangaEntry(json: MangaResponse, lang: String): MangaInfo {
|
||||
val key = buildMangaUrl(json.data.id)
|
||||
return MangaInfo(
|
||||
key = key,
|
||||
title = cleanString(json.data.attributes.title[lang] ?: json.data.attributes.title["en"]!!),
|
||||
cover = formThumbUrl(key, lowQualityCovers)
|
||||
cover = formThumbUrl(key)
|
||||
)
|
||||
}
|
||||
|
||||
fun sessionToken(preferences: PreferencesHelper, mdList: MdList) = preferences.trackToken(mdList).get().nullIfBlank()?.let {
|
||||
fun getLoginBody(preferences: PreferencesHelper, mdList: MdList) = preferences.trackToken(mdList).get().nullIfBlank()?.let {
|
||||
try {
|
||||
jsonParser.decodeFromString<LoginBodyToken>(it)
|
||||
} catch (e: SerializationException) {
|
||||
xLogD("Unable to load session token")
|
||||
xLogD("Unable to load login body")
|
||||
null
|
||||
}
|
||||
}?.session
|
||||
}
|
||||
|
||||
fun refreshToken(preferences: PreferencesHelper, mdList: MdList) = preferences.trackToken(mdList).get().nullIfBlank()?.let {
|
||||
try {
|
||||
jsonParser.decodeFromString<LoginBodyToken>(it)
|
||||
} catch (e: SerializationException) {
|
||||
xLogD("Unable to load session token")
|
||||
null
|
||||
}
|
||||
}?.refresh
|
||||
fun sessionToken(preferences: PreferencesHelper, mdList: MdList) = getLoginBody(preferences, mdList)?.session
|
||||
|
||||
fun refreshToken(preferences: PreferencesHelper, mdList: MdList) = getLoginBody(preferences, mdList)?.refresh
|
||||
|
||||
fun updateLoginToken(token: LoginBodyToken, preferences: PreferencesHelper, mdList: MdList) {
|
||||
preferences.trackToken(mdList).set(jsonParser.encodeToString(token))
|
||||
|
@ -44,7 +44,7 @@ class MangaDexSearchMetadata : RaisedSearchMetadata() {
|
||||
// var maxChapterNumber: Int? = null
|
||||
|
||||
override fun createMangaInfo(manga: MangaInfo): MangaInfo {
|
||||
val key = mdUuid?.let { "/manga/$it" }
|
||||
val key = mdUuid?.let { MdUtil.buildMangaUrl(it) }
|
||||
|
||||
val title = title
|
||||
|
||||
|
@ -146,11 +146,11 @@ abstract class RaisedSearchMetadata {
|
||||
const val TAG_TYPE_VIRTUAL = -2
|
||||
|
||||
fun MutableList<RaisedTag>.toGenreString() =
|
||||
(this).filter { it.type != TAG_TYPE_VIRTUAL }
|
||||
this.filter { it.type != TAG_TYPE_VIRTUAL }
|
||||
.joinToString { (if (it.namespace != null) "${it.namespace}: " else "") + it.name }
|
||||
|
||||
fun MutableList<RaisedTag>.toGenreList() =
|
||||
(this).filter { it.type != TAG_TYPE_VIRTUAL }
|
||||
this.filter { it.type != TAG_TYPE_VIRTUAL }
|
||||
.map { (if (it.namespace != null) "${it.namespace}: " else "") + it.name }
|
||||
|
||||
private val module = SerializersModule {
|
||||
|
Loading…
x
Reference in New Issue
Block a user