diff --git a/EurostreamingProvider/build.gradle.kts b/EurostreamingProvider/build.gradle.kts index 9defcbe..e977bcf 100644 --- a/EurostreamingProvider/build.gradle.kts +++ b/EurostreamingProvider/build.gradle.kts @@ -1,7 +1,6 @@ // use an integer for version numbers version = 2 - cloudstream { language = "it" // All of these properties are optional, you can safely remove them @@ -23,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/EurostreamingProvider/src/main/kotlin/com/lagradost/EurostreamingProvider.kt b/EurostreamingProvider/src/main/kotlin/com/lagradost/EurostreamingProvider.kt index 9d41cdd..ef507c0 100644 --- a/EurostreamingProvider/src/main/kotlin/com/lagradost/EurostreamingProvider.kt +++ b/EurostreamingProvider/src/main/kotlin/com/lagradost/EurostreamingProvider.kt @@ -5,7 +5,9 @@ import com.lagradost.cloudstream3.utils.ExtractorLink import com.lagradost.cloudstream3.utils.loadExtractor import com.lagradost.cloudstream3.utils.AppUtils.parseJson import com.lagradost.cloudstream3.utils.AppUtils.toJson - +import com.lagradost.cloudstream3.network.CloudflareKiller +import okhttp3.FormBody +import org.jsoup.nodes.Element class EurostreamingProvider : MainAPI() { override var lang = "it" @@ -13,62 +15,58 @@ class EurostreamingProvider : MainAPI() { override var name = "Eurostreaming" override val hasMainPage = true override val hasChromecastSupport = true + private val interceptor = CloudflareKiller() override val supportedTypes = setOf( TvType.TvSeries ) override val mainPage = mainPageOf( - Pair("$mainUrl/serie-tv-archive/page/", "Ultime serie Tv"), - Pair("$mainUrl/animazione/page/", "Ultime serie Animazione"), - + "$mainUrl/serie-tv-archive/page/" to "Ultime serie Tv", + "$mainUrl/animazione/page/" to "Ultime serie Animazione", ) 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.post-thumb").map { - val title = it.selectFirst("img")!!.attr("alt") - val link = it.selectFirst("a")!!.attr("href") - val image = fixUrl(it.selectFirst("img")!!.attr("src")) - - MovieSearchResponse( - title, - link, - this.name, - TvType.Movie, - image - ) + val soup = app.get(url, interceptor = interceptor).document + val home = soup.select("div.post-thumb").mapNotNull { + it.toSearchResult() + } + return newHomePageResponse(arrayListOf(HomePageList(request.name, home)), hasNext = true) + } + + private fun Element.toSearchResult(): SearchResponse? { + val title = this.selectFirst("a")?.attr("title") ?: return null + val link = this.selectFirst("a")?.attr("href") ?: return null + val image = fixUrlNull(mainUrl + this.selectFirst("img")?.attr("src")?.trim()) + + return newTvSeriesSearchResponse(title, link, TvType.TvSeries){ + this.posterUrl = image + this.posterHeaders = interceptor.getCookieHeaders(mainUrl).toMap() } - return newHomePageResponse(request.name, home) } override suspend fun search(query: String): List { - val doc = app.post( - "$mainUrl/index.php", data = mapOf( - "do" to "search", - "subaction" to "search", - "story" to query, - "sortby" to "news_read" - ) - ).document - return doc.select("div.post-thumb").map { - val title = it.selectFirst("img")!!.attr("alt") - val link = it.selectFirst("a")!!.attr("href") - val image = mainUrl + it.selectFirst("img")!!.attr("src") + val body = FormBody.Builder() + .addEncoded("do", "search") + .addEncoded("subaction", "search") + .addEncoded("story", query) + .addEncoded("sortby", "news_read") + .build() - MovieSearchResponse( - title, - link, - this.name, - TvType.Movie, - image - ) + val doc = app.post( + "$mainUrl/index.php", + requestBody = body, + interceptor = interceptor + ).document + + return doc.select("div.post-thumb").mapNotNull { + it?.toSearchResult() } } override suspend fun load(url: String): LoadResponse { - val page = app.get(url) + val page = app.get(url, interceptor = interceptor) val document = page.document val title = document.selectFirst("h2")!!.text().replace("^([1-9+]]$","") val style = document.selectFirst("div.entry-cover")!!.attr("style") @@ -93,7 +91,8 @@ class EurostreamingProvider : MainAPI() { } } return newTvSeriesLoadResponse(title, url, TvType.TvSeries, episodeList) { - posterUrl = poster + this.posterUrl = poster + this.posterHeaders = interceptor.getCookieHeaders(mainUrl).toMap() } } diff --git a/NineGoalProvider/build.gradle.kts b/NineGoalProvider/build.gradle.kts new file mode 100644 index 0000000..bd90dd4 --- /dev/null +++ b/NineGoalProvider/build.gradle.kts @@ -0,0 +1,12 @@ +version = 3 + +cloudstream { + description = "" + authors = listOf( "ImZaw" ) + + status = 1 + + tvTypes = listOf( "Live" ) + + iconUrl = "https://media.discordapp.net/attachments/1027568249900109875/1046110428402561025/JK8J1KX.png?width=%size%&height=%size%" +} diff --git a/NineGoalProvider/src/main/AndroidManifest.xml b/NineGoalProvider/src/main/AndroidManifest.xml new file mode 100644 index 0000000..263556b --- /dev/null +++ b/NineGoalProvider/src/main/AndroidManifest.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/NineGoalProvider/src/main/kotlin/com/ninegoal/9GoalPlugin.kt b/NineGoalProvider/src/main/kotlin/com/ninegoal/9GoalPlugin.kt new file mode 100644 index 0000000..c9a5e9e --- /dev/null +++ b/NineGoalProvider/src/main/kotlin/com/ninegoal/9GoalPlugin.kt @@ -0,0 +1,12 @@ +package com.ninegoal + +import com.lagradost.cloudstream3.plugins.CloudstreamPlugin +import com.lagradost.cloudstream3.plugins.Plugin +import android.content.Context + +@CloudstreamPlugin +class NineGoalPlugin: Plugin() { + override fun load(context: Context) { + registerMainAPI(NineGoal()) + } +} \ No newline at end of file diff --git a/NineGoalProvider/src/main/kotlin/com/ninegoal/9GoalProvider.kt b/NineGoalProvider/src/main/kotlin/com/ninegoal/9GoalProvider.kt new file mode 100644 index 0000000..77e190d --- /dev/null +++ b/NineGoalProvider/src/main/kotlin/com/ninegoal/9GoalProvider.kt @@ -0,0 +1,153 @@ +package com.ninegoal + +import com.lagradost.cloudstream3.* +import com.lagradost.cloudstream3.utils.ExtractorLink +import com.fasterxml.jackson.annotation.JsonProperty +import com.lagradost.cloudstream3.utils.AppUtils.parseJson +import com.lagradost.cloudstream3.utils.Qualities +import java.util.* + +data class Data ( + @JsonProperty("id" ) var id : String? = null, + @JsonProperty("name" ) var name : String? = null, + @JsonProperty("slug" ) var slug : String? = null, + @JsonProperty("home" ) var home : Home? = Home(), + @JsonProperty("away" ) var away : Away? = Away(), + @JsonProperty("scores" ) var scores : Scores? = Scores(), + @JsonProperty("is_live" ) var isLive : Boolean? = null +) +data class Home ( + @JsonProperty("model_id" ) var modelId : String? = null, + @JsonProperty("name" ) var name : String? = null, + @JsonProperty("slug" ) var slug : String? = null, + @JsonProperty("logo" ) var logo : String? = null +) +data class Away ( + @JsonProperty("model_id" ) var modelId : String? = null, + @JsonProperty("name" ) var name : String? = null, + @JsonProperty("slug" ) var slug : String? = null, + @JsonProperty("logo" ) var logo : String? = null +) +data class Scores ( + @JsonProperty("home" ) var home : Int? = null, + @JsonProperty("away" ) var away : Int? = null +) +data class matchesJSON ( + @JsonProperty("data" ) var data : ArrayList = arrayListOf() +) +data class oneMatch ( + @JsonProperty("data" ) var data : Data? = Data() +) + + +data class PlayUrls ( + @JsonProperty("name" ) var name : String? = null, + @JsonProperty("cdn" ) var cdn : String? = null, + @JsonProperty("slug" ) var slug : String? = null, + @JsonProperty("url" ) var url : String? = null, + @JsonProperty("role" ) var role : String? = null +) +data class sourceData ( + @JsonProperty("id" ) var id : String? = null, + @JsonProperty("name" ) var name : String? = null, + @JsonProperty("slug" ) var slug : String? = null, + @JsonProperty("has_lineup" ) var hasLineup : Boolean? = null, + @JsonProperty("has_tracker" ) var hasTracker : Boolean? = null, + @JsonProperty("play_urls" ) var playUrls : ArrayList = arrayListOf() +) +data class sourcesJSON ( + @JsonProperty("data" ) var data : sourceData? = sourceData() +) +class NineGoal : MainAPI() { + override var mainUrl = "https://9goaltv.to" + override var name = "9Goal" + override var lang = "en" + override val hasDownloadSupport = false + override val hasMainPage = true + override val supportedTypes = setOf( + TvType.Live + ) + + override suspend fun getMainPage(page: Int, request : MainPageRequest): HomePageResponse { + val doc = app.get(mainUrl).document + val apiUrl = doc.select("head > script").first()?.html()?.substringAfter("window.api_base_url = \"")?.substringBefore("\";") + val matchesData = parseJson(app.get("$apiUrl/v1/match/featured").text) + val liveHomePageList = matchesData.data.filter { it.isLive == true }.map { + LiveSearchResponse( + it.name.toString(), + apiUrl + "/v1/match/" + it.id, + this@NineGoal.name, + TvType.Live, + "https://img.zr5.repl.co/vs?title=${it.name}&home=${it.home?.logo}&away=${it.away?.logo}&live=true", + ) + } + val featuredHomePageList = matchesData.data.filter { it.isLive == false }.map { + LiveSearchResponse( + it.name.toString(), + apiUrl + "/v1/match/" + it.id, + this@NineGoal.name, + TvType.Live, + "https://img.zr5.repl.co/vs?title=${it.name}&home=${it.home?.logo}&away=${it.away?.logo}", + ) + } + return HomePageResponse( + arrayListOf( + HomePageList("Live", liveHomePageList, isHorizontalImages = true), + HomePageList("Featured", featuredHomePageList, isHorizontalImages = true) + ) + ) + } + + override suspend fun load(url: String): LoadResponse { + val json = parseJson(app.get(url).text).data + return LiveStreamLoadResponse( + json?.name.toString(), + url, + this.name, + "$url/stream", + ) + } + override suspend fun loadLinks( + data: String, + isCasting: Boolean, + subtitleCallback: (SubtitleFile) -> Unit, + callback: (ExtractorLink) -> Unit + ): Boolean { + val sourcesData = parseJson(app.get(data).text).data + sourcesData?.playUrls?.apmap { + val brokenDomain = "canyou.letmestreamyou.net" + if(it.url.toString().startsWith("https://$brokenDomain")) { + mapOf( + "smoothlikebutterstream" to "playing.smoothlikebutterstream.com", + "tunnelcdnsw" to "playing.tunnelcdnsw.net", + "goforfreedomwme" to "playing.goforfreedomwme.net", + "gameon" to "turnthe.gameon.tel", + "whydontyoustreamwme" to "playing.whydontyoustreamwme.com" + ).apmap { (name, value) -> + callback.invoke( + ExtractorLink( + this.name, + "${this.name} ${it.name} - ${name}", + it.url.toString().replace(brokenDomain, value), + "$mainUrl/", + Qualities.Unknown.value, + isM3u8 = true, + ) + ) + } + } else { + callback.invoke( + ExtractorLink( + this.name, + "${this.name} ${it.name} - ${sourcesData.name}", + it.url.toString(), + "$mainUrl/", + Qualities.Unknown.value, + isM3u8 = true, + ) + ) + } + } + return true + } +}