fix(it/animeunity): Update playlist name, remove no longer existent URL
argument, fix file name without proper extension (#2694)
This commit is contained in:
parent
328b0daff1
commit
d6d20c08ee
@ -6,7 +6,7 @@ ext {
|
|||||||
extName = 'AnimeUnity'
|
extName = 'AnimeUnity'
|
||||||
pkgNameSuffix = 'it.animeunity'
|
pkgNameSuffix = 'it.animeunity'
|
||||||
extClass = '.AnimeUnity'
|
extClass = '.AnimeUnity'
|
||||||
extVersionCode = 6
|
extVersionCode = 7
|
||||||
libVersion = '13'
|
libVersion = '13'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,8 +36,9 @@ import uy.kohesive.injekt.injectLazy
|
|||||||
import java.lang.Exception
|
import java.lang.Exception
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
|
|
||||||
class AnimeUnity : ConfigurableAnimeSource, AnimeHttpSource() {
|
class AnimeUnity :
|
||||||
|
AnimeHttpSource(),
|
||||||
|
ConfigurableAnimeSource {
|
||||||
override val name = "AnimeUnity"
|
override val name = "AnimeUnity"
|
||||||
|
|
||||||
override val baseUrl by lazy { preferences.getString(PREF_DOMAIN_KEY, PREF_DOMAIN_DEFAULT)!! }
|
override val baseUrl by lazy { preferences.getString(PREF_DOMAIN_KEY, PREF_DOMAIN_DEFAULT)!! }
|
||||||
@ -56,17 +57,19 @@ class AnimeUnity : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||||||
|
|
||||||
// ============================== Popular ===============================
|
// ============================== Popular ===============================
|
||||||
|
|
||||||
override fun popularAnimeRequest(page: Int): Request =
|
override fun popularAnimeRequest(page: Int): Request = GET("$baseUrl/top-anime?popular=true&page=$page", headers = headers)
|
||||||
GET("$baseUrl/top-anime?popular=true&page=$page", headers = headers)
|
|
||||||
|
|
||||||
override fun popularAnimeParse(response: Response): AnimesPage {
|
override fun popularAnimeParse(response: Response): AnimesPage {
|
||||||
val parsed = response.parseAs<AnimeResponse> {
|
val parsed =
|
||||||
it.substringAfter("top-anime animes=\"")
|
response.parseAs<AnimeResponse> {
|
||||||
|
it
|
||||||
|
.substringAfter("top-anime animes=\"")
|
||||||
.substringBefore("\"></top-anime>")
|
.substringBefore("\"></top-anime>")
|
||||||
.replace(""", "\"")
|
.replace(""", "\"")
|
||||||
}
|
}
|
||||||
|
|
||||||
val animeList = parsed.data.map { ani ->
|
val animeList =
|
||||||
|
parsed.data.map { ani ->
|
||||||
SAnime.create().apply {
|
SAnime.create().apply {
|
||||||
title = ani.title_eng
|
title = ani.title_eng
|
||||||
url = "${ani.id}-${ani.slug}"
|
url = "${ani.id}-${ani.slug}"
|
||||||
@ -84,7 +87,8 @@ class AnimeUnity : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||||||
override fun latestUpdatesParse(response: Response): AnimesPage {
|
override fun latestUpdatesParse(response: Response): AnimesPage {
|
||||||
val document = response.asJsoup()
|
val document = response.asJsoup()
|
||||||
|
|
||||||
val animeList = document.select("div.home-wrapper-body > div.row > div.latest-anime-container").map {
|
val animeList =
|
||||||
|
document.select("div.home-wrapper-body > div.row > div.latest-anime-container").map {
|
||||||
SAnime.create().apply {
|
SAnime.create().apply {
|
||||||
title = it.select("a > strong").text()
|
title = it.select("a > strong").text()
|
||||||
url = it.selectFirst("a")!!.attr("href").substringAfter("/anime/")
|
url = it.selectFirst("a")!!.attr("href").substringAfter("/anime/")
|
||||||
@ -99,19 +103,34 @@ class AnimeUnity : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||||||
|
|
||||||
// =============================== Search ===============================
|
// =============================== Search ===============================
|
||||||
|
|
||||||
override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request = throw Exception("Not used")
|
override fun searchAnimeRequest(
|
||||||
|
page: Int,
|
||||||
|
query: String,
|
||||||
|
filters: AnimeFilterList,
|
||||||
|
): Request = throw Exception("Not used")
|
||||||
|
|
||||||
override fun fetchSearchAnime(page: Int, query: String, filters: AnimeFilterList): Observable<AnimesPage> {
|
override fun fetchSearchAnime(
|
||||||
|
page: Int,
|
||||||
|
query: String,
|
||||||
|
filters: AnimeFilterList,
|
||||||
|
): Observable<AnimesPage> {
|
||||||
val params = AnimeUnityFilters.getSearchParameters(filters)
|
val params = AnimeUnityFilters.getSearchParameters(filters)
|
||||||
return client.newCall(searchAnimeRequest(page, query, params))
|
return client
|
||||||
|
.newCall(searchAnimeRequest(page, query, params))
|
||||||
.asObservableSuccess()
|
.asObservableSuccess()
|
||||||
.map { response ->
|
.map { response ->
|
||||||
searchAnimeParse(response, page)
|
searchAnimeParse(response, page)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun searchAnimeRequest(page: Int, query: String, filters: AnimeUnityFilters.FilterSearchParams): Request {
|
private fun searchAnimeRequest(
|
||||||
val archivioResponse = client.newCall(
|
page: Int,
|
||||||
|
query: String,
|
||||||
|
filters: AnimeUnityFilters.FilterSearchParams,
|
||||||
|
): Request {
|
||||||
|
val archivioResponse =
|
||||||
|
client
|
||||||
|
.newCall(
|
||||||
GET("$baseUrl/archivio", headers = headers),
|
GET("$baseUrl/archivio", headers = headers),
|
||||||
).execute()
|
).execute()
|
||||||
|
|
||||||
@ -121,25 +140,36 @@ class AnimeUnity : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||||||
var newHeadersBuilder = headers.newBuilder()
|
var newHeadersBuilder = headers.newBuilder()
|
||||||
for (cookie in archivioResponse.headers) {
|
for (cookie in archivioResponse.headers) {
|
||||||
if (cookie.first == "set-cookie" && cookie.second.startsWith("XSRF-TOKEN")) {
|
if (cookie.first == "set-cookie" && cookie.second.startsWith("XSRF-TOKEN")) {
|
||||||
newHeadersBuilder.add("X-XSRF-TOKEN", cookie.second.substringAfter("=").substringBefore(";").replace("%3D", "="))
|
newHeadersBuilder.add(
|
||||||
|
"X-XSRF-TOKEN",
|
||||||
|
cookie
|
||||||
|
.second
|
||||||
|
.substringAfter("=")
|
||||||
|
.substringBefore(";")
|
||||||
|
.replace("%3D", "="),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cookie.first == "set-cookie" && cookie.second.startsWith("animeunity_session")) {
|
if (cookie.first == "set-cookie" && cookie.second.startsWith("animeunity_session")) {
|
||||||
newHeadersBuilder.add("Cookie", cookie.second.substringBefore(";").replace("%3D", "="))
|
newHeadersBuilder.add("Cookie", cookie.second.substringBefore(";").replace("%3D", "="))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
newHeadersBuilder.add("X-CSRF-TOKEN", crsfToken)
|
newHeadersBuilder
|
||||||
|
.add("X-CSRF-TOKEN", crsfToken)
|
||||||
.add("Accept-Language", "en-US,en;q=0.5")
|
.add("Accept-Language", "en-US,en;q=0.5")
|
||||||
.add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:101.0) Gecko/20100101 Firefox/101.0")
|
.add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:101.0) Gecko/20100101 Firefox/101.0")
|
||||||
|
|
||||||
if (filters.top.isNotEmpty()) {
|
if (filters.top.isNotEmpty()) {
|
||||||
val topHeaders = newHeadersBuilder.add("X-CSRF-TOKEN", crsfToken)
|
val topHeaders =
|
||||||
|
newHeadersBuilder
|
||||||
|
.add("X-CSRF-TOKEN", crsfToken)
|
||||||
.add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8")
|
.add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8")
|
||||||
.add("Referer", "$baseUrl/${filters.top}")
|
.add("Referer", "$baseUrl/${filters.top}")
|
||||||
return GET("$baseUrl/${filters.top}", headers = topHeaders.build())
|
return GET("$baseUrl/${filters.top}", headers = topHeaders.build())
|
||||||
}
|
}
|
||||||
|
|
||||||
val searchHeaders = newHeadersBuilder
|
val searchHeaders =
|
||||||
|
newHeadersBuilder
|
||||||
.add("Accept", "application/json, text/plain, */*")
|
.add("Accept", "application/json, text/plain, */*")
|
||||||
.add("Content-Type", "application/json;charset=utf-8")
|
.add("Content-Type", "application/json;charset=utf-8")
|
||||||
.add("Origin", baseUrl)
|
.add("Origin", baseUrl)
|
||||||
@ -147,7 +177,8 @@ class AnimeUnity : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||||||
.add("X-Requested-With", "XMLHttpRequest")
|
.add("X-Requested-With", "XMLHttpRequest")
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
val body = """
|
val body =
|
||||||
|
"""
|
||||||
{
|
{
|
||||||
"title": ${query.falseIfEmpty()},
|
"title": ${query.falseIfEmpty()},
|
||||||
"type": ${filters.type.falseIfEmpty()},
|
"type": ${filters.type.falseIfEmpty()},
|
||||||
@ -166,11 +197,15 @@ class AnimeUnity : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||||||
|
|
||||||
override fun searchAnimeParse(response: Response): AnimesPage = throw Exception("Not used")
|
override fun searchAnimeParse(response: Response): AnimesPage = throw Exception("Not used")
|
||||||
|
|
||||||
private fun searchAnimeParse(response: Response, page: Int): AnimesPage {
|
private fun searchAnimeParse(
|
||||||
return if (response.request.method == "POST") {
|
response: Response,
|
||||||
|
page: Int,
|
||||||
|
): AnimesPage =
|
||||||
|
if (response.request.method == "POST") {
|
||||||
val data = response.parseAs<SearchResponse>()
|
val data = response.parseAs<SearchResponse>()
|
||||||
|
|
||||||
val animeList = data.records.map {
|
val animeList =
|
||||||
|
data.records.map {
|
||||||
SAnime.create().apply {
|
SAnime.create().apply {
|
||||||
title = it.title_eng
|
title = it.title_eng
|
||||||
thumbnail_url = it.imageurl
|
thumbnail_url = it.imageurl
|
||||||
@ -182,7 +217,6 @@ class AnimeUnity : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||||||
} else {
|
} else {
|
||||||
popularAnimeParse(response)
|
popularAnimeParse(response)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
override fun getFilterList(): AnimeFilterList = AnimeUnityFilters.FILTER_LIST
|
override fun getFilterList(): AnimeFilterList = AnimeUnityFilters.FILTER_LIST
|
||||||
|
|
||||||
@ -195,7 +229,8 @@ class AnimeUnity : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||||||
|
|
||||||
val videoPlayer = document.selectFirst("video-player[episodes_count]")!!
|
val videoPlayer = document.selectFirst("video-player[episodes_count]")!!
|
||||||
|
|
||||||
val animeDetails = json.decodeFromString<AnimeInfo>(
|
val animeDetails =
|
||||||
|
json.decodeFromString<AnimeInfo>(
|
||||||
videoPlayer.attr("anime").replace(""", "\""),
|
videoPlayer.attr("anime").replace(""", "\""),
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -204,7 +239,8 @@ class AnimeUnity : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||||||
status = parseStatus(animeDetails.status)
|
status = parseStatus(animeDetails.status)
|
||||||
artist = animeDetails.studio ?: ""
|
artist = animeDetails.studio ?: ""
|
||||||
genre = animeDetails.genres.joinToString(", ") { it.name }
|
genre = animeDetails.genres.joinToString(", ") { it.name }
|
||||||
description = buildString {
|
description =
|
||||||
|
buildString {
|
||||||
append(animeDetails.plot)
|
append(animeDetails.plot)
|
||||||
append("\n\nTipo: ${animeDetails.type}")
|
append("\n\nTipo: ${animeDetails.type}")
|
||||||
append("\nStagione: ${animeDetails.season} ${animeDetails.date}")
|
append("\nStagione: ${animeDetails.season} ${animeDetails.date}")
|
||||||
@ -225,14 +261,22 @@ class AnimeUnity : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||||||
var newHeadersBuilder = headers.newBuilder()
|
var newHeadersBuilder = headers.newBuilder()
|
||||||
for (cookie in response.headers) {
|
for (cookie in response.headers) {
|
||||||
if (cookie.first == "set-cookie" && cookie.second.startsWith("XSRF-TOKEN")) {
|
if (cookie.first == "set-cookie" && cookie.second.startsWith("XSRF-TOKEN")) {
|
||||||
newHeadersBuilder.add("X-XSRF-TOKEN", cookie.second.substringAfter("=").substringBefore(";").replace("%3D", "="))
|
newHeadersBuilder.add(
|
||||||
|
"X-XSRF-TOKEN",
|
||||||
|
cookie
|
||||||
|
.second
|
||||||
|
.substringAfter("=")
|
||||||
|
.substringBefore(";")
|
||||||
|
.replace("%3D", "="),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cookie.first == "set-cookie" && cookie.second.startsWith("animeunity_session")) {
|
if (cookie.first == "set-cookie" && cookie.second.startsWith("animeunity_session")) {
|
||||||
newHeadersBuilder.add("Cookie", cookie.second.substringBefore(";").replace("%3D", "="))
|
newHeadersBuilder.add("Cookie", cookie.second.substringBefore(";").replace("%3D", "="))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
newHeadersBuilder.add("X-CSRF-TOKEN", crsfToken)
|
newHeadersBuilder
|
||||||
|
.add("X-CSRF-TOKEN", crsfToken)
|
||||||
.add("Content-Type", "application/json")
|
.add("Content-Type", "application/json")
|
||||||
.add("Referer", response.request.url.toString())
|
.add("Referer", response.request.url.toString())
|
||||||
.add("Accept", "application/json, text/plain, */*")
|
.add("Accept", "application/json, text/plain, */*")
|
||||||
@ -242,14 +286,22 @@ class AnimeUnity : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||||||
|
|
||||||
val videoPlayer = document.selectFirst("video-player[episodes_count]")!!
|
val videoPlayer = document.selectFirst("video-player[episodes_count]")!!
|
||||||
val episodeCount = videoPlayer.attr("episodes_count").toInt()
|
val episodeCount = videoPlayer.attr("episodes_count").toInt()
|
||||||
val animeId = response.request.url.toString().substringAfter("/anime/").substringBefore("-")
|
val animeId =
|
||||||
|
response
|
||||||
|
.request
|
||||||
|
.url
|
||||||
|
.toString()
|
||||||
|
.substringAfter("/anime/")
|
||||||
|
.substringBefore("-")
|
||||||
|
|
||||||
val episodes = json.decodeFromString<List<Episode>>(
|
val episodes =
|
||||||
|
json.decodeFromString<List<Episode>>(
|
||||||
videoPlayer.attr("episodes").replace(""", "\""),
|
videoPlayer.attr("episodes").replace(""", "\""),
|
||||||
)
|
)
|
||||||
|
|
||||||
episodeList.addAll(
|
episodeList.addAll(
|
||||||
episodes.filter {
|
episodes
|
||||||
|
.filter {
|
||||||
it.id != null
|
it.id != null
|
||||||
}.map {
|
}.map {
|
||||||
SEpisode.create().apply {
|
SEpisode.create().apply {
|
||||||
@ -257,7 +309,10 @@ class AnimeUnity : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||||||
date_upload = parseDate(it.created_at)
|
date_upload = parseDate(it.created_at)
|
||||||
episode_number = it.number.split("-")[0].toFloatOrNull() ?: 0F
|
episode_number = it.number.split("-")[0].toFloatOrNull() ?: 0F
|
||||||
setUrlWithoutDomain(
|
setUrlWithoutDomain(
|
||||||
response.request.url.newBuilder()
|
response
|
||||||
|
.request
|
||||||
|
.url
|
||||||
|
.newBuilder()
|
||||||
.addPathSegment(it.id.toString())
|
.addPathSegment(it.id.toString())
|
||||||
.toString(),
|
.toString(),
|
||||||
)
|
)
|
||||||
@ -291,46 +346,64 @@ class AnimeUnity : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||||||
|
|
||||||
override fun fetchVideoList(episode: SEpisode): Observable<List<Video>> {
|
override fun fetchVideoList(episode: SEpisode): Observable<List<Video>> {
|
||||||
val videoList = mutableListOf<Video>()
|
val videoList = mutableListOf<Video>()
|
||||||
|
val doc =
|
||||||
val doc = client.newCall(
|
client
|
||||||
|
.newCall(
|
||||||
GET(baseUrl + episode.url, headers),
|
GET(baseUrl + episode.url, headers),
|
||||||
).execute().asJsoup()
|
).execute()
|
||||||
val iframeUrl = doc.selectFirst("video-player[embed_url]")?.attr("abs:embed_url") ?: error("Failed to extract iframe")
|
.asJsoup()
|
||||||
|
val iframeUrl =
|
||||||
val iframeHeaders = headers.newBuilder()
|
doc.selectFirst("video-player[embed_url]")?.attr("abs:embed_url")
|
||||||
|
?: error("Failed to extract iframe")
|
||||||
|
val iframeHeaders =
|
||||||
|
headers
|
||||||
|
.newBuilder()
|
||||||
.add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8")
|
.add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8")
|
||||||
.add("Host", iframeUrl.toHttpUrl().host)
|
.add("Host", iframeUrl.toHttpUrl().host)
|
||||||
.add("Referer", "$baseUrl/")
|
.add("Referer", "$baseUrl/")
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
val iframe = client.newCall(
|
val iframe =
|
||||||
|
client
|
||||||
|
.newCall(
|
||||||
GET(iframeUrl, headers = iframeHeaders),
|
GET(iframeUrl, headers = iframeHeaders),
|
||||||
).execute().asJsoup()
|
).execute()
|
||||||
val script = iframe.selectFirst("script:containsData(masterPlaylistParams)")!!.data()
|
.asJsoup()
|
||||||
|
val scripts = iframe.select("script")
|
||||||
|
val script = scripts.find { it.data().contains("masterPlaylist") }!!.data().replace("\n", "\t")
|
||||||
|
var playlistUrl = Regex("""url: ?'(.*?)'""").find(script)!!.groupValues[1]
|
||||||
|
val filename = playlistUrl.slice(playlistUrl.lastIndexOf("/") + 1 until playlistUrl.length)
|
||||||
|
if (!filename.endsWith(".m3u8")) {
|
||||||
|
playlistUrl = playlistUrl.replace(filename, filename + ".m3u8")
|
||||||
|
}
|
||||||
|
|
||||||
val playlistUrl = Regex("""masterPlaylistUrl.*?'(.*?)'""").find(script)!!.groupValues[1]
|
|
||||||
val expires = Regex("""'expires': ?'(\d+)'""").find(script)!!.groupValues[1]
|
val expires = Regex("""'expires': ?'(\d+)'""").find(script)!!.groupValues[1]
|
||||||
val canCast = Regex("""'canCast': ?'(\d*)'""").find(script)!!.groupValues[1]
|
|
||||||
val token = Regex("""'token': ?'([\w-]+)'""").find(script)!!.groupValues[1]
|
val token = Regex("""'token': ?'([\w-]+)'""").find(script)!!.groupValues[1]
|
||||||
|
|
||||||
// Get subtitles
|
// Get subtitles
|
||||||
val masterPlUrl = "$playlistUrl?token=$token&expires=$expires&canCast=$canCast&n=1"
|
val masterPlUrl = "$playlistUrl?token=$token&expires=$expires&n=1"
|
||||||
val masterPl = client.newCall(GET(masterPlUrl)).execute().body.string()
|
val masterPl =
|
||||||
val subList = Regex("""#EXT-X-MEDIA:TYPE=SUBTITLES.*?NAME="(.*?)".*?URI="(.*?)"""").findAll(masterPl).map {
|
client
|
||||||
|
.newCall(GET(masterPlUrl))
|
||||||
|
.execute()
|
||||||
|
.body
|
||||||
|
.string()
|
||||||
|
val subList =
|
||||||
|
Regex("""#EXT-X-MEDIA:TYPE=SUBTITLES.*?NAME="(.*?)".*?URI="(.*?)"""")
|
||||||
|
.findAll(masterPl)
|
||||||
|
.map {
|
||||||
Track(it.groupValues[2], it.groupValues[1])
|
Track(it.groupValues[2], it.groupValues[1])
|
||||||
}.toList()
|
}.toList()
|
||||||
|
|
||||||
Regex("""'token(\d+p?)': ?'([\w-]+)'""").findAll(script).forEach { match ->
|
Regex("""'token(\d+p?)': ?'([\w-]+)'""").findAll(script).forEach { match ->
|
||||||
val quality = match.groupValues[1]
|
val quality = match.groupValues[1]
|
||||||
|
|
||||||
val videoUrl = buildString {
|
val videoUrl =
|
||||||
|
buildString {
|
||||||
append(playlistUrl)
|
append(playlistUrl)
|
||||||
append("?type=video&rendition=")
|
append("?type=video&rendition=")
|
||||||
append(quality)
|
append(quality)
|
||||||
append("&token=")
|
append("&token=")
|
||||||
append(match.groupValues[2])
|
append(match.groupValues[2])
|
||||||
append("&expires=$expires")
|
append("&expires=$expires")
|
||||||
append("&canCast=$canCast")
|
|
||||||
append("&n=1")
|
append("&n=1")
|
||||||
}
|
}
|
||||||
videoList.add(Video(videoUrl, quality, videoUrl, subtitleTracks = subList))
|
videoList.add(Video(videoUrl, quality, videoUrl, subtitleTracks = subList))
|
||||||
@ -352,18 +425,29 @@ class AnimeUnity : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||||||
return json.decodeFromString(responseBody)
|
return json.decodeFromString(responseBody)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun parseStatus(statusString: String): Int = when (statusString) {
|
private fun parseStatus(statusString: String): Int =
|
||||||
|
when (statusString) {
|
||||||
"In Corso" -> SAnime.ONGOING
|
"In Corso" -> SAnime.ONGOING
|
||||||
"Terminato" -> SAnime.COMPLETED
|
"Terminato" -> SAnime.COMPLETED
|
||||||
else -> SAnime.UNKNOWN
|
else -> SAnime.UNKNOWN
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun addFromApi(start: Int, end: Int, animeId: String, headers: Headers, url: HttpUrl): List<SEpisode> {
|
private fun addFromApi(
|
||||||
val response = client.newCall(
|
start: Int,
|
||||||
|
end: Int,
|
||||||
|
animeId: String,
|
||||||
|
headers: Headers,
|
||||||
|
url: HttpUrl,
|
||||||
|
): List<SEpisode> {
|
||||||
|
val response =
|
||||||
|
client
|
||||||
|
.newCall(
|
||||||
GET("$baseUrl/info_api/$animeId/1?start_range=$start&end_range=$end", headers = headers),
|
GET("$baseUrl/info_api/$animeId/1?start_range=$start&end_range=$end", headers = headers),
|
||||||
).execute()
|
).execute()
|
||||||
val json = response.parseAs<ApiResponse>()
|
val json = response.parseAs<ApiResponse>()
|
||||||
return json.episodes.filter {
|
return json
|
||||||
|
.episodes
|
||||||
|
.filter {
|
||||||
it.id != null
|
it.id != null
|
||||||
}.map {
|
}.map {
|
||||||
SEpisode.create().apply {
|
SEpisode.create().apply {
|
||||||
@ -371,7 +455,8 @@ class AnimeUnity : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||||||
date_upload = parseDate(it.created_at)
|
date_upload = parseDate(it.created_at)
|
||||||
episode_number = it.number.split("-")[0].toFloatOrNull() ?: 0F
|
episode_number = it.number.split("-")[0].toFloatOrNull() ?: 0F
|
||||||
setUrlWithoutDomain(
|
setUrlWithoutDomain(
|
||||||
url.newBuilder()
|
url
|
||||||
|
.newBuilder()
|
||||||
.addPathSegment(it.id.toString())
|
.addPathSegment(it.id.toString())
|
||||||
.toString(),
|
.toString(),
|
||||||
)
|
)
|
||||||
@ -379,7 +464,8 @@ class AnimeUnity : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun String.falseIfEmpty(): String = if (this.isEmpty()) {
|
private fun String.falseIfEmpty(): String =
|
||||||
|
if (this.isEmpty()) {
|
||||||
"false"
|
"false"
|
||||||
} else {
|
} else {
|
||||||
"\"${this}\""
|
"\"${this}\""
|
||||||
@ -404,7 +490,8 @@ class AnimeUnity : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||||||
override fun List<Video>.sort(): List<Video> {
|
override fun List<Video>.sort(): List<Video> {
|
||||||
val quality = preferences.getString(PREF_QUALITY_KEY, PREF_QUALITY_DEFAULT)!!
|
val quality = preferences.getString(PREF_QUALITY_KEY, PREF_QUALITY_DEFAULT)!!
|
||||||
|
|
||||||
return this.sortedWith(
|
return this
|
||||||
|
.sortedWith(
|
||||||
compareBy(
|
compareBy(
|
||||||
{ it.quality.contains(quality) },
|
{ it.quality.contains(quality) },
|
||||||
{ it.quality.substringBefore("p").toIntOrNull() ?: 0 },
|
{ it.quality.substringBefore("p").toIntOrNull() ?: 0 },
|
||||||
@ -425,7 +512,8 @@ class AnimeUnity : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||||||
// ============================== Settings ==============================
|
// ============================== Settings ==============================
|
||||||
|
|
||||||
override fun setupPreferenceScreen(screen: PreferenceScreen) {
|
override fun setupPreferenceScreen(screen: PreferenceScreen) {
|
||||||
EditTextPreference(screen.context).apply {
|
EditTextPreference(screen.context)
|
||||||
|
.apply {
|
||||||
key = PREF_DOMAIN_KEY
|
key = PREF_DOMAIN_KEY
|
||||||
title = PREF_DOMAIN_TITLE
|
title = PREF_DOMAIN_TITLE
|
||||||
summary = PREF_DOMAIN_SUMMARY
|
summary = PREF_DOMAIN_SUMMARY
|
||||||
@ -440,7 +528,8 @@ class AnimeUnity : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||||||
}
|
}
|
||||||
}.also(screen::addPreference)
|
}.also(screen::addPreference)
|
||||||
|
|
||||||
ListPreference(screen.context).apply {
|
ListPreference(screen.context)
|
||||||
|
.apply {
|
||||||
key = PREF_QUALITY_KEY
|
key = PREF_QUALITY_KEY
|
||||||
title = "Preferred quality"
|
title = "Preferred quality"
|
||||||
entries = arrayOf("1080p", "720p", "480p", "360p", "240p", "80p")
|
entries = arrayOf("1080p", "720p", "480p", "360p", "240p", "80p")
|
||||||
|
Loading…
x
Reference in New Issue
Block a user