diff --git a/server/i18n/src/commonMain/moko-resources/values/base/strings.xml b/server/i18n/src/commonMain/moko-resources/values/base/strings.xml index 0e599ff49..1671f1c01 100644 --- a/server/i18n/src/commonMain/moko-resources/values/base/strings.xml +++ b/server/i18n/src/commonMain/moko-resources/values/base/strings.xml @@ -50,6 +50,7 @@ Series with ID %1$d not found. Chapter with index %1$d not found. + No chapters found or the source is unreachable on page %1$d. Sort Order diff --git a/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/sync/KoreaderSyncService.kt b/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/sync/KoreaderSyncService.kt index a0ca9db8a..cbb47f81b 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/sync/KoreaderSyncService.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/sync/KoreaderSyncService.kt @@ -127,29 +127,36 @@ object KoreaderSyncService { } val mangaId = chapterRow[ChapterTable.manga].value + val isDownloaded = chapterRow[ChapterTable.isDownloaded] val checksumMethod = serverConfig.koreaderSyncChecksumMethod.value val newHash = when (checksumMethod) { KoreaderSyncChecksumMethod.BINARY -> { - logger.debug { "[KOSYNC HASH] No hash for chapterId=$chapterId. Generating from downloaded content." } - try { - // Always create a CBZ in memory if it doesn't exist - val (stream, _) = ChapterDownloadHelper.getArchiveStreamWithSize(mangaId, chapterId) - // Write the stream to a temp file for partial hashing - val tempFile = File.createTempFile("kosync-hash-", ".cbz") + // Only generate binary hash if the chapter is downloaded to avoid fetching missing files + if (isDownloaded) { + logger.debug { "[KOSYNC HASH] No hash for chapterId=$chapterId. Generating from downloaded content." } try { - tempFile.outputStream().use { fos -> - stream.use { it.copyTo(fos) } + // Always create a CBZ in memory if it doesn't exist + val (stream, _) = ChapterDownloadHelper.getArchiveStreamWithSize(mangaId, chapterId) + // Write the stream to a temp file for partial hashing + val tempFile = File.createTempFile("kosync-hash-", ".cbz") + try { + tempFile.outputStream().use { fos -> + stream.use { it.copyTo(fos) } + } + // Use the same hashing method as for downloads + KoreaderHelper.hashContents(tempFile) + } finally { + // Always delete the temp file + tempFile.delete() } - // Use the same hashing method as for downloads - KoreaderHelper.hashContents(tempFile) - } finally { - // Always delete the temp file - tempFile.delete() + } catch (e: Exception) { + logger.warn(e) { "[KOSYNC HASH] Failed to generate archive stream for chapterId=$chapterId." } + null } - } catch (e: Exception) { - logger.warn(e) { "[KOSYNC HASH] Failed to generate archive stream for chapterId=$chapterId." } + } else { + logger.debug { "[KOSYNC HASH] Skipping binary hash for chapterId=$chapterId because it is not downloaded." } null } } @@ -175,7 +182,7 @@ object KoreaderSyncService { } logger.info { "[KOSYNC HASH] Generated and saved new hash for chapterId=$chapterId" } } else { - logger.warn { "[KOSYNC HASH] Hashing failed for chapterId=$chapterId." } + logger.warn { "[KOSYNC HASH] Hashing failed or skipped for chapterId=$chapterId." } } newHash } diff --git a/server/src/main/kotlin/suwayomi/tachidesk/opds/impl/OpdsFeedBuilder.kt b/server/src/main/kotlin/suwayomi/tachidesk/opds/impl/OpdsFeedBuilder.kt index 6451a23cb..41c505190 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/opds/impl/OpdsFeedBuilder.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/opds/impl/OpdsFeedBuilder.kt @@ -644,6 +644,16 @@ object OpdsFeedBuilder { skipMetadata, ) + // Return a not-found feed if all available chapters are filtered out as unreachable + if (skipMetadata && chapterEntries.isEmpty() && totalChapters > 0L) { + return buildNotFoundFeed( + baseUrl = baseUrl, + locale = locale, + idPath = "series/$mangaId/chapters", + title = MR.strings.opds_error_chapters_not_found.localized(locale, pageNum), + ) + } + // If no chapters are found in the database, attempt to fetch them from the source. if (chapterEntries.isEmpty() && totalChapters == 0L) { try { diff --git a/server/src/main/kotlin/suwayomi/tachidesk/opds/repository/ChapterRepository.kt b/server/src/main/kotlin/suwayomi/tachidesk/opds/repository/ChapterRepository.kt index df7ca43ea..7b9599ffd 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/opds/repository/ChapterRepository.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/opds/repository/ChapterRepository.kt @@ -169,6 +169,8 @@ object ChapterRepository { } } }.awaitAll() + // Exclude unreachable chapters that are not downloaded and have no page count + .filter { it.downloaded || it.pageCount > 0 } return Pair(enrichedChapters, totalCount) }