From 98d6ce2eaf2c1e85f4763dd37303155d1fc6690d Mon Sep 17 00:00:00 2001 From: arkon Date: Sun, 27 Aug 2023 10:41:58 -0400 Subject: [PATCH] Refactor some tracking-related logic --- .../java/eu/kanade/domain/DomainModule.kt | 4 +- ...Way.kt => SyncChapterProgressWithTrack.kt} | 2 +- .../domain/track/interactor/RefreshTracks.kt | 31 ++++++---- .../library/LibrarySettingsDialog.kt | 2 +- .../settings/screen/SettingsTrackingScreen.kt | 22 ++++--- .../widget/TrackingPreferenceWidget.kt | 2 +- .../track/components/TrackLogoIcon.kt | 3 +- .../data/backup/BackupFileValidator.kt | 2 +- .../data/library/LibraryUpdateJob.kt | 11 +++- .../tachiyomi/data/track/TrackManager.kt | 2 +- .../tachiyomi/data/track/TrackService.kt | 14 ++--- .../tachiyomi/data/track/anilist/Anilist.kt | 5 +- .../tachiyomi/data/track/bangumi/Bangumi.kt | 5 +- .../tachiyomi/data/track/kavita/Kavita.kt | 5 +- .../tachiyomi/data/track/kavita/KavitaApi.kt | 16 ++--- .../tachiyomi/data/track/kitsu/Kitsu.kt | 5 +- .../tachiyomi/data/track/komga/Komga.kt | 6 +- .../tachiyomi/data/track/komga/KomgaApi.kt | 2 +- .../data/track/mangaupdates/MangaUpdates.kt | 5 +- .../data/track/myanimelist/MyAnimeList.kt | 5 +- .../data/track/shikimori/Shikimori.kt | 5 +- .../data/track/shikimori/ShikimoriApi.kt | 4 +- .../tachiyomi/data/track/suwayomi/Suwayomi.kt | 5 +- .../data/track/suwayomi/TachideskApi.kt | 16 ++--- .../source/browse/BrowseSourceScreenModel.kt | 6 +- .../tachiyomi/ui/manga/MangaScreenModel.kt | 2 +- .../ui/manga/track/TrackInfoDialog.kt | 59 +++++++------------ i18n/src/main/res/values/strings.xml | 9 --- 28 files changed, 104 insertions(+), 151 deletions(-) rename app/src/main/java/eu/kanade/domain/chapter/interactor/{SyncChaptersWithTrackServiceTwoWay.kt => SyncChapterProgressWithTrack.kt} (97%) diff --git a/app/src/main/java/eu/kanade/domain/DomainModule.kt b/app/src/main/java/eu/kanade/domain/DomainModule.kt index b245d90574..494033c877 100644 --- a/app/src/main/java/eu/kanade/domain/DomainModule.kt +++ b/app/src/main/java/eu/kanade/domain/DomainModule.kt @@ -1,8 +1,8 @@ package eu.kanade.domain import eu.kanade.domain.chapter.interactor.SetReadStatus +import eu.kanade.domain.chapter.interactor.SyncChapterProgressWithTrack import eu.kanade.domain.chapter.interactor.SyncChaptersWithSource -import eu.kanade.domain.chapter.interactor.SyncChaptersWithTrackServiceTwoWay import eu.kanade.domain.download.interactor.DeleteDownload import eu.kanade.domain.extension.interactor.GetExtensionLanguages import eu.kanade.domain.extension.interactor.GetExtensionSources @@ -127,7 +127,7 @@ class DomainModule : InjektModule { addFactory { SetReadStatus(get(), get(), get(), get()) } addFactory { ShouldUpdateDbChapter() } addFactory { SyncChaptersWithSource(get(), get(), get(), get(), get(), get(), get()) } - addFactory { SyncChaptersWithTrackServiceTwoWay(get(), get(), get()) } + addFactory { SyncChapterProgressWithTrack(get(), get(), get()) } addSingletonFactory { HistoryRepositoryImpl(get()) } addFactory { GetHistory(get()) } diff --git a/app/src/main/java/eu/kanade/domain/chapter/interactor/SyncChaptersWithTrackServiceTwoWay.kt b/app/src/main/java/eu/kanade/domain/chapter/interactor/SyncChapterProgressWithTrack.kt similarity index 97% rename from app/src/main/java/eu/kanade/domain/chapter/interactor/SyncChaptersWithTrackServiceTwoWay.kt rename to app/src/main/java/eu/kanade/domain/chapter/interactor/SyncChapterProgressWithTrack.kt index ddd8ebaa3c..86862504c2 100644 --- a/app/src/main/java/eu/kanade/domain/chapter/interactor/SyncChaptersWithTrackServiceTwoWay.kt +++ b/app/src/main/java/eu/kanade/domain/chapter/interactor/SyncChapterProgressWithTrack.kt @@ -11,7 +11,7 @@ import tachiyomi.domain.chapter.model.toChapterUpdate import tachiyomi.domain.track.interactor.InsertTrack import tachiyomi.domain.track.model.Track -class SyncChaptersWithTrackServiceTwoWay( +class SyncChapterProgressWithTrack( private val updateChapter: UpdateChapter, private val insertTrack: InsertTrack, private val getChapterByMangaId: GetChapterByMangaId, diff --git a/app/src/main/java/eu/kanade/domain/track/interactor/RefreshTracks.kt b/app/src/main/java/eu/kanade/domain/track/interactor/RefreshTracks.kt index dbff0e934a..87b7c8d990 100644 --- a/app/src/main/java/eu/kanade/domain/track/interactor/RefreshTracks.kt +++ b/app/src/main/java/eu/kanade/domain/track/interactor/RefreshTracks.kt @@ -1,14 +1,13 @@ package eu.kanade.domain.track.interactor -import eu.kanade.domain.chapter.interactor.SyncChaptersWithTrackServiceTwoWay +import eu.kanade.domain.chapter.interactor.SyncChapterProgressWithTrack import eu.kanade.domain.track.model.toDbTrack import eu.kanade.domain.track.model.toDomainTrack import eu.kanade.tachiyomi.data.track.TrackManager +import eu.kanade.tachiyomi.data.track.TrackService import kotlinx.coroutines.async import kotlinx.coroutines.awaitAll import kotlinx.coroutines.supervisorScope -import logcat.LogPriority -import tachiyomi.core.util.system.logcat import tachiyomi.domain.track.interactor.GetTracks import tachiyomi.domain.track.interactor.InsertTrack @@ -16,28 +15,34 @@ class RefreshTracks( private val getTracks: GetTracks, private val trackManager: TrackManager, private val insertTrack: InsertTrack, - private val syncChaptersWithTrackServiceTwoWay: SyncChaptersWithTrackServiceTwoWay, + private val syncChapterProgressWithTrack: SyncChapterProgressWithTrack, ) { - suspend fun await(mangaId: Long) { - supervisorScope { - getTracks.await(mangaId) + /** + * Fetches updated tracking data from all logged in trackers. + * + * @return Failed updates. + */ + suspend fun await(mangaId: Long): List> { + return supervisorScope { + return@supervisorScope getTracks.await(mangaId) .map { track -> async { val service = trackManager.getService(track.syncId) - if (service != null && service.isLoggedIn) { - try { + return@async try { + if (service?.isLoggedIn == true) { val updatedTrack = service.refresh(track.toDbTrack()) insertTrack.await(updatedTrack.toDomainTrack()!!) - syncChaptersWithTrackServiceTwoWay.await(mangaId, track, service) - } catch (e: Throwable) { - // Ignore errors and continue - logcat(LogPriority.ERROR, e) + syncChapterProgressWithTrack.await(mangaId, track, service) } + null + } catch (e: Throwable) { + service to e } } } .awaitAll() + .filterNotNull() } } } diff --git a/app/src/main/java/eu/kanade/presentation/library/LibrarySettingsDialog.kt b/app/src/main/java/eu/kanade/presentation/library/LibrarySettingsDialog.kt index aaf8469438..0c8a802171 100644 --- a/app/src/main/java/eu/kanade/presentation/library/LibrarySettingsDialog.kt +++ b/app/src/main/java/eu/kanade/presentation/library/LibrarySettingsDialog.kt @@ -127,7 +127,7 @@ private fun ColumnScope.FilterPage( trackServices.map { service -> val filterTracker by screenModel.libraryPreferences.filterTracking(service.id.toInt()).collectAsState() TriStateItem( - label = stringResource(service.nameRes()), + label = service.name, state = filterTracker, onClick = { screenModel.toggleTracker(service.id.toInt()) }, ) 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 4091f56fa7..3b4df1e0b5 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 @@ -114,9 +114,7 @@ object SettingsTrackingScreen : SearchableSettings { if (enhancedTrackers.second.isNotEmpty()) { val missingSourcesInfo = stringResource( R.string.enhanced_services_not_installed, - enhancedTrackers.second - .map { stringResource(it.nameRes()) } - .joinToString(), + enhancedTrackers.second.joinToString { it.name }, ) enhancedTrackerInfo += "\n\n$missingSourcesInfo" } @@ -130,37 +128,37 @@ object SettingsTrackingScreen : SearchableSettings { title = stringResource(R.string.services), preferenceItems = listOf( Preference.PreferenceItem.TrackingPreference( - title = stringResource(trackManager.myAnimeList.nameRes()), + title = trackManager.myAnimeList.name, service = trackManager.myAnimeList, login = { context.openInBrowser(MyAnimeListApi.authUrl(), forceDefaultBrowser = true) }, logout = { dialog = LogoutDialog(trackManager.myAnimeList) }, ), Preference.PreferenceItem.TrackingPreference( - title = stringResource(trackManager.aniList.nameRes()), + title = trackManager.aniList.name, service = trackManager.aniList, login = { context.openInBrowser(AnilistApi.authUrl(), forceDefaultBrowser = true) }, logout = { dialog = LogoutDialog(trackManager.aniList) }, ), Preference.PreferenceItem.TrackingPreference( - title = stringResource(trackManager.kitsu.nameRes()), + title = trackManager.kitsu.name, service = trackManager.kitsu, login = { dialog = LoginDialog(trackManager.kitsu, R.string.email) }, logout = { dialog = LogoutDialog(trackManager.kitsu) }, ), Preference.PreferenceItem.TrackingPreference( - title = stringResource(trackManager.mangaUpdates.nameRes()), + title = trackManager.mangaUpdates.name, service = trackManager.mangaUpdates, login = { dialog = LoginDialog(trackManager.mangaUpdates, R.string.username) }, logout = { dialog = LogoutDialog(trackManager.mangaUpdates) }, ), Preference.PreferenceItem.TrackingPreference( - title = stringResource(trackManager.shikimori.nameRes()), + title = trackManager.shikimori.name, service = trackManager.shikimori, login = { context.openInBrowser(ShikimoriApi.authUrl(), forceDefaultBrowser = true) }, logout = { dialog = LogoutDialog(trackManager.shikimori) }, ), Preference.PreferenceItem.TrackingPreference( - title = stringResource(trackManager.bangumi.nameRes()), + title = trackManager.bangumi.name, service = trackManager.bangumi, login = { context.openInBrowser(BangumiApi.authUrl(), forceDefaultBrowser = true) }, logout = { dialog = LogoutDialog(trackManager.bangumi) }, @@ -173,7 +171,7 @@ object SettingsTrackingScreen : SearchableSettings { preferenceItems = enhancedTrackers.first .map { service -> Preference.PreferenceItem.TrackingPreference( - title = stringResource(service.nameRes()), + title = service.name, service = service, login = { (service as EnhancedTrackService).loginNoop() }, logout = service::logout, @@ -202,7 +200,7 @@ object SettingsTrackingScreen : SearchableSettings { title = { Row(verticalAlignment = Alignment.CenterVertically) { Text( - text = stringResource(R.string.login_title, stringResource(service.nameRes())), + text = stringResource(R.string.login_title, service.name), modifier = Modifier.weight(1f), ) IconButton(onClick = onDismissRequest) { @@ -310,7 +308,7 @@ object SettingsTrackingScreen : SearchableSettings { onDismissRequest = onDismissRequest, title = { Text( - text = stringResource(R.string.logout_title, stringResource(service.nameRes())), + text = stringResource(R.string.logout_title, service.name), textAlign = TextAlign.Center, modifier = Modifier.fillMaxWidth(), ) diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/widget/TrackingPreferenceWidget.kt b/app/src/main/java/eu/kanade/presentation/more/settings/widget/TrackingPreferenceWidget.kt index 8fcbc807da..e0c34fbc47 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/widget/TrackingPreferenceWidget.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/widget/TrackingPreferenceWidget.kt @@ -40,7 +40,7 @@ fun TrackingPreferenceWidget( ) { TrackLogoIcon(service) Text( - text = stringResource(service.nameRes()), + text = service.name, modifier = Modifier .weight(1f) .padding(horizontal = 16.dp), diff --git a/app/src/main/java/eu/kanade/presentation/track/components/TrackLogoIcon.kt b/app/src/main/java/eu/kanade/presentation/track/components/TrackLogoIcon.kt index 293faf62f4..44d98cbd21 100644 --- a/app/src/main/java/eu/kanade/presentation/track/components/TrackLogoIcon.kt +++ b/app/src/main/java/eu/kanade/presentation/track/components/TrackLogoIcon.kt @@ -11,7 +11,6 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import eu.kanade.tachiyomi.data.track.TrackService import tachiyomi.presentation.core.util.clickableNoIndication @@ -36,7 +35,7 @@ fun TrackLogoIcon( ) { Image( painter = painterResource(service.getLogo()), - contentDescription = stringResource(service.nameRes()), + contentDescription = service.name, ) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupFileValidator.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupFileValidator.kt index 56ac0b8e0a..0fe9ddff9f 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupFileValidator.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupFileValidator.kt @@ -52,7 +52,7 @@ class BackupFileValidator( val missingTrackers = trackers .mapNotNull { trackManager.getService(it.toLong()) } .filter { !it.isLoggedIn } - .map { context.getString(it.nameRes()) } + .map { it.name } .sorted() return Results(missingSources, missingTrackers) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateJob.kt b/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateJob.kt index 7b0c2b8f3e..cdca75770c 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateJob.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateJob.kt @@ -283,7 +283,7 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet } if (libraryPreferences.autoUpdateTrackers().get()) { - refreshTracks.await(manga.id) + refreshTracks(manga.id) } } } @@ -409,13 +409,20 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet val manga = libraryManga.manga notifier.showProgressNotification(listOf(manga), progressCount++, mangaToUpdate.size) - refreshTracks.await(manga.id) + refreshTracks(manga.id) } notifier.cancelProgressNotification() } } + private suspend fun refreshTracks(mangaId: Long) { + refreshTracks.await(mangaId).forEach { (_, e) -> + // Ignore errors and continue + logcat(LogPriority.ERROR, e) + } + } + private suspend fun withUpdateNotification( updatingManga: CopyOnWriteArrayList, completed: AtomicInteger, diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/TrackManager.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/TrackManager.kt index e668aea35e..c6d62c3821 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/TrackManager.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/TrackManager.kt @@ -30,7 +30,7 @@ class TrackManager(context: Context) { val kitsu = Kitsu(KITSU) val shikimori = Shikimori(SHIKIMORI) val bangumi = Bangumi(BANGUMI) - val komga = Komga(context, KOMGA) + val komga = Komga(KOMGA) val mangaUpdates = MangaUpdates(MANGA_UPDATES) val kavita = Kavita(context, KAVITA) val suwayomi = Suwayomi(SUWAYOMI) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/TrackService.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/TrackService.kt index 1a09579643..e30100e293 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/TrackService.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/TrackService.kt @@ -5,7 +5,7 @@ import androidx.annotation.CallSuper import androidx.annotation.ColorInt import androidx.annotation.DrawableRes import androidx.annotation.StringRes -import eu.kanade.domain.chapter.interactor.SyncChaptersWithTrackServiceTwoWay +import eu.kanade.domain.chapter.interactor.SyncChapterProgressWithTrack import eu.kanade.domain.track.model.toDbTrack import eu.kanade.domain.track.model.toDomainTrack import eu.kanade.domain.track.service.TrackPreferences @@ -28,20 +28,16 @@ import uy.kohesive.injekt.injectLazy import java.time.ZoneOffset import tachiyomi.domain.track.model.Track as DomainTrack -abstract class TrackService(val id: Long) { +abstract class TrackService(val id: Long, val name: String) { val trackPreferences: TrackPreferences by injectLazy() val networkService: NetworkHelper by injectLazy() private val insertTrack: InsertTrack by injectLazy() - private val syncChaptersWithTrackServiceTwoWay: SyncChaptersWithTrackServiceTwoWay by injectLazy() + private val syncChapterProgressWithTrack: SyncChapterProgressWithTrack by injectLazy() open val client: OkHttpClient get() = networkService.client - // Name of the manga sync service to display - @StringRes - abstract fun nameRes(): Int - // Application and remote support for reading dates open val supportsReadingDates: Boolean = false @@ -103,7 +99,7 @@ abstract class TrackService(val id: Long) { } // TODO: move this to an interactor, and update all trackers based on common data - suspend fun registerTracking(item: Track, mangaId: Long) { + suspend fun register(item: Track, mangaId: Long) { item.manga_id = mangaId try { withIOContext { @@ -147,7 +143,7 @@ abstract class TrackService(val id: Long) { } } - syncChaptersWithTrackServiceTwoWay.await(mangaId, track, this@TrackService) + syncChapterProgressWithTrack.await(mangaId, track, this@TrackService) } } catch (e: Throwable) { withUIContext { Injekt.get().toast(e.message) } 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 e5718acf05..c6365106ea 100644 --- 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 @@ -12,7 +12,7 @@ import kotlinx.serialization.json.Json import uy.kohesive.injekt.injectLazy import tachiyomi.domain.track.model.Track as DomainTrack -class Anilist(id: Long) : TrackService(id), DeletableTrackService { +class Anilist(id: Long) : TrackService(id, "AniList"), DeletableTrackService { companion object { const val READING = 1 @@ -49,9 +49,6 @@ class Anilist(id: Long) : TrackService(id), DeletableTrackService { } } - @StringRes - override fun nameRes() = R.string.tracker_anilist - override fun getLogo() = R.drawable.ic_tracker_anilist override fun getLogoColor() = Color.rgb(18, 25, 35) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/bangumi/Bangumi.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/bangumi/Bangumi.kt index 2643e58676..f5d8ecc0d4 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/bangumi/Bangumi.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/bangumi/Bangumi.kt @@ -10,7 +10,7 @@ import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json import uy.kohesive.injekt.injectLazy -class Bangumi(id: Long) : TrackService(id) { +class Bangumi(id: Long) : TrackService(id, "Bangumi") { private val json: Json by injectLazy() @@ -18,9 +18,6 @@ class Bangumi(id: Long) : TrackService(id) { private val api by lazy { BangumiApi(client, interceptor) } - @StringRes - override fun nameRes() = R.string.tracker_bangumi - override fun getScoreList(): List { return IntRange(0, 10).map(Int::toString) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/kavita/Kavita.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/kavita/Kavita.kt index 205228ba2f..0a45187a36 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/kavita/Kavita.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/kavita/Kavita.kt @@ -14,7 +14,7 @@ import tachiyomi.domain.manga.model.Manga import java.security.MessageDigest import tachiyomi.domain.track.model.Track as DomainTrack -class Kavita(private val context: Context, id: Long) : TrackService(id), EnhancedTrackService { +class Kavita(private val context: Context, id: Long) : TrackService(id, "Kavita"), EnhancedTrackService { companion object { const val UNREAD = 1 @@ -27,9 +27,6 @@ class Kavita(private val context: Context, id: Long) : TrackService(id), Enhance private val interceptor by lazy { KavitaInterceptor(this) } val api by lazy { KavitaApi(client, interceptor) } - @StringRes - override fun nameRes() = R.string.tracker_kavita - override fun getLogo(): Int = R.drawable.ic_tracker_kavita override fun getLogoColor() = Color.rgb(74, 198, 148) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/kavita/KavitaApi.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/kavita/KavitaApi.kt index cadea435a9..6abc3bd7ec 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/kavita/KavitaApi.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/kavita/KavitaApi.kt @@ -115,8 +115,8 @@ class KavitaApi(private val client: OkHttpClient, interceptor: KavitaInterceptor } private fun getLatestChapterRead(url: String): Float { - val serieId = getIdFromUrl(url) - val requestUrl = "${getApiFromUrl(url)}/Tachiyomi/latest-chapter?seriesId=$serieId" + val seriesId = getIdFromUrl(url) + val requestUrl = "${getApiFromUrl(url)}/Tachiyomi/latest-chapter?seriesId=$seriesId" try { with(json) { authClient.newCall(GET(requestUrl)).execute().use { @@ -137,21 +137,21 @@ class KavitaApi(private val client: OkHttpClient, interceptor: KavitaInterceptor suspend fun getTrackSearch(url: String): TrackSearch = withIOContext { try { - val serieDto: SeriesDto = with(json) { + val seriesDto: SeriesDto = with(json) { authClient.newCall(GET(url)) .awaitSuccess() .parseAs() } - val track = serieDto.toTrack() + val track = seriesDto.toTrack() track.apply { - cover_url = serieDto.thumbnail_url.toString() + cover_url = seriesDto.thumbnail_url.toString() tracking_url = url total_chapters = getTotalChapters(url) - title = serieDto.name - status = when (serieDto.pagesRead) { - serieDto.pages -> Kavita.COMPLETED + title = seriesDto.name + status = when (seriesDto.pagesRead) { + seriesDto.pages -> Kavita.COMPLETED 0 -> Kavita.UNREAD else -> Kavita.READING } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/Kitsu.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/Kitsu.kt index daabd44b1b..ade2456bb5 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/Kitsu.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/Kitsu.kt @@ -12,7 +12,7 @@ import kotlinx.serialization.json.Json import uy.kohesive.injekt.injectLazy import java.text.DecimalFormat -class Kitsu(id: Long) : TrackService(id), DeletableTrackService { +class Kitsu(id: Long) : TrackService(id, "Kitsu"), DeletableTrackService { companion object { const val READING = 1 @@ -22,9 +22,6 @@ class Kitsu(id: Long) : TrackService(id), DeletableTrackService { const val PLAN_TO_READ = 5 } - @StringRes - override fun nameRes() = R.string.tracker_kitsu - override val supportsReadingDates: Boolean = true private val json: Json by injectLazy() diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/komga/Komga.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/komga/Komga.kt index 5dbc6ca09e..8937bd21a6 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/komga/Komga.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/komga/Komga.kt @@ -1,6 +1,5 @@ package eu.kanade.tachiyomi.data.track.komga -import android.content.Context import android.graphics.Color import androidx.annotation.StringRes import eu.kanade.tachiyomi.R @@ -14,7 +13,7 @@ import okhttp3.OkHttpClient import tachiyomi.domain.manga.model.Manga import tachiyomi.domain.track.model.Track as DomainTrack -class Komga(private val context: Context, id: Long) : TrackService(id), EnhancedTrackService { +class Komga(id: Long) : TrackService(id, "Komga"), EnhancedTrackService { companion object { const val UNREAD = 1 @@ -29,9 +28,6 @@ class Komga(private val context: Context, id: Long) : TrackService(id), Enhanced val api by lazy { KomgaApi(client) } - @StringRes - override fun nameRes() = R.string.tracker_komga - override fun getLogo() = R.drawable.ic_tracker_komga override fun getLogoColor() = Color.rgb(51, 37, 50) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/komga/KomgaApi.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/komga/KomgaApi.kt index 313f94cceb..89e7fafbdf 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/komga/KomgaApi.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/komga/KomgaApi.kt @@ -17,7 +17,7 @@ import tachiyomi.core.util.lang.withIOContext import tachiyomi.core.util.system.logcat import uy.kohesive.injekt.injectLazy -const val READLIST_API = "/api/v1/readlists" +private const val READLIST_API = "/api/v1/readlists" class KomgaApi(private val client: OkHttpClient) { 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 87cab2512f..33df93222c 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 @@ -10,7 +10,7 @@ import eu.kanade.tachiyomi.data.track.mangaupdates.dto.copyTo import eu.kanade.tachiyomi.data.track.mangaupdates.dto.toTrackSearch import eu.kanade.tachiyomi.data.track.model.TrackSearch -class MangaUpdates(id: Long) : TrackService(id), DeletableTrackService { +class MangaUpdates(id: Long) : TrackService(id, "MangaUpdates"), DeletableTrackService { companion object { const val READING_LIST = 0 @@ -24,9 +24,6 @@ class MangaUpdates(id: Long) : TrackService(id), DeletableTrackService { private val api by lazy { MangaUpdatesApi(interceptor, client) } - @StringRes - override fun nameRes(): Int = R.string.tracker_manga_updates - override fun getLogo(): Int = R.drawable.ic_manga_updates override fun getLogoColor(): Int = Color.rgb(146, 160, 173) 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 719460690b..3acbb035d5 100644 --- 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,7 @@ import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json import uy.kohesive.injekt.injectLazy -class MyAnimeList(id: Long) : TrackService(id), DeletableTrackService { +class MyAnimeList(id: Long) : TrackService(id, "MyAnimeList"), DeletableTrackService { companion object { const val READING = 1 @@ -30,9 +30,6 @@ class MyAnimeList(id: Long) : TrackService(id), DeletableTrackService { private val interceptor by lazy { MyAnimeListInterceptor(this, getPassword()) } private val api by lazy { MyAnimeListApi(client, interceptor) } - @StringRes - override fun nameRes() = R.string.tracker_myanimelist - override val supportsReadingDates: Boolean = true override fun getLogo() = R.drawable.ic_tracker_mal diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/shikimori/Shikimori.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/shikimori/Shikimori.kt index 0b912a4198..463059055e 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/shikimori/Shikimori.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/shikimori/Shikimori.kt @@ -11,7 +11,7 @@ import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json import uy.kohesive.injekt.injectLazy -class Shikimori(id: Long) : TrackService(id), DeletableTrackService { +class Shikimori(id: Long) : TrackService(id, "Shikimori"), DeletableTrackService { companion object { const val READING = 1 @@ -28,9 +28,6 @@ class Shikimori(id: Long) : TrackService(id), DeletableTrackService { private val api by lazy { ShikimoriApi(client, interceptor) } - @StringRes - override fun nameRes() = R.string.tracker_shikimori - override fun getScoreList(): List { return IntRange(0, 10).map(Int::toString) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/shikimori/ShikimoriApi.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/shikimori/ShikimoriApi.kt index 63b01af640..0137ed6dfe 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/shikimori/ShikimoriApi.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/shikimori/ShikimoriApi.kt @@ -122,7 +122,7 @@ class ShikimoriApi(private val client: OkHttpClient, interceptor: ShikimoriInter } } - suspend fun findLibManga(track: Track, user_id: String): Track? { + suspend fun findLibManga(track: Track, userId: String): Track? { return withIOContext { val urlMangas = "$apiUrl/mangas".toUri().buildUpon() .appendPath(track.media_id.toString()) @@ -134,7 +134,7 @@ class ShikimoriApi(private val client: OkHttpClient, interceptor: ShikimoriInter } val url = "$apiUrl/v2/user_rates".toUri().buildUpon() - .appendQueryParameter("user_id", user_id) + .appendQueryParameter("user_id", userId) .appendQueryParameter("target_id", track.media_id.toString()) .appendQueryParameter("target_type", "Manga") .build() diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/suwayomi/Suwayomi.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/suwayomi/Suwayomi.kt index 8b00dfe9f5..3958bfa2e0 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/suwayomi/Suwayomi.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/suwayomi/Suwayomi.kt @@ -11,13 +11,10 @@ import eu.kanade.tachiyomi.source.Source import tachiyomi.domain.manga.model.Manga as DomainManga import tachiyomi.domain.track.model.Track as DomainTrack -class Suwayomi(id: Long) : TrackService(id), EnhancedTrackService { +class Suwayomi(id: Long) : TrackService(id, "Suwayomi"), EnhancedTrackService { val api by lazy { TachideskApi() } - @StringRes - override fun nameRes() = R.string.tracker_suwayomi - override fun getLogo() = R.drawable.ic_tracker_suwayomi override fun getLogoColor() = Color.rgb(255, 35, 35) // TODO diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/suwayomi/TachideskApi.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/suwayomi/TachideskApi.kt index 66d7088cce..24127c63a7 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/suwayomi/TachideskApi.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/suwayomi/TachideskApi.kt @@ -28,19 +28,19 @@ class TachideskApi { private val network: NetworkHelper by injectLazy() private val json: Json by injectLazy() - val client: OkHttpClient = + private val client: OkHttpClient = network.client.newBuilder() .dns(Dns.SYSTEM) // don't use DNS over HTTPS as it breaks IP addressing .build() - fun headersBuilder(): Headers.Builder = Headers.Builder().apply { + private fun headersBuilder(): Headers.Builder = Headers.Builder().apply { if (basePassword.isNotEmpty() && baseLogin.isNotEmpty()) { val credentials = Credentials.basic(baseLogin, basePassword) add("Authorization", credentials) } } - val headers: Headers by lazy { headersBuilder().build() } + private val headers: Headers by lazy { headersBuilder().build() } private val baseUrl by lazy { getPrefBaseUrl() } private val baseLogin by lazy { getPrefBaseLogin() } @@ -100,7 +100,7 @@ class TachideskApi { return getTrackSearch(track.tracking_url) } - val tachideskExtensionId by lazy { + private val tachideskExtensionId by lazy { val key = "tachidesk/en/1" val bytes = MessageDigest.getInstance("MD5").digest(key.toByteArray()) (0..7).map { bytes[it].toLong() and 0xff shl 8 * (7 - it) }.reduce(Long::or) and Long.MAX_VALUE @@ -110,6 +110,10 @@ class TachideskApi { Injekt.get().getSharedPreferences("source_$tachideskExtensionId", 0x0000) } + private fun getPrefBaseUrl(): String = preferences.getString(ADDRESS_TITLE, ADDRESS_DEFAULT)!! + private fun getPrefBaseLogin(): String = preferences.getString(LOGIN_TITLE, LOGIN_DEFAULT)!! + private fun getPrefBasePassword(): String = preferences.getString(PASSWORD_TITLE, PASSWORD_DEFAULT)!! + companion object { private const val ADDRESS_TITLE = "Server URL Address" private const val ADDRESS_DEFAULT = "" @@ -118,8 +122,4 @@ class TachideskApi { private const val PASSWORD_TITLE = "Password (Basic Auth)" private const val PASSWORD_DEFAULT = "" } - - private fun getPrefBaseUrl(): String = preferences.getString(ADDRESS_TITLE, ADDRESS_DEFAULT)!! - private fun getPrefBaseLogin(): String = preferences.getString(LOGIN_TITLE, LOGIN_DEFAULT)!! - private fun getPrefBasePassword(): String = preferences.getString(PASSWORD_TITLE, PASSWORD_DEFAULT)!! } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceScreenModel.kt index 2c1044d884..ff6ad995bf 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceScreenModel.kt @@ -14,7 +14,7 @@ import cafe.adriel.voyager.core.model.StateScreenModel import cafe.adriel.voyager.core.model.coroutineScope import eu.kanade.core.preference.asState import eu.kanade.domain.base.BasePreferences -import eu.kanade.domain.chapter.interactor.SyncChaptersWithTrackServiceTwoWay +import eu.kanade.domain.chapter.interactor.SyncChapterProgressWithTrack import eu.kanade.domain.manga.interactor.UpdateManga import eu.kanade.domain.manga.model.toDomainManga import eu.kanade.domain.source.service.SourcePreferences @@ -77,7 +77,7 @@ class BrowseSourceScreenModel( private val networkToLocalManga: NetworkToLocalManga = Injekt.get(), private val updateManga: UpdateManga = Injekt.get(), private val insertTrack: InsertTrack = Injekt.get(), - private val syncChaptersWithTrackServiceTwoWay: SyncChaptersWithTrackServiceTwoWay = Injekt.get(), + private val syncChapterProgressWithTrack: SyncChapterProgressWithTrack = Injekt.get(), ) : StateScreenModel(State(Listing.valueOf(listingQuery))) { private val loggedServices by lazy { Injekt.get().services.filter { it.isLoggedIn } } @@ -297,7 +297,7 @@ class BrowseSourceScreenModel( (service as TrackService).bind(track) insertTrack.await(track.toDomainTrack()!!) - syncChaptersWithTrackServiceTwoWay.await(manga.id, track.toDomainTrack()!!, service) + syncChapterProgressWithTrack.await(manga.id, track.toDomainTrack()!!, service) } } catch (e: Exception) { logcat(LogPriority.WARN, e) { "Could not match manga: ${manga.title} with service $service" } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreenModel.kt index c288733a00..71b7c4bf75 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreenModel.kt @@ -323,7 +323,7 @@ class MangaScreenModel( launchIO { try { service.match(manga)?.let { track -> - (service as TrackService).registerTracking(track, mangaId) + (service as TrackService).register(track, mangaId) } } catch (e: Exception) { logcat(LogPriority.WARN, e) { 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 91fea703b3..47d7c51326 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 @@ -39,9 +39,8 @@ import cafe.adriel.voyager.core.model.rememberScreenModel import cafe.adriel.voyager.navigator.LocalNavigator import cafe.adriel.voyager.navigator.Navigator import cafe.adriel.voyager.navigator.currentOrThrow -import eu.kanade.domain.chapter.interactor.SyncChaptersWithTrackServiceTwoWay +import eu.kanade.domain.track.interactor.RefreshTracks import eu.kanade.domain.track.model.toDbTrack -import eu.kanade.domain.track.model.toDomainTrack import eu.kanade.domain.ui.UiPreferences import eu.kanade.presentation.track.TrackChapterSelector import eu.kanade.presentation.track.TrackDateSelector @@ -74,7 +73,6 @@ import tachiyomi.domain.manga.interactor.GetManga import tachiyomi.domain.source.service.SourceManager import tachiyomi.domain.track.interactor.DeleteTrack import tachiyomi.domain.track.interactor.GetTracks -import tachiyomi.domain.track.interactor.InsertTrack import tachiyomi.domain.track.model.Track import tachiyomi.presentation.core.components.material.AlertDialogContent import tachiyomi.presentation.core.components.material.padding @@ -208,7 +206,7 @@ data class TrackInfoDialogHomeScreen( val manga = Injekt.get().await(mangaId) ?: return@launchNonCancellable try { val matchResult = item.service.match(manga) ?: throw Exception() - item.service.registerTracking(matchResult, mangaId) + item.service.register(matchResult, mangaId) } catch (e: Exception) { withUIContext { Injekt.get().toast(R.string.error_no_match) } } @@ -216,38 +214,25 @@ data class TrackInfoDialogHomeScreen( } private suspend fun refreshTrackers() { - val insertTrack = Injekt.get() - val syncChaptersWithTrackServiceTwoWay = Injekt.get() + val refreshTracks = Injekt.get() val context = Injekt.get() - try { - val trackItems = getTracks.await(mangaId).mapToTrackItem() - for (trackItem in trackItems) { - try { - val track = trackItem.track ?: continue - val domainTrack = trackItem.service.refresh(track.toDbTrack()).toDomainTrack() ?: continue - insertTrack.await(domainTrack) - syncChaptersWithTrackServiceTwoWay.await(mangaId, domainTrack, trackItem.service) - } catch (e: Exception) { - logcat( - LogPriority.ERROR, - e, - ) { "Failed to refresh track data mangaId=$mangaId for service ${trackItem.service.id}" } - withUIContext { - context.toast( - context.getString( - R.string.track_error, - context.getString(trackItem.service.nameRes()), - e.message, - ), - ) - } + refreshTracks.await(mangaId) + .filter { it.first != null } + .forEach { (track, e) -> + logcat(LogPriority.ERROR, e) { + "Failed to refresh track data mangaId=$mangaId for service ${track!!.id}" + } + withUIContext { + context.toast( + context.getString( + R.string.track_error, + track!!.name, + e.message, + ), + ) } } - } catch (e: Exception) { - logcat(LogPriority.ERROR, e) { "Failed to refresh track data mangaId=$mangaId" } - withUIContext { context.toast(e.message) } - } } private fun List.mapToTrackItem(): List { @@ -581,7 +566,7 @@ private data class TrackDateRemoverScreen( ) }, text = { - val serviceName = stringResource(sm.getServiceNameRes()) + val serviceName = sm.getServiceName() Text( text = if (start) { stringResource(R.string.track_remove_start_date_conf_text, serviceName) @@ -618,7 +603,7 @@ private data class TrackDateRemoverScreen( private val start: Boolean, ) : ScreenModel { - fun getServiceNameRes() = service.nameRes() + fun getServiceName() = service.name fun removeDate() { coroutineScope.launchNonCancellable { @@ -703,7 +688,7 @@ data class TrackServiceSearchScreen( } fun registerTracking(item: TrackSearch) { - coroutineScope.launchNonCancellable { service.registerTracking(item, mangaId) } + coroutineScope.launchNonCancellable { service.register(item, mangaId) } } fun updateSelection(selected: TrackSearch) { @@ -734,7 +719,7 @@ private data class TrackServiceRemoveScreen( service = Injekt.get().getService(serviceId)!!, ) } - val serviceName = stringResource(sm.getServiceNameRes()) + val serviceName = sm.getServiceName() var removeRemoteTrack by remember { mutableStateOf(false) } AlertDialogContent( modifier = Modifier.windowInsetsPadding(WindowInsets.systemBars), @@ -799,7 +784,7 @@ private data class TrackServiceRemoveScreen( private val deleteTrack: DeleteTrack = Injekt.get(), ) : ScreenModel { - fun getServiceNameRes() = service.nameRes() + fun getServiceName() = service.name fun isServiceDeletable() = service is DeletableTrackService diff --git a/i18n/src/main/res/values/strings.xml b/i18n/src/main/res/values/strings.xml index bf7c33bb26..4da05b9095 100644 --- a/i18n/src/main/res/values/strings.xml +++ b/i18n/src/main/res/values/strings.xml @@ -697,15 +697,6 @@ Are you sure? - AniList - MyAnimeList - Kitsu - Komga - Bangumi - Shikimori - MangaUpdates - Kavita - Suwayomi Tracking %d tracker