From e34bcd47d562a2cd22007e8503cbc3a75e24bd75 Mon Sep 17 00:00:00 2001 From: Koitharu Date: Thu, 15 Aug 2024 09:34:59 +0300 Subject: [PATCH] Refactor tracker --- .../kotatsu/tracker/domain/TrackerTest.kt | 198 ------------------ .../details/domain/DetailsLoadUseCase.kt | 33 ++- .../kotatsu/history/data/HistoryRepository.kt | 8 +- ...{Tracker.kt => CheckNewChaptersUseCase.kt} | 110 +++++----- .../tracker/domain/GetTracksUseCase.kt | 14 ++ .../tracker/domain/TrackingRepository.kt | 4 +- .../tracker/domain/model/MangaUpdates.kt | 7 +- .../kotatsu/tracker/work/TrackWorker.kt | 10 +- 8 files changed, 108 insertions(+), 276 deletions(-) delete mode 100644 app/src/androidTest/kotlin/org/koitharu/kotatsu/tracker/domain/TrackerTest.kt rename app/src/main/kotlin/org/koitharu/kotatsu/tracker/domain/{Tracker.kt => CheckNewChaptersUseCase.kt} (56%) create mode 100644 app/src/main/kotlin/org/koitharu/kotatsu/tracker/domain/GetTracksUseCase.kt diff --git a/app/src/androidTest/kotlin/org/koitharu/kotatsu/tracker/domain/TrackerTest.kt b/app/src/androidTest/kotlin/org/koitharu/kotatsu/tracker/domain/TrackerTest.kt deleted file mode 100644 index 7b86df8d5..000000000 --- a/app/src/androidTest/kotlin/org/koitharu/kotatsu/tracker/domain/TrackerTest.kt +++ /dev/null @@ -1,198 +0,0 @@ -package org.koitharu.kotatsu.tracker.domain - -import androidx.test.ext.junit.runners.AndroidJUnit4 -import dagger.hilt.android.testing.HiltAndroidRule -import dagger.hilt.android.testing.HiltAndroidTest -import junit.framework.TestCase.* -import kotlinx.coroutines.test.runTest -import org.junit.Before -import org.junit.Rule -import org.junit.Test -import org.junit.runner.RunWith -import org.koitharu.kotatsu.SampleData -import org.koitharu.kotatsu.core.parser.MangaDataRepository -import org.koitharu.kotatsu.parsers.model.Manga -import javax.inject.Inject - -@HiltAndroidTest -@RunWith(AndroidJUnit4::class) -class TrackerTest { - - @get:Rule - var hiltRule = HiltAndroidRule(this) - - @Inject - lateinit var repository: TrackingRepository - - @Inject - lateinit var dataRepository: MangaDataRepository - - @Inject - lateinit var tracker: Tracker - - @Before - fun setUp() { - hiltRule.inject() - } - - @Test - fun noUpdates() = runTest { - val manga = loadManga("full.json") - tracker.deleteTrack(manga.id) - - tracker.checkUpdates(manga, commit = true).apply { - assertFalse(isValid) - assert(newChapters.isEmpty()) - } - assertEquals(0, repository.getNewChaptersCount(manga.id)) - tracker.checkUpdates(manga, commit = true).apply { - assertTrue(isValid) - assert(newChapters.isEmpty()) - } - assertEquals(0, repository.getNewChaptersCount(manga.id)) - } - - @Test - fun hasUpdates() = runTest { - val mangaFirst = loadManga("first_chapters.json") - val mangaFull = loadManga("full.json") - tracker.deleteTrack(mangaFirst.id) - - tracker.checkUpdates(mangaFirst, commit = true).apply { - assertFalse(isValid) - assert(newChapters.isEmpty()) - } - assertEquals(0, repository.getNewChaptersCount(mangaFirst.id)) - tracker.checkUpdates(mangaFull, commit = true).apply { - assertTrue(isValid) - assertEquals(3, newChapters.size) - } - assertEquals(3, repository.getNewChaptersCount(mangaFirst.id)) - tracker.checkUpdates(mangaFull, commit = true).apply { - assertTrue(isValid) - assert(newChapters.isEmpty()) - } - assertEquals(3, repository.getNewChaptersCount(mangaFirst.id)) - } - - @Test - fun badIds() = runTest { - val mangaFirst = loadManga("first_chapters.json") - val mangaBad = loadManga("bad_ids.json") - tracker.deleteTrack(mangaFirst.id) - - tracker.checkUpdates(mangaFirst, commit = true).apply { - assertFalse(isValid) - assert(newChapters.isEmpty()) - } - assertEquals(0, repository.getNewChaptersCount(mangaFirst.id)) - tracker.checkUpdates(mangaBad, commit = true).apply { - assertFalse(isValid) - assert(newChapters.isEmpty()) - } - assertEquals(0, repository.getNewChaptersCount(mangaFirst.id)) - tracker.checkUpdates(mangaFirst, commit = true).apply { - assertFalse(isValid) - assert(newChapters.isEmpty()) - } - assertEquals(0, repository.getNewChaptersCount(mangaFirst.id)) - } - - @Test - fun badIds2() = runTest { - val mangaFirst = loadManga("first_chapters.json") - val mangaBad = loadManga("bad_ids.json") - val mangaFull = loadManga("full.json") - tracker.deleteTrack(mangaFirst.id) - - tracker.checkUpdates(mangaFirst, commit = true).apply { - assertFalse(isValid) - assert(newChapters.isEmpty()) - } - assertEquals(0, repository.getNewChaptersCount(mangaFirst.id)) - tracker.checkUpdates(mangaFull, commit = true).apply { - assertTrue(isValid) - assertEquals(3, newChapters.size) - } - assertEquals(3, repository.getNewChaptersCount(mangaFull.id)) - tracker.checkUpdates(mangaBad, commit = true).apply { - assertFalse(isValid) - assert(newChapters.isEmpty()) - } - assertEquals(0, repository.getNewChaptersCount(mangaFirst.id)) - } - - @Test - fun fullReset() = runTest { - val mangaFull = loadManga("full.json") - val mangaFirst = loadManga("first_chapters.json") - val mangaEmpty = loadManga("empty.json") - tracker.deleteTrack(mangaFull.id) - - assertEquals(0, repository.getNewChaptersCount(mangaFull.id)) - tracker.checkUpdates(mangaFull, commit = true).apply { - assertFalse(isValid) - assert(newChapters.isEmpty()) - } - assertEquals(0, repository.getNewChaptersCount(mangaFull.id)) - tracker.checkUpdates(mangaEmpty, commit = true).apply { - assert(newChapters.isEmpty()) - } - assertEquals(0, repository.getNewChaptersCount(mangaFull.id)) - tracker.checkUpdates(mangaFirst, commit = true).apply { - assertFalse(isValid) - assert(newChapters.isEmpty()) - } - assertEquals(0, repository.getNewChaptersCount(mangaFull.id)) - tracker.checkUpdates(mangaFull, commit = true).apply { - assertTrue(isValid) - assertEquals(3, newChapters.size) - } - assertEquals(3, repository.getNewChaptersCount(mangaFull.id)) - tracker.checkUpdates(mangaEmpty, commit = true).apply { - assertFalse(isValid) - assert(newChapters.isEmpty()) - } - assertEquals(0, repository.getNewChaptersCount(mangaFull.id)) - } - - @Test - fun syncWithHistory() = runTest { - val mangaFull = loadManga("full.json") - val mangaFirst = loadManga("first_chapters.json") - tracker.deleteTrack(mangaFull.id) - - tracker.checkUpdates(mangaFirst, commit = true).apply { - assertFalse(isValid) - assert(newChapters.isEmpty()) - } - assertEquals(0, repository.getNewChaptersCount(mangaFirst.id)) - tracker.checkUpdates(mangaFull, commit = true).apply { - assertTrue(isValid) - assertEquals(3, newChapters.size) - } - assertEquals(3, repository.getNewChaptersCount(mangaFirst.id)) - - var chapter = requireNotNull(mangaFull.chapters).run { get(lastIndex - 1) } - tracker.syncWithHistory(mangaFull, chapter.id) - - assertEquals(1, repository.getNewChaptersCount(mangaFirst.id)) - - chapter = requireNotNull(mangaFull.chapters).run { get(lastIndex) } - tracker.syncWithHistory(mangaFull, chapter.id) - - assertEquals(0, repository.getNewChaptersCount(mangaFirst.id)) - - tracker.checkUpdates(mangaFull, commit = true).apply { - assertTrue(isValid) - assert(newChapters.isEmpty()) - } - assertEquals(0, repository.getNewChaptersCount(mangaFirst.id)) - } - - private suspend fun loadManga(name: String): Manga { - val manga = SampleData.loadAsset("manga/$name", Manga::class) - dataRepository.storeManga(manga) - return manga - } -} diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/details/domain/DetailsLoadUseCase.kt b/app/src/main/kotlin/org/koitharu/kotatsu/details/domain/DetailsLoadUseCase.kt index 32142b7f7..ff73e6105 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/details/domain/DetailsLoadUseCase.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/details/domain/DetailsLoadUseCase.kt @@ -27,7 +27,7 @@ import org.koitharu.kotatsu.parsers.exception.NotFoundException import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.util.recoverNotNull import org.koitharu.kotatsu.parsers.util.runCatchingCancellable -import org.koitharu.kotatsu.tracker.domain.Tracker +import org.koitharu.kotatsu.tracker.domain.CheckNewChaptersUseCase import javax.inject.Inject import javax.inject.Provider @@ -37,7 +37,7 @@ class DetailsLoadUseCase @Inject constructor( private val mangaRepositoryFactory: MangaRepository.Factory, private val recoverUseCase: RecoverMangaUseCase, private val imageGetter: Html.ImageGetter, - private val trackerProvider: Provider, + private val newChaptersUseCaseProvider: Provider, ) { operator fun invoke(intent: MangaIntent): Flow = channelFlow { @@ -55,11 +55,32 @@ class DetailsLoadUseCase @Inject constructor( try { val details = getDetails(manga) launch { updateTracker(details) } - send(MangaDetails(details, local?.peek(), details.description?.parseAsHtml(withImages = false)?.trim(), false)) - send(MangaDetails(details, local?.await(), details.description?.parseAsHtml(withImages = true)?.trim(), true)) + send( + MangaDetails( + details, + local?.peek(), + details.description?.parseAsHtml(withImages = false)?.trim(), + false, + ), + ) + send( + MangaDetails( + details, + local?.await(), + details.description?.parseAsHtml(withImages = true)?.trim(), + true, + ), + ) } catch (e: IOException) { local?.await()?.manga?.also { localManga -> - send(MangaDetails(localManga, null, localManga.description?.parseAsHtml(withImages = false)?.trim(), true)) + send( + MangaDetails( + localManga, + null, + localManga.description?.parseAsHtml(withImages = false)?.trim(), + true, + ), + ) } ?: close(e) } } @@ -97,7 +118,7 @@ class DetailsLoadUseCase @Inject constructor( } private suspend fun updateTracker(details: Manga) = runCatchingCancellable { - trackerProvider.get().syncWithDetails(details) + newChaptersUseCaseProvider.get()(details) }.onFailure { e -> e.printStackTraceDebug() } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/history/data/HistoryRepository.kt b/app/src/main/kotlin/org/koitharu/kotatsu/history/data/HistoryRepository.kt index c745858eb..8ab73a816 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/history/data/HistoryRepository.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/history/data/HistoryRepository.kt @@ -1,7 +1,6 @@ package org.koitharu.kotatsu.history.data import androidx.room.withTransaction -import dagger.Lazy import dagger.Reusable import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.distinctUntilChanged @@ -30,8 +29,9 @@ import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.model.MangaTag import org.koitharu.kotatsu.scrobbling.common.domain.Scrobbler import org.koitharu.kotatsu.scrobbling.common.domain.tryScrobble -import org.koitharu.kotatsu.tracker.domain.Tracker +import org.koitharu.kotatsu.tracker.domain.CheckNewChaptersUseCase import javax.inject.Inject +import javax.inject.Provider const val PROGRESS_NONE = -1f @@ -41,7 +41,7 @@ class HistoryRepository @Inject constructor( private val settings: AppSettings, private val scrobblers: Set<@JvmSuppressWildcards Scrobbler>, private val mangaRepository: MangaDataRepository, - private val trackerLazy: Lazy, + private val newChaptersUseCaseProvider: Provider, ) { suspend fun getList(offset: Int, limit: Int): List { @@ -123,7 +123,7 @@ class HistoryRepository @Inject constructor( deletedAt = 0L, ), ) - trackerLazy.get().syncWithHistory(manga, chapterId) + newChaptersUseCaseProvider.get()(manga, chapterId) scrobblers.forEach { it.tryScrobble(manga, chapterId) } } } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/tracker/domain/Tracker.kt b/app/src/main/kotlin/org/koitharu/kotatsu/tracker/domain/CheckNewChaptersUseCase.kt similarity index 56% rename from app/src/main/kotlin/org/koitharu/kotatsu/tracker/domain/Tracker.kt rename to app/src/main/kotlin/org/koitharu/kotatsu/tracker/domain/CheckNewChaptersUseCase.kt index dc7ce0661..7a1699c20 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/tracker/domain/Tracker.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/tracker/domain/CheckNewChaptersUseCase.kt @@ -1,72 +1,56 @@ package org.koitharu.kotatsu.tracker.domain -import androidx.annotation.VisibleForTesting import coil.request.CachePolicy -import dagger.Reusable import org.koitharu.kotatsu.core.model.getPreferredBranch +import org.koitharu.kotatsu.core.model.isLocal +import org.koitharu.kotatsu.core.parser.CachingMangaRepository import org.koitharu.kotatsu.core.parser.MangaRepository -import org.koitharu.kotatsu.core.parser.ParserMangaRepository import org.koitharu.kotatsu.core.util.MultiMutex import org.koitharu.kotatsu.core.util.ext.toInstantOrNull import org.koitharu.kotatsu.history.data.HistoryRepository +import org.koitharu.kotatsu.local.data.LocalMangaRepository import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.util.runCatchingCancellable import org.koitharu.kotatsu.tracker.domain.model.MangaTracking import org.koitharu.kotatsu.tracker.domain.model.MangaUpdates import java.time.Instant import javax.inject.Inject +import javax.inject.Singleton -@Reusable -class Tracker @Inject constructor( +@Singleton +class CheckNewChaptersUseCase @Inject constructor( private val repository: TrackingRepository, private val historyRepository: HistoryRepository, private val mangaRepositoryFactory: MangaRepository.Factory, + private val localMangaRepository: LocalMangaRepository, ) { - private val mangaMutex = MultiMutex() + private val mutex = MultiMutex() - suspend fun getTracks(limit: Int): List { + suspend operator fun invoke(manga: Manga): MangaUpdates = mutex.withLock(manga.id) { repository.updateTracks() - return repository.getTracks(offset = 0, limit = limit) + val tracking = repository.getTrackOrNull(manga) ?: return MangaUpdates.Failure( + manga = manga, + error = null, + ) + invokeImpl(tracking) } - suspend fun fetchUpdates( - track: MangaTracking, - commit: Boolean - ): MangaUpdates = mangaMutex.withLock(track.manga.id) { - val updates = runCatchingCancellable { - val repo = mangaRepositoryFactory.create(track.manga.source) - require(repo is ParserMangaRepository) { "Repository ${repo.javaClass.simpleName} is not supported" } - val manga = repo.getDetails(track.manga, CachePolicy.WRITE_ONLY) - compare(track, manga, getBranch(manga)) - }.getOrElse { error -> - MangaUpdates.Failure( - manga = track.manga, - error = error, - ) - } - if (commit) { - repository.saveUpdates(updates) - } - updates + suspend operator fun invoke(track: MangaTracking): MangaUpdates = mutex.withLock(track.manga.id) { + invokeImpl(track) } - suspend fun syncWithDetails(details: Manga) { - requireNotNull(details.chapters) - val track = repository.getTrackOrNull(details) ?: return - val updates = compare(track, details, getBranch(details)) - repository.saveUpdates(updates) - } - - suspend fun syncWithHistory(details: Manga, chapterId: Long) { - val chapters = requireNotNull(details.chapters) - val track = repository.getTrackOrNull(details) ?: return - val chapterIndex = chapters.indexOfFirst { x -> x.id == chapterId } + suspend operator fun invoke(manga: Manga, currentChapterId: Long) = mutex.withLock(manga.id) { + repository.updateTracks() + val details = getFullManga(manga) + val chapters = details.chapters ?: return@withLock + val track = repository.getTrackOrNull(manga) ?: return@withLock + val chapterIndex = chapters.indexOfFirst { x -> x.id == currentChapterId } val lastNewChapterIndex = chapters.size - track.newChapters val lastChapter = chapters.lastOrNull() val tracking = MangaTracking( manga = details, - lastChapterId = lastChapter?.id ?: NO_ID, + lastChapterId = lastChapter?.id ?: 0L, lastCheck = Instant.now(), lastChapterDate = lastChapter?.uploadDate?.toInstantOrNull() ?: track.lastChapterDate, newChapters = when { @@ -79,19 +63,16 @@ class Tracker @Inject constructor( repository.mergeWith(tracking) } - @VisibleForTesting - suspend fun checkUpdates(manga: Manga, commit: Boolean): MangaUpdates.Success { - val track = repository.getTrack(manga) - val updates = compare(track, manga, getBranch(manga)) - if (commit) { - repository.saveUpdates(updates) - } - return updates - } - - @VisibleForTesting - suspend fun deleteTrack(mangaId: Long) = mangaMutex.withLock(mangaId) { - repository.deleteTrack(mangaId) + private suspend fun invokeImpl(track: MangaTracking): MangaUpdates = runCatchingCancellable { + val details = getFullManga(track.manga) + compare(track, details, getBranch(details)) + }.getOrElse { error -> + MangaUpdates.Failure( + manga = track.manga, + error = error, + ) + }.also { updates -> + repository.saveUpdates(updates) } private suspend fun getBranch(manga: Manga): String? { @@ -99,6 +80,26 @@ class Tracker @Inject constructor( return manga.getPreferredBranch(history) } + private suspend fun getFullManga(manga: Manga): Manga = when { + manga.isLocal -> fetchDetails( + requireNotNull(localMangaRepository.getRemoteManga(manga)) { + "Local manga is not supported" + }, + ) + + manga.chapters.isNullOrEmpty() -> fetchDetails(manga) + else -> manga + } + + private suspend fun fetchDetails(manga: Manga): Manga { + val repo = mangaRepositoryFactory.create(manga.source) + return if (repo is CachingMangaRepository) { + repo.getDetails(manga, CachePolicy.WRITE_ONLY) + } else { + repo.getDetails(manga) + } + } + /** * The main functionality of tracker: check new chapters in [manga] comparing to the [track] */ @@ -127,9 +128,4 @@ class Tracker @Inject constructor( } } } - - private companion object { - - const val NO_ID = 0L - } } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/tracker/domain/GetTracksUseCase.kt b/app/src/main/kotlin/org/koitharu/kotatsu/tracker/domain/GetTracksUseCase.kt new file mode 100644 index 000000000..985e993ff --- /dev/null +++ b/app/src/main/kotlin/org/koitharu/kotatsu/tracker/domain/GetTracksUseCase.kt @@ -0,0 +1,14 @@ +package org.koitharu.kotatsu.tracker.domain + +import org.koitharu.kotatsu.tracker.domain.model.MangaTracking +import javax.inject.Inject + +class GetTracksUseCase @Inject constructor( + private val repository: TrackingRepository, +) { + + suspend operator fun invoke(limit: Int): List { + repository.updateTracks() + return repository.getTracks(offset = 0, limit = limit) + } +} diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/tracker/domain/TrackingRepository.kt b/app/src/main/kotlin/org/koitharu/kotatsu/tracker/domain/TrackingRepository.kt index 011d50a0e..6f95b6a31 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/tracker/domain/TrackingRepository.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/tracker/domain/TrackingRepository.kt @@ -85,7 +85,7 @@ class TrackingRepository @Inject constructor( } } - @VisibleForTesting + @Deprecated("") suspend fun getTrack(manga: Manga): MangaTracking { return getTrackOrNull(manga) ?: MangaTracking( manga = manga, @@ -217,7 +217,7 @@ class TrackingRepository @Inject constructor( size - ids.size } - private suspend fun getOrCreateTrack(mangaId: Long): TrackEntity { + suspend fun getOrCreateTrack(mangaId: Long): TrackEntity { return db.getTracksDao().find(mangaId) ?: TrackEntity.create(mangaId) } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/tracker/domain/model/MangaUpdates.kt b/app/src/main/kotlin/org/koitharu/kotatsu/tracker/domain/model/MangaUpdates.kt index 9726247a8..6c6cda809 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/tracker/domain/model/MangaUpdates.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/tracker/domain/model/MangaUpdates.kt @@ -19,11 +19,8 @@ sealed interface MangaUpdates { fun lastChapterDate(): Long { val lastChapter = newChapters.lastOrNull() - return if (lastChapter == null) { - manga.chapters?.lastOrNull()?.uploadDate ?: 0L - } else { - lastChapter.uploadDate.ifZero { System.currentTimeMillis() } - } + return lastChapter?.uploadDate?.ifZero { System.currentTimeMillis() } + ?: (manga.chapters?.lastOrNull()?.uploadDate ?: 0L) } } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/tracker/work/TrackWorker.kt b/app/src/main/kotlin/org/koitharu/kotatsu/tracker/work/TrackWorker.kt index 97ca8e931..1fd2e9f5a 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/tracker/work/TrackWorker.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/tracker/work/TrackWorker.kt @@ -55,7 +55,8 @@ import org.koitharu.kotatsu.parsers.util.runCatchingCancellable import org.koitharu.kotatsu.parsers.util.toIntUp import org.koitharu.kotatsu.settings.SettingsActivity import org.koitharu.kotatsu.settings.work.PeriodicWorkScheduler -import org.koitharu.kotatsu.tracker.domain.Tracker +import org.koitharu.kotatsu.tracker.domain.CheckNewChaptersUseCase +import org.koitharu.kotatsu.tracker.domain.GetTracksUseCase import org.koitharu.kotatsu.tracker.domain.model.MangaTracking import org.koitharu.kotatsu.tracker.domain.model.MangaUpdates import org.koitharu.kotatsu.tracker.work.TrackerNotificationHelper.NotificationInfo @@ -71,7 +72,8 @@ class TrackWorker @AssistedInject constructor( @Assisted workerParams: WorkerParameters, private val notificationHelper: TrackerNotificationHelper, private val settings: AppSettings, - private val tracker: Tracker, + private val getTracksUseCase: GetTracksUseCase, + private val checkNewChaptersUseCase: CheckNewChaptersUseCase, private val workManager: WorkManager, @TrackerLogger private val logger: FileLogger, ) : CoroutineWorker(context, workerParams) { @@ -101,7 +103,7 @@ class TrackWorker @AssistedInject constructor( if (!settings.isTrackerEnabled) { return Result.success() } - val tracks = tracker.getTracks(if (isFullRun) Int.MAX_VALUE else BATCH_SIZE) + val tracks = getTracksUseCase(if (isFullRun) Int.MAX_VALUE else BATCH_SIZE) logger.log("Total ${tracks.size} tracks") if (tracks.isEmpty()) { return Result.success() @@ -127,7 +129,7 @@ class TrackWorker @AssistedInject constructor( semaphore.withPermit { send( runCatchingCancellable { - tracker.fetchUpdates(track, commit = true) + checkNewChaptersUseCase.invoke(track) }.getOrElse { error -> MangaUpdates.Failure( manga = track.manga,