diff --git a/SoraStream/build.gradle.kts b/SoraStream/build.gradle.kts index 3136cc81..f5e85a9f 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 = 219 +version = 220 android { defaultConfig { diff --git a/SoraStream/src/main/kotlin/com/hexated/SoraExtractor.kt b/SoraStream/src/main/kotlin/com/hexated/SoraExtractor.kt index a13270f9..04d92787 100644 --- a/SoraStream/src/main/kotlin/com/hexated/SoraExtractor.kt +++ b/SoraStream/src/main/kotlin/com/hexated/SoraExtractor.kt @@ -2337,43 +2337,23 @@ object SoraExtractor : SoraStream() { subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit, ) { - val id = imdbId?.removePrefix("tt") - val slug = title.createSlug() - val url = if (season == null) { - "$cinemaTvAPI/movies/play/$id-$slug-$year" + val media = app.get("$cinemaTvAPI/v1/${if (season == null) "movies" else "shows"}?filters[q]=$title") + .parsedSafe()?.items?.find { + it.imdb_id?.removePrefix("tt") + .equals(imdbId?.removePrefix("tt")) || (it.title.equals( + title, + true + ) && it.year == year) + } ?: return + + val mediaId = if (season == null) { + media.id_movie } else { - "$cinemaTvAPI/shows/play/$id-$slug-$year" - } + app.get("$cinemaTvAPI/v1/shows?expand=episodes&id=${media.id_show}") + .parsedSafe()?.episodes?.find { it.episode == episode && it.season == season }?.id + } ?: return - val session = - "PHPSESSID=ngr4cudjrimdnhkth30ssohs0n; _csrf=a6ffd7bb7654083fce6df528225a238d0e85aa1fb885dc7638c1259ec1ba0d5ca%3A2%3A%7Bi%3A0%3Bs%3A5%3A%22_csrf%22%3Bi%3A1%3Bs%3A32%3A%22mTTLiDLjxohs-CpKk0bjRH3HdYMB9uBV%22%3B%7D; _ga=GA1.1.1195498587.1701871187; _ga_VZD7HJ3WK6=GS1.1.$unixTime.4.0.1.$unixTime.0.0.0" - - val headers = mapOf( - "Cookie" to session, - "x-requested-with" to "com.wwcinematv", - ) - - val doc = app.get(url, headers = headers).document - val script = doc.selectFirst("script:containsData(hash:)")?.data() - val hash = Regex("hash:\\s*['\"](\\S+)['\"]").find(script ?: return)?.groupValues?.get(1) - val expires = Regex("expires:\\s*(\\d+)").find(script)?.groupValues?.get(1) - val episodeId = (if (season == null) { - """id_movie:\s*(\d+)""" - } else { - """episode:\s*['"]$episode['"],[\n\s]+id_episode:\s*(\d+),[\n\s]+season:\s*['"]$season['"]""" - }).let { it.toRegex().find(script)?.groupValues?.get(1) } - - val videoUrl = if (season == null) { - "$cinemaTvAPI/api/v1/security/movie-access?id_movie=$episodeId&hash=$hash&expires=$expires" - } else { - "$cinemaTvAPI/api/v1/security/episode-access?id_episode=$episodeId&hash=$hash&expires=$expires" - } - - val sources = app.get( - videoUrl, - referer = url, - headers = mapOf("X-Requested-With" to "XMLHttpRequest") - ).parsedSafe() + val sources = app.get("$cinemaTvAPI/v1/${if (season == null) "movies" else "episodes"}/view?expand=streams,subtitles&id=$mediaId").parsedSafe() sources?.streams?.mapKeys { source -> callback.invoke( @@ -2381,19 +2361,18 @@ object SoraExtractor : SoraStream() { "CinemaTv", "CinemaTv", source.value, - "$cinemaTvAPI/", + "", getQualityFromName(source.key), true ) ) } - sources?.subtitles?.map { sub -> - val file = sub.file.toString() + sources?.subtitles?.map { subtitleCallback.invoke( SubtitleFile( - sub.language ?: return@map, - if (file.startsWith("[")) return@map else fixUrl(file, cinemaTvAPI), + it.language ?: return@map, + fixUrl(it.url ?: return@map, cinemaTvAPI) ) ) } diff --git a/SoraStream/src/main/kotlin/com/hexated/SoraParser.kt b/SoraStream/src/main/kotlin/com/hexated/SoraParser.kt index 57d1a5d7..199833bf 100644 --- a/SoraStream/src/main/kotlin/com/hexated/SoraParser.kt +++ b/SoraStream/src/main/kotlin/com/hexated/SoraParser.kt @@ -191,15 +191,31 @@ data class JikanResponse( @JsonProperty("data") val data: JikanData? = null, ) -data class CinemaTvSubtitles( - @JsonProperty("language") val language: String? = null, - @JsonProperty("file") val file: Any? = null, -) - data class CinemaTvResponse( + @JsonProperty("items") val items: ArrayList? = arrayListOf(), + @JsonProperty("episodes") val episodes: ArrayList? = arrayListOf(), @JsonProperty("streams") val streams: HashMap? = null, - @JsonProperty("subtitles") val subtitles: ArrayList? = arrayListOf(), -) + @JsonProperty("subtitles") val subtitles: ArrayList? = arrayListOf(), + ) { + data class Items( + @JsonProperty("id_movie") val id_movie: Int? = null, + @JsonProperty("id_show") val id_show: Int? = null, + @JsonProperty("title") val title: String? = null, + @JsonProperty("year") val year: Int? = null, + @JsonProperty("imdb_id") val imdb_id: String? = null, + ) + + data class Episodes( + @JsonProperty("id") val id: Int? = null, + @JsonProperty("season") val season: Int? = null, + @JsonProperty("episode") val episode: Int? = null, + ) + + data class Subtitles( + @JsonProperty("language") val language: String? = null, + @JsonProperty("url") val url: String? = null, + ) +} data class VidsrctoResult( @JsonProperty("id") val id: String? = null, diff --git a/SoraStream/src/main/kotlin/com/hexated/SoraStream.kt b/SoraStream/src/main/kotlin/com/hexated/SoraStream.kt index c4e713bf..ce4508ff 100644 --- a/SoraStream/src/main/kotlin/com/hexated/SoraStream.kt +++ b/SoraStream/src/main/kotlin/com/hexated/SoraStream.kt @@ -717,12 +717,12 @@ open class SoraStream : TmdbProvider() { callback ) }, - { - if (!res.isAnime) invokeSFMovies( - res.id, res.title, res.airedYear - ?: res.year, res.season, res.episode, callback - ) - }, +// { +// if (!res.isAnime) invokeSFMovies( +// res.id, res.title, res.airedYear +// ?: res.year, res.season, res.episode, callback +// ) +// }, // { // invokeMMovies(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 e38f4da7..b4f38a3d 100644 --- a/SoraStream/src/main/kotlin/com/hexated/SoraStreamLite.kt +++ b/SoraStream/src/main/kotlin/com/hexated/SoraStreamLite.kt @@ -326,12 +326,12 @@ class SoraStreamLite : SoraStream() { callback ) }, - { - if (!res.isAnime) invokeSFMovies( - res.id, res.title, res.airedYear - ?: res.year, res.season, res.episode, callback - ) - }, +// { +// if (!res.isAnime) invokeSFMovies( +// res.id, res.title, res.airedYear +// ?: res.year, res.season, res.episode, callback +// ) +// }, // { // invokeMMovies(res.title, res.season, res.episode, subtitleCallback, callback) // },