Fix ChapterList parsing issue (#24)

This commit is contained in:
Mio.
2025-07-11 23:03:50 +02:00
parent 26044358d3
commit cf3fca3653
3 changed files with 44 additions and 45 deletions

View File

@@ -342,33 +342,30 @@ class Kavita(private val suffix: String = "") : ConfigurableSource, UnmeteredSou
item.volumeId != null && item.volumeId > 0 -> item.volumeId != null && item.volumeId > 0 ->
"/Volume/${item.volumeId}?readingListId=$readingListId&seriesId=${item.seriesId}&volumeId=${item.volumeId}" "/Volume/${item.volumeId}?readingListId=$readingListId&seriesId=${item.seriesId}&volumeId=${item.volumeId}"
else -> else ->
// Fallback: use both seriesId and order to distinguish
"/Series/${item.seriesId}?readingListId=$readingListId&seriesId=${item.seriesId}&order=${item.order}" "/Series/${item.seriesId}?readingListId=$readingListId&seriesId=${item.seriesId}&order=${item.order}"
} }
name = buildString { name = buildString {
append("${item.order + 1}. ") append("${item.order + 1}. ")
when { when {
!item.chapterTitleName.isNullOrBlank() && !item.chapterTitleName.matches(Regex("^\\d+$")) -> { item.volumeNumber != null && item.volumeNumber != KavitaConstants.UNNUMBERED_VOLUME_STR -> {
append(item.chapterTitleName) append("Volume ${item.volumeNumber}")
} }
!item.volumeNumber.isNullOrBlank() && item.volumeNumber != UNNUMBERED_VOLUME_STR -> { item.chapterNumber != null && item.chapterNumber != KavitaConstants.UNNUMBERED_VOLUME_STR -> {
append("Volume ${item.volumeNumber.padStart(2, '0')}")
}
!item.chapterNumber.isNullOrBlank() && item.chapterNumber != UNNUMBERED_VOLUME_STR -> {
val libraryType = getLibraryType(item.seriesId) val libraryType = getLibraryType(item.seriesId)
when (libraryType) { when (libraryType) {
LibraryTypeEnum.Comic, LibraryTypeEnum.ComicVine -> LibraryTypeEnum.Comic, LibraryTypeEnum.ComicVine -> append("Issue #${item.chapterNumber}")
append("Issue #${item.chapterNumber.padStart(3, '0')}") else -> append("Chapter ${item.chapterNumber}")
else ->
append("Chapter ${item.chapterNumber.padStart(2, '0')}")
} }
} }
else -> {
append("Item ${item.order + 1}")
}
} }
} }
date_upload = if (preferences.RdDate && !item.releaseDate.isNullOrBlank()) { date_upload = if (preferences.RdDate && !item.releaseDate.isNullOrBlank()) {
parseDateSafe(item.releaseDate) parseDateSafe(item.releaseDate)
} else { } else {
0L // Explicitly unset the date 0L
} }
chapter_number = item.order.toFloat() chapter_number = item.order.toFloat()
scanlator = item.seriesName scanlator = item.seriesName
@@ -1021,7 +1018,7 @@ class Kavita(private val suffix: String = "") : ConfigurableSource, UnmeteredSou
for (volume in volumes) { for (volume in volumes) {
// Issue: use chapter covers // Issue: use chapter covers
if (isComicLibrary && volume.number == UNNUMBERED_VOLUME) { if (isComicLibrary && volume.number == KavitaConstants.UNNUMBERED_VOLUME) {
coverCandidates += volume.chapters coverCandidates += volume.chapters
.filterNot { it.coverImage.isNullOrBlank() } .filterNot { it.coverImage.isNullOrBlank() }
.map { chapter -> .map { chapter ->
@@ -1250,23 +1247,16 @@ class Kavita(private val suffix: String = "") : ConfigurableSource, UnmeteredSou
val chapters = mutableListOf<SChapter>() val chapters = mutableListOf<SChapter>()
val volumeItems = mutableListOf<SChapter>() val volumeItems = mutableListOf<SChapter>()
// First determine the content type
val hasChapters = volumes.any { volume ->
volume.chapters.any { chapter ->
ChapterType.of(chapter, volume, libraryType) != ChapterType.SingleFileVolume
}
}
val hasVolumes = volumes.any { volume ->
volume.chapters.any { chapter ->
ChapterType.of(chapter, volume, libraryType) == ChapterType.SingleFileVolume
}
}
volumes.forEach { volume -> volumes.forEach { volume ->
volume.chapters.forEach { chapter -> volume.chapters.forEach { chapter ->
val sChapter = helper.chapterFromVolume(chapter, volume, libraryType = libraryType) val sChapter = helper.chapterFromVolume(chapter, volume, libraryType = libraryType)
when (ChapterType.of(chapter, volume, libraryType)) { when (ChapterType.of(chapter, volume, libraryType)) {
ChapterType.SingleFileVolume -> volumeItems.add(sChapter) ChapterType.SingleFileVolume -> {
// For Case 2, use positive volume numbers
// For Case 3, use negative numbers
sChapter.chapter_number = volume.number.toFloat()
volumeItems.add(sChapter)
}
else -> chapters.add(sChapter) else -> chapters.add(sChapter)
} }
} }
@@ -1274,17 +1264,19 @@ class Kavita(private val suffix: String = "") : ConfigurableSource, UnmeteredSou
return when { return when {
// Case 1: Only chapters // Case 1: Only chapters
hasChapters && !hasVolumes -> chapters.sortedByDescending { it.chapter_number } chapters.isNotEmpty() && volumeItems.isEmpty() ->
chapters.sortedByDescending { it.chapter_number }
// Case 2: Only volumes (treat as chapters) // Case 2: Only volumes - treat as chapters with positive numbers
!hasChapters && hasVolumes -> volumeItems.sortedByDescending { it.chapter_number } volumeItems.isNotEmpty() && chapters.isEmpty() ->
volumeItems.sortedByDescending { it.chapter_number }
// Case 3: Mixed content // Case 3: Mixed content - chapters first, then volumes (as negative numbers)
else -> { else -> {
// Chapters first (sorted descending) // Convert volume numbers to negative for proper sorting
volumeItems.forEach { it.chapter_number = -it.chapter_number }
val sortedChapters = chapters.sortedByDescending { it.chapter_number } val sortedChapters = chapters.sortedByDescending { it.chapter_number }
// Volumes after (sorted descending with negative numbers) val sortedVolumes = volumeItems.sortedBy { it.chapter_number }
val sortedVolumes = volumeItems.sortedByDescending { it.chapter_number }
sortedChapters + sortedVolumes sortedChapters + sortedVolumes
} }
} }
@@ -1846,9 +1838,6 @@ class Kavita(private val suffix: String = "") : ConfigurableSource, UnmeteredSou
} }
companion object { companion object {
private const val UNNUMBERED_VOLUME = -100000
private const val UNNUMBERED_VOLUME_STR = "-100000"
private const val ADDRESS_TITLE = "Address" private const val ADDRESS_TITLE = "Address"
private val JSON_MEDIA_TYPE = "application/json; charset=utf-8".toMediaTypeOrNull() private val JSON_MEDIA_TYPE = "application/json; charset=utf-8".toMediaTypeOrNull()

View File

@@ -2,6 +2,9 @@ package eu.kanade.tachiyomi.extension.all.kavita
object KavitaConstants { object KavitaConstants {
const val UNNUMBERED_VOLUME = -100000
const val UNNUMBERED_VOLUME_STR = "-100000"
val PERSON_ROLES = listOf( val PERSON_ROLES = listOf(
"Writer", "Penciller", "Inker", "Colorist", "Writer", "Penciller", "Inker", "Colorist",
"Letterer", "CoverArtist", "Editor", "Letterer", "CoverArtist", "Editor",

View File

@@ -1,5 +1,6 @@
package eu.kanade.tachiyomi.extension.all.kavita.dto package eu.kanade.tachiyomi.extension.all.kavita.dto
import eu.kanade.tachiyomi.extension.all.kavita.KavitaConstants
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@@ -202,27 +203,33 @@ data class VolumeDto(
@Serializable @Serializable
enum class ChapterType { enum class ChapterType {
Regular, // chapter with volume information Regular, // Chapter with volume information
Chapter, // manga chapter without volume information Chapter, // Chapter without volume information
SingleFileVolume, SingleFileVolume,
Special, Special,
Issue, // For comics Issue, // For comics
; ;
companion object { companion object {
private const val SPECIAL_NUMBER = 100_000
private const val UNNUMBERED_VOLUME_NUMBER = -100_000
fun of(chapter: ChapterDto, volume: VolumeDto, libraryType: LibraryTypeEnum? = null): ChapterType = fun of(chapter: ChapterDto, volume: VolumeDto, libraryType: LibraryTypeEnum? = null): ChapterType =
when { when {
volume.number == 100_000 -> Special // Special cases
volume.number == -100_000 -> when (libraryType) { volume.number == SPECIAL_NUMBER -> Special
volume.number == UNNUMBERED_VOLUME_NUMBER -> when (libraryType) {
LibraryTypeEnum.Comic, LibraryTypeEnum.ComicVine -> Issue LibraryTypeEnum.Comic, LibraryTypeEnum.ComicVine -> Issue
LibraryTypeEnum.Manga, LibraryTypeEnum.LightNovel, LibraryTypeEnum.Book -> Chapter else -> Chapter
else -> Chapter // Default to Chapter for other types
} }
chapter.number == "-100000" -> SingleFileVolume // Single file volumes
chapter.number == KavitaConstants.UNNUMBERED_VOLUME_STR -> SingleFileVolume
// Regular volumes
volume.number > 0 -> SingleFileVolume
// Everything else depends on library type
else -> when (libraryType) { else -> when (libraryType) {
LibraryTypeEnum.Comic, LibraryTypeEnum.ComicVine -> Issue LibraryTypeEnum.Comic, LibraryTypeEnum.ComicVine -> Issue
LibraryTypeEnum.Manga, LibraryTypeEnum.LightNovel, LibraryTypeEnum.Book -> Chapter else -> Chapter
else -> Regular
} }
} }
} }