From dc4ca1991f5101bd7ffce277fcf525f9b715e994 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Diego=20S=C3=A1nchez?= Date: Mon, 12 Dec 2022 05:21:35 -0300 Subject: [PATCH 01/12] Repair last chapters bug in MundoDonghua Provider (#67) --- MundoDonghuaProvider/build.gradle.kts | 4 ++-- .../src/main/kotlin/com/lagradost/MundoDonghuaProvider.kt | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/MundoDonghuaProvider/build.gradle.kts b/MundoDonghuaProvider/build.gradle.kts index 62eb407..9f336ab 100644 --- a/MundoDonghuaProvider/build.gradle.kts +++ b/MundoDonghuaProvider/build.gradle.kts @@ -1,5 +1,5 @@ // use an integer for version numbers -version = 1 +version = 2 cloudstream { @@ -23,4 +23,4 @@ cloudstream { ) iconUrl = "https://www.google.com/s2/favicons?domain=www.mundodonghua.com&sz=%size%" -} \ No newline at end of file +} diff --git a/MundoDonghuaProvider/src/main/kotlin/com/lagradost/MundoDonghuaProvider.kt b/MundoDonghuaProvider/src/main/kotlin/com/lagradost/MundoDonghuaProvider.kt index 8381b2f..e41d77e 100644 --- a/MundoDonghuaProvider/src/main/kotlin/com/lagradost/MundoDonghuaProvider.kt +++ b/MundoDonghuaProvider/src/main/kotlin/com/lagradost/MundoDonghuaProvider.kt @@ -36,9 +36,10 @@ class MundoDonghuaProvider : MainAPI() { val title = it.selectFirst("h5")?.text() ?: "" val poster = it.selectFirst(".fit-1 img")?.attr("src") val epRegex = Regex("(\\/(\\d+)\$)") - val url = it.selectFirst("a")?.attr("href")?.replace(epRegex,"")?.replace("/ver/","/donghua/") val epnumRegex = Regex("((\\d+)$)") val epNum = epnumRegex.find(title)?.value?.toIntOrNull() + val epNumRemoveRegex = Regex("/" + epNum.toString() + "/.*") + val url = it.selectFirst("a")?.attr("href")?.replace(epRegex,"")?.replace("/ver/","/donghua/")?.replace(epNumRemoveRegex,"") val dubstat = if (title.contains("Latino") || title.contains("Castellano")) DubStatus.Dubbed else DubStatus.Subbed newAnimeSearchResponse(title.replace(Regex("Episodio|(\\d+)"),"").trim(), fixUrl(url ?: "")) { this.posterUrl = fixUrl(poster ?: "") @@ -214,4 +215,4 @@ class MundoDonghuaProvider : MainAPI() { } return true } -} \ No newline at end of file +} From 220d62d1dcba8530021485ef50a70c6f32fa8d41 Mon Sep 17 00:00:00 2001 From: contusionglory <102427829+contusionglory@users.noreply.github.com> Date: Mon, 12 Dec 2022 23:03:16 +0000 Subject: [PATCH 02/12] Refactored IlGenioDelloStreaming Provider and fixed it (#65) --- .../build.gradle.kts | 9 +- .../IlGenioDelloStreamingProvider.kt | 339 ++++++++++-------- 2 files changed, 202 insertions(+), 146 deletions(-) diff --git a/IlGenioDelloStreamingProvider/build.gradle.kts b/IlGenioDelloStreamingProvider/build.gradle.kts index 45514eb..fde0550 100644 --- a/IlGenioDelloStreamingProvider/build.gradle.kts +++ b/IlGenioDelloStreamingProvider/build.gradle.kts @@ -1,5 +1,5 @@ // use an integer for version numbers -version = 4 +version = 5 cloudstream { @@ -7,7 +7,7 @@ cloudstream { // All of these properties are optional, you can safely remove them // description = "Lorem Ipsum" - authors = listOf("Adippe") + authors = listOf("Adippe","Forthe") /** * Status int as the following: @@ -16,12 +16,11 @@ cloudstream { * 2: Slow * 3: Beta only * */ - status = 0 // will be 3 if unspecified + status = 1 // will be 3 if unspecified tvTypes = listOf( - "TvSeries}", "TvSeries", "Movie", ) - iconUrl = "https://www.google.com/s2/favicons?domain=ilgeniodellostreaming.quest&sz=%size%" + iconUrl = "https://www.google.com/s2/favicons?domain=ilgeniodellostreaming.hair&sz=%size%" } \ No newline at end of file diff --git a/IlGenioDelloStreamingProvider/src/main/kotlin/com/lagradost/IlGenioDelloStreamingProvider.kt b/IlGenioDelloStreamingProvider/src/main/kotlin/com/lagradost/IlGenioDelloStreamingProvider.kt index 71d89e8..728db9f 100644 --- a/IlGenioDelloStreamingProvider/src/main/kotlin/com/lagradost/IlGenioDelloStreamingProvider.kt +++ b/IlGenioDelloStreamingProvider/src/main/kotlin/com/lagradost/IlGenioDelloStreamingProvider.kt @@ -2,191 +2,248 @@ package com.lagradost import com.lagradost.cloudstream3.* import com.lagradost.cloudstream3.LoadResponse.Companion.addRating +import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer +import com.lagradost.cloudstream3.MainAPI +import com.lagradost.cloudstream3.SearchResponse +import com.lagradost.cloudstream3.TvType import com.lagradost.cloudstream3.network.CloudflareKiller +import com.lagradost.cloudstream3.utils.AppUtils.parseJson import com.lagradost.cloudstream3.utils.AppUtils.toJson -import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson import com.lagradost.cloudstream3.utils.ExtractorLink -import com.lagradost.cloudstream3.utils.ShortLink +import com.lagradost.cloudstream3.utils.ShortLink.unshorten import com.lagradost.cloudstream3.utils.loadExtractor - - +import org.jsoup.nodes.Element class IlGenioDelloStreamingProvider : MainAPI() { override var lang = "it" - override var mainUrl = "https://ilgeniodellostreaming.quest" + override var mainUrl = "https://ilgeniodellostreaming.hair" override var name = "IlGenioDelloStreaming" override val hasMainPage = true override val hasChromecastSupport = true override var sequentialMainPage = true - override val supportedTypes = setOf( - TvType.Movie, - TvType.TvSeries, - ) - override val mainPage = mainPageOf( - Pair("$mainUrl/category/film/page/", "Film Popolari"), - Pair("$mainUrl/category/serie-tv/page/", "Serie Tv Popolari"), - Pair("$mainUrl/the-most-voted/page/", "I più votati"), - Pair("$mainUrl/prime-visioni/page/", "Ultime uscite"), - ) + override val supportedTypes = + setOf( + TvType.Movie, + TvType.TvSeries, + ) + override val mainPage = + mainPageOf( + Pair("$mainUrl/popular-movies/page/", "Film Popolari"), + Pair("$mainUrl/the-most-voted/page/", "I più votati"), + ) private val interceptor = CloudflareKiller() - override suspend fun getMainPage( - page: Int, - request: MainPageRequest - ): HomePageResponse { + + private fun fixTitle(element: Element?): String { + return element?.text() + ?.trim() + ?.substringBefore("Streaming") + ?.replace("[HD]", "") + ?.replace("\\(\\d{4}\\)".toRegex(), "") + ?: "No Title found" + } + + override suspend fun getMainPage(page: Int, request: MainPageRequest): HomePageResponse { val url = request.data + page - val soup = app.get(url, interceptor = interceptor).document - val home = soup.select("div.items > article.item").map { - val title = it.selectFirst("div.data > h3 > a")!!.text().substringBeforeLast("(").substringBeforeLast("[") - 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 soup = app.get(url, referer = mainUrl).document + val home = soup.select("div.items > article.item").mapNotNull { it.toMainPageResult() } + val hasNext = home.isNotEmpty() + return newHomePageResponse(arrayListOf(HomePageList(request.name, home)), hasNext = hasNext) + } + + private fun Element.toMainPageResult(): SearchResponse { + val title = + fixTitle(this.selectFirst("div.data>h3")) + val isMovie = + (this.selectFirst("div.data>h3")?.text() ?: "").contains("\\(\\d{4}\\)".toRegex()) + val link = + this.selectFirst("div.poster>a")?.attr("href") + ?: throw ErrorLoadingException("No Link found") + + val quality = this.selectFirst("div.poster>span.quality")?.text() + val posterUrl = this.selectFirst("div.poster>a>img")?.attr("src") + + return if (isMovie) { + newMovieSearchResponse(title, link, TvType.Movie) { + addPoster(posterUrl) + quality?.let { addQuality(it) } + } + } else { + newTvSeriesSearchResponse(title, link, TvType.TvSeries) { + addPoster(posterUrl) + quality?.let { addQuality(it) } + } } - return newHomePageResponse(request.name, home) } override suspend fun search(query: String): List { - val queryformatted = query.replace(" ", "+") - val url = "$mainUrl?s=$queryformatted" - val doc = app.get(url, interceptor = interceptor, 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().substringBeforeLast("(").substringBeforeLast("[") - MovieSearchResponse( - name, - href, - this.name, - TvType.Movie, - poster - ) + val queryFormatted = query.replace(" ", "+") + val url = "$mainUrl/?s=$queryFormatted" + val doc = app.get(url, referer = mainUrl, interceptor = interceptor).document + return doc.select("div.search-page>div.result-item").map { it.toSearchResult() } + } + private fun Element.toSearchResult(): SearchResponse { + val title = + fixTitle(this.selectFirst("div.title>a")) + val isMovie = + (this.selectFirst("div.title>a")?.text() ?: "").contains("\\(\\d{4}\\)".toRegex()) + val link = + this.selectFirst("div.title>a")?.attr("href") + ?: throw ErrorLoadingException("No Link found") + + val quality = + this.selectFirst("div.title>a")?.text()?.substringAfter("[")?.substringBefore("]") + val posterUrl = this.selectFirst("a>img")?.attr("src") + + return if (isMovie) { + newMovieSearchResponse(title, link, TvType.Movie) { + addPoster(posterUrl) + if (quality != null) { + addQuality(quality) + } + } + } else { + newTvSeriesSearchResponse(title, link, TvType.TvSeries) { + addPoster(posterUrl) + if (quality != null) { + addQuality(quality) + } + } } } override suspend fun load(url: String): LoadResponse { - val page = app.get(url, interceptor = interceptor) - val document = page.document - val type = if (document.select("div.seasons-wraper").isNotEmpty()){TvType.TvSeries} else{TvType.Movie} - val title = document.selectFirst("div.data > h1")!!.text().substringBefore("(").substringBefore("[") - val description = document.selectFirst("div#info")?.selectFirst("p")?.html() - val rating = document.select("span.valor").last()?.text()?.split(" ")?.get(0) - var year = document.selectFirst(" div.data > div.extra > span.date")!!.text().substringAfter(",") - .filter { it.isDigit() } - if (year.length > 4) { - year = year.dropLast(4) - } - - val poster = document.selectFirst("div.poster > img")!!.attr("src") - - val recomm = document.select("article.w_item_b").map { - val href = it.selectFirst("a")!!.attr("href") - val posterUrl = it.selectFirst("img")!!.attr("src") - val name = it.selectFirst("div.data > h3")!!.text().substringBeforeLast("(").substringBeforeLast("[") - MovieSearchResponse( - name, - href, - this.name, - TvType.Movie, - posterUrl - ) - - } - + val document = app.get(url, referer = mainUrl).document + val type = + if (document.select("div.seasons-wraper").isNotEmpty()) TvType.TvSeries + else TvType.Movie + val title = + fixTitle(document.selectFirst("div.data > h1")) + val description = + document.selectFirst("div#info") + ?.text() + ?.substringAfter(".") + ?.substringBefore("Leggi anche") + val year = + document.selectFirst("b.variante>strong>a") + ?.text() + ?.substringBefore("-") + ?.substringAfter(",") + ?.filter { it.isDigit() } + val poster = document.selectFirst("div.poster>img")?.attr("src") + val rating = document.selectFirst("span.valor>strong")?.text()?.toRatingInt() + val trailer = + document.selectFirst("img.youtube__img") + ?.attr("src") + ?.substringAfter("vi/") + ?.substringBefore("/") + ?.let { "https://www.youtube.com/watch?v=$it" } + val recomm = document.select("article.w_item_b").map { it.toRecommendResult() } if (type == TvType.TvSeries) { - - val episodeList = ArrayList() - document.selectFirst("div.seasons-wraper") - ?.select("div.accordion-item ")?.groupBy {it.selectFirst("span.season-title")!!.text() }?.map { seasons -> - seasons.value.map {season -> season.select("div.episode-wrap")}.flatten() - .groupBy { it.selectFirst("li.season-no")?.text()?.substringBeforeLast(" ") } - .map { episodeItaSub -> - val episodes = episodeItaSub.value - val posterUrl = episodes.firstNotNullOf { it.selectFirst("img")?.attr("src")} - val epName = episodes.firstNotNullOf{it.selectFirst("li.other_link")?.text()?:""} - - episodes.map{ episode -> - val seasonNo = episode.selectFirst("li.season-no") - val subtag = seasonNo?.text()?.takeIf {it.contains("Sub")}?.substringAfter(" ") ?: "" - val urls = episode.getElementsByAttributeValue("target", "_blank").map { it.attr("href").trim() } - .filter { it.isNotEmpty()}.toJson() - episodeList.add(Episode( - data = urls, - posterUrl = posterUrl, - season = seasons.key.toIntOrNull(), - name = "$epName ${subtag.uppercase()}", - episode = seasonNo?.text()?.substringAfter("x")?.filter { it.isDigit() }?.toIntOrNull() - - )) - } + val episodeList = + document.select("div.accordion>div.accordion-item") + .map { element -> + val season = + element.selectFirst("li.s_title>span.season-title") + ?.text() + ?.toIntOrNull() + ?: 0 + element.select("div.episode-wrap").map { episode -> + episode.toEpisode(season) } - } + } + .flatten() - - val seasonnames = document.selectFirst("div#info")?.select("p")?.map {it.children() } - ?.filter { it.size<3 && it.isNotEmpty()}?.map{it.text()} - - return newTvSeriesLoadResponse( - title, - url, - type, - episodeList - ){ - addRating(rating) + return newTvSeriesLoadResponse(title, url, TvType.TvSeries, episodeList) { + this.year = year?.toIntOrNull() this.plot = description - this.year = year.toIntOrNull() - this.posterUrl = poster this.recommendations = recomm - this.seasonNames = seasonnames!!.mapIndexed { index, s -> SeasonData(index, s) } - + addPoster(poster) + addRating(rating) + addTrailer(trailer) } - - } else { val actors: List = - document.select("div.cast_wraper > ul > li").map { actorData -> - val actorName = actorData.children()[1].text() - val actorImage : String? = actorData.selectFirst("img")?.attr("data-src") - val roleActor = actorData.children()[2].text() - ActorData(actor = Actor(actorName, image = actorImage), roleString = roleActor ) + document.select("div.cast_wraper>ul>li").map { actordata -> + val actorName = actordata.selectFirst("strong")?.text() ?: "" + val actorImage: String = + actordata.selectFirst("figure>img")?.attr("src") ?: "" + ActorData(actor = Actor(actorName, image = actorImage)) } - return newMovieLoadResponse( - title, - url, - type, - (document.select("div.embed-player") + document.select("a.link_a")).map { (it.attr("href") + it.attr("data-id")).trim() }.distinct().toJson(), - ) { - posterUrl = fixUrlNull(poster) - this.year = year.toIntOrNull() + val data = document.select(".embed-player").map { it.attr("data-id") }.toJson() + return newMovieLoadResponse(title, data, TvType.Movie, data) { + this.year = year?.toIntOrNull() this.plot = description - addRating(rating) - this.recommendations = recomm - this.duration = null this.actors = actors + this.recommendations = recomm + addPoster(poster) + addRating(rating) + addTrailer(trailer) } } } + private fun Element.toRecommendResult(): SearchResponse { + val title = + fixTitle(this.selectFirst("div.data>h3")) + val isMovie = + (this.selectFirst("div.data>h3")?.text() ?: "").contains("\\(\\d{4}\\)".toRegex()) + val link = + this.selectFirst("a")?.attr("href") ?: throw ErrorLoadingException("No Link found") + + val quality = + this.selectFirst("div.data>h3")?.text()?.substringAfter("[")?.substringBefore("]") + val posterUrl = this.selectFirst("div.image>img")?.attr("src") + + return if (isMovie) { + newMovieSearchResponse(title, link, TvType.Movie) { + addPoster(posterUrl) + if (quality != null) { + addQuality(quality) + } + } + } else { + newTvSeriesSearchResponse(title, link, TvType.TvSeries) { + addPoster(posterUrl) + if (quality != null) { + addQuality(quality) + } + } + } + } + + private fun Element.toEpisode(season: Int): Episode { + val data = + this.select("div.fix-table>table>tbody>tr>td>a[target=_blank]") // buckler.link + .map { it.attr("href") } + .toJson() + val epNum = + this.selectFirst("li.season-no") + ?.text() + ?.substringAfter("x") + ?.substringBefore(" ") + ?.filter { it.isDigit() } + .orEmpty().ifBlank { "0" } + + val epTitle = + this.selectFirst("li.other_link>a")?.text().orEmpty().ifBlank { + "Episodio $epNum" + } + val posterUrl = this.selectFirst("img")?.attr("src") + return Episode(data, epTitle, season, epNum?.toInt(), posterUrl = posterUrl) + } + override suspend fun loadLinks( data: String, isCasting: Boolean, subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit ): Boolean { - val links = tryParseJson>(data) - links?.map { link -> - val url = ShortLink.unshorten(link).replace("/v/", "/e/").replace("/f/", "/e/") - loadExtractor(url, data, subtitleCallback, callback) + parseJson>(data).map { videoUrl -> + loadExtractor(unshorten(videoUrl), data, subtitleCallback, callback) } return true } -} \ No newline at end of file +} From 86d2a704efe83c447e551ab4aea7cf634cc5360c Mon Sep 17 00:00:00 2001 From: contusionglory <102427829+contusionglory@users.noreply.github.com> Date: Wed, 14 Dec 2022 22:21:58 +0000 Subject: [PATCH 03/12] Fixes and Improvements CasaCinemaProvider (#66) --- CasaCinemaProvider/build.gradle.kts | 3 +- .../com/lagradost/CasaCinemaProvider.kt | 220 +++++++++++------- 2 files changed, 137 insertions(+), 86 deletions(-) diff --git a/CasaCinemaProvider/build.gradle.kts b/CasaCinemaProvider/build.gradle.kts index 9290fe2..914b7eb 100644 --- a/CasaCinemaProvider/build.gradle.kts +++ b/CasaCinemaProvider/build.gradle.kts @@ -1,5 +1,5 @@ // use an integer for version numbers -version = 2 +version = 3 cloudstream { @@ -22,4 +22,5 @@ cloudstream { "Movie", ) + iconUrl = "https://www.google.com/s2/favicons?domain=casacinema.lol&sz=%size%" } diff --git a/CasaCinemaProvider/src/main/kotlin/com/lagradost/CasaCinemaProvider.kt b/CasaCinemaProvider/src/main/kotlin/com/lagradost/CasaCinemaProvider.kt index 795448b..e9533cd 100644 --- a/CasaCinemaProvider/src/main/kotlin/com/lagradost/CasaCinemaProvider.kt +++ b/CasaCinemaProvider/src/main/kotlin/com/lagradost/CasaCinemaProvider.kt @@ -23,42 +23,143 @@ class CasaCinemaProvider : MainAPI() { // all providers must be an instance of M private val interceptor = CloudflareKiller() override val mainPage = - mainPageOf( - "$mainUrl/category/serie-tv/page/" to "Ultime Serie Tv", - "$mainUrl/category/film/page/" to "Ultimi Film", - ) + mainPageOf( + "$mainUrl/category/serie-tv/page/" to "Ultime Serie Tv", + "$mainUrl/category/film/page/" to "Ultimi Film", + ) + + private fun fixTitle(element: Element?): String { + return element?.text() + ?.trim() + ?.substringBefore("Streaming") + ?.replace("[HD]", "") + ?.replace("\\(\\d{4}\\)".toRegex(), "") + ?: "No Title found" + } + + private fun Element?.isMovie(): Boolean { + return (this + ?.text() ?: "") + .contains("\\(\\d{4}\\)".toRegex()) + } override suspend fun getMainPage(page: Int, request: MainPageRequest): HomePageResponse { val url = request.data + page - val soup = app.get(url).document + val soup = app.get(url, referer = mainUrl).document val home = soup.select("ul.posts>li").mapNotNull { it.toSearchResult() } val hasNext = soup.select("div.navigation>ul>li>a").last()?.text() == "Pagina successiva »" return newHomePageResponse(arrayListOf(HomePageList(request.name, home)), hasNext = hasNext) } + + override suspend fun search(query: String): List { + val queryFormatted = query.replace(" ", "+") + val url = "$mainUrl/?s=$queryFormatted" + val doc = app.get(url, referer = mainUrl, interceptor = interceptor).document + return doc.select("ul.posts>li").map { it.toSearchResult() } + } + private fun Element.toSearchResult(): SearchResponse { - val title = - this.selectFirst(".title")?.text()?.replace("[HD]", "")?.substringBefore("(") - ?: "No title" - val isMovie = (this.selectFirst(".title")?.text() ?: "").contains("\\(\\d{4}\\)".toRegex()) + val title = fixTitle(this.selectFirst(".title")) + val isMovie = this.selectFirst(".title").isMovie() val link = - this.selectFirst("a")?.attr("href") ?: throw ErrorLoadingException("No Link found") + this.selectFirst("a")?.attr("href") ?: throw ErrorLoadingException("No Link found") val quality = this.selectFirst("div.hd")?.text() - val posterUrl = this.selectFirst("a")?.attr("data-thumbnail") - if (isMovie) { - return newMovieSearchResponse(title, link, TvType.Movie) { + return if (isMovie) { + newMovieSearchResponse(title, link, TvType.Movie) { + addPoster(posterUrl) + quality?.let { addQuality(it) } + } + } else { + newTvSeriesSearchResponse(title, link, TvType.TvSeries) { + addPoster(posterUrl) + quality?.let { addQuality(it) } + } + } + } + + override suspend fun load(url: String): LoadResponse { + val document = app.get(url, referer = mainUrl).document + val type = + if (document.select("div.seasons-wraper").isNotEmpty()) TvType.TvSeries + else TvType.Movie + val title = fixTitle(document.selectFirst("div.row > h1")) + val description = document.select("div.element").last()?.text() + val year = document.selectFirst("div.element>a.tag") + ?.text() + ?.substringBefore("-") + ?.substringAfter(",") + ?.filter { it.isDigit() } + val poster = document.selectFirst("img.thumbnail")?.attr("src") + val rating = document.selectFirst("div.rating>div.value")?.text()?.trim()?.toRatingInt() + val recomm = document.select("div.crp_related>ul>li").map { it.toRecommendResult() } + if (type == TvType.TvSeries) { + val episodeList = + document.select("div.accordion>div.accordion-item") + .map { element -> + val season = + element.selectFirst("li.s_title>span.season-title") + ?.text() + ?.toIntOrNull() + ?: 0 + element.select("div.episode-wrap").map { episode -> + episode.toEpisode(season) + } + } + .flatten() + + return newTvSeriesLoadResponse(title, url, TvType.TvSeries, episodeList) { + this.year = year?.toIntOrNull() + this.plot = description + this.recommendations = recomm + addPoster(poster) + addRating(rating) + } + } else { + val actors: List = + document.select("div.cast_wraper>ul>li").map { actordata -> + val actorName = actordata.selectFirst("strong")?.text() ?: "" + val actorImage: String = + actordata.selectFirst("figure>img")?.attr("src") ?: "" + ActorData(actor = Actor(actorName, image = actorImage)) + } + val data = document.select(".embed-player").map { it.attr("data-id") }.toJson() + return newMovieLoadResponse(title, data, TvType.Movie, data) { + this.year = year?.toIntOrNull() + this.plot = description + this.actors = actors + this.recommendations = recomm + addPoster(poster) + addRating(rating) + } + } + } + + private fun Element.toRecommendResult(): SearchResponse { + val title = + fixTitle(this.selectFirst("span.crp_title")) + val isMovie = this.selectFirst("span.crp_title").isMovie() + val link = + this.selectFirst("a")?.attr("href") ?: throw ErrorLoadingException("No Link found") + + val quality = + this.selectFirst("span.crp_title")?.text()?.substringAfter("[")?.substringBefore("]") + val posterUrl = this.selectFirst("img")?.attr("src") + + return if (isMovie) { + newMovieSearchResponse(title, link, TvType.Movie) { addPoster(posterUrl) if (quality != null) { addQuality(quality) } } } else { - return newTvSeriesSearchResponse(title, link, TvType.TvSeries) { + newTvSeriesSearchResponse(title, link, TvType.TvSeries) { addPoster(posterUrl) if (quality != null) { addQuality(quality) @@ -69,82 +170,31 @@ class CasaCinemaProvider : MainAPI() { // all providers must be an instance of M private fun Element.toEpisode(season: Int): Episode { val data = - this.select("div.fix-table>table>tbody>tr>td>a[target=_blank]") - .map { it.attr("href") } - .toJson() // isecure.link - val epTitle = this.selectFirst("li.other_link>a")?.text() ?: "No Ep. Title 0" - val epNum = epTitle.substringAfter("Episodio ").toInt() - return Episode(data, epTitle, season, epNum) - } + this.select("div.fix-table>table>tbody>tr>td>a[target=_blank]") + .map { it.attr("href") } + .toJson() // isecure.link + val epNum = + this.selectFirst("li.season-no") + ?.text() + ?.substringAfter("x") + ?.substringBefore(" ") + ?.filter { it.isDigit() } + .orEmpty().ifBlank { "0" } - override suspend fun search(query: String): List { - val queryFormatted = query.replace(" ", "+") - val url = "$mainUrl/?s=$queryFormatted" - val doc = app.get(url, referer = mainUrl, interceptor = interceptor).document - return doc.select("ul.posts>li").map { it.toSearchResult() } - } - - override suspend fun load(url: String): LoadResponse { - val document = app.get(url).document - val type = - if (document.selectFirst("h3")?.text() == "Altri Film:") TvType.Movie - else TvType.TvSeries - val title = - document.selectFirst("div.row > h1") - ?.text() - ?.replace("[HD]", "") - ?.substringBefore("(") - ?: "No Title found" - val description = document.select("div.element").last()?.text() - val year = document.selectFirst("div.element>a.tag")?.text()?.substringBefore("-") - val poster = document.selectFirst("img.thumbnail")?.attr("src") - val rating = document.selectFirst("div.rating>div.value")?.text()?.trim()?.toRatingInt() - - if (type == TvType.TvSeries) { - val episodeList = - document.select("div.accordion>div.accordion-item") - .map { element -> - val season = - element.selectFirst("li.s_title>span.season-title") - ?.text() - ?.toIntOrNull() - ?: 0 - element.select("div.episode-wrap").map { episode -> - episode.toEpisode(season) - } - } - .flatten() - - return newTvSeriesLoadResponse(title, url, TvType.TvSeries, episodeList) { - this.year = year?.toIntOrNull() - this.plot = description - addPoster(poster) - addRating(rating) + val epTitle = + this.selectFirst("li.other_link>a")?.text().orEmpty().ifBlank { + "Episodio $epNum" } - } else { - val actors: List = - document.select("div.cast_wraper>ul>li").map { actordata -> - val actorName = actordata.selectFirst("strong")?.text() ?: "" - val actorImage: String? = - actordata.selectFirst("figure>img")?.attr("src") ?: "" - ActorData(actor = Actor(actorName, image = actorImage)) - } - val data = document.select(".embed-player").map { it.attr("data-id") }.toJson() - return newMovieLoadResponse(title, data, TvType.Movie, data) { - this.year = year?.toIntOrNull() - this.plot = description - this.actors = actors - addPoster(poster) - addRating(rating) - } - } + val posterUrl = this.selectFirst("figure>img")?.attr("src") + return Episode(data, epTitle, season, epNum.toInt(), posterUrl = posterUrl) } + override suspend fun loadLinks( - data: String, - isCasting: Boolean, - subtitleCallback: (SubtitleFile) -> Unit, - callback: (ExtractorLink) -> Unit + data: String, + isCasting: Boolean, + subtitleCallback: (SubtitleFile) -> Unit, + callback: (ExtractorLink) -> Unit ): Boolean { parseJson>(data).map { videoUrl -> loadExtractor(unshorten(videoUrl), data, subtitleCallback, callback) From 93ee6d5c6a041d1dead451419df2a148e79bf858 Mon Sep 17 00:00:00 2001 From: contusionglory <102427829+contusionglory@users.noreply.github.com> Date: Fri, 23 Dec 2022 20:21:33 +0000 Subject: [PATCH 04/12] Refactoring and fixing SoraItalianStream (#70) * Refactoring and fixing SoraItalianStream * Fixes * Fixes * Remove not null operator * Remove run * Change to apmap and replace some map with foreach * Change map to foreach and set the right referer --- SoraItalianStream/build.gradle.kts | 4 +- .../src/main/kotlin/SoraItalianExtractor.kt | 226 +++++++-------- .../src/main/kotlin/SoraItalianStream.kt | 263 +++++++++--------- 3 files changed, 229 insertions(+), 264 deletions(-) diff --git a/SoraItalianStream/build.gradle.kts b/SoraItalianStream/build.gradle.kts index 8ed141f..0356d7f 100644 --- a/SoraItalianStream/build.gradle.kts +++ b/SoraItalianStream/build.gradle.kts @@ -1,5 +1,5 @@ // use an integer for version numbers -version = 1 +version = 2 cloudstream { @@ -7,7 +7,7 @@ cloudstream { // 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") + authors = listOf("Adippe", "Forthe") /** * Status int as the following: diff --git a/SoraItalianStream/src/main/kotlin/SoraItalianExtractor.kt b/SoraItalianStream/src/main/kotlin/SoraItalianExtractor.kt index 9d898ae..b277fb3 100644 --- a/SoraItalianStream/src/main/kotlin/SoraItalianExtractor.kt +++ b/SoraItalianStream/src/main/kotlin/SoraItalianExtractor.kt @@ -4,6 +4,7 @@ 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.cloudstream3.utils.ShortLink.unshorten import com.lagradost.nicehttp.Requests object SoraItalianExtractor : SoraItalianStream() { @@ -17,14 +18,13 @@ object SoraItalianExtractor : SoraItalianStream() { "https://guardahd.stream/movie/$id", referer = "/" ).document - res.select("ul._player-mirrors > li").map { source -> + res.select("ul._player-mirrors > li").forEach { source -> loadExtractor( fixUrl(source.attr("data-link")), - "$/", + "https://guardahd.stream", subtitleCallback, callback ) - println("LINK DI Guardare " + fixUrl(source.attr("data-link"))) } } @@ -42,18 +42,18 @@ object SoraItalianExtractor : SoraItalianStream() { "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 -> + document.select("div.tab-content > div").forEachIndexed { seasonData, data -> + data.select("li").forEachIndexed { epNum, epData -> if (season == seasonData + 1 && episode == epNum + 1) { - epData.select("div.mirrors > a").map { + epData.select("div.mirrors > a.mr").forEach { loadExtractor( fixUrl(it.attr("data-link")), - "$/", + guardaserieUrl, subtitleCallback, callback ) - println("LINK DI guardaserie " + it.attr("data-link")) } } } @@ -79,121 +79,102 @@ object SoraItalianExtractor : SoraItalianStream() { .filter { it != filmpertuttiUrl } links.apmap { val doc = app.get(it).document - if (id == doc.selectFirst(" div.rating > p > a")?.attr("href") + if (id == doc.selectFirst("div.rating > p > a") //check if corresponds to the imdb id + ?.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() + a.selectFirst("#season > ul > li.s_title > span")!! + .text() + .isNotEmpty() }.find { - season == it.selectFirst("#season > ul > li.s_title > span")!!.text() + 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") + episode == it.selectFirst("li.season-no")!!.text() + .substringAfter("x") + .substringBefore(" ") .filter { it.isDigit() }.toIntOrNull() } episodeData?.select("#links > div > div > table > tbody:nth-child(2) > tr") - ?.map { + ?.forEach { + val unshortenLink = unshorten(it.selectFirst("a")?.attr("href") ?: "") loadExtractor( - it.selectFirst("a")!!.attr("href") ?: "", + unshortenLink, 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")) } + } else { //movie + doc.select("#info > ul > li").forEach { + val unshortenLink = unshorten(it.selectFirst("a")?.attr("href") ?: "") + loadExtractor( + unshortenLink, + filmpertuttiUrl, + subtitleCallback, + callback + ) } } } } } - 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 res = app.get("$cb01Url/search/$title%20$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 { + doc.select("tr > td > a[href*='stayonline.pro']").forEach { 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} + val apiPostId = link.substringAfter("/l/") + .substringBefore("/") //https://stayonline.pro/l/abcdef/ -> abcdef + val apiBodyBypass = app.post( + "https://stayonline.pro/ajax/linkView.php", + data = mapOf("id" to apiPostId) + ).text + var bypassedUrl = + apiBodyBypass.substringAfter("\"value\": \"").substringBefore("\"") + .replace("\\", "") //bypass stayonline link + + if (bypassedUrl.contains("mixdrop.club")) //https://mixdrop.club/f/lllllllll/2/abcdefghilmn.mp4 (fake mp4 url) -> https://mixdrop.ch/e/lllllllll + bypassedUrl = bypassedUrl.replace("mixdrop.club", "mixdrop.ch") + .substringBeforeLast("/") + .substringBeforeLast("/") + .replace("/f/", "/e/") + else + bypassedUrl = unshorten(bypassedUrl) loadExtractor( - processedUrl, - "$/", + bypassedUrl, + cb01Url, 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 @@ -202,13 +183,13 @@ object SoraItalianExtractor : SoraItalianStream() { fixUrl(it.select("a.name").firstOrNull()?.attr("href") ?: "", animeworldUrl) }.apmap { val document = app.get(it).document - val malID = document.select("#mal-button").attr("href") + val pageMalId = document.select("#mal-button").attr("href") .split('/').last().toString() - if (malId == malID) { + if (malId == pageMalId) { 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 -> + .forEach { id -> val url = tryParseJson( app.get("$animeworldUrl/api/episode/info?id=${id.attr("data-id")}").text )?.grabber @@ -229,12 +210,11 @@ object SoraItalianExtractor : SoraItalianStream() { ExtractorLink( "AnimeWorld", nameData, - url?:"", + url ?: "", referer = animeworldUrl, quality = Qualities.Unknown.value ) ) - println("LINK DI Animeworld " + url) } } } @@ -245,7 +225,6 @@ object SoraItalianExtractor : SoraItalianStream() { title: String?, episode: Int?, year: Int?, - subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit ) { val response = @@ -266,7 +245,6 @@ object SoraItalianExtractor : SoraItalianStream() { val streamUrl = parseJson(app.get(episodeUrl).text).url callback.invoke( - ExtractorLink( name, AnimeName, @@ -276,16 +254,16 @@ object SoraItalianExtractor : SoraItalianStream() { isM3u8 = streamUrl.contains(".m3u8"), ) ) - } - else { - val seasonid = response.seasons.sortedBy { it.episodeStart }.last { it.episodeStart < episode!!} + } 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 + val episodeData = episodesData?.find { it.number == episode.toString() }?.id if (episodeData != null) { val streamUrl = parseJson(app.get("$aniplayUrl/api/episode/${episodeData}").text).url @@ -299,7 +277,6 @@ object SoraItalianExtractor : SoraItalianStream() { isM3u8 = streamUrl.contains(".m3u8"), ) ) - println("LINK DI aniplay " + streamUrl) } } } @@ -310,10 +287,10 @@ object SoraItalianExtractor : SoraItalianStream() { malId: String?, title: String?, episode: Int?, - subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit ) { - val document = app.get("$animesaturnUrl/animelist?search=${title?.replace("-"," ")}").document + 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") } @@ -324,53 +301,48 @@ object SoraItalianExtractor : SoraItalianStream() { } else { "AnimeSaturn SUB" } - var malID : String? = null + var malID: String? - 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") + response.select("a[href*=myanimelist]").forEach { + malID = it.attr("href").substringBeforeLast("/") + .substringAfterLast("/") //https://myanimelist.net/anime/19/ -> 19 + if (malId == malID) { + val link = response.select("a.bottone-ep") + .find { it.text().substringAfter("Episodio ") == episode.toString() } + ?.attr("href") + if (link?.isBlank() == false) { //links exists + val page = app.get(link).document + val episodeLink = page.select("div.card-body > a[href*=watch]").attr("href") + ?: throw ErrorLoadingException("No link Found") - val episodePage = app.get(episodeLink).document - val episodeUrl: String? - var isM3U8 = false + val episodePage = app.get(episodeLink).document + val episodeUrl: String? = episodePage.select("video.afterglow > source") + .let { // Old player + it.first()?.attr("src") + } + ?: //new player + Regex("\"(https[A-z0-9\\/\\:\\.]*\\.m3u8)\",").find( + episodePage.select("script").find { + it.toString().contains("jwplayer('player_hls').setup({") + }.toString() + )?.value - 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 = episodeUrl.contains(".m3u8"), + referer = "https://www.animesaturn.io/", //Some servers need the old host as referer, and the new ones accept it too + quality = Qualities.Unknown.value + ) + ) } - 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) } - } - } - } + } } } @@ -397,6 +369,4 @@ fun fixUrl(url: String, domain: String): String { return "$domain/$url" } - } - diff --git a/SoraItalianStream/src/main/kotlin/SoraItalianStream.kt b/SoraItalianStream/src/main/kotlin/SoraItalianStream.kt index 0a258e7..01c3a4f 100644 --- a/SoraItalianStream/src/main/kotlin/SoraItalianStream.kt +++ b/SoraItalianStream/src/main/kotlin/SoraItalianStream.kt @@ -5,7 +5,6 @@ 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 @@ -37,8 +36,7 @@ open class SoraItalianStream : TmdbProvider() { 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 cb01Url = "https://cb01.tours/" const val animeworldUrl = "https://www.animeworld.tv" const val aniplayUrl = "https://aniplay.it" const val animesaturnUrl = "https://www.animesaturn.in" @@ -69,6 +67,12 @@ open class SoraItalianStream : TmdbProvider() { return api.chunked(4).map { base64Decode(it) }.reversed().joinToString("") } + fun containsJapaneseCharacters(str: String?): Boolean { //sometimes the it-It translation of names gives the japanese name of the anime + val japaneseCharactersRegex = + Regex("[\\u3000-\\u303f\\u3040-\\u309f\\u30a0-\\u30ff\\uff00-\\uff9f\\u4e00-\\u9faf\\u3400-\\u4dbf]") + return str?.let { japaneseCharactersRegex.containsMatchIn(it) } == true + } + } @@ -119,22 +123,13 @@ open class SoraItalianStream : TmdbProvider() { } - override suspend fun search(query: String): List { - val searchResponse = mutableListOf() - - val mainResponse = app.get( + override suspend fun search(query: String): List? { + return 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 + ) + .parsedSafe()?.results?.mapNotNull { media -> + media.toSearchResponse() + } } @@ -143,16 +138,16 @@ open class SoraItalianStream : TmdbProvider() { val type = getType(data.type) - val typename = when(type){ - TvType.TvSeries-> "tv" - TvType.Movie -> "movie" - else -> "" - } + val typename = data.type - val res = + var 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") - + if (containsJapaneseCharacters(res.name)) { + res = + app.get("$tmdbAPI/$typename/${data.id}?api_key=$apiKey&language=en-US&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 @@ -175,81 +170,67 @@ open class SoraItalianStream : TmdbProvider() { 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 isAnime = res.genres?.any { it.id == 16L } == true - 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( + return if (type == TvType.Movie) { //can be a movie or a anime movie + newMovieLoadResponse( title, url, - TvType.TvSeries, - episodes + TvType.Movie, + LinkData( + data.id, + res.externalIds?.imdbId, + data.type, + title = title, + year = year, + orgTitle = orgTitle, + isAnime = isAnime + ).toJson(), ) { 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) { + } else { //can be anime series or tv series val episodes = mutableListOf() - res.seasons?.filter { it.seasonNumber != 0L }?.apmap { season -> + var seasonNum = 0 + val seasonDataList = res.seasons?.filter { it.seasonNumber != 0 }?.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) - }) - } + .parsedSafe()?.episodes + } + + res.seasons?.filter { it.seasonNumber != 0 }?.forEachIndexed { index, season -> + val seasonData = seasonDataList?.get(index) + if (seasonData?.first()?.episodeNumber == 1) + seasonNum += 1 + + seasonData?.forEach { eps -> + episodes.add(Episode( + LinkData( + data.id, + res.externalIds?.imdbId, + data.type, + seasonNum, + eps.episodeNumber, + title = title, + year = year ?: season.airDate?.split("-")?.first()?.toIntOrNull(), + orgTitle = orgTitle, + isAnime = isAnime + ).toJson(), + name = eps.name, + season = seasonNum, + episode = eps.episodeNumber, + posterUrl = getImageUrl(eps.stillPath), + rating = eps.voteAverage?.times(10)?.roundToInt(), + description = eps.overview + ).apply { + this.addDate(eps.airDate) + }) + } } newTvSeriesLoadResponse( title, @@ -267,30 +248,6 @@ open class SoraItalianStream : TmdbProvider() { 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( @@ -304,28 +261,60 @@ open class SoraItalianStream : TmdbProvider() { 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) invoAnimeWorld( + malID, + res.title, + res.episode, + callback + ) }, { - if (res.isAnime) invoAniPlay(malID, res.title, res.episode, res.year, subtitleCallback, callback) + if (res.isAnime) invoAniPlay( + malID, + res.title, + res.episode, + res.year, + callback + ) }, { - if (res.isAnime) invoAnimeSaturn(malID, res.title, res.episode, subtitleCallback, callback) + if (res.isAnime) invoAnimeSaturn( + malID, + res.title, + res.episode, + callback + ) }, { - invoGuardare(res.imdbId, subtitleCallback, callback) + if (res.type == "movie") invoGuardare( + res.imdbId, + subtitleCallback, + callback + ) //just movies/anime movie }, { - if (malID == "") invoGuardaserie(res.imdbId, res.season, res.episode, subtitleCallback, callback) + if (res.type == "tv") invoGuardaserie( //has tv series and anime + 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) + invoFilmpertutti( //has tv series, film and some anime + 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) + if (res.type == "movie") invoCb01(res.title, res.year, subtitleCallback, callback) } ) @@ -335,7 +324,7 @@ open class SoraItalianStream : TmdbProvider() { private data class LinkData( val id: Int? = null, val imdbId: String? = null, - val type: String? = null, + val type: String? = null, //movie or tv val season: Int? = null, val episode: Int? = null, val aniId: String? = null, @@ -343,7 +332,7 @@ open class SoraItalianStream : TmdbProvider() { val title: String? = null, val year: Int? = null, val orgTitle: String? = null, - val isAnime : Boolean + val isAnime: Boolean ) data class Data( @@ -415,7 +404,7 @@ open class SoraItalianStream : TmdbProvider() { ) - data class MovieDetails ( + data class MovieDetails( val adult: Boolean? = null, @JsonProperty("first_air_date") val tvDate: String? = null, @JsonProperty("release_date") val movieDate: String? = null, @@ -442,19 +431,19 @@ open class SoraItalianStream : TmdbProvider() { @JsonProperty("external_ids") val externalIds: ExternalIds? = null ) - data class Recommendations ( + data class Recommendations( @JsonProperty("results") val results: List? = null, ) - data class Credits ( + data class Credits( val cast: List? = null, ) - data class ExternalIds ( + data class ExternalIds( @JsonProperty("imdb_id") val imdbId: String? = null ) - data class Videos ( + data class Videos( val results: List? = null, ) @@ -462,19 +451,19 @@ open class SoraItalianStream : TmdbProvider() { @JsonProperty("key") val key: String? = null, ) - data class Genre ( + data class Genre( val id: Long? = null, val name: String? = null ) - data class Season ( + data class Season( @JsonProperty("air_date") val airDate: String? = null, - @JsonProperty("episode_count") val episodeCount: Long? = null, + @JsonProperty("episode_count") val episodeCount: Int? = 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 + @JsonProperty("season_number") val seasonNumber: Int? = null ) data class AnimeWorldJson( @@ -482,30 +471,36 @@ open class SoraItalianStream : TmdbProvider() { @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 + @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 +} From 759ada5f411b7755a692e6ff4d1689a62294152e Mon Sep 17 00:00:00 2001 From: contusionglory <102427829+contusionglory@users.noreply.github.com> Date: Sat, 24 Dec 2022 18:10:29 +0000 Subject: [PATCH 05/12] Added SkillShare.com (#71) * Added SkillShare.com * Fixes and improvement * Fixed cursor and increased timeout * Update build.gradle.kts * Removed some ? and make payload more clear to read --- SkillShareProvider/build.gradle.kts | 25 ++ .../src/main/AndroidManifest.xml | 2 + .../com/lagradost/SkillShareProvider.kt | 252 ++++++++++++++++++ .../com/lagradost/SkillShareProviderPlugin.kt | 14 + 4 files changed, 293 insertions(+) create mode 100644 SkillShareProvider/build.gradle.kts create mode 100644 SkillShareProvider/src/main/AndroidManifest.xml create mode 100644 SkillShareProvider/src/main/kotlin/com/lagradost/SkillShareProvider.kt create mode 100644 SkillShareProvider/src/main/kotlin/com/lagradost/SkillShareProviderPlugin.kt diff --git a/SkillShareProvider/build.gradle.kts b/SkillShareProvider/build.gradle.kts new file mode 100644 index 0000000..c808ff8 --- /dev/null +++ b/SkillShareProvider/build.gradle.kts @@ -0,0 +1,25 @@ +// use an integer for version numbers +version = 1 + + +cloudstream { + // All of these properties are optional, you can safely remove them + + // description = "Lorem Ipsum" + language= "en" + authors = listOf("Forthe") + + /** + * Status int as the following: + * 0: Down + * 1: Ok + * 2: Slow + * 3: Beta only + * */ + status = 1 // will be 3 if unspecified + tvTypes = listOf( + "TvSeries", + ) + + iconUrl = "https://www.google.com/s2/favicons?domain=skillshare.com&sz=%size%" +} diff --git a/SkillShareProvider/src/main/AndroidManifest.xml b/SkillShareProvider/src/main/AndroidManifest.xml new file mode 100644 index 0000000..29aec9d --- /dev/null +++ b/SkillShareProvider/src/main/AndroidManifest.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/SkillShareProvider/src/main/kotlin/com/lagradost/SkillShareProvider.kt b/SkillShareProvider/src/main/kotlin/com/lagradost/SkillShareProvider.kt new file mode 100644 index 0000000..89f5550 --- /dev/null +++ b/SkillShareProvider/src/main/kotlin/com/lagradost/SkillShareProvider.kt @@ -0,0 +1,252 @@ +package com.lagradost + +import com.fasterxml.jackson.annotation.JsonProperty +import com.lagradost.cloudstream3.* +import com.lagradost.cloudstream3.MainAPI +import com.lagradost.cloudstream3.SearchResponse +import com.lagradost.cloudstream3.TvType +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 + +class SkillShareProvider : MainAPI() { // all providers must be an instance of MainAPI + override var mainUrl = "https://www.skillshare.com" + override var name = "SkillShare" + + private val apiUrl = "https://www.skillshare.com/api/graphql" + private val bypassApiUrl = "https://skillshare-api.heckernohecking.repl.co" + + override val supportedTypes = setOf(TvType.TvSeries) + override val hasChromecastSupport = true + override var lang = "en" + override val hasMainPage = true + private var cursor = mutableMapOf("SIX_MONTHS_ENGAGEMENT" to "", "ML_TRENDINESS" to "") + + override val mainPage = + mainPageOf( + "SIX_MONTHS_ENGAGEMENT" to "Popular Classes", + "ML_TRENDINESS" to "Trending Classes", + ) + + private suspend fun queryMovieApi(payload: String): String { + val req = payload.toRequestBody(RequestBodyTypes.JSON.toMediaTypeOrNull()) + return app.post(apiUrl, requestBody = req, referer = "$mainUrl/", timeout = 30).text + } + + override suspend fun getMainPage(page: Int, request: MainPageRequest): HomePageResponse { + val sortAttribute = request.data + if (page == 1) //reset the cursor to "" if the first page is requested + cursor[sortAttribute] = "" + val payload= + """ + { + "query":"query GetClassesByType(${'$'}filter: ClassFilters!, ${'$'}pageSize: Int, ${'$'}cursor: String, ${'$'}type: ClassListType!, ${'$'}sortAttribute: ClassListByTypeSortAttribute) { + classListByType(type: ${'$'}type, where: ${'$'}filter, first: ${'$'}pageSize, after: ${'$'}cursor, sortAttribute: ${'$'}sortAttribute) { + nodes { + id + title + url + sku + smallCoverUrl + largeCoverUrl + } + } + }", + "variables":{ + "type":"TRENDING_CLASSES", + "filter":{ + "subCategory":"", + "classLength":[] + }, + "pageSize":30, + "cursor":"${cursor[sortAttribute]}", + "sortAttribute":"$sortAttribute" + }, + "operationName":"GetClassesByType" + } + """.replace(Regex("\n")," ") + + val responseBody = queryMovieApi(payload) + val parsedJson = parseJson(responseBody).data.classListByType.nodes + val home = parsedJson.map { + it.toSearchResult() + } + cursor[sortAttribute] = parsedJson.lastOrNull()?.id ?: "" //set the right cursor for the nextPage to work + return newHomePageResponse( + arrayListOf(HomePageList(request.name, home, isHorizontalImages = true)), + hasNext = home.isNotEmpty(), + ) + } + + override suspend fun search(query: String): List { + val payload = + """ + { + "query":"fragment ClassFields on Class { + id + smallCoverUrl + largeCoverUrl + sku + title + url + } + + query GetClassesQuery(${"$"}query: String!, ${"$"}where: SearchFilters!, ${"$"}after: String!, ${"$"}first: Int!) { + search(query: ${"$"}query, where: ${"$"}where, analyticsTags: [\"src:browser\", \"src:browser:search\"], after: ${"$"}after, first: ${"$"}first) { + edges { + node { + ...ClassFields + } + } + } + }", + "variables":{ + "query":"$query", + "where":{ + "level": + ["ALL_LEVELS","BEGINNER","INTERMEDIATE","ADVANCED"] + }, + "after":"-1", + "first":30 + }, + "operationName":"GetClassesQuery" + } + """.replace(Regex("\n")," ") + + val responseBody = queryMovieApi(payload) + val home = parseJson(responseBody).data.search.edges.map { + it.node.toSearchResult() + } + return home + } + + private fun ApiNode.toSearchResult(): SearchResponse { + val title = this.title ?: "" + val posterUrl = this.smallCoverUrl + return newTvSeriesSearchResponse( + title, + Data( + title = this.title, + courseId = this.courseId, + largeCoverUrl = this.largeCoverUrl + ).toJson(), + TvType.TvSeries + ) { + addPoster(posterUrl) + } + } + + + override suspend fun load(url: String): LoadResponse { + val data = parseJson(url) + val document = app.get(bypassApiUrl + "/${data.courseId}/0") + .parsedSafe() ?: throw ErrorLoadingException("Invalid Json Response") + val title = data.title ?: "" + val poster = data.largeCoverUrl + val episodeList = document.lessons.mapIndexed { index, episode -> + Episode(episode.url ?: "", episode.title, 1, index) + } + + return newTvSeriesLoadResponse(title, mainUrl, TvType.TvSeries, episodeList) { + addPoster(poster) + } + } + + override suspend fun loadLinks( + data: String, + isCasting: Boolean, + subtitleCallback: (SubtitleFile) -> Unit, + callback: (ExtractorLink) -> Unit + ): Boolean { + callback.invoke( + ExtractorLink( + name, + name, + data, + isM3u8 = false, + referer = "$mainUrl/", + quality = Qualities.Unknown.value + ) + ) + return true + } + + + data class ApiNode( + //mainpage and search page + @JsonProperty("id") var id: String? = null, + @JsonProperty("title") var title: String? = null, + @JsonProperty("url") var url: String? = null, + @JsonProperty("sku") var courseId: String? = null, + @JsonProperty("smallCoverUrl") var smallCoverUrl: String? = null, + @JsonProperty("largeCoverUrl") var largeCoverUrl: String? = null, + ) + + data class ApiNodes( //mainpage + + @JsonProperty("nodes") var nodes: ArrayList = arrayListOf() + + ) + + data class ApiClassListByType( //mainpage + + @JsonProperty("classListByType") var classListByType: ApiNodes = ApiNodes() + + ) + + data class ApiData( //mainpage + + @JsonProperty("data") var data: ApiClassListByType = ApiClassListByType() + + ) + + data class SearchApiNodes( //search + + @JsonProperty("node") var node: ApiNode = ApiNode() + + ) + + data class SearchApiEdges( //search + + @JsonProperty("edges") var edges: ArrayList = arrayListOf() + + ) + + data class SearchApiSearch( //search + + @JsonProperty("search") var search: SearchApiEdges = SearchApiEdges() + + ) + + data class SearchApiData( //search + + @JsonProperty("data") var data: SearchApiSearch = SearchApiSearch() + + ) + + data class BypassApiLesson( //bypass + + @JsonProperty("title") var title: String? = null, + @JsonProperty("url") var url: String? = null + + ) + + data class BypassApiData( //bypass + + @JsonProperty("class") var title: String? = null, + @JsonProperty("class_thumbnail") var largeCoverUrl: String? = null, + @JsonProperty("lessons") var lessons: ArrayList = arrayListOf() + + ) + + data class Data( + //for loading + val title: String? = null, + val courseId: String? = null, + val largeCoverUrl: String? = null, + ) +} diff --git a/SkillShareProvider/src/main/kotlin/com/lagradost/SkillShareProviderPlugin.kt b/SkillShareProvider/src/main/kotlin/com/lagradost/SkillShareProviderPlugin.kt new file mode 100644 index 0000000..2bc844e --- /dev/null +++ b/SkillShareProvider/src/main/kotlin/com/lagradost/SkillShareProviderPlugin.kt @@ -0,0 +1,14 @@ +package com.lagradost + +import android.content.Context +import com.lagradost.cloudstream3.plugins.CloudstreamPlugin +import com.lagradost.cloudstream3.plugins.Plugin + +@CloudstreamPlugin +class SkillShareProviderPlugin : Plugin() { + override fun load(context: Context) { + // All providers should be added in this manner. Please don't edit the providers list + // directly. + registerMainAPI(SkillShareProvider()) + } +} From 71922eaa40f90938845fee3bc1801e51a15872fc Mon Sep 17 00:00:00 2001 From: LagradOst <46196380+Blatzar@users.noreply.github.com> Date: Sat, 24 Dec 2022 19:38:41 +0100 Subject: [PATCH 06/12] Update internal url to fix watch progress --- .../src/main/kotlin/com/lagradost/SkillShareProvider.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SkillShareProvider/src/main/kotlin/com/lagradost/SkillShareProvider.kt b/SkillShareProvider/src/main/kotlin/com/lagradost/SkillShareProvider.kt index 89f5550..3192eb4 100644 --- a/SkillShareProvider/src/main/kotlin/com/lagradost/SkillShareProvider.kt +++ b/SkillShareProvider/src/main/kotlin/com/lagradost/SkillShareProvider.kt @@ -151,7 +151,7 @@ class SkillShareProvider : MainAPI() { // all providers must be an instance of M Episode(episode.url ?: "", episode.title, 1, index) } - return newTvSeriesLoadResponse(title, mainUrl, TvType.TvSeries, episodeList) { + return newTvSeriesLoadResponse(title, data.courseId, TvType.TvSeries, episodeList) { addPoster(poster) } } From 6b9070b9bea074b12494b8d4f283aeb128e8a577 Mon Sep 17 00:00:00 2001 From: Cloudburst <18114966+C10udburst@users.noreply.github.com> Date: Sat, 24 Dec 2022 20:30:01 +0100 Subject: [PATCH 07/12] fix @Blatzar and change type --- SkillShareProvider/build.gradle.kts | 4 ++-- .../src/main/kotlin/com/lagradost/SkillShareProvider.kt | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/SkillShareProvider/build.gradle.kts b/SkillShareProvider/build.gradle.kts index c808ff8..2d2845f 100644 --- a/SkillShareProvider/build.gradle.kts +++ b/SkillShareProvider/build.gradle.kts @@ -1,5 +1,5 @@ // use an integer for version numbers -version = 1 +version = 2 cloudstream { @@ -18,7 +18,7 @@ cloudstream { * */ status = 1 // will be 3 if unspecified tvTypes = listOf( - "TvSeries", + "Others", ) iconUrl = "https://www.google.com/s2/favicons?domain=skillshare.com&sz=%size%" diff --git a/SkillShareProvider/src/main/kotlin/com/lagradost/SkillShareProvider.kt b/SkillShareProvider/src/main/kotlin/com/lagradost/SkillShareProvider.kt index 3192eb4..012b4ba 100644 --- a/SkillShareProvider/src/main/kotlin/com/lagradost/SkillShareProvider.kt +++ b/SkillShareProvider/src/main/kotlin/com/lagradost/SkillShareProvider.kt @@ -20,7 +20,7 @@ class SkillShareProvider : MainAPI() { // all providers must be an instance of M private val apiUrl = "https://www.skillshare.com/api/graphql" private val bypassApiUrl = "https://skillshare-api.heckernohecking.repl.co" - override val supportedTypes = setOf(TvType.TvSeries) + override val supportedTypes = setOf(TvType.Others) override val hasChromecastSupport = true override var lang = "en" override val hasMainPage = true @@ -141,7 +141,7 @@ class SkillShareProvider : MainAPI() { // all providers must be an instance of M } - override suspend fun load(url: String): LoadResponse { + override suspend fun load(url: String): LoadResponse? { val data = parseJson(url) val document = app.get(bypassApiUrl + "/${data.courseId}/0") .parsedSafe() ?: throw ErrorLoadingException("Invalid Json Response") @@ -151,7 +151,7 @@ class SkillShareProvider : MainAPI() { // all providers must be an instance of M Episode(episode.url ?: "", episode.title, 1, index) } - return newTvSeriesLoadResponse(title, data.courseId, TvType.TvSeries, episodeList) { + return newTvSeriesLoadResponse(title, data.courseId ?: return null, TvType.TvSeries, episodeList) { addPoster(poster) } } From fffb56ca4dabf16d6f30c60ff643691e7be5f4ec Mon Sep 17 00:00:00 2001 From: contusionglory <102427829+contusionglory@users.noreply.github.com> Date: Mon, 26 Dec 2022 11:26:34 +0000 Subject: [PATCH 08/12] Fix to load (#72) --- .../src/main/kotlin/com/lagradost/SkillShareProvider.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SkillShareProvider/src/main/kotlin/com/lagradost/SkillShareProvider.kt b/SkillShareProvider/src/main/kotlin/com/lagradost/SkillShareProvider.kt index 012b4ba..6639626 100644 --- a/SkillShareProvider/src/main/kotlin/com/lagradost/SkillShareProvider.kt +++ b/SkillShareProvider/src/main/kotlin/com/lagradost/SkillShareProvider.kt @@ -151,7 +151,7 @@ class SkillShareProvider : MainAPI() { // all providers must be an instance of M Episode(episode.url ?: "", episode.title, 1, index) } - return newTvSeriesLoadResponse(title, data.courseId ?: return null, TvType.TvSeries, episodeList) { + return newTvSeriesLoadResponse(title, url, TvType.TvSeries, episodeList) { addPoster(poster) } } From f26c659cf25ad23b9b235216be90a8ed5f051af6 Mon Sep 17 00:00:00 2001 From: contusionglory <102427829+contusionglory@users.noreply.github.com> Date: Mon, 26 Dec 2022 11:29:57 +0000 Subject: [PATCH 09/12] Up the version (#73) --- SkillShareProvider/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SkillShareProvider/build.gradle.kts b/SkillShareProvider/build.gradle.kts index 2d2845f..0f1c47f 100644 --- a/SkillShareProvider/build.gradle.kts +++ b/SkillShareProvider/build.gradle.kts @@ -1,5 +1,5 @@ // use an integer for version numbers -version = 2 +version = 3 cloudstream { From 23f0ee0c8d7c847043541bcbeed8ef627e9f9a10 Mon Sep 17 00:00:00 2001 From: TECHTANIC Date: Fri, 30 Dec 2022 09:30:30 +0100 Subject: [PATCH 10/12] SkillShare Provider Faster Bypass (#74) * Faster Bypass * bump Co-authored-by: Cloudburst <18114966+C10udburst@users.noreply.github.com> --- SkillShareProvider/build.gradle.kts | 2 +- .../src/main/kotlin/com/lagradost/SkillShareProvider.kt | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/SkillShareProvider/build.gradle.kts b/SkillShareProvider/build.gradle.kts index 0f1c47f..89efcca 100644 --- a/SkillShareProvider/build.gradle.kts +++ b/SkillShareProvider/build.gradle.kts @@ -1,5 +1,5 @@ // use an integer for version numbers -version = 3 +version = 4 cloudstream { diff --git a/SkillShareProvider/src/main/kotlin/com/lagradost/SkillShareProvider.kt b/SkillShareProvider/src/main/kotlin/com/lagradost/SkillShareProvider.kt index 6639626..598e1c8 100644 --- a/SkillShareProvider/src/main/kotlin/com/lagradost/SkillShareProvider.kt +++ b/SkillShareProvider/src/main/kotlin/com/lagradost/SkillShareProvider.kt @@ -18,7 +18,7 @@ class SkillShareProvider : MainAPI() { // all providers must be an instance of M override var name = "SkillShare" private val apiUrl = "https://www.skillshare.com/api/graphql" - private val bypassApiUrl = "https://skillshare-api.heckernohecking.repl.co" + private val bypassApiUrl = "https://skillshare.techtanic.xyz/id" override val supportedTypes = setOf(TvType.Others) override val hasChromecastSupport = true @@ -143,7 +143,7 @@ class SkillShareProvider : MainAPI() { // all providers must be an instance of M override suspend fun load(url: String): LoadResponse? { val data = parseJson(url) - val document = app.get(bypassApiUrl + "/${data.courseId}/0") + val document = app.get(bypassApiUrl + "/${data.courseId}") .parsedSafe() ?: throw ErrorLoadingException("Invalid Json Response") val title = data.title ?: "" val poster = data.largeCoverUrl From a4bdb2caba2482afa785d649f1d0c039a215c149 Mon Sep 17 00:00:00 2001 From: Cloudburst <18114966+C10udburst@users.noreply.github.com> Date: Fri, 30 Dec 2022 11:29:57 +0100 Subject: [PATCH 11/12] skill(share) issue: add fallback --- SkillShareProvider/build.gradle.kts | 2 +- .../src/main/kotlin/com/lagradost/SkillShareProvider.kt | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/SkillShareProvider/build.gradle.kts b/SkillShareProvider/build.gradle.kts index 89efcca..7243cae 100644 --- a/SkillShareProvider/build.gradle.kts +++ b/SkillShareProvider/build.gradle.kts @@ -1,5 +1,5 @@ // use an integer for version numbers -version = 4 +version = 5 cloudstream { diff --git a/SkillShareProvider/src/main/kotlin/com/lagradost/SkillShareProvider.kt b/SkillShareProvider/src/main/kotlin/com/lagradost/SkillShareProvider.kt index 598e1c8..d9026eb 100644 --- a/SkillShareProvider/src/main/kotlin/com/lagradost/SkillShareProvider.kt +++ b/SkillShareProvider/src/main/kotlin/com/lagradost/SkillShareProvider.kt @@ -19,6 +19,7 @@ class SkillShareProvider : MainAPI() { // all providers must be an instance of M private val apiUrl = "https://www.skillshare.com/api/graphql" private val bypassApiUrl = "https://skillshare.techtanic.xyz/id" + private val bypassApiUrlFallback = "https://skillshare-api.heckernohecking.repl.co" override val supportedTypes = setOf(TvType.Others) override val hasChromecastSupport = true @@ -144,6 +145,7 @@ class SkillShareProvider : MainAPI() { // all providers must be an instance of M override suspend fun load(url: String): LoadResponse? { val data = parseJson(url) val document = app.get(bypassApiUrl + "/${data.courseId}") + .parsedSafe() ?: app.get(bypassApiUrlFallback + "/${data.courseId}/0") .parsedSafe() ?: throw ErrorLoadingException("Invalid Json Response") val title = data.title ?: "" val poster = data.largeCoverUrl From e9ff7909ff365028c5336303ed97d32662aaad72 Mon Sep 17 00:00:00 2001 From: Cloudburst <18114966+C10udburst@users.noreply.github.com> Date: Fri, 6 Jan 2023 11:03:50 +0100 Subject: [PATCH 12/12] tantifilm url --- TantiFilmProvider/build.gradle.kts | 4 ++-- .../src/main/kotlin/com/lagradost/TantiFilmProvider.kt | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/TantiFilmProvider/build.gradle.kts b/TantiFilmProvider/build.gradle.kts index 8e8c2f1..b4f799f 100644 --- a/TantiFilmProvider/build.gradle.kts +++ b/TantiFilmProvider/build.gradle.kts @@ -1,5 +1,5 @@ // use an integer for version numbers -version = 3 +version = 4 cloudstream { @@ -23,5 +23,5 @@ cloudstream { ) - iconUrl = "https://www.google.com/s2/favicons?domain=tantifilm.yachts&sz=%size%" + iconUrl = "https://www.google.com/s2/favicons?domain=tantifilm.mobi&sz=%size%" } \ No newline at end of file diff --git a/TantiFilmProvider/src/main/kotlin/com/lagradost/TantiFilmProvider.kt b/TantiFilmProvider/src/main/kotlin/com/lagradost/TantiFilmProvider.kt index 7b8fbf9..ec350a6 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.delivery" + override var mainUrl = "https://tantifilm.mobi" override var name = "Tantifilm" override val hasMainPage = true override val hasChromecastSupport = true