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