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:
parent
81376ae818
commit
ce7177efc6
7 changed files with 98 additions and 12 deletions
|
|
@ -1,7 +1,6 @@
|
||||||
package eu.kanade.domain.track.interactor
|
package eu.kanade.domain.track.interactor
|
||||||
|
|
||||||
import eu.kanade.domain.track.model.toDbTrack
|
import eu.kanade.domain.track.model.toDbTrack
|
||||||
import eu.kanade.tachiyomi.data.track.EnhancedTracker
|
|
||||||
import eu.kanade.tachiyomi.data.track.Tracker
|
import eu.kanade.tachiyomi.data.track.Tracker
|
||||||
import logcat.LogPriority
|
import logcat.LogPriority
|
||||||
import tachiyomi.core.common.util.system.logcat
|
import tachiyomi.core.common.util.system.logcat
|
||||||
|
|
@ -22,26 +21,36 @@ class SyncChapterProgressWithTrack(
|
||||||
remoteTrack: Track,
|
remoteTrack: Track,
|
||||||
tracker: Tracker,
|
tracker: Tracker,
|
||||||
) {
|
) {
|
||||||
if (tracker !is EnhancedTracker) {
|
// KKM -->
|
||||||
return
|
// if (tracker !is EnhancedTracker) {
|
||||||
}
|
// return
|
||||||
|
// }
|
||||||
|
// <-- KKM
|
||||||
|
|
||||||
|
// Current chapters in database
|
||||||
val sortedChapters = getChaptersByMangaId.await(mangaId)
|
val sortedChapters = getChaptersByMangaId.await(mangaId)
|
||||||
.sortedBy { it.chapterNumber }
|
.sortedBy { it.chapterNumber }
|
||||||
.filter { it.isRecognizedNumber }
|
.filter { it.isRecognizedNumber }
|
||||||
|
|
||||||
|
// Chapters to update to follow tracker
|
||||||
val chapterUpdates = sortedChapters
|
val chapterUpdates = sortedChapters
|
||||||
.filter { chapter -> chapter.chapterNumber <= remoteTrack.lastChapterRead && !chapter.read }
|
.filter { chapter -> chapter.chapterNumber <= remoteTrack.lastChapterRead && !chapter.read }
|
||||||
.map { it.copy(read = true).toChapterUpdate() }
|
.map { it.copy(read = true).toChapterUpdate() }
|
||||||
|
|
||||||
// only take into account continuous reading
|
// only take into account continuous reading
|
||||||
val localLastRead = sortedChapters.takeWhile { it.read }.lastOrNull()?.chapterNumber ?: 0F
|
val localLastRead = sortedChapters.takeWhile { it.read }.lastOrNull()?.chapterNumber ?: 0F
|
||||||
|
// Tracker will update to latest read chapter
|
||||||
val updatedTrack = remoteTrack.copy(lastChapterRead = localLastRead.toDouble())
|
val updatedTrack = remoteTrack.copy(lastChapterRead = localLastRead.toDouble())
|
||||||
|
|
||||||
try {
|
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)
|
updateChapter.awaitAll(chapterUpdates)
|
||||||
insertTrack.await(updatedTrack)
|
|
||||||
} catch (e: Throwable) {
|
} catch (e: Throwable) {
|
||||||
logcat(LogPriority.WARN, e)
|
logcat(LogPriority.WARN, e)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,4 +35,6 @@ class TrackPreferences(
|
||||||
fun anilistScoreType() = preferenceStore.getString("anilist_score_type", Anilist.POINT_10)
|
fun anilistScoreType() = preferenceStore.getString("anilist_score_type", Anilist.POINT_10)
|
||||||
|
|
||||||
fun autoUpdateTrack() = preferenceStore.getBoolean("pref_auto_update_manga_sync_key", true)
|
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)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -125,6 +125,14 @@ object SettingsTrackingScreen : SearchableSettings {
|
||||||
pref = trackPreferences.autoUpdateTrack(),
|
pref = trackPreferences.autoUpdateTrack(),
|
||||||
title = stringResource(MR.strings.pref_auto_update_manga_sync),
|
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(
|
Preference.PreferenceGroup(
|
||||||
title = stringResource(MR.strings.services),
|
title = stringResource(MR.strings.services),
|
||||||
preferenceItems = persistentListOf(
|
preferenceItems = persistentListOf(
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
package eu.kanade.tachiyomi.ui.manga
|
package eu.kanade.tachiyomi.ui.manga
|
||||||
|
|
||||||
|
import android.app.Application
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import androidx.compose.material3.SnackbarHostState
|
import androidx.compose.material3.SnackbarHostState
|
||||||
import androidx.compose.material3.SnackbarResult
|
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.manga.model.toSManga
|
||||||
import eu.kanade.domain.source.service.SourcePreferences
|
import eu.kanade.domain.source.service.SourcePreferences
|
||||||
import eu.kanade.domain.track.interactor.AddTracks
|
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.model.toDomainTrack
|
||||||
|
import eu.kanade.domain.track.service.TrackPreferences
|
||||||
import eu.kanade.domain.ui.UiPreferences
|
import eu.kanade.domain.ui.UiPreferences
|
||||||
import eu.kanade.presentation.manga.DownloadAction
|
import eu.kanade.presentation.manga.DownloadAction
|
||||||
import eu.kanade.presentation.manga.components.ChapterDownloadAction
|
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.chapter.getNextUnread
|
||||||
import eu.kanade.tachiyomi.util.removeCovers
|
import eu.kanade.tachiyomi.util.removeCovers
|
||||||
import eu.kanade.tachiyomi.util.shouldDownloadNewChapters
|
import eu.kanade.tachiyomi.util.shouldDownloadNewChapters
|
||||||
|
import eu.kanade.tachiyomi.util.system.toast
|
||||||
import exh.debug.DebugToggles
|
import exh.debug.DebugToggles
|
||||||
import exh.eh.EHentaiUpdateHelper
|
import exh.eh.EHentaiUpdateHelper
|
||||||
import exh.log.xLogD
|
import exh.log.xLogD
|
||||||
|
|
@ -156,6 +161,10 @@ class MangaScreenModel(
|
||||||
private val libraryPreferences: LibraryPreferences = Injekt.get(),
|
private val libraryPreferences: LibraryPreferences = Injekt.get(),
|
||||||
readerPreferences: ReaderPreferences = Injekt.get(),
|
readerPreferences: ReaderPreferences = Injekt.get(),
|
||||||
uiPreferences: UiPreferences = 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 trackerManager: TrackerManager = Injekt.get(),
|
||||||
private val downloadManager: DownloadManager = Injekt.get(),
|
private val downloadManager: DownloadManager = Injekt.get(),
|
||||||
private val downloadCache: DownloadCache = Injekt.get(),
|
private val downloadCache: DownloadCache = Injekt.get(),
|
||||||
|
|
@ -450,6 +459,7 @@ class MangaScreenModel(
|
||||||
}
|
}
|
||||||
// KMK <--
|
// KMK <--
|
||||||
val fetchFromSourceTasks = listOf(
|
val fetchFromSourceTasks = listOf(
|
||||||
|
async { syncTrackers() },
|
||||||
async { if (needRefreshInfo) fetchMangaFromSource() },
|
async { if (needRefreshInfo) fetchMangaFromSource() },
|
||||||
async { if (needRefreshChapter) fetchChaptersFromSource() },
|
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) {
|
fun fetchAllFromSource(manualFetch: Boolean = true) {
|
||||||
screenModelScope.launch {
|
screenModelScope.launch {
|
||||||
updateSuccessState { it.copy(isRefreshingData = true) }
|
updateSuccessState { it.copy(isRefreshingData = true) }
|
||||||
val fetchFromSourceTasks = listOf(
|
val fetchFromSourceTasks = listOf(
|
||||||
|
async { syncTrackers() },
|
||||||
async { fetchMangaFromSource(manualFetch) },
|
async { fetchMangaFromSource(manualFetch) },
|
||||||
async { fetchChaptersFromSource(manualFetch) },
|
async { fetchChaptersFromSource(manualFetch) },
|
||||||
)
|
)
|
||||||
|
|
@ -669,7 +704,7 @@ class MangaScreenModel(
|
||||||
mergedManga = networkToLocalManga.await(mergedManga)
|
mergedManga = networkToLocalManga.await(mergedManga)
|
||||||
|
|
||||||
getCategories.await(originalMangaId)
|
getCategories.await(originalMangaId)
|
||||||
.let {
|
.let { it ->
|
||||||
setMangaCategories.await(mergedManga.id, it.map { it.id })
|
setMangaCategories.await(mergedManga.id, it.map { it.id })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1163,6 +1198,11 @@ class MangaScreenModel(
|
||||||
when (swipeAction) {
|
when (swipeAction) {
|
||||||
LibraryPreferences.ChapterSwipeAction.ToggleRead -> {
|
LibraryPreferences.ChapterSwipeAction.ToggleRead -> {
|
||||||
markChaptersRead(listOf(chapter), !chapter.read)
|
markChaptersRead(listOf(chapter), !chapter.read)
|
||||||
|
// KMK -->
|
||||||
|
if (!chapter.read) {
|
||||||
|
updateTrackChapterMarkedAsRead(chapter)
|
||||||
|
}
|
||||||
|
// KMK <--
|
||||||
}
|
}
|
||||||
LibraryPreferences.ChapterSwipeAction.ToggleBookmark -> {
|
LibraryPreferences.ChapterSwipeAction.ToggleBookmark -> {
|
||||||
bookmarkChapters(listOf(chapter), !chapter.bookmark)
|
bookmarkChapters(listOf(chapter), !chapter.bookmark)
|
||||||
|
|
@ -1306,9 +1346,32 @@ class MangaScreenModel(
|
||||||
chapters = chapters.toTypedArray(),
|
chapters = chapters.toTypedArray(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
// KMK -->
|
||||||
|
if (read) {
|
||||||
|
chapters.maxByOrNull { it.chapterNumber }
|
||||||
|
?.also { updateTrackChapterMarkedAsRead(it) }
|
||||||
|
}
|
||||||
|
// KMK <--
|
||||||
toggleAllSelection(false)
|
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.
|
* Downloads the given list of chapters with the manager.
|
||||||
* @param chapters the list of chapters to download.
|
* @param chapters the list of chapters to download.
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,13 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<changelog bulletedList="true">
|
<changelog bulletedList="true">
|
||||||
<changelogversion versionName="Latest (r8894)" changeDate="May 17, 2024">
|
<changelogversion versionName="Latest (r8894)" changeDate="May 17, 2024">
|
||||||
<changelogtext>A dedicated screen for related entries, fetching directly from sources</changelogtext>
|
<changelogtext>[b]New[/b] A dedicated screen for related entries, fetching directly from sources</changelogtext>
|
||||||
<changelogtext>Faster loading of related entries</changelogtext>
|
<changelogtext>[b]Improved[/b] 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]Improved[/b] Enable fetching related entries from site's entry page (things like "More like this", "Recommendations" etc.)</changelogtext>
|
||||||
<changelogtext>Improve & fix bugs of algorithm looking for related entries</changelogtext>
|
<changelogtext>Improve & fix bugs of algorithm looking for related entries</changelogtext>
|
||||||
<changelogtext>A peek into Preview-build's 'What's New' in About screen</changelogtext>
|
<changelogtext>[b]Improved[/b] Auto sync read chapters from Trackers & mark read to update</changelogtext>
|
||||||
<changelogtext>Update to TachiyomiSY preview-142</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>
|
||||||
<changelogversion versionName="r8852" changeDate="May 9,2024">
|
<changelogversion versionName="r8852" changeDate="May 9,2024">
|
||||||
<changelogtext>Beta build switch to 'preview' repo</changelogtext>
|
<changelogtext>Beta build switch to 'preview' repo</changelogtext>
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
<changelogtext>[b]Improved[/b] Faster loading of related entries</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>[b]Improved[/b] Enable fetching related entries from site's entry page (things like "More like this", "Recommendations" etc.)</changelogtext>
|
||||||
<changelogtext>Improve & fix bugs of algorithm looking for related entries</changelogtext>
|
<changelogtext>Improve & fix bugs of algorithm looking for related entries</changelogtext>
|
||||||
|
<changelogtext>[b]Improved[/b] Auto sync read chapters from Trackers & mark read to update</changelogtext>
|
||||||
<changelogtext>[b]New[/b] A peek into Preview-build's 'What's New' in About screen</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 TachiyomiSY 1.10.6[/b]</changelogtext>
|
||||||
<changelogtext>[b]Update to Mihon 0.16.6[/b]</changelogtext>
|
<changelogtext>[b]Update to Mihon 0.16.6[/b]</changelogtext>
|
||||||
|
|
|
||||||
|
|
@ -501,6 +501,8 @@
|
||||||
<!-- Tracking section -->
|
<!-- Tracking section -->
|
||||||
<string name="tracking_guide">Tracking guide</string>
|
<string name="tracking_guide">Tracking guide</string>
|
||||||
<string name="pref_auto_update_manga_sync">Update progress after reading</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="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="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>
|
<string name="enhanced_services">Enhanced trackers</string>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue