Build a chapter's folder name variants from parts computed once

This commit is contained in:
AntsyLich
2026-10-07 19:59:52 +06:00
parent 179bfaca72
commit 6a329386c2
@@ -168,48 +168,21 @@ class DownloadProvider(
chapterUrl: String,
disallowNonAsciiFilenames: Boolean = libraryPreferences.disallowNonAsciiFilenames.get(),
enableChapterNameHash: Boolean = libraryPreferences.enableChapterNameHash.get(),
sanitizeScanlator: Boolean = true,
): String {
return buildString {
if (!chapterScanlator.isNullOrBlank()) {
// A "/" in the scanlator would otherwise nest the chapter in a folder of its own
append(if (sanitizeScanlator) DiskUtil.buildValidFilename(chapterScanlator) else chapterScanlator)
append("_")
}
// Subtract 7 bytes for hash and underscore, 4 bytes for .cbz
append(
DiskUtil.buildValidFilename(
sanitizeChapterName(chapterName),
DiskUtil.MAX_FILE_NAME_BYTES - 11,
disallowNonAsciiFilenames,
),
)
if (enableChapterNameHash) {
append("_${md5(chapterUrl).take(6)}")
}
}
return ChapterDirNameParts(chapterName, chapterScanlator, chapterUrl)
.dirName(disallowNonAsciiFilenames, enableChapterNameHash, sanitizeScanlator = true)
}
/**
* Returns list of names that might have been previously used as
* the directory name for a chapter.
* Add to this list if naming pattern ever changes.
*
* @param chapterName the name of the chapter to query.
* @param chapterScanlator scanlator of the chapter to query.
* @param chapterUrl url of the chapter to query.
*/
private fun getLegacyChapterDirNames(
chapterName: String,
chapterScanlator: String?,
chapterUrl: String,
): Set<String> {
val sanitizedChapterName = sanitizeChapterName(chapterName)
private fun getLegacyChapterDirNames(parts: ChapterDirNameParts): Set<String> {
val chapterNameV1 = DiskUtil.buildValidFilename(
when {
!chapterScanlator.isNullOrBlank() -> "${chapterScanlator}_$sanitizedChapterName"
else -> sanitizedChapterName
!parts.chapterScanlator.isNullOrBlank() -> "${parts.chapterScanlator}_${parts.chapterName}"
else -> parts.chapterName
},
)
@@ -220,26 +193,14 @@ class DownloadProvider(
val booleanPairPermutation = listOf(false to false, false to true, true to false, true to true)
val othersChapterDirNames = booleanPairPermutation
.map { (disallowNonAsciiFilenames, enableChapterNameHash) ->
getChapterDirName(
chapterName,
chapterScanlator,
chapterUrl,
disallowNonAsciiFilenames,
enableChapterNameHash,
)
parts.dirName(disallowNonAsciiFilenames, enableChapterNameHash, sanitizeScanlator = true)
}
// Scanlators weren't sanitized for a while. One with a "/" nested its folder, so it was never found anyway.
val unsanitizedScanlatorChapterDirNames = if (chapterScanlator != null && '/' !in chapterScanlator) {
val scanlator = parts.chapterScanlator
val unsanitizedScanlatorChapterDirNames = if (scanlator != null && '/' !in scanlator) {
booleanPairPermutation.map { (disallowNonAsciiFilenames, enableChapterNameHash) ->
getChapterDirName(
chapterName,
chapterScanlator,
chapterUrl,
disallowNonAsciiFilenames,
enableChapterNameHash,
sanitizeScanlator = false,
)
parts.dirName(disallowNonAsciiFilenames, enableChapterNameHash, sanitizeScanlator = false)
}
} else {
emptyList()
@@ -254,17 +215,6 @@ class DownloadProvider(
}
}
/**
* Return the new name for the chapter (in case it's empty or blank)
*
* @param chapterName the name of the chapter
*/
private fun sanitizeChapterName(chapterName: String): String {
return chapterName.ifBlank {
"Chapter"
}
}
fun isChapterDirNameChanged(oldChapter: Chapter, newChapter: Chapter): Boolean {
return getChapterDirName(oldChapter.name, oldChapter.scanlator, oldChapter.url) !=
getChapterDirName(newChapter.name, newChapter.scanlator, newChapter.url)
@@ -276,8 +226,13 @@ class DownloadProvider(
* @param chapter the domain chapter object.
*/
fun getValidChapterDirNames(chapterName: String, chapterScanlator: String?, chapterUrl: String): List<String> {
val chapterDirName = getChapterDirName(chapterName, chapterScanlator, chapterUrl)
val legacyChapterDirNames = getLegacyChapterDirNames(chapterName, chapterScanlator, chapterUrl)
val parts = ChapterDirNameParts(chapterName, chapterScanlator, chapterUrl)
val chapterDirName = parts.dirName(
disallowNonAscii = libraryPreferences.disallowNonAsciiFilenames.get(),
enableHash = libraryPreferences.enableChapterNameHash.get(),
sanitizeScanlator = true,
)
val legacyChapterDirNames = getLegacyChapterDirNames(parts)
return buildList {
// Folder of images
@@ -293,3 +248,40 @@ class DownloadProvider(
}
}
}
/**
* The parts of a chapter's directory name, each computed once however many name variations are built from them.
*/
private class ChapterDirNameParts(chapterName: String, val chapterScanlator: String?, private val chapterUrl: String) {
/** The chapter name, or a placeholder when it's blank. */
val chapterName = chapterName.ifBlank { "Chapter" }
private val hashSuffix by lazy(LazyThreadSafetyMode.NONE) { "_${md5(chapterUrl).take(6)}" }
private val sanitizedScanlator by lazy(LazyThreadSafetyMode.NONE) {
chapterScanlator?.let { DiskUtil.buildValidFilename(it) }
}
private val validChapterNames = arrayOfNulls<String>(2)
fun dirName(disallowNonAscii: Boolean, enableHash: Boolean, sanitizeScanlator: Boolean): String {
return buildString {
if (!chapterScanlator.isNullOrBlank()) {
// A "/" in the scanlator would otherwise nest the chapter in a folder of its own
append(if (sanitizeScanlator) sanitizedScanlator else chapterScanlator)
append("_")
}
append(validChapterName(disallowNonAscii))
if (enableHash) append(hashSuffix)
}
}
private fun validChapterName(disallowNonAscii: Boolean): String {
val index = if (disallowNonAscii) 1 else 0
return validChapterNames[index]
// Subtract 7 bytes for hash and underscore, 4 bytes for .cbz
?: DiskUtil.buildValidFilename(chapterName, DiskUtil.MAX_FILE_NAME_BYTES - 11, disallowNonAscii)
.also { validChapterNames[index] = it }
}
}