Add Kavita EPUB reader handoff
This commit is contained in:
@@ -2,7 +2,7 @@ ext {
|
|||||||
kmkVersionCode = 1
|
kmkVersionCode = 1
|
||||||
extName = 'Kavita'
|
extName = 'Kavita'
|
||||||
extClass = '.KavitaFactory'
|
extClass = '.KavitaFactory'
|
||||||
extVersionCode = 32
|
extVersionCode = 33
|
||||||
isNsfw = false
|
isNsfw = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ import uy.kohesive.injekt.Injekt
|
|||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
|
import java.net.URLEncoder
|
||||||
import java.security.MessageDigest
|
import java.security.MessageDigest
|
||||||
import java.util.Calendar
|
import java.util.Calendar
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
@@ -1774,6 +1775,9 @@ class Kavita(private val suffix: String = "") : ConfigurableSource, UnmeteredSou
|
|||||||
params += "pages=$pageCount"
|
params += "pages=$pageCount"
|
||||||
}
|
}
|
||||||
params += "extractPdf=${shouldExtractPdf(chapter, forceExtractPdf)}"
|
params += "extractPdf=${shouldExtractPdf(chapter, forceExtractPdf)}"
|
||||||
|
if (isEpubChapter(chapter)) {
|
||||||
|
params += "epub=true"
|
||||||
|
}
|
||||||
if (chapter.fileCount > 1) {
|
if (chapter.fileCount > 1) {
|
||||||
params += "split=${chapter.fileCount}"
|
params += "split=${chapter.fileCount}"
|
||||||
}
|
}
|
||||||
@@ -1797,6 +1801,16 @@ class Kavita(private val suffix: String = "") : ConfigurableSource, UnmeteredSou
|
|||||||
file.format == MangaFormat.Pdf.format || file.extension.equals("pdf", ignoreCase = true)
|
file.format == MangaFormat.Pdf.format || file.extension.equals("pdf", ignoreCase = true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun isEpubChapter(chapter: ChapterDto): Boolean =
|
||||||
|
chapter.files.orEmpty().any { file ->
|
||||||
|
file.format == MangaFormat.Epub.format || file.extension.equals("epub", ignoreCase = true)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isEpubFromChapterUrl(chapter: SChapter): Boolean =
|
||||||
|
chapter.url.substringAfter("epub=", "")
|
||||||
|
.substringBefore("&")
|
||||||
|
.equals("true", ignoreCase = true)
|
||||||
|
|
||||||
private fun isPdfSeries(seriesId: Int?): Boolean =
|
private fun isPdfSeries(seriesId: Int?): Boolean =
|
||||||
seriesId?.let { id ->
|
seriesId?.let { id ->
|
||||||
series.find { it.id == id }?.format == MangaFormat.Pdf.format ||
|
series.find { it.id == id }?.format == MangaFormat.Pdf.format ||
|
||||||
@@ -1830,6 +1844,22 @@ class Kavita(private val suffix: String = "") : ConfigurableSource, UnmeteredSou
|
|||||||
return Page(index = index, url = imageUrl, imageUrl = imageUrl)
|
return Page(index = index, url = imageUrl, imageUrl = imageUrl)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun readerEpubPage(chapterId: Any, pageCount: Int, title: String? = null): Page {
|
||||||
|
val params = mutableListOf(
|
||||||
|
"apiUrl=${apiUrl.urlEncode()}",
|
||||||
|
"apiKey=${apiKey.urlEncode()}",
|
||||||
|
"chapterId=${chapterId.toString().urlEncode()}",
|
||||||
|
"pages=${pageCount.coerceAtLeast(1)}",
|
||||||
|
)
|
||||||
|
if (!title.isNullOrBlank()) {
|
||||||
|
params += "title=${title.urlEncode()}"
|
||||||
|
}
|
||||||
|
val url = "kavita-epub://reader?${params.joinToString("&")}"
|
||||||
|
return Page(index = 0, url = url, imageUrl = null)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun String.urlEncode(): String = URLEncoder.encode(this, Charsets.UTF_8.name())
|
||||||
|
|
||||||
override suspend fun getPageList(chapter: SChapter): List<Page> = withContext(Dispatchers.IO) {
|
override suspend fun getPageList(chapter: SChapter): List<Page> = withContext(Dispatchers.IO) {
|
||||||
// Check if this is a reading list item (has readingListId in URL)
|
// Check if this is a reading list item (has readingListId in URL)
|
||||||
if (chapter.url.contains("readingListId=")) {
|
if (chapter.url.contains("readingListId=")) {
|
||||||
@@ -1877,6 +1907,9 @@ class Kavita(private val suffix: String = "") : ConfigurableSource, UnmeteredSou
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Generate pages with consistent URL format
|
// Generate pages with consistent URL format
|
||||||
|
if (isEpubChapter(chapterDetails)) {
|
||||||
|
return@withContext listOf(readerEpubPage(chapterDetails.id, chapterDetails.pages, chapterDetails.titleName ?: chapterDetails.title))
|
||||||
|
}
|
||||||
val extractPdf = shouldExtractPdf(chapterDetails, isPdfSeries(seriesId))
|
val extractPdf = shouldExtractPdf(chapterDetails, isPdfSeries(seriesId))
|
||||||
return@withContext (0 until chapterDetails.pages).map { i -> readerPage(i, chapterDetails.id, extractPdf = extractPdf) }
|
return@withContext (0 until chapterDetails.pages).map { i -> readerPage(i, chapterDetails.id, extractPdf = extractPdf) }
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
@@ -1913,6 +1946,9 @@ class Kavita(private val suffix: String = "") : ConfigurableSource, UnmeteredSou
|
|||||||
.runningFold(0) { acc, chapter -> acc + chapter.pages }
|
.runningFold(0) { acc, chapter -> acc + chapter.pages }
|
||||||
.zip(volume.chapters.sortedBy { it.number.toFloatOrNull() ?: 0f })
|
.zip(volume.chapters.sortedBy { it.number.toFloatOrNull() ?: 0f })
|
||||||
.flatMap { (startIndex, chapter) ->
|
.flatMap { (startIndex, chapter) ->
|
||||||
|
if (isEpubChapter(chapter)) {
|
||||||
|
return@withContext listOf(readerEpubPage(chapter.id, chapter.pages, chapter.titleName ?: chapter.title))
|
||||||
|
}
|
||||||
val extractPdf = shouldExtractPdf(chapter, isPdfSeries(volume.seriesId))
|
val extractPdf = shouldExtractPdf(chapter, isPdfSeries(volume.seriesId))
|
||||||
(0 until chapter.pages).map { i ->
|
(0 until chapter.pages).map { i ->
|
||||||
readerPage(startIndex + i, chapter.id, i, extractPdf)
|
readerPage(startIndex + i, chapter.id, i, extractPdf)
|
||||||
@@ -1930,6 +1966,9 @@ class Kavita(private val suffix: String = "") : ConfigurableSource, UnmeteredSou
|
|||||||
|
|
||||||
val extractPdf = extractPdfFromChapterUrl(chapter)
|
val extractPdf = extractPdfFromChapterUrl(chapter)
|
||||||
pageCountFromChapterUrl(chapter)?.let { pageCount ->
|
pageCountFromChapterUrl(chapter)?.let { pageCount ->
|
||||||
|
if (isEpubFromChapterUrl(chapter)) {
|
||||||
|
return@withContext listOf(readerEpubPage(chapterId, pageCount, chapter.name))
|
||||||
|
}
|
||||||
return@withContext (0 until pageCount).map { i -> readerPage(i, chapterId, extractPdf = extractPdf) }
|
return@withContext (0 until pageCount).map { i -> readerPage(i, chapterId, extractPdf = extractPdf) }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1952,6 +1991,9 @@ class Kavita(private val suffix: String = "") : ConfigurableSource, UnmeteredSou
|
|||||||
}
|
}
|
||||||
|
|
||||||
val fetchedExtractPdf = extractPdf || shouldExtractPdf(chapterDetails)
|
val fetchedExtractPdf = extractPdf || shouldExtractPdf(chapterDetails)
|
||||||
|
if (isEpubChapter(chapterDetails)) {
|
||||||
|
return@withContext listOf(readerEpubPage(chapterId, chapterDetails.pages, chapterDetails.titleName ?: chapterDetails.title))
|
||||||
|
}
|
||||||
return@withContext (0 until chapterDetails.pages).map { i -> readerPage(i, chapterId, extractPdf = fetchedExtractPdf) }
|
return@withContext (0 until chapterDetails.pages).map { i -> readerPage(i, chapterId, extractPdf = fetchedExtractPdf) }
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
|
|||||||
Reference in New Issue
Block a user