diff --git a/SoraStream/build.gradle.kts b/SoraStream/build.gradle.kts index cc49bd00..5dddfb7e 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 = 147 +version = 148 android { defaultConfig { diff --git a/SoraStream/src/main/kotlin/com/hexated/SoraExtractor.kt b/SoraStream/src/main/kotlin/com/hexated/SoraExtractor.kt index 8b3819d5..829ca294 100644 --- a/SoraStream/src/main/kotlin/com/hexated/SoraExtractor.kt +++ b/SoraStream/src/main/kotlin/com/hexated/SoraExtractor.kt @@ -6,6 +6,8 @@ import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson import com.lagradost.nicehttp.Requests import com.lagradost.nicehttp.Session import com.hexated.RabbitStream.extractRabbitStream +import com.lagradost.cloudstream3.extractors.Filesim +import com.lagradost.cloudstream3.extractors.StreamSB import com.lagradost.cloudstream3.extractors.helper.GogoHelper import com.lagradost.cloudstream3.network.CloudflareKiller import com.lagradost.nicehttp.RequestBodyTypes @@ -437,6 +439,41 @@ object SoraExtractor : SoraStream() { } } + suspend fun invokeMultimovies( + title: String? = null, + season: Int? = null, + episode: Int? = null, + subtitleCallback: (SubtitleFile) -> Unit, + callback: (ExtractorLink) -> Unit + ) { + val fixTitle = title.createSlug() + val url = if (season == null) { + "$multimoviesAPI/movies/$fixTitle" + } else { + "$multimoviesAPI/episodes/$fixTitle-${season}x${episode}" + } + + val res = app.get(url) + val referer = getBaseUrl(res.url) + val document = res.document + val id = document.select("meta#dooplay-ajax-counter").attr("data-postid") + val type = if (url.contains("/movies/")) "movie" else "tv" + + document.select("ul#playeroptionsul > li").map { + it.attr("data-nume") + }.apmap { nume -> + val source = app.post( + url = "$referer/wp-admin/admin-ajax.php", data = mapOf( + "action" to "doo_player_ajax", "post" to id, "nume" to nume, "type" to type + ), headers = mapOf("X-Requested-With" to "XMLHttpRequest"), referer = url + ).parsed().embed_url.let { Jsoup.parse(it).select("IFRAME").attr("SRC") } + + if (!source.contains("youtube")) { + loadExtractor(source, "$referer/", subtitleCallback, callback) + } + } + } + suspend fun invokeUniqueStream( title: String? = null, year: Int? = null, @@ -2029,7 +2066,7 @@ object SoraExtractor : SoraStream() { it.attr("data-id") to it.text() }.apmap { when { - it.first.contains("/ffix") && !isAnime -> { + it.first.contains("/fix.php") && !isAnime -> { invokeSmashyFfix(it.second, it.first, url, callback) } it.first.contains("/gtop") -> { @@ -2044,6 +2081,9 @@ object SoraExtractor : SoraStream() { it.first.contains("/im.php") && !isAnime -> { invokeSmashyIm(it.second, it.first, subtitleCallback, callback) } + it.first.contains("/rw.php") && !isAnime -> { + invokeSmashyRw(it.second, it.first, subtitleCallback, callback) + } else -> return@apmap } } @@ -3225,3 +3265,18 @@ object SoraExtractor : SoraStream() { } +class Animefever : Filesim() { + override val name = "Animefever" + override var mainUrl = "https://animefever.fun" +} + +class Multimovies : Filesim() { + override val name = "Multimovies" + override var mainUrl = "https://multimovies.cloud" +} + +class MultimoviesSB : StreamSB() { + override var name = "Multimovies" + override var mainUrl = "https://multimovies.website" +} + diff --git a/SoraStream/src/main/kotlin/com/hexated/SoraStream.kt b/SoraStream/src/main/kotlin/com/hexated/SoraStream.kt index 16d00b6b..090117d8 100644 --- a/SoraStream/src/main/kotlin/com/hexated/SoraStream.kt +++ b/SoraStream/src/main/kotlin/com/hexated/SoraStream.kt @@ -50,6 +50,7 @@ import com.hexated.SoraExtractor.invokeSmashyStream import com.hexated.SoraExtractor.invokeDumpStream import com.hexated.SoraExtractor.invokeEmovies import com.hexated.SoraExtractor.invokeFourCartoon +import com.hexated.SoraExtractor.invokeMultimovies import com.hexated.SoraExtractor.invokePobmovies import com.hexated.SoraExtractor.invokeTvMovies import com.hexated.SoraExtractor.invokeUhdmovies @@ -98,7 +99,6 @@ open class SoraStream : TmdbProvider() { const val uniqueStreamAPI = "https://uniquestream.net" const val filmxyAPI = "https://www.filmxy.vip" const val kimcartoonAPI = "https://kimcartoon.li" - const val xMovieAPI = "https://xemovies.to" const val aniwatchAPI = "https://aniwatch.to" const val crunchyrollAPI = "https://beta-api.crunchyroll.com" const val kissKhAPI = "https://kisskh.co" @@ -114,7 +114,6 @@ open class SoraStream : TmdbProvider() { const val moviesbayAPI = "https://moviesbay.live" const val rStreamAPI = "https://remotestre.am" const val flixonAPI = "https://flixon.lol" - const val animeKaizokuAPI = "https://animekaizoku.com" const val movie123NetAPI = "https://ww8.0123movie.net" const val smashyStreamAPI = "https://embed.smashystream.com" const val watchSomuchAPI = "https://watchsomuch.tv" // sub only @@ -132,6 +131,7 @@ open class SoraStream : TmdbProvider() { const val emoviesAPI = "https://emovies.si" const val pobmoviesAPI = "https://pobmovies.cam" const val fourCartoonAPI = "https://4cartoon.net" + const val multimoviesAPI = "https://multimovies.xyz" // INDEX SITE const val blackMoviesAPI = "https://dl.blacklistedbois.workers.dev/0:" @@ -157,6 +157,8 @@ open class SoraStream : TmdbProvider() { const val baymoviesAPI = "https://opengatewayindex.pages.dev" const val papaonMovies1API = "https://m.papaonwork.workers.dev/0:" const val papaonMovies2API = "https://m.papaonwork.workers.dev/1:" + const val animeKaizokuAPI = "https://animekaizoku.com" + const val xMovieAPI = "https://xemovies.to" fun getType(t: String?): TvType { return when (t) { @@ -815,6 +817,9 @@ open class SoraStream : TmdbProvider() { }, { if(!res.isAnime) invokeFourCartoon(res.title, res.year, res.season, res.episode, callback) + }, + { + invokeMultimovies(res.title,res.season,res.episode,subtitleCallback,callback) } ) diff --git a/SoraStream/src/main/kotlin/com/hexated/SoraStreamLite.kt b/SoraStream/src/main/kotlin/com/hexated/SoraStreamLite.kt index dec99931..285f002e 100644 --- a/SoraStream/src/main/kotlin/com/hexated/SoraStreamLite.kt +++ b/SoraStream/src/main/kotlin/com/hexated/SoraStreamLite.kt @@ -29,6 +29,7 @@ import com.hexated.SoraExtractor.invokeSmashyStream import com.hexated.SoraExtractor.invokeDumpStream import com.hexated.SoraExtractor.invokeEmovies import com.hexated.SoraExtractor.invokeFourCartoon +import com.hexated.SoraExtractor.invokeMultimovies import com.hexated.SoraExtractor.invokeVidSrc import com.hexated.SoraExtractor.invokeWatchOnline import com.hexated.SoraExtractor.invokeWatchsomuch @@ -308,6 +309,9 @@ class SoraStreamLite : SoraStream() { res.episode, callback ) + }, + { + invokeMultimovies(res.title,res.season,res.episode,subtitleCallback,callback) } ) diff --git a/SoraStream/src/main/kotlin/com/hexated/SoraStreamPlugin.kt b/SoraStream/src/main/kotlin/com/hexated/SoraStreamPlugin.kt index 27f4b152..69a6aec1 100644 --- a/SoraStream/src/main/kotlin/com/hexated/SoraStreamPlugin.kt +++ b/SoraStream/src/main/kotlin/com/hexated/SoraStreamPlugin.kt @@ -11,5 +11,8 @@ class SoraStreamPlugin: Plugin() { // All providers should be added in this manner. Please don't edit the providers list directly. registerMainAPI(SoraStream()) registerMainAPI(SoraStreamLite()) + registerExtractorAPI(Animefever()) + registerExtractorAPI(Multimovies()) + registerExtractorAPI(MultimoviesSB()) } } \ No newline at end of file diff --git a/SoraStream/src/main/kotlin/com/hexated/SoraUtils.kt b/SoraStream/src/main/kotlin/com/hexated/SoraUtils.kt index 5f2ae0fd..a92603b6 100644 --- a/SoraStream/src/main/kotlin/com/hexated/SoraUtils.kt +++ b/SoraStream/src/main/kotlin/com/hexated/SoraUtils.kt @@ -597,6 +597,32 @@ suspend fun invokeSmashyIm( } +suspend fun invokeSmashyRw( + name: String, + url: String, + subtitleCallback: (SubtitleFile) -> Unit, + callback: (ExtractorLink) -> Unit, +) { + val res = app.get(url).document + val video = res.selectFirst("media-player")?.attr("src") + + M3u8Helper.generateM3u8( + "Smashy [$name]", + video ?: return, + "" + ).forEach(callback) + + res.select("track").map { track -> + subtitleCallback.invoke( + SubtitleFile( + track.attr("label"), + track.attr("src"), + ) + ) + } + +} + suspend fun getDumpIdAndType(title: String?, year: Int?, season: Int?): Pair { val res = tryParseJson( queryApi(