From b25cd24c9d89c04943d83e7e6ddf36b5646e604f Mon Sep 17 00:00:00 2001 From: Syer10 Date: Sat, 4 Nov 2023 14:10:41 -0400 Subject: [PATCH 1/7] Chapter fetch improvements --- .../util/chapter/ChapterSanitizer.kt | 45 +++ .../suwayomi/tachidesk/manga/impl/Chapter.kt | 261 ++++++++++-------- .../manga/model/dataclass/ChapterDataClass.kt | 2 +- 3 files changed, 199 insertions(+), 109 deletions(-) create mode 100644 server/src/main/kotlin/eu/kanade/tachiyomi/util/chapter/ChapterSanitizer.kt diff --git a/server/src/main/kotlin/eu/kanade/tachiyomi/util/chapter/ChapterSanitizer.kt b/server/src/main/kotlin/eu/kanade/tachiyomi/util/chapter/ChapterSanitizer.kt new file mode 100644 index 000000000..03f4be030 --- /dev/null +++ b/server/src/main/kotlin/eu/kanade/tachiyomi/util/chapter/ChapterSanitizer.kt @@ -0,0 +1,45 @@ +package eu.kanade.tachiyomi.util.chapter + +object ChapterSanitizer { + fun String.sanitize(title: String): String { + return trim() + .removePrefix(title) + .trim(*CHAPTER_TRIM_CHARS) + } + + private val CHAPTER_TRIM_CHARS = + arrayOf( + // Whitespace + ' ', + '\u0009', + '\u000A', + '\u000B', + '\u000C', + '\u000D', + '\u0020', + '\u0085', + '\u00A0', + '\u1680', + '\u2000', + '\u2001', + '\u2002', + '\u2003', + '\u2004', + '\u2005', + '\u2006', + '\u2007', + '\u2008', + '\u2009', + '\u200A', + '\u2028', + '\u2029', + '\u202F', + '\u205F', + '\u3000', + // Separators + '-', + '_', + ',', + ':', + ).toCharArray() +} diff --git a/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/Chapter.kt b/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/Chapter.kt index 4f13e719a..7b476c14c 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/Chapter.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/Chapter.kt @@ -7,17 +7,21 @@ package suwayomi.tachidesk.manga.impl * 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 com.google.common.cache.Cache +import com.google.common.cache.CacheBuilder import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.online.HttpSource import eu.kanade.tachiyomi.util.chapter.ChapterRecognition +import eu.kanade.tachiyomi.util.chapter.ChapterSanitizer.sanitize +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock import kotlinx.serialization.Serializable import mu.KotlinLogging import org.jetbrains.exposed.dao.id.EntityID import org.jetbrains.exposed.sql.Op import org.jetbrains.exposed.sql.ResultRow import org.jetbrains.exposed.sql.SortOrder -import org.jetbrains.exposed.sql.SortOrder.ASC import org.jetbrains.exposed.sql.SqlExpressionBuilder.inList import org.jetbrains.exposed.sql.and import org.jetbrains.exposed.sql.batchInsert @@ -41,7 +45,11 @@ import suwayomi.tachidesk.manga.model.table.MangaTable import suwayomi.tachidesk.manga.model.table.PageTable import suwayomi.tachidesk.manga.model.table.toDataClass import suwayomi.tachidesk.server.serverConfig +import java.lang.Long import java.time.Instant +import java.util.TreeSet +import java.util.concurrent.TimeUnit +import kotlin.math.max object Chapter { private val logger = KotlinLogging.logger { } @@ -109,133 +117,170 @@ object Chapter { } } + val map: Cache = + CacheBuilder.newBuilder() + .expireAfterAccess(10, TimeUnit.MINUTES) + .build() + suspend fun fetchChapterList(mangaId: Int): List { - val manga = getManga(mangaId) - val source = getCatalogueSourceOrStub(manga.sourceId.toLong()) + val mutex = map.get(mangaId) { Mutex() } + val chapterList = + mutex.withLock { + val manga = getManga(mangaId) + val source = getCatalogueSourceOrStub(manga.sourceId.toLong()) + + val sManga = + SManga.create().apply { + title = manga.title + url = manga.url + } - val sManga = - SManga.create().apply { - title = manga.title - url = manga.url - } + val numberOfCurrentChapters = getCountOfMangaChapters(mangaId) + val chapterList = source.getChapterList(sManga) - val numberOfCurrentChapters = getCountOfMangaChapters(mangaId) - val chapterList = source.getChapterList(sManga) + // Recognize number for new chapters. + chapterList.forEach { chapter -> + (source as? HttpSource)?.prepareNewChapter(chapter, sManga) + val chapterNumber = ChapterRecognition.parseChapterNumber(manga.title, chapter.name, chapter.chapter_number.toDouble()) + chapter.chapter_number = chapterNumber.toFloat() + chapter.name = chapter.name.sanitize(manga.title) + chapter.scanlator = chapter.scanlator?.ifBlank { null } + } - // Recognize number for new chapters. - chapterList.forEach { chapter -> - (source as? HttpSource)?.prepareNewChapter(chapter, sManga) - val chapterNumber = ChapterRecognition.parseChapterNumber(manga.title, chapter.name, chapter.chapter_number.toDouble()) - chapter.chapter_number = chapterNumber.toFloat() - } + val now = Instant.now().epochSecond + // Used to not set upload date of older chapters + // to a higher value than newer chapters + var maxSeenUploadDate = 0L - val now = Instant.now().epochSecond - val chaptersInDb = - transaction { - ChapterTable.select { ChapterTable.manga eq mangaId } - .map { ChapterTable.toDataClass(it) } - .toSet() - } + val chaptersInDb = + transaction { + ChapterTable.select { ChapterTable.manga eq mangaId } + .map { ChapterTable.toDataClass(it) } + .toList() + } - val chaptersToInsert = mutableListOf() - val chaptersToUpdate = mutableListOf() - - chapterList.reversed().forEachIndexed { index, fetchedChapter -> - val chapterEntry = chaptersInDb.find { it.url == fetchedChapter.url } - - val chapterData = - ChapterDataClass.fromSChapter( - fetchedChapter, - chapterEntry?.id ?: 0, - index + 1, - now, - mangaId, - runCatching { - (source as? HttpSource)?.getChapterUrl(fetchedChapter) - }.getOrNull(), - ) - - if (chapterEntry == null) { - chaptersToInsert.add(chapterData) - } else { - chaptersToUpdate.add(chapterData) - } - } + val chaptersToInsert = mutableListOf() + val chaptersToUpdate = mutableListOf() + + chapterList.reversed().forEachIndexed { index, fetchedChapter -> + val chapterEntry = chaptersInDb.find { it.url == fetchedChapter.url } + + val chapterData = + ChapterDataClass.fromSChapter( + fetchedChapter, + chapterEntry?.id ?: 0, + index + 1, + now, + mangaId, + runCatching { + (source as? HttpSource)?.getChapterUrl(fetchedChapter) + }.getOrNull(), + ) - transaction { - if (chaptersToInsert.isNotEmpty()) { - ChapterTable.batchInsert(chaptersToInsert) { - this[ChapterTable.url] = it.url - this[ChapterTable.name] = it.name - this[ChapterTable.date_upload] = it.uploadDate - this[ChapterTable.chapter_number] = it.chapterNumber - this[ChapterTable.scanlator] = it.scanlator - this[ChapterTable.sourceOrder] = it.index - this[ChapterTable.fetchedAt] = it.fetchedAt - this[ChapterTable.manga] = it.mangaId - this[ChapterTable.realUrl] = it.realUrl + if (chapterEntry == null) { + val newChapterData = + if (chapterData.uploadDate == 0L) { + val altDateUpload = if (maxSeenUploadDate == 0L) now else maxSeenUploadDate + chapterData.copy(uploadDate = altDateUpload) + } else { + maxSeenUploadDate = max(maxSeenUploadDate, chapterData.uploadDate) + chapterData + } + maxSeenUploadDate = max(maxSeenUploadDate, chapterData.uploadDate) + chaptersToInsert.add(newChapterData) + } else { + chaptersToUpdate.add(chapterData) + } } - } - if (chaptersToUpdate.isNotEmpty()) { - BatchUpdateStatement(ChapterTable).apply { - chaptersToUpdate.forEach { - addBatch(EntityID(it.id, ChapterTable)) - this[ChapterTable.name] = it.name - this[ChapterTable.date_upload] = it.uploadDate - this[ChapterTable.chapter_number] = it.chapterNumber - this[ChapterTable.scanlator] = it.scanlator - this[ChapterTable.sourceOrder] = it.index - this[ChapterTable.realUrl] = it.realUrl + val deletedChapterNumbers = TreeSet() + val deletedReadChapterNumbers = TreeSet() + val deletedBookmarkedChapterNumbers = TreeSet() + val deletedChapterNumberDateFetchMap = mutableMapOf() + + // clear any orphaned/duplicate chapters that are in the db but not in `chapterList` + val dbChapterCount = chaptersInDb.count() + if (dbChapterCount > chapterList.size) { // we got some clean up due + val chapterUrls = chapterList.map { it.url }.toSet() + + val chaptersIdsToDelete = + chaptersInDb.mapNotNull { dbChapter -> + if (!chapterUrls.contains(dbChapter.url)) { + if (dbChapter.read) deletedReadChapterNumbers.add(dbChapter.chapterNumber) + if (dbChapter.bookmarked) deletedBookmarkedChapterNumbers.add(dbChapter.chapterNumber) + deletedChapterNumbers.add(dbChapter.chapterNumber) + deletedChapterNumberDateFetchMap[dbChapter.chapterNumber] = dbChapter.fetchedAt + dbChapter.id + } else { + null + } + } + + transaction { + PageTable.deleteWhere { PageTable.chapter inList chaptersIdsToDelete } + ChapterTable.deleteWhere { ChapterTable.id inList chaptersIdsToDelete } } - execute(this@transaction) } - } - MangaTable.update({ MangaTable.id eq mangaId }) { - it[MangaTable.chaptersLastFetchedAt] = Instant.now().epochSecond - } - } + transaction { + if (chaptersToInsert.isNotEmpty()) { + ChapterTable.batchInsert(chaptersToInsert) { chapter -> + this[ChapterTable.url] = chapter.url + this[ChapterTable.name] = chapter.name + this[ChapterTable.date_upload] = chapter.uploadDate + this[ChapterTable.chapter_number] = chapter.chapterNumber + this[ChapterTable.scanlator] = chapter.scanlator + this[ChapterTable.sourceOrder] = chapter.index + this[ChapterTable.fetchedAt] = chapter.fetchedAt + this[ChapterTable.manga] = chapter.mangaId + this[ChapterTable.realUrl] = chapter.realUrl + this[ChapterTable.isRead] = false + this[ChapterTable.isBookmarked] = false + + // is recognized chapter number + if (chapter.chapterNumber >= 0f && chapter.chapterNumber in deletedChapterNumbers) { + this[ChapterTable.isRead] = chapter.chapterNumber in deletedReadChapterNumbers + this[ChapterTable.isBookmarked] = chapter.chapterNumber in deletedBookmarkedChapterNumbers + // Try to to use the fetch date of the original entry to not pollute 'Updates' tab + deletedChapterNumberDateFetchMap[chapter.chapterNumber]?.let { + this[ChapterTable.fetchedAt] = it + } + } + } + } - val newChapters = - transaction { - ChapterTable.select { ChapterTable.manga eq mangaId } - .orderBy(ChapterTable.sourceOrder to SortOrder.DESC).toList() - } + if (chaptersToUpdate.isNotEmpty()) { + BatchUpdateStatement(ChapterTable).apply { + chaptersToUpdate.forEach { + addBatch(EntityID(it.id, ChapterTable)) + this[ChapterTable.name] = it.name + this[ChapterTable.date_upload] = it.uploadDate + this[ChapterTable.chapter_number] = it.chapterNumber + this[ChapterTable.scanlator] = it.scanlator + this[ChapterTable.sourceOrder] = it.index + this[ChapterTable.realUrl] = it.realUrl + } + execute(this@transaction) + } + } - // clear any orphaned/duplicate chapters that are in the db but not in `chapterList` - val dbChapterCount = newChapters.count() - if (dbChapterCount > chapterList.size) { // we got some clean up due - val dbChapterList = - transaction { - ChapterTable.select { ChapterTable.manga eq mangaId } - .orderBy(ChapterTable.url to ASC).toList() + MangaTable.update({ MangaTable.id eq mangaId }) { + it[MangaTable.chaptersLastFetchedAt] = Instant.now().epochSecond + } } - val chapterUrls = chapterList.map { it.url }.toSet() - - val chaptersIdsToDelete = - dbChapterList.mapIndexedNotNull { index, dbChapter -> - val isOrphaned = !chapterUrls.contains(dbChapter[ChapterTable.url]) - val isDuplicate = - index < dbChapterList.lastIndex && dbChapter[ChapterTable.url] == dbChapterList[index + 1][ChapterTable.url] - val deleteChapter = isOrphaned || isDuplicate - if (deleteChapter) { - dbChapter[ChapterTable.id].value - } else { - null + val newChapters = + transaction { + ChapterTable.select { ChapterTable.manga eq mangaId } + .orderBy(ChapterTable.sourceOrder to SortOrder.DESC).toList() } + + if (manga.inLibrary) { + downloadNewChapters(mangaId, numberOfCurrentChapters, newChapters) } - transaction { - PageTable.deleteWhere { PageTable.chapter inList chaptersIdsToDelete } - ChapterTable.deleteWhere { ChapterTable.id inList chaptersIdsToDelete } + chapterList } - } - - if (manga.inLibrary) { - downloadNewChapters(mangaId, numberOfCurrentChapters, newChapters) - } return chapterList } diff --git a/server/src/main/kotlin/suwayomi/tachidesk/manga/model/dataclass/ChapterDataClass.kt b/server/src/main/kotlin/suwayomi/tachidesk/manga/model/dataclass/ChapterDataClass.kt index 1023a6797..9c59b313e 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/manga/model/dataclass/ChapterDataClass.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/manga/model/dataclass/ChapterDataClass.kt @@ -56,7 +56,7 @@ data class ChapterDataClass( name = sChapter.name, uploadDate = sChapter.date_upload, chapterNumber = sChapter.chapter_number, - scanlator = sChapter.scanlator ?: "", + scanlator = sChapter.scanlator, index = index, fetchedAt = fetchedAt, realUrl = realUrl, From daf6e89a89c16e247fcfd36dca4fbc65adb21945 Mon Sep 17 00:00:00 2001 From: Syer10 Date: Sat, 4 Nov 2023 14:25:03 -0400 Subject: [PATCH 2/7] Update previous date uploads --- .../suwayomi/tachidesk/manga/impl/Chapter.kt | 7 ++++++- .../database/migration/M0030_FixDateUpload.kt | 21 +++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0030_FixDateUpload.kt diff --git a/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/Chapter.kt b/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/Chapter.kt index 7b476c14c..a9de0fd54 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/Chapter.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/Chapter.kt @@ -189,7 +189,12 @@ object Chapter { maxSeenUploadDate = max(maxSeenUploadDate, chapterData.uploadDate) chaptersToInsert.add(newChapterData) } else { - chaptersToUpdate.add(chapterData) + val newChapterData = if (chapterData.uploadDate == 0L) { + chapterData.copy(uploadDate = chapterEntry.uploadDate) + } else { + chapterData + } + chaptersToUpdate.add(newChapterData) } } diff --git a/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0030_FixDateUpload.kt b/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0030_FixDateUpload.kt new file mode 100644 index 000000000..75f9add87 --- /dev/null +++ b/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0030_FixDateUpload.kt @@ -0,0 +1,21 @@ +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 M0030_FixDateUpload : SQLMigration() { + // language=h2 + override val sql = + """ + UPDATE CHAPTER + SET DATE_UPLOAD = (FETCHED_AT * 1000) + WHERE DATE_UPLOAD = 0; + """.trimIndent() +} From 3e3fdb125b0016ef6068f3b5c92a1ea2a789de80 Mon Sep 17 00:00:00 2001 From: Syer10 Date: Sat, 4 Nov 2023 14:25:31 -0400 Subject: [PATCH 3/7] Lint --- .../kotlin/suwayomi/tachidesk/manga/impl/Chapter.kt | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/Chapter.kt b/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/Chapter.kt index a9de0fd54..aff9e55ad 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/Chapter.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/Chapter.kt @@ -189,11 +189,12 @@ object Chapter { maxSeenUploadDate = max(maxSeenUploadDate, chapterData.uploadDate) chaptersToInsert.add(newChapterData) } else { - val newChapterData = if (chapterData.uploadDate == 0L) { - chapterData.copy(uploadDate = chapterEntry.uploadDate) - } else { - chapterData - } + val newChapterData = + if (chapterData.uploadDate == 0L) { + chapterData.copy(uploadDate = chapterEntry.uploadDate) + } else { + chapterData + } chaptersToUpdate.add(newChapterData) } } From e57b511b4f63a85f9e2da50ed914bfceb146d956 Mon Sep 17 00:00:00 2001 From: Syer10 Date: Sat, 4 Nov 2023 15:29:29 -0400 Subject: [PATCH 4/7] Fix backup inserts --- .../impl/backup/proto/ProtoBackupImport.kt | 37 +++++++++++-------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/backup/proto/ProtoBackupImport.kt b/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/backup/proto/ProtoBackupImport.kt index ec7d75297..99df5ca3d 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/backup/proto/ProtoBackupImport.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/backup/proto/ProtoBackupImport.kt @@ -22,6 +22,7 @@ import okio.buffer import okio.gzip import okio.source import org.jetbrains.exposed.sql.and +import org.jetbrains.exposed.sql.batchInsert import org.jetbrains.exposed.sql.insert import org.jetbrains.exposed.sql.insertAndGetId import org.jetbrains.exposed.sql.select @@ -294,23 +295,25 @@ object ProtoBackupImport : ProtoBackupBase() { // insert chapter data val chaptersLength = chapters.size - chapters.forEach { chapter -> - ChapterTable.insert { - it[url] = chapter.url - it[name] = chapter.name - it[date_upload] = chapter.date_upload - it[chapter_number] = chapter.chapter_number - it[scanlator] = chapter.scanlator + ChapterTable.batchInsert(chapters) { chapter -> + this[ChapterTable.url] = chapter.url + this[ChapterTable.name] = chapter.name + if (chapter.date_upload == 0L) { + this[ChapterTable.date_upload] = chapter.date_fetch + } else { + this[ChapterTable.date_upload] = chapter.date_upload + } + this[ChapterTable.chapter_number] = chapter.chapter_number + this[ChapterTable.scanlator] = chapter.scanlator - it[sourceOrder] = chaptersLength - chapter.source_order - it[ChapterTable.manga] = mangaId + this[ChapterTable.sourceOrder] = chaptersLength - chapter.source_order + this[ChapterTable.manga] = mangaId - it[isRead] = chapter.read - it[lastPageRead] = chapter.last_page_read - it[isBookmarked] = chapter.bookmark + this[ChapterTable.isRead] = chapter.read + this[ChapterTable.lastPageRead] = chapter.last_page_read + this[ChapterTable.isBookmarked] = chapter.bookmark - it[fetchedAt] = TimeUnit.MILLISECONDS.toSeconds(chapter.date_fetch) - } + this[ChapterTable.fetchedAt] = TimeUnit.MILLISECONDS.toSeconds(chapter.date_fetch) } // insert categories @@ -350,7 +353,11 @@ object ProtoBackupImport : ProtoBackupBase() { ChapterTable.insert { it[url] = chapter.url it[name] = chapter.name - it[date_upload] = chapter.date_upload + if (chapter.date_upload == 0L) { + it[date_upload] = chapter.date_fetch + } else { + it[date_upload] = chapter.date_upload + } it[chapter_number] = chapter.chapter_number it[scanlator] = chapter.scanlator From 4e7426d0624789bd2624bdc93e5405e3fbc75e31 Mon Sep 17 00:00:00 2001 From: Syer10 Date: Sat, 4 Nov 2023 17:00:56 -0400 Subject: [PATCH 5/7] Remove extra maxSeenUploadDate --- server/src/main/kotlin/suwayomi/tachidesk/manga/impl/Chapter.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/Chapter.kt b/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/Chapter.kt index aff9e55ad..8e6f98b46 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/Chapter.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/Chapter.kt @@ -186,7 +186,6 @@ object Chapter { maxSeenUploadDate = max(maxSeenUploadDate, chapterData.uploadDate) chapterData } - maxSeenUploadDate = max(maxSeenUploadDate, chapterData.uploadDate) chaptersToInsert.add(newChapterData) } else { val newChapterData = From 4ff23706d74c3c01a92ff45ccb05302cba3d257d Mon Sep 17 00:00:00 2001 From: Syer10 Date: Sat, 4 Nov 2023 17:07:08 -0400 Subject: [PATCH 6/7] Port downloaded over --- .../src/main/kotlin/suwayomi/tachidesk/manga/impl/Chapter.kt | 5 ++++- .../impl/download/fileProvider/ChaptersFilesProvider.kt | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/Chapter.kt b/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/Chapter.kt index 8e6f98b46..ef77869d0 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/Chapter.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/Chapter.kt @@ -201,6 +201,7 @@ object Chapter { val deletedChapterNumbers = TreeSet() val deletedReadChapterNumbers = TreeSet() val deletedBookmarkedChapterNumbers = TreeSet() + val deletedDownloadedChapterNumbers = TreeSet() val deletedChapterNumberDateFetchMap = mutableMapOf() // clear any orphaned/duplicate chapters that are in the db but not in `chapterList` @@ -213,6 +214,7 @@ object Chapter { if (!chapterUrls.contains(dbChapter.url)) { if (dbChapter.read) deletedReadChapterNumbers.add(dbChapter.chapterNumber) if (dbChapter.bookmarked) deletedBookmarkedChapterNumbers.add(dbChapter.chapterNumber) + if (dbChapter.downloaded) deletedDownloadedChapterNumbers.add(dbChapter.chapterNumber) deletedChapterNumbers.add(dbChapter.chapterNumber) deletedChapterNumberDateFetchMap[dbChapter.chapterNumber] = dbChapter.fetchedAt dbChapter.id @@ -246,7 +248,8 @@ object Chapter { if (chapter.chapterNumber >= 0f && chapter.chapterNumber in deletedChapterNumbers) { this[ChapterTable.isRead] = chapter.chapterNumber in deletedReadChapterNumbers this[ChapterTable.isBookmarked] = chapter.chapterNumber in deletedBookmarkedChapterNumbers - // Try to to use the fetch date of the original entry to not pollute 'Updates' tab + this[ChapterTable.isDownloaded] = chapter.chapterNumber in deletedDownloadedChapterNumbers + // Try to use the fetch date of the original entry to not pollute 'Updates' tab deletedChapterNumberDateFetchMap[chapter.chapterNumber]?.let { this[ChapterTable.fetchedAt] = it } diff --git a/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/download/fileProvider/ChaptersFilesProvider.kt b/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/download/fileProvider/ChaptersFilesProvider.kt index e5428bba9..cfe567d37 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/download/fileProvider/ChaptersFilesProvider.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/download/fileProvider/ChaptersFilesProvider.kt @@ -15,7 +15,7 @@ import java.io.InputStream /* * Base class for downloaded chapter files provider, example: Folder, Archive -* */ +*/ abstract class ChaptersFilesProvider(val mangaId: Int, val chapterId: Int) : DownloadedFilesProvider { abstract fun getImageImpl(index: Int): Pair From 025bf87d8bd170ed37f0ec96d18cde5777a72197 Mon Sep 17 00:00:00 2001 From: Syer10 Date: Sat, 4 Nov 2023 17:23:19 -0400 Subject: [PATCH 7/7] Make sure to set isDownloaded on all inserts --- server/src/main/kotlin/suwayomi/tachidesk/manga/impl/Chapter.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/Chapter.kt b/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/Chapter.kt index ef77869d0..ed15659fb 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/Chapter.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/Chapter.kt @@ -243,6 +243,7 @@ object Chapter { this[ChapterTable.realUrl] = chapter.realUrl this[ChapterTable.isRead] = false this[ChapterTable.isBookmarked] = false + this[ChapterTable.isDownloaded] = false // is recognized chapter number if (chapter.chapterNumber >= 0f && chapter.chapterNumber in deletedChapterNumbers) {