diff --git a/app/src/main/java/eu/kanade/data/manga/MangaRepositoryImpl.kt b/app/src/main/java/eu/kanade/data/manga/MangaRepositoryImpl.kt index addc23864..562584c6e 100644 --- a/app/src/main/java/eu/kanade/data/manga/MangaRepositoryImpl.kt +++ b/app/src/main/java/eu/kanade/data/manga/MangaRepositoryImpl.kt @@ -1,7 +1,10 @@ package eu.kanade.data.manga import eu.kanade.data.DatabaseHandler +import eu.kanade.data.listOfStringsAdapter +import eu.kanade.data.toLong import eu.kanade.domain.manga.model.Manga +import eu.kanade.domain.manga.model.MangaUpdate import eu.kanade.domain.manga.repository.MangaRepository import eu.kanade.tachiyomi.util.system.logcat import kotlinx.coroutines.flow.Flow @@ -11,6 +14,10 @@ class MangaRepositoryImpl( private val handler: DatabaseHandler, ) : MangaRepository { + override suspend fun getMangaById(id: Long): Manga { + return handler.awaitOne { mangasQueries.getMangaById(id, mangaMapper) } + } + override fun getFavoritesBySourceId(sourceId: Long): Flow> { return handler.subscribeToList { mangasQueries.getFavoriteBySourceId(sourceId, mangaMapper) } } @@ -25,11 +32,33 @@ class MangaRepositoryImpl( } } - override suspend fun updateLastUpdate(mangaId: Long, lastUpdate: Long) { - try { - handler.await { mangasQueries.updateLastUpdate(lastUpdate, mangaId) } + override suspend fun update(update: MangaUpdate): Boolean { + return try { + handler.await { + mangasQueries.update( + source = update.source, + url = update.url, + artist = update.artist, + author = update.author, + description = update.description, + genre = update.genre?.let(listOfStringsAdapter::encode), + title = update.title, + status = update.status, + thumbnailUrl = update.thumbnailUrl, + favorite = update.favorite?.toLong(), + lastUpdate = update.lastUpdate, + initialized = update.initialized?.toLong(), + viewer = update.viewerFlags, + chapterFlags = update.chapterFlags, + coverLastModified = update.coverLastModified, + dateAdded = update.dateAdded, + mangaId = update.id, + ) + } + true } catch (e: Exception) { logcat(LogPriority.ERROR, e) + false } } } diff --git a/app/src/main/java/eu/kanade/domain/DomainModule.kt b/app/src/main/java/eu/kanade/domain/DomainModule.kt index c728d9cba..2d7187a73 100644 --- a/app/src/main/java/eu/kanade/domain/DomainModule.kt +++ b/app/src/main/java/eu/kanade/domain/DomainModule.kt @@ -20,8 +20,9 @@ import eu.kanade.domain.history.interactor.RemoveHistoryByMangaId import eu.kanade.domain.history.interactor.UpsertHistory import eu.kanade.domain.history.repository.HistoryRepository import eu.kanade.domain.manga.interactor.GetFavoritesBySourceId +import eu.kanade.domain.manga.interactor.GetMangaById import eu.kanade.domain.manga.interactor.ResetViewerFlags -import eu.kanade.domain.manga.interactor.UpdateMangaLastUpdate +import eu.kanade.domain.manga.interactor.UpdateManga import eu.kanade.domain.manga.repository.MangaRepository import eu.kanade.domain.source.interactor.GetEnabledSources import eu.kanade.domain.source.interactor.GetLanguagesWithSources @@ -48,9 +49,10 @@ class DomainModule : InjektModule { override fun InjektRegistrar.registerInjectables() { addSingletonFactory { MangaRepositoryImpl(get()) } addFactory { GetFavoritesBySourceId(get()) } + addFactory { GetMangaById(get()) } addFactory { GetNextChapter(get()) } addFactory { ResetViewerFlags(get()) } - addFactory { UpdateMangaLastUpdate(get()) } + addFactory { UpdateManga(get()) } addSingletonFactory { ChapterRepositoryImpl(get()) } addFactory { UpdateChapter(get()) } diff --git a/app/src/main/java/eu/kanade/domain/chapter/interactor/SyncChaptersWithSource.kt b/app/src/main/java/eu/kanade/domain/chapter/interactor/SyncChaptersWithSource.kt index 0591b8d10..38aa4b434 100644 --- a/app/src/main/java/eu/kanade/domain/chapter/interactor/SyncChaptersWithSource.kt +++ b/app/src/main/java/eu/kanade/domain/chapter/interactor/SyncChaptersWithSource.kt @@ -5,7 +5,7 @@ import eu.kanade.domain.chapter.model.Chapter import eu.kanade.domain.chapter.model.toChapterUpdate import eu.kanade.domain.chapter.model.toDbChapter import eu.kanade.domain.chapter.repository.ChapterRepository -import eu.kanade.domain.manga.interactor.UpdateMangaLastUpdate +import eu.kanade.domain.manga.interactor.UpdateManga import eu.kanade.domain.manga.model.Manga import eu.kanade.domain.manga.model.toDbManga import eu.kanade.tachiyomi.data.download.DownloadManager @@ -25,7 +25,7 @@ class SyncChaptersWithSource( private val downloadManager: DownloadManager = Injekt.get(), private val chapterRepository: ChapterRepository = Injekt.get(), private val shouldUpdateDbChapter: ShouldUpdateDbChapter = Injekt.get(), - private val updateMangaLastUpdate: UpdateMangaLastUpdate = Injekt.get(), + private val updateManga: UpdateManga = Injekt.get(), ) { suspend fun await( @@ -188,7 +188,7 @@ class SyncChaptersWithSource( // Set this manga as updated since chapters were changed // Note that last_update actually represents last time the chapter list changed at all - updateMangaLastUpdate.await(manga.id, Date().time) + updateManga.awaitUpdateLastUpdate(manga.id) @Suppress("ConvertArgumentToSet") // See tachiyomiorg/tachiyomi#6372. return Pair(updatedToAdd.subtract(reAdded).toList(), toDelete.subtract(reAdded).toList()) diff --git a/app/src/main/java/eu/kanade/domain/manga/interactor/GetMangaById.kt b/app/src/main/java/eu/kanade/domain/manga/interactor/GetMangaById.kt new file mode 100644 index 000000000..9513c0c47 --- /dev/null +++ b/app/src/main/java/eu/kanade/domain/manga/interactor/GetMangaById.kt @@ -0,0 +1,20 @@ +package eu.kanade.domain.manga.interactor + +import eu.kanade.domain.manga.model.Manga +import eu.kanade.domain.manga.repository.MangaRepository +import eu.kanade.tachiyomi.util.system.logcat +import logcat.LogPriority + +class GetMangaById( + private val mangaRepository: MangaRepository, +) { + + suspend fun await(id: Long): Manga? { + return try { + mangaRepository.getMangaById(id) + } catch (e: Exception) { + logcat(LogPriority.ERROR, e) + null + } + } +} diff --git a/app/src/main/java/eu/kanade/domain/manga/interactor/UpdateManga.kt b/app/src/main/java/eu/kanade/domain/manga/interactor/UpdateManga.kt new file mode 100644 index 000000000..babb7ac41 --- /dev/null +++ b/app/src/main/java/eu/kanade/domain/manga/interactor/UpdateManga.kt @@ -0,0 +1,61 @@ +package eu.kanade.domain.manga.interactor + +import eu.kanade.domain.manga.model.Manga +import eu.kanade.domain.manga.model.MangaUpdate +import eu.kanade.domain.manga.model.hasCustomCover +import eu.kanade.domain.manga.model.isLocal +import eu.kanade.domain.manga.model.toDbManga +import eu.kanade.domain.manga.repository.MangaRepository +import eu.kanade.tachiyomi.data.cache.CoverCache +import tachiyomi.source.model.MangaInfo +import java.util.Date + +class UpdateManga( + private val mangaRepository: MangaRepository, +) { + + suspend fun awaitUpdateFromSource( + localManga: Manga, + remoteManga: MangaInfo, + manualFetch: Boolean, + coverCache: CoverCache, + ): Boolean { + // if the manga isn't a favorite, set its title from source and update in db + val title = if (!localManga.favorite) remoteManga.title else null + + // Never refresh covers if the url is empty to avoid "losing" existing covers + val updateCover = remoteManga.cover.isNotEmpty() && (manualFetch || localManga.thumbnailUrl != remoteManga.cover) + val coverLastModified = if (updateCover) { + when { + localManga.isLocal() -> Date().time + localManga.hasCustomCover(coverCache) -> { + coverCache.deleteFromCache(localManga.toDbManga(), false) + null + } + else -> { + coverCache.deleteFromCache(localManga.toDbManga(), false) + Date().time + } + } + } else null + + return mangaRepository.update( + MangaUpdate( + id = localManga.id, + title = title?.takeIf { it.isNotEmpty() }, + coverLastModified = coverLastModified, + author = remoteManga.author, + artist = remoteManga.artist, + description = remoteManga.description, + genre = remoteManga.genres, + thumbnailUrl = remoteManga.cover.takeIf { it.isNotEmpty() }, + status = remoteManga.status.toLong(), + initialized = true, + ), + ) + } + + suspend fun awaitUpdateLastUpdate(mangaId: Long): Boolean { + return mangaRepository.update(MangaUpdate(id = mangaId, lastUpdate = Date().time)) + } +} diff --git a/app/src/main/java/eu/kanade/domain/manga/interactor/UpdateMangaLastUpdate.kt b/app/src/main/java/eu/kanade/domain/manga/interactor/UpdateMangaLastUpdate.kt deleted file mode 100644 index 641192744..000000000 --- a/app/src/main/java/eu/kanade/domain/manga/interactor/UpdateMangaLastUpdate.kt +++ /dev/null @@ -1,12 +0,0 @@ -package eu.kanade.domain.manga.interactor - -import eu.kanade.domain.manga.repository.MangaRepository - -class UpdateMangaLastUpdate( - private val mangaRepository: MangaRepository, -) { - - suspend fun await(mangaId: Long, lastUpdate: Long) { - mangaRepository.updateLastUpdate(mangaId, lastUpdate) - } -} diff --git a/app/src/main/java/eu/kanade/domain/manga/model/Manga.kt b/app/src/main/java/eu/kanade/domain/manga/model/Manga.kt index df5fe85e4..49db1c8de 100644 --- a/app/src/main/java/eu/kanade/domain/manga/model/Manga.kt +++ b/app/src/main/java/eu/kanade/domain/manga/model/Manga.kt @@ -1,7 +1,12 @@ package eu.kanade.domain.manga.model +import eu.kanade.tachiyomi.data.cache.CoverCache import eu.kanade.tachiyomi.data.library.CustomMangaManager +import eu.kanade.tachiyomi.source.LocalSource import eu.kanade.tachiyomi.source.model.SManga +import tachiyomi.source.model.MangaInfo +import uy.kohesive.injekt.Injekt +import uy.kohesive.injekt.api.get import uy.kohesive.injekt.injectLazy import eu.kanade.tachiyomi.data.database.models.Manga as DbManga @@ -88,7 +93,7 @@ data class Manga( } // TODO: Remove when all deps are migrated -fun Manga.toDbManga(): DbManga = DbManga.create(url, title, source).also { +fun Manga.toDbManga(): DbManga = DbManga.create(url, ogTitle, source).also { it.id = id it.favorite = favorite it.last_update = lastUpdate @@ -97,3 +102,22 @@ fun Manga.toDbManga(): DbManga = DbManga.create(url, title, source).also { it.chapter_flags = chapterFlags.toInt() it.cover_last_modified = coverLastModified } + +fun Manga.toMangaInfo(): MangaInfo = MangaInfo( + // SY --> + artist = ogArtist ?: "", + author = ogAuthor ?: "", + cover = thumbnailUrl ?: "", + description = ogDescription ?: "", + genres = ogGenre ?: emptyList(), + key = url, + status = ogStatus.toInt(), + title = ogTitle, + // SY <-- +) + +fun Manga.isLocal(): Boolean = source == LocalSource.ID + +fun Manga.hasCustomCover(coverCache: CoverCache = Injekt.get()): Boolean { + return coverCache.getCustomCoverFile(id).exists() +} diff --git a/app/src/main/java/eu/kanade/domain/manga/model/MangaUpdate.kt b/app/src/main/java/eu/kanade/domain/manga/model/MangaUpdate.kt new file mode 100644 index 000000000..0d18659d4 --- /dev/null +++ b/app/src/main/java/eu/kanade/domain/manga/model/MangaUpdate.kt @@ -0,0 +1,21 @@ +package eu.kanade.domain.manga.model + +data class MangaUpdate( + val id: Long, + val source: Long? = null, + val favorite: Boolean? = null, + val lastUpdate: Long? = null, + val dateAdded: Long? = null, + val viewerFlags: Long? = null, + val chapterFlags: Long? = null, + val coverLastModified: Long? = null, + val url: String? = null, + val title: String? = null, + val artist: String? = null, + val author: String? = null, + val description: String? = null, + val genre: List? = null, + val status: Long? = null, + val thumbnailUrl: String? = null, + val initialized: Boolean? = null, +) diff --git a/app/src/main/java/eu/kanade/domain/manga/repository/MangaRepository.kt b/app/src/main/java/eu/kanade/domain/manga/repository/MangaRepository.kt index 83367d103..875cc9cdc 100644 --- a/app/src/main/java/eu/kanade/domain/manga/repository/MangaRepository.kt +++ b/app/src/main/java/eu/kanade/domain/manga/repository/MangaRepository.kt @@ -1,13 +1,16 @@ package eu.kanade.domain.manga.repository import eu.kanade.domain.manga.model.Manga +import eu.kanade.domain.manga.model.MangaUpdate import kotlinx.coroutines.flow.Flow interface MangaRepository { + suspend fun getMangaById(id: Long): Manga + fun getFavoritesBySourceId(sourceId: Long): Flow> suspend fun resetViewerFlags(): Boolean - suspend fun updateLastUpdate(mangaId: Long, lastUpdate: Long) + suspend fun update(update: MangaUpdate): Boolean } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/models/Manga.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/models/Manga.kt index 2c26755d5..fbb7c46a5 100755 --- a/app/src/main/java/eu/kanade/tachiyomi/data/database/models/Manga.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/database/models/Manga.kt @@ -151,14 +151,18 @@ fun Manga.toDomainManga(): DomainManga? { chapterFlags = chapter_flags.toLong(), coverLastModified = cover_last_modified, url = url, - ogTitle = title, - ogArtist = artist, - ogAuthor = author, - ogDescription = description, - ogGenre = getGenres(), - ogStatus = status.toLong(), + // SY --> + ogTitle = originalTitle, + ogArtist = originalArtist, + ogAuthor = originalAuthor, + ogDescription = originalDescription, + ogGenre = getOriginalGenres(), + ogStatus = originalStatus.toLong(), + // SY <-- thumbnailUrl = thumbnail_url, initialized = initialized, + // SY --> filteredScanlators = MdUtil.getScanlators(filtered_scanlators).toList(), + // SY <-- ) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/queries/MangaQueries.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/queries/MangaQueries.kt index 037be5799..3eb35558e 100755 --- a/app/src/main/java/eu/kanade/tachiyomi/data/database/queries/MangaQueries.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/database/queries/MangaQueries.kt @@ -12,7 +12,6 @@ import eu.kanade.tachiyomi.data.database.resolvers.MangaFavoritePutResolver import eu.kanade.tachiyomi.data.database.resolvers.MangaFilteredScanlatorsPutResolver import eu.kanade.tachiyomi.data.database.resolvers.MangaFlagsPutResolver import eu.kanade.tachiyomi.data.database.resolvers.MangaInfoPutResolver -import eu.kanade.tachiyomi.data.database.resolvers.MangaLastUpdatedPutResolver import eu.kanade.tachiyomi.data.database.resolvers.MangaMigrationPutResolver import eu.kanade.tachiyomi.data.database.resolvers.MangaThumbnailPutResolver import eu.kanade.tachiyomi.data.database.tables.CategoryTable @@ -146,11 +145,6 @@ interface MangaQueries : DbProvider { .withPutResolver(MangaFlagsPutResolver(MangaTable.COL_VIEWER, Manga::viewer_flags)) .prepare() - fun updateLastUpdated(manga: Manga) = db.put() - .`object`(manga) - .withPutResolver(MangaLastUpdatedPutResolver()) - .prepare() - fun updateMangaFavorite(manga: Manga) = db.put() .`object`(manga) .withPutResolver(MangaFavoritePutResolver()) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/MangaLastUpdatedPutResolver.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/MangaLastUpdatedPutResolver.kt deleted file mode 100755 index e2dcb22dc..000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/MangaLastUpdatedPutResolver.kt +++ /dev/null @@ -1,32 +0,0 @@ -package eu.kanade.tachiyomi.data.database.resolvers - -import androidx.core.content.contentValuesOf -import com.pushtorefresh.storio.sqlite.StorIOSQLite -import com.pushtorefresh.storio.sqlite.operations.put.PutResolver -import com.pushtorefresh.storio.sqlite.operations.put.PutResult -import com.pushtorefresh.storio.sqlite.queries.UpdateQuery -import eu.kanade.tachiyomi.data.database.inTransactionReturn -import eu.kanade.tachiyomi.data.database.models.Manga -import eu.kanade.tachiyomi.data.database.tables.MangaTable - -class MangaLastUpdatedPutResolver : PutResolver() { - - override fun performPut(db: StorIOSQLite, manga: Manga) = db.inTransactionReturn { - val updateQuery = mapToUpdateQuery(manga) - val contentValues = mapToContentValues(manga) - - val numberOfRowsUpdated = db.lowLevel().update(updateQuery, contentValues) - PutResult.newUpdateResult(numberOfRowsUpdated, updateQuery.table()) - } - - fun mapToUpdateQuery(manga: Manga) = UpdateQuery.builder() - .table(MangaTable.TABLE) - .where("${MangaTable.COL_ID} = ?") - .whereArgs(manga.id) - .build() - - fun mapToContentValues(manga: Manga) = - contentValuesOf( - MangaTable.COL_LAST_UPDATE to manga.last_update, - ) -} diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateService.kt b/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateService.kt index 5aa800206..086a1d379 100755 --- a/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateService.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateService.kt @@ -7,6 +7,12 @@ import android.os.IBinder import android.os.PowerManager import androidx.core.content.ContextCompat import eu.kanade.data.chapter.NoChaptersException +import eu.kanade.domain.chapter.interactor.SyncChaptersWithSource +import eu.kanade.domain.chapter.model.toDbChapter +import eu.kanade.domain.manga.interactor.GetMangaById +import eu.kanade.domain.manga.interactor.UpdateManga +import eu.kanade.domain.manga.model.toDbManga +import eu.kanade.domain.manga.model.toMangaInfo import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.cache.CoverCache import eu.kanade.tachiyomi.data.database.DatabaseHelper @@ -14,6 +20,7 @@ import eu.kanade.tachiyomi.data.database.models.Category import eu.kanade.tachiyomi.data.database.models.Chapter import eu.kanade.tachiyomi.data.database.models.LibraryManga import eu.kanade.tachiyomi.data.database.models.Manga +import eu.kanade.tachiyomi.data.database.models.toDomainManga import eu.kanade.tachiyomi.data.database.models.toMangaInfo import eu.kanade.tachiyomi.data.download.DownloadManager import eu.kanade.tachiyomi.data.download.DownloadService @@ -30,13 +37,11 @@ import eu.kanade.tachiyomi.data.track.TrackService import eu.kanade.tachiyomi.source.SourceManager import eu.kanade.tachiyomi.source.UnmeteredSource import eu.kanade.tachiyomi.source.model.SManga -import eu.kanade.tachiyomi.source.model.toMangaInfo import eu.kanade.tachiyomi.source.model.toSChapter import eu.kanade.tachiyomi.source.model.toSManga import eu.kanade.tachiyomi.source.online.all.MergedSource import eu.kanade.tachiyomi.ui.library.LibraryGroup import eu.kanade.tachiyomi.ui.manga.track.TrackItem -import eu.kanade.tachiyomi.util.chapter.syncChaptersWithSource import eu.kanade.tachiyomi.util.chapter.syncChaptersWithTrackServiceTwoWay import eu.kanade.tachiyomi.util.lang.withIOContext import eu.kanade.tachiyomi.util.prepUpdateCover @@ -52,7 +57,6 @@ import exh.md.utils.MdUtil import exh.metadata.metadata.base.insertFlatMetadataAsync import exh.source.LIBRARY_UPDATE_EXCLUDED_SOURCES import exh.source.MERGED_SOURCE_ID -import exh.source.getMainSource import exh.source.isMdBasedSource import exh.source.mangaDexSourceIds import exh.util.executeOnIO @@ -70,12 +74,15 @@ import kotlinx.coroutines.supervisorScope import kotlinx.coroutines.sync.Semaphore import kotlinx.coroutines.sync.withPermit import logcat.LogPriority +import tachiyomi.source.model.MangaInfo import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get import java.io.File import java.util.concurrent.CopyOnWriteArrayList import java.util.concurrent.atomic.AtomicBoolean import java.util.concurrent.atomic.AtomicInteger +import eu.kanade.domain.chapter.model.Chapter as DomainChapter +import eu.kanade.domain.manga.model.Manga as DomainManga /** * This class will take care of updating the chapters of the manga from the library. It can be @@ -92,6 +99,9 @@ class LibraryUpdateService( val downloadManager: DownloadManager = Injekt.get(), val trackManager: TrackManager = Injekt.get(), val coverCache: CoverCache = Injekt.get(), + private val getMangaById: GetMangaById = Injekt.get(), + private val updateManga: UpdateManga = Injekt.get(), + private val syncChaptersWithSource: SyncChaptersWithSource = Injekt.get(), ) : Service() { private lateinit var wakeLock: PowerManager.WakeLock @@ -386,7 +396,7 @@ class LibraryUpdateService( } // Don't continue to update if manga not in library - db.getManga(manga.id!!).executeAsBlocking() ?: return@forEach + manga.id?.let { getMangaById.await(it) } ?: return@forEach withUpdateNotification( currentlyUpdatingManga, @@ -406,19 +416,22 @@ class LibraryUpdateService( else -> { // Convert to the manga that contains new chapters - val (newChapters, _) = updateManga(mangaWithNotif, loggedServices) + mangaWithNotif.toDomainManga()?.let { domainManga -> + val (newChapters, _) = updateManga(domainManga, loggedServices) + val newDbChapters = newChapters.map { it.toDbChapter() } - if (newChapters.isNotEmpty()) { - if (mangaWithNotif.shouldDownloadNewChapters(db, preferences)) { - downloadChapters(mangaWithNotif, newChapters) - hasDownloads.set(true) + if (newChapters.isNotEmpty()) { + if (mangaWithNotif.shouldDownloadNewChapters(db, preferences)) { + downloadChapters(mangaWithNotif, newDbChapters) + hasDownloads.set(true) + } + + // Convert to the manga that contains new chapters + newUpdates.add( + mangaWithNotif to newDbChapters.sortedByDescending { ch -> ch.source_order } + .toTypedArray(), + ) } - - // Convert to the manga that contains new chapters - newUpdates.add( - mangaWithNotif to newChapters.sortedByDescending { ch -> ch.source_order } - .toTypedArray(), - ) } } } @@ -494,23 +507,15 @@ class LibraryUpdateService( * @param manga the manga to update. * @return a pair of the inserted and removed chapters. */ - private suspend fun updateManga(manga: Manga, loggedServices: List): Pair, List> { - val source = sourceManager.getOrStub(manga.source).getMainSource() + private suspend fun updateManga(manga: DomainManga, loggedServices: List): Pair, List> { + val source = sourceManager.getOrStub(manga.source) - var updatedManga: SManga = manga + val mangaInfo: MangaInfo = manga.toMangaInfo() - // Update manga details metadata + // Update manga metadata if needed if (preferences.autoUpdateMetadata()) { - val updatedMangaDetails = source.getMangaDetails(manga.toMangaInfo()) - val sManga = updatedMangaDetails.toSManga() - // Avoid "losing" existing cover - if (!sManga.thumbnail_url.isNullOrEmpty()) { - manga.prepUpdateCover(coverCache, sManga, false) - } else { - sManga.thumbnail_url = manga.thumbnail_url - } - - updatedManga = sManga + val updatedMangaInfo = source.getMangaDetails(manga.toMangaInfo()) + updateManga.awaitUpdateFromSource(manga, updatedMangaInfo, manualFetch = false, coverCache) } // SY --> @@ -521,7 +526,7 @@ class LibraryUpdateService( ioScope?.launch(handler) { val tracks = db.getTracks(manga.id).executeAsBlocking() if (tracks.isEmpty() || tracks.none { it.sync_id == TrackManager.MDLIST }) { - val track = trackManager.mdList.createInitialTracker(manga) + val track = trackManager.mdList.createInitialTracker(manga.toDbManga()) db.insertTrack(trackManager.mdList.refresh(track)).executeAsBlocking() } } @@ -532,20 +537,16 @@ class LibraryUpdateService( } // SY <-- - val chapters = source.getChapterList(updatedManga.toMangaInfo()) + val chapters = source.getChapterList(mangaInfo) .map { it.toSChapter() } // Get manga from database to account for if it was removed during the update - val dbManga = db.getManga(manga.id!!).executeAsBlocking() + val dbManga = getMangaById.await(manga.id) ?: return Pair(emptyList(), emptyList()) - // Copy into [dbManga] to retain favourite value - dbManga.copyFrom(updatedManga) - db.insertManga(dbManga).executeAsBlocking() - // [dbmanga] was used so that manga data doesn't get overwritten // in case manga gets new chapter - return syncChaptersWithSource(chapters, dbManga, source) + return syncChaptersWithSource.await(chapters, dbManga, source) } private suspend fun updateCovers() { diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/online/all/MergedSource.kt b/app/src/main/java/eu/kanade/tachiyomi/source/online/all/MergedSource.kt index c326e1e08..bd692d5b5 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/source/online/all/MergedSource.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/source/online/all/MergedSource.kt @@ -1,8 +1,12 @@ package eu.kanade.tachiyomi.source.online.all +import eu.kanade.domain.chapter.interactor.SyncChaptersWithSource +import eu.kanade.domain.chapter.model.toDbChapter +import eu.kanade.domain.manga.model.toDbManga import eu.kanade.tachiyomi.data.database.DatabaseHelper import eu.kanade.tachiyomi.data.database.models.Chapter import eu.kanade.tachiyomi.data.database.models.Manga +import eu.kanade.tachiyomi.data.database.models.toDomainManga import eu.kanade.tachiyomi.data.database.models.toMangaInfo import eu.kanade.tachiyomi.data.download.DownloadManager import eu.kanade.tachiyomi.data.preference.PreferencesHelper @@ -15,7 +19,6 @@ import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.toSChapter import eu.kanade.tachiyomi.source.model.toSManga import eu.kanade.tachiyomi.source.online.HttpSource -import eu.kanade.tachiyomi.util.chapter.syncChaptersWithSource import eu.kanade.tachiyomi.util.lang.withIOContext import eu.kanade.tachiyomi.util.shouldDownloadNewChapters import exh.log.xLogW @@ -31,7 +34,11 @@ import okhttp3.Response import rx.Observable import tachiyomi.source.model.ChapterInfo import tachiyomi.source.model.MangaInfo +import uy.kohesive.injekt.Injekt +import uy.kohesive.injekt.api.get import uy.kohesive.injekt.injectLazy +import eu.kanade.domain.chapter.model.Chapter as DomainChapter +import eu.kanade.domain.manga.model.Manga as DomainManga class MergedSource : HttpSource() { private val db: DatabaseHelper by injectLazy() @@ -92,8 +99,8 @@ class MergedSource : HttpSource() { } // TODO more chapter dedupe - private fun transformMergedChapters(manga: Manga, chapterList: List, editScanlators: Boolean, dedupe: Boolean): List { - val mangaReferences = db.getMergedMangaReferences(manga.id!!).executeAsBlocking() + private fun transformMergedChapters(manga: DomainManga, chapterList: List, editScanlators: Boolean, dedupe: Boolean): List { + val mangaReferences = db.getMergedMangaReferences(manga.id).executeAsBlocking() if (editScanlators) { val sources = mangaReferences.map { sourceManager.getOrStub(it.mangaSourceId) to it.mangaId } chapterList.onEach { chapter -> @@ -107,12 +114,12 @@ class MergedSource : HttpSource() { return if (dedupe) dedupeChapterList(mangaReferences, chapterList) else chapterList } - fun getChaptersAsBlocking(manga: Manga, editScanlators: Boolean = false, dedupe: Boolean = true): List { - return transformMergedChapters(manga, db.getChaptersByMergedMangaId(manga.id!!).executeAsBlocking(), editScanlators, dedupe) + fun getChaptersAsBlocking(manga: DomainManga, editScanlators: Boolean = false, dedupe: Boolean = true): List { + return transformMergedChapters(manga, db.getChaptersByMergedMangaId(manga.id).executeAsBlocking(), editScanlators, dedupe) } - fun getChaptersObservable(manga: Manga, editScanlators: Boolean = false, dedupe: Boolean = true): Observable> { - return db.getChaptersByMergedMangaId(manga.id!!).asRxObservable() + fun getChaptersObservable(manga: DomainManga, editScanlators: Boolean = false, dedupe: Boolean = true): Observable> { + return db.getChaptersByMergedMangaId(manga.id).asRxObservable() .map { chapterList -> transformMergedChapters(manga, chapterList, editScanlators, dedupe) } @@ -144,20 +151,21 @@ class MergedSource : HttpSource() { return chapterList.maxByOrNull { it.chapter_number }?.manga_id } - suspend fun fetchChaptersForMergedManga(manga: Manga, downloadChapters: Boolean = true, editScanlators: Boolean = false, dedupe: Boolean = true): List { + suspend fun fetchChaptersForMergedManga(manga: DomainManga, downloadChapters: Boolean = true, editScanlators: Boolean = false, dedupe: Boolean = true): List { return withIOContext { fetchChaptersAndSync(manga, downloadChapters) getChaptersAsBlocking(manga, editScanlators, dedupe) } } - suspend fun fetchChaptersAndSync(manga: Manga, downloadChapters: Boolean = true): Pair, List> { - val mangaReferences = db.getMergedMangaReferences(manga.id!!).executeAsBlocking() + suspend fun fetchChaptersAndSync(manga: DomainManga, downloadChapters: Boolean = true): Pair, List> { + val syncChaptersWithSource = Injekt.get() + val mangaReferences = db.getMergedMangaReferences(manga.id).executeAsBlocking() if (mangaReferences.isEmpty()) { throw IllegalArgumentException("Manga references are empty, chapters unavailable, merge is likely corrupted") } - val ifDownloadNewChapters = downloadChapters && manga.shouldDownloadNewChapters(db, preferences) + val ifDownloadNewChapters = downloadChapters && manga.toDbManga().shouldDownloadNewChapters(db, preferences) val semaphore = Semaphore(5) var exception: Exception? = null return supervisorScope { @@ -175,11 +183,11 @@ class MergedSource : HttpSource() { val chapterList = source.getChapterList(loadedManga.toMangaInfo()) .map(ChapterInfo::toSChapter) val results = - syncChaptersWithSource(chapterList, loadedManga, source) + syncChaptersWithSource.await(chapterList, loadedManga.toDomainManga()!!, source) if (ifDownloadNewChapters && reference.downloadChapters) { downloadManager.downloadChapters( loadedManga, - results.first, + results.first.map(DomainChapter::toDbChapter), ) } results diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt index 7aea41346..7823e7f05 100755 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt @@ -9,6 +9,7 @@ import eu.kanade.tachiyomi.data.database.models.Category import eu.kanade.tachiyomi.data.database.models.Chapter import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.data.database.models.MangaCategory +import eu.kanade.tachiyomi.data.database.models.toDomainManga import eu.kanade.tachiyomi.data.download.DownloadManager import eu.kanade.tachiyomi.data.library.CustomMangaManager import eu.kanade.tachiyomi.data.preference.PreferencesHelper @@ -641,7 +642,7 @@ class LibraryPresenter( val mergedSource = sourceManager.get(MERGED_SOURCE_ID) as MergedSource val mergedMangas = db.getMergedMangas(manga.id!!).executeAsBlocking() mergedSource - .getChaptersAsBlocking(manga) + .getChaptersAsBlocking(manga.toDomainManga()!!) .filter { !it.read } .groupBy { it.manga_id!! } .forEach ab@{ (mangaId, chapters) -> @@ -710,7 +711,11 @@ class LibraryPresenter( fun markReadStatus(mangas: List, read: Boolean) { mangas.forEach { manga -> launchIO { - val chapters = if (manga.source == MERGED_SOURCE_ID) (sourceManager.get(MERGED_SOURCE_ID) as MergedSource).getChaptersAsBlocking(manga) else db.getChapters(manga).executeAsBlocking() + val chapters = if (manga.source == MERGED_SOURCE_ID) { + (sourceManager.get(MERGED_SOURCE_ID) as MergedSource).getChaptersAsBlocking(manga.toDomainManga()!!) + } else { + db.getChapters(manga).executeAsBlocking() + } chapters.forEach { it.read = read if (!read) { @@ -815,7 +820,7 @@ class LibraryPresenter( /** Returns first unread chapter of a manga */ fun getFirstUnread(manga: Manga): Chapter? { val chapters = if (manga.source == MERGED_SOURCE_ID) { - (sourceManager.get(MERGED_SOURCE_ID) as MergedSource).getChaptersAsBlocking(manga) + (sourceManager.get(MERGED_SOURCE_ID) as MergedSource).getChaptersAsBlocking(manga.toDomainManga()!!) } else db.getChapters(manga).executeAsBlocking() return if (manga.isEhBasedManga()) { val chapter = chapters.sortedBy { it.source_order }.getOrNull(0) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaPresenter.kt index 5106b9bd9..6fc9e78db 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaPresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaPresenter.kt @@ -12,6 +12,7 @@ import eu.kanade.tachiyomi.data.database.models.Chapter import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.data.database.models.MangaCategory import eu.kanade.tachiyomi.data.database.models.Track +import eu.kanade.tachiyomi.data.database.models.toDomainManga import eu.kanade.tachiyomi.data.database.models.toMangaInfo import eu.kanade.tachiyomi.data.download.DownloadManager import eu.kanade.tachiyomi.data.download.model.Download @@ -222,7 +223,7 @@ class MangaPresenter( // Add the subscription that retrieves the chapters from the database, keeps subscribed to // changes, and sends the list of chapters to the relay. add( - (/* SY --> */if (source is MergedSource) source.getChaptersObservable(manga, true, dedupe) else /* SY <-- */ db.getChapters(manga).asRxObservable()) + (/* SY --> */if (source is MergedSource) source.getChaptersObservable(manga.toDomainManga()!!, true, dedupe) else /* SY <-- */ db.getChapters(manga).asRxObservable()) .map { chapters -> // Convert every chapter to a model. chapters.map { it.toModel() } @@ -761,7 +762,7 @@ class MangaPresenter( downloadNewChapters(newChapters) } } else { - source.fetchChaptersForMergedManga(manga, manualFetch, true, dedupe) + source.fetchChaptersForMergedManga(manga.toDomainManga()!!, manualFetch, true, dedupe) } withUIContext { view?.onFetchChaptersDone() } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderPresenter.kt index 9abc0b659..3bcca1e54 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderPresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderPresenter.kt @@ -15,6 +15,7 @@ import eu.kanade.tachiyomi.data.cache.CoverCache import eu.kanade.tachiyomi.data.database.DatabaseHelper import eu.kanade.tachiyomi.data.database.models.Chapter import eu.kanade.tachiyomi.data.database.models.Manga +import eu.kanade.tachiyomi.data.database.models.toDomainManga import eu.kanade.tachiyomi.data.download.DownloadManager import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.data.saver.Image @@ -47,7 +48,6 @@ import eu.kanade.tachiyomi.util.lang.takeBytes import eu.kanade.tachiyomi.util.storage.DiskUtil import eu.kanade.tachiyomi.util.storage.cacheImageDir import eu.kanade.tachiyomi.util.system.ImageUtil -import eu.kanade.tachiyomi.util.system.isLTR import eu.kanade.tachiyomi.util.system.isOnline import eu.kanade.tachiyomi.util.system.logcat import eu.kanade.tachiyomi.util.updateCoverLastModified @@ -146,7 +146,7 @@ class ReaderPresenter( // SY <-- val dbChapters = /* SY --> */ if (manga.source == MERGED_SOURCE_ID) { (sourceManager.get(MERGED_SOURCE_ID) as MergedSource) - .getChaptersAsBlocking(manga) + .getChaptersAsBlocking(manga.toDomainManga()!!) } else /* SY <-- */ db.getChapters(manga).executeAsBlocking() val selectedChapter = dbChapters.find { it.id == chapterId } diff --git a/app/src/main/sqldelight/data/mangas.sq b/app/src/main/sqldelight/data/mangas.sq index 1afd1c6c3..b677fc76d 100644 --- a/app/src/main/sqldelight/data/mangas.sq +++ b/app/src/main/sqldelight/data/mangas.sq @@ -69,7 +69,22 @@ WHERE favorite = 0 AND source IN :sourceIdsAND AND _id NOT IN ( SELECT manga_id FROM chapters WHERE read = 1 OR last_page_read != 0 ); -updateLastUpdate: -UPDATE mangas -SET last_update = :lastUpdate +update: +UPDATE mangas SET + source = coalesce(:source, source), + url = coalesce(:url, url), + artist = coalesce(:artist, artist), + author = coalesce(:author, author), + description = coalesce(:description, description), + genre = coalesce(:genre, genre), + title = coalesce(:title, title), + status = coalesce(:status, status), + thumbnail_url = coalesce(:thumbnailUrl, thumbnail_url), + favorite = coalesce(:favorite, favorite), + last_update = coalesce(:lastUpdate, last_update), + initialized = coalesce(:initialized, initialized), + viewer = coalesce(:viewer, viewer), + chapter_flags = coalesce(:chapterFlags, chapter_flags), + cover_last_modified = coalesce(:coverLastModified, cover_last_modified), + date_added = coalesce(:dateAdded, date_added) WHERE _id = :mangaId;