diff --git a/Animasu/build.gradle.kts b/Animasu/build.gradle.kts index ce71e900..e938935a 100644 --- a/Animasu/build.gradle.kts +++ b/Animasu/build.gradle.kts @@ -1,5 +1,5 @@ // use an integer for version numbers -version = 3 +version = 4 cloudstream { diff --git a/Animasu/src/main/kotlin/com/hexated/Animasu.kt b/Animasu/src/main/kotlin/com/hexated/Animasu.kt index 04efbd3a..9be80866 100644 --- a/Animasu/src/main/kotlin/com/hexated/Animasu.kt +++ b/Animasu/src/main/kotlin/com/hexated/Animasu.kt @@ -9,7 +9,7 @@ import org.jsoup.Jsoup import org.jsoup.nodes.Element class Animasu : MainAPI() { - override var mainUrl = "https://animasu.uno" + override var mainUrl = "https://animasu.info" override var name = "Animasu" override val hasMainPage = true override var lang = "id" diff --git a/SoraStream/build.gradle.kts b/SoraStream/build.gradle.kts index 71382c79..7a3a9c0d 100644 --- a/SoraStream/build.gradle.kts +++ b/SoraStream/build.gradle.kts @@ -1,7 +1,7 @@ import org.jetbrains.kotlin.konan.properties.Properties // use an integer for version numbers -version = 172 +version = 173 android { defaultConfig { diff --git a/SoraStream/src/main/kotlin/com/hexated/Extractors.kt b/SoraStream/src/main/kotlin/com/hexated/Extractors.kt index 4f846a8c..9dc10e24 100644 --- a/SoraStream/src/main/kotlin/com/hexated/Extractors.kt +++ b/SoraStream/src/main/kotlin/com/hexated/Extractors.kt @@ -208,8 +208,7 @@ open class VCloud : ExtractorApi() { ) ).document.select("p.text-success ~ a").apmap { val link = it.attr("href") - val uri = URI(link) - if (uri.path.contains("workers.dev")) { + if (link.contains("workers.dev")) { callback.invoke( ExtractorLink( this.name, diff --git a/SoraStream/src/main/kotlin/com/hexated/SoraExtractor.kt b/SoraStream/src/main/kotlin/com/hexated/SoraExtractor.kt index 0feb4765..abd39122 100644 --- a/SoraStream/src/main/kotlin/com/hexated/SoraExtractor.kt +++ b/SoraStream/src/main/kotlin/com/hexated/SoraExtractor.kt @@ -1,6 +1,7 @@ package com.hexated import com.lagradost.cloudstream3.* +import com.lagradost.cloudstream3.APIHolder.unixTime import com.lagradost.cloudstream3.APIHolder.unixTimeMS import com.lagradost.cloudstream3.utils.* import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson @@ -1022,7 +1023,16 @@ object SoraExtractor : SoraStream() { } - + suspend fun invokeDotmovies( + title: String? = null, + year: Int? = null, + season: Int? = null, + episode: Int? = null, + subtitleCallback: (SubtitleFile) -> Unit, + callback: (ExtractorLink) -> Unit + ) { + invokeWpredis(title, year, season, episode, subtitleCallback, callback, dotmoviesAPI) + } suspend fun invokeVegamovies( title: String? = null, year: Int? = null, @@ -1031,7 +1041,18 @@ object SoraExtractor : SoraStream() { subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit ) { - var res = app.get("$vegaMoviesAPI/search/$title").document + invokeWpredis(title, year, season, episode, subtitleCallback, callback, vegaMoviesAPI) + } + private suspend fun invokeWpredis( + title: String? = null, + year: Int? = null, + season: Int? = null, + episode: Int? = null, + subtitleCallback: (SubtitleFile) -> Unit, + callback: (ExtractorLink) -> Unit, + api: String + ) { + var res = app.get("$api/search/$title").document val match = if (season == null) "$year" else "Season $season" val media = res.selectFirst("div.blog-items article:has(h3.entry-title:matches((?i)$title.*$match)) a") @@ -1048,7 +1069,7 @@ object SoraExtractor : SoraStream() { app.post( "${getBaseUrl(url)}/red.php", data = mapOf("link" to url), - referer = "$vegaMoviesAPI/" + referer = "$api/" ).text.substringAfter("location.href = \"").substringBefore("\"") } val selector = @@ -1059,7 +1080,7 @@ object SoraExtractor : SoraStream() { loadCustomTagExtractor( tags, server ?: return@apmap, - "$vegaMoviesAPI/", + "$api/", subtitleCallback, callback, getIndexQuality(it.text()) @@ -2401,7 +2422,7 @@ object SoraExtractor : SoraStream() { })?.substringAfter("id=")?.substringBefore("&") val server = app.get( - "$emoviesAPI/ajax/v4_get_sources?s=oserver&id=${id ?: return}&_=${APIHolder.unixTimeMS}", + "$emoviesAPI/ajax/v4_get_sources?s=oserver&id=${id ?: return}&_=${unixTimeMS}", headers = mapOf( "X-Requested-With" to "XMLHttpRequest" ) @@ -2513,7 +2534,7 @@ object SoraExtractor : SoraStream() { ExtractorLink( "Jump1", "Jump1", - "$jump1API/hls/${source ?: return}/master.m3u8?ts=${APIHolder.unixTimeMS}", + "$jump1API/hls/${source ?: return}/master.m3u8?ts=${unixTimeMS}", referer, Qualities.P1080.value, true @@ -2523,30 +2544,36 @@ object SoraExtractor : SoraStream() { suspend fun invokeNetflix( imdbId: String? = null, + title: String? = null, season: Int? = null, episode: Int? = null, callback: (ExtractorLink) -> Unit, ) { val headers = mapOf("X-Requested-With" to "XMLHttpRequest", "Cookie" to "hd=on") - val netflixId = imdbToNetflixId(imdbId, season) - val (title, id) = app.get( - "$netflixAPI/post.php?id=${netflixId ?: return}&t=${APIHolder.unixTime}", + val netflixId = imdbToNetflixId(imdbId, season) ?: run { + app.get("$netflixAPI/search.php?s=$title&t=${unixTime}", headers = headers) + .parsedSafe()?.searchResult?.find { it.t.equals(title) }?.id + } + val (t, id) = app.get( + "$netflixAPI/post.php?id=${netflixId ?: return}&t=${unixTime}", headers = headers ).parsedSafe().let { media -> if (season == null) { media?.title to netflixId } else { val seasonId = media?.season?.find { it.s == "$season" }?.id - val episodeId = app.get( - "$netflixAPI/episodes.php?s=${seasonId}&series=$netflixId&t=${APIHolder.unixTime}", - headers = headers - ).parsedSafe()?.episodes?.find { it.ep == "E$episode" }?.id + val episodeId = + app.get( + "$netflixAPI/episodes.php?s=${seasonId}&series=$netflixId&t=${unixTime}", + headers = headers + ) + .parsedSafe()?.episodes?.find { it.ep == "E$episode" }?.id media?.title to episodeId } } app.get( - "$netflixAPI/playlist.php?id=${id ?: return}&t=${title ?: return}&tm=${APIHolder.unixTime}", + "$netflixAPI/playlist.php?id=${id ?: return}&t=${t ?: return}&tm=${unixTime}", headers = headers ).text.let { tryParseJson>(it) diff --git a/SoraStream/src/main/kotlin/com/hexated/SoraParser.kt b/SoraStream/src/main/kotlin/com/hexated/SoraParser.kt index b85cf61d..538176da 100644 --- a/SoraStream/src/main/kotlin/com/hexated/SoraParser.kt +++ b/SoraStream/src/main/kotlin/com/hexated/SoraParser.kt @@ -419,3 +419,12 @@ data class NetflixResponse( @JsonProperty("episodes") val episodes: ArrayList? = arrayListOf(), @JsonProperty("sources") val sources: ArrayList? = arrayListOf(), ) + +data class NetflixSearchResult( + @JsonProperty("t") val t: String? = null, + @JsonProperty("id") val id: String? = null, +) + +data class NetflixSearch( + @JsonProperty("searchResult") val searchResult: ArrayList? = arrayListOf(), +) diff --git a/SoraStream/src/main/kotlin/com/hexated/SoraStream.kt b/SoraStream/src/main/kotlin/com/hexated/SoraStream.kt index 25f6dea4..21095851 100644 --- a/SoraStream/src/main/kotlin/com/hexated/SoraStream.kt +++ b/SoraStream/src/main/kotlin/com/hexated/SoraStream.kt @@ -14,6 +14,7 @@ import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer import com.lagradost.cloudstream3.metaproviders.TmdbProvider import com.hexated.SoraExtractor.invokeDahmerMovies import com.hexated.SoraExtractor.invokeDoomovies +import com.hexated.SoraExtractor.invokeDotmovies import com.hexated.SoraExtractor.invokeDramaday import com.hexated.SoraExtractor.invokeDreamfilm import com.hexated.SoraExtractor.invokeFDMovies @@ -129,6 +130,7 @@ open class SoraStream : TmdbProvider() { const val netflixAPI = "https://m.netflixmirror.com" const val hdmovies4uAPI = "https://hdmovies4u.name" const val watchflxAPI = "https://watchflx.tv" + const val dotmoviesAPI = "https://dotmovies.today" // INDEX SITE const val dahmerMoviesAPI = "https://edytjedhgmdhm.abfhaqrhbnf.workers.dev" @@ -247,6 +249,7 @@ open class SoraStream : TmdbProvider() { val isAnime = genres?.contains("Animation") == true && (res.original_language == "zh" || res.original_language == "ja") val isAsian = !isAnime && (res.original_language == "zh" || res.original_language == "ko") + val isBollywood = res.production_countries?.any { it.name == "India" } ?: false val keywords = res.keywords?.results?.mapNotNull { it.name }.orEmpty() .ifEmpty { res.keywords?.keywords?.mapNotNull { it.name } } @@ -289,6 +292,7 @@ open class SoraStream : TmdbProvider() { date = season.airDate, airedDate = res.releaseDate ?: res.firstAirDate, isAsian = isAsian, + isBollywood = isBollywood ).toJson(), name = eps.name + if (isUpcoming(eps.airDate)) " - [UPCOMING]" else "", season = eps.seasonNumber, @@ -337,6 +341,7 @@ open class SoraStream : TmdbProvider() { jpTitle = res.alternative_titles?.results?.find { it.iso_3166_1 == "JP" }?.title, airedDate = res.releaseDate ?: res.firstAirDate, isAsian = isAsian, + isBollywood = isBollywood ).toJson(), ) { this.posterUrl = poster @@ -525,7 +530,7 @@ open class SoraStream : TmdbProvider() { ) }, { - if (!res.isAnime) invokeBollyMaza( + if (!res.isAnime && res.isBollywood) invokeBollyMaza( bollyMazaAPI, "BollyMaza", res.title, @@ -653,6 +658,16 @@ open class SoraStream : TmdbProvider() { callback ) }, + { + if (!res.isAnime && res.isBollywood) invokeDotmovies( + res.title, + res.year, + res.season, + res.episode, + subtitleCallback, + callback + ) + }, { if (!res.isAnime && res.season == null) invokePobmovies( res.title, @@ -710,6 +725,7 @@ open class SoraStream : TmdbProvider() { { if (!res.isAnime) invokeNetflix( res.imdbId, + res.title, res.season, res.episode, callback @@ -763,6 +779,7 @@ open class SoraStream : TmdbProvider() { val date: String? = null, val airedDate: String? = null, val isAsian: Boolean = false, + val isBollywood: Boolean = false, ) data class Data( @@ -867,6 +884,10 @@ open class SoraStream : TmdbProvider() { @JsonProperty("season_number") val season_number: Int? = null, ) + data class ProductionCountries( + @JsonProperty("name") val name: String? = null, + ) + data class MediaDetail( @JsonProperty("id") val id: Int? = null, @JsonProperty("imdb_id") val imdbId: String? = null, @@ -892,6 +913,7 @@ open class SoraStream : TmdbProvider() { @JsonProperty("credits") val credits: Credits? = null, @JsonProperty("recommendations") val recommendations: ResultsRecommendations? = null, @JsonProperty("alternative_titles") val alternative_titles: ResultsAltTitles? = null, + @JsonProperty("production_countries") val production_countries: ArrayList? = arrayListOf(), ) } diff --git a/SoraStream/src/main/kotlin/com/hexated/SoraStreamLite.kt b/SoraStream/src/main/kotlin/com/hexated/SoraStreamLite.kt index 79053efc..a262379c 100644 --- a/SoraStream/src/main/kotlin/com/hexated/SoraStreamLite.kt +++ b/SoraStream/src/main/kotlin/com/hexated/SoraStreamLite.kt @@ -316,6 +316,7 @@ class SoraStreamLite : SoraStream() { { if (!res.isAnime) invokeNetflix( res.imdbId, + res.title, res.season, res.episode, callback diff --git a/SoraStream/src/main/kotlin/com/hexated/SoraUtils.kt b/SoraStream/src/main/kotlin/com/hexated/SoraUtils.kt index b2c3e9ac..64e34d0f 100644 --- a/SoraStream/src/main/kotlin/com/hexated/SoraUtils.kt +++ b/SoraStream/src/main/kotlin/com/hexated/SoraUtils.kt @@ -17,6 +17,7 @@ import com.hexated.SoraStream.Companion.watchhubApi import com.lagradost.cloudstream3.* import com.lagradost.cloudstream3.APIHolder.getCaptchaToken import com.lagradost.cloudstream3.APIHolder.unixTimeMS +import com.lagradost.cloudstream3.mvvm.logError import com.lagradost.cloudstream3.utils.* import com.lagradost.cloudstream3.utils.AppUtils.toJson import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson @@ -1334,10 +1335,14 @@ fun getBaseUrl(url: String): String { } fun isUpcoming(dateString: String?): Boolean { - if (dateString == null) return false - val format = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()) - val dateTime = format.parse(dateString)?.time ?: return false - return unixTimeMS < dateTime + return try { + val format = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()) + val dateTime = dateString?.let { format.parse(it)?.time } ?: return false + return unixTimeMS < dateTime + } catch (t: Throwable) { + logError(t) + false + } } fun decode(input: String): String = URLDecoder.decode(input, "utf-8") diff --git a/StremioX/build.gradle.kts b/StremioX/build.gradle.kts index 3366ed71..fb6333b2 100644 --- a/StremioX/build.gradle.kts +++ b/StremioX/build.gradle.kts @@ -1,5 +1,5 @@ // use an integer for version numbers -version = 10 +version = 11 cloudstream { diff --git a/StremioX/src/main/kotlin/com/hexated/Utils.kt b/StremioX/src/main/kotlin/com/hexated/Utils.kt index a75987a5..1b215411 100644 --- a/StremioX/src/main/kotlin/com/hexated/Utils.kt +++ b/StremioX/src/main/kotlin/com/hexated/Utils.kt @@ -1,6 +1,7 @@ package com.hexated import com.lagradost.cloudstream3.APIHolder +import com.lagradost.cloudstream3.mvvm.logError import com.lagradost.nicehttp.Requests.Companion.await import okhttp3.OkHttpClient import okhttp3.Request @@ -58,10 +59,15 @@ fun getEpisodeSlug( } fun isUpcoming(dateString: String?): Boolean { - if (dateString == null) return false - val format = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()) - val dateTime = format.parse(dateString)?.time ?: return false - return APIHolder.unixTimeMS < dateTime + return try { + val format = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()) + val dateTime = dateString?.let { format.parse(it)?.time } ?: return false + return APIHolder.unixTimeMS < dateTime + } catch (t: Throwable) { + logError(t) + false + } + } fun fixUrl(url: String, domain: String): String {