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)
}