Separate MDList from Mangadex manga, allowing it to be used with other sources(not implemented)
This commit is contained in:
parent
86c228243d
commit
227de5d838
@ -4,7 +4,6 @@ import android.content.Context
|
|||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
import androidx.annotation.StringRes
|
import androidx.annotation.StringRes
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
|
||||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||||
import eu.kanade.tachiyomi.data.database.models.Track
|
import eu.kanade.tachiyomi.data.database.models.Track
|
||||||
import eu.kanade.tachiyomi.data.track.TrackManager
|
import eu.kanade.tachiyomi.data.track.TrackManager
|
||||||
@ -13,17 +12,10 @@ import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
|||||||
import eu.kanade.tachiyomi.source.model.SManga
|
import eu.kanade.tachiyomi.source.model.SManga
|
||||||
import exh.md.utils.FollowStatus
|
import exh.md.utils.FollowStatus
|
||||||
import exh.md.utils.MdUtil
|
import exh.md.utils.MdUtil
|
||||||
import exh.metadata.metadata.MangaDexSearchMetadata
|
|
||||||
import exh.metadata.metadata.base.getFlatMetadataForManga
|
|
||||||
import exh.metadata.metadata.base.insertFlatMetadataAsync
|
|
||||||
import exh.util.executeOnIO
|
|
||||||
import exh.util.floor
|
|
||||||
import uy.kohesive.injekt.injectLazy
|
|
||||||
|
|
||||||
class MdList(private val context: Context, id: Int) : TrackService(id) {
|
class MdList(private val context: Context, id: Int) : TrackService(id) {
|
||||||
|
|
||||||
private val mdex by lazy { MdUtil.getEnabledMangaDex() }
|
private val mdex by lazy { MdUtil.getEnabledMangaDex() }
|
||||||
private val db: DatabaseHelper by injectLazy()
|
|
||||||
|
|
||||||
@StringRes
|
@StringRes
|
||||||
override fun nameRes(): Int = R.string.mdlist
|
override fun nameRes(): Int = R.string.mdlist
|
||||||
@ -51,16 +43,16 @@ class MdList(private val context: Context, id: Int) : TrackService(id) {
|
|||||||
|
|
||||||
override suspend fun update(track: Track): Track {
|
override suspend fun update(track: Track): Track {
|
||||||
val mdex = mdex ?: throw Exception("Mangadex not enabled")
|
val mdex = mdex ?: throw Exception("Mangadex not enabled")
|
||||||
val mangaMetadata = db.getFlatMetadataForManga(track.manga_id).executeAsBlocking()
|
|
||||||
?.raise<MangaDexSearchMetadata>()
|
val remoteTrack = mdex.fetchTrackingInfo(track.tracking_url)
|
||||||
?: throw Exception("Invalid manga metadata")
|
|
||||||
val followStatus = FollowStatus.fromInt(track.status)
|
val followStatus = FollowStatus.fromInt(track.status)
|
||||||
|
|
||||||
|
// this updates the follow status in the metadata
|
||||||
// allow follow status to update
|
// allow follow status to update
|
||||||
if (mangaMetadata.follow_status != followStatus.int) {
|
if (remoteTrack.status != followStatus.int) {
|
||||||
mdex.updateFollowStatus(MdUtil.getMangaId(track.tracking_url), followStatus)
|
mdex.updateFollowStatus(MdUtil.getMangaId(track.tracking_url), followStatus)
|
||||||
mangaMetadata.follow_status = followStatus.int
|
remoteTrack.status = followStatus.int
|
||||||
db.insertFlatMetadataAsync(mangaMetadata.flatten()).await()
|
// db.insertFlatMetadataAsync(mangaMetadata.flatten()).await()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (track.score.toInt() > 0) {
|
if (track.score.toInt() > 0) {
|
||||||
@ -78,8 +70,8 @@ class MdList(private val context: Context, id: Int) : TrackService(id) {
|
|||||||
val newFollowStatus = FollowStatus.READING
|
val newFollowStatus = FollowStatus.READING
|
||||||
track.status = FollowStatus.READING.int
|
track.status = FollowStatus.READING.int
|
||||||
mdex.updateFollowStatus(MdUtil.getMangaId(track.tracking_url), newFollowStatus)
|
mdex.updateFollowStatus(MdUtil.getMangaId(track.tracking_url), newFollowStatus)
|
||||||
mangaMetadata.follow_status = newFollowStatus.int
|
remoteTrack.status = newFollowStatus.int
|
||||||
db.insertFlatMetadataAsync(mangaMetadata.flatten()).await()
|
// db.insertFlatMetadataAsync(mangaMetadata.flatten()).await()
|
||||||
}
|
}
|
||||||
|
|
||||||
mdex.updateReadingProgress(track)
|
mdex.updateReadingProgress(track)
|
||||||
@ -96,20 +88,20 @@ class MdList(private val context: Context, id: Int) : TrackService(id) {
|
|||||||
|
|
||||||
override suspend fun refresh(track: Track): Track {
|
override suspend fun refresh(track: Track): Track {
|
||||||
val mdex = mdex ?: throw Exception("Mangadex not enabled")
|
val mdex = mdex ?: throw Exception("Mangadex not enabled")
|
||||||
val remoteTrack = mdex.fetchTrackingInfo(track.tracking_url)
|
val (remoteTrack, mangaMetadata) = mdex.getTrackingAndMangaInfo(track)
|
||||||
track.copyPersonalFrom(remoteTrack)
|
track.copyPersonalFrom(remoteTrack)
|
||||||
if (track.total_chapters == 0 && db.getManga(track.manga_id).executeOnIO()?.status == SManga.COMPLETED) {
|
if (track.total_chapters == 0 && mangaMetadata.status == SManga.COMPLETED) {
|
||||||
track.total_chapters = db.getChapters(track.manga_id).executeOnIO().maxOfOrNull { it.chapter_number }?.floor() ?: 0
|
track.total_chapters = mangaMetadata.maxChapterNumber ?: 0
|
||||||
}
|
}
|
||||||
return track
|
return track
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createInitialTracker(manga: Manga): Track {
|
fun createInitialTracker(dbManga: Manga, mdManga: Manga = dbManga): Track {
|
||||||
val track = Track.create(TrackManager.MDLIST)
|
val track = Track.create(TrackManager.MDLIST)
|
||||||
track.manga_id = manga.id!!
|
track.manga_id = dbManga.id!!
|
||||||
track.status = FollowStatus.UNFOLLOWED.int
|
track.status = FollowStatus.UNFOLLOWED.int
|
||||||
track.tracking_url = MdUtil.baseUrl + manga.url
|
track.tracking_url = MdUtil.baseUrl + mdManga.url
|
||||||
track.title = manga.title
|
track.title = mdManga.title
|
||||||
return track
|
return track
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -268,6 +268,10 @@ class MangaDex(delegate: HttpSource, val context: Context) :
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun getTrackingAndMangaInfo(track: Track): Pair<Track, MangaDexSearchMetadata> {
|
||||||
|
return MangaHandler(client, headers, lang).getTrackingInfo(track, useLowQualityThumbnail())
|
||||||
|
}
|
||||||
|
|
||||||
override suspend fun updateFollowStatus(mangaID: String, followStatus: FollowStatus): Boolean {
|
override suspend fun updateFollowStatus(mangaID: String, followStatus: FollowStatus): Boolean {
|
||||||
return withIOContext { FollowsHandler(client, headers, Injekt.get(), useLowQualityThumbnail()).updateFollowStatus(mangaID, followStatus) }
|
return withIOContext { FollowsHandler(client, headers, Injekt.get(), useLowQualityThumbnail()).updateFollowStatus(mangaID, followStatus) }
|
||||||
}
|
}
|
||||||
|
@ -126,6 +126,7 @@ class ApiMangaParser(private val lang: String) {
|
|||||||
if (publishedOrCancelled && isMangaCompleted(networkApiManga, filteredChapters)) {
|
if (publishedOrCancelled && isMangaCompleted(networkApiManga, filteredChapters)) {
|
||||||
status = SManga.COMPLETED
|
status = SManga.COMPLETED
|
||||||
missing_chapters = null
|
missing_chapters = null
|
||||||
|
maxChapterNumber = networkApiManga.data.manga.lastChapter?.toDoubleOrNull()?.floor()
|
||||||
} else {
|
} else {
|
||||||
status = tempStatus
|
status = tempStatus
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ import eu.kanade.tachiyomi.data.track.TrackManager
|
|||||||
import eu.kanade.tachiyomi.network.GET
|
import eu.kanade.tachiyomi.network.GET
|
||||||
import eu.kanade.tachiyomi.network.POST
|
import eu.kanade.tachiyomi.network.POST
|
||||||
import eu.kanade.tachiyomi.network.await
|
import eu.kanade.tachiyomi.network.await
|
||||||
|
import eu.kanade.tachiyomi.network.parseAs
|
||||||
import eu.kanade.tachiyomi.source.model.MangasPage
|
import eu.kanade.tachiyomi.source.model.MangasPage
|
||||||
import eu.kanade.tachiyomi.source.model.MetadataMangasPage
|
import eu.kanade.tachiyomi.source.model.MetadataMangasPage
|
||||||
import eu.kanade.tachiyomi.source.model.SManga
|
import eu.kanade.tachiyomi.source.model.SManga
|
||||||
@ -75,9 +76,7 @@ class FollowsHandler(val client: OkHttpClient, val headers: Headers, val prefere
|
|||||||
|
|
||||||
private fun followStatusParse(response: Response): Track {
|
private fun followStatusParse(response: Response): Track {
|
||||||
val followsPageResult = try {
|
val followsPageResult = try {
|
||||||
MdUtil.jsonParser.decodeFromString<FollowsIndividualSerializer>(
|
response.parseAs<FollowsIndividualSerializer>(MdUtil.jsonParser)
|
||||||
response.body?.string().orEmpty()
|
|
||||||
)
|
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
XLog.tag("FollowsHandler").enableStackTrace(2).e("error parsing follows", e)
|
XLog.tag("FollowsHandler").enableStackTrace(2).e("error parsing follows", e)
|
||||||
throw e
|
throw e
|
||||||
@ -214,14 +213,21 @@ class FollowsHandler(val client: OkHttpClient, val headers: Headers, val prefere
|
|||||||
suspend fun fetchTrackingInfo(url: String): Track {
|
suspend fun fetchTrackingInfo(url: String): Track {
|
||||||
return withIOContext {
|
return withIOContext {
|
||||||
val request = GET(
|
val request = GET(
|
||||||
"${MdUtil.apiUrl}${MdUtil.followsMangaApi}" + MdUtil.getMangaId(url),
|
MdUtil.apiUrl + MdUtil.followsMangaApi + MdUtil.getMangaId(url),
|
||||||
headers,
|
headers,
|
||||||
CacheControl.FORCE_NETWORK
|
CacheControl.FORCE_NETWORK
|
||||||
)
|
)
|
||||||
val response = client.newCall(request).await()
|
try {
|
||||||
val track = followStatusParse(response)
|
val response = client.newCall(request).await()
|
||||||
|
followStatusParse(response)
|
||||||
track
|
} catch (e: Exception) {
|
||||||
|
if (e.message.equals("HTTP error 404", true)) {
|
||||||
|
XLog.enableStackTrace(10).e(e)
|
||||||
|
Track.create(TrackManager.MDLIST).apply {
|
||||||
|
status = FollowStatus.UNFOLLOWED.int
|
||||||
|
}
|
||||||
|
} else throw e
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package exh.md.handlers
|
package exh.md.handlers
|
||||||
|
|
||||||
|
import eu.kanade.tachiyomi.data.database.models.Track
|
||||||
import eu.kanade.tachiyomi.network.GET
|
import eu.kanade.tachiyomi.network.GET
|
||||||
import eu.kanade.tachiyomi.network.asObservableSuccess
|
import eu.kanade.tachiyomi.network.asObservableSuccess
|
||||||
import eu.kanade.tachiyomi.network.await
|
import eu.kanade.tachiyomi.network.await
|
||||||
@ -13,6 +14,7 @@ import eu.kanade.tachiyomi.util.lang.withIOContext
|
|||||||
import exh.md.handlers.serializers.ApiCovers
|
import exh.md.handlers.serializers.ApiCovers
|
||||||
import exh.md.handlers.serializers.ApiMangaSerializer
|
import exh.md.handlers.serializers.ApiMangaSerializer
|
||||||
import exh.md.utils.MdUtil
|
import exh.md.utils.MdUtil
|
||||||
|
import exh.metadata.metadata.MangaDexSearchMetadata
|
||||||
import okhttp3.CacheControl
|
import okhttp3.CacheControl
|
||||||
import okhttp3.Headers
|
import okhttp3.Headers
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
@ -20,6 +22,8 @@ import okhttp3.Request
|
|||||||
import rx.Observable
|
import rx.Observable
|
||||||
import tachiyomi.source.model.ChapterInfo
|
import tachiyomi.source.model.ChapterInfo
|
||||||
import tachiyomi.source.model.MangaInfo
|
import tachiyomi.source.model.MangaInfo
|
||||||
|
import uy.kohesive.injekt.Injekt
|
||||||
|
import uy.kohesive.injekt.api.get
|
||||||
|
|
||||||
class MangaHandler(val client: OkHttpClient, val headers: Headers, val lang: String, val forceLatestCovers: Boolean = false) {
|
class MangaHandler(val client: OkHttpClient, val headers: Headers, val lang: String, val forceLatestCovers: Boolean = false) {
|
||||||
|
|
||||||
@ -115,6 +119,16 @@ class MangaHandler(val client: OkHttpClient, val headers: Headers, val lang: Str
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun getTrackingInfo(track: Track, useLowQualityCovers: Boolean): Pair<Track, MangaDexSearchMetadata> {
|
||||||
|
val mangaUrl = MdUtil.mapMdIdToMangaUrl(MdUtil.getMangaId(track.tracking_url).toInt())
|
||||||
|
val manga = MangaInfo(mangaUrl, track.title)
|
||||||
|
val response = client.newCall(apiRequest(manga)).await()
|
||||||
|
val metadata = MangaDexSearchMetadata()
|
||||||
|
ApiMangaParser(lang).parseIntoMetadata(metadata, response, emptyList())
|
||||||
|
val remoteTrack = FollowsHandler(client, headers, Injekt.get(), useLowQualityCovers).fetchTrackingInfo(track.tracking_url)
|
||||||
|
return remoteTrack to metadata
|
||||||
|
}
|
||||||
|
|
||||||
private fun randomMangaRequest(): Request {
|
private fun randomMangaRequest(): Request {
|
||||||
return GET(MdUtil.baseUrl + MdUtil.randMangaPage, cache = CacheControl.Builder().noCache().build())
|
return GET(MdUtil.baseUrl + MdUtil.randMangaPage, cache = CacheControl.Builder().noCache().build())
|
||||||
}
|
}
|
||||||
|
@ -40,6 +40,8 @@ class MangaDexSearchMetadata : RaisedSearchMetadata() {
|
|||||||
|
|
||||||
var follow_status: Int? = null
|
var follow_status: Int? = null
|
||||||
|
|
||||||
|
var maxChapterNumber: Int? = null
|
||||||
|
|
||||||
override fun createMangaInfo(manga: MangaInfo): MangaInfo {
|
override fun createMangaInfo(manga: MangaInfo): MangaInfo {
|
||||||
val key = mdUrl?.let {
|
val key = mdUrl?.let {
|
||||||
try {
|
try {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user