2021-04-30 17:20:15 +00:00
|
|
|
package com.lagradost.cloudstream3
|
|
|
|
|
2021-10-09 12:19:26 +00:00
|
|
|
import android.annotation.SuppressLint
|
2021-09-23 18:08:57 +00:00
|
|
|
import android.content.Context
|
2022-02-19 15:15:48 +00:00
|
|
|
import android.net.Uri
|
|
|
|
import android.util.Base64.encodeToString
|
2022-02-11 09:17:04 +00:00
|
|
|
import androidx.annotation.WorkerThread
|
2021-05-15 23:37:42 +00:00
|
|
|
import androidx.preference.PreferenceManager
|
2021-04-30 17:20:15 +00:00
|
|
|
import com.fasterxml.jackson.databind.DeserializationFeature
|
|
|
|
import com.fasterxml.jackson.databind.json.JsonMapper
|
|
|
|
import com.fasterxml.jackson.module.kotlin.KotlinModule
|
2021-08-15 17:38:41 +00:00
|
|
|
import com.lagradost.cloudstream3.animeproviders.*
|
2021-08-26 17:01:14 +00:00
|
|
|
import com.lagradost.cloudstream3.movieproviders.*
|
2022-01-07 19:27:25 +00:00
|
|
|
import com.lagradost.cloudstream3.ui.player.SubtitleData
|
2021-05-20 15:22:28 +00:00
|
|
|
import com.lagradost.cloudstream3.utils.ExtractorLink
|
2021-04-30 17:20:15 +00:00
|
|
|
import java.util.*
|
|
|
|
|
2021-08-14 17:31:27 +00:00
|
|
|
const val USER_AGENT =
|
|
|
|
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"
|
2021-09-25 10:07:40 +00:00
|
|
|
|
2021-08-29 13:10:36 +00:00
|
|
|
//val baseHeader = mapOf("User-Agent" to USER_AGENT)
|
2021-04-30 17:20:15 +00:00
|
|
|
val mapper = JsonMapper.builder().addModule(KotlinModule())
|
|
|
|
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false).build()!!
|
|
|
|
|
2021-05-12 21:51:02 +00:00
|
|
|
object APIHolder {
|
2021-06-17 16:20:05 +00:00
|
|
|
val unixTime: Long
|
|
|
|
get() = System.currentTimeMillis() / 1000L
|
2021-08-15 17:38:41 +00:00
|
|
|
val unixTimeMS: Long
|
|
|
|
get() = System.currentTimeMillis()
|
2021-06-17 16:20:05 +00:00
|
|
|
|
2021-05-15 23:37:42 +00:00
|
|
|
private const val defProvider = 0
|
|
|
|
|
2021-06-16 22:31:41 +00:00
|
|
|
val apis = arrayListOf(
|
2021-12-27 17:41:55 +00:00
|
|
|
PelisplusProvider(),
|
2022-01-16 17:43:44 +00:00
|
|
|
PelisplusHDProvider(),
|
2022-01-24 21:15:40 +00:00
|
|
|
PeliSmartProvider(),
|
2021-09-05 11:56:25 +00:00
|
|
|
GogoanimeProvider(),
|
2021-10-28 18:47:46 +00:00
|
|
|
AllAnimeProvider(),
|
2022-02-10 09:27:33 +00:00
|
|
|
AnimekisaProvider(),
|
2021-08-11 17:04:31 +00:00
|
|
|
//ShiroProvider(), // v2 fucked me
|
2021-08-24 18:41:08 +00:00
|
|
|
AnimeFlickProvider(),
|
2022-01-24 21:15:40 +00:00
|
|
|
AnimeflvnetProvider(),
|
2021-09-05 11:56:25 +00:00
|
|
|
|
2021-07-21 23:49:56 +00:00
|
|
|
TenshiProvider(),
|
2021-07-23 11:58:53 +00:00
|
|
|
WcoProvider(),
|
2021-08-11 17:04:31 +00:00
|
|
|
// MeloMovieProvider(), // Captcha for links
|
2021-06-23 18:33:47 +00:00
|
|
|
DubbedAnimeProvider(),
|
2022-01-18 12:06:35 +00:00
|
|
|
DoramasYTProvider(),
|
2022-01-24 21:15:40 +00:00
|
|
|
CinecalidadProvider(),
|
2022-02-05 13:32:02 +00:00
|
|
|
CuevanaProvider(),
|
|
|
|
EntrepeliculasyseriesProvider(),
|
|
|
|
PelisflixProvider(),
|
|
|
|
SeriesflixProvider(),
|
2021-12-08 23:41:26 +00:00
|
|
|
IHaveNoTvProvider(), // Documentaries provider
|
2021-07-23 23:44:54 +00:00
|
|
|
//LookMovieProvider(), // RECAPTCHA (Please allow up to 5 seconds...)
|
2021-08-11 17:04:31 +00:00
|
|
|
VMoveeProvider(),
|
2021-08-14 17:31:27 +00:00
|
|
|
WatchCartoonOnlineProvider(),
|
2021-08-25 22:16:20 +00:00
|
|
|
AllMoviesForYouProvider(),
|
2021-10-03 19:15:56 +00:00
|
|
|
|
2022-01-18 12:06:35 +00:00
|
|
|
MonoschinosProvider(),
|
|
|
|
|
2021-10-02 07:28:22 +00:00
|
|
|
VidEmbedProvider(),
|
2021-10-03 20:23:06 +00:00
|
|
|
VfFilmProvider(),
|
2021-11-07 22:53:49 +00:00
|
|
|
VfSerieProvider(),
|
2021-12-27 01:15:49 +00:00
|
|
|
FrenchStreamProvider(),
|
|
|
|
|
2021-10-03 20:23:06 +00:00
|
|
|
AsianLoadProvider(),
|
2021-10-05 16:39:38 +00:00
|
|
|
|
2021-12-08 23:39:30 +00:00
|
|
|
SflixProvider("https://sflix.to", "Sflix"),
|
|
|
|
SflixProvider("https://dopebox.to", "Dopebox"),
|
2022-02-07 13:32:24 +00:00
|
|
|
SflixProvider("https://solarmovie.pe", "Solarmovie"),
|
2021-11-25 22:36:35 +00:00
|
|
|
|
2021-12-08 23:39:30 +00:00
|
|
|
//TmdbProvider(),
|
2021-11-28 16:10:19 +00:00
|
|
|
|
2021-12-21 17:58:42 +00:00
|
|
|
FilmanProvider(),
|
|
|
|
|
2021-12-09 08:57:41 +00:00
|
|
|
ZoroProvider(),
|
2021-12-21 23:11:13 +00:00
|
|
|
PinoyMoviePediaProvider(),
|
|
|
|
PinoyHDXyzProvider(),
|
2021-12-27 17:43:15 +00:00
|
|
|
PinoyMoviesEsProvider(),
|
|
|
|
TrailersTwoProvider(),
|
2022-01-09 12:27:10 +00:00
|
|
|
DramaSeeProvider(),
|
2022-01-13 15:00:51 +00:00
|
|
|
WatchAsianProvider(),
|
2022-01-14 21:18:24 +00:00
|
|
|
KdramaHoodProvider(),
|
2022-01-31 20:47:59 +00:00
|
|
|
AkwamProvider(),
|
|
|
|
AnimePaheProvider(),
|
2021-08-30 21:42:58 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
val restrictedApis = arrayListOf(
|
2021-11-12 16:55:54 +00:00
|
|
|
// TrailersToProvider(), // be aware that this is fuckery
|
2021-11-09 21:15:11 +00:00
|
|
|
// NyaaProvider(), // torrents in cs3 is wack
|
|
|
|
// ThenosProvider(), // ddos protection and wacked links
|
2021-10-03 19:15:56 +00:00
|
|
|
AsiaFlixProvider(),
|
2021-05-12 21:51:02 +00:00
|
|
|
)
|
2021-05-15 23:37:42 +00:00
|
|
|
|
2021-12-08 23:39:30 +00:00
|
|
|
private val backwardsCompatibleProviders = arrayListOf(
|
|
|
|
KawaiifuProvider(), // removed due to cloudflare
|
2022-01-13 21:09:05 +00:00
|
|
|
HDMProvider(),// removed due to cloudflare
|
2021-12-08 23:39:30 +00:00
|
|
|
)
|
|
|
|
|
2021-05-22 22:25:56 +00:00
|
|
|
fun getApiFromName(apiName: String?): MainAPI {
|
2021-12-08 23:39:30 +00:00
|
|
|
return getApiFromNameNull(apiName) ?: apis[defProvider]
|
2021-05-18 13:43:32 +00:00
|
|
|
}
|
|
|
|
|
2021-07-29 00:19:42 +00:00
|
|
|
fun getApiFromNameNull(apiName: String?): MainAPI? {
|
2021-12-08 23:39:30 +00:00
|
|
|
if (apiName == null) return null
|
2021-07-29 00:19:42 +00:00
|
|
|
for (api in apis) {
|
|
|
|
if (apiName == api.name)
|
|
|
|
return api
|
|
|
|
}
|
2021-12-08 23:39:30 +00:00
|
|
|
for (api in restrictedApis) {
|
|
|
|
if (apiName == api.name)
|
|
|
|
return api
|
|
|
|
}
|
|
|
|
for (api in backwardsCompatibleProviders) {
|
|
|
|
if (apiName == api.name)
|
|
|
|
return api
|
|
|
|
}
|
2021-07-29 00:19:42 +00:00
|
|
|
return null
|
|
|
|
}
|
2021-07-25 16:08:34 +00:00
|
|
|
|
|
|
|
fun LoadResponse.getId(): Int {
|
2021-07-30 23:41:54 +00:00
|
|
|
return url.replace(getApiFromName(apiName).mainUrl, "").replace("/", "").hashCode()
|
2021-07-25 16:08:34 +00:00
|
|
|
}
|
|
|
|
|
2022-02-19 15:15:48 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Gets the website captcha token
|
|
|
|
* discovered originally by https://github.com/ahmedgamal17
|
|
|
|
* optimized by https://github.com/justfoolingaround
|
|
|
|
*
|
|
|
|
* @param url the main url, likely the same website you found the key from.
|
|
|
|
* @param key used to fill https://www.google.com/recaptcha/api.js?render=....
|
|
|
|
*
|
|
|
|
* @param referer the referer for the google.com/recaptcha/api.js... request, optional.
|
|
|
|
* */
|
|
|
|
|
|
|
|
// Try document.select("script[src*=https://www.google.com/recaptcha/api.js?render=]").attr("src").substringAfter("render=")
|
|
|
|
// To get the key
|
|
|
|
suspend fun getCaptchaToken(url: String, key: String, referer: String? = null): String? {
|
|
|
|
val uri = Uri.parse(url)
|
|
|
|
val domain = encodeToString(
|
|
|
|
(uri.scheme + "://" + uri.host + ":443").encodeToByteArray(),
|
|
|
|
0
|
|
|
|
).replace("\n", "").replace("=",".")
|
|
|
|
|
|
|
|
val vToken =
|
|
|
|
app.get(
|
|
|
|
"https://www.google.com/recaptcha/api.js?render=$key",
|
|
|
|
referer = referer,
|
|
|
|
cacheTime = 0
|
|
|
|
)
|
|
|
|
.text
|
|
|
|
.substringAfter("releases/")
|
|
|
|
.substringBefore("/")
|
|
|
|
val recapToken =
|
|
|
|
app.get("https://www.google.com/recaptcha/api2/anchor?ar=1&hl=en&size=invisible&cb=cs3&k=$key&co=$domain&v=$vToken")
|
|
|
|
.document
|
|
|
|
.selectFirst("#recaptcha-token")?.attr("value")
|
|
|
|
if (recapToken != null) {
|
|
|
|
return app.post(
|
|
|
|
"https://www.google.com/recaptcha/api2/reload?k=$key",
|
|
|
|
data = mapOf(
|
|
|
|
"v" to vToken,
|
|
|
|
"k" to key,
|
|
|
|
"c" to recapToken,
|
|
|
|
"co" to domain,
|
|
|
|
"sa" to "",
|
|
|
|
"reason" to "q"
|
|
|
|
), cacheTime = 0
|
|
|
|
).text
|
|
|
|
.substringAfter("rresp\",\"")
|
|
|
|
.substringBefore("\"")
|
|
|
|
}
|
|
|
|
return null
|
|
|
|
}
|
|
|
|
|
2021-09-23 18:08:57 +00:00
|
|
|
fun Context.getApiSettings(): HashSet<String> {
|
2022-01-30 01:50:49 +00:00
|
|
|
//val settingsManager = PreferenceManager.getDefaultSharedPreferences(this)
|
2021-05-15 23:37:42 +00:00
|
|
|
|
2021-08-19 20:05:18 +00:00
|
|
|
val hashSet = HashSet<String>()
|
2021-10-02 17:10:50 +00:00
|
|
|
val activeLangs = getApiProviderLangSettings()
|
|
|
|
hashSet.addAll(apis.filter { activeLangs.contains(it.lang) }.map { it.name })
|
2021-08-19 20:05:18 +00:00
|
|
|
|
2022-01-30 01:50:49 +00:00
|
|
|
/*val set = settingsManager.getStringSet(
|
2021-07-02 19:43:15 +00:00
|
|
|
this.getString(R.string.search_providers_list_key),
|
2021-08-19 20:05:18 +00:00
|
|
|
hashSet
|
|
|
|
)?.toHashSet() ?: hashSet
|
2021-09-23 18:08:57 +00:00
|
|
|
|
|
|
|
val list = HashSet<String>()
|
|
|
|
for (name in set) {
|
|
|
|
val api = getApiFromNameNull(name) ?: continue
|
2021-09-25 10:07:40 +00:00
|
|
|
if (activeLangs.contains(api.lang)) {
|
2021-09-23 18:08:57 +00:00
|
|
|
list.add(name)
|
|
|
|
}
|
2022-01-30 01:50:49 +00:00
|
|
|
}*/
|
|
|
|
//if (list.isEmpty()) return hashSet
|
|
|
|
//return list
|
|
|
|
return hashSet
|
2021-05-15 23:37:42 +00:00
|
|
|
}
|
2021-08-14 19:35:26 +00:00
|
|
|
|
2021-09-23 18:08:57 +00:00
|
|
|
fun Context.getApiDubstatusSettings(): HashSet<DubStatus> {
|
2021-09-12 14:10:22 +00:00
|
|
|
val settingsManager = PreferenceManager.getDefaultSharedPreferences(this)
|
|
|
|
val hashSet = HashSet<DubStatus>()
|
|
|
|
hashSet.addAll(DubStatus.values())
|
|
|
|
val list = settingsManager.getStringSet(
|
|
|
|
this.getString(R.string.display_sub_key),
|
|
|
|
hashSet.map { it.name }.toMutableSet()
|
|
|
|
) ?: return hashSet
|
|
|
|
|
|
|
|
val names = DubStatus.values().map { it.name }.toHashSet()
|
|
|
|
//if(realSet.isEmpty()) return hashSet
|
|
|
|
|
|
|
|
return list.filter { names.contains(it) }.map { DubStatus.valueOf(it) }.toHashSet()
|
|
|
|
}
|
|
|
|
|
2021-09-23 18:08:57 +00:00
|
|
|
fun Context.getApiProviderLangSettings(): HashSet<String> {
|
|
|
|
val settingsManager = PreferenceManager.getDefaultSharedPreferences(this)
|
|
|
|
val hashSet = HashSet<String>()
|
|
|
|
hashSet.add("en") // def is only en
|
|
|
|
val list = settingsManager.getStringSet(
|
|
|
|
this.getString(R.string.provider_lang_key),
|
|
|
|
hashSet.toMutableSet()
|
|
|
|
)
|
|
|
|
|
2021-09-25 10:07:40 +00:00
|
|
|
if (list.isNullOrEmpty()) return hashSet
|
2021-09-23 18:08:57 +00:00
|
|
|
return list.toHashSet()
|
|
|
|
}
|
|
|
|
|
|
|
|
fun Context.getApiTypeSettings(): HashSet<TvType> {
|
2021-08-14 19:35:26 +00:00
|
|
|
val settingsManager = PreferenceManager.getDefaultSharedPreferences(this)
|
2021-08-19 20:05:18 +00:00
|
|
|
val hashSet = HashSet<TvType>()
|
|
|
|
hashSet.addAll(TvType.values())
|
2021-08-14 19:35:26 +00:00
|
|
|
val list = settingsManager.getStringSet(
|
|
|
|
this.getString(R.string.search_types_list_key),
|
2021-08-19 20:05:18 +00:00
|
|
|
hashSet.map { it.name }.toMutableSet()
|
2021-08-14 19:35:26 +00:00
|
|
|
)
|
2021-08-19 20:05:18 +00:00
|
|
|
|
2021-09-25 10:07:40 +00:00
|
|
|
if (list.isNullOrEmpty()) return hashSet
|
2021-08-14 19:35:26 +00:00
|
|
|
|
|
|
|
val names = TvType.values().map { it.name }.toHashSet()
|
|
|
|
val realSet = list.filter { names.contains(it) }.map { TvType.valueOf(it) }.toHashSet()
|
2021-09-25 10:07:40 +00:00
|
|
|
if (realSet.isEmpty()) return hashSet
|
2021-08-14 19:35:26 +00:00
|
|
|
|
|
|
|
return realSet
|
|
|
|
}
|
2021-12-16 23:45:20 +00:00
|
|
|
|
2022-02-05 22:21:45 +00:00
|
|
|
fun Context.filterProviderByPreferredMedia(hasHomePageIsRequired: Boolean = true): List<MainAPI> {
|
2021-12-16 23:45:20 +00:00
|
|
|
val settingsManager = PreferenceManager.getDefaultSharedPreferences(this)
|
2022-01-13 21:09:05 +00:00
|
|
|
val currentPrefMedia =
|
|
|
|
settingsManager.getInt(this.getString(R.string.prefer_media_type_key), 0)
|
2021-12-16 23:45:20 +00:00
|
|
|
val langs = this.getApiProviderLangSettings()
|
2022-02-05 22:21:45 +00:00
|
|
|
val allApis = apis.filter { langs.contains(it.lang) }
|
|
|
|
.filter { api -> api.hasMainPage || !hasHomePageIsRequired }
|
2021-12-16 23:45:20 +00:00
|
|
|
return if (currentPrefMedia < 1) {
|
|
|
|
allApis
|
|
|
|
} else {
|
|
|
|
// Filter API depending on preferred media type
|
2022-01-31 20:47:59 +00:00
|
|
|
val listEnumAnime = listOf(TvType.Anime, TvType.AnimeMovie, TvType.OVA)
|
2021-12-16 23:45:20 +00:00
|
|
|
val listEnumMovieTv = listOf(TvType.Movie, TvType.TvSeries, TvType.Cartoon)
|
|
|
|
val mediaTypeList = if (currentPrefMedia == 1) listEnumMovieTv else listEnumAnime
|
|
|
|
|
|
|
|
val filteredAPI =
|
|
|
|
allApis.filter { api -> api.supportedTypes.any { it in mediaTypeList } }
|
|
|
|
filteredAPI
|
|
|
|
}
|
|
|
|
}
|
2021-05-12 21:51:02 +00:00
|
|
|
}
|
|
|
|
|
2021-07-23 23:44:54 +00:00
|
|
|
/**Every provider will **not** have try catch built in, so handle exceptions when calling these functions*/
|
2021-05-12 21:51:02 +00:00
|
|
|
abstract class MainAPI {
|
2021-04-30 17:20:15 +00:00
|
|
|
open val name = "NONE"
|
|
|
|
open val mainUrl = "NONE"
|
2021-07-23 23:44:54 +00:00
|
|
|
|
2021-09-23 18:08:57 +00:00
|
|
|
open val lang = "en" // ISO_639_1 check SubtitleHelper
|
|
|
|
|
2021-07-23 23:44:54 +00:00
|
|
|
/**If link is stored in the "data" string, so links can be instantly loaded*/
|
|
|
|
open val instantLinkLoading = false
|
|
|
|
|
|
|
|
/**Set false if links require referer or for some reason cant be played on a chromecast*/
|
|
|
|
open val hasChromecastSupport = true
|
|
|
|
|
2021-11-09 21:15:11 +00:00
|
|
|
/**If all links are encrypted then set this to false*/
|
2021-07-23 23:44:54 +00:00
|
|
|
open val hasDownloadSupport = true
|
|
|
|
|
2021-11-09 21:15:11 +00:00
|
|
|
/**Used for testing and can be used to disable the providers if WebView is not available*/
|
|
|
|
open val usesWebView = false
|
|
|
|
|
2021-07-29 00:19:42 +00:00
|
|
|
open val hasMainPage = false
|
|
|
|
open val hasQuickSearch = false
|
|
|
|
|
2021-08-14 17:31:27 +00:00
|
|
|
open val supportedTypes = setOf(
|
|
|
|
TvType.Movie,
|
|
|
|
TvType.TvSeries,
|
|
|
|
TvType.Cartoon,
|
|
|
|
TvType.Anime,
|
2022-01-31 20:47:59 +00:00
|
|
|
TvType.OVA,
|
2021-08-14 17:31:27 +00:00
|
|
|
)
|
|
|
|
|
2021-08-29 13:10:36 +00:00
|
|
|
open val vpnStatus = VPNStatus.None
|
2021-11-29 19:26:57 +00:00
|
|
|
open val providerType = ProviderType.DirectProvider
|
2021-08-29 13:10:36 +00:00
|
|
|
|
2022-02-11 09:17:04 +00:00
|
|
|
@WorkerThread
|
2022-01-16 22:31:42 +00:00
|
|
|
suspend open fun getMainPage(): HomePageResponse? {
|
2021-08-21 21:06:24 +00:00
|
|
|
throw NotImplementedError()
|
2021-07-29 00:19:42 +00:00
|
|
|
}
|
2022-02-19 15:15:48 +00:00
|
|
|
|
2022-02-11 09:17:04 +00:00
|
|
|
@WorkerThread
|
2022-01-16 22:31:42 +00:00
|
|
|
suspend open fun search(query: String): List<SearchResponse>? {
|
2021-08-21 21:06:24 +00:00
|
|
|
throw NotImplementedError()
|
2021-04-30 17:20:15 +00:00
|
|
|
}
|
2022-02-19 15:15:48 +00:00
|
|
|
|
2022-02-11 09:17:04 +00:00
|
|
|
@WorkerThread
|
2022-01-16 22:31:42 +00:00
|
|
|
suspend open fun quickSearch(query: String): List<SearchResponse>? {
|
2021-08-21 21:06:24 +00:00
|
|
|
throw NotImplementedError()
|
2021-06-17 16:20:05 +00:00
|
|
|
}
|
2022-02-19 15:15:48 +00:00
|
|
|
|
2022-02-11 09:17:04 +00:00
|
|
|
@WorkerThread
|
|
|
|
/**
|
|
|
|
* Based on data from search() or getMainPage() it generates a LoadResponse,
|
|
|
|
* basically opening the info page from a link.
|
|
|
|
* */
|
2022-01-16 22:31:42 +00:00
|
|
|
suspend open fun load(url: String): LoadResponse? {
|
2021-08-21 21:06:24 +00:00
|
|
|
throw NotImplementedError()
|
2021-04-30 17:20:15 +00:00
|
|
|
}
|
|
|
|
|
2022-02-11 09:17:04 +00:00
|
|
|
/**
|
|
|
|
* Largely redundant feature for most providers.
|
|
|
|
*
|
|
|
|
* This job runs in the background when a link is playing in exoplayer.
|
|
|
|
* First implemented to do polling for sflix to keep the link from getting expired.
|
|
|
|
*
|
|
|
|
* This function might be updated to include exoplayer timestamps etc in the future
|
|
|
|
* if the need arises.
|
|
|
|
* */
|
|
|
|
@WorkerThread
|
|
|
|
suspend open fun extractorVerifierJob(extractorData: String?) {
|
|
|
|
throw NotImplementedError()
|
|
|
|
}
|
|
|
|
|
2021-07-23 23:44:54 +00:00
|
|
|
/**Callback is fired once a link is found, will return true if method is executed successfully*/
|
2022-02-11 09:17:04 +00:00
|
|
|
@WorkerThread
|
2022-01-16 22:31:42 +00:00
|
|
|
suspend open fun loadLinks(
|
2021-07-02 19:43:15 +00:00
|
|
|
data: String,
|
|
|
|
isCasting: Boolean,
|
|
|
|
subtitleCallback: (SubtitleFile) -> Unit,
|
|
|
|
callback: (ExtractorLink) -> Unit
|
|
|
|
): Boolean {
|
2021-08-21 21:06:24 +00:00
|
|
|
throw NotImplementedError()
|
2021-04-30 17:20:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-03 11:58:39 +00:00
|
|
|
/** Might need a different implementation for desktop*/
|
2021-10-09 12:19:26 +00:00
|
|
|
@SuppressLint("NewApi")
|
2021-10-03 11:58:39 +00:00
|
|
|
fun base64Decode(string: String): String {
|
2022-01-29 18:37:23 +00:00
|
|
|
return String(base64DecodeArray(string), Charsets.ISO_8859_1)
|
|
|
|
}
|
|
|
|
|
|
|
|
@SuppressLint("NewApi")
|
|
|
|
fun base64DecodeArray(string: String): ByteArray {
|
|
|
|
return try {
|
|
|
|
android.util.Base64.decode(string, android.util.Base64.DEFAULT)
|
|
|
|
} catch (e: Exception) {
|
|
|
|
Base64.getDecoder().decode(string)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@SuppressLint("NewApi")
|
|
|
|
fun base64Encode(array: ByteArray): String {
|
2021-10-03 11:58:39 +00:00
|
|
|
return try {
|
2022-01-29 18:37:23 +00:00
|
|
|
String(android.util.Base64.encode(array, android.util.Base64.NO_WRAP), Charsets.ISO_8859_1)
|
2021-10-03 11:58:39 +00:00
|
|
|
} catch (e: Exception) {
|
2022-01-29 18:37:23 +00:00
|
|
|
String(Base64.getEncoder().encode(array))
|
2021-10-03 11:58:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-08-04 01:50:24 +00:00
|
|
|
class ErrorLoadingException(message: String? = null) : Exception(message)
|
|
|
|
|
2021-06-26 14:44:53 +00:00
|
|
|
fun parseRating(ratingString: String?): Int? {
|
|
|
|
if (ratingString == null) return null
|
2021-06-24 17:45:59 +00:00
|
|
|
val floatRating = ratingString.toFloatOrNull() ?: return null
|
|
|
|
return (floatRating * 10).toInt()
|
|
|
|
}
|
|
|
|
|
2022-01-13 21:09:05 +00:00
|
|
|
fun MainAPI.fixUrlNull(url: String?): String? {
|
2022-01-03 00:57:36 +00:00
|
|
|
if (url.isNullOrEmpty()) {
|
|
|
|
return null
|
|
|
|
}
|
2022-01-13 15:00:51 +00:00
|
|
|
return fixUrl(url)
|
2021-12-26 00:05:10 +00:00
|
|
|
}
|
|
|
|
|
2021-05-15 23:37:42 +00:00
|
|
|
fun MainAPI.fixUrl(url: String): String {
|
2021-06-26 14:44:53 +00:00
|
|
|
if (url.startsWith("http")) {
|
2021-06-23 18:33:47 +00:00
|
|
|
return url
|
|
|
|
}
|
2022-01-03 00:57:36 +00:00
|
|
|
if (url.isEmpty()) {
|
|
|
|
return ""
|
|
|
|
}
|
2021-06-23 18:33:47 +00:00
|
|
|
|
|
|
|
val startsWithNoHttp = url.startsWith("//")
|
2021-06-26 14:44:53 +00:00
|
|
|
if (startsWithNoHttp) {
|
2021-06-23 18:33:47 +00:00
|
|
|
return "https:$url"
|
2021-06-26 14:44:53 +00:00
|
|
|
} else {
|
|
|
|
if (url.startsWith('/')) {
|
2021-06-23 18:33:47 +00:00
|
|
|
return mainUrl + url
|
|
|
|
}
|
2021-05-15 23:37:42 +00:00
|
|
|
return "$mainUrl/$url"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-07 19:27:25 +00:00
|
|
|
fun sortUrls(urls: Set<ExtractorLink>): List<ExtractorLink> {
|
2021-06-10 19:43:05 +00:00
|
|
|
return urls.sortedBy { t -> -t.quality }
|
|
|
|
}
|
2021-05-15 23:37:42 +00:00
|
|
|
|
2022-01-13 21:09:05 +00:00
|
|
|
fun sortSubs(subs: Set<SubtitleData>): List<SubtitleData> {
|
2022-01-07 19:27:25 +00:00
|
|
|
return subs.sortedBy { it.name }
|
2021-07-02 19:43:15 +00:00
|
|
|
}
|
|
|
|
|
2021-12-08 23:41:26 +00:00
|
|
|
fun capitalizeString(str: String): String {
|
|
|
|
return capitalizeStringNullable(str) ?: str
|
|
|
|
}
|
|
|
|
|
|
|
|
fun capitalizeStringNullable(str: String?): String? {
|
|
|
|
if (str == null)
|
|
|
|
return null
|
|
|
|
return try {
|
|
|
|
str.replaceFirstChar { if (it.isLowerCase()) it.titlecase(Locale.getDefault()) else it.toString() }
|
|
|
|
} catch (e: Exception) {
|
|
|
|
str
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-08-04 01:50:24 +00:00
|
|
|
/** https://www.imdb.com/title/tt2861424/ -> tt2861424 */
|
2021-10-30 18:14:12 +00:00
|
|
|
fun imdbUrlToId(url: String): String? {
|
2021-11-02 15:09:29 +00:00
|
|
|
return Regex("/title/(tt[0-9]*)").find(url)?.groupValues?.get(1)
|
|
|
|
?: Regex("tt[0-9]{5,}").find(url)?.groupValues?.get(0)
|
2021-08-04 01:50:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fun imdbUrlToIdNullable(url: String?): String? {
|
2021-08-11 17:04:31 +00:00
|
|
|
if (url == null) return null
|
2021-08-04 01:50:24 +00:00
|
|
|
return imdbUrlToId(url)
|
|
|
|
}
|
|
|
|
|
2021-11-29 19:26:57 +00:00
|
|
|
enum class ProviderType {
|
|
|
|
// When data is fetched from a 3rd party site like imdb
|
|
|
|
MetaProvider,
|
2021-12-08 23:39:30 +00:00
|
|
|
|
2021-11-29 19:26:57 +00:00
|
|
|
// When all data is from the site
|
|
|
|
DirectProvider,
|
|
|
|
}
|
|
|
|
|
2021-08-29 13:10:36 +00:00
|
|
|
enum class VPNStatus {
|
|
|
|
None,
|
|
|
|
MightBeNeeded,
|
|
|
|
Torrent,
|
|
|
|
}
|
|
|
|
|
2021-04-30 17:20:15 +00:00
|
|
|
enum class ShowStatus {
|
|
|
|
Completed,
|
|
|
|
Ongoing,
|
|
|
|
}
|
|
|
|
|
|
|
|
enum class DubStatus {
|
2021-05-22 22:25:56 +00:00
|
|
|
Dubbed,
|
|
|
|
Subbed,
|
2021-04-30 17:20:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
enum class TvType {
|
|
|
|
Movie,
|
2021-08-14 19:35:26 +00:00
|
|
|
AnimeMovie,
|
2021-04-30 17:20:15 +00:00
|
|
|
TvSeries,
|
2021-08-14 17:31:27 +00:00
|
|
|
Cartoon,
|
2021-04-30 17:20:15 +00:00
|
|
|
Anime,
|
2022-01-31 20:47:59 +00:00
|
|
|
OVA,
|
2021-08-30 17:11:04 +00:00
|
|
|
Torrent,
|
2021-12-08 23:41:26 +00:00
|
|
|
Documentary,
|
2021-04-30 17:20:15 +00:00
|
|
|
}
|
|
|
|
|
2021-07-15 16:45:25 +00:00
|
|
|
// IN CASE OF FUTURE ANIME MOVIE OR SMTH
|
2021-07-25 16:08:34 +00:00
|
|
|
fun TvType.isMovieType(): Boolean {
|
2021-08-30 17:11:04 +00:00
|
|
|
return this == TvType.Movie || this == TvType.AnimeMovie || this == TvType.Torrent
|
2021-07-15 16:45:25 +00:00
|
|
|
}
|
|
|
|
|
2022-01-07 19:27:25 +00:00
|
|
|
// returns if the type has an anime opening
|
|
|
|
fun TvType.isAnimeOp(): Boolean {
|
2022-01-31 20:47:59 +00:00
|
|
|
return this == TvType.Anime || this == TvType.OVA
|
2022-01-07 19:27:25 +00:00
|
|
|
}
|
|
|
|
|
2021-07-02 19:43:15 +00:00
|
|
|
data class SubtitleFile(val lang: String, val url: String)
|
2021-07-01 20:11:33 +00:00
|
|
|
|
2021-07-29 00:19:42 +00:00
|
|
|
class HomePageResponse(
|
|
|
|
val items: List<HomePageList>
|
|
|
|
)
|
|
|
|
|
|
|
|
class HomePageList(
|
|
|
|
val name: String,
|
2021-09-12 14:10:22 +00:00
|
|
|
var list: List<SearchResponse>
|
2021-07-29 00:19:42 +00:00
|
|
|
)
|
|
|
|
|
2021-04-30 17:20:15 +00:00
|
|
|
interface SearchResponse {
|
|
|
|
val name: String
|
2021-08-25 15:28:25 +00:00
|
|
|
val url: String
|
2021-04-30 17:20:15 +00:00
|
|
|
val apiName: String
|
2021-11-12 16:55:54 +00:00
|
|
|
val type: TvType?
|
2021-04-30 17:20:15 +00:00
|
|
|
val posterUrl: String?
|
2021-07-30 23:41:54 +00:00
|
|
|
val id: Int?
|
2021-04-30 17:20:15 +00:00
|
|
|
}
|
|
|
|
|
2022-02-05 22:21:45 +00:00
|
|
|
enum class ActorRole {
|
|
|
|
Main,
|
|
|
|
Supporting,
|
2022-02-05 23:58:56 +00:00
|
|
|
Background,
|
2022-02-05 22:21:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
data class Actor(
|
|
|
|
val name: String,
|
|
|
|
val image: String? = null,
|
|
|
|
)
|
|
|
|
|
|
|
|
data class ActorData(
|
|
|
|
val actor: Actor,
|
|
|
|
val role: ActorRole? = null,
|
2022-02-19 15:15:48 +00:00
|
|
|
val roleString: String? = null,
|
2022-02-05 22:21:45 +00:00
|
|
|
val voiceActor: Actor? = null,
|
|
|
|
)
|
|
|
|
|
2021-04-30 17:20:15 +00:00
|
|
|
data class AnimeSearchResponse(
|
|
|
|
override val name: String,
|
|
|
|
override val url: String,
|
|
|
|
override val apiName: String,
|
|
|
|
override val type: TvType,
|
|
|
|
|
|
|
|
override val posterUrl: String?,
|
2021-10-10 02:26:18 +00:00
|
|
|
val year: Int? = null,
|
2021-12-13 18:41:33 +00:00
|
|
|
val dubStatus: EnumSet<DubStatus>? = null,
|
2021-10-10 02:26:18 +00:00
|
|
|
|
|
|
|
val otherName: String? = null,
|
|
|
|
val dubEpisodes: Int? = null,
|
|
|
|
val subEpisodes: Int? = null,
|
2021-07-30 23:41:54 +00:00
|
|
|
override val id: Int? = null,
|
2021-04-30 17:20:15 +00:00
|
|
|
) : SearchResponse
|
|
|
|
|
2021-08-30 17:11:04 +00:00
|
|
|
data class TorrentSearchResponse(
|
|
|
|
override val name: String,
|
|
|
|
override val url: String,
|
|
|
|
override val apiName: String,
|
|
|
|
override val type: TvType,
|
|
|
|
|
|
|
|
override val posterUrl: String?,
|
|
|
|
override val id: Int? = null,
|
|
|
|
) : SearchResponse
|
|
|
|
|
2021-04-30 17:20:15 +00:00
|
|
|
data class MovieSearchResponse(
|
|
|
|
override val name: String,
|
|
|
|
override val url: String,
|
|
|
|
override val apiName: String,
|
|
|
|
override val type: TvType,
|
|
|
|
|
|
|
|
override val posterUrl: String?,
|
2022-02-06 22:38:53 +00:00
|
|
|
val year: Int? = null,
|
2021-07-30 23:41:54 +00:00
|
|
|
override val id: Int? = null,
|
2021-04-30 17:20:15 +00:00
|
|
|
) : SearchResponse
|
|
|
|
|
|
|
|
data class TvSeriesSearchResponse(
|
|
|
|
override val name: String,
|
|
|
|
override val url: String,
|
|
|
|
override val apiName: String,
|
|
|
|
override val type: TvType,
|
|
|
|
|
|
|
|
override val posterUrl: String?,
|
2021-08-25 15:28:25 +00:00
|
|
|
val year: Int?,
|
2021-04-30 17:20:15 +00:00
|
|
|
val episodes: Int?,
|
2021-07-30 23:41:54 +00:00
|
|
|
override val id: Int? = null,
|
2021-04-30 17:20:15 +00:00
|
|
|
) : SearchResponse
|
|
|
|
|
|
|
|
interface LoadResponse {
|
|
|
|
val name: String
|
|
|
|
val url: String
|
|
|
|
val apiName: String
|
|
|
|
val type: TvType
|
|
|
|
val posterUrl: String?
|
|
|
|
val year: Int?
|
2021-05-22 22:25:56 +00:00
|
|
|
val plot: String?
|
2022-01-31 20:47:59 +00:00
|
|
|
val rating: Int? // 1-1000
|
2021-08-14 17:31:27 +00:00
|
|
|
val tags: List<String>?
|
2021-12-13 18:41:33 +00:00
|
|
|
var duration: Int? // in minutes
|
2021-06-26 14:44:53 +00:00
|
|
|
val trailerUrl: String?
|
2021-10-02 17:10:50 +00:00
|
|
|
val recommendations: List<SearchResponse>?
|
2022-02-05 22:21:45 +00:00
|
|
|
var actors: List<ActorData>?
|
|
|
|
|
|
|
|
companion object {
|
2022-02-05 23:58:56 +00:00
|
|
|
@JvmName("addActorNames")
|
|
|
|
fun LoadResponse.addActors(actors: List<String>?) {
|
2022-02-05 22:21:45 +00:00
|
|
|
this.actors = actors?.map { ActorData(Actor(it)) }
|
|
|
|
}
|
|
|
|
|
2022-02-05 23:58:56 +00:00
|
|
|
@JvmName("addActors")
|
|
|
|
fun LoadResponse.addActors(actors: List<Pair<Actor, String?>>?) {
|
2022-02-05 22:21:45 +00:00
|
|
|
this.actors = actors?.map { (actor, role) -> ActorData(actor, roleString = role) }
|
|
|
|
}
|
|
|
|
|
2022-02-05 23:58:56 +00:00
|
|
|
@JvmName("addActorsRole")
|
|
|
|
fun LoadResponse.addActors(actors: List<Pair<Actor, ActorRole?>>?) {
|
|
|
|
this.actors = actors?.map { (actor, role) -> ActorData(actor, role = role) }
|
|
|
|
}
|
|
|
|
|
2022-02-06 22:38:53 +00:00
|
|
|
@JvmName("addActorsOnly")
|
|
|
|
fun LoadResponse.addActors(actors: List<Actor>?) {
|
|
|
|
this.actors = actors?.map { actor -> ActorData(actor) }
|
|
|
|
}
|
|
|
|
|
2022-02-05 22:21:45 +00:00
|
|
|
fun LoadResponse.setDuration(input: String?) {
|
2022-02-19 15:15:48 +00:00
|
|
|
val cleanInput = input?.trim()?.replace(" ", "") ?: return
|
2022-02-05 22:21:45 +00:00
|
|
|
Regex("([0-9]*)h.*?([0-9]*)m").find(cleanInput)?.groupValues?.let { values ->
|
|
|
|
if (values.size == 3) {
|
|
|
|
val hours = values[1].toIntOrNull()
|
|
|
|
val minutes = values[2].toIntOrNull()
|
|
|
|
this.duration = if (minutes != null && hours != null) {
|
|
|
|
hours * 60 + minutes
|
|
|
|
} else null
|
|
|
|
if (this.duration != null) return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Regex("([0-9]*)m").find(cleanInput)?.groupValues?.let { values ->
|
|
|
|
if (values.size == 2) {
|
|
|
|
this.duration = values[1].toIntOrNull()
|
|
|
|
if (this.duration != null) return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-04-30 17:20:15 +00:00
|
|
|
}
|
|
|
|
|
2021-06-17 15:39:01 +00:00
|
|
|
fun LoadResponse?.isEpisodeBased(): Boolean {
|
|
|
|
if (this == null) return false
|
2022-01-07 19:27:25 +00:00
|
|
|
return (this is AnimeLoadResponse || this is TvSeriesLoadResponse) && this.type.isEpisodeBased()
|
2021-06-17 15:39:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fun LoadResponse?.isAnimeBased(): Boolean {
|
|
|
|
if (this == null) return false
|
2022-01-31 20:47:59 +00:00
|
|
|
return (this.type == TvType.Anime || this.type == TvType.OVA) // && (this is AnimeLoadResponse)
|
2021-05-28 13:38:06 +00:00
|
|
|
}
|
|
|
|
|
2022-01-13 21:09:05 +00:00
|
|
|
fun TvType?.isEpisodeBased(): Boolean {
|
2022-01-07 19:27:25 +00:00
|
|
|
if (this == null) return false
|
|
|
|
return (this == TvType.TvSeries || this == TvType.Anime)
|
|
|
|
}
|
|
|
|
|
2021-06-26 19:32:50 +00:00
|
|
|
data class AnimeEpisode(
|
|
|
|
val url: String,
|
2021-11-02 15:09:29 +00:00
|
|
|
var name: String? = null,
|
|
|
|
var posterUrl: String? = null,
|
|
|
|
var date: String? = null,
|
|
|
|
var rating: Int? = null,
|
|
|
|
var description: String? = null,
|
|
|
|
var episode: Int? = null,
|
2021-06-26 19:32:50 +00:00
|
|
|
)
|
2021-06-23 18:33:47 +00:00
|
|
|
|
2021-08-30 17:11:04 +00:00
|
|
|
data class TorrentLoadResponse(
|
2021-12-13 18:41:33 +00:00
|
|
|
override var name: String,
|
|
|
|
override var url: String,
|
|
|
|
override var apiName: String,
|
|
|
|
var magnet: String?,
|
|
|
|
var torrent: String?,
|
|
|
|
override var plot: String?,
|
|
|
|
override var type: TvType = TvType.Torrent,
|
|
|
|
override var posterUrl: String? = null,
|
|
|
|
override var year: Int? = null,
|
|
|
|
override var rating: Int? = null,
|
|
|
|
override var tags: List<String>? = null,
|
|
|
|
override var duration: Int? = null,
|
|
|
|
override var trailerUrl: String? = null,
|
|
|
|
override var recommendations: List<SearchResponse>? = null,
|
2022-02-05 22:21:45 +00:00
|
|
|
override var actors: List<ActorData>? = null,
|
2021-08-30 17:11:04 +00:00
|
|
|
) : LoadResponse
|
|
|
|
|
2021-04-30 17:20:15 +00:00
|
|
|
data class AnimeLoadResponse(
|
2021-11-02 15:09:29 +00:00
|
|
|
var engName: String? = null,
|
|
|
|
var japName: String? = null,
|
2021-12-13 18:41:33 +00:00
|
|
|
override var name: String,
|
|
|
|
override var url: String,
|
|
|
|
override var apiName: String,
|
|
|
|
override var type: TvType,
|
2021-04-30 17:20:15 +00:00
|
|
|
|
2021-11-02 15:09:29 +00:00
|
|
|
override var posterUrl: String? = null,
|
|
|
|
override var year: Int? = null,
|
2021-04-30 17:20:15 +00:00
|
|
|
|
2021-11-02 15:09:29 +00:00
|
|
|
var episodes: HashMap<DubStatus, List<AnimeEpisode>> = hashMapOf(),
|
|
|
|
var showStatus: ShowStatus? = null,
|
2021-04-30 17:20:15 +00:00
|
|
|
|
2021-11-02 15:09:29 +00:00
|
|
|
override var plot: String? = null,
|
|
|
|
override var tags: List<String>? = null,
|
|
|
|
var synonyms: List<String>? = null,
|
2021-04-30 17:20:15 +00:00
|
|
|
|
2021-11-02 15:09:29 +00:00
|
|
|
var malId: Int? = null,
|
|
|
|
var anilistId: Int? = null,
|
|
|
|
override var rating: Int? = null,
|
2021-12-13 18:41:33 +00:00
|
|
|
override var duration: Int? = null,
|
2021-11-02 15:09:29 +00:00
|
|
|
override var trailerUrl: String? = null,
|
|
|
|
override var recommendations: List<SearchResponse>? = null,
|
2022-02-05 22:21:45 +00:00
|
|
|
override var actors: List<ActorData>? = null,
|
2021-04-30 17:20:15 +00:00
|
|
|
) : LoadResponse
|
|
|
|
|
2021-12-08 23:39:30 +00:00
|
|
|
fun AnimeLoadResponse.addEpisodes(status: DubStatus, episodes: List<AnimeEpisode>?) {
|
|
|
|
if (episodes == null) return
|
2021-11-02 15:09:29 +00:00
|
|
|
this.episodes[status] = episodes
|
|
|
|
}
|
|
|
|
|
|
|
|
fun MainAPI.newAnimeLoadResponse(
|
|
|
|
name: String,
|
|
|
|
url: String,
|
|
|
|
type: TvType,
|
|
|
|
initializer: AnimeLoadResponse.() -> Unit = { }
|
|
|
|
): AnimeLoadResponse {
|
|
|
|
val builder = AnimeLoadResponse(name = name, url = url, apiName = this.name, type = type)
|
|
|
|
builder.initializer()
|
|
|
|
return builder
|
|
|
|
}
|
|
|
|
|
2021-04-30 17:20:15 +00:00
|
|
|
data class MovieLoadResponse(
|
2021-12-13 18:41:33 +00:00
|
|
|
override var name: String,
|
|
|
|
override var url: String,
|
|
|
|
override var apiName: String,
|
|
|
|
override var type: TvType,
|
|
|
|
var dataUrl: String,
|
|
|
|
|
|
|
|
override var posterUrl: String? = null,
|
|
|
|
override var year: Int? = null,
|
|
|
|
override var plot: String? = null,
|
|
|
|
|
|
|
|
var imdbId: String? = null,
|
|
|
|
override var rating: Int? = null,
|
|
|
|
override var tags: List<String>? = null,
|
|
|
|
override var duration: Int? = null,
|
|
|
|
override var trailerUrl: String? = null,
|
|
|
|
override var recommendations: List<SearchResponse>? = null,
|
2022-02-05 22:21:45 +00:00
|
|
|
override var actors: List<ActorData>? = null,
|
2021-04-30 17:20:15 +00:00
|
|
|
) : LoadResponse
|
|
|
|
|
2021-12-13 18:41:33 +00:00
|
|
|
fun MainAPI.newMovieLoadResponse(
|
|
|
|
name: String,
|
|
|
|
url: String,
|
|
|
|
type: TvType,
|
2021-12-16 23:45:20 +00:00
|
|
|
dataUrl: String,
|
2021-12-13 18:41:33 +00:00
|
|
|
initializer: MovieLoadResponse.() -> Unit = { }
|
|
|
|
): MovieLoadResponse {
|
2022-01-13 21:09:05 +00:00
|
|
|
val builder = MovieLoadResponse(
|
|
|
|
name = name,
|
|
|
|
url = url,
|
|
|
|
apiName = this.name,
|
|
|
|
type = type,
|
|
|
|
dataUrl = dataUrl
|
|
|
|
)
|
2021-12-13 18:41:33 +00:00
|
|
|
builder.initializer()
|
|
|
|
return builder
|
|
|
|
}
|
|
|
|
|
2021-06-26 14:44:53 +00:00
|
|
|
data class TvSeriesEpisode(
|
2021-11-02 15:09:29 +00:00
|
|
|
val name: String? = null,
|
|
|
|
val season: Int? = null,
|
|
|
|
val episode: Int? = null,
|
2021-06-26 14:44:53 +00:00
|
|
|
val data: String,
|
|
|
|
val posterUrl: String? = null,
|
|
|
|
val date: String? = null,
|
|
|
|
val rating: Int? = null,
|
2021-12-13 18:41:33 +00:00
|
|
|
val description: String? = null,
|
2021-06-26 14:44:53 +00:00
|
|
|
)
|
2021-06-16 22:31:41 +00:00
|
|
|
|
2021-04-30 17:20:15 +00:00
|
|
|
data class TvSeriesLoadResponse(
|
2021-12-13 18:41:33 +00:00
|
|
|
override var name: String,
|
|
|
|
override var url: String,
|
|
|
|
override var apiName: String,
|
|
|
|
override var type: TvType,
|
|
|
|
var episodes: List<TvSeriesEpisode>,
|
|
|
|
|
|
|
|
override var posterUrl: String? = null,
|
|
|
|
override var year: Int? = null,
|
|
|
|
override var plot: String? = null,
|
|
|
|
|
|
|
|
var showStatus: ShowStatus? = null,
|
|
|
|
var imdbId: String? = null,
|
|
|
|
override var rating: Int? = null,
|
|
|
|
override var tags: List<String>? = null,
|
|
|
|
override var duration: Int? = null,
|
|
|
|
override var trailerUrl: String? = null,
|
|
|
|
override var recommendations: List<SearchResponse>? = null,
|
2022-02-05 22:21:45 +00:00
|
|
|
override var actors: List<ActorData>? = null,
|
2021-07-21 23:49:56 +00:00
|
|
|
) : LoadResponse
|
2021-12-13 18:41:33 +00:00
|
|
|
|
|
|
|
fun MainAPI.newTvSeriesLoadResponse(
|
|
|
|
name: String,
|
|
|
|
url: String,
|
|
|
|
type: TvType,
|
2021-12-16 23:45:20 +00:00
|
|
|
episodes: List<TvSeriesEpisode>,
|
2021-12-13 18:41:33 +00:00
|
|
|
initializer: TvSeriesLoadResponse.() -> Unit = { }
|
|
|
|
): TvSeriesLoadResponse {
|
2022-01-13 21:09:05 +00:00
|
|
|
val builder = TvSeriesLoadResponse(
|
|
|
|
name = name,
|
|
|
|
url = url,
|
|
|
|
apiName = this.name,
|
|
|
|
type = type,
|
|
|
|
episodes = episodes
|
|
|
|
)
|
2021-12-13 18:41:33 +00:00
|
|
|
builder.initializer()
|
|
|
|
return builder
|
2021-12-27 17:41:55 +00:00
|
|
|
}
|
2022-01-29 17:02:52 +00:00
|
|
|
|
|
|
|
fun fetchUrls(text: String?): List<String> {
|
|
|
|
if (text.isNullOrEmpty()) {
|
|
|
|
return listOf()
|
|
|
|
}
|
2022-02-05 22:21:45 +00:00
|
|
|
val linkRegex =
|
|
|
|
Regex("""(https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&\/\/=]*))""")
|
2022-01-29 17:02:52 +00:00
|
|
|
return linkRegex.findAll(text).map { it.value.trim().removeSurrounding("\"") }.toList()
|
|
|
|
}
|