mirror of
https://github.com/tachiyomiorg/tachiyomi.git
synced 2024-11-20 13:29:17 +01:00
feat(SyncManager): implement timestamp optimization in sync process
Introduce timestamp optimization to sync process by storing the last successful sync timestamp. Now, only records modified after this timestamp are queried, ensuring efficiency by considering only the latest changes. Import measureTimeMillis for performance measurement, add processFavoriteManga method to refine favorite manga processing, and update various conditions for streamlined sync checks. Enhance logging for better process visibility and timing accuracy. Signed-off-by: KaiserBh <kaiserbh@proton.me>
This commit is contained in:
parent
35ce19d8f3
commit
db4ec11262
@ -31,6 +31,7 @@ import java.io.File
|
|||||||
import java.io.FileOutputStream
|
import java.io.FileOutputStream
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
|
import kotlin.system.measureTimeMillis
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A manager to handle synchronization tasks in the app, such as updating
|
* A manager to handle synchronization tasks in the app, such as updating
|
||||||
@ -122,8 +123,10 @@ class SyncManager(
|
|||||||
val (filteredFavorites, nonFavorites) = filterFavoritesAndNonFavorites(remoteBackup)
|
val (filteredFavorites, nonFavorites) = filterFavoritesAndNonFavorites(remoteBackup)
|
||||||
updateNonFavorites(nonFavorites)
|
updateNonFavorites(nonFavorites)
|
||||||
|
|
||||||
|
val mangas = processFavoriteManga(filteredFavorites)
|
||||||
|
|
||||||
val newSyncData = backup.copy(
|
val newSyncData = backup.copy(
|
||||||
backupManga = filteredFavorites,
|
backupManga = mangas,
|
||||||
backupCategories = remoteBackup.backupCategories,
|
backupCategories = remoteBackup.backupCategories,
|
||||||
backupSources = remoteBackup.backupSources,
|
backupSources = remoteBackup.backupSources,
|
||||||
backupPreferences = remoteBackup.backupPreferences,
|
backupPreferences = remoteBackup.backupPreferences,
|
||||||
@ -131,7 +134,7 @@ class SyncManager(
|
|||||||
)
|
)
|
||||||
|
|
||||||
// It's local sync no need to restore data. (just update remote data)
|
// It's local sync no need to restore data. (just update remote data)
|
||||||
if (filteredFavorites.isEmpty()) {
|
if (mangas.isEmpty()) {
|
||||||
// update the sync timestamp
|
// update the sync timestamp
|
||||||
syncPreferences.lastSyncTimestamp().set(Date().time)
|
syncPreferences.lastSyncTimestamp().set(Date().time)
|
||||||
return
|
return
|
||||||
@ -150,6 +153,9 @@ class SyncManager(
|
|||||||
library = true,
|
library = true,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// update the sync timestamp
|
||||||
|
syncPreferences.lastSyncTimestamp().set(Date().time)
|
||||||
} else {
|
} else {
|
||||||
logcat(LogPriority.ERROR) { "Failed to write sync data to file" }
|
logcat(LogPriority.ERROR) { "Failed to write sync data to file" }
|
||||||
}
|
}
|
||||||
@ -185,10 +191,6 @@ class SyncManager(
|
|||||||
return localManga.source != remoteManga.source ||
|
return localManga.source != remoteManga.source ||
|
||||||
localManga.url != remoteManga.url ||
|
localManga.url != remoteManga.url ||
|
||||||
localManga.title != remoteManga.title ||
|
localManga.title != remoteManga.title ||
|
||||||
localManga.artist != remoteManga.artist ||
|
|
||||||
localManga.author != remoteManga.author ||
|
|
||||||
localManga.description != remoteManga.description ||
|
|
||||||
localManga.genre != remoteManga.genre ||
|
|
||||||
localManga.status.toInt() != remoteManga.status ||
|
localManga.status.toInt() != remoteManga.status ||
|
||||||
localManga.thumbnailUrl != remoteManga.thumbnailUrl ||
|
localManga.thumbnailUrl != remoteManga.thumbnailUrl ||
|
||||||
localManga.dateAdded != remoteManga.dateAdded ||
|
localManga.dateAdded != remoteManga.dateAdded ||
|
||||||
@ -217,15 +219,10 @@ class SyncManager(
|
|||||||
val localChapter = localChapterMap[remoteChapter.url]
|
val localChapter = localChapterMap[remoteChapter.url]
|
||||||
localChapter == null || // No corresponding local chapter
|
localChapter == null || // No corresponding local chapter
|
||||||
localChapter.url != remoteChapter.url ||
|
localChapter.url != remoteChapter.url ||
|
||||||
localChapter.name != remoteChapter.name ||
|
|
||||||
localChapter.scanlator != remoteChapter.scanlator ||
|
|
||||||
localChapter.read != remoteChapter.read ||
|
localChapter.read != remoteChapter.read ||
|
||||||
localChapter.bookmark != remoteChapter.bookmark ||
|
localChapter.bookmark != remoteChapter.bookmark ||
|
||||||
localChapter.last_page_read != remoteChapter.lastPageRead ||
|
localChapter.last_page_read != remoteChapter.lastPageRead ||
|
||||||
localChapter.chapter_number != remoteChapter.chapterNumber ||
|
localChapter.chapter_number != remoteChapter.chapterNumber
|
||||||
localChapter.source_order != remoteChapter.sourceOrder ||
|
|
||||||
localChapter.date_fetch != remoteChapter.dateFetch ||
|
|
||||||
localChapter.date_upload != remoteChapter.dateUpload
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -235,26 +232,85 @@ class SyncManager(
|
|||||||
* @return a Pair of lists, where the first list contains different favorite manga and the second list contains non-favorite manga.
|
* @return a Pair of lists, where the first list contains different favorite manga and the second list contains non-favorite manga.
|
||||||
*/
|
*/
|
||||||
private suspend fun filterFavoritesAndNonFavorites(backup: Backup): Pair<List<BackupManga>, List<BackupManga>> {
|
private suspend fun filterFavoritesAndNonFavorites(backup: Backup): Pair<List<BackupManga>, List<BackupManga>> {
|
||||||
val databaseMangaFavorites = getFavorites.await()
|
|
||||||
val localMangaMap = databaseMangaFavorites.associateBy { it.url }
|
|
||||||
val favorites = mutableListOf<BackupManga>()
|
val favorites = mutableListOf<BackupManga>()
|
||||||
val nonFavorites = mutableListOf<BackupManga>()
|
val nonFavorites = mutableListOf<BackupManga>()
|
||||||
|
val elapsedTimeMillis = measureTimeMillis {
|
||||||
|
val databaseMangaFavorites = getFavorites.await()
|
||||||
|
val localMangaMap = databaseMangaFavorites.associateBy { it.url }
|
||||||
|
|
||||||
backup.backupManga.forEach { remoteManga ->
|
logcat(LogPriority.DEBUG) { "Starting to filter favorites and non-favorites from backup data." }
|
||||||
if (remoteManga.favorite) {
|
|
||||||
localMangaMap[remoteManga.url]?.let { localManga ->
|
backup.backupManga.forEach { remoteManga ->
|
||||||
if (isMangaDifferent(localManga, remoteManga)) {
|
val localManga = localMangaMap[remoteManga.url]
|
||||||
favorites.add(remoteManga)
|
when {
|
||||||
|
// Checks if the manga is in favorites and needs updating or adding
|
||||||
|
remoteManga.favorite -> {
|
||||||
|
if (localManga == null || isMangaDifferent(localManga, remoteManga)) {
|
||||||
|
logcat(LogPriority.DEBUG) { "Adding to favorites: ${remoteManga.title}" }
|
||||||
|
favorites.add(remoteManga)
|
||||||
|
} else {
|
||||||
|
logcat(LogPriority.DEBUG) { "Already up-to-date favorite: ${remoteManga.title}" }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} ?: favorites.add(remoteManga)
|
// Handle non-favorites
|
||||||
} else {
|
!remoteManga.favorite -> {
|
||||||
nonFavorites.add(remoteManga)
|
logcat(LogPriority.DEBUG) { "Adding to non-favorites: ${remoteManga.title}" }
|
||||||
|
nonFavorites.add(remoteManga)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val minutes = elapsedTimeMillis / 60000
|
||||||
|
val seconds = (elapsedTimeMillis % 60000) / 1000
|
||||||
|
logcat(LogPriority.DEBUG) { "Filtering completed in ${minutes}m ${seconds}s. Favorites found: ${favorites.size}, Non-favorites found: ${nonFavorites.size}" }
|
||||||
|
|
||||||
return Pair(favorites, nonFavorites)
|
return Pair(favorites, nonFavorites)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun processFavoriteManga(backupManga: List<BackupManga>): List<BackupManga> {
|
||||||
|
val mangas = mutableListOf<BackupManga>()
|
||||||
|
val lastSyncTimeStamp = syncPreferences.lastSyncTimestamp().get()
|
||||||
|
|
||||||
|
val elapsedTimeMillis = measureTimeMillis {
|
||||||
|
logcat(LogPriority.DEBUG) { "Starting to process BackupMangas." }
|
||||||
|
backupManga.forEach { manga ->
|
||||||
|
val mangaLastUpdatedStatus = manga.lastModifiedAt * 1000L > lastSyncTimeStamp
|
||||||
|
val chaptersUpdatedStatus = chaptersUpdatedAfterSync(manga, lastSyncTimeStamp)
|
||||||
|
|
||||||
|
if (mangaLastUpdatedStatus || chaptersUpdatedStatus) {
|
||||||
|
mangas.add(manga)
|
||||||
|
logcat(LogPriority.DEBUG) {
|
||||||
|
"Added ${manga.title} to the process list. Manga Last Updated: ${mangaLastUpdatedStatus}, Chapters Updated: ${chaptersUpdatedStatus}."
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logcat(LogPriority.DEBUG) {
|
||||||
|
"Skipped ${manga.title} as it has not been updated since the last sync (Last Modified: ${manga.lastModifiedAt * 1000L}, Last Sync: $lastSyncTimeStamp)."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val minutes = elapsedTimeMillis / 60000
|
||||||
|
val seconds = (elapsedTimeMillis % 60000) / 1000
|
||||||
|
logcat(LogPriority.DEBUG) { "Processing completed in ${minutes}m ${seconds}s. Total Processed: ${mangas.size}" }
|
||||||
|
|
||||||
|
return mangas
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun chaptersUpdatedAfterSync(manga: BackupManga, lastSyncTimeStamp: Long): Boolean {
|
||||||
|
return manga.chapters.any { chapter ->
|
||||||
|
val updated = chapter.lastModifiedAt * 1000L > lastSyncTimeStamp
|
||||||
|
if(updated) {
|
||||||
|
logcat(LogPriority.DEBUG) {
|
||||||
|
"Chapter ${chapter.name} of ${manga.title} updated after last sync (Chapter Last Modified: ${chapter.lastModifiedAt}, Last Sync: $lastSyncTimeStamp)."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
updated
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the non-favorite manga in the local database with their favorite status from the backup.
|
* Updates the non-favorite manga in the local database with their favorite status from the backup.
|
||||||
* @param nonFavorites the list of non-favorite BackupManga objects from the backup.
|
* @param nonFavorites the list of non-favorite BackupManga objects from the backup.
|
||||||
|
Loading…
Reference in New Issue
Block a user