|
|
|
@ -12,25 +12,34 @@ import org.koitharu.kotatsu.history.data.toMangaHistory
|
|
|
|
import org.koitharu.kotatsu.parsers.model.Manga
|
|
|
|
import org.koitharu.kotatsu.parsers.model.Manga
|
|
|
|
import org.koitharu.kotatsu.parsers.model.MangaChapter
|
|
|
|
import org.koitharu.kotatsu.parsers.model.MangaChapter
|
|
|
|
import org.koitharu.kotatsu.parsers.util.runCatchingCancellable
|
|
|
|
import org.koitharu.kotatsu.parsers.util.runCatchingCancellable
|
|
|
|
|
|
|
|
import org.koitharu.kotatsu.scrobbling.common.domain.Scrobbler
|
|
|
|
|
|
|
|
import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblingStatus
|
|
|
|
import org.koitharu.kotatsu.tracker.data.TrackEntity
|
|
|
|
import org.koitharu.kotatsu.tracker.data.TrackEntity
|
|
|
|
import javax.inject.Inject
|
|
|
|
import javax.inject.Inject
|
|
|
|
|
|
|
|
|
|
|
|
class MigrateUseCase @Inject constructor(
|
|
|
|
class MigrateUseCase
|
|
|
|
|
|
|
|
@Inject
|
|
|
|
|
|
|
|
constructor(
|
|
|
|
private val mangaRepositoryFactory: MangaRepository.Factory,
|
|
|
|
private val mangaRepositoryFactory: MangaRepository.Factory,
|
|
|
|
private val mangaDataRepository: MangaDataRepository,
|
|
|
|
private val mangaDataRepository: MangaDataRepository,
|
|
|
|
private val database: MangaDatabase,
|
|
|
|
private val database: MangaDatabase,
|
|
|
|
private val progressUpdateUseCase: ProgressUpdateUseCase,
|
|
|
|
private val progressUpdateUseCase: ProgressUpdateUseCase,
|
|
|
|
) {
|
|
|
|
private val scrobblers: Set<@JvmSuppressWildcards Scrobbler>,
|
|
|
|
|
|
|
|
) {
|
|
|
|
suspend operator fun invoke(oldManga: Manga, newManga: Manga) {
|
|
|
|
suspend operator fun invoke(
|
|
|
|
val oldDetails = if (oldManga.chapters.isNullOrEmpty()) {
|
|
|
|
oldManga: Manga,
|
|
|
|
|
|
|
|
newManga: Manga,
|
|
|
|
|
|
|
|
) {
|
|
|
|
|
|
|
|
val oldDetails =
|
|
|
|
|
|
|
|
if (oldManga.chapters.isNullOrEmpty()) {
|
|
|
|
runCatchingCancellable {
|
|
|
|
runCatchingCancellable {
|
|
|
|
mangaRepositoryFactory.create(oldManga.source).getDetails(oldManga)
|
|
|
|
mangaRepositoryFactory.create(oldManga.source).getDetails(oldManga)
|
|
|
|
}.getOrDefault(oldManga)
|
|
|
|
}.getOrDefault(oldManga)
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
oldManga
|
|
|
|
oldManga
|
|
|
|
}
|
|
|
|
}
|
|
|
|
val newDetails = if (newManga.chapters.isNullOrEmpty()) {
|
|
|
|
val newDetails =
|
|
|
|
|
|
|
|
if (newManga.chapters.isNullOrEmpty()) {
|
|
|
|
mangaRepositoryFactory.create(newManga.source).getDetails(newManga)
|
|
|
|
mangaRepositoryFactory.create(newManga.source).getDetails(newManga)
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
newManga
|
|
|
|
newManga
|
|
|
|
@ -43,7 +52,8 @@ class MigrateUseCase @Inject constructor(
|
|
|
|
if (oldFavourites.isNotEmpty()) {
|
|
|
|
if (oldFavourites.isNotEmpty()) {
|
|
|
|
favoritesDao.delete(oldManga.id)
|
|
|
|
favoritesDao.delete(oldManga.id)
|
|
|
|
for (f in oldFavourites) {
|
|
|
|
for (f in oldFavourites) {
|
|
|
|
val e = f.copy(
|
|
|
|
val e =
|
|
|
|
|
|
|
|
f.copy(
|
|
|
|
mangaId = newManga.id,
|
|
|
|
mangaId = newManga.id,
|
|
|
|
)
|
|
|
|
)
|
|
|
|
favoritesDao.upsert(e)
|
|
|
|
favoritesDao.upsert(e)
|
|
|
|
@ -52,17 +62,22 @@ class MigrateUseCase @Inject constructor(
|
|
|
|
// replace history
|
|
|
|
// replace history
|
|
|
|
val historyDao = database.getHistoryDao()
|
|
|
|
val historyDao = database.getHistoryDao()
|
|
|
|
val oldHistory = historyDao.find(oldDetails.id)
|
|
|
|
val oldHistory = historyDao.find(oldDetails.id)
|
|
|
|
|
|
|
|
val newHistory =
|
|
|
|
if (oldHistory != null) {
|
|
|
|
if (oldHistory != null) {
|
|
|
|
val newHistory = makeNewHistory(oldDetails, newDetails, oldHistory)
|
|
|
|
val newHistory = makeNewHistory(oldDetails, newDetails, oldHistory)
|
|
|
|
historyDao.delete(oldDetails.id)
|
|
|
|
historyDao.delete(oldDetails.id)
|
|
|
|
historyDao.upsert(newHistory)
|
|
|
|
historyDao.upsert(newHistory)
|
|
|
|
|
|
|
|
newHistory
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
null
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// track
|
|
|
|
// track
|
|
|
|
val tracksDao = database.getTracksDao()
|
|
|
|
val tracksDao = database.getTracksDao()
|
|
|
|
val oldTrack = tracksDao.find(oldDetails.id)
|
|
|
|
val oldTrack = tracksDao.find(oldDetails.id)
|
|
|
|
if (oldTrack != null) {
|
|
|
|
if (oldTrack != null) {
|
|
|
|
val lastChapter = newDetails.chapters?.lastOrNull()
|
|
|
|
val lastChapter = newDetails.chapters?.lastOrNull()
|
|
|
|
val newTrack = TrackEntity(
|
|
|
|
val newTrack =
|
|
|
|
|
|
|
|
TrackEntity(
|
|
|
|
mangaId = newDetails.id,
|
|
|
|
mangaId = newDetails.id,
|
|
|
|
lastChapterId = lastChapter?.id ?: 0L,
|
|
|
|
lastChapterId = lastChapter?.id ?: 0L,
|
|
|
|
newChapters = 0,
|
|
|
|
newChapters = 0,
|
|
|
|
@ -74,6 +89,32 @@ class MigrateUseCase @Inject constructor(
|
|
|
|
tracksDao.delete(oldDetails.id)
|
|
|
|
tracksDao.delete(oldDetails.id)
|
|
|
|
tracksDao.upsert(newTrack)
|
|
|
|
tracksDao.upsert(newTrack)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// scrobbling
|
|
|
|
|
|
|
|
for (scrobbler in scrobblers) {
|
|
|
|
|
|
|
|
if (!scrobbler.isEnabled) {
|
|
|
|
|
|
|
|
continue
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
val prevInfo = scrobbler.getScrobblingInfoOrNull(oldDetails.id) ?: continue
|
|
|
|
|
|
|
|
scrobbler.unregisterScrobbling(oldDetails.id)
|
|
|
|
|
|
|
|
scrobbler.linkManga(newDetails.id, prevInfo.targetId)
|
|
|
|
|
|
|
|
scrobbler.updateScrobblingInfo(
|
|
|
|
|
|
|
|
mangaId = newDetails.id,
|
|
|
|
|
|
|
|
rating = prevInfo.rating,
|
|
|
|
|
|
|
|
status =
|
|
|
|
|
|
|
|
prevInfo.status ?: when {
|
|
|
|
|
|
|
|
newHistory == null -> ScrobblingStatus.PLANNED
|
|
|
|
|
|
|
|
newHistory.percent == 1f -> ScrobblingStatus.COMPLETED
|
|
|
|
|
|
|
|
else -> ScrobblingStatus.READING
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
comment = prevInfo.comment,
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
if (newHistory != null) {
|
|
|
|
|
|
|
|
scrobbler.scrobble(
|
|
|
|
|
|
|
|
manga = newDetails,
|
|
|
|
|
|
|
|
chapterId = newHistory.chapterId,
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
progressUpdateUseCase(newManga)
|
|
|
|
progressUpdateUseCase(newManga)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@ -86,7 +127,8 @@ class MigrateUseCase @Inject constructor(
|
|
|
|
if (oldManga.chapters.isNullOrEmpty()) { // probably broken manga/source
|
|
|
|
if (oldManga.chapters.isNullOrEmpty()) { // probably broken manga/source
|
|
|
|
val branch = newManga.getPreferredBranch(null)
|
|
|
|
val branch = newManga.getPreferredBranch(null)
|
|
|
|
val chapters = checkNotNull(newManga.getChapters(branch))
|
|
|
|
val chapters = checkNotNull(newManga.getChapters(branch))
|
|
|
|
val currentChapter = if (history.percent in 0f..1f) {
|
|
|
|
val currentChapter =
|
|
|
|
|
|
|
|
if (history.percent in 0f..1f) {
|
|
|
|
chapters[(chapters.lastIndex * history.percent).toInt()]
|
|
|
|
chapters[(chapters.lastIndex * history.percent).toInt()]
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
chapters.first()
|
|
|
|
chapters.first()
|
|
|
|
@ -107,19 +149,23 @@ class MigrateUseCase @Inject constructor(
|
|
|
|
val oldChapters = checkNotNull(oldManga.getChapters(branch))
|
|
|
|
val oldChapters = checkNotNull(oldManga.getChapters(branch))
|
|
|
|
var index = oldChapters.indexOfFirst { it.id == history.chapterId }
|
|
|
|
var index = oldChapters.indexOfFirst { it.id == history.chapterId }
|
|
|
|
if (index < 0) {
|
|
|
|
if (index < 0) {
|
|
|
|
index = if (history.percent in 0f..1f) {
|
|
|
|
index =
|
|
|
|
|
|
|
|
if (history.percent in 0f..1f) {
|
|
|
|
(oldChapters.lastIndex * history.percent).toInt()
|
|
|
|
(oldChapters.lastIndex * history.percent).toInt()
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
0
|
|
|
|
0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
val newChapters = checkNotNull(newManga.chapters).groupBy { it.branch }
|
|
|
|
val newChapters = checkNotNull(newManga.chapters).groupBy { it.branch }
|
|
|
|
val newBranch = if (newChapters.containsKey(branch)) {
|
|
|
|
val newBranch =
|
|
|
|
|
|
|
|
if (newChapters.containsKey(branch)) {
|
|
|
|
branch
|
|
|
|
branch
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
newManga.getPreferredBranch(null)
|
|
|
|
newManga.getPreferredBranch(null)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
val newChapterId = checkNotNull(newChapters[newBranch]).let {
|
|
|
|
val newChapterId =
|
|
|
|
|
|
|
|
checkNotNull(newChapters[newBranch])
|
|
|
|
|
|
|
|
.let {
|
|
|
|
val oldChapter = oldChapters[index]
|
|
|
|
val oldChapter = oldChapters[index]
|
|
|
|
it.findByNumber(oldChapter.volume, oldChapter.number) ?: it.getOrNull(index) ?: it.last()
|
|
|
|
it.findByNumber(oldChapter.volume, oldChapter.number) ?: it.getOrNull(index) ?: it.last()
|
|
|
|
}.id
|
|
|
|
}.id
|
|
|
|
@ -137,11 +183,13 @@ class MigrateUseCase @Inject constructor(
|
|
|
|
)
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private fun List<MangaChapter>.findByNumber(volume: Int, number: Float): MangaChapter? {
|
|
|
|
private fun List<MangaChapter>.findByNumber(
|
|
|
|
return if (number <= 0f) {
|
|
|
|
volume: Int,
|
|
|
|
|
|
|
|
number: Float,
|
|
|
|
|
|
|
|
): MangaChapter? =
|
|
|
|
|
|
|
|
if (number <= 0f) {
|
|
|
|
null
|
|
|
|
null
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
firstOrNull { it.volume == volume && it.number == number }
|
|
|
|
firstOrNull { it.volume == volume && it.number == number }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|