Add Kavita extension (#10241)
* Trying out git Sorry in advance if this messes up. Trying to work on my extensions fork to develop a new extension So far Mangas are listed Successfully. * Added Kavita Icons * Added Kavita ParseDetails. All data is retrieved the first time SManga is created, but reimplemented since it retrieves info from backup * Added Chapter List "chapters": [ { "id": 750, "range": "1.1", "number": "11", "pages": 16, "isSpecial": false, }, { "id": 767, "range": "001.jpg", "number": "0", "pages": 5, "isSpecial": true, }, { "id": 818, "range": "1.3", "number": "13", "pages": 8, "isSpecial": false, }, { "id": 817, "range": "1.4", "number": "14", "pages": 12, "isSpecial": false, }, { "id": 768, "range": "002.jpg", "number": "0", "pages": 5, "isSpecial": true, }, <- extracted json see how when isSpecial, number = 0 Needs to be fixed * Delete .github/ISSUE_TEMPLATE directory * Checklist: ✓ It Lists the library ✓ It Lists the chapters of a serie ✓ Clicking on a chapter shows the image * New Icons & login finished Added token isvalid else relogins Login should be confirmed of not having problems * Changed Defaults to Kavita Wiki's * Added Search Manga Feature * Removed User Authentication. Leaving only token Behind * Refactored out login credentials and rewrote the authentication for joining. user now just puts in base path and api key * Cleanup some of the code and re-arange to keep related code together. * Cleanup some of the code and re-arange to keep related code together. * Still WIP, stream lined creation of Series and Series detail. Chapters are a bit broken. * Series generation with metadata is done. Working on chapter code. * Code to properly label chapters is done * Revert "Delete .github/ISSUE_TEMPLATE directory" This reverts commit 8d5740c4 * Reset editor Config * Removed Input token * Cleaned Unused code and files * Readded Search Removed token again * Modified all imports to avoid lintcheck errors -> deleted all wildcards * Integrated format filter with latest backend code * Refactored authentication to now grab it from solely the address field. * Refactored authentication to now grab it from solely the address field. * Refactored authentication to now grab it from solely the address field. Auth token is fetched when needed without requiring user to restart their session. * - Fixed duped Pages on main - Fixed Chapters going backwards - Fixed last chapter getting duped * - Fixed login with new opds url setting. * Cleaned commented code * Cleaned commented code * Added isLogin. IOException if invalid apikey * Fixes Volume Naming Previously All Volume Number was displayed as '0', It fixes that bug. * Removed Gson usages * Updated the filter Dto for all methods * Merged Http err Handling * Added debug option to see 400 error * 1.2.3. Commented debugRequest * Crappy code warning: Added first filtering support * Manga details fixed: Artist,Author,Summary, ¿genres? should be displayed properly now * Pushing nothing changed * - Fixed 500 error when reset filter - Added reading status filter - Cleaned some spaghetti code that was redundant * Code cleanup * Format Filter is almost readt. Majora finish it. * Added library filter * More code cleanup. Authentication request only sent once. * People filter Added * Added collection,character and translator filters Remaining filters: - Rating - Format * Fixed displayed chapter number. Cleaned chapter title. * - Fixed #12 - Reworked Login - Added Logs - Added more errors handlers * Added format filter Added check for url (must start with http/s) Fixed filters getting disabled when scrolling further (request for new pages did not have filters) Code cleanup * updated extVersionCode ->5 - ready for release * updated extVersionCode ->6 - pull request to tachiyomiorg/ext * removed release folder from git and removed unwanted modifications in the project * removed release folder from git and removed unwanted modifications in the project * unwanted modification * Update src/all/kavita/src/eu/kanade/tachiyomi/extension/all/kavita/Kavita.kt Co-authored-by: Alessandro Jean <alessandrojean@gmail.com> * Update src/all/kavita/build.gradle Co-authored-by: Alessandro Jean <alessandrojean@gmail.com> * removed unused import * Changed icons to be more consistent with other extensions. * QuickFix: format filter wrong default. * Added webview support (Needs to be tested thoroughly) Refactored baseUrl to apiUrl baseURl is now only "Server:Port" (without trailing slashes.) Closes #14 * Fixed Json Decode error when genres,people or artists are empty. Solution to #15 is to use tachiyomi `sort by chapter number` feature. * Added publication status filter * Added sort filter * Bump extVersionCode * Updated cover artist serial name in SeriesMetadataDto * Added user rating filter * Removed other people filter * Removed other people filter Fixed filtering suddenly not applying * Filters that are not populated won't show * Added new preferences options to customize filters showing in filter list * Added more configurable sources to have multipe kavita instances * Code Cleanup * Fixed ReadStatus * Changed order of preference setting * Added more checks and log exceptions v0.5+ is required message added * Added more checks and log exceptions v0.5+ is required message added * Fixed Cover Artist filter preference not working * Changed extVersionCode to 1 * Fixed Tags filter not populating * Added toast to restart app when source name is changed * Forgot to stage this file. Fixes tags filter not populated * Added one more error message. v0.5+ required * Fixed having to restart twice the app after preference changes Changed setupLogin order Fixed some log messages. * Changed more log messages Some cleanup. * Fixed Unexpected JSON token in manga details * Fixed search was creating a Smanga with url = series ID instead of complete url * Fixed search was creating a Smanga with url = series ID instead of complete url Co-authored-by: Joseph Milazzo <joseph.v.milazzo@gmail.com> Co-authored-by: Shashank Pujari <shashank-p@users.noreply.github.com> Co-authored-by: Alessandro Jean <alessandrojean@gmail.com>
This commit is contained in:
parent
f1a9fe6d16
commit
59380ed6f4
|
@ -0,0 +1,2 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<manifest package="eu.kanade.tachiyomi.extension" />
|
|
@ -0,0 +1,16 @@
|
||||||
|
apply plugin: 'com.android.application'
|
||||||
|
apply plugin: 'kotlin-android'
|
||||||
|
apply plugin: 'kotlinx-serialization'
|
||||||
|
|
||||||
|
ext {
|
||||||
|
extName = 'Kavita'
|
||||||
|
pkgNameSuffix = 'all.kavita'
|
||||||
|
extClass = '.KavitaFactory'
|
||||||
|
extVersionCode = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation 'info.debatty:java-string-similarity:2.0.0'
|
||||||
|
}
|
||||||
|
|
||||||
|
apply from: "$rootDir/common.gradle"
|
Binary file not shown.
After Width: | Height: | Size: 3.1 KiB |
Binary file not shown.
After Width: | Height: | Size: 1.8 KiB |
Binary file not shown.
After Width: | Height: | Size: 3.9 KiB |
Binary file not shown.
After Width: | Height: | Size: 6.4 KiB |
Binary file not shown.
After Width: | Height: | Size: 9.0 KiB |
Binary file not shown.
After Width: | Height: | Size: 33 KiB |
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,77 @@
|
||||||
|
package eu.kanade.tachiyomi.extension.all.kavita
|
||||||
|
|
||||||
|
object KavitaConstants {
|
||||||
|
// togle filters
|
||||||
|
const val toggledFiltersPref = "toggledFilters"
|
||||||
|
val filterPrefEntries = arrayOf(
|
||||||
|
"Sort Options",
|
||||||
|
"Format",
|
||||||
|
"Libraries",
|
||||||
|
"Read Status",
|
||||||
|
"Genres",
|
||||||
|
"Tags",
|
||||||
|
"Collections",
|
||||||
|
"Languages",
|
||||||
|
"Publication Status",
|
||||||
|
"Rating",
|
||||||
|
"Age Rating",
|
||||||
|
"Writers",
|
||||||
|
"Penciller",
|
||||||
|
"Inker",
|
||||||
|
"Colorist",
|
||||||
|
"Letterer",
|
||||||
|
"Cover Artist",
|
||||||
|
"Editor",
|
||||||
|
"Publisher",
|
||||||
|
"Character",
|
||||||
|
"Translators"
|
||||||
|
)
|
||||||
|
val filterPrefEntriesValue = arrayOf(
|
||||||
|
"Sort Options",
|
||||||
|
"Format",
|
||||||
|
"Libraries",
|
||||||
|
"Read Status",
|
||||||
|
"Genres",
|
||||||
|
"Tags",
|
||||||
|
"Collections",
|
||||||
|
"Languages",
|
||||||
|
"Publication Status",
|
||||||
|
"Rating",
|
||||||
|
"Age Rating",
|
||||||
|
"Writers",
|
||||||
|
"Penciller",
|
||||||
|
"Inker",
|
||||||
|
"Colorist",
|
||||||
|
"Letterer",
|
||||||
|
"CoverArtist",
|
||||||
|
"Editor",
|
||||||
|
"Publisher",
|
||||||
|
"Character",
|
||||||
|
"Translators"
|
||||||
|
)
|
||||||
|
val defaultFilterPrefEntries = setOf(
|
||||||
|
"Sort Options",
|
||||||
|
"Format",
|
||||||
|
"Libraries",
|
||||||
|
"Read Status",
|
||||||
|
"Genres",
|
||||||
|
"Tags",
|
||||||
|
"Collections",
|
||||||
|
"Languages",
|
||||||
|
"Publication Status",
|
||||||
|
"Rating",
|
||||||
|
"Age Rating",
|
||||||
|
"Writers",
|
||||||
|
"Penciller",
|
||||||
|
"Inker",
|
||||||
|
"Colorist",
|
||||||
|
"Letterer",
|
||||||
|
"CoverArtist",
|
||||||
|
"Editor",
|
||||||
|
"Publisher",
|
||||||
|
"Character",
|
||||||
|
"Translators"
|
||||||
|
)
|
||||||
|
|
||||||
|
const val customSourceNamePref = "customSourceName"
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
package eu.kanade.tachiyomi.extension.all.kavita
|
||||||
|
|
||||||
|
import eu.kanade.tachiyomi.source.Source
|
||||||
|
import eu.kanade.tachiyomi.source.SourceFactory
|
||||||
|
|
||||||
|
class KavitaFactory : SourceFactory {
|
||||||
|
override fun createSources(): List<Source> =
|
||||||
|
listOf(
|
||||||
|
Kavita("1"),
|
||||||
|
Kavita("2"),
|
||||||
|
Kavita("3")
|
||||||
|
)
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
package eu.kanade.tachiyomi.extension.all.kavita
|
||||||
|
|
||||||
|
import eu.kanade.tachiyomi.extension.all.kavita.dto.PaginationInfo
|
||||||
|
import eu.kanade.tachiyomi.extension.all.kavita.dto.SeriesDto
|
||||||
|
import eu.kanade.tachiyomi.source.model.SManga
|
||||||
|
import kotlinx.serialization.decodeFromString
|
||||||
|
import kotlinx.serialization.json.Json
|
||||||
|
import okhttp3.Response
|
||||||
|
import java.text.SimpleDateFormat
|
||||||
|
import java.util.Locale
|
||||||
|
import java.util.TimeZone
|
||||||
|
|
||||||
|
class KavitaHelper {
|
||||||
|
val json = Json {
|
||||||
|
isLenient = true
|
||||||
|
ignoreUnknownKeys = true
|
||||||
|
allowSpecialFloatingPointValues = true
|
||||||
|
useArrayPolymorphism = true
|
||||||
|
prettyPrint = true
|
||||||
|
}
|
||||||
|
|
||||||
|
val dateFormatter = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSSSSSS", Locale.US)
|
||||||
|
.apply { timeZone = TimeZone.getTimeZone("UTC") }
|
||||||
|
fun parseDate(dateAsString: String): Long =
|
||||||
|
dateFormatter.parse(dateAsString)?.time ?: 0
|
||||||
|
|
||||||
|
fun hasNextPage(response: Response): Boolean {
|
||||||
|
val paginationHeader = response.header("Pagination")
|
||||||
|
var hasNextPage = false
|
||||||
|
if (!paginationHeader.isNullOrEmpty()) {
|
||||||
|
val paginationInfo = json.decodeFromString<PaginationInfo>(paginationHeader)
|
||||||
|
hasNextPage = paginationInfo.currentPage + 1 > paginationInfo.totalPages
|
||||||
|
}
|
||||||
|
return !hasNextPage
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getIdFromUrl(url: String): Int {
|
||||||
|
return url.split("/").last().toInt()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun createSeriesDto(obj: SeriesDto, baseUrl: String): SManga =
|
||||||
|
SManga.create().apply {
|
||||||
|
url = "$baseUrl/Series/${obj.id}"
|
||||||
|
title = obj.name
|
||||||
|
// Deprecated: description = obj.summary
|
||||||
|
thumbnail_url = "$baseUrl/image/series-cover?seriesId=${obj.id}"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,110 @@
|
||||||
|
package eu.kanade.tachiyomi.extension.all.kavita.dto
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
enum class MangaFormat(val format: Int) {
|
||||||
|
Image(0),
|
||||||
|
Archive(1),
|
||||||
|
Unknown(2),
|
||||||
|
Epub(3),
|
||||||
|
Pdf(4);
|
||||||
|
companion object {
|
||||||
|
private val map = PersonRole.values().associateBy(PersonRole::role)
|
||||||
|
fun fromInt(type: Int) = map[type]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
enum class PersonRole(val role: Int) {
|
||||||
|
Other(1),
|
||||||
|
Writer(3),
|
||||||
|
Penciller(4),
|
||||||
|
Inker(5),
|
||||||
|
Colorist(6),
|
||||||
|
Letterer(7),
|
||||||
|
CoverArtist(8),
|
||||||
|
Editor(9),
|
||||||
|
Publisher(10),
|
||||||
|
Character(11),
|
||||||
|
Translator(12);
|
||||||
|
companion object {
|
||||||
|
private val map = PersonRole.values().associateBy(PersonRole::role)
|
||||||
|
fun fromInt(type: Int) = map[type]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@Serializable
|
||||||
|
data class SeriesDto(
|
||||||
|
val id: Int,
|
||||||
|
val name: String,
|
||||||
|
val originalName: String = "",
|
||||||
|
val thumbnail_url: String? = "",
|
||||||
|
val localizedName: String? = "",
|
||||||
|
val sortName: String? = "",
|
||||||
|
val pages: Int,
|
||||||
|
val coverImageLocked: Boolean = true,
|
||||||
|
val pagesRead: Int,
|
||||||
|
val userRating: Int,
|
||||||
|
val userReview: String? = "",
|
||||||
|
val format: Int,
|
||||||
|
val created: String? = "",
|
||||||
|
val libraryId: Int,
|
||||||
|
val libraryName: String? = ""
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class SeriesMetadataDto(
|
||||||
|
val id: Int,
|
||||||
|
val summary: String? = "",
|
||||||
|
val writers: List<Person> = emptyList(),
|
||||||
|
val coverArtists: List<Person> = emptyList(),
|
||||||
|
val genres: List<Genres> = emptyList(),
|
||||||
|
val seriesId: Int,
|
||||||
|
val ageRating: Int
|
||||||
|
|
||||||
|
)
|
||||||
|
@Serializable
|
||||||
|
data class Genres(
|
||||||
|
val title: String
|
||||||
|
)
|
||||||
|
@Serializable
|
||||||
|
data class Person(
|
||||||
|
val name: String
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class VolumeDto(
|
||||||
|
val id: Int,
|
||||||
|
val number: Int,
|
||||||
|
val name: String,
|
||||||
|
val pages: Int,
|
||||||
|
val pagesRead: Int,
|
||||||
|
val lastModified: String,
|
||||||
|
val created: String,
|
||||||
|
val seriesId: Int,
|
||||||
|
val chapters: List<ChapterDto> = emptyList()
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class ChapterDto(
|
||||||
|
val id: Int,
|
||||||
|
val range: String,
|
||||||
|
val number: String,
|
||||||
|
val pages: Int,
|
||||||
|
val isSpecial: Boolean,
|
||||||
|
val title: String,
|
||||||
|
val pagesRead: Int,
|
||||||
|
val coverImageLocked: Boolean,
|
||||||
|
val volumeId: Int,
|
||||||
|
val created: String
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class KavitaComicsSearch(
|
||||||
|
val seriesId: Int,
|
||||||
|
val name: String,
|
||||||
|
val originalName: String,
|
||||||
|
val sortName: String,
|
||||||
|
val localizedName: String,
|
||||||
|
val format: Int,
|
||||||
|
val libraryName: String,
|
||||||
|
val libraryId: Int
|
||||||
|
)
|
|
@ -0,0 +1,76 @@
|
||||||
|
package eu.kanade.tachiyomi.extension.all.kavita.dto
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
/**
|
||||||
|
* This file contains all class for filtering
|
||||||
|
* */
|
||||||
|
@Serializable
|
||||||
|
data class MetadataGenres(
|
||||||
|
val id: Int,
|
||||||
|
val title: String,
|
||||||
|
)
|
||||||
|
@Serializable
|
||||||
|
data class MetadataPeople(
|
||||||
|
val id: Int,
|
||||||
|
val name: String,
|
||||||
|
val role: Int
|
||||||
|
)
|
||||||
|
@Serializable
|
||||||
|
data class MetadataPubStatus(
|
||||||
|
val value: Int,
|
||||||
|
val title: String
|
||||||
|
)
|
||||||
|
@Serializable
|
||||||
|
data class MetadataTag(
|
||||||
|
val id: Int,
|
||||||
|
val title: String,
|
||||||
|
)
|
||||||
|
@Serializable
|
||||||
|
data class MetadataAgeRatings(
|
||||||
|
val value: Int,
|
||||||
|
val title: String
|
||||||
|
)
|
||||||
|
@Serializable
|
||||||
|
data class MetadataLanguages(
|
||||||
|
val isoCode: String,
|
||||||
|
val title: String
|
||||||
|
)
|
||||||
|
@Serializable
|
||||||
|
data class MetadataLibrary(
|
||||||
|
val id: Int,
|
||||||
|
val name: String,
|
||||||
|
val type: Int
|
||||||
|
)
|
||||||
|
@Serializable
|
||||||
|
data class MetadataCollections(
|
||||||
|
val id: Int,
|
||||||
|
val title: String,
|
||||||
|
)
|
||||||
|
|
||||||
|
data class MetadataPayload(
|
||||||
|
var sorting: Int = 1,
|
||||||
|
var sorting_asc: Boolean = true,
|
||||||
|
var readStatus: ArrayList<String> = arrayListOf< String>(),
|
||||||
|
var genres: ArrayList<Int> = arrayListOf<Int>(),
|
||||||
|
var tags: ArrayList<Int> = arrayListOf<Int>(),
|
||||||
|
var ageRating: ArrayList<Int> = arrayListOf<Int>(),
|
||||||
|
var formats: ArrayList<Int> = arrayListOf<Int>(),
|
||||||
|
var collections: ArrayList<Int> = arrayListOf<Int>(),
|
||||||
|
var userRating: Int = 0,
|
||||||
|
var people: ArrayList<Int> = arrayListOf<Int>(),
|
||||||
|
var language: ArrayList<String> = arrayListOf<String>(),
|
||||||
|
var libraries: ArrayList<Int> = arrayListOf<Int>(),
|
||||||
|
var pubStatus: ArrayList<Int> = arrayListOf<Int>(),
|
||||||
|
|
||||||
|
var peopleWriters: ArrayList<Int> = arrayListOf<Int>(),
|
||||||
|
var peoplePenciller: ArrayList<Int> = arrayListOf<Int>(),
|
||||||
|
var peopleInker: ArrayList<Int> = arrayListOf<Int>(),
|
||||||
|
var peoplePeoplecolorist: ArrayList<Int> = arrayListOf<Int>(),
|
||||||
|
var peopleLetterer: ArrayList<Int> = arrayListOf<Int>(),
|
||||||
|
var peopleCoverArtist: ArrayList<Int> = arrayListOf<Int>(),
|
||||||
|
var peopleEditor: ArrayList<Int> = arrayListOf<Int>(),
|
||||||
|
var peoplePublisher: ArrayList<Int> = arrayListOf<Int>(),
|
||||||
|
var peopleCharacter: ArrayList<Int> = arrayListOf<Int>(),
|
||||||
|
var peopleTranslator: ArrayList<Int> = arrayListOf<Int>(),
|
||||||
|
|
||||||
|
)
|
|
@ -0,0 +1,18 @@
|
||||||
|
package eu.kanade.tachiyomi.extension.all.kavita.dto
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable // Used to process login
|
||||||
|
data class AuthenticationDto(
|
||||||
|
val username: String,
|
||||||
|
val token: String,
|
||||||
|
val apiKey: String
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class PaginationInfo(
|
||||||
|
val currentPage: Int,
|
||||||
|
val itemsPerPage: Int,
|
||||||
|
val totalItems: Int,
|
||||||
|
val totalPages: Int
|
||||||
|
)
|
Loading…
Reference in New Issue