feat(en/allanimechi): Add option to use hoster names & fix gogo (#2575)
This commit is contained in:
parent
b2a68f135a
commit
d60ff529e2
@ -8,7 +8,7 @@ ext {
|
||||
extName = 'AllAnimeChi'
|
||||
pkgNameSuffix = 'en.allanimechi'
|
||||
extClass = '.AllAnimeChi'
|
||||
extVersionCode = 1
|
||||
extVersionCode = 2
|
||||
libVersion = '13'
|
||||
}
|
||||
|
||||
|
@ -38,6 +38,7 @@ import kotlinx.serialization.json.putJsonArray
|
||||
import kotlinx.serialization.json.putJsonObject
|
||||
import okhttp3.Headers
|
||||
import okhttp3.HttpUrl.Companion.toHttpUrl
|
||||
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import okhttp3.Response
|
||||
@ -46,6 +47,7 @@ import rx.Observable
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.util.Locale
|
||||
|
||||
class AllAnimeChi : ConfigurableAnimeSource, AnimeHttpSource() {
|
||||
|
||||
@ -252,8 +254,9 @@ class AllAnimeChi : ConfigurableAnimeSource, AnimeHttpSource() {
|
||||
return GET(url, apiHeaders)
|
||||
}
|
||||
|
||||
// TODO: replace with getAnimeUrl when new ext-lib is available
|
||||
override fun animeDetailsRequest(anime: SAnime): Request {
|
||||
return GET("data:text/plain,This%20extension%20does%20not%20exist%20as%20a%20website%21")
|
||||
return GET("data:text/plain,This%20extension%20does%20not%20have%20a%20website.")
|
||||
}
|
||||
|
||||
override fun animeDetailsParse(response: Response): SAnime {
|
||||
@ -308,7 +311,7 @@ class AllAnimeChi : ConfigurableAnimeSource, AnimeHttpSource() {
|
||||
|
||||
// ============================ Video Links =============================
|
||||
|
||||
private val internalExtractor by lazy { InternalExtractor(client, apiHeaders) }
|
||||
private val internalExtractor by lazy { InternalExtractor(client, apiHeaders, headers) }
|
||||
|
||||
override fun videoListRequest(episode: SEpisode): Request {
|
||||
val variables = episode.url
|
||||
@ -334,6 +337,7 @@ class AllAnimeChi : ConfigurableAnimeSource, AnimeHttpSource() {
|
||||
|
||||
val hosterBlackList = preferences.getHosterBlacklist
|
||||
val altHosterBlackList = preferences.getAltHosterBlacklist
|
||||
val useHosterNames = preferences.useHosterName
|
||||
|
||||
val serverList = videoJson.data.episode.sourceUrls.mapNotNull { video ->
|
||||
when {
|
||||
@ -359,26 +363,32 @@ class AllAnimeChi : ConfigurableAnimeSource, AnimeHttpSource() {
|
||||
}
|
||||
|
||||
return prioritySort(
|
||||
serverList.parallelCatchingFlatMap(::getVideoFromServer),
|
||||
serverList.parallelCatchingFlatMap { getVideoFromServer(it, useHosterNames) },
|
||||
)
|
||||
}
|
||||
|
||||
private fun getVideoFromServer(server: Server): List<Pair<Video, Float>> {
|
||||
private fun getVideoFromServer(server: Server, useHosterName: Boolean): List<Pair<Video, Float>> {
|
||||
return when (server.type) {
|
||||
"player" -> getFromPlayer(server)
|
||||
"internal" -> internalExtractor.videosFromServer(server, removeRaw = preferences.removeRaw)
|
||||
"external" -> getFromExternal(server)
|
||||
"player" -> getFromPlayer(server, useHosterName)
|
||||
"internal" -> internalExtractor.videosFromServer(server, useHosterName, removeRaw = preferences.removeRaw)
|
||||
"external" -> getFromExternal(server, useHosterName)
|
||||
else -> emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
private fun getFromPlayer(server: Server): List<Pair<Video, Float>> {
|
||||
private fun getFromPlayer(server: Server, useHosterName: Boolean): List<Pair<Video, Float>> {
|
||||
val name = if (useHosterName) {
|
||||
getHostName(server.sourceUrl, server.sourceName)
|
||||
} else {
|
||||
server.sourceName
|
||||
}
|
||||
|
||||
val videoHeaders = headers.newBuilder().apply {
|
||||
add("origin", siteUrl)
|
||||
add("referer", "$siteUrl/")
|
||||
}.build()
|
||||
|
||||
val video = Video(server.sourceUrl, server.sourceName, server.sourceUrl, headers = videoHeaders)
|
||||
val video = Video(server.sourceUrl, name, server.sourceUrl, headers = videoHeaders)
|
||||
return listOf(
|
||||
Pair(video, server.priority),
|
||||
)
|
||||
@ -392,9 +402,14 @@ class AllAnimeChi : ConfigurableAnimeSource, AnimeHttpSource() {
|
||||
private val allanimeExtractor by lazy { AllAnimeExtractor(client, headers) }
|
||||
private val streamwishExtractor by lazy { StreamWishExtractor(client, headers) }
|
||||
|
||||
private fun getFromExternal(server: Server): List<Pair<Video, Float>> {
|
||||
private fun getFromExternal(server: Server, useHosterName: Boolean): List<Pair<Video, Float>> {
|
||||
val url = server.sourceUrl.replace(Regex("""^//"""), "https://")
|
||||
val prefix = "${server.sourceName} - "
|
||||
val prefix = if (useHosterName) {
|
||||
"${getHostName(url, server.sourceName)} - "
|
||||
} else {
|
||||
"${server.sourceName} - "
|
||||
}
|
||||
|
||||
val videoList = when {
|
||||
url.startsWith("https://ok") -> okruExtractor.videosFromUrl(url, prefix = prefix)
|
||||
url.startsWith("https://filemoon") -> filemoonExtractor.videosFromUrl(url, prefix = prefix)
|
||||
@ -411,6 +426,14 @@ class AllAnimeChi : ConfigurableAnimeSource, AnimeHttpSource() {
|
||||
|
||||
// ============================= Utilities ==============================
|
||||
|
||||
private fun getHostName(host: String, fallback: String): String {
|
||||
return host.toHttpUrlOrNull()?.host?.split(".")?.let {
|
||||
it.getOrNull(it.size - 2)?.replaceFirstChar { c ->
|
||||
if (c.isLowerCase()) c.titlecase(Locale.ROOT) else c.toString()
|
||||
}
|
||||
} ?: fallback
|
||||
}
|
||||
|
||||
private fun String.decodeBase64(): String {
|
||||
return String(Base64.decode(this, Base64.DEFAULT))
|
||||
}
|
||||
@ -468,6 +491,8 @@ class AllAnimeChi : ConfigurableAnimeSource, AnimeHttpSource() {
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val PAGE_SIZE = 30 // number of items to retrieve when calling API
|
||||
|
||||
private const val POPULAR_HASH = "31a117653812a2547fd981632e8c99fa8bf8a75c4ef1a77a1567ef1741a7ab9c"
|
||||
private const val LATEST_HASH = "e42a4466d984b2c0a2cecae5dd13aa68867f634b16ee0f17b380047d14482406"
|
||||
private const val DETAILS_HASH = "bb263f91e5bdd048c1c978f324613aeccdfe2cbc694a419466a31edb58c0cc0b"
|
||||
@ -492,8 +517,6 @@ class AllAnimeChi : ConfigurableAnimeSource, AnimeHttpSource() {
|
||||
"Yt-mp4",
|
||||
)
|
||||
|
||||
private const val PAGE_SIZE = 30 // number of items to retrieve when calling API
|
||||
|
||||
private const val PREF_HOSTER_BLACKLIST_KEY = "pref_hoster_blacklist"
|
||||
private val PREF_HOSTER_BLACKLIST_ENTRY_VALUES = INTERNAL_HOSTER_NAMES.map {
|
||||
it.lowercase().substringBefore(" (")
|
||||
@ -542,6 +565,9 @@ class AllAnimeChi : ConfigurableAnimeSource, AnimeHttpSource() {
|
||||
|
||||
private const val PREF_SUB_KEY = "preferred_sub"
|
||||
private const val PREF_SUB_DEFAULT = "sub"
|
||||
|
||||
private const val PREF_USE_HOSTER_NAMES_KEY = "use_host_prefix"
|
||||
private const val PREF_USE_HOSTER_NAMES_DEFAULT = false
|
||||
}
|
||||
|
||||
// ============================== Settings ==============================
|
||||
@ -588,17 +614,6 @@ class AllAnimeChi : ConfigurableAnimeSource, AnimeHttpSource() {
|
||||
}
|
||||
}.also(screen::addPreference)
|
||||
|
||||
SwitchPreferenceCompat(screen.context).apply {
|
||||
key = PREF_REMOVE_RAW_KEY
|
||||
title = "Attempt to filter out raw"
|
||||
setDefaultValue(PREF_REMOVE_RAW_DEFAULT)
|
||||
|
||||
setOnPreferenceChangeListener { _, newValue ->
|
||||
val new = newValue as Boolean
|
||||
preferences.edit().putBoolean(key, new).commit()
|
||||
}
|
||||
}.also(screen::addPreference)
|
||||
|
||||
ListPreference(screen.context).apply {
|
||||
key = PREF_QUALITY_KEY
|
||||
title = "Preferred quality"
|
||||
@ -646,6 +661,28 @@ class AllAnimeChi : ConfigurableAnimeSource, AnimeHttpSource() {
|
||||
preferences.edit().putString(key, entry).commit()
|
||||
}
|
||||
}.also(screen::addPreference)
|
||||
|
||||
SwitchPreferenceCompat(screen.context).apply {
|
||||
key = PREF_REMOVE_RAW_KEY
|
||||
title = "Attempt to filter out raw"
|
||||
setDefaultValue(PREF_REMOVE_RAW_DEFAULT)
|
||||
|
||||
setOnPreferenceChangeListener { _, newValue ->
|
||||
val new = newValue as Boolean
|
||||
preferences.edit().putBoolean(key, new).commit()
|
||||
}
|
||||
}.also(screen::addPreference)
|
||||
|
||||
SwitchPreferenceCompat(screen.context).apply {
|
||||
key = PREF_USE_HOSTER_NAMES_KEY
|
||||
title = "Use names of video hoster"
|
||||
setDefaultValue(PREF_USE_HOSTER_NAMES_DEFAULT)
|
||||
|
||||
setOnPreferenceChangeListener { _, newValue ->
|
||||
val new = newValue as Boolean
|
||||
preferences.edit().putBoolean(key, new).commit()
|
||||
}
|
||||
}.also(screen::addPreference)
|
||||
}
|
||||
|
||||
private val SharedPreferences.subPref
|
||||
@ -668,4 +705,7 @@ class AllAnimeChi : ConfigurableAnimeSource, AnimeHttpSource() {
|
||||
|
||||
private val SharedPreferences.removeRaw
|
||||
get() = getBoolean(PREF_REMOVE_RAW_KEY, PREF_REMOVE_RAW_DEFAULT)
|
||||
|
||||
private val SharedPreferences.useHosterName
|
||||
get() = getBoolean(PREF_USE_HOSTER_NAMES_KEY, PREF_USE_HOSTER_NAMES_DEFAULT)
|
||||
}
|
||||
|
@ -9,11 +9,13 @@ import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.json.Json
|
||||
import okhttp3.Headers
|
||||
import okhttp3.HttpUrl.Companion.toHttpUrl
|
||||
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Response
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.util.Locale
|
||||
|
||||
class InternalExtractor(private val client: OkHttpClient, private val apiHeaders: Headers) {
|
||||
class InternalExtractor(private val client: OkHttpClient, private val apiHeaders: Headers, private val headers: Headers) {
|
||||
|
||||
private val blogUrl = "aHR0cHM6Ly9ibG9nLmFsbGFuaW1lLnBybw==".decodeBase64()
|
||||
|
||||
@ -22,11 +24,11 @@ class InternalExtractor(private val client: OkHttpClient, private val apiHeaders
|
||||
"Dalvik/2.1.0 (Linux; U; Android 13; Pixel 5 Build/TQ3A.230705.001.B4)",
|
||||
)
|
||||
|
||||
private val playlistUtils by lazy { PlaylistUtils(client, playlistHeaders) }
|
||||
private val playlistUtils by lazy { PlaylistUtils(client, headers) }
|
||||
|
||||
private val json: Json by injectLazy()
|
||||
|
||||
fun videosFromServer(server: AllAnimeChi.Server, removeRaw: Boolean): List<Pair<Video, Float>> {
|
||||
fun videosFromServer(server: AllAnimeChi.Server, useHosterName: Boolean, removeRaw: Boolean): List<Pair<Video, Float>> {
|
||||
val blogHeaders = apiHeaders.newBuilder().apply {
|
||||
set("host", blogUrl.toHttpUrl().host)
|
||||
}.build()
|
||||
@ -37,8 +39,8 @@ class InternalExtractor(private val client: OkHttpClient, private val apiHeaders
|
||||
|
||||
val videoList = videoData.links.flatMap {
|
||||
when {
|
||||
it.hls == true -> getFromHls(server, it, removeRaw)
|
||||
it.mp4 == true -> getFromMp4(server, it)
|
||||
it.hls == true -> getFromHls(server, it, useHosterName, removeRaw)
|
||||
it.mp4 == true -> getFromMp4(server, it, useHosterName)
|
||||
else -> emptyList()
|
||||
}
|
||||
}
|
||||
@ -46,20 +48,26 @@ class InternalExtractor(private val client: OkHttpClient, private val apiHeaders
|
||||
return videoList
|
||||
}
|
||||
|
||||
private fun getFromMp4(server: AllAnimeChi.Server, data: VideoData.LinkObject): List<Pair<Video, Float>> {
|
||||
val baseName = "${server.sourceName} - ${data.resolutionStr}"
|
||||
private fun getFromMp4(server: AllAnimeChi.Server, data: VideoData.LinkObject, useHosterName: Boolean): List<Pair<Video, Float>> {
|
||||
val host = if (useHosterName) getHostName(data.link, server.sourceName) else server.sourceName
|
||||
|
||||
val baseName = "$host - ${data.resolutionStr}"
|
||||
val video = Video(data.link, baseName, data.link, headers = playlistHeaders)
|
||||
return listOf(
|
||||
Pair(video, server.priority),
|
||||
)
|
||||
}
|
||||
|
||||
private fun getFromHls(server: AllAnimeChi.Server, data: VideoData.LinkObject, removeRaw: Boolean): List<Pair<Video, Float>> {
|
||||
private fun getFromHls(server: AllAnimeChi.Server, data: VideoData.LinkObject, useHosterName: Boolean, removeRaw: Boolean): List<Pair<Video, Float>> {
|
||||
if (removeRaw && data.resolutionStr.contains("raw", true)) return emptyList()
|
||||
val host = if (useHosterName) getHostName(data.link, server.sourceName) else server.sourceName
|
||||
|
||||
val linkHost = data.link.toHttpUrl().host
|
||||
|
||||
// Doesn't seem to work
|
||||
if (server.sourceName.equals("Luf-mp4", true) && linkHost.contains("maverickki")) return emptyList()
|
||||
if (server.sourceName.equals("Luf-mp4", true)) {
|
||||
return getFromGogo(server, data, host)
|
||||
}
|
||||
|
||||
// Hardcode some names
|
||||
val baseName = if (linkHost.contains("crunchyroll")) {
|
||||
@ -73,8 +81,7 @@ class InternalExtractor(private val client: OkHttpClient, private val apiHeaders
|
||||
.replace("vo_SUB", "Sub")
|
||||
.replace("SUB", "Sub")
|
||||
} else {
|
||||
"${server.sourceName} - ${data.resolutionStr}"
|
||||
.replace("Luf-mp4", "Luf-mp4 (gogo)")
|
||||
"$host - ${data.resolutionStr}"
|
||||
}
|
||||
|
||||
// Get stuff
|
||||
@ -91,7 +98,7 @@ class InternalExtractor(private val client: OkHttpClient, private val apiHeaders
|
||||
|
||||
val videoList = playlistUtils.extractFromHls(
|
||||
data.link,
|
||||
videoNameGen = { q -> "$baseName - $q" },
|
||||
videoNameGen = { q -> "$baseName - ${data.resolutionStr} - $q" },
|
||||
masterHeadersGen = { _, _ -> masterHeaders },
|
||||
)
|
||||
|
||||
@ -100,8 +107,33 @@ class InternalExtractor(private val client: OkHttpClient, private val apiHeaders
|
||||
}
|
||||
}
|
||||
|
||||
private fun getFromGogo(server: AllAnimeChi.Server, data: VideoData.LinkObject, hostName: String): List<Pair<Video, Float>> {
|
||||
val host = data.link.toHttpUrl().host
|
||||
|
||||
// Seems to be dead
|
||||
if (host.contains("maverickki", true)) return emptyList()
|
||||
|
||||
val videoList = playlistUtils.extractFromHls(
|
||||
data.link,
|
||||
videoNameGen = { q -> "$hostName - ${data.resolutionStr} - $q" },
|
||||
referer = "https://playtaku.net/",
|
||||
)
|
||||
|
||||
return videoList.map {
|
||||
Pair(it, server.priority)
|
||||
}
|
||||
}
|
||||
|
||||
// ============================= Utilities ==============================
|
||||
|
||||
private fun getHostName(host: String, fallback: String): String {
|
||||
return host.toHttpUrlOrNull()?.host?.split(".")?.let {
|
||||
it.getOrNull(it.size - 2)?.replaceFirstChar { c ->
|
||||
if (c.isLowerCase()) c.titlecase(Locale.ROOT) else c.toString()
|
||||
}
|
||||
} ?: fallback
|
||||
}
|
||||
|
||||
@Serializable
|
||||
data class VideoData(
|
||||
val links: List<LinkObject>,
|
||||
|
Loading…
x
Reference in New Issue
Block a user