fix(kosync): use correct partial hash for binary checksum (#1610)

When generating a hash on-the-fly for the binary checksum method, the code was performing a full MD5 hash of the entire file stream. This was incorrect as the KOReader binary method expects a specific partial hash (reading small chunks at different offsets).

This change ensures that when an in-memory CBZ is created, it is first written to a temporary file. Then, the correct `KoreaderHelper.hashContents()` function is used on that file to generate the partial hash, matching KOReader's logic. The temporary file is deleted immediately after.
This commit is contained in:
Zeedif
2025-08-24 10:35:38 -06:00
committed by GitHub
parent 4482b325d7
commit a5d64be197

View File

@@ -18,10 +18,12 @@ import suwayomi.tachidesk.graphql.types.KoSyncStatusPayload
import suwayomi.tachidesk.graphql.types.KoreaderSyncChecksumMethod import suwayomi.tachidesk.graphql.types.KoreaderSyncChecksumMethod
import suwayomi.tachidesk.graphql.types.KoreaderSyncStrategy import suwayomi.tachidesk.graphql.types.KoreaderSyncStrategy
import suwayomi.tachidesk.manga.impl.ChapterDownloadHelper import suwayomi.tachidesk.manga.impl.ChapterDownloadHelper
import suwayomi.tachidesk.manga.impl.util.KoreaderHelper
import suwayomi.tachidesk.manga.model.table.ChapterTable import suwayomi.tachidesk.manga.model.table.ChapterTable
import suwayomi.tachidesk.manga.model.table.MangaTable import suwayomi.tachidesk.manga.model.table.MangaTable
import suwayomi.tachidesk.server.serverConfig import suwayomi.tachidesk.server.serverConfig
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
import java.io.File
import java.util.UUID import java.util.UUID
import kotlin.math.abs import kotlin.math.abs
@@ -119,11 +121,19 @@ object KoreaderSyncService {
KoreaderSyncChecksumMethod.BINARY -> { KoreaderSyncChecksumMethod.BINARY -> {
logger.info { "[KOSYNC HASH] No hash for chapterId=$chapterId. Generating from downloaded content." } logger.info { "[KOSYNC HASH] No hash for chapterId=$chapterId. Generating from downloaded content." }
try { try {
// This generates a deterministic CBZ stream from either a folder or an existing CBZ file. // Always create a CBZ in memory if it doesn't exist
// If it fails, it means the chapter is not available for hashing.
val (stream, _) = ChapterDownloadHelper.getArchiveStreamWithSize(mangaId, chapterId) val (stream, _) = ChapterDownloadHelper.getArchiveStreamWithSize(mangaId, chapterId)
stream.use { // Write the stream to a temp file for partial hashing
Hash.md5(it.readBytes()) 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()
} }
} catch (e: Exception) { } catch (e: Exception) {
logger.warn(e) { "[KOSYNC HASH] Failed to generate archive stream for chapterId=$chapterId." } logger.warn(e) { "[KOSYNC HASH] Failed to generate archive stream for chapterId=$chapterId." }