Auto sync read chapters from Trackers & mark read to update (#28)

* Mark chapter(s) as read will update Tracking

* Fix: sync tracking 2 ways for all trackers

* automatically sync read chapters from Trackers
This commit is contained in:
Cuong M. Tran 2024-05-22 17:54:22 +07:00
parent 81376ae818
commit ce7177efc6
7 changed files with 98 additions and 12 deletions

View file

@ -1,7 +1,6 @@
package eu.kanade.domain.track.interactor
import eu.kanade.domain.track.model.toDbTrack
import eu.kanade.tachiyomi.data.track.EnhancedTracker
import eu.kanade.tachiyomi.data.track.Tracker
import logcat.LogPriority
import tachiyomi.core.common.util.system.logcat
@ -22,26 +21,36 @@ class SyncChapterProgressWithTrack(
remoteTrack: Track,
tracker: Tracker,
) {
if (tracker !is EnhancedTracker) {
return
}
// KKM -->
// if (tracker !is EnhancedTracker) {
// return
// }
// <-- KKM
// Current chapters in database
val sortedChapters = getChaptersByMangaId.await(mangaId)
.sortedBy { it.chapterNumber }
.filter { it.isRecognizedNumber }
// Chapters to update to follow tracker
val chapterUpdates = sortedChapters
.filter { chapter -> chapter.chapterNumber <= remoteTrack.lastChapterRead && !chapter.read }
.map { it.copy(read = true).toChapterUpdate() }
// only take into account continuous reading
val localLastRead = sortedChapters.takeWhile { it.read }.lastOrNull()?.chapterNumber ?: 0F
// Tracker will update to latest read chapter
val updatedTrack = remoteTrack.copy(lastChapterRead = localLastRead.toDouble())
try {
tracker.update(updatedTrack.toDbTrack())
// Update Tracker to localLastRead if needed
if (updatedTrack.lastChapterRead > remoteTrack.lastChapterRead) {
tracker.update(updatedTrack.toDbTrack())
// update Track in database
insertTrack.await(updatedTrack)
}
// Update local chapters following Tracker
updateChapter.awaitAll(chapterUpdates)
insertTrack.await(updatedTrack)
} catch (e: Throwable) {
logcat(LogPriority.WARN, e)
}

View file

@ -35,4 +35,6 @@ class TrackPreferences(
fun anilistScoreType() = preferenceStore.getString("anilist_score_type", Anilist.POINT_10)
fun autoUpdateTrack() = preferenceStore.getBoolean("pref_auto_update_manga_sync_key", true)
fun updateTrackMarkedRead() = preferenceStore.getBoolean("pref_update_tracking_marked_read_key", false)
fun autoSyncReadChapters() = preferenceStore.getBoolean("pref_auto_sync_read_chapters_key", false)
}

View file

@ -125,6 +125,14 @@ object SettingsTrackingScreen : SearchableSettings {
pref = trackPreferences.autoUpdateTrack(),
title = stringResource(MR.strings.pref_auto_update_manga_sync),
),
Preference.PreferenceItem.SwitchPreference(
pref = trackPreferences.updateTrackMarkedRead(),
title = stringResource(MR.strings.pref_update_tracking_marked_read),
),
Preference.PreferenceItem.SwitchPreference(
pref = trackPreferences.autoSyncReadChapters(),
title = stringResource(MR.strings.pref_auto_sync_read_chapters),
),
Preference.PreferenceGroup(
title = stringResource(MR.strings.services),
preferenceItems = persistentListOf(

View file

@ -1,5 +1,6 @@
package eu.kanade.tachiyomi.ui.manga
import android.app.Application
import android.content.Context
import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.SnackbarResult
@ -29,7 +30,10 @@ import eu.kanade.domain.manga.model.toDomainManga
import eu.kanade.domain.manga.model.toSManga
import eu.kanade.domain.source.service.SourcePreferences
import eu.kanade.domain.track.interactor.AddTracks
import eu.kanade.domain.track.interactor.RefreshTracks
import eu.kanade.domain.track.interactor.TrackChapter
import eu.kanade.domain.track.model.toDomainTrack
import eu.kanade.domain.track.service.TrackPreferences
import eu.kanade.domain.ui.UiPreferences
import eu.kanade.presentation.manga.DownloadAction
import eu.kanade.presentation.manga.components.ChapterDownloadAction
@ -55,6 +59,7 @@ import eu.kanade.tachiyomi.ui.reader.setting.ReaderPreferences
import eu.kanade.tachiyomi.util.chapter.getNextUnread
import eu.kanade.tachiyomi.util.removeCovers
import eu.kanade.tachiyomi.util.shouldDownloadNewChapters
import eu.kanade.tachiyomi.util.system.toast
import exh.debug.DebugToggles
import exh.eh.EHentaiUpdateHelper
import exh.log.xLogD
@ -156,6 +161,10 @@ class MangaScreenModel(
private val libraryPreferences: LibraryPreferences = Injekt.get(),
readerPreferences: ReaderPreferences = Injekt.get(),
uiPreferences: UiPreferences = Injekt.get(),
// KMK -->
private val trackPreferences: TrackPreferences = Injekt.get(),
private val trackChapter: TrackChapter = Injekt.get(),
// KMK <--
private val trackerManager: TrackerManager = Injekt.get(),
private val downloadManager: DownloadManager = Injekt.get(),
private val downloadCache: DownloadCache = Injekt.get(),
@ -450,6 +459,7 @@ class MangaScreenModel(
}
// KMK <--
val fetchFromSourceTasks = listOf(
async { syncTrackers() },
async { if (needRefreshInfo) fetchMangaFromSource() },
async { if (needRefreshChapter) fetchChaptersFromSource() },
)
@ -461,10 +471,35 @@ class MangaScreenModel(
}
}
// KMK -->
private suspend fun syncTrackers() {
if (!trackPreferences.updateTrackMarkedRead().get()) return
val refreshTracks = Injekt.get<RefreshTracks>()
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.stringResource(
MR.strings.track_error,
track!!.name,
e.message ?: "",
),
)
}
}
}
// KMK <--
fun fetchAllFromSource(manualFetch: Boolean = true) {
screenModelScope.launch {
updateSuccessState { it.copy(isRefreshingData = true) }
val fetchFromSourceTasks = listOf(
async { syncTrackers() },
async { fetchMangaFromSource(manualFetch) },
async { fetchChaptersFromSource(manualFetch) },
)
@ -669,7 +704,7 @@ class MangaScreenModel(
mergedManga = networkToLocalManga.await(mergedManga)
getCategories.await(originalMangaId)
.let {
.let { it ->
setMangaCategories.await(mergedManga.id, it.map { it.id })
}
@ -1163,6 +1198,11 @@ class MangaScreenModel(
when (swipeAction) {
LibraryPreferences.ChapterSwipeAction.ToggleRead -> {
markChaptersRead(listOf(chapter), !chapter.read)
// KMK -->
if (!chapter.read) {
updateTrackChapterMarkedAsRead(chapter)
}
// KMK <--
}
LibraryPreferences.ChapterSwipeAction.ToggleBookmark -> {
bookmarkChapters(listOf(chapter), !chapter.bookmark)
@ -1306,9 +1346,32 @@ class MangaScreenModel(
chapters = chapters.toTypedArray(),
)
}
// KMK -->
if (read) {
chapters.maxByOrNull { it.chapterNumber }
?.also { updateTrackChapterMarkedAsRead(it) }
}
// KMK <--
toggleAllSelection(false)
}
// KMK -->
/**
* Starts the service that updates the chapter marked as read in sync services. This operation
* will run in a background thread and errors are ignored.
*/
private fun updateTrackChapterMarkedAsRead(chapter: Chapter) {
if (!trackPreferences.updateTrackMarkedRead().get()) return
val manga = manga ?: return
val context = Injekt.get<Application>()
screenModelScope.launchNonCancellable {
trackChapter.await(context, manga.id, chapter.chapterNumber)
}
}
// KMK <--
/**
* Downloads the given list of chapters with the manager.
* @param chapters the list of chapters to download.

View file

@ -1,12 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<changelog bulletedList="true">
<changelogversion versionName="Latest (r8894)" changeDate="May 17, 2024">
<changelogtext>A dedicated screen for related entries, fetching directly from sources</changelogtext>
<changelogtext>Faster loading of related entries</changelogtext>
<changelogtext>Enable fetching related entries from site's entry page (things like "More like this", "Recommendations" etc.)</changelogtext>
<changelogtext>[b]New[/b] A dedicated screen for related entries, fetching directly from sources</changelogtext>
<changelogtext>[b]Improved[/b] Faster loading of related entries</changelogtext>
<changelogtext>[b]Improved[/b] Enable fetching related entries from site's entry page (things like "More like this", "Recommendations" etc.)</changelogtext>
<changelogtext>Improve &amp; fix bugs of algorithm looking for related entries</changelogtext>
<changelogtext>A peek into Preview-build's 'What's New' in About screen</changelogtext>
<changelogtext>Update to TachiyomiSY preview-142</changelogtext>
<changelogtext>[b]Improved[/b] Auto sync read chapters from Trackers &amp; mark read to update</changelogtext>
<changelogtext>[b]New[/b] A peek into Preview-build's 'What's New' in About screen</changelogtext>
<changelogtext>[b]Update to TachiyomiSY preview-142[/b]</changelogtext>
</changelogversion>
<changelogversion versionName="r8852" changeDate="May 9,2024">
<changelogtext>Beta build switch to 'preview' repo</changelogtext>

View file

@ -5,6 +5,7 @@
<changelogtext>[b]Improved[/b] Faster loading of related entries</changelogtext>
<changelogtext>[b]Improved[/b] Enable fetching related entries from site's entry page (things like "More like this", "Recommendations" etc.)</changelogtext>
<changelogtext>Improve &amp; fix bugs of algorithm looking for related entries</changelogtext>
<changelogtext>[b]Improved[/b] Auto sync read chapters from Trackers &amp; mark read to update</changelogtext>
<changelogtext>[b]New[/b] A peek into Preview-build's 'What's New' in About screen</changelogtext>
<changelogtext>[b]Update to TachiyomiSY 1.10.6[/b]</changelogtext>
<changelogtext>[b]Update to Mihon 0.16.6[/b]</changelogtext>

View file

@ -501,6 +501,8 @@
<!-- Tracking section -->
<string name="tracking_guide">Tracking guide</string>
<string name="pref_auto_update_manga_sync">Update progress after reading</string>
<string name="pref_update_tracking_marked_read">Update progress when marked as read</string>
<string name="pref_auto_sync_read_chapters">Auto sync read chapters from Trackers</string>
<string name="services">Trackers</string>
<string name="tracking_info">One-way sync to update the chapter progress in external tracker services. Set up tracking for individual entries from their tracking button.</string>
<string name="enhanced_services">Enhanced trackers</string>