From 72c0ecc64fceac9aa392ff4de9b8e215b0c9bd5a Mon Sep 17 00:00:00 2001 From: Uranus Date: Sun, 23 Mar 2025 23:03:55 +0800 Subject: [PATCH] Komga: add search for books (#8102) * Komga: add search for books * clean up unused code * add String.isFromBook() method * fix lint error --- src/all/komga/build.gradle | 2 +- .../tachiyomi/extension/all/komga/Komga.kt | 38 +++++++++++++++++-- .../extension/all/komga/KomgaFilters.kt | 3 +- .../tachiyomi/extension/all/komga/dto/Dto.kt | 15 +++++++- 4 files changed, 52 insertions(+), 6 deletions(-) diff --git a/src/all/komga/build.gradle b/src/all/komga/build.gradle index 78082712d..fd51392e6 100644 --- a/src/all/komga/build.gradle +++ b/src/all/komga/build.gradle @@ -1,7 +1,7 @@ ext { extName = 'Komga' extClass = '.KomgaFactory' - extVersionCode = 60 + extVersionCode = 61 } apply from: "$rootDir/common.gradle" diff --git a/src/all/komga/src/eu/kanade/tachiyomi/extension/all/komga/Komga.kt b/src/all/komga/src/eu/kanade/tachiyomi/extension/all/komga/Komga.kt index 13d537679..3db6c9b1c 100644 --- a/src/all/komga/src/eu/kanade/tachiyomi/extension/all/komga/Komga.kt +++ b/src/all/komga/src/eu/kanade/tachiyomi/extension/all/komga/Komga.kt @@ -130,6 +130,7 @@ open class Komga(private val suffix: String = "") : ConfigurableSource, Unmetere val type = when { collectionId != null -> "collections/$collectionId/series" filters.find { it is TypeSelect }?.state == 1 -> "readlists" + filters.find { it is TypeSelect }?.state == 2 -> "books" else -> "series" } @@ -171,6 +172,8 @@ open class Komga(private val suffix: String = "") : ConfigurableSource, Unmetere private fun processSeriesPage(response: Response, baseUrl: String): MangasPage { val data = if (response.isFromReadList()) { response.parseAs>() + } else if (response.isFromBook()) { + response.parseAs>() } else { response.parseAs>() } @@ -185,6 +188,8 @@ open class Komga(private val suffix: String = "") : ConfigurableSource, Unmetere override fun mangaDetailsParse(response: Response): SManga { return if (response.isFromReadList()) { response.parseAs().toSManga(baseUrl) + } else if (response.isFromBook()) { + response.parseAs().toSManga(baseUrl) } else { response.parseAs().toSManga(baseUrl) } @@ -195,10 +200,30 @@ open class Komga(private val suffix: String = "") : ConfigurableSource, Unmetere override fun getChapterUrl(chapter: SChapter) = chapter.url.replace("/api/v1/books", "/book") - override fun chapterListRequest(manga: SManga): Request = - GET("${manga.url}/books?unpaged=true&media_status=READY&deleted=false", headers) + override fun chapterListRequest(manga: SManga): Request = when { + manga.url.isFromBook() -> GET("${manga.url}?unpaged=true&media_status=READY&deleted=false", headers) + else -> GET("${manga.url}/books?unpaged=true&media_status=READY&deleted=false", headers) + } override fun chapterListParse(response: Response): List { + if (response.isFromBook()) { + val book = response.parseAs() + return listOf( + SChapter.create().apply { + chapter_number = 1F + url = "$baseUrl/api/v1/books/${book.id}" + name = book.getChapterName(chapterNameTemplate, isFromReadList = true) + scanlator = book.metadata.authors + .filter { it.role == "translator" } + .joinToString { it.name } + date_upload = when { + book.metadata.releaseDate != null -> parseDate(book.metadata.releaseDate) + book.created != null -> parseDateTime(book.created) + else -> parseDateTime(book.fileLastModified) + } + }, + ) + } val page = response.parseAs>().content val isFromReadList = response.isFromReadList() val chapterNameTemplate = chapterNameTemplate @@ -464,7 +489,13 @@ open class Komga(private val suffix: String = "") : ConfigurableSource, Unmetere } } - fun Response.isFromReadList() = request.url.toString().contains("/api/v1/readlists") + fun String.isFromReadList() = contains("/api/v1/readlists") + + fun String.isFromBook() = contains("/api/v1/books") + + fun Response.isFromReadList() = request.url.toString().isFromReadList() + + fun Response.isFromBook() = request.url.toString().isFromBook() private inline fun Response.parseAs(): T = json.decodeFromString(body.string()) @@ -477,6 +508,7 @@ open class Komga(private val suffix: String = "") : ConfigurableSource, Unmetere internal const val TYPE_SERIES = "Series" internal const val TYPE_READLISTS = "Read lists" + internal const val TYPE_BOOKS = "Books" } } diff --git a/src/all/komga/src/eu/kanade/tachiyomi/extension/all/komga/KomgaFilters.kt b/src/all/komga/src/eu/kanade/tachiyomi/extension/all/komga/KomgaFilters.kt index 4692097b4..ace2e13ab 100644 --- a/src/all/komga/src/eu/kanade/tachiyomi/extension/all/komga/KomgaFilters.kt +++ b/src/all/komga/src/eu/kanade/tachiyomi/extension/all/komga/KomgaFilters.kt @@ -14,13 +14,14 @@ internal class TypeSelect : Filter.Select( arrayOf( Komga.TYPE_SERIES, Komga.TYPE_READLISTS, + Komga.TYPE_BOOKS, ), ) internal class SeriesSort(selection: Selection? = null) : Filter.Sort( "Sort", arrayOf("Relevance", "Alphabetically", "Date added", "Date updated", "Random"), - selection ?: Selection(0, false), + selection ?: Selection(0, true), ) internal class UnreadFilter : Filter.CheckBox("Unread", false), UriFilter { diff --git a/src/all/komga/src/eu/kanade/tachiyomi/extension/all/komga/dto/Dto.kt b/src/all/komga/src/eu/kanade/tachiyomi/extension/all/komga/dto/Dto.kt index 5c59d9278..7bb63cd59 100644 --- a/src/all/komga/src/eu/kanade/tachiyomi/extension/all/komga/dto/Dto.kt +++ b/src/all/komga/src/eu/kanade/tachiyomi/extension/all/komga/dto/Dto.kt @@ -97,7 +97,7 @@ class BookDto( val size: String, val media: MediaDto, val metadata: BookMetadataDto, -) { +) : ConvertibleToSManga { fun getChapterName(template: String, isFromReadList: Boolean): String { val values = hashMapOf( "title" to metadata.title, @@ -119,6 +119,17 @@ class BookDto( append(sub.replace(template)) } } + + override fun toSManga(baseUrl: String) = SManga.create().apply { + title = metadata.title + url = "$baseUrl/api/v1/books/$id" + thumbnail_url = "$url/thumbnail" + status = SManga.UNKNOWN + genre = metadata.tags.distinct().joinToString(", ") + description = metadata.summary + author = metadata.authors.joinToString { it.name } + artist = author + } } @Serializable @@ -151,6 +162,8 @@ class BookMetadataDto( val releaseDateLock: Boolean, val authors: List, val authorsLock: Boolean, + val tags: Set, + val tagsLock: Boolean, ) @Serializable