un fucky my wucky
CI / Prepare job (push) Successful in 3s Details
CI / Build multisrc modules (push) Successful in 11m4s Details
CI / Build individual modules (push) Successful in 1m44s Details
CI / Publish repo (push) Successful in 56s Details

This commit is contained in:
Draff 2024-01-30 22:17:44 +00:00
parent 56f64ce41c
commit 36f4827539
16 changed files with 1 additions and 920 deletions

1
.gitignore vendored
View File

@ -1,5 +1,4 @@
.gradle
.secrets
/local.properties
/.idea/workspace.xml
.DS_Store

View File

@ -6,7 +6,7 @@
# Usage
https://github.com/keiyoushi/extensions/blob/main/README.md
[Getting started](https://keiyoushi.github.io/docs/guides/getting-started#adding-the-extension-repo)
# Contributing

View File

@ -1,383 +0,0 @@
## 1.4.47
Minimum Komga version required: `0.151.0`
### Feat
* add support for AVIF and HEIF image types
## 1.4.46
Minimum Komga version required: `0.151.0`
### Feat
* Update to extension-lib 1.4
- Clicking on chapter WebView should now open the chapter/book page.
## 1.3.45
Minimum Komga version required: `0.151.0`
### Feat
* Edit source display name
## 1.3.44
Minimum Komga version required: `0.151.0`
### Fix
* Better date/time parsing
## 1.3.43
Minimum Komga version required: `0.151.0`
### Fix
* Requests failing if address preference is saved with a trailing slash
### Features
* Add URL validation in the address preferences
* Use a URL-focused keyboard when available while editing the address preferences
## 1.3.42
Minimum Komga version required: `0.151.0`
### Fix
* default sort broken since Komga 0.155.1
* proper sort criteria for readlists
## 1.3.41
Minimum Komga version required: `0.151.0`
### Features
* Improve how the status is displayed
## 1.3.40
Minimum Komga version required: `0.151.0`
### Features
* Exclude from bulk update warnings
## 1.2.39
Minimum Komga version required: `0.151.0`
### Features
* Prepend series name in front of books within readlists
## 1.2.38
Minimum Komga version required: `0.113.0`
### Features
* Add `README.md`
## 1.2.37
Minimum Komga version required: `0.113.0`
### Features
* In app link to `CHANGELOG.md`
## 1.2.36
Minimum Komga version required: `0.113.0`
### Features
* Don't request conversion for JPEG XL images
## 1.2.35
Minimum Komga version required: `0.113.0`
### Features
* Display the Translators of a book in the scanlator chapter field
## 1.2.34
Minimum Komga version required: `0.113.0`
### Fix
* Loading of filter values could fail in some cases
## 1.2.33
Minimum Komga version required: `0.113.0`
### Fix
* Open in WebView and Share options now open regular browser link instead of showing JSON
* Note that Komga cannot be viewed using System WebView since there is no login prompt
However, opening in a regular browser works.
## 1.2.32
Minimum Komga version required: `0.113.0`
### Fix
* Source language, conventionally set to "en", is now changed to "all"
* Downloaded files, if any, will have to be moved to new location
- `Komga (EN)` to `Komga (ALL)`
- `Komga (3) (EN)` to `Komga (3) (ALL)`
## 1.2.31
Minimum Komga version required: `0.113.0`
### Refactor
* replace Gson with kotlinx.serialization
## 1.2.30
Minimum Komga version required: `0.113.0`
### Features
* display read list summary
* display aggregated tags on series
* search series by book tags
## 1.2.29
Minimum Komga version required: `0.97.0`
### Features
* filter deleted series and books
## 1.2.28
Minimum Komga version required: `0.97.0`
### Fix
* incorrect User Agent
## 1.2.27
Minimum Komga version required: `0.97.0`
### Fix
* filter series by read or in progress
## 1.2.26
Minimum Komga version required: `0.87.4`
### Fix
* show series with only in progress books when searching for unread only
## 1.2.25
Minimum Komga version required: `0.87.4`
### Fix
* sort order for read list books
## 1.2.24
Minimum Komga version required: `0.87.4`
### Fix
* only show series tags in the filter panel
* set URL properly on series and read lists, so restoring from a backup can work properly
## 1.2.23
Minimum Komga version required: `0.75.0`
### Features
* ignore DNS over HTTPS so it can reach IP addresses
## 1.2.22
Minimum Komga version required: `0.75.0`
### Features
* add error logs and better catch exceptions
## 1.2.21
Minimum Komga version required: `0.75.0`
### Features
* browse read lists (from the filter menu)
* filter by collection, respecting the collection's ordering
## 1.2.20
Minimum Komga version required: `0.75.0`
### Features
* filter by authors, grouped by role
## 1.2.19
Minimum Komga version required: `0.68.0`
### Features
* display Series authors
* display Series summary from books if no summary exists for Series
## 1.2.18
Minimum Komga version required: `0.63.2`
### Fix
* use metadata.releaseDate or fileLastModified for chapter date
## 1.2.17
Minimum Komga version required: `0.63.2`
### Fix
* list of collections for filtering could be empty in some conditions
## 1.2.16
Minimum Komga version required: `0.59.0`
### Features
* filter by genres, tags and publishers
## 1.2.15
Minimum Komga version required: `0.56.0`
### Features
* remove the 1000 chapters limit
* display series description and tags (genres + tags)
## 1.2.14
Minimum Komga version required: `0.41.0`
### Features
* change chapter display name to use the display number instead of the sort number
## 1.2.13
Minimum Komga version required: `0.41.0`
### Features
* compatibility for the upcoming version of Komga which have changes in the API (IDs are String instead of Long)
## 1.2.12
Minimum Komga version required: `0.41.0`
### Features
* filter by collection
## 1.2.11
Minimum Komga version required: `0.35.2`
### Features
* Set password preferences inputTypes
## 1.2.10
Minimum Komga version required: `0.35.2`
### Features
* unread only filter (closes gotson/komga#180)
* prefix book titles with number (closes gotson/komga#169)
## 1.2.9
Minimum Komga version required: `0.22.0`
### Features
* use SourceFactory to have multiple Komga servers (3 for the moment)
## 1.2.8
Minimum Komga version required: `0.22.0`
### Features
* use book metadata title for chapter display name
* use book metadata sort number for chapter number
## 1.2.7
### Features
* use series metadata title for display name
* filter on series status
## 1.2.6
### Features
* Add support for AndroidX preferences
## 1.2.5
### Features
* add sort options in filter
## 1.2.4
### Features
* better handling of authentication
## 1.2.3
### Features
* filters by library
## 1.2.2
### Features
* request converted image from server if format is not supported
## 1.2.1
### Features
* first version

View File

@ -1,35 +0,0 @@
# Komga
Table of Content
- [FAQ](#FAQ)
- [Why do I see no manga?](#why-do-i-see-no-manga)
- [Where can I get more information about Komga?](#where-can-i-get-more-information-about-komga)
- [The Komga extension stopped working?](#the-komga-extension-stopped-working)
- [Can I add more than one Komga server or user?](#can-i-add-more-than-one-komga-server-or-user)
- [Can I test the Komga extension before setting up my own server?](#can-i-test-the-komga-extension-before-setting-up-my-own-server)
- [Guides](#Guides)
- [How do I add my Komga server to Tachiyomi?](#how-do-i-add-my-komga-server-to-tachiyomi)
Don't find the question you are look for go check out our general FAQs and Guides over at [Extension FAQ](https://tachiyomi.org/help/faq/#extensions) or [Getting Started](https://tachiyomi.org/help/guides/getting-started/#installation)
## FAQ
### Why do I see no manga?
Komga is a self-hosted comic/manga media server.
### Where can I get more information about Komga?
You can visit the [Komga](https://komga.org/) website for for more information.
### The Komga extension stopped working?
Make sure that your Komga server and extension are on the newest version.
### Can I add more than one Komga server or user?
Yes, currently you can add up to 3 different Komga instances to Tachiyomi.
### Can I test the Komga extension before setting up my own server?
Yes, you can try it out with the DEMO server `https://demo.komga.org`, username `demo@komga.org` and password `komga-demo`.
## Guides
### How do I add my Komga server to Tachiyomi?
Go into the settings of the Komga extension from the Extension tab in Browse and fill in your server address and login details.

View File

@ -1,12 +1,3 @@
<<<<<<< HEAD
ext {
extName = 'Komga'
extClass = '.KomgaFactory'
extVersionCode = 50
}
apply from: "$rootDir/common.gradle"
=======
ext {
extName = 'Komga'
extClass = '.KomgaFactory'
@ -18,4 +9,3 @@ apply from: "$rootDir/common.gradle"
dependencies {
implementation("org.apache.commons:commons-text:1.11.0")
}
>>>>>>> d52b3e572 (Add Komga (#579))

0
src/all/komga/res/mipmap-hdpi/ic_launcher.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 5.9 KiB

After

Width:  |  Height:  |  Size: 5.9 KiB

0
src/all/komga/res/mipmap-mdpi/ic_launcher.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

0
src/all/komga/res/mipmap-xhdpi/ic_launcher.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 8.0 KiB

After

Width:  |  Height:  |  Size: 8.0 KiB

0
src/all/komga/res/mipmap-xxhdpi/ic_launcher.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

0
src/all/komga/res/mipmap-xxxhdpi/ic_launcher.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

View File

@ -9,10 +9,7 @@ import android.util.Log
import android.widget.Button
import android.widget.Toast
import androidx.preference.EditTextPreference
<<<<<<< HEAD
=======
import androidx.preference.ListPreference
>>>>>>> d52b3e572 (Add Komga (#579))
import androidx.preference.PreferenceScreen
import eu.kanade.tachiyomi.AppInfo
import eu.kanade.tachiyomi.extension.all.komga.dto.AuthorDto
@ -24,11 +21,6 @@ import eu.kanade.tachiyomi.extension.all.komga.dto.PageWrapperDto
import eu.kanade.tachiyomi.extension.all.komga.dto.ReadListDto
import eu.kanade.tachiyomi.extension.all.komga.dto.SeriesDto
import eu.kanade.tachiyomi.network.GET
<<<<<<< HEAD
import eu.kanade.tachiyomi.network.asObservable
import eu.kanade.tachiyomi.network.await
=======
>>>>>>> d52b3e572 (Add Komga (#579))
import eu.kanade.tachiyomi.source.ConfigurableSource
import eu.kanade.tachiyomi.source.UnmeteredSource
import eu.kanade.tachiyomi.source.model.Filter
@ -42,20 +34,12 @@ import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json
import okhttp3.Credentials
import okhttp3.Dns
<<<<<<< HEAD
import okhttp3.Headers
=======
import okhttp3.HttpUrl.Companion.toHttpUrl
>>>>>>> d52b3e572 (Add Komga (#579))
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Response
<<<<<<< HEAD
import rx.Observable
=======
import org.apache.commons.text.StringSubstitutor
>>>>>>> d52b3e572 (Add Komga (#579))
import rx.Single
import rx.schedulers.Schedulers
import uy.kohesive.injekt.Injekt
@ -65,10 +49,6 @@ import java.security.MessageDigest
import java.util.Locale
open class Komga(private val suffix: String = "") : ConfigurableSource, UnmeteredSource, HttpSource() {
<<<<<<< HEAD
override fun popularMangaRequest(page: Int): Request =
GET("$baseUrl/api/v1/series?page=${page - 1}&deleted=false&sort=metadata.titleSort,asc", headers)
=======
override val name by lazy { "Komga${displayName.ifBlank { suffix }.let { if (it.isNotBlank()) " ($it)" else "" }}" }
@ -118,31 +98,23 @@ open class Komga(private val suffix: String = "") : ConfigurableSource, Unmetere
"",
FilterList(SeriesSort()),
)
>>>>>>> d52b3e572 (Add Komga (#579))
override fun popularMangaParse(response: Response): MangasPage =
processSeriesPage(response)
override fun latestUpdatesRequest(page: Int): Request =
<<<<<<< HEAD
GET("$baseUrl/api/v1/series/latest?page=${page - 1}&deleted=false", headers)
=======
searchMangaRequest(
page,
"",
FilterList(SeriesSort(Filter.Sort.Selection(2, false))),
)
>>>>>>> d52b3e572 (Add Komga (#579))
override fun latestUpdatesParse(response: Response): MangasPage =
processSeriesPage(response)
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
<<<<<<< HEAD
=======
runCatching { fetchFilterOptions() }
>>>>>>> d52b3e572 (Add Komga (#579))
val collectionId = (filters.find { it is CollectionSelect } as? CollectionSelect)?.let {
it.values[it.state].id
}
@ -153,11 +125,7 @@ open class Komga(private val suffix: String = "") : ConfigurableSource, Unmetere
else -> "series"
}
<<<<<<< HEAD
val url = "$baseUrl/api/v1/$type?search=$query&page=${page - 1}&deleted=false".toHttpUrlOrNull()!!.newBuilder()
=======
val url = "$baseUrl/api/v1/$type?search=$query&page=${page - 1}&deleted=false".toHttpUrl().newBuilder()
>>>>>>> d52b3e572 (Add Komga (#579))
filters.forEach { filter ->
when (filter) {
@ -178,65 +146,29 @@ open class Komga(private val suffix: String = "") : ConfigurableSource, Unmetere
}
}
is LibraryGroup -> {
<<<<<<< HEAD
val libraryToInclude = mutableListOf<String>()
filter.state.forEach { content ->
if (content.state) {
libraryToInclude.add(content.id)
}
}
=======
val libraryToInclude = filter.state.filter { it.state }.map { it.id }
>>>>>>> d52b3e572 (Add Komga (#579))
if (libraryToInclude.isNotEmpty()) {
url.addQueryParameter("library_id", libraryToInclude.joinToString(","))
}
}
is StatusGroup -> {
<<<<<<< HEAD
val statusToInclude = mutableListOf<String>()
filter.state.forEach { content ->
if (content.state) {
statusToInclude.add(content.name.uppercase(Locale.ROOT))
}
}
=======
val statusToInclude = filter.state.filter { it.state }.map { it.name.uppercase(Locale.ROOT) }
>>>>>>> d52b3e572 (Add Komga (#579))
if (statusToInclude.isNotEmpty()) {
url.addQueryParameter("status", statusToInclude.joinToString(","))
}
}
is GenreGroup -> {
<<<<<<< HEAD
val genreToInclude = mutableListOf<String>()
filter.state.forEach { content ->
if (content.state) {
genreToInclude.add(content.name)
}
}
=======
val genreToInclude = filter.state.filter { it.state }.map { it.name }
>>>>>>> d52b3e572 (Add Komga (#579))
if (genreToInclude.isNotEmpty()) {
url.addQueryParameter("genre", genreToInclude.joinToString(","))
}
}
is TagGroup -> {
<<<<<<< HEAD
val tagToInclude = mutableListOf<String>()
filter.state.forEach { content ->
if (content.state) {
tagToInclude.add(content.name)
}
}
=======
val tagToInclude = filter.state.filter { it.state }.map { it.name }
>>>>>>> d52b3e572 (Add Komga (#579))
if (tagToInclude.isNotEmpty()) {
url.addQueryParameter("tag", tagToInclude.joinToString(","))
}
@ -253,34 +185,13 @@ open class Komga(private val suffix: String = "") : ConfigurableSource, Unmetere
}
}
is AuthorGroup -> {
<<<<<<< HEAD
val authorToInclude = mutableListOf<AuthorDto>()
filter.state.forEach { content ->
if (content.state) {
authorToInclude.add(content.author)
}
}
=======
val authorToInclude = filter.state.filter { it.state }.map { it.author }
>>>>>>> d52b3e572 (Add Komga (#579))
authorToInclude.forEach {
url.addQueryParameter("author", "${it.name},${it.role}")
}
}
is Filter.Sort -> {
<<<<<<< HEAD
var sortCriteria = when (filter.state?.index) {
0 -> if (type == "series") "metadata.titleSort" else "name"
1 -> "createdDate"
2 -> "lastModifiedDate"
else -> ""
}
if (sortCriteria.isNotEmpty()) {
sortCriteria += "," + if (filter.state?.ascending!!) "asc" else "desc"
url.addQueryParameter("sort", sortCriteria)
}
=======
val state = filter.state ?: return@forEach
val sortCriteria = when (state.index) {
@ -291,47 +202,17 @@ open class Komga(private val suffix: String = "") : ConfigurableSource, Unmetere
} + "," + if (state.ascending) "asc" else "desc"
url.addQueryParameter("sort", sortCriteria)
>>>>>>> d52b3e572 (Add Komga (#579))
}
else -> {}
}
}
<<<<<<< HEAD
return GET(url.toString(), headers)
=======
return GET(url.build(), headers)
>>>>>>> d52b3e572 (Add Komga (#579))
}
override fun searchMangaParse(response: Response): MangasPage =
processSeriesPage(response)
<<<<<<< HEAD
override fun fetchMangaDetails(manga: SManga): Observable<SManga> {
return client.newCall(GET(manga.url, headers))
.asObservable()
.map { response ->
mangaDetailsParse(response).apply { initialized = true }
}
}
override fun mangaDetailsRequest(manga: SManga): Request =
GET(manga.url.replaceFirst("api/v1/", "", ignoreCase = true), headers)
override fun mangaDetailsParse(response: Response): SManga {
return response.body.use { body ->
if (response.fromReadList()) {
val readList = json.decodeFromString<ReadListDto>(body.string())
readList.toSManga()
} else {
val series = json.decodeFromString<SeriesDto>(body.string())
series.toSManga()
}
}
}
=======
override fun getMangaUrl(manga: SManga) = manga.url.replace("/api/v1", "")
override fun mangaDetailsRequest(manga: SManga) = GET(manga.url)
@ -350,31 +231,19 @@ open class Komga(private val suffix: String = "") : ConfigurableSource, Unmetere
override fun getChapterUrl(chapter: SChapter) = chapter.url.replace("/api/v1/books", "/book")
>>>>>>> d52b3e572 (Add Komga (#579))
override fun chapterListRequest(manga: SManga): Request =
GET("${manga.url}/books?unpaged=true&media_status=READY&deleted=false", headers)
override fun chapterListParse(response: Response): List<SChapter> {
<<<<<<< HEAD
val responseBody = response.body
val page = responseBody.use { json.decodeFromString<PageWrapperDto<BookDto>>(it.string()).content }
=======
val page = response.parseAs<PageWrapperDto<BookDto>>().content
>>>>>>> d52b3e572 (Add Komga (#579))
val r = page.mapIndexed { index, book ->
SChapter.create().apply {
chapter_number = if (!response.fromReadList()) book.metadata.numberSort else index + 1F
<<<<<<< HEAD
name = "${if (!response.fromReadList()) "${book.metadata.number} - " else "${book.seriesTitle} ${book.metadata.number}: "}${book.metadata.title} (${book.size})"
=======
>>>>>>> d52b3e572 (Add Komga (#579))
url = "$baseUrl/api/v1/books/${book.id}"
scanlator = book.metadata.authors.groupBy({ it.role }, { it.name })["translator"]?.joinToString()
date_upload = book.metadata.releaseDate?.let { parseDate(it) }
?: parseDateTime(book.fileLastModified)
<<<<<<< HEAD
=======
val values = hashMapOf(
"title" to book.metadata.title,
@ -388,7 +257,6 @@ open class Komga(private val suffix: String = "") : ConfigurableSource, Unmetere
val sub = StringSubstitutor(values, "{", "}")
name = (if (!response.fromReadList()) "" else "${book.seriesTitle} ") + sub.replace(chapterNameTemplate)
>>>>>>> d52b3e572 (Add Komga (#579))
}
}
return r.sortedByDescending { it.chapter_number }
@ -398,13 +266,8 @@ open class Komga(private val suffix: String = "") : ConfigurableSource, Unmetere
GET("${chapter.url}/pages")
override fun pageListParse(response: Response): List<Page> {
<<<<<<< HEAD
val responseBody = response.body
val pages = responseBody.use { json.decodeFromString<List<PageDto>>(it.string()) }
=======
val pages = response.parseAs<List<PageDto>>()
>>>>>>> d52b3e572 (Add Komga (#579))
return pages.map {
val url = "${response.request.url}/${it.number}" +
if (!supportedImageTypes.contains(it.mediaType)) {
@ -413,124 +276,13 @@ open class Komga(private val suffix: String = "") : ConfigurableSource, Unmetere
""
}
Page(
<<<<<<< HEAD
index = it.number - 1,
=======
index = it.number,
>>>>>>> d52b3e572 (Add Komga (#579))
imageUrl = url,
)
}
}
<<<<<<< HEAD
override fun getMangaUrl(manga: SManga) = manga.url.replace("/api/v1", "")
override fun getChapterUrl(chapter: SChapter) = chapter.url.replace("/api/v1/books", "/book")
private fun processSeriesPage(response: Response): MangasPage {
val responseBody = response.body
return responseBody.use { body ->
if (response.fromReadList()) {
with(json.decodeFromString<PageWrapperDto<ReadListDto>>(body.string())) {
MangasPage(content.map { it.toSManga() }, !last)
}
} else {
with(json.decodeFromString<PageWrapperDto<SeriesDto>>(body.string())) {
MangasPage(content.map { it.toSManga() }, !last)
}
}
}
}
private fun SeriesDto.toSManga(): SManga =
SManga.create().apply {
title = metadata.title
url = "$baseUrl/api/v1/series/$id"
thumbnail_url = "$url/thumbnail"
status = when {
metadata.status == "ENDED" && metadata.totalBookCount != null && booksCount < metadata.totalBookCount -> SManga.PUBLISHING_FINISHED
metadata.status == "ENDED" -> SManga.COMPLETED
metadata.status == "ONGOING" -> SManga.ONGOING
metadata.status == "ABANDONED" -> SManga.CANCELLED
metadata.status == "HIATUS" -> SManga.ON_HIATUS
else -> SManga.UNKNOWN
}
genre = (metadata.genres + metadata.tags + booksMetadata.tags).distinct().joinToString(", ")
description = metadata.summary.ifBlank { booksMetadata.summary }
booksMetadata.authors.groupBy { it.role }.let { map ->
author = map["writer"]?.map { it.name }?.distinct()?.joinToString()
artist = map["penciller"]?.map { it.name }?.distinct()?.joinToString()
}
}
private fun ReadListDto.toSManga(): SManga =
SManga.create().apply {
title = name
description = summary
url = "$baseUrl/api/v1/readlists/$id"
thumbnail_url = "$url/thumbnail"
status = SManga.UNKNOWN
}
private fun Response.fromReadList() = request.url.toString().contains("/api/v1/readlists")
private fun parseDate(date: String?): Long =
if (date == null) {
0
} else {
try {
KomgaHelper.formatterDate.parse(date)?.time ?: 0
} catch (ex: Exception) {
0
}
}
private fun parseDateTime(date: String?): Long =
if (date == null) {
0
} else {
try {
KomgaHelper.formatterDateTime.parse(date)?.time ?: 0
} catch (ex: Exception) {
try {
KomgaHelper.formatterDateTimeMilli.parse(date)?.time ?: 0
} catch (ex: Exception) {
0
}
}
}
override fun imageUrlParse(response: Response): String = ""
private class TypeSelect : Filter.Select<String>("Search for", arrayOf(TYPE_SERIES, TYPE_READLISTS))
private class LibraryFilter(val id: String, name: String) : Filter.CheckBox(name, false)
private class LibraryGroup(libraries: List<LibraryFilter>) : Filter.Group<LibraryFilter>("Libraries", libraries)
private class CollectionSelect(collections: List<CollectionFilterEntry>) : Filter.Select<CollectionFilterEntry>("Collection", collections.toTypedArray())
private class SeriesSort : Filter.Sort("Sort", arrayOf("Alphabetically", "Date added", "Date updated"), Selection(0, true))
private class StatusFilter(name: String) : Filter.CheckBox(name, false)
private class StatusGroup(filters: List<StatusFilter>) : Filter.Group<StatusFilter>("Status", filters)
private class UnreadFilter : Filter.CheckBox("Unread", false)
private class InProgressFilter : Filter.CheckBox("In Progress", false)
private class ReadFilter : Filter.CheckBox("Read", false)
private class GenreFilter(genre: String) : Filter.CheckBox(genre, false)
private class GenreGroup(genres: List<GenreFilter>) : Filter.Group<GenreFilter>("Genres", genres)
private class TagFilter(tag: String) : Filter.CheckBox(tag, false)
private class TagGroup(tags: List<TagFilter>) : Filter.Group<TagFilter>("Tags", tags)
private class PublisherFilter(publisher: String) : Filter.CheckBox(publisher, false)
private class PublisherGroup(publishers: List<PublisherFilter>) : Filter.Group<PublisherFilter>("Publishers", publishers)
private class AuthorFilter(val author: AuthorDto) : Filter.CheckBox(author.name, false)
private class AuthorGroup(role: String, authors: List<AuthorFilter>) : Filter.Group<AuthorFilter>(role, authors)
private data class CollectionFilterEntry(
val name: String,
val id: String? = null,
) {
override fun toString() = name
}
=======
override fun imageUrlParse(response: Response): String = throw UnsupportedOperationException()
>>>>>>> d52b3e572 (Add Komga (#579))
override fun getFilterList(): FilterList {
val filters = try {
@ -546,31 +298,22 @@ open class Komga(private val suffix: String = "") : ConfigurableSource, Unmetere
TagGroup(tags.map { TagFilter(it) }),
PublisherGroup(publishers.map { PublisherFilter(it) }),
).also { list ->
<<<<<<< HEAD
=======
if (collections.isEmpty() && libraries.isEmpty() && genres.isEmpty() && tags.isEmpty() && publishers.isEmpty()) {
list.add(0, Filter.Header("Press 'Reset' to show filtering options"))
list.add(1, Filter.Separator())
}
>>>>>>> d52b3e572 (Add Komga (#579))
list.addAll(authors.map { (role, authors) -> AuthorGroup(role, authors.map { AuthorFilter(it) }) })
list.add(SeriesSort())
}
} catch (e: Exception) {
<<<<<<< HEAD
Log.e(LOG_TAG, "error while creating filter list", e)
=======
Log.e(logTag, "error while creating filter list", e)
>>>>>>> d52b3e572 (Add Komga (#579))
emptyList()
}
return FilterList(filters)
}
<<<<<<< HEAD
=======
override fun setupPreferenceScreen(screen: PreferenceScreen) {
if (suffix.isBlank()) {
ListPreference(screen.context).apply {
@ -652,7 +395,6 @@ open class Komga(private val suffix: String = "") : ConfigurableSource, Unmetere
}.also(screen::addPreference)
}
>>>>>>> d52b3e572 (Add Komga (#579))
private var libraries = emptyList<LibraryDto>()
private var collections = emptyList<CollectionDto>()
private var genres = emptySet<String>()
@ -660,77 +402,6 @@ open class Komga(private val suffix: String = "") : ConfigurableSource, Unmetere
private var publishers = emptySet<String>()
private var authors = emptyMap<String, List<AuthorDto>>() // roles to list of authors
<<<<<<< HEAD
// keep the previous ID when lang was "en", so that preferences and manga bindings are not lost
override val id by lazy {
val key = "komga${if (suffix.isNotBlank()) " ($suffix)" else ""}/en/$versionId"
val bytes = MessageDigest.getInstance("MD5").digest(key.toByteArray())
(0..7).map { bytes[it].toLong() and 0xff shl 8 * (7 - it) }.reduce(Long::or) and Long.MAX_VALUE
}
private val displayName by lazy { preferences.displayName }
final override val baseUrl by lazy { preferences.baseUrl }
private val username by lazy { preferences.username }
private val password by lazy { preferences.password }
private val json: Json by injectLazy()
override fun headersBuilder(): Headers.Builder =
Headers.Builder()
.add("User-Agent", "TachiyomiKomga/${AppInfo.getVersionName()}")
private val preferences: SharedPreferences by lazy {
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
}
override val name = "Komga${displayName.ifBlank { suffix }.let { if (it.isNotBlank()) " ($it)" else "" }}"
override val lang = "all"
override val supportsLatest = true
private val LOG_TAG = "extension.all.komga${if (suffix.isNotBlank()) ".$suffix" else ""}"
override val client: OkHttpClient =
network.client.newBuilder()
.authenticator { _, response ->
if (response.request.header("Authorization") != null) {
null // Give up, we've already failed to authenticate.
} else {
response.request.newBuilder()
.addHeader("Authorization", Credentials.basic(username, password))
.build()
}
}
.dns(Dns.SYSTEM) // don't use DNS over HTTPS as it breaks IP addressing
.build()
override fun setupPreferenceScreen(screen: PreferenceScreen) {
screen.addEditTextPreference(
title = "Source display name",
default = suffix,
summary = displayName.ifBlank { "Here you can change the source displayed suffix" },
key = PREF_DISPLAYNAME,
)
screen.addEditTextPreference(
title = "Address",
default = ADDRESS_DEFAULT,
summary = baseUrl.ifBlank { "The server address" },
inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_URI,
validate = { it.toHttpUrlOrNull() != null },
validationMessage = "The URL is invalid or malformed",
key = PREF_ADDRESS,
)
screen.addEditTextPreference(
title = "Username",
default = USERNAME_DEFAULT,
summary = username.ifBlank { "The user account email" },
key = PREF_USERNAME,
)
screen.addEditTextPreference(
title = "Password",
default = PASSWORD_DEFAULT,
summary = if (password.isBlank()) "The user account password" else "*".repeat(password.length),
inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_PASSWORD,
key = PREF_PASSWORD,
)
=======
private class TypeSelect : Filter.Select<String>("Search for", arrayOf(TYPE_SERIES, TYPE_READLISTS))
private class LibraryFilter(val id: String, name: String) : Filter.CheckBox(name, false)
private class LibraryGroup(libraries: List<LibraryFilter>) : Filter.Group<LibraryFilter>("Libraries", libraries)
@ -755,7 +426,6 @@ open class Komga(private val suffix: String = "") : ConfigurableSource, Unmetere
val id: String? = null,
) {
override fun toString() = name
>>>>>>> d52b3e572 (Add Komga (#579))
}
private fun PreferenceScreen.addEditTextPreference(
@ -817,125 +487,6 @@ open class Komga(private val suffix: String = "") : ConfigurableSource, Unmetere
addPreference(preference)
}
<<<<<<< HEAD
private val SharedPreferences.displayName
get() = getString(PREF_DISPLAYNAME, "")!!
private val SharedPreferences.baseUrl
get() = getString(PREF_ADDRESS, ADDRESS_DEFAULT)!!.removeSuffix("/")
private val SharedPreferences.username
get() = getString(PREF_USERNAME, USERNAME_DEFAULT)!!
private val SharedPreferences.password
get() = getString(PREF_PASSWORD, PASSWORD_DEFAULT)!!
init {
if (baseUrl.isNotBlank()) {
Single.fromCallable {
try {
client.newCall(GET("$baseUrl/api/v1/libraries", headers)).execute().use { response ->
libraries = try {
val responseBody = response.body
responseBody.use { json.decodeFromString(it.string()) }
} catch (e: Exception) {
Log.e(LOG_TAG, "error while decoding JSON for libraries filter", e)
emptyList()
}
}
} catch (e: Exception) {
Log.e(LOG_TAG, "error while loading libraries for filters", e)
}
try {
client.newCall(GET("$baseUrl/api/v1/collections?unpaged=true", headers)).execute().use { response ->
collections = try {
val responseBody = response.body
responseBody.use { json.decodeFromString<PageWrapperDto<CollectionDto>>(it.string()).content }
} catch (e: Exception) {
Log.e(LOG_TAG, "error while decoding JSON for collections filter", e)
emptyList()
}
}
} catch (e: Exception) {
Log.e(LOG_TAG, "error while loading collections for filters", e)
}
try {
client.newCall(GET("$baseUrl/api/v1/genres", headers)).execute().use { response ->
genres = try {
val responseBody = response.body
responseBody.use { json.decodeFromString(it.string()) }
} catch (e: Exception) {
Log.e(LOG_TAG, "error while decoding JSON for genres filter", e)
emptySet()
}
}
} catch (e: Exception) {
Log.e(LOG_TAG, "error while loading genres for filters", e)
}
try {
client.newCall(GET("$baseUrl/api/v1/tags", headers)).execute().use { response ->
tags = try {
response.body.use { json.decodeFromString(it.string()) }
} catch (e: Exception) {
Log.e(LOG_TAG, "error while decoding JSON for tags filter", e)
emptySet()
}
}
} catch (e: Exception) {
Log.e(LOG_TAG, "error while loading tags for filters", e)
}
try {
client.newCall(GET("$baseUrl/api/v1/publishers", headers)).execute().use { response ->
publishers = try {
response.body.use { json.decodeFromString(it.string()) }
} catch (e: Exception) {
Log.e(LOG_TAG, "error while decoding JSON for publishers filter", e)
emptySet()
}
}
} catch (e: Exception) {
Log.e(LOG_TAG, "error while loading publishers for filters", e)
}
try {
client.newCall(GET("$baseUrl/api/v1/authors", headers)).execute().use { response ->
authors = try {
response.body
.use { json.decodeFromString<List<AuthorDto>>(it.string()) }
.groupBy { it.role }
} catch (e: Exception) {
Log.e(LOG_TAG, "error while decoding JSON for authors filter", e)
emptyMap()
}
}
} catch (e: Exception) {
Log.e(LOG_TAG, "error while loading authors for filters", e)
}
}
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.io())
.subscribe(
{},
{ tr ->
Log.e(LOG_TAG, "error while doing initial calls", tr)
},
)
}
}
companion object {
private const val PREF_DISPLAYNAME = "Source display name"
private const val PREF_ADDRESS = "Address"
private const val ADDRESS_DEFAULT = ""
private const val PREF_USERNAME = "Username"
private const val USERNAME_DEFAULT = ""
private const val PREF_PASSWORD = "Password"
private const val PASSWORD_DEFAULT = ""
=======
private var fetchFiltersFailed = false
private var fetchFiltersAttempts = 0
@ -1054,7 +605,6 @@ open class Komga(private val suffix: String = "") : ConfigurableSource, Unmetere
private const val PREF_PASSWORD = "Password"
private const val PREF_CHAPTER_NAME_TEMPLATE = "Chapter name template"
private const val PREF_CHAPTER_NAME_TEMPLATE_DEFAULT = "{number} - {title} ({size})"
>>>>>>> d52b3e572 (Add Komga (#579))
private val supportedImageTypes = listOf("image/jpeg", "image/png", "image/gif", "image/webp", "image/jxl", "image/heif", "image/avif")

View File

@ -4,15 +4,6 @@ import eu.kanade.tachiyomi.source.Source
import eu.kanade.tachiyomi.source.SourceFactory
class KomgaFactory : SourceFactory {
<<<<<<< HEAD
override fun createSources(): List<Source> =
listOf(
Komga(),
Komga("2"),
Komga("3"),
)
=======
override fun createSources(): List<Source> {
val firstKomga = Komga("")
val komgaCount = firstKomga.preferences.getString(Komga.PREF_EXTRA_SOURCES_COUNT, Komga.PREF_EXTRA_SOURCES_DEFAULT)!!.toInt()
@ -20,5 +11,4 @@ class KomgaFactory : SourceFactory {
// Komga(""), Komga("2"), Komga("3"), ...
return listOf(firstKomga) + (0 until komgaCount).map { Komga("${it + 2}") }
}
>>>>>>> d52b3e572 (Add Komga (#579))
}

View File

@ -24,11 +24,7 @@ You can visit the [LANraragi](https://github.com/Difegue/LANraragi) github page
Make sure that your LANraragi server and extension are on the newest version.
### Can I add more than one LANraragi server or user?
<<<<<<< HEAD
No, currently there is only support for 1 instances in Tachiyomi, if you need more instances please open a feature request on [tachiyomi-extensions](https://github.com/tachiyomiorg/tachiyomi-extensions/issues/new/choose) repo.
=======
No, currently there is only support for 1 instances in Tachiyomi, if you need more instances please open a feature request on [extensions](https://github.com/tachiyomiorg/extensions/issues/new/choose) repo.
>>>>>>> 4dac8de22 (Add LANraragi (#702))
### Can I test the LANraragi extension before setting up my own server?
Yes, you can try it out with the DEMO server `https://lrr.tvc-16.science`.

View File

@ -1,11 +1,7 @@
ext {
extName = 'LANraragi'
extClass = '.LANraragiFactory'
<<<<<<< HEAD
extVersionCode = 15
=======
extVersionCode = 16
>>>>>>> 4dac8de22 (Add LANraragi (#702))
}
apply from: "$rootDir/common.gradle"

View File

@ -6,10 +6,7 @@ import android.net.Uri
import android.text.InputType
import android.util.Base64
import android.widget.Toast
<<<<<<< HEAD
=======
import androidx.preference.ListPreference
>>>>>>> 4dac8de22 (Add LANraragi (#702))
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.network.asObservableSuccess
import eu.kanade.tachiyomi.source.ConfigurableSource
@ -276,11 +273,7 @@ open class LANraragi(private val suffix: String = "") : ConfigurableSource, Unme
(0..7).map { bytes[it].toLong() and 0xff shl 8 * (7 - it) }.reduce(Long::or) and Long.MAX_VALUE
}
<<<<<<< HEAD
private val preferences: SharedPreferences by lazy {
=======
internal val preferences: SharedPreferences by lazy {
>>>>>>> 4dac8de22 (Add LANraragi (#702))
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
}
@ -290,8 +283,6 @@ open class LANraragi(private val suffix: String = "") : ConfigurableSource, Unme
private fun getPrefCustomLabel(): String = preferences.getString(CUSTOM_LABEL_KEY, suffix)!!.ifBlank { suffix }
override fun setupPreferenceScreen(screen: androidx.preference.PreferenceScreen) {
<<<<<<< HEAD
=======
if (suffix == "1") {
ListPreference(screen.context).apply {
key = EXTRA_SOURCES_COUNT_KEY
@ -313,7 +304,6 @@ open class LANraragi(private val suffix: String = "") : ConfigurableSource, Unme
}
}.also(screen::addPreference)
}
>>>>>>> 4dac8de22 (Add LANraragi (#702))
screen.addPreference(screen.editTextPreference(HOSTNAME_KEY, "Hostname", HOSTNAME_DEFAULT, baseUrl, refreshSummary = true))
screen.addPreference(screen.editTextPreference(APIKEY_KEY, "API Key", "", "Required if No-Fun Mode is enabled.", true))
screen.addPreference(screen.editTextPreference(CUSTOM_LABEL_KEY, "Custom Label", "", "Show the given label for the source instead of the default."))
@ -490,13 +480,10 @@ open class LANraragi(private val suffix: String = "") : ConfigurableSource, Unme
}
companion object {
<<<<<<< HEAD
=======
internal const val EXTRA_SOURCES_COUNT_KEY = "extraSourcesCount"
internal const val EXTRA_SOURCES_COUNT_DEFAULT = "2"
private val EXTRA_SOURCES_ENTRIES = (0..10).map { it.toString() }.toTypedArray()
>>>>>>> 4dac8de22 (Add LANraragi (#702))
private const val HOSTNAME_DEFAULT = "http://127.0.0.1:3000"
private const val HOSTNAME_KEY = "hostname"
private const val APIKEY_KEY = "apiKey"

View File

@ -4,14 +4,6 @@ import eu.kanade.tachiyomi.source.Source
import eu.kanade.tachiyomi.source.SourceFactory
class LANraragiFactory : SourceFactory {
<<<<<<< HEAD
override fun createSources(): List<Source> =
listOf(
LANraragi("1"),
LANraragi("2"),
LANraragi("3"),
)
=======
override fun createSources(): List<Source> {
val firstLrr = LANraragi("1")
val lrrCount = firstLrr.preferences.getString(LANraragi.EXTRA_SOURCES_COUNT_KEY, LANraragi.EXTRA_SOURCES_COUNT_DEFAULT)!!.toInt()
@ -23,5 +15,4 @@ class LANraragiFactory : SourceFactory {
}
}
}
>>>>>>> 4dac8de22 (Add LANraragi (#702))
}