Files
mihon-bookoasis/app/src/main/java/mihon/domain/migration/usecases/MigrateMangaUseCase.kt
T
Secozzi 16b5317b90 Fix migration progress not updating and category flag mischeck (#2484)
- Fixed an issue where migration progress wasn't updated after a manual source search
- Fixed incorrect logic where the category migration flag was ignored due to checking the chapter flag instead
2025-09-17 17:12:21 +06:00

146 lines
6.1 KiB
Kotlin

package mihon.domain.migration.usecases
import eu.kanade.domain.chapter.interactor.SyncChaptersWithSource
import eu.kanade.domain.manga.interactor.UpdateManga
import eu.kanade.domain.manga.model.hasCustomCover
import eu.kanade.domain.manga.model.toSManga
import eu.kanade.domain.source.service.SourcePreferences
import eu.kanade.tachiyomi.data.cache.CoverCache
import eu.kanade.tachiyomi.data.download.DownloadManager
import eu.kanade.tachiyomi.data.track.EnhancedTracker
import eu.kanade.tachiyomi.data.track.TrackerManager
import kotlinx.coroutines.CancellationException
import mihon.domain.migration.models.MigrationFlag
import tachiyomi.domain.category.interactor.GetCategories
import tachiyomi.domain.category.interactor.SetMangaCategories
import tachiyomi.domain.chapter.interactor.GetChaptersByMangaId
import tachiyomi.domain.chapter.interactor.UpdateChapter
import tachiyomi.domain.chapter.model.toChapterUpdate
import tachiyomi.domain.manga.model.Manga
import tachiyomi.domain.manga.model.MangaUpdate
import tachiyomi.domain.source.service.SourceManager
import tachiyomi.domain.track.interactor.GetTracks
import tachiyomi.domain.track.interactor.InsertTrack
import java.time.Instant
class MigrateMangaUseCase(
private val sourcePreferences: SourcePreferences,
private val trackerManager: TrackerManager,
private val sourceManager: SourceManager,
private val downloadManager: DownloadManager,
private val updateManga: UpdateManga,
private val getChaptersByMangaId: GetChaptersByMangaId,
private val syncChaptersWithSource: SyncChaptersWithSource,
private val updateChapter: UpdateChapter,
private val getCategories: GetCategories,
private val setMangaCategories: SetMangaCategories,
private val getTracks: GetTracks,
private val insertTrack: InsertTrack,
private val coverCache: CoverCache,
) {
private val enhancedServices by lazy { trackerManager.trackers.filterIsInstance<EnhancedTracker>() }
suspend operator fun invoke(current: Manga, target: Manga, replace: Boolean) {
val targetSource = sourceManager.get(target.source) ?: return
val currentSource = sourceManager.get(current.source)
val flags = sourcePreferences.migrationFlags().get()
try {
val chapters = targetSource.getChapterList(target.toSManga())
try {
syncChaptersWithSource.await(chapters, target, targetSource)
} catch (_: Exception) {
// Worst case, chapters won't be synced
}
// Update chapters read, bookmark and dateFetch
if (MigrationFlag.CHAPTER in flags) {
val prevMangaChapters = getChaptersByMangaId.await(current.id)
val mangaChapters = getChaptersByMangaId.await(target.id)
val maxChapterRead = prevMangaChapters
.filter { it.read }
.maxOfOrNull { it.chapterNumber }
val updatedMangaChapters = mangaChapters.map { mangaChapter ->
var updatedChapter = mangaChapter
if (updatedChapter.isRecognizedNumber) {
val prevChapter = prevMangaChapters
.find { it.isRecognizedNumber && it.chapterNumber == updatedChapter.chapterNumber }
if (prevChapter != null) {
updatedChapter = updatedChapter.copy(
dateFetch = prevChapter.dateFetch,
bookmark = prevChapter.bookmark,
)
}
if (maxChapterRead != null && updatedChapter.chapterNumber <= maxChapterRead) {
updatedChapter = updatedChapter.copy(read = true)
}
}
updatedChapter
}
val chapterUpdates = updatedMangaChapters.map { it.toChapterUpdate() }
updateChapter.awaitAll(chapterUpdates)
}
// Update categories
if (MigrationFlag.CATEGORY in flags) {
val categoryIds = getCategories.await(current.id).map { it.id }
setMangaCategories.await(target.id, categoryIds)
}
// Update track
getTracks.await(current.id).mapNotNull { track ->
val updatedTrack = track.copy(mangaId = target.id)
val service = enhancedServices
.firstOrNull { it.isTrackFrom(updatedTrack, current, currentSource) }
if (service != null) {
service.migrateTrack(updatedTrack, target, targetSource)
} else {
updatedTrack
}
}
.takeIf { it.isNotEmpty() }
?.let { insertTrack.awaitAll(it) }
// Delete downloaded
if (MigrationFlag.REMOVE_DOWNLOAD in flags && currentSource != null) {
downloadManager.deleteManga(current, currentSource)
}
// Update custom cover (recheck if custom cover exists)
if (MigrationFlag.CUSTOM_COVER in flags && current.hasCustomCover()) {
coverCache.setCustomCoverToCache(target, coverCache.getCustomCoverFile(current.id).inputStream())
}
val currentMangaUpdate = MangaUpdate(
id = current.id,
favorite = false,
dateAdded = 0,
)
.takeIf { replace }
val targetMangaUpdate = MangaUpdate(
id = target.id,
favorite = true,
chapterFlags = current.chapterFlags,
viewerFlags = current.viewerFlags,
dateAdded = if (replace) current.dateAdded else Instant.now().toEpochMilli(),
notes = if (MigrationFlag.NOTES in flags) current.notes else null,
)
updateManga.awaitAll(listOfNotNull(currentMangaUpdate, targetMangaUpdate))
} catch (e: Throwable) {
if (e is CancellationException) {
throw e
}
}
}
}