mirror of
https://github.com/null2264/yokai.git
synced 2025-06-21 10:44:42 +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
|
source_order = other.source_order
|
||||||
copyFrom(other as SChapter)
|
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.
|
// Return if there's nothing to add, delete or change, avoid unnecessary db transactions.
|
||||||
if (toAdd.isEmpty() && toDelete.isEmpty() && toChange.isEmpty()) {
|
if (toAdd.isEmpty() && toDelete.isEmpty() && toChange.isEmpty()) {
|
||||||
val newestDate = dbChapters.maxOfOrNull { it.date_upload } ?: 0L
|
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
|
manga.last_update = newestDate
|
||||||
val update = MangaUpdate(manga.id!!, lastUpdate = manga.last_update)
|
val update = MangaUpdate(manga.id!!, lastUpdate = newestDate)
|
||||||
updateManga.await(update)
|
updateManga.await(update)
|
||||||
}
|
}
|
||||||
return Pair(emptyList(), emptyList())
|
return Pair(emptyList(), emptyList())
|
||||||
}
|
}
|
||||||
|
|
||||||
val readded = mutableListOf<Chapter>()
|
val reAdded = mutableListOf<Chapter>()
|
||||||
|
|
||||||
val deletedChapterNumbers = TreeSet<Float>()
|
val deletedChapterNumbers = TreeSet<Float>()
|
||||||
val deletedReadChapterNumbers = TreeSet<Float>()
|
val deletedReadChapterNumbers = TreeSet<Float>()
|
||||||
if (toDelete.isNotEmpty()) {
|
val deletedBookmarkedChapterNumbers = TreeSet<Float>()
|
||||||
for (c in toDelete) {
|
toDelete.forEach {
|
||||||
if (c.read) {
|
if (it.read) deletedReadChapterNumbers.add(it.chapter_number)
|
||||||
deletedReadChapterNumbers.add(c.chapter_number)
|
if (it.bookmark) deletedBookmarkedChapterNumbers.add(it.chapter_number)
|
||||||
}
|
deletedChapterNumbers.add(it.chapter_number)
|
||||||
deletedChapterNumbers.add(c.chapter_number)
|
|
||||||
}
|
|
||||||
deleteChapter.awaitAll(toDelete)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (toAdd.isNotEmpty()) {
|
val now = Date().time
|
||||||
// Set the date fetch for new items in reverse order to allow another sorting method.
|
|
||||||
|
// 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.
|
// Sources MUST return the chapters from most to less recent, which is common.
|
||||||
var now = Date().time
|
var itemCount = toAdd.size
|
||||||
|
var updatedToAdd = toAdd.map { toAddItem ->
|
||||||
|
val chapter: Chapter = toAddItem.copy()
|
||||||
|
|
||||||
for (i in toAdd.indices.reversed()) {
|
chapter.date_fetch = now + itemCount--
|
||||||
val chapter = toAdd[i]
|
|
||||||
chapter.date_fetch = now++
|
if (!chapter.isRecognizedNumber || chapter.chapter_number !in deletedChapterNumbers) return@map chapter
|
||||||
if (chapter.isRecognizedNumber && chapter.chapter_number in deletedChapterNumbers) {
|
|
||||||
// Try to mark already read chapters as read when the source deletes them
|
chapter.read = chapter.chapter_number in deletedReadChapterNumbers
|
||||||
if (chapter.chapter_number in deletedReadChapterNumbers) {
|
chapter.bookmark = chapter.chapter_number in deletedBookmarkedChapterNumbers
|
||||||
chapter.read = true
|
|
||||||
}
|
// Try to use the fetch date it originally had to not pollute 'Updates' tab
|
||||||
// Try to to use the fetch date it originally had to not pollute 'Updates' tab
|
|
||||||
toDelete.filter { it.chapter_number == chapter.chapter_number }
|
toDelete.filter { it.chapter_number == chapter.chapter_number }
|
||||||
.minByOrNull { it.date_fetch }?.let {
|
.minByOrNull { it.date_fetch }?.let {
|
||||||
chapter.date_fetch = it.date_fetch
|
chapter.date_fetch = it.date_fetch
|
||||||
}
|
}
|
||||||
|
|
||||||
readded.add(chapter)
|
reAdded.add(chapter)
|
||||||
|
|
||||||
|
chapter
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (toDelete.isNotEmpty()) {
|
||||||
|
val idsToDelete = toDelete.mapNotNull { it.id }
|
||||||
|
deleteChapter.awaitAllById(idsToDelete)
|
||||||
}
|
}
|
||||||
toAdd.forEach { chapter ->
|
|
||||||
chapter.id = insertChapter.await(chapter)
|
if (updatedToAdd.isNotEmpty()) {
|
||||||
}
|
updatedToAdd = insertChapter.awaitBulk(toAdd)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (toChange.isNotEmpty()) {
|
if (toChange.isNotEmpty()) {
|
||||||
|
@ -182,24 +187,15 @@ suspend fun syncChaptersWithSource(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var mangaUpdate: MangaUpdate? = null
|
|
||||||
// Set this manga as updated since chapters were changed
|
// Set this manga as updated since chapters were changed
|
||||||
val newestChapterDate = getChapter.awaitAll(manga, false)
|
// Note that last_update actually represents last time the chapter list changed at all
|
||||||
.maxOfOrNull { it.date_upload } ?: 0L
|
// Those changes already checked beforehand, so we can proceed to updating the manga
|
||||||
if (newestChapterDate == 0L) {
|
|
||||||
if (toAdd.isNotEmpty()) {
|
|
||||||
manga.last_update = Date().time
|
manga.last_update = Date().time
|
||||||
mangaUpdate = MangaUpdate(manga.id!!, lastUpdate = manga.last_update)
|
updateManga.await(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) }
|
|
||||||
|
|
||||||
val reAddedSet = readded.toSet()
|
val reAddedSet = reAdded.toSet()
|
||||||
return Pair(
|
return Pair(
|
||||||
toAdd.subtract(reAddedSet).toList().filterChaptersByScanlators(manga),
|
updatedToAdd.subtract(reAddedSet).toList().filterChaptersByScanlators(manga),
|
||||||
toDelete - reAddedSet,
|
toDelete - reAddedSet,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,27 +54,26 @@ class ChapterRepositoryImpl(private val handler: DatabaseHandler) : ChapterRepos
|
||||||
|
|
||||||
override suspend fun delete(chapter: Chapter) =
|
override suspend fun delete(chapter: Chapter) =
|
||||||
try {
|
try {
|
||||||
partialDelete(chapter)
|
partialDelete(chapter.id!!)
|
||||||
true
|
true
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Logger.e(e) { "Failed to delete chapter with id '${chapter.id}'" }
|
Logger.e(e) { "Failed to delete chapter with id '${chapter.id}'" }
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun deleteAll(chapters: List<Chapter>) =
|
override suspend fun deleteAllById(chapters: List<Long>) =
|
||||||
try {
|
try {
|
||||||
partialDelete(*chapters.toTypedArray())
|
partialDelete(*chapters.toLongArray())
|
||||||
true
|
true
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Logger.e(e) { "Failed to bulk delete chapters" }
|
Logger.e(e) { "Failed to bulk delete chapters" }
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun partialDelete(vararg chapters: Chapter) {
|
private suspend fun partialDelete(vararg chapterIds: Long) {
|
||||||
handler.await(inTransaction = true) {
|
handler.await(inTransaction = true) {
|
||||||
chapters.forEach { chapter ->
|
chapterIds.forEach { chapterId ->
|
||||||
if (chapter.id == null) return@forEach
|
chaptersQueries.delete(chapterId)
|
||||||
chaptersQueries.delete(chapter.id!!)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -143,7 +142,7 @@ class ChapterRepositoryImpl(private val handler: DatabaseHandler) : ChapterRepos
|
||||||
|
|
||||||
override suspend fun insertBulk(chapters: List<Chapter>) =
|
override suspend fun insertBulk(chapters: List<Chapter>) =
|
||||||
handler.await(true) {
|
handler.await(true) {
|
||||||
chapters.forEach { chapter ->
|
chapters.map { chapter ->
|
||||||
chaptersQueries.insert(
|
chaptersQueries.insert(
|
||||||
mangaId = chapter.manga_id!!,
|
mangaId = chapter.manga_id!!,
|
||||||
url = chapter.url,
|
url = chapter.url,
|
||||||
|
@ -158,6 +157,8 @@ class ChapterRepositoryImpl(private val handler: DatabaseHandler) : ChapterRepos
|
||||||
dateFetch = chapter.date_fetch,
|
dateFetch = chapter.date_fetch,
|
||||||
dateUpload = chapter.date_upload,
|
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>>
|
fun getScanlatorsByChapterAsFlow(mangaId: Long): Flow<List<String>>
|
||||||
|
|
||||||
suspend fun delete(chapter: Chapter): Boolean
|
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 update(update: ChapterUpdate): Boolean
|
||||||
suspend fun updateAll(updates: List<ChapterUpdate>): Boolean
|
suspend fun updateAll(updates: List<ChapterUpdate>): Boolean
|
||||||
|
|
||||||
suspend fun insert(chapter: Chapter): Long?
|
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,
|
private val chapterRepository: ChapterRepository,
|
||||||
) {
|
) {
|
||||||
suspend fun await(chapter: Chapter) = chapterRepository.delete(chapter)
|
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