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
2
src/all/kavita/AndroidManifest.xml
Normal file
2
src/all/kavita/AndroidManifest.xml
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<manifest package="eu.kanade.tachiyomi.extension" />
|
||||||
16
src/all/kavita/build.gradle
Normal file
16
src/all/kavita/build.gradle
Normal file
@ -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"
|
||||||
BIN
src/all/kavita/res/mipmap-hdpi/ic_launcher.png
Normal file
BIN
src/all/kavita/res/mipmap-hdpi/ic_launcher.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.1 KiB |
BIN
src/all/kavita/res/mipmap-mdpi/ic_launcher.png
Normal file
BIN
src/all/kavita/res/mipmap-mdpi/ic_launcher.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.8 KiB |
BIN
src/all/kavita/res/mipmap-xhdpi/ic_launcher.png
Normal file
BIN
src/all/kavita/res/mipmap-xhdpi/ic_launcher.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.9 KiB |
BIN
src/all/kavita/res/mipmap-xxhdpi/ic_launcher.png
Normal file
BIN
src/all/kavita/res/mipmap-xxhdpi/ic_launcher.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.4 KiB |
BIN
src/all/kavita/res/mipmap-xxxhdpi/ic_launcher.png
Normal file
BIN
src/all/kavita/res/mipmap-xxxhdpi/ic_launcher.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 9.0 KiB |
BIN
src/all/kavita/res/web_hi_res_512.png
Normal file
BIN
src/all/kavita/res/web_hi_res_512.png
Normal file
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…
x
Reference in New Issue
Block a user