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