fix(en/marinmoe): Sort video qualities (#1709)
This commit is contained in:
parent
7464a5e1bb
commit
46b362c6ec
@ -6,7 +6,7 @@ ext {
|
|||||||
extName = 'marin.moe'
|
extName = 'marin.moe'
|
||||||
pkgNameSuffix = 'en.marinmoe'
|
pkgNameSuffix = 'en.marinmoe'
|
||||||
extClass = '.MarinMoe'
|
extClass = '.MarinMoe'
|
||||||
extVersionCode = 7
|
extVersionCode = 8
|
||||||
libVersion = '13'
|
libVersion = '13'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ import eu.kanade.tachiyomi.network.POST
|
|||||||
import eu.kanade.tachiyomi.network.asObservableSuccess
|
import eu.kanade.tachiyomi.network.asObservableSuccess
|
||||||
import eu.kanade.tachiyomi.util.asJsoup
|
import eu.kanade.tachiyomi.util.asJsoup
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
|
import okhttp3.HttpUrl.Companion.toHttpUrl
|
||||||
import okhttp3.MediaType.Companion.toMediaType
|
import okhttp3.MediaType.Companion.toMediaType
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
import okhttp3.Request
|
import okhttp3.Request
|
||||||
@ -32,7 +32,6 @@ import uy.kohesive.injekt.injectLazy
|
|||||||
import java.lang.Exception
|
import java.lang.Exception
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
import kotlin.collections.ArrayList
|
|
||||||
|
|
||||||
class MarinMoe : ConfigurableAnimeSource, AnimeHttpSource() {
|
class MarinMoe : ConfigurableAnimeSource, AnimeHttpSource() {
|
||||||
|
|
||||||
@ -59,24 +58,20 @@ class MarinMoe : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||||||
|
|
||||||
// ============================== Popular ===============================
|
// ============================== Popular ===============================
|
||||||
|
|
||||||
override fun popularAnimeParse(response: Response): AnimesPage {
|
override fun popularAnimeRequest(page: Int): Request = GET("$baseUrl/anime?sort=vwk-d&page=$page", headers)
|
||||||
return parseAnime(response)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun popularAnimeRequest(page: Int): Request {
|
override fun popularAnimeParse(response: Response): AnimesPage = parseAnime(response)
|
||||||
return GET("$baseUrl/anime?sort=vwk-d&page=$page", headers = headers)
|
|
||||||
}
|
|
||||||
|
|
||||||
// =============================== Latest ===============================
|
// =============================== Latest ===============================
|
||||||
|
|
||||||
override fun latestUpdatesParse(response: Response): AnimesPage {
|
override fun latestUpdatesRequest(page: Int): Request = GET("$baseUrl/anime?sort=rel-d&page=$page", headers)
|
||||||
return parseAnime(response)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun latestUpdatesRequest(page: Int): Request = GET("$baseUrl/anime?sort=rel-d&page=$page")
|
override fun latestUpdatesParse(response: Response): AnimesPage = parseAnime(response)
|
||||||
|
|
||||||
// =============================== Search ===============================
|
// =============================== Search ===============================
|
||||||
|
|
||||||
|
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 = MarinMoeFilters.getSearchParameters(filters)
|
val params = MarinMoeFilters.getSearchParameters(filters)
|
||||||
return client.newCall(searchAnimeRequest(page, query, params))
|
return client.newCall(searchAnimeRequest(page, query, params))
|
||||||
@ -86,10 +81,8 @@ class MarinMoe : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request = throw Exception("Not used")
|
|
||||||
|
|
||||||
private fun searchAnimeRequest(page: Int, query: String, filters: MarinMoeFilters.FilterSearchParams): Request {
|
private fun searchAnimeRequest(page: Int, query: String, filters: MarinMoeFilters.FilterSearchParams): Request {
|
||||||
var url = "$baseUrl/anime".toHttpUrlOrNull()!!.newBuilder()
|
var url = "$baseUrl/anime".toHttpUrl().newBuilder()
|
||||||
.addQueryParameter("sort", filters.sort)
|
.addQueryParameter("sort", filters.sort)
|
||||||
.addQueryParameter("search", query)
|
.addQueryParameter("search", query)
|
||||||
.addQueryParameter("page", page.toString())
|
.addQueryParameter("page", page.toString())
|
||||||
@ -103,12 +96,12 @@ class MarinMoe : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||||||
if (filters.group.isNotBlank()) url += "&filter[group][0][id]=${filters.group}&filter[group][0][opr]=include"
|
if (filters.group.isNotBlank()) url += "&filter[group][0][id]=${filters.group}&filter[group][0][opr]=include"
|
||||||
if (filters.studio.isNotBlank()) url += "&filter[production][0][id]=${filters.studio}&filter[production][0][opr]=include"
|
if (filters.studio.isNotBlank()) url += "&filter[production][0][id]=${filters.studio}&filter[production][0][opr]=include"
|
||||||
|
|
||||||
return GET(url, headers = headers)
|
return GET(url, headers)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun searchAnimeParse(response: Response): AnimesPage {
|
override fun searchAnimeParse(response: Response): AnimesPage = parseAnime(response)
|
||||||
return parseAnime(response)
|
|
||||||
}
|
// ============================== Filters ===============================
|
||||||
|
|
||||||
override fun getFilterList(): AnimeFilterList = MarinMoeFilters.FILTER_LIST
|
override fun getFilterList(): AnimeFilterList = MarinMoeFilters.FILTER_LIST
|
||||||
|
|
||||||
@ -116,27 +109,26 @@ class MarinMoe : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||||||
|
|
||||||
override fun animeDetailsParse(response: Response): SAnime {
|
override fun animeDetailsParse(response: Response): SAnime {
|
||||||
val document = response.asJsoup()
|
val document = response.asJsoup()
|
||||||
val anime = SAnime.create()
|
|
||||||
|
|
||||||
val dataPage = document.select("div#app").attr("data-page").replace(""", "\"")
|
val dataPage = document.select("div#app").attr("data-page").replace(""", "\"")
|
||||||
val details = json.decodeFromString<AnimeDetails>(dataPage).props.anime
|
val details = json.decodeFromString<AnimeDetails>(dataPage).props.anime
|
||||||
|
|
||||||
anime.thumbnail_url = details.cover
|
var desc = Jsoup.parse(
|
||||||
anime.title = details.title
|
|
||||||
anime.genre = details.genre_list.joinToString(", ") { it.name }
|
|
||||||
anime.author = details.production_list.joinToString(", ") { it.name }
|
|
||||||
anime.status = parseStatus(details.status.name)
|
|
||||||
|
|
||||||
var description = Jsoup.parse(
|
|
||||||
details.description.replace("<br />", "br2n"),
|
details.description.replace("<br />", "br2n"),
|
||||||
).text().replace("br2n", "\n") + "\n"
|
).text().replace("br2n", "\n") + "\n"
|
||||||
description += "\nContent Rating: ${details.content_rating.name}"
|
desc += "\nContent Rating: ${details.content_rating.name}"
|
||||||
description += "\nRelease Date: ${details.release_date}"
|
desc += "\nRelease Date: ${details.release_date}"
|
||||||
description += "\nType: ${details.type.name}"
|
desc += "\nType: ${details.type.name}"
|
||||||
description += "\nSource: ${details.source_list.joinToString(separator = ", ") { it.name }}"
|
desc += "\nSource: ${details.source_list.joinToString(separator = ", ") { it.name }}"
|
||||||
anime.description = description
|
|
||||||
|
|
||||||
return anime
|
return SAnime.create().apply {
|
||||||
|
title = details.title
|
||||||
|
thumbnail_url = details.cover
|
||||||
|
genre = details.genre_list.joinToString(", ") { it.name }
|
||||||
|
author = details.production_list.joinToString(", ") { it.name }
|
||||||
|
status = parseStatus(details.status.name)
|
||||||
|
description = desc
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================== Episodes ==============================
|
// ============================== Episodes ==============================
|
||||||
@ -147,19 +139,20 @@ class MarinMoe : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||||||
val dataPage = document.select("div#app").attr("data-page").replace(""", "\"")
|
val dataPage = document.select("div#app").attr("data-page").replace(""", "\"")
|
||||||
|
|
||||||
val dataJson = json.decodeFromString<AnimeDetails>(dataPage)
|
val dataJson = json.decodeFromString<AnimeDetails>(dataPage)
|
||||||
val includeSpecial = preferences.getBoolean("preferred_special", true)
|
val includeSpecial = preferences.getBoolean(PREF_SPECIAL_KEY, PREF_SPECIAL_DEFAULT)
|
||||||
|
|
||||||
dataJson.props.episode_list.data.forEach {
|
dataJson.props.episode_list.data.forEach {
|
||||||
val episode = SEpisode.create()
|
val episode = SEpisode.create().apply {
|
||||||
|
name = "Episode ${it.slug} ${it.title}"
|
||||||
episode.name = "Episode ${it.slug} ${it.title}"
|
episode_number = it.sort
|
||||||
episode.episode_number = it.sort
|
url = "${response.request.url}/${it.slug}"
|
||||||
episode.url = "${response.request.url}/${it.slug}"
|
|
||||||
|
|
||||||
val parsedDate = parseDate(it.release_date)
|
val parsedDate = parseDate(it.release_date)
|
||||||
if (parsedDate.time != -1L) episode.date_upload = parsedDate.time
|
if (parsedDate.time != -1L) date_upload = parsedDate.time
|
||||||
|
}
|
||||||
|
|
||||||
if (includeSpecial || it.type != 2) episodes.add(episode)
|
if (includeSpecial || it.type != 2) {
|
||||||
|
episodes.add(episode)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var next = dataJson.props.episode_list.links.next
|
var next = dataJson.props.episode_list.links.next
|
||||||
@ -170,14 +163,13 @@ class MarinMoe : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||||||
val nextDataJson = json.decodeFromString<AnimeDetails>(nextDataPage)
|
val nextDataJson = json.decodeFromString<AnimeDetails>(nextDataPage)
|
||||||
|
|
||||||
nextDataJson.props.episode_list.data.forEach {
|
nextDataJson.props.episode_list.data.forEach {
|
||||||
val episode = SEpisode.create()
|
val episode = SEpisode.create().apply {
|
||||||
|
name = "Episode ${it.slug} ${it.title}"
|
||||||
episode.name = "Episode ${it.slug} ${it.title}"
|
episode_number = it.sort
|
||||||
episode.episode_number = it.sort
|
url = "${response.request.url}/${it.slug}"
|
||||||
episode.url = "${response.request.url}/${it.slug}"
|
|
||||||
|
|
||||||
val parsedDate = parseDate(it.release_date)
|
val parsedDate = parseDate(it.release_date)
|
||||||
if (parsedDate.time != -1L) episode.date_upload = parsedDate.time
|
if (parsedDate.time != -1L) date_upload = parsedDate.time
|
||||||
|
}
|
||||||
|
|
||||||
episodes.add(episode)
|
episodes.add(episode)
|
||||||
}
|
}
|
||||||
@ -190,9 +182,7 @@ class MarinMoe : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||||||
|
|
||||||
// ============================ Video Links =============================
|
// ============================ Video Links =============================
|
||||||
|
|
||||||
override fun videoListRequest(episode: SEpisode): Request {
|
override fun videoListRequest(episode: SEpisode): Request = GET(episode.url, headers)
|
||||||
return GET(episode.url, headers = headers)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun videoListParse(response: Response): List<Video> {
|
override fun videoListParse(response: Response): List<Video> {
|
||||||
var newHeaders = headers.newBuilder()
|
var newHeaders = headers.newBuilder()
|
||||||
@ -258,14 +248,15 @@ class MarinMoe : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||||||
// ============================= Utilities ==============================
|
// ============================= Utilities ==============================
|
||||||
|
|
||||||
private fun prioritySort(pList: List<Pair<Video, Float>>): List<Video> {
|
private fun prioritySort(pList: List<Pair<Video, Float>>): List<Video> {
|
||||||
val prefGroup = preferences.getString("preferred_group", "site_default")!!
|
val prefGroup = preferences.getString(PREF_GROUP_KEY, PREF_GROUP_DEFAULT)!!
|
||||||
val quality = preferences.getString("preferred_quality", "1080")!!
|
val quality = preferences.getString(PREF_QUALITY_KEY, PREF_QUALITY_DEFAULT)!!
|
||||||
val subOrDub = preferences.getString("preferred_sub", "sub")!!
|
val subOrDub = preferences.getString(PREF_SUBS_KEY, PREF_SUBS_DEFAULT)!!
|
||||||
|
|
||||||
return pList.sortedWith(
|
return pList.sortedWith(
|
||||||
compareBy(
|
compareBy(
|
||||||
{ it.first.quality.lowercase().contains(subOrDub) },
|
{ it.first.quality.lowercase().contains(subOrDub) },
|
||||||
{ it.first.quality.contains(quality) },
|
{ it.first.quality.contains(quality) },
|
||||||
|
{ Regex("""(\d+)p""").find(it.first.quality)?.groupValues?.get(1)?.toIntOrNull() ?: 0 },
|
||||||
{ if (prefGroup == "site_default") -it.second else it.first.quality.contains(prefGroup) },
|
{ if (prefGroup == "site_default") -it.second else it.first.quality.contains(prefGroup) },
|
||||||
),
|
),
|
||||||
).reversed().map { t -> t.first }
|
).reversed().map { t -> t.first }
|
||||||
@ -300,16 +291,17 @@ class MarinMoe : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||||||
|
|
||||||
@SuppressLint("SimpleDateFormat")
|
@SuppressLint("SimpleDateFormat")
|
||||||
private fun parseDate(date: String): Date {
|
private fun parseDate(date: String): Date {
|
||||||
val knownPatterns: MutableList<SimpleDateFormat> = ArrayList()
|
val patterns = arrayOf(
|
||||||
knownPatterns.add(SimpleDateFormat("dd'th of 'MMM, yyyy"))
|
"dd'th of 'MMM, yyyy",
|
||||||
knownPatterns.add(SimpleDateFormat("dd'nd of 'MMM, yyyy"))
|
"dd'nd of 'MMM, yyyy",
|
||||||
knownPatterns.add(SimpleDateFormat("dd'st of 'MMM, yyyy"))
|
"dd'st of 'MMM, yyyy",
|
||||||
knownPatterns.add(SimpleDateFormat("dd'rd of 'MMM, yyyy"))
|
"dd'rd of 'MMM, yyyy",
|
||||||
|
)
|
||||||
|
|
||||||
for (pattern in knownPatterns) {
|
for (pattern in patterns) {
|
||||||
try {
|
try {
|
||||||
// Take a try
|
// Take a try
|
||||||
return Date(pattern.parse(date)!!.time)
|
return Date(SimpleDateFormat(pattern).parse(date)!!.time)
|
||||||
} catch (e: Throwable) {
|
} catch (e: Throwable) {
|
||||||
// Loop on
|
// Loop on
|
||||||
}
|
}
|
||||||
@ -317,13 +309,37 @@ class MarinMoe : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||||||
return Date(-1L)
|
return Date(-1L)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val PREF_QUALITY_KEY = "preferred_quality"
|
||||||
|
private const val PREF_QUALITY_TITLE = "Preferred quality"
|
||||||
|
private val PREF_QUALITY_ENTRY_VALUES = arrayOf("1080", "720", "480", "360")
|
||||||
|
private val PREF_QUALITY_ENTRIES = PREF_QUALITY_ENTRY_VALUES.map { "${it}p" }.toTypedArray()
|
||||||
|
private const val PREF_QUALITY_DEFAULT = "1080"
|
||||||
|
|
||||||
|
private const val PREF_GROUP_KEY = "preferred_group"
|
||||||
|
private const val PREF_GROUP_TITLE = "Preferred group"
|
||||||
|
private const val PREF_GROUP_DEFAULT = "site_default"
|
||||||
|
|
||||||
|
private const val PREF_SUBS_KEY = "preferred_sub"
|
||||||
|
private const val PREF_SUBS_TITLE = "Prefer subs or dubs?"
|
||||||
|
private val PREF_SUBS_ENTRY_VALUES = arrayOf("sub", "dub")
|
||||||
|
private val PREF_SUBS_ENTRIES = arrayOf("Subs", "Dubs")
|
||||||
|
private const val PREF_SUBS_DEFAULT = "sub"
|
||||||
|
|
||||||
|
private const val PREF_SPECIAL_KEY = "preferred_special"
|
||||||
|
private const val PREF_SPECIAL_TITLE = "Include Special Episodes"
|
||||||
|
private const val PREF_SPECIAL_DEFAULT = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================== Settings ==============================
|
||||||
|
|
||||||
override fun setupPreferenceScreen(screen: PreferenceScreen) {
|
override fun setupPreferenceScreen(screen: PreferenceScreen) {
|
||||||
val videoQualityPref = ListPreference(screen.context).apply {
|
ListPreference(screen.context).apply {
|
||||||
key = "preferred_quality"
|
key = PREF_QUALITY_KEY
|
||||||
title = "Preferred quality"
|
title = PREF_QUALITY_TITLE
|
||||||
entries = arrayOf("1080p", "720p", "480p", "360p")
|
entries = PREF_QUALITY_ENTRIES
|
||||||
entryValues = arrayOf("1080", "720", "480", "360")
|
entryValues = PREF_QUALITY_ENTRY_VALUES
|
||||||
setDefaultValue("1080")
|
setDefaultValue(PREF_QUALITY_DEFAULT)
|
||||||
summary = "%s"
|
summary = "%s"
|
||||||
|
|
||||||
setOnPreferenceChangeListener { _, newValue ->
|
setOnPreferenceChangeListener { _, newValue ->
|
||||||
@ -332,14 +348,14 @@ class MarinMoe : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||||||
val entry = entryValues[index] as String
|
val entry = entryValues[index] as String
|
||||||
preferences.edit().putString(key, entry).commit()
|
preferences.edit().putString(key, entry).commit()
|
||||||
}
|
}
|
||||||
}
|
}.let { screen.addPreference(it) }
|
||||||
|
|
||||||
val groupPref = ListPreference(screen.context).apply {
|
ListPreference(screen.context).apply {
|
||||||
key = "preferred_group"
|
key = PREF_GROUP_KEY
|
||||||
title = "Preferred group"
|
title = PREF_GROUP_TITLE
|
||||||
entries = MarinMoeConstants.GROUP_ENTRIES
|
entries = MarinMoeConstants.GROUP_ENTRIES
|
||||||
entryValues = MarinMoeConstants.GROUP_ENTRY_VALUES
|
entryValues = MarinMoeConstants.GROUP_ENTRY_VALUES
|
||||||
setDefaultValue("site_default")
|
setDefaultValue(PREF_GROUP_DEFAULT)
|
||||||
summary = "%s"
|
summary = "%s"
|
||||||
|
|
||||||
setOnPreferenceChangeListener { _, newValue ->
|
setOnPreferenceChangeListener { _, newValue ->
|
||||||
@ -348,14 +364,14 @@ class MarinMoe : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||||||
val entry = entryValues[index] as String
|
val entry = entryValues[index] as String
|
||||||
preferences.edit().putString(key, entry).commit()
|
preferences.edit().putString(key, entry).commit()
|
||||||
}
|
}
|
||||||
}
|
}.let { screen.addPreference(it) }
|
||||||
|
|
||||||
val subPref = ListPreference(screen.context).apply {
|
ListPreference(screen.context).apply {
|
||||||
key = "preferred_sub"
|
key = PREF_SUBS_KEY
|
||||||
title = "Prefer subs or dubs?"
|
title = PREF_SUBS_TITLE
|
||||||
entries = arrayOf("Subs", "Dubs")
|
entries = PREF_SUBS_ENTRIES
|
||||||
entryValues = arrayOf("sub", "dub")
|
entryValues = PREF_SUBS_ENTRY_VALUES
|
||||||
setDefaultValue("sub")
|
setDefaultValue(PREF_SUBS_DEFAULT)
|
||||||
summary = "%s"
|
summary = "%s"
|
||||||
|
|
||||||
setOnPreferenceChangeListener { _, newValue ->
|
setOnPreferenceChangeListener { _, newValue ->
|
||||||
@ -364,22 +380,17 @@ class MarinMoe : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||||||
val entry = entryValues[index] as String
|
val entry = entryValues[index] as String
|
||||||
preferences.edit().putString(key, entry).commit()
|
preferences.edit().putString(key, entry).commit()
|
||||||
}
|
}
|
||||||
}
|
}.let { screen.addPreference(it) }
|
||||||
|
|
||||||
val specialPref = SwitchPreferenceCompat(screen.context).apply {
|
SwitchPreferenceCompat(screen.context).apply {
|
||||||
key = "preferred_special"
|
key = PREF_SPECIAL_KEY
|
||||||
title = "Include Special Episodes"
|
title = PREF_SPECIAL_TITLE
|
||||||
setDefaultValue(true)
|
setDefaultValue(PREF_SPECIAL_DEFAULT)
|
||||||
|
|
||||||
setOnPreferenceChangeListener { _, newValue ->
|
setOnPreferenceChangeListener { _, newValue ->
|
||||||
val new = newValue as Boolean
|
val new = newValue as Boolean
|
||||||
preferences.edit().putBoolean(key, new).commit()
|
preferences.edit().putBoolean(key, new).commit()
|
||||||
}
|
}
|
||||||
}
|
}.let { screen.addPreference(it) }
|
||||||
|
|
||||||
screen.addPreference(videoQualityPref)
|
|
||||||
screen.addPreference(groupPref)
|
|
||||||
screen.addPreference(subPref)
|
|
||||||
screen.addPreference(specialPref)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user