mirror of
https://github.com/null2264/yokai.git
synced 2025-06-21 02:34:39 +00:00
refactor(ChapterSourceSync): Simplify code and insert new chapters in
bulk
This commit is contained in:
parent
365875590f
commit
ea04968581
5 changed files with 60 additions and 59 deletions
|
@ -90,4 +90,8 @@ interface Chapter : SChapter, Serializable {
|
|||
source_order = other.source_order
|
||||
copyFrom(other as SChapter)
|
||||
}
|
||||
|
||||
fun copy() = ChapterImpl().apply {
|
||||
copyFrom(this@Chapter)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -117,53 +117,58 @@ suspend fun syncChaptersWithSource(
|
|||
// Return if there's nothing to add, delete or change, avoid unnecessary db transactions.
|
||||
if (toAdd.isEmpty() && toDelete.isEmpty() && toChange.isEmpty()) {
|
||||
val newestDate = dbChapters.maxOfOrNull { it.date_upload } ?: 0L
|
||||
if (newestDate != 0L && newestDate != manga.last_update) {
|
||||
if (newestDate != 0L && newestDate > manga.last_update) {
|
||||
manga.last_update = newestDate
|
||||
val update = MangaUpdate(manga.id!!, lastUpdate = manga.last_update)
|
||||
val update = MangaUpdate(manga.id!!, lastUpdate = newestDate)
|
||||
updateManga.await(update)
|
||||
}
|
||||
return Pair(emptyList(), emptyList())
|
||||
}
|
||||
|
||||
val readded = mutableListOf<Chapter>()
|
||||
val reAdded = mutableListOf<Chapter>()
|
||||
|
||||
val deletedChapterNumbers = TreeSet<Float>()
|
||||
val deletedReadChapterNumbers = TreeSet<Float>()
|
||||
if (toDelete.isNotEmpty()) {
|
||||
for (c in toDelete) {
|
||||
if (c.read) {
|
||||
deletedReadChapterNumbers.add(c.chapter_number)
|
||||
}
|
||||
deletedChapterNumbers.add(c.chapter_number)
|
||||
}
|
||||
deleteChapter.awaitAll(toDelete)
|
||||
val deletedBookmarkedChapterNumbers = TreeSet<Float>()
|
||||
toDelete.forEach {
|
||||
if (it.read) deletedReadChapterNumbers.add(it.chapter_number)
|
||||
if (it.bookmark) deletedBookmarkedChapterNumbers.add(it.chapter_number)
|
||||
deletedChapterNumbers.add(it.chapter_number)
|
||||
}
|
||||
|
||||
if (toAdd.isNotEmpty()) {
|
||||
// Set the date fetch for new items in reverse order to allow another sorting method.
|
||||
// Sources MUST return the chapters from most to less recent, which is common.
|
||||
var now = Date().time
|
||||
val now = Date().time
|
||||
|
||||
for (i in toAdd.indices.reversed()) {
|
||||
val chapter = toAdd[i]
|
||||
chapter.date_fetch = now++
|
||||
if (chapter.isRecognizedNumber && chapter.chapter_number in deletedChapterNumbers) {
|
||||
// Try to mark already read chapters as read when the source deletes them
|
||||
if (chapter.chapter_number in deletedReadChapterNumbers) {
|
||||
chapter.read = true
|
||||
}
|
||||
// Try to to use the fetch date it originally had to not pollute 'Updates' tab
|
||||
toDelete.filter { it.chapter_number == chapter.chapter_number }
|
||||
.minByOrNull { it.date_fetch }?.let {
|
||||
chapter.date_fetch = it.date_fetch
|
||||
}
|
||||
// Date fetch is set in such a way that the upper ones will have bigger value than the lower ones
|
||||
// Sources MUST return the chapters from most to less recent, which is common.
|
||||
var itemCount = toAdd.size
|
||||
var updatedToAdd = toAdd.map { toAddItem ->
|
||||
val chapter: Chapter = toAddItem.copy()
|
||||
|
||||
readded.add(chapter)
|
||||
chapter.date_fetch = now + itemCount--
|
||||
|
||||
if (!chapter.isRecognizedNumber || chapter.chapter_number !in deletedChapterNumbers) return@map chapter
|
||||
|
||||
chapter.read = chapter.chapter_number in deletedReadChapterNumbers
|
||||
chapter.bookmark = chapter.chapter_number in deletedBookmarkedChapterNumbers
|
||||
|
||||
// Try to use the fetch date it originally had to not pollute 'Updates' tab
|
||||
toDelete.filter { it.chapter_number == chapter.chapter_number }
|
||||
.minByOrNull { it.date_fetch }?.let {
|
||||
chapter.date_fetch = it.date_fetch
|
||||
}
|
||||
}
|
||||
toAdd.forEach { chapter ->
|
||||
chapter.id = insertChapter.await(chapter)
|
||||
}
|
||||
|
||||
reAdded.add(chapter)
|
||||
|
||||
chapter
|
||||
}
|
||||
|
||||
if (toDelete.isNotEmpty()) {
|
||||
val idsToDelete = toDelete.mapNotNull { it.id }
|
||||
deleteChapter.awaitAllById(idsToDelete)
|
||||
}
|
||||
|
||||
if (updatedToAdd.isNotEmpty()) {
|
||||
updatedToAdd = insertChapter.awaitBulk(toAdd)
|
||||
}
|
||||
|
||||
if (toChange.isNotEmpty()) {
|
||||
|
@ -182,24 +187,15 @@ suspend fun syncChaptersWithSource(
|
|||
}
|
||||
}
|
||||
|
||||
var mangaUpdate: MangaUpdate? = null
|
||||
// Set this manga as updated since chapters were changed
|
||||
val newestChapterDate = getChapter.awaitAll(manga, false)
|
||||
.maxOfOrNull { it.date_upload } ?: 0L
|
||||
if (newestChapterDate == 0L) {
|
||||
if (toAdd.isNotEmpty()) {
|
||||
manga.last_update = Date().time
|
||||
mangaUpdate = MangaUpdate(manga.id!!, lastUpdate = manga.last_update)
|
||||
}
|
||||
} else {
|
||||
manga.last_update = newestChapterDate
|
||||
mangaUpdate = MangaUpdate(manga.id!!, lastUpdate = manga.last_update)
|
||||
}
|
||||
mangaUpdate?.let { updateManga.await(it) }
|
||||
// Note that last_update actually represents last time the chapter list changed at all
|
||||
// Those changes already checked beforehand, so we can proceed to updating the manga
|
||||
manga.last_update = Date().time
|
||||
updateManga.await(MangaUpdate(manga.id!!, lastUpdate = manga.last_update))
|
||||
|
||||
val reAddedSet = readded.toSet()
|
||||
val reAddedSet = reAdded.toSet()
|
||||
return Pair(
|
||||
toAdd.subtract(reAddedSet).toList().filterChaptersByScanlators(manga),
|
||||
updatedToAdd.subtract(reAddedSet).toList().filterChaptersByScanlators(manga),
|
||||
toDelete - reAddedSet,
|
||||
)
|
||||
}
|
||||
|
|
|
@ -54,27 +54,26 @@ class ChapterRepositoryImpl(private val handler: DatabaseHandler) : ChapterRepos
|
|||
|
||||
override suspend fun delete(chapter: Chapter) =
|
||||
try {
|
||||
partialDelete(chapter)
|
||||
partialDelete(chapter.id!!)
|
||||
true
|
||||
} catch (e: Exception) {
|
||||
Logger.e(e) { "Failed to delete chapter with id '${chapter.id}'" }
|
||||
false
|
||||
}
|
||||
|
||||
override suspend fun deleteAll(chapters: List<Chapter>) =
|
||||
override suspend fun deleteAllById(chapters: List<Long>) =
|
||||
try {
|
||||
partialDelete(*chapters.toTypedArray())
|
||||
partialDelete(*chapters.toLongArray())
|
||||
true
|
||||
} catch (e: Exception) {
|
||||
Logger.e(e) { "Failed to bulk delete chapters" }
|
||||
false
|
||||
}
|
||||
|
||||
private suspend fun partialDelete(vararg chapters: Chapter) {
|
||||
private suspend fun partialDelete(vararg chapterIds: Long) {
|
||||
handler.await(inTransaction = true) {
|
||||
chapters.forEach { chapter ->
|
||||
if (chapter.id == null) return@forEach
|
||||
chaptersQueries.delete(chapter.id!!)
|
||||
chapterIds.forEach { chapterId ->
|
||||
chaptersQueries.delete(chapterId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -143,7 +142,7 @@ class ChapterRepositoryImpl(private val handler: DatabaseHandler) : ChapterRepos
|
|||
|
||||
override suspend fun insertBulk(chapters: List<Chapter>) =
|
||||
handler.await(true) {
|
||||
chapters.forEach { chapter ->
|
||||
chapters.map { chapter ->
|
||||
chaptersQueries.insert(
|
||||
mangaId = chapter.manga_id!!,
|
||||
url = chapter.url,
|
||||
|
@ -158,6 +157,8 @@ class ChapterRepositoryImpl(private val handler: DatabaseHandler) : ChapterRepos
|
|||
dateFetch = chapter.date_fetch,
|
||||
dateUpload = chapter.date_upload,
|
||||
)
|
||||
val lastInsertId = chaptersQueries.selectLastInsertedRowId().executeAsOne()
|
||||
chapter.copy().apply { id = lastInsertId }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,11 +23,11 @@ interface ChapterRepository {
|
|||
fun getScanlatorsByChapterAsFlow(mangaId: Long): Flow<List<String>>
|
||||
|
||||
suspend fun delete(chapter: Chapter): Boolean
|
||||
suspend fun deleteAll(chapters: List<Chapter>): Boolean
|
||||
suspend fun deleteAllById(chapters: List<Long>): Boolean
|
||||
|
||||
suspend fun update(update: ChapterUpdate): Boolean
|
||||
suspend fun updateAll(updates: List<ChapterUpdate>): Boolean
|
||||
|
||||
suspend fun insert(chapter: Chapter): Long?
|
||||
suspend fun insertBulk(chapters: List<Chapter>)
|
||||
suspend fun insertBulk(chapters: List<Chapter>): List<Chapter>
|
||||
}
|
||||
|
|
|
@ -7,5 +7,5 @@ class DeleteChapter(
|
|||
private val chapterRepository: ChapterRepository,
|
||||
) {
|
||||
suspend fun await(chapter: Chapter) = chapterRepository.delete(chapter)
|
||||
suspend fun awaitAll(chapters: List<Chapter>) = chapterRepository.deleteAll(chapters)
|
||||
suspend fun awaitAllById(chapterIds: List<Long>) = chapterRepository.deleteAllById(chapterIds)
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue