feat(MangaDex): use tracker links to associate mangas automatically with trackers (#1387)
* feat: add searchById support to trackers (MAL, AniList, MangaUpdates only) * feat: add new preference to toggle auto selection of tracker items using source metadata if available * feat: add new preference to toggle auto selection of tracker items using source metadata if available * feat: add automatic title selection using source metadata to TrackInfoDialog.kt * style: apply spotless * refactor: remove hardcoded MangaDexSearchMetadata cast and introduce common interface
This commit is contained in:
parent
8d062cecfd
commit
217503eab0
@ -42,4 +42,11 @@ class TrackPreferences(
|
||||
"pref_auto_update_manga_on_mark_read",
|
||||
AutoTrackState.ALWAYS,
|
||||
)
|
||||
|
||||
// SY -->
|
||||
fun resolveUsingSourceMetadata() = preferenceStore.getBoolean(
|
||||
"pref_resolve_using_source_metadata_key",
|
||||
true,
|
||||
)
|
||||
// SY <--
|
||||
}
|
||||
|
@ -59,6 +59,7 @@ import tachiyomi.core.common.util.lang.launchIO
|
||||
import tachiyomi.core.common.util.lang.withUIContext
|
||||
import tachiyomi.domain.source.service.SourceManager
|
||||
import tachiyomi.i18n.MR
|
||||
import tachiyomi.i18n.sy.SYMR
|
||||
import tachiyomi.presentation.core.components.material.padding
|
||||
import tachiyomi.presentation.core.i18n.stringResource
|
||||
import uy.kohesive.injekt.Injekt
|
||||
@ -135,6 +136,13 @@ object SettingsTrackingScreen : SearchableSettings {
|
||||
.associateWith { stringResource(it.titleRes) }
|
||||
.toPersistentMap(),
|
||||
),
|
||||
// SY -->
|
||||
Preference.PreferenceItem.SwitchPreference(
|
||||
pref = trackPreferences.resolveUsingSourceMetadata(),
|
||||
title = stringResource(SYMR.strings.pref_tracker_resolve_using_source_metadata),
|
||||
subtitle = stringResource(SYMR.strings.pref_tracker_resolve_using_source_metadata_summary),
|
||||
),
|
||||
// SY <--
|
||||
Preference.PreferenceGroup(
|
||||
title = stringResource(MR.strings.services),
|
||||
preferenceItems = persistentListOf(
|
||||
|
@ -7,6 +7,7 @@ import eu.kanade.domain.track.model.toDomainTrack
|
||||
import eu.kanade.domain.track.service.TrackPreferences
|
||||
import eu.kanade.tachiyomi.data.database.models.Track
|
||||
import eu.kanade.tachiyomi.data.track.model.TrackMangaMetadata
|
||||
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
||||
import eu.kanade.tachiyomi.network.NetworkHelper
|
||||
import eu.kanade.tachiyomi.util.system.toast
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
@ -125,6 +126,12 @@ abstract class BaseTracker(
|
||||
throw NotImplementedError("Not implemented.")
|
||||
}
|
||||
|
||||
// SY -->
|
||||
override suspend fun searchById(id: String): TrackSearch? {
|
||||
throw NotImplementedError("Not implemented.")
|
||||
}
|
||||
// SY <--
|
||||
|
||||
private suspend fun updateRemote(track: Track): Unit = withIOContext {
|
||||
try {
|
||||
update(track)
|
||||
|
@ -85,4 +85,8 @@ interface Tracker {
|
||||
suspend fun setRemoteFinishDate(track: Track, epochMillis: Long)
|
||||
|
||||
suspend fun getMangaMetadata(track: DomainTrack): TrackMangaMetadata?
|
||||
|
||||
// SY -->
|
||||
suspend fun searchById(id: String): TrackSearch?
|
||||
// SY <--
|
||||
}
|
||||
|
@ -237,6 +237,12 @@ class Anilist(id: Long) : BaseTracker(id, "AniList"), DeletableTracker {
|
||||
return api.getMangaMetadata(track)
|
||||
}
|
||||
|
||||
// SY -->
|
||||
override suspend fun searchById(id: String): TrackSearch {
|
||||
return api.searchById(id)
|
||||
}
|
||||
// SY <--
|
||||
|
||||
fun saveOAuth(alOAuth: ALOAuth?) {
|
||||
trackPreferences.trackToken(this).set(json.encodeToString(alOAuth))
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import androidx.core.net.toUri
|
||||
import eu.kanade.tachiyomi.data.database.models.Track
|
||||
import eu.kanade.tachiyomi.data.track.anilist.dto.ALAddMangaResult
|
||||
import eu.kanade.tachiyomi.data.track.anilist.dto.ALCurrentUserResult
|
||||
import eu.kanade.tachiyomi.data.track.anilist.dto.ALIdSearchResult
|
||||
import eu.kanade.tachiyomi.data.track.anilist.dto.ALMangaMetadata
|
||||
import eu.kanade.tachiyomi.data.track.anilist.dto.ALOAuth
|
||||
import eu.kanade.tachiyomi.data.track.anilist.dto.ALSearchResult
|
||||
@ -356,6 +357,56 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
|
||||
}
|
||||
}
|
||||
|
||||
// SY -->
|
||||
suspend fun searchById(id: String): TrackSearch {
|
||||
return withIOContext {
|
||||
val query = """
|
||||
|query (${'$'}mangaId: Int!) {
|
||||
|Media (id: ${'$'}mangaId) {
|
||||
|id
|
||||
|title {
|
||||
|userPreferred
|
||||
|}
|
||||
|coverImage {
|
||||
|large
|
||||
|}
|
||||
|format
|
||||
|status
|
||||
|chapters
|
||||
|description
|
||||
|startDate {
|
||||
|year
|
||||
|month
|
||||
|day
|
||||
|}
|
||||
|averageScore
|
||||
|}
|
||||
|}
|
||||
|
|
||||
""".trimMargin()
|
||||
val payload = buildJsonObject {
|
||||
put("query", query)
|
||||
putJsonObject("variables") {
|
||||
put("mangaId", id)
|
||||
}
|
||||
}
|
||||
with(json) {
|
||||
authClient.newCall(
|
||||
POST(
|
||||
API_URL,
|
||||
body = payload.toString().toRequestBody(jsonMime),
|
||||
),
|
||||
)
|
||||
.awaitSuccess()
|
||||
.parseAs<ALIdSearchResult>()
|
||||
.data.media
|
||||
.toALManga()
|
||||
.toTrack()
|
||||
}
|
||||
}
|
||||
}
|
||||
// SY <--
|
||||
|
||||
private fun createDate(dateValue: Long): JsonObject {
|
||||
if (dateValue == 0L) {
|
||||
return buildJsonObject {
|
||||
|
@ -18,3 +18,16 @@ data class ALSearchPage(
|
||||
data class ALSearchMedia(
|
||||
val media: List<ALSearchItem>,
|
||||
)
|
||||
|
||||
// SY -->
|
||||
@Serializable
|
||||
data class ALIdSearchResult(
|
||||
val data: ALIdSearchMedia,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class ALIdSearchMedia(
|
||||
@SerialName("Media")
|
||||
val media: ALSearchItem,
|
||||
)
|
||||
// SY <--
|
||||
|
@ -133,6 +133,29 @@ class MangaUpdates(id: Long) : BaseTracker(id, "MangaUpdates"), DeletableTracker
|
||||
}
|
||||
}
|
||||
|
||||
// SY -->
|
||||
override suspend fun searchById(id: String): TrackSearch? {
|
||||
/*
|
||||
* MangaUpdates uses newer base36 IDs (in URLs displayed as an encoded string, internally as a long)
|
||||
* as well as older sequential numeric IDs, which were phased out to prevent heavy load caused by
|
||||
* database scraping. Unfortunately, sites like MD sometimes still provides links with the old IDs,
|
||||
* so we need to convert them.
|
||||
* Because the API only accepts the newer IDs, we are forced to access the legacy non-API website
|
||||
* (ex. https://www.mangaupdates.com/series.html?id=15), which is a permanent redirect (HTTP 308) to the new one.
|
||||
*/
|
||||
|
||||
val base36Id = if (id.matches(Regex("""^\d+$"""))) {
|
||||
api.convertToNewId(id.toInt()) ?: return null
|
||||
} else {
|
||||
id
|
||||
}
|
||||
|
||||
return base36Id.toLong(36).let { longId ->
|
||||
api.getSeries(longId).toTrackSearch(this.id)
|
||||
}
|
||||
}
|
||||
// SY <--
|
||||
|
||||
fun restoreSession(): String? {
|
||||
return trackPreferences.trackPassword(this).get().ifBlank { null }
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ import eu.kanade.tachiyomi.network.DELETE
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.network.POST
|
||||
import eu.kanade.tachiyomi.network.PUT
|
||||
import eu.kanade.tachiyomi.network.await
|
||||
import eu.kanade.tachiyomi.network.awaitSuccess
|
||||
import eu.kanade.tachiyomi.network.parseAs
|
||||
import kotlinx.serialization.json.Json
|
||||
@ -25,6 +26,7 @@ import kotlinx.serialization.json.putJsonObject
|
||||
import okhttp3.MediaType.Companion.toMediaType
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.RequestBody.Companion.toRequestBody
|
||||
import okhttp3.Response
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import tachiyomi.domain.track.model.Track as DomainTrack
|
||||
|
||||
@ -190,14 +192,35 @@ class MangaUpdatesApi(
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun getSeries(track: DomainTrack): MURecord {
|
||||
suspend fun getSeries(track: DomainTrack): MURecord =
|
||||
getSeries(track.remoteId)
|
||||
|
||||
// SY -->
|
||||
suspend fun getSeries(remoteId: Long): MURecord {
|
||||
return with(json) {
|
||||
client.newCall(GET("$BASE_URL/v1/series/${track.remoteId}"))
|
||||
client.newCall(GET("$BASE_URL/v1/series/$remoteId"))
|
||||
.awaitSuccess()
|
||||
.parseAs<MURecord>()
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun convertToNewId(legacyId: Int): String? =
|
||||
client.newBuilder()
|
||||
.followRedirects(false)
|
||||
.build()
|
||||
.newCall(GET("https://www.mangaupdates.com/series.html?id=$legacyId"))
|
||||
.await()
|
||||
.takeIf(Response::isRedirect)
|
||||
?.header("Location")
|
||||
?.let {
|
||||
// Extract the new id from the redirected URL
|
||||
Regex("""/series/(\w+)(/([\w-]+)?)?/?${'$'}""")
|
||||
.find(it)
|
||||
?.groups?.get(1)
|
||||
?.value
|
||||
}
|
||||
// SY <--
|
||||
|
||||
companion object {
|
||||
private const val BASE_URL = "https://api.mangaupdates.com"
|
||||
|
||||
|
@ -11,7 +11,6 @@ import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
||||
import eu.kanade.tachiyomi.data.track.myanimelist.dto.MALOAuth
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
import tachiyomi.i18n.MR
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
@ -161,6 +160,12 @@ class MyAnimeList(id: Long) : BaseTracker(id, "MyAnimeList"), DeletableTracker {
|
||||
return api.getMangaMetadata(track)
|
||||
}
|
||||
|
||||
// SY -->
|
||||
override suspend fun searchById(id: String): TrackSearch {
|
||||
return api.getMangaDetails(id.toInt())
|
||||
}
|
||||
// SY <--
|
||||
|
||||
fun getIfAuthExpired(): Boolean {
|
||||
return trackPreferences.trackAuthExpired(this).get()
|
||||
}
|
||||
|
@ -2,17 +2,20 @@ package eu.kanade.tachiyomi.ui.manga.track
|
||||
|
||||
import android.app.Application
|
||||
import android.content.Context
|
||||
import androidx.compose.animation.animateContentSize
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.systemBars
|
||||
import androidx.compose.foundation.layout.windowInsetsPadding
|
||||
import androidx.compose.foundation.text.input.rememberTextFieldState
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Delete
|
||||
import androidx.compose.material3.ButtonDefaults
|
||||
import androidx.compose.material3.CircularProgressIndicator
|
||||
import androidx.compose.material3.FilledTonalButton
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
@ -30,6 +33,8 @@ import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import cafe.adriel.voyager.core.model.ScreenModel
|
||||
import cafe.adriel.voyager.core.model.StateScreenModel
|
||||
import cafe.adriel.voyager.core.model.rememberScreenModel
|
||||
@ -40,6 +45,7 @@ import cafe.adriel.voyager.navigator.currentOrThrow
|
||||
import dev.icerock.moko.resources.StringResource
|
||||
import eu.kanade.domain.track.interactor.RefreshTracks
|
||||
import eu.kanade.domain.track.model.toDbTrack
|
||||
import eu.kanade.domain.track.service.TrackPreferences
|
||||
import eu.kanade.domain.ui.UiPreferences
|
||||
import eu.kanade.presentation.track.TrackChapterSelector
|
||||
import eu.kanade.presentation.track.TrackDateSelector
|
||||
@ -53,10 +59,13 @@ import eu.kanade.tachiyomi.data.track.EnhancedTracker
|
||||
import eu.kanade.tachiyomi.data.track.Tracker
|
||||
import eu.kanade.tachiyomi.data.track.TrackerManager
|
||||
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
||||
import eu.kanade.tachiyomi.source.online.MetadataSource
|
||||
import eu.kanade.tachiyomi.util.lang.convertEpochMillisZone
|
||||
import eu.kanade.tachiyomi.util.system.copyToClipboard
|
||||
import eu.kanade.tachiyomi.util.system.openInBrowser
|
||||
import eu.kanade.tachiyomi.util.system.toast
|
||||
import exh.metadata.metadata.base.TrackerIdMetadata
|
||||
import exh.source.getMainSource
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.coroutines.flow.catch
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
@ -70,6 +79,7 @@ import tachiyomi.core.common.util.lang.launchNonCancellable
|
||||
import tachiyomi.core.common.util.lang.withIOContext
|
||||
import tachiyomi.core.common.util.lang.withUIContext
|
||||
import tachiyomi.core.common.util.system.logcat
|
||||
import tachiyomi.domain.manga.interactor.GetFlatMetadataById
|
||||
import tachiyomi.domain.manga.interactor.GetManga
|
||||
import tachiyomi.domain.source.service.SourceManager
|
||||
import tachiyomi.domain.track.interactor.DeleteTrack
|
||||
@ -102,77 +112,94 @@ data class TrackInfoDialogHomeScreen(
|
||||
val dateFormat = remember { UiPreferences.dateFormat(Injekt.get<UiPreferences>().dateFormat().get()) }
|
||||
val state by screenModel.state.collectAsState()
|
||||
|
||||
TrackInfoDialogHome(
|
||||
trackItems = state.trackItems,
|
||||
dateFormat = dateFormat,
|
||||
onStatusClick = {
|
||||
navigator.push(
|
||||
TrackStatusSelectorScreen(
|
||||
track = it.track!!,
|
||||
serviceId = it.tracker.id,
|
||||
),
|
||||
)
|
||||
},
|
||||
onChapterClick = {
|
||||
navigator.push(
|
||||
TrackChapterSelectorScreen(
|
||||
track = it.track!!,
|
||||
serviceId = it.tracker.id,
|
||||
),
|
||||
)
|
||||
},
|
||||
onScoreClick = {
|
||||
navigator.push(
|
||||
TrackScoreSelectorScreen(
|
||||
track = it.track!!,
|
||||
serviceId = it.tracker.id,
|
||||
),
|
||||
)
|
||||
},
|
||||
onStartDateEdit = {
|
||||
navigator.push(
|
||||
TrackDateSelectorScreen(
|
||||
track = it.track!!,
|
||||
serviceId = it.tracker.id,
|
||||
start = true,
|
||||
),
|
||||
)
|
||||
},
|
||||
onEndDateEdit = {
|
||||
navigator.push(
|
||||
TrackDateSelectorScreen(
|
||||
track = it.track!!,
|
||||
serviceId = it.tracker.id,
|
||||
start = false,
|
||||
),
|
||||
)
|
||||
},
|
||||
onNewSearch = {
|
||||
if (it.tracker is EnhancedTracker) {
|
||||
screenModel.registerEnhancedTracking(it)
|
||||
} else {
|
||||
navigator.push(
|
||||
TrackerSearchScreen(
|
||||
mangaId = mangaId,
|
||||
initialQuery = it.track?.title ?: mangaTitle,
|
||||
currentUrl = it.track?.remoteUrl,
|
||||
serviceId = it.tracker.id,
|
||||
),
|
||||
// SY -->
|
||||
Column(modifier = Modifier.animateContentSize()) {
|
||||
if (state.isLoading) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(32.dp)
|
||||
.windowInsetsPadding(WindowInsets.systemBars),
|
||||
verticalArrangement = Arrangement.spacedBy(24.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
CircularProgressIndicator()
|
||||
Text(
|
||||
stringResource(MR.strings.loading),
|
||||
fontSize = 14.sp,
|
||||
)
|
||||
}
|
||||
},
|
||||
onOpenInBrowser = { openTrackerInBrowser(context, it) },
|
||||
onRemoved = {
|
||||
navigator.push(
|
||||
TrackerRemoveScreen(
|
||||
mangaId = mangaId,
|
||||
track = it.track!!,
|
||||
serviceId = it.tracker.id,
|
||||
),
|
||||
}
|
||||
// SY <--
|
||||
else {
|
||||
TrackInfoDialogHome(
|
||||
trackItems = state.trackItems,
|
||||
dateFormat = dateFormat,
|
||||
onStatusClick = {
|
||||
navigator.push(
|
||||
TrackStatusSelectorScreen(
|
||||
track = it.track!!,
|
||||
serviceId = it.tracker.id,
|
||||
),
|
||||
)
|
||||
},
|
||||
onChapterClick = {
|
||||
navigator.push(
|
||||
TrackChapterSelectorScreen(
|
||||
track = it.track!!,
|
||||
serviceId = it.tracker.id,
|
||||
),
|
||||
)
|
||||
},
|
||||
onScoreClick = {
|
||||
navigator.push(
|
||||
TrackScoreSelectorScreen(
|
||||
track = it.track!!,
|
||||
serviceId = it.tracker.id,
|
||||
),
|
||||
)
|
||||
},
|
||||
onStartDateEdit = {
|
||||
navigator.push(
|
||||
TrackDateSelectorScreen(
|
||||
track = it.track!!,
|
||||
serviceId = it.tracker.id,
|
||||
start = true,
|
||||
),
|
||||
)
|
||||
},
|
||||
onEndDateEdit = {
|
||||
navigator.push(
|
||||
TrackDateSelectorScreen(
|
||||
track = it.track!!,
|
||||
serviceId = it.tracker.id,
|
||||
start = false,
|
||||
),
|
||||
)
|
||||
},
|
||||
onNewSearch = {
|
||||
if (it.tracker is EnhancedTracker) {
|
||||
screenModel.registerEnhancedTracking(it)
|
||||
} else {
|
||||
// SY -->
|
||||
screenModel.newSearch(navigator, it, mangaTitle)
|
||||
// SY <--
|
||||
}
|
||||
},
|
||||
onOpenInBrowser = { openTrackerInBrowser(context, it) },
|
||||
onRemoved = {
|
||||
navigator.push(
|
||||
TrackerRemoveScreen(
|
||||
mangaId = mangaId,
|
||||
track = it.track!!,
|
||||
serviceId = it.tracker.id,
|
||||
),
|
||||
)
|
||||
},
|
||||
onCopyLink = { context.copyTrackerLink(it) },
|
||||
)
|
||||
},
|
||||
onCopyLink = { context.copyTrackerLink(it) },
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -196,6 +223,10 @@ data class TrackInfoDialogHomeScreen(
|
||||
private val mangaId: Long,
|
||||
private val sourceId: Long,
|
||||
private val getTracks: GetTracks = Injekt.get(),
|
||||
/* SY --> */
|
||||
private val trackerManager: TrackerManager = Injekt.get(),
|
||||
private val trackPreferences: TrackPreferences = Injekt.get(),
|
||||
/* SY <-- */
|
||||
) : StateScreenModel<Model.State>(State()) {
|
||||
|
||||
init {
|
||||
@ -225,6 +256,79 @@ data class TrackInfoDialogHomeScreen(
|
||||
}
|
||||
}
|
||||
|
||||
// SY -->
|
||||
fun newSearch(navigator: Navigator, item: TrackItem, mangaTitle: String) {
|
||||
screenModelScope.launchNonCancellable {
|
||||
if (trackPreferences.resolveUsingSourceMetadata().get()) {
|
||||
// Check if the tracker id is contained in the metadata
|
||||
val result = getTrackerIdFromMetadata(item.tracker.id)
|
||||
if (result != null) {
|
||||
mutableState.update { it.copy(isLoading = true) }
|
||||
|
||||
// Try to register tracking by id
|
||||
val success = registerTrackingById(item.tracker.id, result)
|
||||
|
||||
mutableState.update { it.copy(isLoading = false) }
|
||||
|
||||
if (success) {
|
||||
// Return on success
|
||||
return@launchNonCancellable
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Open search screen
|
||||
navigator.push(
|
||||
TrackerSearchScreen(
|
||||
mangaId = mangaId,
|
||||
initialQuery = item.track?.title ?: mangaTitle,
|
||||
currentUrl = item.track?.remoteUrl,
|
||||
serviceId = item.tracker.id,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun getTrackerIdFromMetadata(trackerId: Long): String? {
|
||||
try {
|
||||
val sourceManager = Injekt.get<SourceManager>()
|
||||
val getFlatMetadataById = Injekt.get<GetFlatMetadataById>()
|
||||
|
||||
val metadataSource = sourceManager.get(sourceId)
|
||||
?.getMainSource<MetadataSource<*, *>>() ?: return null
|
||||
|
||||
return getFlatMetadataById.await(mangaId)?.run {
|
||||
raise(metadataSource.metaClass) as? TrackerIdMetadata
|
||||
}?.let { metadata ->
|
||||
when (trackerId) {
|
||||
trackerManager.aniList.id -> metadata.anilistId
|
||||
trackerManager.kitsu.id -> metadata.kitsuId
|
||||
trackerManager.myAnimeList.id -> metadata.myAnimeListId
|
||||
trackerManager.mangaUpdates.id -> metadata.mangaUpdatesId
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
} catch (e: Throwable) {
|
||||
logcat(LogPriority.ERROR, e) { "Failed to search manga on tracker by id" }
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun registerTrackingById(trackerId: Long, remoteId: String): Boolean {
|
||||
trackerManager.get(trackerId)?.let { tracker ->
|
||||
try {
|
||||
tracker.searchById(remoteId)?.let { track ->
|
||||
tracker.register(track, mangaId)
|
||||
return true
|
||||
}
|
||||
} catch (e: Throwable) {
|
||||
logcat(LogPriority.ERROR, e) { "Failed to register tracking by id" }
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
// SY <--
|
||||
|
||||
private suspend fun refreshTrackers() {
|
||||
val refreshTracks = Injekt.get<RefreshTracks>()
|
||||
val context = Injekt.get<Application>()
|
||||
@ -260,6 +364,9 @@ data class TrackInfoDialogHomeScreen(
|
||||
@Immutable
|
||||
data class State(
|
||||
val trackItems: List<TrackItem> = emptyList(),
|
||||
// SY -->
|
||||
val isLoading: Boolean = false,
|
||||
// SY <--
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -125,4 +125,6 @@ data class DummyTracker(
|
||||
): eu.kanade.tachiyomi.data.track.model.TrackMangaMetadata = eu.kanade.tachiyomi.data.track.model.TrackMangaMetadata(
|
||||
0, "test", "test", "test", "test", "test",
|
||||
)
|
||||
|
||||
override suspend fun searchById(id: String) = null
|
||||
}
|
||||
|
@ -176,6 +176,10 @@
|
||||
<string name="pref_hide_history_button">Show history in the nav</string>
|
||||
<string name="pref_show_bottom_bar_labels">Always show nav labels</string>
|
||||
|
||||
<!-- Tracker settings -->
|
||||
<string name="pref_tracker_resolve_using_source_metadata">Select entries using source metadata</string>
|
||||
<string name="pref_tracker_resolve_using_source_metadata_summary">Automatically selects the matching title if the source provides links to trackers. Currently supported by MangaDex</string>
|
||||
|
||||
<!-- Library settings -->
|
||||
<string name="pref_sorting_settings">Sorting Settings</string>
|
||||
<string name="pref_skip_pre_migration_summary">Use last saved pre-migration preferences and sources to mass migrate</string>
|
||||
|
@ -4,13 +4,14 @@ import android.content.Context
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import eu.kanade.tachiyomi.source.model.copy
|
||||
import exh.md.utils.MangaDexRelation
|
||||
import exh.metadata.metadata.base.TrackerIdMetadata
|
||||
import kotlinx.serialization.Serializable
|
||||
import tachiyomi.core.common.i18n.stringResource
|
||||
import tachiyomi.i18n.MR
|
||||
import tachiyomi.i18n.sy.SYMR
|
||||
|
||||
@Serializable
|
||||
class MangaDexSearchMetadata : RaisedSearchMetadata() {
|
||||
class MangaDexSearchMetadata : RaisedSearchMetadata(), TrackerIdMetadata {
|
||||
var mdUuid: String? = null
|
||||
|
||||
// var mdUrl: String? = null
|
||||
@ -31,11 +32,11 @@ class MangaDexSearchMetadata : RaisedSearchMetadata() {
|
||||
var rating: Float? = null
|
||||
// var users: String? = null
|
||||
|
||||
var anilistId: String? = null
|
||||
var kitsuId: String? = null
|
||||
var myAnimeListId: String? = null
|
||||
var mangaUpdatesId: String? = null
|
||||
var animePlanetId: String? = null
|
||||
override var anilistId: String? = null
|
||||
override var kitsuId: String? = null
|
||||
override var myAnimeListId: String? = null
|
||||
override var mangaUpdatesId: String? = null
|
||||
override var animePlanetId: String? = null
|
||||
|
||||
var status: Int? = null
|
||||
|
||||
|
@ -0,0 +1,9 @@
|
||||
package exh.metadata.metadata.base
|
||||
|
||||
interface TrackerIdMetadata {
|
||||
var anilistId: String?
|
||||
var kitsuId: String?
|
||||
var myAnimeListId: String?
|
||||
var mangaUpdatesId: String?
|
||||
var animePlanetId: String?
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user