mirror of
https://github.com/tachiyomiorg/tachiyomi-extensions-inspector.git
synced 2024-12-27 01:01:48 +01:00
Delete Anime
This commit is contained in:
parent
afd659813d
commit
9de8aff8a8
@ -1,46 +0,0 @@
|
|||||||
package eu.kanade.tachiyomi.animesource
|
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.animesource.model.AnimeFilterList
|
|
||||||
import eu.kanade.tachiyomi.animesource.model.AnimesPage
|
|
||||||
import rx.Observable
|
|
||||||
|
|
||||||
interface AnimeCatalogueSource : AnimeSource {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An ISO 639-1 compliant language code (two letters in lower case).
|
|
||||||
*/
|
|
||||||
val lang: String
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether the source has support for latest updates.
|
|
||||||
*/
|
|
||||||
val supportsLatest: Boolean
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an observable containing a page with a list of anime.
|
|
||||||
*
|
|
||||||
* @param page the page number to retrieve.
|
|
||||||
*/
|
|
||||||
fun fetchPopularAnime(page: Int): Observable<AnimesPage>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an observable containing a page with a list of anime.
|
|
||||||
*
|
|
||||||
* @param page the page number to retrieve.
|
|
||||||
* @param query the search query.
|
|
||||||
* @param filters the list of filters to apply.
|
|
||||||
*/
|
|
||||||
fun fetchSearchAnime(page: Int, query: String, filters: AnimeFilterList): Observable<AnimesPage>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an observable containing a page with a list of latest anime updates.
|
|
||||||
*
|
|
||||||
* @param page the page number to retrieve.
|
|
||||||
*/
|
|
||||||
fun fetchLatestUpdates(page: Int): Observable<AnimesPage>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the list of filters for the source.
|
|
||||||
*/
|
|
||||||
fun getFilterList(): AnimeFilterList
|
|
||||||
}
|
|
@ -1,77 +0,0 @@
|
|||||||
package eu.kanade.tachiyomi.animesource
|
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.animesource.model.SAnime
|
|
||||||
import eu.kanade.tachiyomi.animesource.model.SEpisode
|
|
||||||
import rx.Observable
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A basic interface for creating a source. It could be an online source, a local source, etc...
|
|
||||||
*/
|
|
||||||
interface AnimeSource {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Id for the source. Must be unique.
|
|
||||||
*/
|
|
||||||
val id: Long
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Name of the source.
|
|
||||||
*/
|
|
||||||
val name: String
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an observable with the updated details for a anime.
|
|
||||||
*
|
|
||||||
* @param anime the anime to update.
|
|
||||||
*/
|
|
||||||
// @Deprecated("Use getAnimeDetails instead")
|
|
||||||
fun fetchAnimeDetails(anime: SAnime): Observable<SAnime>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an observable with all the available episodes for an anime.
|
|
||||||
*
|
|
||||||
* @param anime the anime to update.
|
|
||||||
*/
|
|
||||||
// @Deprecated("Use getEpisodeList instead")
|
|
||||||
fun fetchEpisodeList(anime: SAnime): Observable<List<SEpisode>>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an observable with a link for the episode of an anime.
|
|
||||||
*
|
|
||||||
* @param episode the episode to get the link for.
|
|
||||||
*/
|
|
||||||
// @Deprecated("Use getEpisodeList instead")
|
|
||||||
fun fetchEpisodeLink(episode: SEpisode): Observable<String>
|
|
||||||
|
|
||||||
// /**
|
|
||||||
// * [1.x API] Get the updated details for a anime.
|
|
||||||
// */
|
|
||||||
// @Suppress("DEPRECATION")
|
|
||||||
// override suspend fun getAnimeDetails(anime: AnimeInfo): AnimeInfo {
|
|
||||||
// val sAnime = anime.toSAnime()
|
|
||||||
// val networkAnime = fetchAnimeDetails(sAnime).awaitSingle()
|
|
||||||
// sAnime.copyFrom(networkAnime)
|
|
||||||
// return sAnime.toAnimeInfo()
|
|
||||||
// }
|
|
||||||
|
|
||||||
// /**
|
|
||||||
// * [1.x API] Get all the available episodes for a anime.
|
|
||||||
// */
|
|
||||||
// @Suppress("DEPRECATION")
|
|
||||||
// override suspend fun getEpisodeList(anime: AnimeInfo): List<EpisodeInfo> {
|
|
||||||
// return fetchEpisodeList(anime.toSAnime()).awaitSingle()
|
|
||||||
// .map { it.toEpisodeInfo() }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// /**
|
|
||||||
// * [1.x API] Get a link for the episode of an anime.
|
|
||||||
// */
|
|
||||||
// @Suppress("DEPRECATION")
|
|
||||||
// override suspend fun getEpisodeLink(episode: EpisodeInfo): String {
|
|
||||||
// return fetchEpisodeLink(episode.toSEpisode()).awaitSingle()
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
// fun AnimeSource.icon(): Drawable? = Injekt.get<AnimeExtensionManager>().getAppIconForSource(this)
|
|
||||||
|
|
||||||
// fun AnimeSource.getPreferenceKey(): String = "source_$id"
|
|
@ -1,12 +0,0 @@
|
|||||||
package eu.kanade.tachiyomi.animesource
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A factory for creating sources at runtime.
|
|
||||||
*/
|
|
||||||
interface AnimeSourceFactory {
|
|
||||||
/**
|
|
||||||
* Create a new copy of the sources
|
|
||||||
* @return The created sources
|
|
||||||
*/
|
|
||||||
fun createSources(): List<AnimeSource>
|
|
||||||
}
|
|
@ -1,76 +0,0 @@
|
|||||||
package eu.kanade.tachiyomi.animesource
|
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import eu.kanade.tachiyomi.animesource.model.SAnime
|
|
||||||
import eu.kanade.tachiyomi.animesource.model.SEpisode
|
|
||||||
import eu.kanade.tachiyomi.animesource.online.AnimeHttpSource
|
|
||||||
import rx.Observable
|
|
||||||
|
|
||||||
open class AnimeSourceManager(private val context: Context) {
|
|
||||||
|
|
||||||
private val sourcesMap = mutableMapOf<Long, AnimeSource>()
|
|
||||||
|
|
||||||
private val stubSourcesMap = mutableMapOf<Long, StubSource>()
|
|
||||||
|
|
||||||
init {
|
|
||||||
createInternalSources().forEach { registerSource(it) }
|
|
||||||
}
|
|
||||||
|
|
||||||
open fun get(sourceKey: Long): AnimeSource? {
|
|
||||||
return sourcesMap[sourceKey]
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getOrStub(sourceKey: Long): AnimeSource {
|
|
||||||
return sourcesMap[sourceKey] ?: stubSourcesMap.getOrPut(sourceKey) {
|
|
||||||
StubSource(sourceKey)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getOnlineSources() = sourcesMap.values.filterIsInstance<AnimeHttpSource>()
|
|
||||||
|
|
||||||
fun getCatalogueSources() = sourcesMap.values.filterIsInstance<AnimeCatalogueSource>()
|
|
||||||
|
|
||||||
internal fun registerSource(source: AnimeSource) {
|
|
||||||
if (!sourcesMap.containsKey(source.id)) {
|
|
||||||
sourcesMap[source.id] = source
|
|
||||||
}
|
|
||||||
if (!stubSourcesMap.containsKey(source.id)) {
|
|
||||||
stubSourcesMap[source.id] = StubSource(source.id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal fun unregisterSource(source: AnimeSource) {
|
|
||||||
sourcesMap.remove(source.id)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun createInternalSources(): List<AnimeSource> = listOf(
|
|
||||||
// LocalAnimeSource(context)
|
|
||||||
)
|
|
||||||
|
|
||||||
inner class StubSource(override val id: Long) : AnimeSource {
|
|
||||||
|
|
||||||
override val name: String
|
|
||||||
get() = id.toString()
|
|
||||||
|
|
||||||
override fun fetchAnimeDetails(anime: SAnime): Observable<SAnime> {
|
|
||||||
return Observable.error(getSourceNotInstalledException())
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun fetchEpisodeList(anime: SAnime): Observable<List<SEpisode>> {
|
|
||||||
return Observable.error(getSourceNotInstalledException())
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun fetchEpisodeLink(episode: SEpisode): Observable<String> {
|
|
||||||
return Observable.error(getSourceNotInstalledException())
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun toString(): String {
|
|
||||||
return name
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getSourceNotInstalledException(): Exception {
|
|
||||||
// return Exception(context.getString(R.string.source_not_installed, id.toString()))
|
|
||||||
return Exception("source not found")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,8 +0,0 @@
|
|||||||
package eu.kanade.tachiyomi.animesource
|
|
||||||
|
|
||||||
import android.support.v7.preference.PreferenceScreen
|
|
||||||
|
|
||||||
interface ConfigurableAnimeSource : AnimeSource {
|
|
||||||
|
|
||||||
fun setupPreferenceScreen(screen: PreferenceScreen)
|
|
||||||
}
|
|
@ -1,40 +0,0 @@
|
|||||||
package eu.kanade.tachiyomi.animesource.model
|
|
||||||
|
|
||||||
sealed class AnimeFilter<T>(val name: String, var state: T) {
|
|
||||||
open class Header(name: String) : AnimeFilter<Any>(name, 0)
|
|
||||||
open class Separator(name: String = "") : AnimeFilter<Any>(name, 0)
|
|
||||||
abstract class Select<V>(name: String, val values: Array<V>, state: Int = 0) : AnimeFilter<Int>(name, state)
|
|
||||||
abstract class Text(name: String, state: String = "") : AnimeFilter<String>(name, state)
|
|
||||||
abstract class CheckBox(name: String, state: Boolean = false) : AnimeFilter<Boolean>(name, state)
|
|
||||||
abstract class TriState(name: String, state: Int = STATE_IGNORE) : AnimeFilter<Int>(name, state) {
|
|
||||||
fun isIgnored() = state == STATE_IGNORE
|
|
||||||
fun isIncluded() = state == STATE_INCLUDE
|
|
||||||
fun isExcluded() = state == STATE_EXCLUDE
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
const val STATE_IGNORE = 0
|
|
||||||
const val STATE_INCLUDE = 1
|
|
||||||
const val STATE_EXCLUDE = 2
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract class Group<V>(name: String, state: List<V>) : AnimeFilter<List<V>>(name, state)
|
|
||||||
|
|
||||||
abstract class Sort(name: String, val values: Array<String>, state: Selection? = null) :
|
|
||||||
AnimeFilter<Sort.Selection?>(name, state) {
|
|
||||||
data class Selection(val index: Int, val ascending: Boolean)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
|
||||||
if (this === other) return true
|
|
||||||
if (other !is AnimeFilter<*>) return false
|
|
||||||
|
|
||||||
return name == other.name && state == other.state
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun hashCode(): Int {
|
|
||||||
var result = name.hashCode()
|
|
||||||
result = 31 * result + (state?.hashCode() ?: 0)
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,6 +0,0 @@
|
|||||||
package eu.kanade.tachiyomi.animesource.model
|
|
||||||
|
|
||||||
data class AnimeFilterList(val list: List<AnimeFilter<*>>) : List<AnimeFilter<*>> by list {
|
|
||||||
|
|
||||||
constructor(vararg fs: AnimeFilter<*>) : this(if (fs.isNotEmpty()) fs.asList() else emptyList())
|
|
||||||
}
|
|
@ -1,3 +0,0 @@
|
|||||||
package eu.kanade.tachiyomi.animesource.model
|
|
||||||
|
|
||||||
data class AnimesPage(val animes: List<SAnime>, val hasNextPage: Boolean)
|
|
@ -1,67 +0,0 @@
|
|||||||
package eu.kanade.tachiyomi.animesource.model
|
|
||||||
|
|
||||||
import java.io.Serializable
|
|
||||||
|
|
||||||
interface SAnime : Serializable {
|
|
||||||
|
|
||||||
var url: String
|
|
||||||
|
|
||||||
var title: String
|
|
||||||
|
|
||||||
var artist: String?
|
|
||||||
|
|
||||||
var author: String?
|
|
||||||
|
|
||||||
var description: String?
|
|
||||||
|
|
||||||
var genre: String?
|
|
||||||
|
|
||||||
var status: Int
|
|
||||||
|
|
||||||
var thumbnail_url: String?
|
|
||||||
|
|
||||||
var initialized: Boolean
|
|
||||||
|
|
||||||
fun copyFrom(other: SAnime) {
|
|
||||||
if (other.title != null) {
|
|
||||||
title = other.title
|
|
||||||
}
|
|
||||||
|
|
||||||
if (other.author != null) {
|
|
||||||
author = other.author
|
|
||||||
}
|
|
||||||
|
|
||||||
if (other.artist != null) {
|
|
||||||
artist = other.artist
|
|
||||||
}
|
|
||||||
|
|
||||||
if (other.description != null) {
|
|
||||||
description = other.description
|
|
||||||
}
|
|
||||||
|
|
||||||
if (other.genre != null) {
|
|
||||||
genre = other.genre
|
|
||||||
}
|
|
||||||
|
|
||||||
if (other.thumbnail_url != null) {
|
|
||||||
thumbnail_url = other.thumbnail_url
|
|
||||||
}
|
|
||||||
|
|
||||||
status = other.status
|
|
||||||
|
|
||||||
if (!initialized) {
|
|
||||||
initialized = other.initialized
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
const val UNKNOWN = 0
|
|
||||||
const val ONGOING = 1
|
|
||||||
const val COMPLETED = 2
|
|
||||||
const val LICENSED = 3
|
|
||||||
|
|
||||||
fun create(): SAnime {
|
|
||||||
return SAnimeImpl()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,22 +0,0 @@
|
|||||||
package eu.kanade.tachiyomi.animesource.model
|
|
||||||
|
|
||||||
class SAnimeImpl : SAnime {
|
|
||||||
|
|
||||||
override lateinit var url: String
|
|
||||||
|
|
||||||
override lateinit var title: String
|
|
||||||
|
|
||||||
override var artist: String? = null
|
|
||||||
|
|
||||||
override var author: String? = null
|
|
||||||
|
|
||||||
override var description: String? = null
|
|
||||||
|
|
||||||
override var genre: String? = null
|
|
||||||
|
|
||||||
override var status: Int = 0
|
|
||||||
|
|
||||||
override var thumbnail_url: String? = null
|
|
||||||
|
|
||||||
override var initialized: Boolean = false
|
|
||||||
}
|
|
@ -1,30 +0,0 @@
|
|||||||
package eu.kanade.tachiyomi.animesource.model
|
|
||||||
|
|
||||||
import java.io.Serializable
|
|
||||||
|
|
||||||
interface SEpisode : Serializable {
|
|
||||||
|
|
||||||
var url: String
|
|
||||||
|
|
||||||
var name: String
|
|
||||||
|
|
||||||
var date_upload: Long
|
|
||||||
|
|
||||||
var episode_number: Float
|
|
||||||
|
|
||||||
var scanlator: String?
|
|
||||||
|
|
||||||
fun copyFrom(other: SEpisode) {
|
|
||||||
name = other.name
|
|
||||||
url = other.url
|
|
||||||
date_upload = other.date_upload
|
|
||||||
episode_number = other.episode_number
|
|
||||||
scanlator = other.scanlator
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
fun create(): SEpisode {
|
|
||||||
return SEpisodeImpl()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,14 +0,0 @@
|
|||||||
package eu.kanade.tachiyomi.animesource.model
|
|
||||||
|
|
||||||
class SEpisodeImpl : SEpisode {
|
|
||||||
|
|
||||||
override lateinit var url: String
|
|
||||||
|
|
||||||
override lateinit var name: String
|
|
||||||
|
|
||||||
override var date_upload: Long = 0
|
|
||||||
|
|
||||||
override var episode_number: Float = -1f
|
|
||||||
|
|
||||||
override var scanlator: String? = null
|
|
||||||
}
|
|
@ -1,388 +0,0 @@
|
|||||||
package eu.kanade.tachiyomi.animesource.online
|
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.animesource.AnimeCatalogueSource
|
|
||||||
import eu.kanade.tachiyomi.animesource.model.AnimeFilterList
|
|
||||||
import eu.kanade.tachiyomi.animesource.model.AnimesPage
|
|
||||||
import eu.kanade.tachiyomi.animesource.model.SAnime
|
|
||||||
import eu.kanade.tachiyomi.animesource.model.SEpisode
|
|
||||||
import eu.kanade.tachiyomi.network.GET
|
|
||||||
import eu.kanade.tachiyomi.network.NetworkHelper
|
|
||||||
import eu.kanade.tachiyomi.network.asObservableSuccess
|
|
||||||
import eu.kanade.tachiyomi.network.newCallWithProgress
|
|
||||||
import eu.kanade.tachiyomi.source.model.Page
|
|
||||||
import okhttp3.Headers
|
|
||||||
import okhttp3.OkHttpClient
|
|
||||||
import okhttp3.Request
|
|
||||||
import okhttp3.Response
|
|
||||||
import rx.Observable
|
|
||||||
import uy.kohesive.injekt.injectLazy
|
|
||||||
import java.net.URI
|
|
||||||
import java.net.URISyntaxException
|
|
||||||
import java.security.MessageDigest
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A simple implementation for sources from a website.
|
|
||||||
*/
|
|
||||||
abstract class AnimeHttpSource : AnimeCatalogueSource {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Network service.
|
|
||||||
*/
|
|
||||||
protected val network: NetworkHelper by injectLazy()
|
|
||||||
|
|
||||||
// /**
|
|
||||||
// * Preferences that a source may need.
|
|
||||||
// */
|
|
||||||
// val preferences: SharedPreferences by lazy {
|
|
||||||
// Injekt.get<Application>().getSharedPreferences(source.getPreferenceKey(), Context.MODE_PRIVATE)
|
|
||||||
// }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Base url of the website without the trailing slash, like: http://mysite.com
|
|
||||||
*/
|
|
||||||
abstract val baseUrl: String
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Version id used to generate the source id. If the site completely changes and urls are
|
|
||||||
* incompatible, you may increase this value and it'll be considered as a new source.
|
|
||||||
*/
|
|
||||||
open val versionId = 1
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Id of the source. By default it uses a generated id using the first 16 characters (64 bits)
|
|
||||||
* of the MD5 of the string: sourcename/language/versionId
|
|
||||||
* Note the generated id sets the sign bit to 0.
|
|
||||||
*/
|
|
||||||
override val id by lazy {
|
|
||||||
val key = "${name.toLowerCase()}/$lang/$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
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Headers used for requests.
|
|
||||||
*/
|
|
||||||
val headers: Headers by lazy { headersBuilder().build() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Default network client for doing requests.
|
|
||||||
*/
|
|
||||||
open val client: OkHttpClient
|
|
||||||
get() = network.client
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Headers builder for requests. Implementations can override this method for custom headers.
|
|
||||||
*/
|
|
||||||
protected open fun headersBuilder() = Headers.Builder().apply {
|
|
||||||
add("User-Agent", DEFAULT_USER_AGENT)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Visible name of the source.
|
|
||||||
*/
|
|
||||||
override fun toString() = "$name (${lang.toUpperCase()})"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an observable containing a page with a list of anime. Normally it's not needed to
|
|
||||||
* override this method.
|
|
||||||
*
|
|
||||||
* @param page the page number to retrieve.
|
|
||||||
*/
|
|
||||||
override fun fetchPopularAnime(page: Int): Observable<AnimesPage> {
|
|
||||||
return client.newCall(popularAnimeRequest(page))
|
|
||||||
.asObservableSuccess()
|
|
||||||
.map { response ->
|
|
||||||
popularAnimeParse(response)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the request for the popular anime given the page.
|
|
||||||
*
|
|
||||||
* @param page the page number to retrieve.
|
|
||||||
*/
|
|
||||||
protected abstract fun popularAnimeRequest(page: Int): Request
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parses the response from the site and returns a [AnimesPage] object.
|
|
||||||
*
|
|
||||||
* @param response the response from the site.
|
|
||||||
*/
|
|
||||||
protected abstract fun popularAnimeParse(response: Response): AnimesPage
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an observable containing a page with a list of anime. Normally it's not needed to
|
|
||||||
* override this method.
|
|
||||||
*
|
|
||||||
* @param page the page number to retrieve.
|
|
||||||
* @param query the search query.
|
|
||||||
* @param filters the list of filters to apply.
|
|
||||||
*/
|
|
||||||
override fun fetchSearchAnime(page: Int, query: String, filters: AnimeFilterList): Observable<AnimesPage> {
|
|
||||||
return client.newCall(searchAnimeRequest(page, query, filters))
|
|
||||||
.asObservableSuccess()
|
|
||||||
.map { response ->
|
|
||||||
searchAnimeParse(response)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the request for the search anime given the page.
|
|
||||||
*
|
|
||||||
* @param page the page number to retrieve.
|
|
||||||
* @param query the search query.
|
|
||||||
* @param filters the list of filters to apply.
|
|
||||||
*/
|
|
||||||
protected abstract fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parses the response from the site and returns a [AnimesPage] object.
|
|
||||||
*
|
|
||||||
* @param response the response from the site.
|
|
||||||
*/
|
|
||||||
protected abstract fun searchAnimeParse(response: Response): AnimesPage
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an observable containing a page with a list of latest anime updates.
|
|
||||||
*
|
|
||||||
* @param page the page number to retrieve.
|
|
||||||
*/
|
|
||||||
override fun fetchLatestUpdates(page: Int): Observable<AnimesPage> {
|
|
||||||
return client.newCall(latestUpdatesRequest(page))
|
|
||||||
.asObservableSuccess()
|
|
||||||
.map { response ->
|
|
||||||
latestUpdatesParse(response)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the request for latest anime given the page.
|
|
||||||
*
|
|
||||||
* @param page the page number to retrieve.
|
|
||||||
*/
|
|
||||||
protected abstract fun latestUpdatesRequest(page: Int): Request
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parses the response from the site and returns a [AnimesPage] object.
|
|
||||||
*
|
|
||||||
* @param response the response from the site.
|
|
||||||
*/
|
|
||||||
protected abstract fun latestUpdatesParse(response: Response): AnimesPage
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an observable with the updated details for a anime. Normally it's not needed to
|
|
||||||
* override this method.
|
|
||||||
*
|
|
||||||
* @param anime the anime to be updated.
|
|
||||||
*/
|
|
||||||
override fun fetchAnimeDetails(anime: SAnime): Observable<SAnime> {
|
|
||||||
return client.newCall(animeDetailsRequest(anime))
|
|
||||||
.asObservableSuccess()
|
|
||||||
.map { response ->
|
|
||||||
animeDetailsParse(response).apply { initialized = true }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the request for the details of a anime. Override only if it's needed to change the
|
|
||||||
* url, send different headers or request method like POST.
|
|
||||||
*
|
|
||||||
* @param anime the anime to be updated.
|
|
||||||
*/
|
|
||||||
open fun animeDetailsRequest(anime: SAnime): Request {
|
|
||||||
return GET(baseUrl + anime.url, headers)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parses the response from the site and returns the details of a anime.
|
|
||||||
*
|
|
||||||
* @param response the response from the site.
|
|
||||||
*/
|
|
||||||
protected abstract fun animeDetailsParse(response: Response): SAnime
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an observable with the updated episode list for a anime. Normally it's not needed to
|
|
||||||
* override this method. If a anime is licensed an empty episode list observable is returned
|
|
||||||
*
|
|
||||||
* @param anime the anime to look for episodes.
|
|
||||||
*/
|
|
||||||
override fun fetchEpisodeList(anime: SAnime): Observable<List<SEpisode>> {
|
|
||||||
return if (anime.status != SAnime.LICENSED) {
|
|
||||||
client.newCall(episodeListRequest(anime))
|
|
||||||
.asObservableSuccess()
|
|
||||||
.map { response ->
|
|
||||||
episodeListParse(response)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Observable.error(Exception("Licensed - No episodes to show"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun fetchEpisodeLink(episode: SEpisode): Observable<String> {
|
|
||||||
return client.newCall(episodeLinkRequest(episode))
|
|
||||||
.asObservableSuccess()
|
|
||||||
.map { response ->
|
|
||||||
episodeLinkParse(response)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the request for updating the episode list. Override only if it's needed to override
|
|
||||||
* the url, send different headers or request method like POST.
|
|
||||||
*
|
|
||||||
* @param anime the anime to look for episodes.
|
|
||||||
*/
|
|
||||||
protected open fun episodeListRequest(anime: SAnime): Request {
|
|
||||||
return GET(baseUrl + anime.url, headers)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the request for getting the episode link. Override only if it's needed to override
|
|
||||||
* the url, send different headers or request method like POST.
|
|
||||||
*
|
|
||||||
* @param episode the episode to look for links.
|
|
||||||
*/
|
|
||||||
protected open fun episodeLinkRequest(episode: SEpisode): Request {
|
|
||||||
return GET(baseUrl + episode.url, headers)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parses the response from the site and returns a list of episodes.
|
|
||||||
*
|
|
||||||
* @param response the response from the site.
|
|
||||||
*/
|
|
||||||
protected abstract fun episodeListParse(response: Response): List<SEpisode>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parses the response from the site and returns a list of episodes.
|
|
||||||
*
|
|
||||||
* @param response the response from the site.
|
|
||||||
*/
|
|
||||||
protected abstract fun episodeLinkParse(response: Response): String
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the request for getting the page list. Override only if it's needed to override the
|
|
||||||
* url, send different headers or request method like POST.
|
|
||||||
*
|
|
||||||
* @param episode the episode whose page list has to be fetched.
|
|
||||||
*/
|
|
||||||
protected open fun pageListRequest(episode: SEpisode): Request {
|
|
||||||
return GET(baseUrl + episode.url, headers)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parses the response from the site and returns a list of pages.
|
|
||||||
*
|
|
||||||
* @param response the response from the site.
|
|
||||||
*/
|
|
||||||
protected abstract fun pageListParse(response: Response): List<Page>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an observable with the page containing the source url of the image. If there's any
|
|
||||||
* error, it will return null instead of throwing an exception.
|
|
||||||
*
|
|
||||||
* @param page the page whose source image has to be fetched.
|
|
||||||
*/
|
|
||||||
open fun fetchImageUrl(page: Page): Observable<String> {
|
|
||||||
return client.newCall(imageUrlRequest(page))
|
|
||||||
.asObservableSuccess()
|
|
||||||
.map { imageUrlParse(it) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the request for getting the url to the source image. Override only if it's needed to
|
|
||||||
* override the url, send different headers or request method like POST.
|
|
||||||
*
|
|
||||||
* @param page the episode whose page list has to be fetched
|
|
||||||
*/
|
|
||||||
protected open fun imageUrlRequest(page: Page): Request {
|
|
||||||
return GET(page.url, headers)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parses the response from the site and returns the absolute url to the source image.
|
|
||||||
*
|
|
||||||
* @param response the response from the site.
|
|
||||||
*/
|
|
||||||
protected abstract fun imageUrlParse(response: Response): String
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an observable with the response of the source image.
|
|
||||||
*
|
|
||||||
* @param page the page whose source image has to be downloaded.
|
|
||||||
*/
|
|
||||||
fun fetchImage(page: Page): Observable<Response> {
|
|
||||||
return client.newCallWithProgress(imageRequest(page), page)
|
|
||||||
.asObservableSuccess()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the request for getting the source image. Override only if it's needed to override
|
|
||||||
* the url, send different headers or request method like POST.
|
|
||||||
*
|
|
||||||
* @param page the episode whose page list has to be fetched
|
|
||||||
*/
|
|
||||||
protected open fun imageRequest(page: Page): Request {
|
|
||||||
return GET(page.imageUrl!!, headers)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Assigns the url of the episode without the scheme and domain. It saves some redundancy from
|
|
||||||
* database and the urls could still work after a domain change.
|
|
||||||
*
|
|
||||||
* @param url the full url to the episode.
|
|
||||||
*/
|
|
||||||
fun SEpisode.setUrlWithoutDomain(url: String) {
|
|
||||||
this.url = getUrlWithoutDomain(url)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Assigns the url of the anime without the scheme and domain. It saves some redundancy from
|
|
||||||
* database and the urls could still work after a domain change.
|
|
||||||
*
|
|
||||||
* @param url the full url to the anime.
|
|
||||||
*/
|
|
||||||
fun SAnime.setUrlWithoutDomain(url: String) {
|
|
||||||
this.url = getUrlWithoutDomain(url)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the url of the given string without the scheme and domain.
|
|
||||||
*
|
|
||||||
* @param orig the full url.
|
|
||||||
*/
|
|
||||||
private fun getUrlWithoutDomain(orig: String): String {
|
|
||||||
return try {
|
|
||||||
val uri = URI(orig)
|
|
||||||
var out = uri.path
|
|
||||||
if (uri.query != null) {
|
|
||||||
out += "?" + uri.query
|
|
||||||
}
|
|
||||||
if (uri.fragment != null) {
|
|
||||||
out += "#" + uri.fragment
|
|
||||||
}
|
|
||||||
out
|
|
||||||
} catch (e: URISyntaxException) {
|
|
||||||
orig
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called before inserting a new episode into database. Use it if you need to override episode
|
|
||||||
* fields, like the title or the episode number. Do not change anything to [anime].
|
|
||||||
*
|
|
||||||
* @param episode the episode to be added.
|
|
||||||
* @param anime the anime of the episode.
|
|
||||||
*/
|
|
||||||
open fun prepareNewEpisode(episode: SEpisode, anime: SAnime) {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the list of filters for the source.
|
|
||||||
*/
|
|
||||||
override fun getFilterList() = AnimeFilterList()
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
const val DEFAULT_USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.150 Safari/537.36 Edg/88.0.705.63"
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,26 +0,0 @@
|
|||||||
package eu.kanade.tachiyomi.source.online
|
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.animesource.online.AnimeHttpSource
|
|
||||||
import eu.kanade.tachiyomi.source.model.Page
|
|
||||||
import rx.Observable
|
|
||||||
|
|
||||||
fun AnimeHttpSource.getImageUrl(page: Page): Observable<Page> {
|
|
||||||
page.status = Page.LOAD_PAGE
|
|
||||||
return fetchImageUrl(page)
|
|
||||||
.doOnError { page.status = Page.ERROR }
|
|
||||||
.onErrorReturn { null }
|
|
||||||
.doOnNext { page.imageUrl = it }
|
|
||||||
.map { page }
|
|
||||||
}
|
|
||||||
|
|
||||||
fun AnimeHttpSource.fetchAllImageUrlsFromPageList(pages: List<Page>): Observable<Page> {
|
|
||||||
return Observable.from(pages)
|
|
||||||
.filter { !it.imageUrl.isNullOrEmpty() }
|
|
||||||
.mergeWith(fetchRemainingImageUrlsFromPageList(pages))
|
|
||||||
}
|
|
||||||
|
|
||||||
fun AnimeHttpSource.fetchRemainingImageUrlsFromPageList(pages: List<Page>): Observable<Page> {
|
|
||||||
return Observable.from(pages)
|
|
||||||
.filter { it.imageUrl.isNullOrEmpty() }
|
|
||||||
.concatMap { getImageUrl(it) }
|
|
||||||
}
|
|
@ -1,222 +0,0 @@
|
|||||||
package eu.kanade.tachiyomi.animesource.online
|
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.animesource.model.AnimesPage
|
|
||||||
import eu.kanade.tachiyomi.animesource.model.SAnime
|
|
||||||
import eu.kanade.tachiyomi.animesource.model.SEpisode
|
|
||||||
import eu.kanade.tachiyomi.source.model.Page
|
|
||||||
import eu.kanade.tachiyomi.util.asJsoup
|
|
||||||
import okhttp3.Response
|
|
||||||
import org.jsoup.nodes.Document
|
|
||||||
import org.jsoup.nodes.Element
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A simple implementation for sources from a website using Jsoup, an HTML parser.
|
|
||||||
*/
|
|
||||||
abstract class ParsedAnimeHttpSource : AnimeHttpSource() {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parses the response from the site and returns a [AnimesPage] object.
|
|
||||||
*
|
|
||||||
* @param response the response from the site.
|
|
||||||
*/
|
|
||||||
override fun popularAnimeParse(response: Response): AnimesPage {
|
|
||||||
val document = response.asJsoup()
|
|
||||||
|
|
||||||
val animes = document.select(popularAnimeSelector()).map { element ->
|
|
||||||
popularAnimeFromElement(element)
|
|
||||||
}
|
|
||||||
|
|
||||||
val hasNextPage = popularAnimeNextPageSelector()?.let { selector ->
|
|
||||||
document.select(selector).first()
|
|
||||||
} != null
|
|
||||||
|
|
||||||
return AnimesPage(animes, hasNextPage)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the Jsoup selector that returns a list of [Element] corresponding to each anime.
|
|
||||||
*/
|
|
||||||
protected abstract fun popularAnimeSelector(): String
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a anime from the given [element]. Most sites only show the title and the url, it's
|
|
||||||
* totally fine to fill only those two values.
|
|
||||||
*
|
|
||||||
* @param element an element obtained from [popularAnimeSelector].
|
|
||||||
*/
|
|
||||||
protected abstract fun popularAnimeFromElement(element: Element): SAnime
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the Jsoup selector that returns the <a> tag linking to the next page, or null if
|
|
||||||
* there's no next page.
|
|
||||||
*/
|
|
||||||
protected abstract fun popularAnimeNextPageSelector(): String?
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parses the response from the site and returns a [AnimesPage] object.
|
|
||||||
*
|
|
||||||
* @param response the response from the site.
|
|
||||||
*/
|
|
||||||
override fun searchAnimeParse(response: Response): AnimesPage {
|
|
||||||
val document = response.asJsoup()
|
|
||||||
|
|
||||||
val animes = document.select(searchAnimeSelector()).map { element ->
|
|
||||||
searchAnimeFromElement(element)
|
|
||||||
}
|
|
||||||
|
|
||||||
val hasNextPage = searchAnimeNextPageSelector()?.let { selector ->
|
|
||||||
document.select(selector).first()
|
|
||||||
} != null
|
|
||||||
|
|
||||||
return AnimesPage(animes, hasNextPage)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the Jsoup selector that returns a list of [Element] corresponding to each anime.
|
|
||||||
*/
|
|
||||||
protected abstract fun searchAnimeSelector(): String
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a anime from the given [element]. Most sites only show the title and the url, it's
|
|
||||||
* totally fine to fill only those two values.
|
|
||||||
*
|
|
||||||
* @param element an element obtained from [searchAnimeSelector].
|
|
||||||
*/
|
|
||||||
protected abstract fun searchAnimeFromElement(element: Element): SAnime
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the Jsoup selector that returns the <a> tag linking to the next page, or null if
|
|
||||||
* there's no next page.
|
|
||||||
*/
|
|
||||||
protected abstract fun searchAnimeNextPageSelector(): String?
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parses the response from the site and returns a [AnimesPage] object.
|
|
||||||
*
|
|
||||||
* @param response the response from the site.
|
|
||||||
*/
|
|
||||||
override fun latestUpdatesParse(response: Response): AnimesPage {
|
|
||||||
val document = response.asJsoup()
|
|
||||||
|
|
||||||
val animes = document.select(latestUpdatesSelector()).map { element ->
|
|
||||||
latestUpdatesFromElement(element)
|
|
||||||
}
|
|
||||||
|
|
||||||
val hasNextPage = latestUpdatesNextPageSelector()?.let { selector ->
|
|
||||||
document.select(selector).first()
|
|
||||||
} != null
|
|
||||||
|
|
||||||
return AnimesPage(animes, hasNextPage)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the Jsoup selector that returns a list of [Element] corresponding to each anime.
|
|
||||||
*/
|
|
||||||
protected abstract fun latestUpdatesSelector(): String
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a anime from the given [element]. Most sites only show the title and the url, it's
|
|
||||||
* totally fine to fill only those two values.
|
|
||||||
*
|
|
||||||
* @param element an element obtained from [latestUpdatesSelector].
|
|
||||||
*/
|
|
||||||
protected abstract fun latestUpdatesFromElement(element: Element): SAnime
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the Jsoup selector that returns the <a> tag linking to the next page, or null if
|
|
||||||
* there's no next page.
|
|
||||||
*/
|
|
||||||
protected abstract fun latestUpdatesNextPageSelector(): String?
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parses the response from the site and returns the details of a anime.
|
|
||||||
*
|
|
||||||
* @param response the response from the site.
|
|
||||||
*/
|
|
||||||
override fun animeDetailsParse(response: Response): SAnime {
|
|
||||||
return animeDetailsParse(response.asJsoup())
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the details of the anime from the given [document].
|
|
||||||
*
|
|
||||||
* @param document the parsed document.
|
|
||||||
*/
|
|
||||||
protected abstract fun animeDetailsParse(document: Document): SAnime
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parses the response from the site and returns a list of episodes.
|
|
||||||
*
|
|
||||||
* @param response the response from the site.
|
|
||||||
*/
|
|
||||||
override fun episodeListParse(response: Response): List<SEpisode> {
|
|
||||||
val document = response.asJsoup()
|
|
||||||
return document.select(episodeListSelector()).map { episodeFromElement(it) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the Jsoup selector that returns a list of [Element] corresponding to each episode.
|
|
||||||
*/
|
|
||||||
protected abstract fun episodeListSelector(): String
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parses the response from the site and returns a list of episodes.
|
|
||||||
*
|
|
||||||
* @param response the response from the site.
|
|
||||||
*/
|
|
||||||
override fun episodeLinkParse(response: Response): String {
|
|
||||||
val document = response.asJsoup()
|
|
||||||
return linkFromElement(document.select(episodeLinkSelector()).first())
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the Jsoup selector that returns a list of [Element] corresponding to each episode.
|
|
||||||
*/
|
|
||||||
protected abstract fun episodeLinkSelector(): String
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a episode from the given element.
|
|
||||||
*
|
|
||||||
* @param element an element obtained from [episodeListSelector].
|
|
||||||
*/
|
|
||||||
protected abstract fun episodeFromElement(element: Element): SEpisode
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a episode from the given element.
|
|
||||||
*
|
|
||||||
* @param element an element obtained from [episodeListSelector].
|
|
||||||
*/
|
|
||||||
protected abstract fun linkFromElement(element: Element): String
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parses the response from the site and returns the page list.
|
|
||||||
*
|
|
||||||
* @param response the response from the site.
|
|
||||||
*/
|
|
||||||
override fun pageListParse(response: Response): List<Page> {
|
|
||||||
return pageListParse(response.asJsoup())
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a page list from the given document.
|
|
||||||
*
|
|
||||||
* @param document the parsed document.
|
|
||||||
*/
|
|
||||||
protected abstract fun pageListParse(document: Document): List<Page>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parse the response from the site and returns the absolute url to the source image.
|
|
||||||
*
|
|
||||||
* @param response the response from the site.
|
|
||||||
*/
|
|
||||||
override fun imageUrlParse(response: Response): String {
|
|
||||||
return imageUrlParse(response.asJsoup())
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the absolute url to the source image from the document.
|
|
||||||
*
|
|
||||||
* @param document the parsed document.
|
|
||||||
*/
|
|
||||||
protected abstract fun imageUrlParse(document: Document): String
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user