cloudstream/app/src/main/java/com/lagradost/cloudstream3/MainAPI.kt

657 lines
19 KiB
Kotlin
Raw Normal View History

2021-04-30 17:20:15 +00:00
package com.lagradost.cloudstream3
import android.annotation.SuppressLint
import android.content.Context
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
import com.lagradost.cloudstream3.animeproviders.*
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"
//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
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
val apis = arrayListOf(
PelisplusProvider(),
PelisplusHDProvider(),
2021-09-05 11:56:25 +00:00
GogoanimeProvider(),
2021-10-28 18:47:46 +00:00
AllAnimeProvider(),
2021-08-11 17:04:31 +00:00
//ShiroProvider(), // v2 fucked me
2021-08-29 19:10:21 +00:00
//AnimePaheProvider(), //ddos guard
2021-08-24 18:41:08 +00:00
AnimeFlickProvider(),
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(),
DoramasYTProvider(),
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(),
AllMoviesForYouProvider(),
2021-10-03 19:15:56 +00:00
MonoschinosProvider(),
2021-10-02 07:28:22 +00:00
VidEmbedProvider(),
VfFilmProvider(),
VfSerieProvider(),
FrenchStreamProvider(),
AsianLoadProvider(),
2021-10-05 16:39:38 +00:00
SflixProvider("https://sflix.to", "Sflix"),
SflixProvider("https://dopebox.to", "Dopebox"),
//TmdbProvider(),
2021-11-28 16:10:19 +00:00
2021-12-21 17:58:42 +00:00
FilmanProvider(),
ZoroProvider(),
PinoyMoviePediaProvider(),
PinoyHDXyzProvider(),
2021-12-27 17:43:15 +00:00
PinoyMoviesEsProvider(),
TrailersTwoProvider(),
DramaSeeProvider(),
WatchAsianProvider(),
KdramaHoodProvider(),
AkwamProvider()
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
// 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
private val backwardsCompatibleProviders = arrayListOf(
KawaiifuProvider(), // removed due to cloudflare
2022-01-13 21:09:05 +00:00
HDMProvider(),// removed due to cloudflare
)
2021-05-22 22:25:56 +00:00
fun getApiFromName(apiName: String?): MainAPI {
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? {
if (apiName == null) return null
2021-07-29 00:19:42 +00:00
for (api in apis) {
if (apiName == api.name)
return api
}
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
}
fun Context.getApiSettings(): HashSet<String> {
2021-05-15 23:37:42 +00:00
val settingsManager = PreferenceManager.getDefaultSharedPreferences(this)
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
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
val list = HashSet<String>()
for (name in set) {
val api = getApiFromNameNull(name) ?: continue
if (activeLangs.contains(api.lang)) {
list.add(name)
}
}
if (list.isEmpty()) return hashSet
return list
2021-05-15 23:37:42 +00:00
}
2021-08-14 19:35:26 +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()
}
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()
)
if (list.isNullOrEmpty()) return hashSet
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
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()
if (realSet.isEmpty()) return hashSet
2021-08-14 19:35:26 +00:00
return realSet
}
fun Context.filterProviderByPreferredMedia(): List<MainAPI> {
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)
val langs = this.getApiProviderLangSettings()
val allApis = apis.filter { langs.contains(it.lang) }.filter { api -> api.hasMainPage }
return if (currentPrefMedia < 1) {
allApis
} else {
// Filter API depending on preferred media type
val listEnumAnime = listOf(TvType.Anime, TvType.AnimeMovie, TvType.ONA)
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
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
/**If all links are encrypted then set this to false*/
2021-07-23 23:44:54 +00:00
open val hasDownloadSupport = true
/**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,
2021-08-30 17:11:04 +00:00
TvType.ONA,
2021-08-14 17:31:27 +00:00
)
open val vpnStatus = VPNStatus.None
open val providerType = ProviderType.DirectProvider
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-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-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-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
}
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-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
}
}
/** Might need a different implementation for desktop*/
@SuppressLint("NewApi")
fun base64Decode(string: String): String {
return try {
String(android.util.Base64.decode(string, android.util.Base64.DEFAULT), Charsets.ISO_8859_1)
} catch (e: Exception) {
String(Base64.getDecoder().decode(string))
}
}
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? {
if (url.isNullOrEmpty()) {
return null
}
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
}
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
}
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)
}
enum class ProviderType {
// When data is fetched from a 3rd party site like imdb
MetaProvider,
// When all data is from the site
DirectProvider,
}
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,
ONA,
2021-08-30 17:11:04 +00:00
Torrent,
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 {
return this == TvType.Anime || this == TvType.ONA
}
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
}
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?,
2021-08-25 15:28:25 +00:00
val year: Int?,
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?
2021-06-26 14:44:53 +00:00
val rating: Int? // 0-100
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>?
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
return (this.type == TvType.Anime || this.type == TvType.ONA) // && (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,
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,
2021-04-30 17:20:15 +00:00
) : LoadResponse
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,
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,
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
}
fun LoadResponse.setDuration(input: String?) {
2021-12-13 18:41:33 +00:00
if (input == null) return
Regex("([0-9]*)h.*?([0-9]*)m").matchEntire(input)?.groupValues?.let { values ->
if (values.size == 3) {
2021-12-13 18:41:33 +00:00
val hours = values[1].toIntOrNull()
val minutes = values[2].toIntOrNull()
this.duration = if (minutes != null && hours != null) {
hours * 60 + minutes
} else null
2021-12-13 18:41:33 +00:00
}
}
Regex("([0-9]*)m").matchEntire(input)?.groupValues?.let { values ->
if (values.size == 2) {
2021-12-13 18:41:33 +00:00
this.duration = values[1].toIntOrNull()
}
}
}
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-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,
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,
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
}