fix broken pages
This commit is contained in:
@@ -1009,7 +1009,7 @@ class Kavita(private val suffix: String = "") : ConfigurableSource, UnmeteredSou
|
|||||||
if (chapter.coverImage.isNotBlank()) {
|
if (chapter.coverImage.isNotBlank()) {
|
||||||
val url = "$apiUrl/Image/chapter-cover?chapterId=${chapter.id}&apiKey=$apiKey"
|
val url = "$apiUrl/Image/chapter-cover?chapterId=${chapter.id}&apiKey=$apiKey"
|
||||||
coverCandidates.add(
|
coverCandidates.add(
|
||||||
Triple(url, chapter.pagesRead < chapter.pages, chapter.number.toFloatOrNull() ?: 0f)
|
Triple(url, chapter.pagesRead < chapter.pages, chapter.number.toFloatOrNull() ?: 0f),
|
||||||
)
|
)
|
||||||
chapterMap[url] = chapter
|
chapterMap[url] = chapter
|
||||||
}
|
}
|
||||||
@@ -1567,16 +1567,12 @@ class Kavita(private val suffix: String = "") : ConfigurableSource, UnmeteredSou
|
|||||||
throw IOException(helper.intl["error_invalid_reading_list_item"])
|
throw IOException(helper.intl["error_invalid_reading_list_item"])
|
||||||
}
|
}
|
||||||
|
|
||||||
val pages = mutableListOf<Page>()
|
(0 until chapterDetails.pages).map { i ->
|
||||||
for (i in 0 until chapterDetails.pages) {
|
|
||||||
pages.add(
|
|
||||||
Page(
|
Page(
|
||||||
index = i,
|
index = i,
|
||||||
imageUrl = "$apiUrl/Reader/image?chapterId=${chapterDetails.id}&page=$i&extractPdf=true&apiKey=$apiKey",
|
imageUrl = "$apiUrl/Reader/image?chapterId=${chapterDetails.id}&page=$i&extractPdf=true&apiKey=$apiKey",
|
||||||
),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
pages.toList()
|
|
||||||
}.onErrorResumeNext { error ->
|
}.onErrorResumeNext { error ->
|
||||||
Log.e(LOG_TAG, "Error fetching reading list chapter pages", error)
|
Log.e(LOG_TAG, "Error fetching reading list chapter pages", error)
|
||||||
Observable.error(error)
|
Observable.error(error)
|
||||||
@@ -1596,30 +1592,36 @@ class Kavita(private val suffix: String = "") : ConfigurableSource, UnmeteredSou
|
|||||||
val matchingChapter = volume.chapters.firstOrNull() // or match a chapterId if available
|
val matchingChapter = volume.chapters.firstOrNull() // or match a chapterId if available
|
||||||
?: throw IOException(helper.intl["error_no_chapters_found"])
|
?: throw IOException(helper.intl["error_no_chapters_found"])
|
||||||
|
|
||||||
val pages = (0 until matchingChapter.pages).map { i ->
|
val initialPages = (0 until matchingChapter.pages).map { i ->
|
||||||
Page(
|
Page(
|
||||||
index = i,
|
index = i,
|
||||||
imageUrl = "$apiUrl/Reader/image?chapterId=${matchingChapter.id}&page=$i&extractPdf=true&apiKey=$apiKey",
|
imageUrl = "$apiUrl/Reader/image?chapterId=${matchingChapter.id}&page=$i&extractPdf=true&apiKey=$apiKey",
|
||||||
)
|
)
|
||||||
}.toMutableList()
|
}
|
||||||
|
|
||||||
var pageOffset = matchingChapter.pages
|
val remainingPages = volume.chapters
|
||||||
|
.sortedBy { it.number.toFloatOrNull() ?: 0f }
|
||||||
volume.chapters.sortedBy { it.number.toFloatOrNull() ?: 0f }.forEach { chapterDto ->
|
.runningFold(initialPages.size) { acc, chapter -> acc + chapter.pages }
|
||||||
val chapterPages = (0 until chapterDto.pages).map { i ->
|
.drop(1)
|
||||||
|
.zip(volume.chapters.sortedBy { it.number.toFloatOrNull() ?: 0f })
|
||||||
|
.flatMap { (offset, chapter) ->
|
||||||
|
(0 until chapter.pages).map { i ->
|
||||||
Page(
|
Page(
|
||||||
index = pageOffset + i,
|
index = offset - chapter.pages + i,
|
||||||
imageUrl = "$apiUrl/Reader/image?chapterId=${chapterDto.id}&page=$i&extractPdf=true&apiKey=$apiKey",
|
imageUrl = "$apiUrl/Reader/image?chapterId=${chapter.id}&page=$i&extractPdf=true&apiKey=$apiKey",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
pages.addAll(chapterPages)
|
|
||||||
pageOffset += chapterDto.pages
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pages.toList()
|
(initialPages + remainingPages).toList()
|
||||||
} else {
|
} else {
|
||||||
// Original chapter handling
|
// Original chapter handling
|
||||||
val chapterId = chapter.url.substringAfter("/Chapter/").substringBefore("_")
|
val chapterId = when {
|
||||||
|
chapter.url.startsWith("chapter_") -> chapter.url.substringAfter("chapter_").substringBefore("_")
|
||||||
|
chapter.url.contains("/Chapter/") -> chapter.url.substringAfter("/Chapter/").substringBefore("_")
|
||||||
|
else -> throw IOException("Invalid chapter URL format")
|
||||||
|
}
|
||||||
|
|
||||||
val chapterRequest = GET("$apiUrl/Chapter?chapterId=$chapterId", headersBuilder().build())
|
val chapterRequest = GET("$apiUrl/Chapter?chapterId=$chapterId", headersBuilder().build())
|
||||||
val response = client.newCall(chapterRequest).execute()
|
val response = client.newCall(chapterRequest).execute()
|
||||||
|
|
||||||
@@ -1633,25 +1635,23 @@ class Kavita(private val suffix: String = "") : ConfigurableSource, UnmeteredSou
|
|||||||
throw IOException("${helper.intl["error_failed_parse_chapter"]}: ${e.message}")
|
throw IOException("${helper.intl["error_failed_parse_chapter"]}: ${e.message}")
|
||||||
}
|
}
|
||||||
|
|
||||||
val pages = (0 until chapterDetails.pages).map { i ->
|
(0 until chapterDetails.pages).map { i ->
|
||||||
Page(
|
Page(
|
||||||
index = i,
|
index = i,
|
||||||
imageUrl = "$apiUrl/Reader/image?chapterId=$chapterId&page=$i&extractPdf=true&apiKey=$apiKey",
|
imageUrl = "$apiUrl/Reader/image?chapterId=$chapterId&page=$i&extractPdf=true&apiKey=$apiKey",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
pages.toList()
|
|
||||||
}
|
}
|
||||||
}.onErrorResumeNext { error ->
|
}.onErrorResumeNext { error ->
|
||||||
// Fallback to using the scanlator field if we can't get chapter details
|
// Fallback to using the scanlator field if we can't get chapter details
|
||||||
Log.e(LOG_TAG, "Error fetching chapter details, using fallback", error)
|
Log.e(LOG_TAG, "Error fetching chapter details, using fallback", error)
|
||||||
val fallbackPageCount = chapter.scanlator?.replace(" pages", "")?.toIntOrNull() ?: 1
|
val fallbackPageCount = chapter.scanlator?.replace(" pages", "")?.toIntOrNull() ?: 1
|
||||||
val pages = (0 until fallbackPageCount).map { i ->
|
(0 until fallbackPageCount).map { i ->
|
||||||
Page(
|
Page(
|
||||||
index = i,
|
index = i,
|
||||||
imageUrl = "$apiUrl/Reader/image?chapterId=${chapter.url.substringBefore("_")}&page=$i&extractPdf=true&apiKey=$apiKey",
|
imageUrl = "$apiUrl/Reader/image?chapterId=${chapter.url.substringBefore("_")}&page=$i&extractPdf=true&apiKey=$apiKey",
|
||||||
)
|
)
|
||||||
}
|
}.let { Observable.just(it) }
|
||||||
Observable.just(pages.toList())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -163,39 +163,59 @@ class KavitaHelper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @todo Keeping this in case we're switching the logic here this after the Mihon PR
|
||||||
// Handle decimal chapter numbers properly
|
// Handle decimal chapter numbers properly
|
||||||
chapter_number = when {
|
// chapter_number = when {
|
||||||
type == ChapterType.SingleFileVolume && singleFileVolumeNumber != null ->
|
// type == ChapterType.SingleFileVolume && singleFileVolumeNumber != null ->
|
||||||
singleFileVolumeNumber.toFloat()
|
// singleFileVolumeNumber.toFloat()
|
||||||
|
//
|
||||||
|
// type == ChapterType.SingleFileVolume -> {
|
||||||
|
// // For standalone volumes, use positive numbers
|
||||||
|
// volume.minNumber.toFloat()
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // For regular chapters
|
||||||
|
// type != ChapterType.SingleFileVolume && type != ChapterType.Special -> {
|
||||||
|
// // Handle decimal chapter numbers
|
||||||
|
// if (chapter.minNumber % 1 != 0.0) {
|
||||||
|
// chapter.minNumber.toFloat()
|
||||||
|
// } else {
|
||||||
|
// chapter.minNumber.toInt().toFloat()
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // For volumes/specials in mixed content, place them below chapter 0
|
||||||
|
// else -> {
|
||||||
|
// val volumeNum = try {
|
||||||
|
// if (volume.minNumber % 1 != 0.0) {
|
||||||
|
// volume.minNumber.toFloat()
|
||||||
|
// } else {
|
||||||
|
// volume.minNumber.toInt().toFloat()
|
||||||
|
// }
|
||||||
|
// } catch (e: NumberFormatException) {
|
||||||
|
// 0f
|
||||||
|
// }
|
||||||
|
// -volumeNum - KavitaConstants.VOLUME_NUMBER_OFFSET
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// url = when {
|
||||||
|
// type == ChapterType.SingleFileVolume && singleFileVolumeNumber != null ->
|
||||||
|
// "volume_${volume.id}"
|
||||||
|
// else -> "chapter_${chapter.id}"
|
||||||
|
// }
|
||||||
|
|
||||||
type == ChapterType.SingleFileVolume -> {
|
// Handle decimal chapter numbers properly
|
||||||
// For standalone volumes, use positive numbers
|
chapter_number = if (type == ChapterType.SingleFileVolume) {
|
||||||
volume.minNumber.toFloat()
|
|
||||||
}
|
|
||||||
|
|
||||||
// For regular chapters
|
|
||||||
type != ChapterType.SingleFileVolume && type != ChapterType.Special -> {
|
|
||||||
// Handle decimal chapter numbers
|
|
||||||
if (chapter.minNumber % 1 != 0.0) {
|
|
||||||
chapter.minNumber.toFloat()
|
|
||||||
} else {
|
|
||||||
chapter.minNumber.toInt().toFloat()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// For volumes/specials in mixed content, place them below chapter 0
|
|
||||||
else -> {
|
|
||||||
val volumeNum = try {
|
|
||||||
if (volume.minNumber % 1 != 0.0) {
|
if (volume.minNumber % 1 != 0.0) {
|
||||||
volume.minNumber.toFloat()
|
volume.minNumber.toFloat()
|
||||||
} else {
|
} else {
|
||||||
volume.minNumber.toInt().toFloat()
|
volume.minNumber.toInt().toFloat()
|
||||||
}
|
}
|
||||||
} catch (e: NumberFormatException) {
|
} else if (chapter.minNumber % 1 != 0.0) {
|
||||||
0f
|
chapter.minNumber.toFloat()
|
||||||
}
|
} else {
|
||||||
-volumeNum - KavitaConstants.VOLUME_NUMBER_OFFSET
|
chapter.minNumber.toInt().toFloat()
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
url = when {
|
url = when {
|
||||||
@@ -248,11 +268,14 @@ class KavitaHelper {
|
|||||||
// Helper function to remove .0 from whole numbers while preserving actual decimals
|
// Helper function to remove .0 from whole numbers while preserving actual decimals
|
||||||
@SuppressLint("DefaultLocale")
|
@SuppressLint("DefaultLocale")
|
||||||
private fun removeTrailingZero(number: Double): String {
|
private fun removeTrailingZero(number: Double): String {
|
||||||
return if (number % 1 == 0.0) {
|
return if (number.isInfinite() || number.isNaN()) {
|
||||||
number.toInt().toString()
|
number.toString()
|
||||||
} else {
|
} else {
|
||||||
// Use String.format to avoid scientific notation for very small decimals
|
val formatted = String.format("%.10f", number)
|
||||||
String.format("%.10f", number).replace(",", ".").trimEnd('0').trimEnd('.')
|
.replace(",", ".")
|
||||||
|
.trimEnd('0')
|
||||||
|
.trimEnd('.')
|
||||||
|
formatted.ifEmpty { "0" }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user