diff --git a/app/src/main/java/eu/kanade/domain/track/service/TrackPreferences.kt b/app/src/main/java/eu/kanade/domain/track/service/TrackPreferences.kt index d07bc715d..e1e9100ce 100644 --- a/app/src/main/java/eu/kanade/domain/track/service/TrackPreferences.kt +++ b/app/src/main/java/eu/kanade/domain/track/service/TrackPreferences.kt @@ -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 <-- } diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsTrackingScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsTrackingScreen.kt index 2a7231112..54e3ada14 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsTrackingScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsTrackingScreen.kt @@ -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( diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/BaseTracker.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/BaseTracker.kt index ce98908ae..a8143dcda 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/BaseTracker.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/BaseTracker.kt @@ -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) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/Tracker.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/Tracker.kt index 28ee93956..4a297a2e9 100755 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/Tracker.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/Tracker.kt @@ -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 <-- } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/Anilist.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/Anilist.kt index d401f8f98..e35d77551 100755 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/Anilist.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/Anilist.kt @@ -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)) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/AnilistApi.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/AnilistApi.kt index 2e0f98ea0..efe77cbe4 100755 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/AnilistApi.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/AnilistApi.kt @@ -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() + .data.media + .toALManga() + .toTrack() + } + } + } + // SY <-- + private fun createDate(dateValue: Long): JsonObject { if (dateValue == 0L) { return buildJsonObject { diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/dto/ALSearch.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/dto/ALSearch.kt index f13ebb400..c84d28c3e 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/dto/ALSearch.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/dto/ALSearch.kt @@ -18,3 +18,16 @@ data class ALSearchPage( data class ALSearchMedia( val media: List, ) + +// SY --> +@Serializable +data class ALIdSearchResult( + val data: ALIdSearchMedia, +) + +@Serializable +data class ALIdSearchMedia( + @SerialName("Media") + val media: ALSearchItem, +) +// SY <-- diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/mangaupdates/MangaUpdates.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/mangaupdates/MangaUpdates.kt index b16b3ffe4..c86e521fc 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/mangaupdates/MangaUpdates.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/mangaupdates/MangaUpdates.kt @@ -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 } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/mangaupdates/MangaUpdatesApi.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/mangaupdates/MangaUpdatesApi.kt index 8f85e9a5b..d80c85ffc 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/mangaupdates/MangaUpdatesApi.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/mangaupdates/MangaUpdatesApi.kt @@ -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() } } + 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" diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeList.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeList.kt index 59233fb87..8d8c9d2b6 100755 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeList.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeList.kt @@ -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() } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackInfoDialog.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackInfoDialog.kt index 3541be7ac..dacdeb382 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackInfoDialog.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackInfoDialog.kt @@ -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().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(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() + val getFlatMetadataById = Injekt.get() + + val metadataSource = sourceManager.get(sourceId) + ?.getMainSource>() ?: 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() val context = Injekt.get() @@ -260,6 +364,9 @@ data class TrackInfoDialogHomeScreen( @Immutable data class State( val trackItems: List = emptyList(), + // SY --> + val isLoading: Boolean = false, + // SY <-- ) } } diff --git a/app/src/main/java/eu/kanade/test/DummyTracker.kt b/app/src/main/java/eu/kanade/test/DummyTracker.kt index 1c1064c99..596037b18 100644 --- a/app/src/main/java/eu/kanade/test/DummyTracker.kt +++ b/app/src/main/java/eu/kanade/test/DummyTracker.kt @@ -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 } diff --git a/i18n-sy/src/commonMain/moko-resources/base/strings.xml b/i18n-sy/src/commonMain/moko-resources/base/strings.xml index 4a45fe9ce..88096bb30 100644 --- a/i18n-sy/src/commonMain/moko-resources/base/strings.xml +++ b/i18n-sy/src/commonMain/moko-resources/base/strings.xml @@ -176,6 +176,10 @@ Show history in the nav Always show nav labels + + Select entries using source metadata + Automatically selects the matching title if the source provides links to trackers. Currently supported by MangaDex + Sorting Settings Use last saved pre-migration preferences and sources to mass migrate diff --git a/source-api/src/commonMain/kotlin/exh/metadata/metadata/MangaDexSearchMetadata.kt b/source-api/src/commonMain/kotlin/exh/metadata/metadata/MangaDexSearchMetadata.kt index 468058cae..d01c72f1c 100644 --- a/source-api/src/commonMain/kotlin/exh/metadata/metadata/MangaDexSearchMetadata.kt +++ b/source-api/src/commonMain/kotlin/exh/metadata/metadata/MangaDexSearchMetadata.kt @@ -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 diff --git a/source-api/src/commonMain/kotlin/exh/metadata/metadata/base/TrackerIdMetadata.kt b/source-api/src/commonMain/kotlin/exh/metadata/metadata/base/TrackerIdMetadata.kt new file mode 100644 index 000000000..388e518b4 --- /dev/null +++ b/source-api/src/commonMain/kotlin/exh/metadata/metadata/base/TrackerIdMetadata.kt @@ -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? +}