diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupManga.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupManga.kt index 9a35302555..ae40c83583 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupManga.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupManga.kt @@ -1,8 +1,6 @@ package eu.kanade.tachiyomi.data.backup.models import eu.kanade.tachiyomi.data.database.models.ChapterImpl -import eu.kanade.tachiyomi.data.database.models.MangaImpl -import eu.kanade.tachiyomi.data.database.models.TrackImpl import eu.kanade.tachiyomi.data.library.CustomMangaManager import eu.kanade.tachiyomi.source.model.UpdateStrategy import eu.kanade.tachiyomi.util.chapter.ChapterUtil @@ -11,6 +9,7 @@ import kotlinx.serialization.protobuf.ProtoNumber import yokai.data.manga.models.readingModeType import yokai.domain.library.custom.model.CustomMangaInfo import yokai.domain.manga.models.Manga +import yokai.domain.track.models.Track @Suppress("DEPRECATION") @Serializable @@ -56,27 +55,28 @@ data class BackupManga( @ProtoNumber(804) var customDescription: String? = null, @ProtoNumber(805) var customGenre: List? = null, ) { - fun getMangaImpl(): MangaImpl { - return MangaImpl().apply { - url = this@BackupManga.url - title = this@BackupManga.title - artist = this@BackupManga.artist - author = this@BackupManga.author - description = this@BackupManga.description - genre = this@BackupManga.genre.joinToString() - status = this@BackupManga.status - thumbnail_url = this@BackupManga.thumbnailUrl - favorite = this@BackupManga.favorite - source = this@BackupManga.source - date_added = this@BackupManga.dateAdded - viewer_flags = ( + fun getMangaImpl(): Manga { + return Manga( + id = null, + url = this@BackupManga.url, + ogTitle = this@BackupManga.title, + ogArtist = this@BackupManga.artist, + ogAuthor = this@BackupManga.author, + ogDescription = this@BackupManga.description, + ogGenres = this@BackupManga.genre, + ogStatus = this@BackupManga.status, + thumbnailUrl = this@BackupManga.thumbnailUrl, + favorite = this@BackupManga.favorite, + source = this@BackupManga.source, + dateAdded = this@BackupManga.dateAdded, + viewerFlags = ( this@BackupManga.viewer_flags ?: this@BackupManga.viewer ).takeIf { it != 0 } - ?: -1 - chapter_flags = this@BackupManga.chapterFlags - update_strategy = this@BackupManga.updateStrategy - } + ?: -1, + chapterFlags = this@BackupManga.chapterFlags, + updateStrategy = this@BackupManga.updateStrategy, + ) } fun getChaptersImpl(): List { @@ -106,7 +106,7 @@ data class BackupManga( return null } - fun getTrackingImpl(): List { + fun getTrackingImpl(): List { return tracking.map { it.getTrackingImpl() } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupTracking.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupTracking.kt index f9fb5f3b00..74fef16f1e 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupTracking.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupTracking.kt @@ -1,6 +1,5 @@ package eu.kanade.tachiyomi.data.backup.models -import eu.kanade.tachiyomi.data.database.models.TrackImpl import kotlinx.serialization.Serializable import kotlinx.serialization.protobuf.ProtoNumber import yokai.domain.track.models.Track @@ -30,24 +29,25 @@ data class BackupTracking( @ProtoNumber(100) var mediaId: Long = 0, ) { - fun getTrackingImpl(): TrackImpl { - return TrackImpl().apply { - sync_id = this@BackupTracking.syncId - media_id = if (this@BackupTracking.mediaIdInt != 0) { + fun getTrackingImpl(): Track { + return Track( + id = -1L, + syncId = this@BackupTracking.syncId, + mediaId = if (this@BackupTracking.mediaIdInt != 0) { this@BackupTracking.mediaIdInt.toLong() } else { this@BackupTracking.mediaId - } - library_id = this@BackupTracking.libraryId - title = this@BackupTracking.title - last_chapter_read = this@BackupTracking.lastChapterRead - total_chapters = this@BackupTracking.totalChapters - score = this@BackupTracking.score - status = this@BackupTracking.status - started_reading_date = this@BackupTracking.startedReadingDate - finished_reading_date = this@BackupTracking.finishedReadingDate - tracking_url = this@BackupTracking.trackingUrl - } + }, + libraryId = this@BackupTracking.libraryId, + title = this@BackupTracking.title, + lastChapterRead = this@BackupTracking.lastChapterRead, + totalChapters = this@BackupTracking.totalChapters, + score = this@BackupTracking.score, + status = this@BackupTracking.status, + startedReadingDate = this@BackupTracking.startedReadingDate, + finishedReadingDate = this@BackupTracking.finishedReadingDate, + trackingUrl = this@BackupTracking.trackingUrl, + ) } companion object { diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/restorers/MangaBackupRestorer.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/restorers/MangaBackupRestorer.kt index d5701f469f..054bc786ac 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/restorers/MangaBackupRestorer.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/restorers/MangaBackupRestorer.kt @@ -3,11 +3,7 @@ package eu.kanade.tachiyomi.data.backup.restore.restorers import eu.kanade.tachiyomi.data.backup.models.BackupCategory import eu.kanade.tachiyomi.data.backup.models.BackupHistory import eu.kanade.tachiyomi.data.backup.models.BackupManga -import eu.kanade.tachiyomi.data.database.DatabaseHelper import eu.kanade.tachiyomi.data.database.models.Chapter -import eu.kanade.tachiyomi.data.database.models.History -import eu.kanade.tachiyomi.data.database.models.Manga -import eu.kanade.tachiyomi.data.database.models.Track import eu.kanade.tachiyomi.data.library.CustomMangaManager import eu.kanade.tachiyomi.data.library.LibraryUpdateJob import eu.kanade.tachiyomi.source.model.SChapter @@ -16,23 +12,39 @@ import eu.kanade.tachiyomi.util.manga.MangaUtil import eu.kanade.tachiyomi.util.system.launchNow import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get +import yokai.data.DatabaseHandler +import yokai.data.manga.models.copyFrom import yokai.domain.category.interactor.GetCategories import yokai.domain.chapter.interactor.GetChapter +import yokai.domain.chapter.interactor.UpdateChapter +import yokai.domain.history.interactor.GetHistory +import yokai.domain.history.interactor.UpsertHistory +import yokai.domain.history.models.HistoryUpdate import yokai.domain.library.custom.model.CustomMangaInfo +import yokai.domain.manga.category.interactor.DeleteMangaCategory import yokai.domain.manga.interactor.GetManga import yokai.domain.manga.interactor.InsertManga import yokai.domain.manga.interactor.UpdateManga +import yokai.domain.manga.models.Manga import yokai.domain.manga.models.MangaCategory +import yokai.domain.track.interactor.GetTrack +import yokai.domain.track.models.Track +import yokai.domain.track.models.TrackUpdate import kotlin.math.max class MangaBackupRestorer( - private val db: DatabaseHelper = Injekt.get(), + private val handler: DatabaseHandler = Injekt.get(), private val customMangaManager: CustomMangaManager = Injekt.get(), private val getCategories: GetCategories = Injekt.get(), private val getChapter: GetChapter = Injekt.get(), + private val updateChapter: UpdateChapter = Injekt.get(), + private val getHistory: GetHistory = Injekt.get(), + private val upsertHistory: UpsertHistory = Injekt.get(), private val getManga: GetManga = Injekt.get(), private val insertManga: InsertManga = Injekt.get(), private val updateManga: UpdateManga = Injekt.get(), + private val deleteMangaCategory: DeleteMangaCategory = Injekt.get(), + private val getTrack: GetTrack = Injekt.get(), ) { suspend fun restoreManga( backupManga: BackupManga, @@ -57,12 +69,13 @@ class MangaBackupRestorer( } else { // Manga in database // Copy information from manga already in database - manga.id = dbManga.id - manga.filtered_scanlators = dbManga.filtered_scanlators - manga.copyFrom(dbManga) - updateManga.await(manga.toMangaUpdate()) + val copy = manga.copy( + id = dbManga.id, + filteredScanlators = dbManga.filteredScanlators + ).copyFrom(dbManga) + updateManga.await(copy.toMangaUpdate()) // Fetch rest of manga information - restoreExistingManga(manga, chapters, categories, history, tracks, backupCategories, filteredScanlators, customManga) + restoreExistingManga(copy, chapters, categories, history, tracks, backupCategories, filteredScanlators, customManga) } } catch (e: Exception) { onError(manga, e) @@ -89,10 +102,10 @@ class MangaBackupRestorer( filteredScanlators: List, customManga: CustomMangaInfo?, ) { - val fetchedManga = manga.also { - it.initialized = it.description != null - it.id = insertManga.await(it) - } + val fetchedManga = manga.copy( + initialized = manga.ogDescription != null, + id = insertManga.await(manga), + ) fetchedManga.id ?: return restoreChapters(fetchedManga, chapters) @@ -136,10 +149,30 @@ class MangaBackupRestorer( } val newChapters = chapters.groupBy { it.id != null } - newChapters[true]?.let { db.updateKnownChaptersBackup(it).executeAsBlocking() } - newChapters[false]?.let { db.insertChapters(it).executeAsBlocking() } + newChapters[true]?.let { updateChapter.awaitAll(it.map{ c -> c.toChapterUpdate() }) } + newChapters[false]?.let { insertChapters(it) } } + private suspend fun insertChapters(chapters: List) = + handler.await(true) { + chapters.forEach { chapter -> + chaptersQueries.insert( + mangaId = chapter.manga_id!!, + url = chapter.url, + name = chapter.name, + scanlator = chapter.scanlator, + read = chapter.read, + bookmark = chapter.bookmark, + lastPageRead = chapter.last_page_read.toLong(), + pagesLeft = chapter.pages_left.toLong(), + chapterNumber = chapter.chapter_number.toDouble(), + sourceOrder = chapter.source_order.toLong(), + dateFetch = chapter.date_fetch, + dateUpload = chapter.date_upload, + ) + } + } + private suspend fun restoreExtras( manga: Manga, categories: List, @@ -177,15 +210,19 @@ class MangaBackupRestorer( dbCategories.firstOrNull { dbCategory -> dbCategory.name == backupCategory.name }?.let { dbCategory -> - mangaCategoriesToUpdate += MangaCategory.create(manga, dbCategory) + mangaCategoriesToUpdate += MangaCategory(manga.id!!, dbCategory.id?.toLong()!!) } } } // Update database if (mangaCategoriesToUpdate.isNotEmpty()) { - db.deleteOldMangasCategories(listOf(manga)).executeAsBlocking() - db.insertMangasCategories(mangaCategoriesToUpdate).executeAsBlocking() + deleteMangaCategory.awaitByMangaId(manga.id!!) + handler.await(true) { + mangaCategoriesToUpdate.forEach { update -> + mangas_categoriesQueries.insert(update.mangaId, update.categoryId.toLong()) + } + } } } @@ -196,28 +233,32 @@ class MangaBackupRestorer( */ internal suspend fun restoreHistoryForManga(history: List) { // List containing history to be updated - val historyToBeUpdated = ArrayList(history.size) + val historyToBeUpdated = ArrayList(history.size) for ((url, lastRead, readDuration) in history) { - val dbHistory = db.getHistoryByChapterUrl(url).executeAsBlocking() + val dbHistory = getHistory.awaitByChapterUrl(url) // Check if history already in database and update if (dbHistory != null) { - dbHistory.apply { - last_read = max(lastRead, dbHistory.last_read) - time_read = max(readDuration, dbHistory.time_read) - } - historyToBeUpdated.add(dbHistory) + historyToBeUpdated.add( + HistoryUpdate( + chapterId = dbHistory.chapterId, + readAt = max(lastRead, dbHistory.timeRead), + sessionReadDuration = max(readDuration, dbHistory.timeRead), + ) + ) } else { // If not in database create - db.getChapter(url).executeAsBlocking()?.let { - val historyToAdd = History.create(it).apply { - last_read = lastRead - time_read = readDuration - } - historyToBeUpdated.add(historyToAdd) + getChapter.await(url)?.let { + historyToBeUpdated.add( + HistoryUpdate( + chapterId = it.id!!, + readAt = lastRead, + sessionReadDuration = readDuration, + ) + ) } } } - db.upsertHistoryLastRead(historyToBeUpdated).executeAsBlocking() + upsertHistory.awaitAll(historyToBeUpdated) } /** @@ -228,43 +269,67 @@ class MangaBackupRestorer( */ private suspend fun restoreTrackForManga(manga: Manga, tracks: List) { // Fix foreign keys with the current manga id - tracks.map { it.manga_id = manga.id!! } + val actualTracks = tracks.map { it.copy(mangaId = manga.id!!) } // Get tracks from database - val dbTracks = db.getTracks(manga).executeAsBlocking() - val trackToUpdate = mutableListOf() + val dbTracks = getTrack.awaitAllByMangaId(manga.id!!) + val trackToUpdate = mutableListOf() + val trackToAdd = mutableListOf() - tracks.forEach { track -> + actualTracks.forEach { track -> var isInDatabase = false for (dbTrack in dbTracks) { - if (track.sync_id == dbTrack.sync_id) { - // The sync is already in the db, only update its fields - if (track.media_id != dbTrack.media_id) { - dbTrack.media_id = track.media_id - } - if (track.library_id != dbTrack.library_id) { - dbTrack.library_id = track.library_id - } - dbTrack.last_chapter_read = max(dbTrack.last_chapter_read, track.last_chapter_read) + if (track.syncId == dbTrack.syncId) { + val update = TrackUpdate( + id = dbTrack.id, + lastChapterRead = max(dbTrack.lastChapterRead, track.lastChapterRead), + // The sync is already in the db, only update its fields + mediaId = if (track.mediaId != dbTrack.mediaId) track.mediaId else null, + libraryId = if (track.libraryId != dbTrack.libraryId) track.libraryId else null, + ) isInDatabase = true - trackToUpdate.add(dbTrack) + trackToUpdate.add(update) break } } if (!isInDatabase) { // Insert new sync. Let the db assign the id - track.id = null - trackToUpdate.add(track) + trackToAdd.add(track.copy(id = -1L)) } } // Update database - if (trackToUpdate.isNotEmpty()) { - db.insertTracks(trackToUpdate).executeAsBlocking() + handler.await(true) { + trackToUpdate.forEach { update -> + manga_syncQueries.update( + trackId = update.id, + mangaId = update.mangaId, + trackingUrl = update.trackingUrl, + lastChapterRead = update.lastChapterRead?.toDouble(), + mediaId = update.mediaId, + libraryId = update.libraryId, + ) + } + trackToAdd.forEach { track -> + manga_syncQueries.insert( + mangaId = track.mangaId, + syncId = track.syncId.toLong(), + lastChapterRead = track.lastChapterRead.toDouble(), + mediaId = track.mediaId, + libraryId = track.libraryId, + title = track.title, + totalChapters = track.totalChapters.toLong(), + status = track.status.toLong(), + score = track.score.toDouble(), + trackingUrl = track.trackingUrl, + startDate = track.startedReadingDate, + finishDate = track.finishedReadingDate, + ) + } } } private suspend fun restoreFilteredScanlatorsForManga(manga: Manga, filteredScanlators: List) { - val actualList = ChapterUtil.getScanlators(manga.filtered_scanlators) + filteredScanlators + val actualList = ChapterUtil.getScanlators(manga.filteredScanlators) + filteredScanlators MangaUtil.setScanlatorFilter(updateManga, manga, actualList.toSet()) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/models/Chapter.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/models/Chapter.kt index 450bc71203..e380e2eed3 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/database/models/Chapter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/database/models/Chapter.kt @@ -1,6 +1,7 @@ package eu.kanade.tachiyomi.data.database.models import eu.kanade.tachiyomi.source.model.SChapter +import yokai.domain.chapter.models.ChapterUpdate import java.io.Serializable interface Chapter : SChapter, Serializable { @@ -24,6 +25,23 @@ interface Chapter : SChapter, Serializable { val isRecognizedNumber: Boolean get() = chapter_number >= 0f + fun toChapterUpdate() = + ChapterUpdate( + id = id ?: -1, + mangaId = manga_id ?: -1, + url = url, + name = name, + scanlator = scanlator, + read = read, + bookmark = bookmark, + lastPageRead = last_page_read.toLong(), + pagesLeft = pages_left.toLong(), + chapterNumber = chapter_number.toDouble(), + sourceOrder = source_order.toLong(), + dateFetch = date_fetch, + dateUpload = date_upload + ) + companion object { fun create(): Chapter = ChapterImpl().apply { diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/EnhancedTrackService.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/EnhancedTrackService.kt index e095c3a8e3..eaab907267 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/EnhancedTrackService.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/EnhancedTrackService.kt @@ -5,6 +5,7 @@ import eu.kanade.tachiyomi.source.Source import yokai.domain.manga.models.Manga import yokai.domain.track.models.Track import yokai.domain.track.models.TrackUpdate +import kotlin.math.max /** * An Enhanced Track Service will never prompt the user to match a manga with the remote. @@ -45,6 +46,7 @@ interface EnhancedTrackService { id = track.id, mangaId = manga.id!!, trackingUrl = manga.url, + lastChapterRead = max(dbTrack.lastChapterRead, track.lastChapterRead), ) } else { null diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/manga/MangaUtil.kt b/app/src/main/java/eu/kanade/tachiyomi/util/manga/MangaUtil.kt index 7235b9fc56..9a98ebc971 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/util/manga/MangaUtil.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/util/manga/MangaUtil.kt @@ -1,17 +1,19 @@ package eu.kanade.tachiyomi.util.manga -import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.util.chapter.ChapterUtil import yokai.domain.manga.interactor.UpdateManga +import yokai.domain.manga.models.Manga import yokai.domain.manga.models.MangaUpdate object MangaUtil { suspend fun setScanlatorFilter(updateManga: UpdateManga, manga: Manga, filteredScanlators: Set) { if (manga.id == null) return - manga.filtered_scanlators = - if (filteredScanlators.isEmpty()) null else ChapterUtil.getScanlatorString(filteredScanlators) - - updateManga.await(MangaUpdate(manga.id!!, filteredScanlators = manga.filtered_scanlators)) + updateManga.await(MangaUpdate( + manga.id!!, + filteredScanlators = if (filteredScanlators.isEmpty()) null else ChapterUtil.getScanlatorString( + filteredScanlators, + ), + )) } } diff --git a/app/src/main/java/yokai/data/chapter/ChapterRepositoryImpl.kt b/app/src/main/java/yokai/data/chapter/ChapterRepositoryImpl.kt index 2cd1bf848b..d9056c38b0 100644 --- a/app/src/main/java/yokai/data/chapter/ChapterRepositoryImpl.kt +++ b/app/src/main/java/yokai/data/chapter/ChapterRepositoryImpl.kt @@ -11,6 +11,8 @@ import yokai.domain.chapter.models.ChapterUpdate class ChapterRepositoryImpl(private val handler: DatabaseHandler) : ChapterRepository { override suspend fun getChapter(chapterId: Long): Chapter? = handler.awaitOneOrNull { chaptersQueries.find(chapterId, Chapter::mapper) } + override suspend fun getChapter(url: String): Chapter? = + handler.awaitOneOrNull { chaptersQueries.findByUrl(url, Chapter::mapper) } override suspend fun getChapters(mangaId: Long, filterScanlators: Boolean): List = handler.awaitList { chaptersQueries.getChaptersByMangaId(mangaId, filterScanlators.toInt().toLong(), Chapter::mapper) } diff --git a/app/src/main/java/yokai/data/history/HistoryRepositoryImpl.kt b/app/src/main/java/yokai/data/history/HistoryRepositoryImpl.kt index 8b4e986283..a1ec39422c 100644 --- a/app/src/main/java/yokai/data/history/HistoryRepositoryImpl.kt +++ b/app/src/main/java/yokai/data/history/HistoryRepositoryImpl.kt @@ -7,12 +7,15 @@ import yokai.domain.history.models.History import yokai.domain.history.models.HistoryUpdate class HistoryRepositoryImpl(private val handler: DatabaseHandler) : HistoryRepository { - override suspend fun findByMangaId(mangaId: Long): List = + override suspend fun findAllByMangaId(mangaId: Long): List = handler.awaitList { historyQueries.findByMangaId(mangaId, History::mapper) } - override suspend fun findBySourceUrl(url: String): List = + override suspend fun findAllByChapterUrl(url: String): List = handler.awaitList { historyQueries.findByChapterUrl(url, History::mapper) } + override suspend fun findByChapterUrl(url: String): History? = + handler.awaitOneOrNull { historyQueries.findByChapterUrl(url, History::mapper) } + override suspend fun upsert(update: HistoryUpdate): Boolean { return try { partialUpsert(update) diff --git a/app/src/main/java/yokai/data/manga/models/MangaExtensions.kt b/app/src/main/java/yokai/data/manga/models/MangaExtensions.kt index c678740353..a70f472ea7 100644 --- a/app/src/main/java/yokai/data/manga/models/MangaExtensions.kt +++ b/app/src/main/java/yokai/data/manga/models/MangaExtensions.kt @@ -6,6 +6,8 @@ import eu.kanade.tachiyomi.data.database.models.Manga.Companion.TYPE_MANGA import eu.kanade.tachiyomi.data.database.models.Manga.Companion.TYPE_MANHUA import eu.kanade.tachiyomi.data.database.models.Manga.Companion.TYPE_MANHWA import eu.kanade.tachiyomi.data.database.models.Manga.Companion.TYPE_WEBTOON +import eu.kanade.tachiyomi.data.download.DownloadManager +import eu.kanade.tachiyomi.data.download.DownloadProvider import eu.kanade.tachiyomi.data.library.CustomMangaManager import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.source.SourceManager @@ -20,23 +22,50 @@ import uy.kohesive.injekt.api.get import uy.kohesive.injekt.injectLazy import yokai.domain.chapter.interactor.GetChapter import yokai.domain.manga.models.Manga -import yokai.domain.manga.models.MangaUpdate import yokai.i18n.MR import yokai.util.lang.getString import java.util.* fun Manga.toSManga() = SManga.create().also { it.url = url - it.title = title - it.artist = artist - it.author = author - it.description = description - it.genre = genres.joinToString() - it.status = status + it.title = ogTitle + it.artist = ogArtist + it.author = ogAuthor + it.description = ogDescription + it.genre = ogGenres.joinToString() + it.status = ogStatus it.thumbnail_url = thumbnailUrl it.initialized = initialized } +fun Manga.copyFrom(other: Manga): Manga { + val title: String + if (other.ogTitle != ogTitle) { + title = other.ogTitle + val db: DownloadManager by injectLazy() + val provider = DownloadProvider(db.context) + provider.renameMangaFolder(ogTitle, other.title, source) + } else { + title = ogTitle + } + + val author = other.ogAuthor ?: ogAuthor + val artist = other.ogArtist ?: ogArtist + val description = other.ogDescription ?: ogDescription + val genres = other.ogGenres.ifEmpty { ogGenres } + val status = other.ogStatus.takeIf { it != -1 } ?: ogStatus + val thumbnailUrl = other.thumbnailUrl ?: thumbnailUrl + return this.copy( + ogTitle = title, + ogAuthor = author, + ogArtist = artist, + ogDescription = description, + ogGenres = genres, + ogStatus = status, + thumbnailUrl = thumbnailUrl, + ) +} + fun Manga.copyFrom(other: SManga): Manga { val author = other.author ?: ogAuthor val artist = other.artist ?: ogArtist @@ -124,30 +153,6 @@ var Manga.dominantCoverColors: Pair? MangaCoverMetadata.addCoverColor(this, value.first, value.second) } -fun Manga.toMangaUpdate(): MangaUpdate { - return MangaUpdate( - id = id!!, - source = source, - url = url, - artist = artist, - author = author, - description = description, - genres = genres, - title = title, - status = status, - thumbnailUrl = thumbnailUrl, - favorite = favorite, - lastUpdate = lastUpdate, - initialized = initialized, - viewerFlags = viewerFlags, - hideTitle = hideTitle, - chapterFlags = chapterFlags, - dateAdded = dateAdded, - filteredScanlators = filteredScanlators, - updateStrategy = updateStrategy, - ) -} - fun Manga.seriesType(context: Context, sourceManager: SourceManager? = null): String { return context.getString( when (seriesType(sourceManager = sourceManager)) { diff --git a/app/src/main/java/yokai/data/track/TrackRepositoryImpl.kt b/app/src/main/java/yokai/data/track/TrackRepositoryImpl.kt index 8c3521bd9c..7d21ca759a 100644 --- a/app/src/main/java/yokai/data/track/TrackRepositoryImpl.kt +++ b/app/src/main/java/yokai/data/track/TrackRepositoryImpl.kt @@ -40,6 +40,9 @@ class TrackRepositoryImpl(private val handler: DatabaseHandler) : TrackRepositor trackId = update.id, mangaId = update.mangaId, trackingUrl = update.trackingUrl, + lastChapterRead = update.lastChapterRead?.toDouble(), + mediaId = update.mediaId, + libraryId = update.libraryId, ) } } diff --git a/app/src/main/java/yokai/domain/chapter/ChapterRepository.kt b/app/src/main/java/yokai/domain/chapter/ChapterRepository.kt index 6d3ad48f76..d9f49b9ba1 100644 --- a/app/src/main/java/yokai/domain/chapter/ChapterRepository.kt +++ b/app/src/main/java/yokai/domain/chapter/ChapterRepository.kt @@ -6,6 +6,7 @@ import yokai.domain.chapter.models.ChapterUpdate interface ChapterRepository { suspend fun getChapter(chapterId: Long): Chapter? + suspend fun getChapter(url: String): Chapter? suspend fun getChapters(mangaId: Long, filterScanlators: Boolean): List fun getChaptersAsFlow(mangaId: Long, filterScanlators: Boolean): Flow> diff --git a/app/src/main/java/yokai/domain/chapter/interactor/GetChapter.kt b/app/src/main/java/yokai/domain/chapter/interactor/GetChapter.kt index d48e5683c8..1d66711270 100644 --- a/app/src/main/java/yokai/domain/chapter/interactor/GetChapter.kt +++ b/app/src/main/java/yokai/domain/chapter/interactor/GetChapter.kt @@ -7,6 +7,7 @@ class GetChapter( private val chapterRepository: ChapterRepository, ) { suspend fun await(chapterId: Long) = chapterRepository.getChapter(chapterId) + suspend fun await(url: String) = chapterRepository.getChapter(url) suspend fun awaitAll(mangaId: Long, filterScanlators: Boolean) = chapterRepository.getChapters(mangaId, filterScanlators) suspend fun awaitAll(manga: Manga, filterScanlators: Boolean? = null) = diff --git a/app/src/main/java/yokai/domain/history/HistoryRepository.kt b/app/src/main/java/yokai/domain/history/HistoryRepository.kt index fc2f24941a..3137bbcd56 100644 --- a/app/src/main/java/yokai/domain/history/HistoryRepository.kt +++ b/app/src/main/java/yokai/domain/history/HistoryRepository.kt @@ -4,8 +4,9 @@ import yokai.domain.history.models.History import yokai.domain.history.models.HistoryUpdate interface HistoryRepository { - suspend fun findByMangaId(mangaId: Long): List - suspend fun findBySourceUrl(url: String): List + suspend fun findAllByMangaId(mangaId: Long): List + suspend fun findAllByChapterUrl(url: String): List + suspend fun findByChapterUrl(url: String): History? suspend fun upsert(update: HistoryUpdate): Boolean suspend fun upsertAll(updates: List): Boolean } diff --git a/app/src/main/java/yokai/domain/history/interactor/GetHistory.kt b/app/src/main/java/yokai/domain/history/interactor/GetHistory.kt index 65fed9d1e8..5fec3c4310 100644 --- a/app/src/main/java/yokai/domain/history/interactor/GetHistory.kt +++ b/app/src/main/java/yokai/domain/history/interactor/GetHistory.kt @@ -5,6 +5,7 @@ import yokai.domain.history.HistoryRepository class GetHistory( private val historyRepository: HistoryRepository, ) { - suspend fun awaitAllByMangaId(mangaId: Long) = historyRepository.findByMangaId(mangaId) - suspend fun awaitAllBySourceUrl(url: String) = historyRepository.findBySourceUrl(url) + suspend fun awaitAllByMangaId(mangaId: Long) = historyRepository.findAllByMangaId(mangaId) + suspend fun awaitAllByChapterUrl(url: String) = historyRepository.findAllByChapterUrl(url) + suspend fun awaitByChapterUrl(url: String) = historyRepository.findByChapterUrl(url) } diff --git a/app/src/main/java/yokai/domain/manga/interactor/InsertManga.kt b/app/src/main/java/yokai/domain/manga/interactor/InsertManga.kt index 255771fdcd..ce8899071d 100644 --- a/app/src/main/java/yokai/domain/manga/interactor/InsertManga.kt +++ b/app/src/main/java/yokai/domain/manga/interactor/InsertManga.kt @@ -1,7 +1,7 @@ package yokai.domain.manga.interactor -import eu.kanade.tachiyomi.data.database.models.Manga import yokai.domain.manga.MangaRepository +import yokai.domain.manga.models.Manga class InsertManga ( private val mangaRepository: MangaRepository, diff --git a/data/src/commonMain/sqldelight/tachiyomi/data/chapters.sq b/data/src/commonMain/sqldelight/tachiyomi/data/chapters.sq index 2b13433fdd..4bc05f854d 100644 --- a/data/src/commonMain/sqldelight/tachiyomi/data/chapters.sq +++ b/data/src/commonMain/sqldelight/tachiyomi/data/chapters.sq @@ -26,6 +26,11 @@ SELECT * FROM chapters WHERE _id = :chapterId; +findByUrl: +SELECT * +FROM chapters +WHERE url = :url; + getChaptersByMangaId: SELECT C.* FROM chapters AS C diff --git a/data/src/commonMain/sqldelight/tachiyomi/data/manga_sync.sq b/data/src/commonMain/sqldelight/tachiyomi/data/manga_sync.sq index 9f4a463a23..e081be2651 100644 --- a/data/src/commonMain/sqldelight/tachiyomi/data/manga_sync.sq +++ b/data/src/commonMain/sqldelight/tachiyomi/data/manga_sync.sq @@ -29,5 +29,12 @@ WHERE manga_id = :mangaId; update: UPDATE manga_sync SET manga_id = coalesce(:mangaId, manga_id), - remote_url = coalesce(:trackingUrl, remote_url) + remote_id = coalesce(:mediaId, remote_id), + library_id = coalesce(:libraryId, library_id), + remote_url = coalesce(:trackingUrl, remote_url), + last_chapter_read = coalesce(:lastChapterRead, last_chapter_read) WHERE _id = :trackId; + +insert: +INSERT INTO manga_sync (manga_id, sync_id, remote_id, library_id, title, last_chapter_read, total_chapters, status, score, remote_url, start_date, finish_date) +VALUES (:mangaId, :syncId, :mediaId, :libraryId, :title, :lastChapterRead, :totalChapters, :status, :score, :trackingUrl, :startDate, :finishDate); diff --git a/domain/src/commonMain/kotlin/yokai/domain/manga/models/Manga.kt b/domain/src/commonMain/kotlin/yokai/domain/manga/models/Manga.kt index ea288e046b..3a2eecff78 100644 --- a/domain/src/commonMain/kotlin/yokai/domain/manga/models/Manga.kt +++ b/domain/src/commonMain/kotlin/yokai/domain/manga/models/Manga.kt @@ -126,6 +126,30 @@ data class Manga( id?.let { vibrantCoverColorMap[it] = value } } + fun toMangaUpdate(): MangaUpdate { + return MangaUpdate( + id = id!!, + source = source, + url = url, + artist = ogArtist, + author = ogAuthor, + description = ogDescription, + genres = ogGenres, + title = ogTitle, + status = ogStatus, + thumbnailUrl = thumbnailUrl, + favorite = favorite, + lastUpdate = lastUpdate, + initialized = initialized, + viewerFlags = viewerFlags, + hideTitle = hideTitle, + chapterFlags = chapterFlags, + dateAdded = dateAdded, + filteredScanlators = filteredScanlators, + updateStrategy = updateStrategy, + ) + } + companion object { // Generic filter that does not filter anything const val SHOW_ALL = 0x00000000 diff --git a/domain/src/commonMain/kotlin/yokai/domain/track/models/TrackUpdate.kt b/domain/src/commonMain/kotlin/yokai/domain/track/models/TrackUpdate.kt index f2c9cd84ed..a231c1abdf 100644 --- a/domain/src/commonMain/kotlin/yokai/domain/track/models/TrackUpdate.kt +++ b/domain/src/commonMain/kotlin/yokai/domain/track/models/TrackUpdate.kt @@ -4,4 +4,7 @@ data class TrackUpdate( val id: Long, val mangaId: Long? = null, val trackingUrl: String? = null, + val lastChapterRead: Float? = null, + val mediaId: Long? = null, + val libraryId: Long? = null, )