mirror of
https://github.com/Suwayomi/Tachidesk.git
synced 2025-12-10 06:42:07 +01:00
Prevent duplicated chapter pages (#1353)
In case "ChapterForDownload#asDownloadReady" was called in quick succession, the page list got inserted twice. This caused problems with getting the images from the rest endpoint, because they are selected by sorting them by asc index and selecting the page by using the provided index as an offset. This, however, only works as long as there are no duplicates, otherwise, page indexes 1, 2; 3, 4; 5, 6; ... will just return the same page.
This commit is contained in:
@@ -11,6 +11,9 @@ import eu.kanade.tachiyomi.source.model.Page
|
||||
import eu.kanade.tachiyomi.source.model.SChapter
|
||||
import io.github.oshai.kotlinlogging.KLogger
|
||||
import io.github.oshai.kotlinlogging.KotlinLogging
|
||||
import io.github.reactivecircus.cache4k.Cache
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import org.jetbrains.exposed.sql.ResultRow
|
||||
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
|
||||
import org.jetbrains.exposed.sql.and
|
||||
@@ -26,6 +29,7 @@ import suwayomi.tachidesk.manga.model.table.ChapterTable
|
||||
import suwayomi.tachidesk.manga.model.table.MangaTable
|
||||
import suwayomi.tachidesk.manga.model.table.PageTable
|
||||
import suwayomi.tachidesk.manga.model.table.toDataClass
|
||||
import kotlin.time.Duration.Companion.minutes
|
||||
|
||||
suspend fun getChapterDownloadReady(
|
||||
chapterId: Int? = null,
|
||||
@@ -43,6 +47,12 @@ suspend fun getChapterDownloadReadyByIndex(
|
||||
mangaId: Int,
|
||||
): ChapterDataClass = getChapterDownloadReady(chapterIndex = chapterIndex, mangaId = mangaId)
|
||||
|
||||
private val mutexByChapterId: Cache<Int, Mutex> =
|
||||
Cache
|
||||
.Builder<Int, Mutex>()
|
||||
.expireAfterAccess(10.minutes)
|
||||
.build()
|
||||
|
||||
private class ChapterForDownload(
|
||||
optChapterId: Int? = null,
|
||||
optChapterIndex: Int? = null,
|
||||
@@ -69,9 +79,7 @@ private class ChapterForDownload(
|
||||
|
||||
markAsNotDownloaded()
|
||||
|
||||
val pageList = fetchPageList()
|
||||
|
||||
updateDatabasePages(pageList)
|
||||
updatePageList()
|
||||
}
|
||||
|
||||
return asDataClass()
|
||||
@@ -109,6 +117,14 @@ private class ChapterForDownload(
|
||||
}.first()
|
||||
}
|
||||
|
||||
private suspend fun updatePageList() {
|
||||
val mutex = mutexByChapterId.get(chapterId) { Mutex() }
|
||||
mutex.withLock {
|
||||
val pageList = fetchPageList()
|
||||
updateDatabasePages(pageList)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun fetchPageList(): List<Page> {
|
||||
val mangaEntry = transaction { MangaTable.selectAll().where { MangaTable.id eq mangaId }.first() }
|
||||
val source = getCatalogueSourceOrStub(mangaEntry[MangaTable.sourceReference])
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
package suwayomi.tachidesk.server.database.migration
|
||||
|
||||
/*
|
||||
* Copyright (C) Contributors to the Suwayomi project
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
import de.neonew.exposed.migrations.helpers.SQLMigration
|
||||
|
||||
@Suppress("ClassName", "unused")
|
||||
class M0045_PreventDuplicatedChapterPages : SQLMigration() {
|
||||
override val sql: String =
|
||||
"""
|
||||
DELETE FROM PAGE
|
||||
WHERE ID NOT IN (
|
||||
SELECT MIN(ID)
|
||||
FROM PAGE
|
||||
GROUP BY INDEX, "imageUrl", CHAPTER
|
||||
);
|
||||
|
||||
ALTER TABLE PAGE
|
||||
ADD CONSTRAINT UC_PAGE UNIQUE (INDEX, imageUrl, CHAPTER)
|
||||
""".trimIndent()
|
||||
}
|
||||
Reference in New Issue
Block a user