From b4366f6368f618159d1c70da6e9be6147c0f359f Mon Sep 17 00:00:00 2001 From: antonydp <38143733+antonydp@users.noreply.github.com> Date: Wed, 7 Dec 2022 00:35:00 +0100 Subject: [PATCH] Italian providers fixes and improvements (#47) --- AltadefinizioneProvider/build.gradle.kts | 2 +- .../com/lagradost/AltadefinizioneProvider.kt | 127 ++--- AniPlayProvider/build.gradle.kts | 2 +- .../kotlin/com/lagradost/AniPlayProvider.kt | 55 +- AnimeWorldProvider/build.gradle.kts | 2 +- .../com/lagradost/AnimeWorldProvider.kt | 5 +- CineBlog01Provider/build.gradle.kts | 2 +- .../kotlin/com/lagradost/CineBlogProvider.kt | 105 ++-- .../kotlin/com/lagradost/CineBlogProvider.kt | 171 +++--- EurostreamingProvider/build.gradle.kts | 2 +- FilmpertuttiProvider/build.gradle.kts | 2 +- .../com/lagradost/FilmpertuttiProvider.kt | 24 +- GuardaSerieProvider/build.gradle.kts | 2 +- .../com/lagradost/GuardaSerieProvider.kt | 17 +- .../build.gradle.kts | 2 +- SoraItalianStream/build.gradle.kts | 29 + .../src/main/AndroidManifest.xml | 2 + .../src/main/kotlin/SoraItalianExtractor.kt | 402 ++++++++++++++ .../src/main/kotlin/SoraItalianStream.kt | 511 ++++++++++++++++++ .../main/kotlin/SoraItalianStreamPlugin.kt | 13 + StreamingcommunityProvider/build.gradle.kts | 4 +- .../lagradost/StreamingcommunityProvider.kt | 37 +- TantiFilmProvider/build.gradle.kts | 2 +- .../kotlin/com/lagradost/TantiFilmProvider.kt | 4 +- TvItalianaProvider/build.gradle.kts | 2 +- .../com/lagradost/TvItalianaProvider.kt | 189 ++++++- 26 files changed, 1389 insertions(+), 326 deletions(-) create mode 100644 SoraItalianStream/build.gradle.kts create mode 100644 SoraItalianStream/src/main/AndroidManifest.xml create mode 100644 SoraItalianStream/src/main/kotlin/SoraItalianExtractor.kt create mode 100644 SoraItalianStream/src/main/kotlin/SoraItalianStream.kt create mode 100644 SoraItalianStream/src/main/kotlin/SoraItalianStreamPlugin.kt diff --git a/AltadefinizioneProvider/build.gradle.kts b/AltadefinizioneProvider/build.gradle.kts index 4d19548..ed63616 100644 --- a/AltadefinizioneProvider/build.gradle.kts +++ b/AltadefinizioneProvider/build.gradle.kts @@ -1,5 +1,5 @@ // use an integer for version numbers -version = 2 +version = 3 cloudstream { diff --git a/AltadefinizioneProvider/src/main/kotlin/com/lagradost/AltadefinizioneProvider.kt b/AltadefinizioneProvider/src/main/kotlin/com/lagradost/AltadefinizioneProvider.kt index 838332f..252911d 100644 --- a/AltadefinizioneProvider/src/main/kotlin/com/lagradost/AltadefinizioneProvider.kt +++ b/AltadefinizioneProvider/src/main/kotlin/com/lagradost/AltadefinizioneProvider.kt @@ -1,15 +1,18 @@ package com.lagradost import com.lagradost.cloudstream3.* +import com.lagradost.cloudstream3.LoadResponse.Companion.addActors +import com.lagradost.cloudstream3.LoadResponse.Companion.addRating import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer import com.lagradost.cloudstream3.utils.ExtractorLink import com.lagradost.cloudstream3.utils.loadExtractor -import com.lagradost.cloudstream3.utils.AppUtils.html +import okhttp3.FormBody +import org.jsoup.nodes.Element class AltadefinizioneProvider : MainAPI() { override var lang = "it" - override var mainUrl = "https://altadefinizione.clinic" + override var mainUrl = "https://altadefinizione.navy" override var name = "Altadefinizione" override val hasMainPage = true override val hasChromecastSupport = true @@ -25,109 +28,76 @@ class AltadefinizioneProvider : MainAPI() { override suspend fun getMainPage(page: Int, request: MainPageRequest): HomePageResponse { val url = request.data + page - val soup = app.get(url).document - val home = soup.select("div.box").map { - val title = it.selectFirst("img")!!.attr("alt") - val link = it.selectFirst("a")!!.attr("href") - val image = mainUrl + it.selectFirst("img")!!.attr("src") - val quality = getQualityFromString(it.selectFirst("span")!!.text()) - - MovieSearchResponse( - title, - link, - this.name, - TvType.Movie, - image, - null, - null, - quality, - ) + val home = soup.select("div.box").mapNotNull { + it.toSearchResult() + } + return newHomePageResponse(arrayListOf(HomePageList(request.name, home)), hasNext = true) + } + + private fun Element.toSearchResult(): SearchResponse? { + val title = this.selectFirst("img")?.attr("alt") ?: return null + val link = this.selectFirst("a")?.attr("href") ?: return null + val image = mainUrl + this.selectFirst("img")?.attr("src") + val quality = getQualityFromString(this.selectFirst("span")?.text()) + return newMovieSearchResponse(title, link, TvType.Movie) { + this.posterUrl = image + this.quality = quality } - return newHomePageResponse(request.name, home) } override suspend fun search(query: String): List { + val body = FormBody.Builder() + .addEncoded("do", "search") + .addEncoded("subaction", "search") + .addEncoded("story", query) + .addEncoded("sortby", "news_read") + .build() + val doc = app.post( - "$mainUrl/index.php", data = mapOf( - "do" to "search", - "subaction" to "search", - "story" to query, - "sortby" to "news_read" - ) + "$mainUrl/index.php", + requestBody = body ).document - return doc.select("div.box").map { - val title = it.selectFirst("img")!!.attr("alt") - val link = it.selectFirst("a")!!.attr("href") - val image = mainUrl + it.selectFirst("img")!!.attr("src") - val quality = getQualityFromString(it.selectFirst("span")!!.text()) - MovieSearchResponse( - title, - link, - this.name, - TvType.Movie, - image, - null, - null, - quality, - ) + return doc.select("div.box").mapNotNull { + it.toSearchResult() } } override suspend fun load(url: String): LoadResponse { - val page = app.get(url) - val document = page.document - val title = document.selectFirst(" h1 > a")!!.text().replace("streaming", "") - val description = document.select("#sfull").toString().substringAfter("altadefinizione") - .substringBeforeLast("fonte trama").html().toString() - val rating = null - - val year = document.selectFirst("#details > li:nth-child(2)")!!.childNode(2).toString() - .filter { it.isDigit() }.toInt() - - val poster = fixUrl(document.selectFirst("div.thumbphoto > img")!!.attr("src")) - - val recomm = document.select("ul.related-list > li").map { - val href = it.selectFirst("a")!!.attr("href") - val posterUrl = mainUrl + it.selectFirst("img")!!.attr("src") - val name = it.selectFirst("img")!!.attr("alt") - MovieSearchResponse( - name, - href, - this.name, - TvType.Movie, - posterUrl, - null - ) + val document = app.get(url).document + val title = document.selectFirst(" h1 > a")?.text()?.replace("streaming", "") + ?: throw ErrorLoadingException("No Title found") + val description = document.select("#sfull").textNodes().first { it.text().trim().isNotEmpty() }.text().trim() + val rating = document.select("span.rateIMDB").text().substringAfter(" ") + val year = document.selectFirst("#details")?.select("li") + ?.firstOrNull { it.select("label").text().contains("Anno") } + ?.text()?.substringAfter(" ")?.toIntOrNull() + val poster = fixUrl(document.selectFirst("div.thumbphoto > img")?.attr("src")?: throw ErrorLoadingException("No Poster found") ) + val recomm = document.select("ul.related-list > li").mapNotNull { + it.toSearchResult() } - - - val actors: List = + val actors: List = document.select("#staring > a").map { - ActorData(actor = Actor(it.text())) + Actor(it.text()) } - val tags: List = document.select("#details > li:nth-child(1) > a").map { it.text() } - - val trailerurl = document.selectFirst("#showtrailer > div > div > iframe")?.attr("src") - + val trailerUrl = document.selectFirst("#showtrailer > div > div > iframe")?.attr("src") return newMovieLoadResponse( title, url, TvType.Movie, url ) { - posterUrl = fixUrlNull(poster) this.year = year this.plot = description - this.rating = rating this.recommendations = recomm - this.duration = null - this.actors = actors this.tags = tags - addTrailer(trailerurl) + addActors(actors) + addPoster(poster) + addRating(rating) + addTrailer(trailerUrl) } } @@ -153,7 +123,6 @@ class AltadefinizioneProvider : MainAPI() { loadExtractor(fixUrl(it.attr("data-link")), data, subtitleCallback, callback) } } - return true } } \ No newline at end of file diff --git a/AniPlayProvider/build.gradle.kts b/AniPlayProvider/build.gradle.kts index 788b96c..2247b83 100644 --- a/AniPlayProvider/build.gradle.kts +++ b/AniPlayProvider/build.gradle.kts @@ -1,5 +1,5 @@ // use an integer for version numbers -version = 3 +version = 4 cloudstream { diff --git a/AniPlayProvider/src/main/kotlin/com/lagradost/AniPlayProvider.kt b/AniPlayProvider/src/main/kotlin/com/lagradost/AniPlayProvider.kt index 1aea8ba..1d07a4d 100644 --- a/AniPlayProvider/src/main/kotlin/com/lagradost/AniPlayProvider.kt +++ b/AniPlayProvider/src/main/kotlin/com/lagradost/AniPlayProvider.kt @@ -51,11 +51,15 @@ class AniPlayProvider : MainAPI() { data class ApiMainPageAnime( @JsonProperty("animeId") val id: Int, + @JsonProperty("id") val id2: Int, @JsonProperty("episodeNumber") val episode: String?, - @JsonProperty("animeTitle") val title: String, - @JsonProperty("animeType") val type: String, + @JsonProperty("animeTitle") val title: String?, + @JsonProperty("title") val title2: String?, + @JsonProperty("animeType") val type: String?, + @JsonProperty("type") val type2: String?, @JsonProperty("fullHd") val fullHD: Boolean, - @JsonProperty("animeVerticalImages") val posters: List + @JsonProperty("animeVerticalImages") val posters: List?, + @JsonProperty("verticalImages") val posters2: List? ) data class ApiSearchResult( @@ -107,6 +111,7 @@ class AniPlayProvider : MainAPI() { @JsonProperty("status") val status: String, @JsonProperty("genres") val genres: List, @JsonProperty("verticalImages") val posters: List, + @JsonProperty("horizontalImages") val horizontalPosters: List, @JsonProperty("listWebsites") val websites: List, @JsonProperty("episodes") val episodes: List, @JsonProperty("seasons") val seasons: List? @@ -115,23 +120,29 @@ class AniPlayProvider : MainAPI() { data class ApiEpisodeUrl( @JsonProperty("videoUrl") val url: String ) + override val mainPage = mainPageOf( + Pair("$mainUrl/api/home/latest-episodes?page=", "Ultime uscite"), + Pair("$mainUrl/api/anime/advanced-search?size=36&sort=views,desc&sort=id&page=", "I più popolari"), + ) + override suspend fun getMainPage(page: Int, request: MainPageRequest): HomePageResponse { - override suspend fun getMainPage(page: Int, request : MainPageRequest): HomePageResponse { - val response = parseJson>(app.get("$mainUrl/api/home/latest-episodes?page=0").text) + val response = parseJson>(app.get(request.data + page).text) - val results = response.map{ - val isDub = isDub(it.title) + val results = response.mapNotNull{ + val title = it.title?:it.title2?: return@mapNotNull null + val isDub = isDub(title) + val id = if (it.id == 0) it.id2 else it.id newAnimeSearchResponse( - name = if (isDub) it.title.replace(dubIdentifier, "") else it.title, - url = "$mainUrl/api/anime/${it.id}", - type = getType(it.type), + name = if (isDub) title.replace(dubIdentifier, "") else title, + url = "$mainUrl/api/anime/$id", + type = getType(it.type?:it.type2), ){ addDubStatus(isDub, it.episode?.toIntOrNull()) - this.posterUrl = it.posters.first().posterUrl + this.posterUrl = (it.posters?:it.posters2!!).first().posterUrl this.quality = if (it.fullHD) SearchQuality.HD else null } } - return HomePageResponse(listOf(HomePageList("Ultime uscite",results))) + return newHomePageResponse(request.name, results) } override suspend fun quickSearch(query: String): List? { @@ -185,7 +196,7 @@ class AniPlayProvider : MainAPI() { this.plot = response.plot this.tags = tags this.showStatus = getStatus(response.status) - addPoster(response.posters.first().posterUrl) + addPoster(response.horizontalPosters.firstOrNull()?.posterUrl) addEpisodes(if (isDub) DubStatus.Dubbed else DubStatus.Subbed, episodes) addMalId(malId) addAniListId(aniListId) @@ -202,22 +213,6 @@ class AniPlayProvider : MainAPI() { val episode = parseJson(app.get(data).text) - if(episode.url.contains(".m3u8")){ - val m3u8Helper = M3u8Helper() - val streams = m3u8Helper.m3u8Generation(M3u8Helper.M3u8Stream(episode.url,Qualities.Unknown.value), false) - - streams.forEach { - callback.invoke( - ExtractorLink( - name, - name, - it.streamUrl, - referer = mainUrl, - quality = it.quality ?: Qualities.Unknown.value, - isM3u8 = it.streamUrl.contains(".m3u8"))) } - return true - } - callback.invoke( ExtractorLink( name, @@ -225,7 +220,7 @@ class AniPlayProvider : MainAPI() { episode.url, referer = mainUrl, quality = Qualities.Unknown.value, - isM3u8 = false, + isM3u8 = episode.url.contains(".m3u8"), ) ) return true diff --git a/AnimeWorldProvider/build.gradle.kts b/AnimeWorldProvider/build.gradle.kts index 231e63b..58eac0a 100644 --- a/AnimeWorldProvider/build.gradle.kts +++ b/AnimeWorldProvider/build.gradle.kts @@ -1,5 +1,5 @@ // use an integer for version numbers -version = 2 +version = 3 cloudstream { diff --git a/AnimeWorldProvider/src/main/kotlin/com/lagradost/AnimeWorldProvider.kt b/AnimeWorldProvider/src/main/kotlin/com/lagradost/AnimeWorldProvider.kt index 8602123..2e1f040 100644 --- a/AnimeWorldProvider/src/main/kotlin/com/lagradost/AnimeWorldProvider.kt +++ b/AnimeWorldProvider/src/main/kotlin/com/lagradost/AnimeWorldProvider.kt @@ -167,7 +167,8 @@ class AnimeWorldProvider : MainAPI() { @JsonProperty("link") val link: String, @JsonProperty("animeTypeName") val type: String, @JsonProperty("language") val language: String, - @JsonProperty("jtitle") val otherTitle: String + @JsonProperty("jtitle") val otherTitle: String, + @JsonProperty("identifier") val id: String ) override suspend fun quickSearch(query: String): List? { @@ -183,7 +184,7 @@ class AnimeWorldProvider : MainAPI() { "it" -> true else -> false } - newAnimeSearchResponse(anime.name, anime.link, type) { + newAnimeSearchResponse(anime.name, "$mainUrl/play/${anime.link}.${anime.id}", type) { addDubStatus(dub) this.otherName = anime.otherTitle this.posterUrl = anime.image diff --git a/CineBlog01Provider/build.gradle.kts b/CineBlog01Provider/build.gradle.kts index 9e63de9..3d9175c 100644 --- a/CineBlog01Provider/build.gradle.kts +++ b/CineBlog01Provider/build.gradle.kts @@ -1,5 +1,5 @@ // use an integer for version numbers -version = 1 +version = 2 cloudstream { diff --git a/CineBlog01Provider/src/main/kotlin/com/lagradost/CineBlogProvider.kt b/CineBlog01Provider/src/main/kotlin/com/lagradost/CineBlogProvider.kt index 9923a53..d2ba2d7 100644 --- a/CineBlog01Provider/src/main/kotlin/com/lagradost/CineBlogProvider.kt +++ b/CineBlog01Provider/src/main/kotlin/com/lagradost/CineBlogProvider.kt @@ -1,12 +1,16 @@ package com.lagradost import com.lagradost.cloudstream3.* +import com.lagradost.cloudstream3.LoadResponse.Companion.addDuration +import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer import com.lagradost.cloudstream3.utils.ExtractorLink import com.lagradost.cloudstream3.utils.loadExtractor +import okhttp3.FormBody +import org.jsoup.nodes.Element class CineBlog01Provider : MainAPI() { override var lang = "it" - override var mainUrl = "https://www.cineblog01.legal" + override var mainUrl = "https://www.cineblog01.moe" override var name = "CineBlog01" override val hasMainPage = true override val hasChromecastSupport = true @@ -25,74 +29,87 @@ class CineBlog01Provider : MainAPI() { ): HomePageResponse { val url = request.data + page val soup = app.get(url).document - - val home = soup.select("div.filmbox").map { series -> - val title = series.selectFirst("img")!!.attr("alt") - val link = series.selectFirst("a")!!.attr("href") - val posterUrl = fixUrl(series.selectFirst("img")!!.attr("src")) - val quality = Regex("\\[([^\\]]*)]").find(series.selectFirst("h1")!!.text())?.groupValues?.get(1) - val year = Regex("\\(([^)]*)\\)").find(series.selectFirst("h1")!!.text())?.groupValues?.get(1)?.toIntOrNull() - - newMovieSearchResponse( - title, - link, - TvType.TvSeries - ) { - this.posterUrl = posterUrl - this.quality = getQualityFromString(quality) - this.year = year - } + val home = soup.select("div.filmbox").mapNotNull { series -> + series.toSearchResult() + } + return newHomePageResponse(arrayListOf(HomePageList(request.name, home)), hasNext = true) + } + + private fun Element.toSearchResult(): SearchResponse? { + val title = + this.selectFirst("img")?.attr("alt") ?: throw ErrorLoadingException("No Title found") + val link = + this.selectFirst("a")?.attr("href") ?: throw ErrorLoadingException("No Link found") + val posterUrl = fixUrl( + this.selectFirst("img")?.attr("src") ?: throw ErrorLoadingException("No Poster found") + ) + val quality = Regex("\\[([^\\]]*)]").find( + this.selectFirst("h1")?.text() ?: "" + )?.groupValues?.getOrNull(1) ?: "" + val year = Regex("\\(([^)]*)\\)").find( + this.selectFirst("h1")?.text() ?: "" + )?.groupValues?.getOrNull(1)?.toIntOrNull() + return newMovieSearchResponse( + title, + link, + TvType.TvSeries + ) { + this.year = year + addPoster(posterUrl) + addQuality(quality) } - return newHomePageResponse(request.name, home) } override suspend fun search(query: String): List { + val body = FormBody.Builder() + .addEncoded("do", "search") + .addEncoded("subaction", "search") + .addEncoded("story", query) + .addEncoded("sortby", "news_read") + .build() val doc = app.post( - "$mainUrl/index.php?do=search", data = mapOf( - "do" to "search", - "subaction" to "search", - "story" to query - ) + "$mainUrl/index.php", + requestBody = body ).document - return doc.select("div.filmbox").map { series -> - val title = series.selectFirst("img")!!.attr("alt") - val link = series.selectFirst("a")!!.attr("href") - val posterUrl = fixUrl(series.selectFirst("img")!!.attr("src")) - var quality = Regex("\\[([^\\]]*)]").find(series.selectFirst("h1")!!.text())?.groupValues?.get(1) - var year = Regex("\\(([^)]*)\\)").find(series.selectFirst("h1")!!.text())?.groupValues?.get(1)?.toIntOrNull() - - newMovieSearchResponse( - title, - link, - TvType.TvSeries - ) { - this.posterUrl = posterUrl - this.quality = getQualityFromString(quality) - this.year = year - } + return doc.select("div.filmbox").mapNotNull { series -> + series.toSearchResult() } } override suspend fun load(url: String): LoadResponse { val document = app.get(url).document val title = document.selectFirst("div.imgrow > img")!!.attr("alt") - val description = document.selectFirst("div.fstory")?.text()?.removeSuffix(" +Info »")?.substringAfter("′ - ") - var year = document.selectFirst("div.filmboxfull")?.getElementsByAttributeValueContaining("href" , "/anno/")?.text()?.toIntOrNull() + val description = document.selectFirst("div.fstory")?.text()?.removeSuffix(" +Info »") + ?.substringAfter("′ - ") + val year = document.selectFirst("div.filmboxfull") + ?.getElementsByAttributeValueContaining("href", "/anno/")?.text()?.toIntOrNull() val poster = fixUrl(document.selectFirst("div.imgrow > img")!!.attr("src")) val dataUrl = document.select("ul.mirrors-list__list > li").map { it.select("a").attr("href") - }.drop(1).joinToString (",") + }.drop(1).joinToString(",") + val trailerUrl = + document.select("iframe").firstOrNull { it.attr("src").contains("youtube") } + ?.attr("src") + ?.let { fixUrl(it) } + val tags = + document.selectFirst("#dle-content h4")?.text()?.substringBefore("- DURATA")?.trim() + ?.split(" / ") + val duration = Regex("DURATA (.*)′").find( + document.selectFirst("#dle-content h4")?.text() ?: "" + )?.groupValues?.last() return newMovieLoadResponse( title, url, TvType.Movie, dataUrl = dataUrl ) { - this.plot = description this.year = year this.posterUrl = poster + this.tags = tags + addTrailer(trailerUrl) + addDuration(duration) } } diff --git a/CineBlogProvider/src/main/kotlin/com/lagradost/CineBlogProvider.kt b/CineBlogProvider/src/main/kotlin/com/lagradost/CineBlogProvider.kt index b98033a..499b3db 100644 --- a/CineBlogProvider/src/main/kotlin/com/lagradost/CineBlogProvider.kt +++ b/CineBlogProvider/src/main/kotlin/com/lagradost/CineBlogProvider.kt @@ -3,11 +3,13 @@ package com.lagradost import com.lagradost.cloudstream3.* import com.lagradost.cloudstream3.utils.ExtractorLink import com.lagradost.cloudstream3.utils.loadExtractor +import okhttp3.FormBody +import org.jsoup.nodes.Element class CineBlogProvider : MainAPI() { override var lang = "it" - override var mainUrl = "https://cb01.rip" + override var mainUrl = "https://cb01.li" override var name = "CB01" override val hasMainPage = true override val hasChromecastSupport = true @@ -29,116 +31,94 @@ class CineBlogProvider : MainAPI() { ): HomePageResponse { val url = request.data.replace("number", page.toString()) val soup = app.get(url, referer = url.substringBefore("page")).document - val home = soup.select("article.item").map { - val title = it.selectFirst("div.data > h3 > a")!!.text().substringBefore("(") - val link = it.selectFirst("div.poster > a")!!.attr("href") - val quality = getQualityFromString(it.selectFirst("span.quality")?.text()) - TvSeriesSearchResponse( - title, - link, - this.name, - TvType.Movie, - it.selectFirst("img")!!.attr("src"), - null, - null, - quality = quality - ) + val home = soup.select("article.item").mapNotNull { + it.toSearchResult() } - return newHomePageResponse(request.name, home) + return newHomePageResponse(arrayListOf(HomePageList(request.name, home)), hasNext = true) + } + + private fun Element.toSearchResult(): SearchResponse{ + val title = this.selectFirst("div.data > h3 > a")?.text()?.substringBefore("(") ?: + this.selectFirst("a > img")?.attr("alt")?.substringBeforeLast("(") ?: + throw ErrorLoadingException("No Title found") + + val link = this.selectFirst("div.poster > a")?.attr("href") ?: + this.selectFirst("a")?.attr("href") ?: + throw ErrorLoadingException("No Link found") + + val quality = this.selectFirst("span.quality")?.text() + + val posterUrl = this.selectFirst("img")?.attr("src") ?: + this.selectFirst("a > img")?.attr("src") + + return newMovieSearchResponse(title, link, TvType.Movie){ + addPoster(posterUrl) + if (quality != null) { + addQuality(quality) + } + } + } + + private fun Element.toEpisode(season: Int): Episode { + val href = this.selectFirst("div.episodiotitle > a")?.attr("href")?: throw ErrorLoadingException("No Link found") + val epNum = this.selectFirst("div.numerando")?.text()?.substringAfter("-")?.filter { it.isDigit() }?.toIntOrNull() + val epTitle = this.selectFirst("div.episodiotitle > a")?.text()?: throw ErrorLoadingException("No Title found") + val posterUrl = this.selectFirst("div.imagen > img")?.attr("src") + return Episode( + href, + epTitle, + season, + epNum, + posterUrl, + ) } override suspend fun search(query: String): List { - val queryformatted = query.replace(" ", "+") - val url = "$mainUrl?s=$queryformatted" + val queryFormatted = query.replace(" ", "+") + val url = "$mainUrl?s=$queryFormatted" val doc = app.get(url,referer= mainUrl ).document return doc.select("div.result-item").map { - val href = it.selectFirst("div.image > div > a")!!.attr("href") - val poster = it.selectFirst("div.image > div > a > img")!!.attr("src") - val name = it.selectFirst("div.details > div.title > a")!!.text().substringBefore("(") - MovieSearchResponse( - name, - href, - this.name, - TvType.Movie, - poster - ) - + it.toSearchResult() } } override suspend fun load(url: String): LoadResponse { - val page = app.get(url) - val document = page.document + val document = app.get(url).document val type = if (url.contains("film")) TvType.Movie else TvType.TvSeries - val title = document.selectFirst("div.data > h1")!!.text().substringBefore("(") + val title = document.selectFirst("div.data > h1")?.text()?.substringBefore("(")?: throw ErrorLoadingException("No Title found") val description = document.select("#info > div.wp-content > p").html().toString() - val rating = null - var year = document.selectFirst(" div.data > div.extra > span.date")!!.text().substringAfter(",") - .filter { it.isDigit() } - if (year.length > 4) { - year = year.dropLast(4) + val year = document.selectFirst(" div.data > div.extra > span.date")?.text()?.substringAfter(",")?.filter { it.isDigit() }.let { it?.dropLast(4) } + val poster = + document.selectFirst("#dt_galery")?.selectFirst("a")?.attr("href")?.trim()?: + document.selectFirst("div.poster > img")?.attr("src") + val recommendations = document.select("#single_relacionados >article").map { + it.toSearchResult() } - val poster = document.selectFirst("div.poster > img")!!.attr("src") - - val recomm = document.select("#single_relacionados >article").map { - val href = it.selectFirst("a")!!.attr("href") - val posterUrl = it.selectFirst("a > img")!!.attr("src") - val name = it.selectFirst("a > img")!!.attr("alt").substringBeforeLast("(") - MovieSearchResponse( - name, - href, - this.name, - TvType.Movie, - posterUrl - ) - - } - - if (type == TvType.TvSeries) { - - val episodeList = ArrayList() - document.select("#seasons > div").reversed().map { element -> - val season = element.selectFirst("div.se-q > span.se-t")!!.text().toInt() + val episodeList = document.select("#seasons > div").reversed().map { element -> + val season = element.selectFirst("div.se-q > span.se-t")?.text()?.toIntOrNull()?:throw ErrorLoadingException("No Season found") element.select("div.se-a > ul > li").filter { it -> it.text()!="There are still no episodes this season" }.map{ episode -> - val href = episode.selectFirst("div.episodiotitle > a")!!.attr("href") - val epNum =episode.selectFirst("div.numerando")!!.text().substringAfter("-").filter { it.isDigit() }.toIntOrNull() - val epTitle = episode.selectFirst("div.episodiotitle > a")!!.text() - val posterUrl = episode.selectFirst("div.imagen > img")!!.attr("src") - episodeList.add( - Episode( - href, - epTitle, - season, - epNum, - posterUrl, - ) - ) + episode.toEpisode(season) } - } - return TvSeriesLoadResponse( + }.flatten() + + return newTvSeriesLoadResponse( title, url, - this.name, type, - episodeList, - fixUrlNull(poster), - year.toIntOrNull(), - description, - null, - rating, - null, - null, - mutableListOf(), - recomm - ) + episodeList){ + this.recommendations = recommendations + this.year = year?.toIntOrNull() + this.plot = description + addPoster(poster) + } } else { val actors: List = - document.select("div.person").filter{ it -> it.selectFirst("div.img > a > img")?.attr("src")!!.contains("/no/cast.png").not()}.map { actordata -> - val actorName = actordata.selectFirst("div.data > div.name > a")!!.text() + document.select("div.person").filter{ it -> it.selectFirst("div.img > a > img")?.attr("src")?.contains("/no/cast.png")?.not()?:false}.map { actordata -> + val actorName = actordata.selectFirst("div.data > div.name > a")?.text()?:throw ErrorLoadingException("No Actor name found") val actorImage : String? = actordata.selectFirst("div.img > a > img")?.attr("src") - val roleActor = actordata.selectFirst("div.data > div.caracter")!!.text() + val roleActor = actordata.selectFirst("div.data > div.caracter")?.text() ActorData(actor = Actor(actorName, image = actorImage), roleString = roleActor ) } return newMovieLoadResponse( @@ -147,13 +127,11 @@ class CineBlogProvider : MainAPI() { type, url ) { - posterUrl = fixUrlNull(poster) - this.year = year.toIntOrNull() + this.recommendations = recommendations + this.year = year?.toIntOrNull() this.plot = description - this.rating = rating - this.recommendations = recomm - this.duration = null this.actors = actors + addPoster(poster) } } } @@ -167,11 +145,14 @@ class CineBlogProvider : MainAPI() { val doc = app.get(data).document val type = if( data.contains("film") ){"movie"} else {"tv"} val idpost=doc.select("#player-option-1").attr("data-post") - val test = app.post("$mainUrl/wp-admin/admin-ajax.php", headers = mapOf( + + val test = app.post("$mainUrl/wp-admin/admin-ajax.php", + headers = mapOf( "content-type" to "application/x-www-form-urlencoded; charset=UTF-8", "accept" to "*/*", "X-Requested-With" to "XMLHttpRequest", - ), data = mapOf( + ), + data = mapOf( "action" to "doo_player_ajax", "post" to idpost, "nume" to "1", diff --git a/EurostreamingProvider/build.gradle.kts b/EurostreamingProvider/build.gradle.kts index 46e2d8e..e977bcf 100644 --- a/EurostreamingProvider/build.gradle.kts +++ b/EurostreamingProvider/build.gradle.kts @@ -22,4 +22,4 @@ cloudstream { iconUrl = "https://www.google.com/s2/favicons?domain=eurostreaming.social&sz=%size%" -} \ No newline at end of file +} diff --git a/FilmpertuttiProvider/build.gradle.kts b/FilmpertuttiProvider/build.gradle.kts index d6467d7..b401629 100644 --- a/FilmpertuttiProvider/build.gradle.kts +++ b/FilmpertuttiProvider/build.gradle.kts @@ -1,5 +1,5 @@ // use an integer for version numbers -version = 3 +version = 4 cloudstream { diff --git a/FilmpertuttiProvider/src/main/kotlin/com/lagradost/FilmpertuttiProvider.kt b/FilmpertuttiProvider/src/main/kotlin/com/lagradost/FilmpertuttiProvider.kt index 31e1a3d..3cb9fc6 100644 --- a/FilmpertuttiProvider/src/main/kotlin/com/lagradost/FilmpertuttiProvider.kt +++ b/FilmpertuttiProvider/src/main/kotlin/com/lagradost/FilmpertuttiProvider.kt @@ -16,7 +16,7 @@ import com.lagradost.cloudstream3.network.CloudflareKiller class FilmpertuttiProvider : MainAPI() { override var lang = "it" - override var mainUrl = "https://filmpertutti.sbs" + override var mainUrl = "https://filmpertutti.skin" override var name = "FilmPerTutti" override val hasMainPage = true override val hasChromecastSupport = true @@ -25,19 +25,19 @@ class FilmpertuttiProvider : MainAPI() { TvType.TvSeries ) override var sequentialMainPage = true + override var sequentialMainPageDelay: Long = 50 override val mainPage = mainPageOf( Pair("$mainUrl/category/film/page/", "Film Popolari"), Pair("$mainUrl/category/serie-tv/page/", "Serie Tv Popolari"), Pair("$mainUrl/prime-visioni/", "Ultime uscite") ) - private val interceptor = CloudflareKiller() override suspend fun getMainPage( page: Int, request: MainPageRequest ): HomePageResponse { val url = request.data + page - val soup = app.get(url, interceptor = interceptor, referer = mainUrl).document + val soup = app.get(url).document val home = soup.select("ul.posts > li").map { val title = it.selectFirst("div.title")!!.text().substringBeforeLast("(") .substringBeforeLast("[") @@ -64,7 +64,7 @@ class FilmpertuttiProvider : MainAPI() { override suspend fun search(query: String): List { val queryformatted = query.replace(" ", "+") val url = "$mainUrl/?s=$queryformatted" - val doc = app.get(url, interceptor = interceptor).document + val doc = app.get(url).document return doc.select("ul.posts > li").map { val title = it.selectFirst("div.title")!!.text().substringBeforeLast("(") .substringBeforeLast("[") @@ -83,7 +83,7 @@ class FilmpertuttiProvider : MainAPI() { } override suspend fun load(url: String): LoadResponse { - val document = app.get(url, interceptor = interceptor).document + val document = app.get(url).document val type = if (document.selectFirst("a.taxonomy.category")!!.attr("href").contains("serie-tv") .not() @@ -91,10 +91,8 @@ class FilmpertuttiProvider : MainAPI() { val title = document.selectFirst("#content > h1")!!.text().substringBeforeLast("(") .substringBeforeLast("[") - val description = - document.selectFirst("i.fa.fa-file-text-o.fa-fw")?.parent()?.nextSibling()?.toString() - ?.html().toString() - + val descriptionindex = document.select("div.meta > div > div").indexOfFirst { it.getElementsContainingText("Trama").isNotEmpty() } + val description = document.select("div.meta > div > div")[descriptionindex +1].text() val rating = document.selectFirst("div.rating > div.value")?.text() @@ -106,8 +104,10 @@ class FilmpertuttiProvider : MainAPI() { ?.nextSibling() as Element?)?.text()?.substringAfterLast(" ") ?.filter { it.isDigit() }?.toIntOrNull() - - val poster = document.selectFirst("div.meta > div > img")?.attr("data-src") + val horizontalPosterData = document.selectFirst("body > main")?.attr("style")?:"" + val poster = + Regex("url\\('(.*)'").find(horizontalPosterData)?.groups?.lastOrNull()?.value?: + document.selectFirst("div.meta > div > img")?.attr("src") val trailerurl = @@ -191,4 +191,4 @@ class FilmpertuttiProvider : MainAPI() { } return true } -} \ No newline at end of file +} diff --git a/GuardaSerieProvider/build.gradle.kts b/GuardaSerieProvider/build.gradle.kts index 71e7f14..08e65ec 100644 --- a/GuardaSerieProvider/build.gradle.kts +++ b/GuardaSerieProvider/build.gradle.kts @@ -1,5 +1,5 @@ // use an integer for version numbers -version = 2 +version = 3 cloudstream { diff --git a/GuardaSerieProvider/src/main/kotlin/com/lagradost/GuardaSerieProvider.kt b/GuardaSerieProvider/src/main/kotlin/com/lagradost/GuardaSerieProvider.kt index 1851199..e153cd6 100644 --- a/GuardaSerieProvider/src/main/kotlin/com/lagradost/GuardaSerieProvider.kt +++ b/GuardaSerieProvider/src/main/kotlin/com/lagradost/GuardaSerieProvider.kt @@ -8,7 +8,7 @@ import com.lagradost.cloudstream3.utils.loadExtractor class GuardaSerieProvider : MainAPI() { override var lang = "it" - override var mainUrl = "https://guardaserie.skin" + override var mainUrl = "https://guardaserie.app" override var name = "GuardaSerie" override val hasMainPage = true override val hasChromecastSupport = true @@ -32,7 +32,7 @@ class GuardaSerieProvider : MainAPI() { val home = soup.select("div.mlnew").drop(1).map { series -> val title = series.selectFirst("div.mlnh-2")!!.text() val link = series.selectFirst("div.mlnh-2 > h2 > a")!!.attr("href") - val posterUrl = fixUrl(series.selectFirst("img")!!.attr("src")) + val posterUrl = fixUrl(series.selectFirst("img")!!.attr("src")).replace("/60x85-0-85/", "/141x200-0-85/") newTvSeriesSearchResponse( title, @@ -40,6 +40,7 @@ class GuardaSerieProvider : MainAPI() { TvType.TvSeries ) { this.posterUrl = posterUrl + this.posterHeaders = mapOf("user-agent" to "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36") } } @@ -57,13 +58,14 @@ class GuardaSerieProvider : MainAPI() { return doc.select("div.mlnew").drop(1).map { series -> val title = series.selectFirst("div.mlnh-2")!!.text() val link = series.selectFirst("div.mlnh-2 > h2 > a")!!.attr("href") - val posterUrl = fixUrl(series.selectFirst("img")!!.attr("src")) + val posterUrl = fixUrl(series.selectFirst("img")!!.attr("src")).replace("/60x85-0-85/", "/141x200-0-85/") newMovieSearchResponse( title, link, TvType.Movie ) { this.posterUrl = posterUrl + this.posterHeaders = mapOf("user-agent" to "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36") } } @@ -72,10 +74,12 @@ class GuardaSerieProvider : MainAPI() { override suspend fun load(url: String): LoadResponse { val document = app.get(url).document val title = document.selectFirst("h1")!!.text().removeSuffix(" streaming") - val description = document.selectFirst("div.tv_info_right")?.textNodes()?.joinToString("") + val description = document.selectFirst("div.tv_info_right")?.textNodes()?.joinToString("")?.removeSuffix("!")?.trim() val rating = document.selectFirst("span.post-ratings")?.text() var year = document.select("div.tv_info_list > ul").find { it.text().contains("Anno") }?.text()?.substringBefore("-")?.filter { it.isDigit() }?.toIntOrNull() - val poster = fixUrl(document.selectFirst("#cover")!!.attr("src")).replace("/141x200-0-85/", "/60x85-0-85/") + val poster = Regex("poster: '(.*)'").find(document.html())?.groups?.lastOrNull()?.value?.let { + fixUrl( it ) + }?: fixUrl(document.selectFirst("#cover")!!.attr("src")) val episodeList = document.select("div.tab-content > div").mapIndexed { season, data -> data.select("li").mapIndexed { epNum, epData -> @@ -101,6 +105,7 @@ class GuardaSerieProvider : MainAPI() { this.plot = description this.year = year this.posterUrl = poster + this.posterHeaders = mapOf("user-agent" to "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36") } } @@ -116,4 +121,4 @@ class GuardaSerieProvider : MainAPI() { } return true } -} \ No newline at end of file +} diff --git a/IlGenioDelloStreamingProvider/build.gradle.kts b/IlGenioDelloStreamingProvider/build.gradle.kts index 5b315ec..45514eb 100644 --- a/IlGenioDelloStreamingProvider/build.gradle.kts +++ b/IlGenioDelloStreamingProvider/build.gradle.kts @@ -16,7 +16,7 @@ cloudstream { * 2: Slow * 3: Beta only * */ - status = 1 // will be 3 if unspecified + status = 0 // will be 3 if unspecified tvTypes = listOf( "TvSeries}", "TvSeries", diff --git a/SoraItalianStream/build.gradle.kts b/SoraItalianStream/build.gradle.kts new file mode 100644 index 0000000..8ed141f --- /dev/null +++ b/SoraItalianStream/build.gradle.kts @@ -0,0 +1,29 @@ +// use an integer for version numbers +version = 1 + + +cloudstream { + language = "it" + // All of these properties are optional, you can safely remove them + + description = "Provider che utilizza tmdb. Non tutti i links sono funzionanti" + authors = listOf("Adippe") + + /** + * Status int as the following: + * 0: Down + * 1: Ok + * 2: Slow + * 3: Beta only + * */ + status = 1 // will be 3 if unspecified + tvTypes = listOf( + "TvSeries", + "Movie", + "AnimeMovie", + "Anime", + "OVA" + ) + + iconUrl = "https://www.google.com/s2/favicons?domain=seriesflix.video&sz=%size%" +} \ No newline at end of file diff --git a/SoraItalianStream/src/main/AndroidManifest.xml b/SoraItalianStream/src/main/AndroidManifest.xml new file mode 100644 index 0000000..0474547 --- /dev/null +++ b/SoraItalianStream/src/main/AndroidManifest.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/SoraItalianStream/src/main/kotlin/SoraItalianExtractor.kt b/SoraItalianStream/src/main/kotlin/SoraItalianExtractor.kt new file mode 100644 index 0000000..9d898ae --- /dev/null +++ b/SoraItalianStream/src/main/kotlin/SoraItalianExtractor.kt @@ -0,0 +1,402 @@ +package com.lagradost + +import com.lagradost.cloudstream3.* +import com.lagradost.cloudstream3.utils.* +import com.lagradost.cloudstream3.utils.AppUtils.parseJson +import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson +import com.lagradost.nicehttp.Requests + +object SoraItalianExtractor : SoraItalianStream() { + + suspend fun invoGuardare( + id: String? = null, + subtitleCallback: (SubtitleFile) -> Unit, + callback: (ExtractorLink) -> Unit + ) { + val res = app.get( + "https://guardahd.stream/movie/$id", + referer = "/" + ).document + res.select("ul._player-mirrors > li").map { source -> + loadExtractor( + fixUrl(source.attr("data-link")), + "$/", + subtitleCallback, + callback + ) + println("LINK DI Guardare " + fixUrl(source.attr("data-link"))) + } + } + + suspend fun invoGuardaserie( + id: String? = null, + season: Int? = null, + episode: Int? = null, + subtitleCallback: (SubtitleFile) -> Unit, + callback: (ExtractorLink) -> Unit + ) { + val url = app.post( + guardaserieUrl, data = mapOf( + "do" to "search", + "subaction" to "search", + "story" to id!! + ) + ).document.selectFirst("h2>a")?.attr("href") ?: return + val document = app.get(url).document + document.select("div.tab-content > div").mapIndexed { seasonData, data -> + data.select("li").mapIndexed { epNum, epData -> + if (season == seasonData + 1 && episode == epNum + 1) { + epData.select("div.mirrors > a").map { + loadExtractor( + fixUrl(it.attr("data-link")), + "$/", + subtitleCallback, + callback + ) + println("LINK DI guardaserie " + it.attr("data-link")) + } + } + } + } + } + + suspend fun invoFilmpertutti( + id: String?, + title: String?, + type: String?, + season: Int?, + episode: Int?, + year: Int?, + subtitleCallback: (SubtitleFile) -> Unit, + callback: (ExtractorLink) -> Unit + ) { + val url = when (type) { + "movie" -> "$filmpertuttiUrl/search/$title%20$year/feed/rss2" + else -> "$filmpertuttiUrl/search/$title/feed/rss2" + } + val res = app.get(url).text + val links = Regex("(.*)").findAll(res).map { it.groupValues.last() }.toList() + .filter { it != filmpertuttiUrl } + links.apmap { + val doc = app.get(it).document + if (id == doc.selectFirst(" div.rating > p > a")?.attr("href") + ?.substringAfterLast("/") + ) { + if (type == "tv") { + + val seasonData = doc.select("div.accordion-item").filter { a -> + a.selectFirst("#season > ul > li.s_title > span")!!.text().isNotEmpty() + }.find { + season == it.selectFirst("#season > ul > li.s_title > span")!!.text() + .toInt() + } + + val episodeData = seasonData?.select("div.episode-wrap")?.find { + episode == it.selectFirst("li.season-no")!!.text().substringAfter("x") + .filter { it.isDigit() }.toIntOrNull() + } + + episodeData?.select("#links > div > div > table > tbody:nth-child(2) > tr") + ?.map { + loadExtractor( + it.selectFirst("a")!!.attr("href") ?: "", + filmpertuttiUrl, + subtitleCallback, + callback + ) + println("FIlmpetutti " + it.selectFirst("a")!!.attr("href") ?: "") + } + } else { + val urls0 = doc.select("div.embed-player") + if (urls0.isNotEmpty()) { + urls0.map { + loadExtractor( + it.attr("data-id"), + filmpertuttiUrl, + subtitleCallback, + callback + + ) + println("LINK DI FIlmpetutti " + it.attr("data-id")) + } + } else { + doc.select("#info > ul > li ").mapNotNull { + val link = it.selectFirst("a")?.attr("href") ?: "" + loadExtractor( + ShortLink.unshorten(link).trim().replace("/v/", "/e/") + .replace("/f/", "/e/"), + "$/", + subtitleCallback, + callback + ) + println("LINK DI FIlmpetutti " + it.selectFirst("a")?.attr("href")) + } + } + } + } + } + } + + suspend fun invoAltadefinizione( + id: String? = null, + subtitleCallback: (SubtitleFile) -> Unit, + callback: (ExtractorLink) -> Unit + ) { + val url = app.get( + "$altadefinizioneUrl/index.php?story=$id&do=search&subaction=search" + ).document.selectFirst("div.cover_kapsul > a")?.attr("href") ?: return + val document = app.get(url).document + document.select("ul.host>a").map { + loadExtractor( + fixUrl(it.attr("data-link")), + altadefinizioneUrl, + subtitleCallback, + callback + ) + println("LINK DI altadefinizione " + fixUrl(it.attr("data-link"))) + } + + } + + suspend fun invoCb01( + title: String?, + year: Int?, + subtitleCallback: (SubtitleFile) -> Unit, + callback: (ExtractorLink) -> Unit + ) { + val res = app.get("$cb01Url/search/$title $year/feed").text + val links = Regex("(.*)").findAll(res).map { it.groupValues.last() }.toList() + .filter { it != cb01Url && it != "$cb01Url/" } + if (links.size != 1) return + links.apmap { + val doc = app.get(it).document + doc.select("tr > td > a").mapNotNull { + val link = it.selectFirst("a")?.attr("href") ?: "" + val url = ShortLink.unshorten(link).trim().replace("/v/", "/e/") + .replace("/f/", "/e/") + val processedUrl = if (url.contains("mixdrop.club")){ + fixUrl(app.get(url).document.selectFirst("iframe")?.attr("src")?:"") + } + else{url} + loadExtractor( + processedUrl, + "$/", + subtitleCallback, + callback + ) + println("LINK DI CB01 " + url) + } + + } + } + suspend fun invoAnimeWorld( + malId: String?, + title: String?, + episode: Int?, + subtitleCallback: (SubtitleFile) -> Unit, + callback: (ExtractorLink) -> Unit + ) { + val pagedata = app.get("$animeworldUrl/search?keyword=$title").document + + pagedata.select(".film-list > .item").map { + fixUrl(it.select("a.name").firstOrNull()?.attr("href") ?: "", animeworldUrl) + }.apmap { + val document = app.get(it).document + val malID = document.select("#mal-button").attr("href") + .split('/').last().toString() + if (malId == malID) { + val servers = document.select(".widget.servers") + servers.select(".server[data-name=\"9\"] .episode > a").toList() + .filter { it.attr("data-episode-num").toIntOrNull()?.equals(episode) ?: false } + .map { id -> + val url = tryParseJson( + app.get("$animeworldUrl/api/episode/info?id=${id.attr("data-id")}").text + )?.grabber + var dub = false + for (meta in document.select(".meta dt, .meta dd")) { + val text = meta.text() + if (text.contains("Audio")) { + dub = meta.nextElementSibling()?.text() == "Italiano" + } + } + val nameData = if (dub) { + "AnimeWorld DUB" + } else { + "AnimeWorld SUB" + } + + callback.invoke( + ExtractorLink( + "AnimeWorld", + nameData, + url?:"", + referer = animeworldUrl, + quality = Qualities.Unknown.value + ) + ) + println("LINK DI Animeworld " + url) + } + } + } + } + + suspend fun invoAniPlay( + malId: String?, + title: String?, + episode: Int?, + year: Int?, + subtitleCallback: (SubtitleFile) -> Unit, + callback: (ExtractorLink) -> Unit + ) { + val response = + parseJson>(app.get("$aniplayUrl/api/anime/advanced-search?page=0&size=36&query=$title&startYear=$year").text) + val links = response.filter { it.websites.joinToString().contains("anime/$malId") } + .map { "https://aniplay.it/api/anime/${it.id}" } + + links.apmap { url -> + val response = parseJson(app.get(url).text) + val AnimeName = if (isDub(response.title)) { + "AniPlay DUB" + } else { + "AniPlay SUB" + } + if (response.seasons.isNullOrEmpty()) { + val episodeUrl = + "$aniplayUrl/api/episode/${response.episodes.find { it.number.toInt() == episode }?.id}" + val streamUrl = + parseJson(app.get(episodeUrl).text).url + callback.invoke( + + ExtractorLink( + name, + AnimeName, + streamUrl, + referer = mainUrl, + quality = Qualities.Unknown.value, + isM3u8 = streamUrl.contains(".m3u8"), + ) + ) + } + else { + val seasonid = response.seasons.sortedBy { it.episodeStart }.last { it.episodeStart < episode!!} + val episodesData = + tryParseJson>( + app.get( + "$url/season/${seasonid.id}" + ).text + ) + val episodeData = episodesData?.find { it.number == episode.toString() }?.id + if (episodeData != null) { + val streamUrl = + parseJson(app.get("$aniplayUrl/api/episode/${episodeData}").text).url + callback.invoke( + ExtractorLink( + name, + AnimeName, + streamUrl, + referer = mainUrl, + quality = Qualities.Unknown.value, + isM3u8 = streamUrl.contains(".m3u8"), + ) + ) + println("LINK DI aniplay " + streamUrl) + } + } + } + + } + + suspend fun invoAnimeSaturn( + malId: String?, + title: String?, + episode: Int?, + subtitleCallback: (SubtitleFile) -> Unit, + callback: (ExtractorLink) -> Unit + ) { + val document = app.get("$animesaturnUrl/animelist?search=${title?.replace("-"," ")}").document + val links = document.select("div.item-archivio").map { + it.select("a.badge-archivio").first()!!.attr("href") + } + links.apmap { url -> + val response = app.get(url).document + val AnimeName = if (isDub(response.select("img.cover-anime").first()!!.attr("alt"))) { + "AnimeSaturn DUB" + } else { + "AnimeSaturn SUB" + } + var malID : String? = null + + response.select("[rel=\"noopener noreferrer\"]").forEach { + if(it.attr("href").contains("myanimelist")) + malID = it.attr("href").removeSuffix("/").split('/').last() + if (malId == malID){ + val link = response.select("a.bottone-ep").find { it.text().split(" ")[1] == episode.toString() }?.attr("href") + if (link != null) { + val page = app.get(link).document + val episodeLink = page.select("div.card-body > a[href]").find { it1 -> + it1.attr("href").contains("watch?") + }?.attr("href") ?: throw ErrorLoadingException("No link Found") + + val episodePage = app.get(episodeLink).document + val episodeUrl: String? + var isM3U8 = false + + if (episodePage.select("video.afterglow > source").isNotEmpty()) // Old player + episodeUrl = + episodePage.select("video.afterglow > source").first()!!.attr("src") + else { // New player + val script = episodePage.select("script").find { + it.toString().contains("jwplayer('player_hls').setup({") + }!!.toString() + episodeUrl = script.split(" ") + .find { it.contains(".m3u8") and !it.contains(".replace") }!! + .replace("\"", "").replace(",", "") + isM3U8 = true + } + + callback.invoke( + ExtractorLink( + name, + AnimeName, + episodeUrl!!, + isM3u8 = isM3U8, + referer = "https://www.animesaturn.io/", //Some servers need the old host as referer, and the new ones accept it too + quality = Qualities.Unknown.value + ) + ) + println("LINK DI animesaturn " + episodeUrl) + } + + } + } + + } + } +} + + +private fun isDub(title: String?): Boolean { + return title?.contains(" (ITA)") ?: false +} + +fun fixUrl(url: String, domain: String): String { + if (url.startsWith("http")) { + return url + } + if (url.isEmpty()) { + return "" + } + + val startsWithNoHttp = url.startsWith("//") + if (startsWithNoHttp) { + return "https:$url" + } else { + if (url.startsWith('/')) { + return domain + url + } + return "$domain/$url" + } + + +} + diff --git a/SoraItalianStream/src/main/kotlin/SoraItalianStream.kt b/SoraItalianStream/src/main/kotlin/SoraItalianStream.kt new file mode 100644 index 0000000..0a258e7 --- /dev/null +++ b/SoraItalianStream/src/main/kotlin/SoraItalianStream.kt @@ -0,0 +1,511 @@ +package com.lagradost + +import com.fasterxml.jackson.annotation.JsonProperty +import com.lagradost.SoraItalianExtractor.invoGuardare +import com.lagradost.cloudstream3.* +import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer +import com.lagradost.cloudstream3.metaproviders.TmdbProvider +import com.lagradost.SoraItalianExtractor.invoAltadefinizione +import com.lagradost.SoraItalianExtractor.invoAniPlay +import com.lagradost.SoraItalianExtractor.invoAnimeSaturn +import com.lagradost.SoraItalianExtractor.invoAnimeWorld +import com.lagradost.SoraItalianExtractor.invoCb01 +import com.lagradost.SoraItalianExtractor.invoFilmpertutti +import com.lagradost.SoraItalianExtractor.invoGuardaserie +import com.lagradost.cloudstream3.utils.AppUtils.parseJson +import com.lagradost.cloudstream3.utils.AppUtils.toJson +import com.lagradost.cloudstream3.utils.ExtractorLink +import kotlin.math.roundToInt + +open class SoraItalianStream : TmdbProvider() { + override var name = "SoraStreamItaliano" + override val hasMainPage = true + override val hasDownloadSupport = true + override val instantLinkLoading = true + override val useMetaLoadResponse = true + override var lang = "it" + override val hasChromecastSupport = true + override val supportedTypes = setOf( + TvType.Movie, + TvType.TvSeries, + TvType.Anime, + ) + + /** AUTHOR : Adippe & Hexated & Sora */ + companion object { + private const val tmdbAPI = "https://api.themoviedb.org/3" + private const val apiKey = "71f37e6dff3b879fa4656f19547c418c" // PLEASE DON'T STEAL + const val guardaserieUrl = "https://guardaserie.app" + const val filmpertuttiUrl = "https://www.filmpertutti.skin" + const val altadefinizioneUrl = "https://altadefinizione01.autos" + const val cb01Url = "https://cb01.delivery" + const val animeworldUrl = "https://www.animeworld.tv" + const val aniplayUrl = "https://aniplay.it" + const val animesaturnUrl = "https://www.animesaturn.in" + const val tmdb2mal = "https://tmdb2mal.slidemovies.org" + fun getType(t: String?): TvType { + return when (t) { + "movie" -> TvType.Movie + else -> TvType.TvSeries + } + } + + fun getActorRole(t: String?): ActorRole { + return when (t) { + "Acting" -> ActorRole.Main + else -> ActorRole.Background + } + } + + + fun getStatus(t: String?): ShowStatus { + return when (t) { + "Returning Series" -> ShowStatus.Ongoing + else -> ShowStatus.Completed + } + } + + fun base64DecodeAPI(api: String): String { + return api.chunked(4).map { base64Decode(it) }.reversed().joinToString("") + } + + } + + + override val mainPage = mainPageOf( + "$tmdbAPI/movie/popular?api_key=$apiKey®ion=&language=it-IT&page=" to "Film Popolari", + "$tmdbAPI/tv/popular?api_key=$apiKey®ion=&language=it-IT&page=" to "Serie TV Popolari", + "$tmdbAPI/discover/tv?api_key=$apiKey&with_keywords=210024|222243&page=" to "Anime", + "$tmdbAPI/movie/top_rated?api_key=$apiKey®ion=&language=it-IT&page=" to "Film più votati", + "$tmdbAPI/tv/top_rated?api_key=$apiKey®ion=&language=it-IT&page=" to "Serie TV più votate", + "$tmdbAPI/discover/tv?api_key=$apiKey&language=it-IT&with_networks=213&page=" to "Netflix", + "$tmdbAPI/discover/tv?api_key=$apiKey&language=it-IT&with_networks=1024&page=" to "Amazon", + "$tmdbAPI/discover/tv?api_key=$apiKey&language=it-IT&with_networks=2739&page=" to "Disney+", + "$tmdbAPI/discover/tv?api_key=$apiKey&language=it-IT&with_networks=453&page=" to "Hulu", + "$tmdbAPI/discover/tv?api_key=$apiKey&language=it-IT&with_networks=2552&page=" to "Apple TV+" + ) + + private fun getImageUrl(link: String?): String? { + if (link == null) return null + return if (link.startsWith("/")) "https://image.tmdb.org/t/p/w500/$link" else link + } + + private fun getOriImageUrl(link: String?): String? { + if (link == null) return null + return if (link.startsWith("/")) "https://image.tmdb.org/t/p/original/$link" else link + } + + override suspend fun getMainPage( + page: Int, + request: MainPageRequest + ): HomePageResponse { + val type = if (request.data.contains("/movie")) "movie" else "tv" + val home = app.get(request.data + page) + .parsedSafe()?.results + ?.mapNotNull { media -> + media.toSearchResponse(type) + } ?: throw ErrorLoadingException("Invalid Json reponse") + return newHomePageResponse(request.name, home) + } + + private fun Media.toSearchResponse(type: String? = null): SearchResponse? { + return newMovieSearchResponse( + title ?: name ?: originalTitle ?: return null, + Data(id = id, type = mediaType ?: type).toJson(), + TvType.Movie, + ) { + this.posterUrl = getImageUrl(posterPath) + } + } + + + override suspend fun search(query: String): List { + val searchResponse = mutableListOf() + + val mainResponse = app.get( + "$tmdbAPI/search/multi?api_key=$apiKey&language=it-IT&query=$query&page=1&include_adult=false" + ).parsedSafe()?.results?.mapNotNull { media -> + media.toSearchResponse() + } + if (mainResponse?.isNotEmpty() == true) searchResponse.addAll(mainResponse) + +// val animeResponse = +// app.get("$mainServerAPI/search/anime/$query?_data=routes/search/anime/\$animeKeyword") +// .parsedSafe()?.searchResults?.results?.mapNotNull { anime -> anime.toSearchResponse() } +// if (animeResponse?.isNotEmpty() == true) searchResponse.addAll(animeResponse) + + return searchResponse + } + + + override suspend fun load(url: String): LoadResponse? { + val data = parseJson(url) + + val type = getType(data.type) + + val typename = when(type){ + TvType.TvSeries-> "tv" + TvType.Movie -> "movie" + else -> "" + } + + val res = + app.get("$tmdbAPI/$typename/${data.id}?api_key=$apiKey&language=it-IT&append_to_response=external_ids,credits,recommendations,videos") + .parsedSafe() ?: throw ErrorLoadingException("Invalid Json Response") + + + val title = res.name ?: res.title ?: return null + val orgTitle = res.originalName ?: res.originalTitle ?: return null + + val year = (res.tvDate ?: res.movieDate)?.split("-")?.first()?.toIntOrNull() + + val actors = res.credits?.cast?.mapNotNull { cast -> + ActorData( + Actor( + cast.name ?: cast.originalName ?: return@mapNotNull null, + getImageUrl(cast.profilePath) + ), + getActorRole(cast.knownForDepartment) + ) + } ?: return null + val recommendations = + res.recommandations?.results?.mapNotNull { media -> media.toSearchResponse() } + + val trailer = + res.videos?.results?.map { "https://www.youtube.com/watch?v=${it.key}" } + ?.randomOrNull() + + if (res.genres?.map { it.id }?.contains(16) == true && type == TvType.TvSeries) { + + val episodes = mutableListOf() + res.seasons?.filter { it.seasonNumber != 0L }?.apmap { season -> + val seasonData = app.get("$tmdbAPI/${data.type}/${data.id}/season/${season.seasonNumber}?api_key=$apiKey&language=it-IT") + .parsedSafe()?.episodes + val seasonID = if (season.seasonNumber!! > 1 && seasonData?.isNotEmpty() == true && seasonData?.first()?.episodeNumber != 1){ 1 } else { season.seasonNumber }.toInt() + seasonData?.map { eps -> + episodes.add(Episode( + LinkData( + data.id, + res.externalIds?.imdbId, + data.type, + seasonID, + eps.episodeNumber, + title = title, + year = year, + orgTitle = orgTitle, + isAnime = true + ).toJson(), + name = eps.name, + season = eps.seasonNumber, + episode = eps.episodeNumber, + posterUrl = getImageUrl(eps.stillPath), + rating = eps.voteAverage?.times(10)?.roundToInt(), + description = eps.overview + ).apply { + this.addDate(eps.airDate) + }) + } + } + return newTvSeriesLoadResponse( + title, + url, + TvType.TvSeries, + episodes + ) { + this.posterUrl = getOriImageUrl(res.backdropPath) + this.year = year + this.plot = res.overview + this.tags = res.genres?.mapNotNull { it.name } + this.showStatus = getStatus(res.status) + this.recommendations = recommendations + this.actors = actors + addTrailer(trailer) + } + + } + return if (type == TvType.TvSeries) { + val episodes = mutableListOf() + res.seasons?.filter { it.seasonNumber != 0L }?.apmap { season -> + app.get("$tmdbAPI/${data.type}/${data.id}/season/${season.seasonNumber}?api_key=$apiKey&language=it-IT") + .parsedSafe()?.episodes?.map { eps -> + episodes.add(Episode( + LinkData( + data.id, + res.externalIds?.imdbId, + data.type, + eps.seasonNumber, + eps.episodeNumber, + title = title, + year = season.airDate?.split("-")?.first()?.toIntOrNull(), + orgTitle = orgTitle, + isAnime = false + ).toJson(), + name = eps.name, + season = eps.seasonNumber, + episode = eps.episodeNumber, + posterUrl = getImageUrl(eps.stillPath), + rating = eps.voteAverage?.times(10)?.roundToInt(), + description = eps.overview + ).apply { + this.addDate(eps.airDate) + }) + } + } + newTvSeriesLoadResponse( + title, + url, + TvType.TvSeries, + episodes + ) { + this.posterUrl = getOriImageUrl(res.backdropPath) + this.year = year + this.plot = res.overview + this.tags = res.genres?.mapNotNull { it.name } + this.showStatus = getStatus(res.status) + this.recommendations = recommendations + this.actors = actors + addTrailer(trailer) + } + } + else { + newMovieLoadResponse( + title, + url, + TvType.Movie, + LinkData( + data.id, + res.externalIds?.imdbId, + data.type, + title = title, + year = year, + orgTitle = orgTitle, + isAnime = res.genres?.map { it.id }?.contains(16)?:false + ).toJson(), + ) { + this.posterUrl = getOriImageUrl(res.backdropPath) + this.year = year + this.plot = res.overview + this.tags = res.genres?.mapNotNull { it.name } + this.recommendations = recommendations + this.actors = actors + addTrailer(trailer) + } + } + } + + override suspend fun loadLinks( + data: String, + isCasting: Boolean, + subtitleCallback: (SubtitleFile) -> Unit, + callback: (ExtractorLink) -> Unit + ): Boolean { + + val res = parseJson(data) + val malID = app.get("$tmdb2mal/?id=${res.id}&s=${res.season}").text.trim() + argamap( + { + if (res.isAnime ) invoAnimeWorld(malID, res.title, res.episode, subtitleCallback, callback) + }, + { + if (res.isAnime) invoAniPlay(malID, res.title, res.episode, res.year, subtitleCallback, callback) + }, + { + if (res.isAnime) invoAnimeSaturn(malID, res.title, res.episode, subtitleCallback, callback) + }, + { + invoGuardare(res.imdbId, subtitleCallback, callback) + }, + { + if (malID == "") invoGuardaserie(res.imdbId, res.season, res.episode, subtitleCallback, callback) + }, + { + if (!res.isAnime) invoFilmpertutti(res.imdbId,res.title, res.type, res.season, res.episode, res.year, subtitleCallback, callback) + }, + { + if (!res.isAnime) invoAltadefinizione(res.imdbId, subtitleCallback, callback) + }, + { + if (!res.isAnime) invoCb01(res.title, res.year, subtitleCallback, callback) + } + ) + + return true + } + + private data class LinkData( + val id: Int? = null, + val imdbId: String? = null, + val type: String? = null, + val season: Int? = null, + val episode: Int? = null, + val aniId: String? = null, + val animeId: String? = null, + val title: String? = null, + val year: Int? = null, + val orgTitle: String? = null, + val isAnime : Boolean + ) + + data class Data( + val id: Int? = null, + val type: String? = null, + val aniId: String? = null, + val malId: Int? = null, + ) + + data class Subtitles( + @JsonProperty("url") val url: String? = null, + @JsonProperty("lang") val lang: String? = null, + @JsonProperty("language") val language: String? = null, + ) + + data class Sources( + @JsonProperty("url") val url: String? = null, + @JsonProperty("quality") val quality: String? = null, + @JsonProperty("isM3U8") val isM3U8: Boolean = true, + ) + + data class LoadLinks( + @JsonProperty("sources") val sources: ArrayList? = arrayListOf(), + @JsonProperty("subtitles") val subtitles: ArrayList? = arrayListOf(), + ) + + data class Results( + @JsonProperty("results") val results: ArrayList? = arrayListOf(), + ) + + data class Media( + @JsonProperty("id") val id: Int? = null, + @JsonProperty("name") val name: String? = null, + @JsonProperty("title") val title: String? = null, + @JsonProperty("original_title") val originalTitle: String? = null, + @JsonProperty("media_type") val mediaType: String? = null, + @JsonProperty("poster_path") val posterPath: String? = null, + ) + + data class Seasons( + @JsonProperty("id") val id: Int? = null, + @JsonProperty("name") val name: String? = null, + @JsonProperty("season_number") val seasonNumber: Int? = null, + @JsonProperty("air_date") val airDate: String? = null, + ) + + data class Cast( + @JsonProperty("id") val id: Int? = null, + @JsonProperty("name") val name: String? = null, + @JsonProperty("original_name") val originalName: String? = null, + @JsonProperty("character") val character: String? = null, + @JsonProperty("known_for_department") val knownForDepartment: String? = null, + @JsonProperty("profile_path") val profilePath: String? = null, + ) + + data class Episodes( + @JsonProperty("id") val id: Int? = null, + @JsonProperty("name") val name: String? = null, + @JsonProperty("overview") val overview: String? = null, + @JsonProperty("air_date") val airDate: String? = null, + @JsonProperty("still_path") val stillPath: String? = null, + @JsonProperty("vote_average") val voteAverage: Double? = null, + @JsonProperty("episode_number") val episodeNumber: Int? = null, + @JsonProperty("season_number") val seasonNumber: Int? = null, + ) + + data class MediaDetailEpisodes( + @JsonProperty("episodes") val episodes: ArrayList? = arrayListOf(), + ) + + + data class MovieDetails ( + val adult: Boolean? = null, + @JsonProperty("first_air_date") val tvDate: String? = null, + @JsonProperty("release_date") val movieDate: String? = null, + @JsonProperty("backdrop_path") val backdropPath: String? = null, + val genres: List? = null, + val id: Long? = null, + val name: String? = null, + val title: String? = null, + @JsonProperty("number_of_seasons") val numberOfSeasons: Long? = null, + @JsonProperty("original_name") val originalName: String? = null, + @JsonProperty("original_title") val originalTitle: String? = null, + val overview: String? = null, + val popularity: Double? = null, + @JsonProperty("poster_path") val posterPath: String? = null, + val seasons: List? = null, + val status: String? = null, + val tagline: String? = null, + val type: String? = null, + @JsonProperty("vote_average") val voteAverage: Double? = null, + @JsonProperty("vote_count") val voteCount: Long? = null, + @JsonProperty("credits") val credits: Credits? = null, + @JsonProperty("recommendations") val recommandations: Recommendations? = null, + @JsonProperty("videos") val videos: Videos? = null, + @JsonProperty("external_ids") val externalIds: ExternalIds? = null + ) + + data class Recommendations ( + @JsonProperty("results") val results: List? = null, + ) + + data class Credits ( + val cast: List? = null, + ) + + data class ExternalIds ( + @JsonProperty("imdb_id") val imdbId: String? = null + ) + + data class Videos ( + val results: List? = null, + ) + + data class Trailers( + @JsonProperty("key") val key: String? = null, + ) + + data class Genre ( + val id: Long? = null, + val name: String? = null + ) + + data class Season ( + @JsonProperty("air_date") val airDate: String? = null, + @JsonProperty("episode_count") val episodeCount: Long? = null, + val id: Long? = null, + val name: String? = null, + val overview: String? = null, + @JsonProperty("poster_path") val posterPath: String? = null, + @JsonProperty("season_number") val seasonNumber: Long? = null + ) + + data class AnimeWorldJson( + @JsonProperty("grabber") val grabber: String, + @JsonProperty("name") val name: String, + @JsonProperty("target") val target: String, + ) + data class AniPlayApiSearchResult( + @JsonProperty("id") val id: Int, + @JsonProperty("listWebsites") val websites: List + ) + data class AniPlayWebsites( + @JsonProperty("url") val url: String? = null, + @JsonProperty("listWebsiteId") val websitesId: Int? = null + ) + data class AniplayApiAnime( + @JsonProperty("episodes") val episodes: List, + @JsonProperty("seasons") val seasons: List?, + @JsonProperty("title") val title: String? + ) + data class AniplayApiEpisode( + @JsonProperty("id") val id: Int, + @JsonProperty("title") val title: String?, + @JsonProperty("episodeNumber") val number: String, + ) + data class AniplayApiSeason( + @JsonProperty("id") val id: Int, + @JsonProperty("name") val name: String, + @JsonProperty("episodeStart") val episodeStart: Int + ) + data class AniPlayApiEpisodeUrl( + @JsonProperty("videoUrl") val url: String + ) +} \ No newline at end of file diff --git a/SoraItalianStream/src/main/kotlin/SoraItalianStreamPlugin.kt b/SoraItalianStream/src/main/kotlin/SoraItalianStreamPlugin.kt new file mode 100644 index 0000000..5003f3b --- /dev/null +++ b/SoraItalianStream/src/main/kotlin/SoraItalianStreamPlugin.kt @@ -0,0 +1,13 @@ +package com.lagradost + +import com.lagradost.cloudstream3.plugins.CloudstreamPlugin +import com.lagradost.cloudstream3.plugins.Plugin +import android.content.Context + +@CloudstreamPlugin +class SoraStreamItalianPlugin: Plugin() { + override fun load(context: Context) { + // All providers should be added in this manner. Please don't edit the providers list directly. + registerMainAPI(SoraItalianStream()) + } +} \ No newline at end of file diff --git a/StreamingcommunityProvider/build.gradle.kts b/StreamingcommunityProvider/build.gradle.kts index 1a8e42d..61472f6 100644 --- a/StreamingcommunityProvider/build.gradle.kts +++ b/StreamingcommunityProvider/build.gradle.kts @@ -1,5 +1,5 @@ // use an integer for version numbers -version = 3 +version = 4 cloudstream { @@ -23,4 +23,4 @@ cloudstream { ) iconUrl = "https://www.google.com/s2/favicons?domain=streamingcommunity.best&sz=%size%" -} \ No newline at end of file +} diff --git a/StreamingcommunityProvider/src/main/kotlin/com/lagradost/StreamingcommunityProvider.kt b/StreamingcommunityProvider/src/main/kotlin/com/lagradost/StreamingcommunityProvider.kt index e8b71d1..0fda93b 100644 --- a/StreamingcommunityProvider/src/main/kotlin/com/lagradost/StreamingcommunityProvider.kt +++ b/StreamingcommunityProvider/src/main/kotlin/com/lagradost/StreamingcommunityProvider.kt @@ -128,7 +128,7 @@ data class TrailerElement( class StreamingcommunityProvider: MainAPI() { override var lang = "it" - override var mainUrl = "https://streamingcommunity.golf" + override var mainUrl = "https://streamingcommunity.cheap" override var name = "StreamingCommunity" override val hasMainPage = true override val hasChromecastSupport = true @@ -170,9 +170,9 @@ class StreamingcommunityProvider: MainAPI() { } } - companion object { - val posterMap = hashMapOf() - } +// companion object { +// val posterMap = hashMapOf() +// } override suspend fun getMainPage(page: Int, request : MainPageRequest): HomePageResponse { val items = ArrayList() @@ -191,7 +191,7 @@ class StreamingcommunityProvider: MainAPI() { val ip = translateip(searchr.images[0].proxyID.toInt()) val posterurl = "https://$ip/images/$number/$img" val videourl = "$mainUrl/titles/$id-$name" - posterMap[videourl] = posterurl + //posterMap[videourl] = posterurl val data = app.post("$mainUrl/api/titles/preview/$id", referer = mainUrl).text val datajs = parseJson(data) val type: TvType = if (datajs.type == "movie") { @@ -239,7 +239,7 @@ class StreamingcommunityProvider: MainAPI() { val datajs = parseJson(data) val posterurl = "https://$ip/images/$number/$img" val videourl = "$mainUrl/titles/$id-$name" - posterMap[videourl] = posterurl + //posterMap[videourl] = posterurl if (datajs.type == "movie") { val type = TvType.Movie MovieSearchResponse( @@ -271,7 +271,8 @@ class StreamingcommunityProvider: MainAPI() { override suspend fun load(url: String): LoadResponse { val document = app.get(url).document - val poster = posterMap[url] + val poster = Regex("url\\('(.*)'").find(document.selectFirst("div.title-wrap")?.attributes() + ?.get("style") ?: "")?.groupValues?.last() //posterMap[url] val id = url.substringBefore("-").filter { it.isDigit() } val data = app.post("$mainUrl/api/titles/preview/$id", referer = mainUrl).text @@ -307,7 +308,7 @@ class StreamingcommunityProvider: MainAPI() { val videourl = "$mainUrl/titles/$idcorr-$name" val posterurl = "https://$ip/images/$number/$img" - posterMap[videourl] = posterurl + //posterMap[videourl] = posterurl val typecorr: TvType = if (datajscorrel.type == "movie") { TvType.Movie } else { @@ -431,13 +432,17 @@ class StreamingcommunityProvider: MainAPI() { val token = token2.replace("=", "").replace("+", "-").replace("/", "_") val link = "https://scws.work/master/$scwsid?token=$token&expires=$expire&n=1" - Regex("URI=\".*\"").findAll(app.get("https://scws.work/master/$scwsid?token=$token&expires=$expire&n=1").text).toList().filter{it.value.contains("auto-forced").not()}.map{ - val link = app.get(it.value.substringAfter("\"").dropLast(1)).text.lines().filter{it.contains("http")}[0] - val lang = it.value.substringAfter("rendition=").substringBefore("&") - SubtitleFile(lang, link) - }.forEach(subtitleCallback) - - getM3u8Qualities(link, data, URI(link).host).forEach(callback) + + callback.invoke( + ExtractorLink( + name, + name, + link, + isM3u8 = true, + referer = mainUrl, + quality = Qualities.Unknown.value + ) + ) return true } -} +} \ No newline at end of file diff --git a/TantiFilmProvider/build.gradle.kts b/TantiFilmProvider/build.gradle.kts index ce09274..8e8c2f1 100644 --- a/TantiFilmProvider/build.gradle.kts +++ b/TantiFilmProvider/build.gradle.kts @@ -1,5 +1,5 @@ // use an integer for version numbers -version = 2 +version = 3 cloudstream { diff --git a/TantiFilmProvider/src/main/kotlin/com/lagradost/TantiFilmProvider.kt b/TantiFilmProvider/src/main/kotlin/com/lagradost/TantiFilmProvider.kt index 8252768..7b8fbf9 100644 --- a/TantiFilmProvider/src/main/kotlin/com/lagradost/TantiFilmProvider.kt +++ b/TantiFilmProvider/src/main/kotlin/com/lagradost/TantiFilmProvider.kt @@ -9,7 +9,7 @@ import com.lagradost.cloudstream3.network.CloudflareKiller class TantifilmProvider : MainAPI() { override var lang = "it" - override var mainUrl = "https://tantifilm.yachts" + override var mainUrl = "https://tantifilm.delivery" override var name = "Tantifilm" override val hasMainPage = true override val hasChromecastSupport = true @@ -52,7 +52,7 @@ class TantifilmProvider : MainAPI() { override suspend fun search(query: String): List { val queryformatted = query.replace(" ", "+") - val url = "$mainUrl/search/$queryformatted" + val url = "$mainUrl/?s=$queryformatted" val doc = app.get(url, interceptor = interceptor).document return doc.select("div.film.film-2").map { diff --git a/TvItalianaProvider/build.gradle.kts b/TvItalianaProvider/build.gradle.kts index 187c379..73f173c 100644 --- a/TvItalianaProvider/build.gradle.kts +++ b/TvItalianaProvider/build.gradle.kts @@ -1,5 +1,5 @@ // use an integer for version numbers -version = 1 +version = 2 cloudstream { diff --git a/TvItalianaProvider/src/main/kotlin/com/lagradost/TvItalianaProvider.kt b/TvItalianaProvider/src/main/kotlin/com/lagradost/TvItalianaProvider.kt index d0436c7..0e5305c 100644 --- a/TvItalianaProvider/src/main/kotlin/com/lagradost/TvItalianaProvider.kt +++ b/TvItalianaProvider/src/main/kotlin/com/lagradost/TvItalianaProvider.kt @@ -1,15 +1,19 @@ package com.lagradost +import com.fasterxml.jackson.annotation.JsonProperty import com.lagradost.cloudstream3.* import com.lagradost.cloudstream3.utils.AppUtils.parseJson import com.lagradost.cloudstream3.utils.AppUtils.toJson import com.lagradost.cloudstream3.utils.ExtractorLink import com.lagradost.cloudstream3.utils.Qualities +import com.lagradost.nicehttp.RequestBodyTypes +import okhttp3.MediaType.Companion.toMediaTypeOrNull +import okhttp3.RequestBody.Companion.toRequestBody import java.io.InputStream +import java.util.UUID class TvItalianaProvider : MainAPI() { override var lang = "it" - override var mainUrl = "https://raw.githubusercontent.com/Tundrak/IPTV-Italia/main/iptvitaplus.m3u" override var name = "TvItaliana" override val hasMainPage = true override val hasChromecastSupport = true @@ -21,29 +25,85 @@ class TvItalianaProvider : MainAPI() { page: Int, request : MainPageRequest ): HomePageResponse { - val data = IptvPlaylistParser().parseM3U(app.get(mainUrl).text) - return HomePageResponse(data.items.groupBy{it.attributes["group-title"]}.map { group -> - val title = group.key ?: "" - val show = group.value.map { channel -> - val streamurl = channel.url.toString() - val channelname = channel.title.toString() - val posterurl = channel.attributes["tvg-logo"].toString() - val nation = channel.attributes["group-title"].toString() + val iptvUrl = "https://raw.githubusercontent.com/Tundrak/IPTV-Italia/main/iptvitaplus.m3u" + val data = IptvPlaylistParser().parseM3U(app.get(iptvUrl).text) + val res = data.items.groupBy{it.attributes["group-title"]}.map { group -> + val title = group.key ?: "" + val show = group.value.map { channel -> + val streamurl = channel.url.toString() + val channelname = channel.title.toString() + val posterurl = channel.attributes["tvg-logo"].toString() + val nation = channel.attributes["group-title"].toString() + LiveSearchResponse( + channelname, + LoadData(streamurl, channelname, posterurl, nation, false).toJson(), + this@TvItalianaProvider.name, + TvType.Live, + posterurl, + lang = "ita" + ) + } + HomePageList( + title, + show, + isHorizontalImages = true + ) + }.toMutableList() + + val skyStreams = listOf(7,2,1).map{ n -> + app.get("https://apid.sky.it/vdp/v1/getLivestream?id=$n").parsedSafe()} + + val shows = skyStreams.map { + val posterUrl = when (it?.title){ + "MTV8" -> "https://upload.wikimedia.org/wikipedia/commons/b/ba/MTV8_logo.jpg" + else -> "https://upload.wikimedia.org/wikipedia/commons/thumb/b/bf/Sky_italia_2018.png/640px-Sky_italia_2018.png" + } + LiveSearchResponse( + it?.title!!, + LoadData(it.streamingUrl!!, it.title!!, posterUrl, "", false).toJson(), + this@TvItalianaProvider.name, + TvType.Live, + posterUrl, + lang = "ita" + ) + } + res.add( + HomePageList( + "sky italia", + shows, + isHorizontalImages = true + ) + ) + + val domain = "https://" + app.get("https://prod-realmservice.mercury.dnitv.com/realm-config/www.discoveryplus.com%2Fit%2Fepg").parsedSafe()?.domain + val deviceId = UUID.randomUUID().toString().replace("-","") + val cookies = app.get("$domain/token?deviceId=$deviceId&realm=dplay&shortlived=true").cookies + val streamDatas = app.get("$domain/cms/routes/home?include=default&decorators=playbackAllowed", cookies = cookies).parsedSafe()?.included + val posterValues = streamDatas?.filter { it.type == "image" } + ?.map { it.id to it.attributes?.src } + val discoveryinfo = streamDatas?.filter { it.type == "channel" && it.attributes?.hasLiveStream == true && it.attributes.packages?.contains("Free") ?: false } + ?.map { streamInfo -> + val posterUrl = posterValues?.find { it.first == streamInfo.relationships?.images?.data?.first()?.id }?.second!! LiveSearchResponse( - channelname, - LoadData(streamurl, channelname, posterurl, nation).toJson(), + streamInfo.attributes?.name!!, + LoadData(streamInfo.id, streamInfo.attributes.name, posterUrl, streamInfo.attributes.longDescription!!, true).toJson(), this@TvItalianaProvider.name, TvType.Live, - posterurl, + posterUrl, lang = "ita" ) } + res.add( HomePageList( - title, - show, + "Discovery", + discoveryinfo!!, isHorizontalImages = true ) - }) + ) + + return HomePageResponse(res) + + } override suspend fun search(query: String): List { @@ -56,7 +116,7 @@ class TvItalianaProvider : MainAPI() { val nation = channel.attributes["group-title"].toString() LiveSearchResponse( channelname, - LoadData(streamurl, channelname, posterurl, nation).toJson(), + LoadData(streamurl, channelname, posterurl, nation,false).toJson(), this@TvItalianaProvider.name, TvType.Live, posterurl, @@ -66,20 +126,22 @@ class TvItalianaProvider : MainAPI() { override suspend fun load(url: String): LoadResponse { val data = parseJson(url) + return LiveStreamLoadResponse( data.title, data.url, this.name, url, data.poster, - plot = data.nation + plot = data.plot ) } data class LoadData( val url: String, val title: String, val poster: String, - val nation: String + val plot: String, + val discoveryBoolean: Boolean ) override suspend fun loadLinks( @@ -88,26 +150,97 @@ class TvItalianaProvider : MainAPI() { subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit ): Boolean { + + val loadData = parseJson(data) - callback.invoke( - ExtractorLink( - this.name, - loadData.title, - loadData.url, - "", - Qualities.Unknown.value, - isM3u8 = true + + if (!loadData.discoveryBoolean) { + callback.invoke( + ExtractorLink( + this.name, + loadData.title, + loadData.url, + "", + Qualities.Unknown.value, + isM3u8 = true + ) ) - ) + } + else{ + val domain = "https://" + app.get("https://prod-realmservice.mercury.dnitv.com/realm-config/www.discoveryplus.com%2Fit%2Fepg").parsedSafe()?.domain + val deviceId = UUID.randomUUID().toString() + val cookies = app.get("$domain/token?deviceId=$deviceId&realm=dplay&shortlived=true").cookies + + val post = PostData(loadData.url, DeviceInfo(ad = false, dmr = true)).toJson() + val data = app.post("$domain/playback/v3/channelPlaybackInfo", requestBody = post.toRequestBody( + RequestBodyTypes.JSON.toMediaTypeOrNull()), cookies = cookies).text.substringAfter("\"url\" : \"").substringBefore("\"") + callback.invoke( + ExtractorLink( + this.name, + loadData.title, + data, + "", + Qualities.Unknown.value, + isM3u8 = true + ) + ) + } return true } + data class PostData( + @JsonProperty("channelId") val id: String, + @JsonProperty("deviceInfo") val deviceInfo : DeviceInfo + ) + data class DeviceInfo( + @JsonProperty("drmSupported") val dmr : Boolean, + @JsonProperty("adBlocker") val ad: Boolean, + ) + data class DomainDiscovery( + @JsonProperty("domain") val domain: String, + ) + data class DataDiscovery( + val included: List? = null + ) + + data class Included( + val attributes: IncludedAttributes? = null, + val id: String, + val relationships : IncludedRelationships? = null, + val type: String + ) + + data class IncludedRelationships( + val images: ImagesData? = null + ) + + data class ImagesData ( + val data: List? = null + ) + data class DAT ( + val id: String? = null, + ) + + + data class IncludedAttributes( + val name: String?, + val hasLiveStream : Boolean?, + val packages: List?, + val longDescription: String?, + val src: String? + ) + } data class Playlist( val items: List = emptyList(), ) +data class LivestreamResponse( + @JsonProperty("channel") val channel: String? = null, + @JsonProperty("title") val title: String? = null, + @JsonProperty("streaming_url") val streamingUrl: String? = null, +) data class PlaylistItem( val title: String? = null, val attributes: Map = emptyMap(), @@ -340,4 +473,4 @@ sealed class PlaylistParserException(message: String) : Exception(message) { class InvalidHeader : PlaylistParserException("Invalid file header. Header doesn't start with #EXTM3U") -} +} \ No newline at end of file