diff --git a/AltadefinizioneProvider/build.gradle.kts b/AltadefinizioneProvider/build.gradle.kts index ed63616..4d19548 100644 --- a/AltadefinizioneProvider/build.gradle.kts +++ b/AltadefinizioneProvider/build.gradle.kts @@ -1,5 +1,5 @@ // use an integer for version numbers -version = 3 +version = 2 cloudstream { diff --git a/AltadefinizioneProvider/src/main/kotlin/com/lagradost/AltadefinizioneProvider.kt b/AltadefinizioneProvider/src/main/kotlin/com/lagradost/AltadefinizioneProvider.kt index ed64c13..9f03630 100644 --- a/AltadefinizioneProvider/src/main/kotlin/com/lagradost/AltadefinizioneProvider.kt +++ b/AltadefinizioneProvider/src/main/kotlin/com/lagradost/AltadefinizioneProvider.kt @@ -9,7 +9,7 @@ import com.lagradost.cloudstream3.utils.AppUtils.html class AltadefinizioneProvider : MainAPI() { override var lang = "it" - override var mainUrl = "https://altadefinizione.camera" + override var mainUrl = "https://altadefinizione.audio" override var name = "Altadefinizione" override val hasMainPage = true override val hasChromecastSupport = true diff --git a/EurostreamingProvider/build.gradle.kts b/EurostreamingProvider/build.gradle.kts index 62f8d76..9defcbe 100644 --- a/EurostreamingProvider/build.gradle.kts +++ b/EurostreamingProvider/build.gradle.kts @@ -1,5 +1,5 @@ // use an integer for version numbers -version = 1 +version = 2 cloudstream { diff --git a/EurostreamingProvider/src/main/kotlin/com/lagradost/EurostreamingProvider.kt b/EurostreamingProvider/src/main/kotlin/com/lagradost/EurostreamingProvider.kt index ec81f4e..9d41cdd 100644 --- a/EurostreamingProvider/src/main/kotlin/com/lagradost/EurostreamingProvider.kt +++ b/EurostreamingProvider/src/main/kotlin/com/lagradost/EurostreamingProvider.kt @@ -9,7 +9,7 @@ import com.lagradost.cloudstream3.utils.AppUtils.toJson class EurostreamingProvider : MainAPI() { override var lang = "it" - override var mainUrl = "https://eurostreaming.social" + override var mainUrl = "https://eurostreaming.taxi" override var name = "Eurostreaming" override val hasMainPage = true override val hasChromecastSupport = true diff --git a/FilmpertuttiProvider/src/main/kotlin/com/lagradost/FilmpertuttiProvider.kt b/FilmpertuttiProvider/src/main/kotlin/com/lagradost/FilmpertuttiProvider.kt index d1fd283..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.hair" + override var mainUrl = "https://filmpertutti.skin" override var name = "FilmPerTutti" override val hasMainPage = true override val hasChromecastSupport = true diff --git a/SoraItalianStream/build.gradle.kts b/SoraItalianStream/build.gradle.kts new file mode 100644 index 0000000..26a021a --- /dev/null +++ b/SoraItalianStream/build.gradle.kts @@ -0,0 +1,29 @@ +// use an integer for version numbers +version = 1 + + +cloudstream { + language = "es" + // 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/AndroidManifest.xml b/SoraItalianStream/src/AndroidManifest.xml new file mode 100644 index 0000000..0474547 --- /dev/null +++ b/SoraItalianStream/src/AndroidManifest.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/SoraItalianStream/src/kotlin/SoraItalianExtractor.kt b/SoraItalianStream/src/kotlin/SoraItalianExtractor.kt new file mode 100644 index 0000000..6938eaf --- /dev/null +++ b/SoraItalianStream/src/kotlin/SoraItalianExtractor.kt @@ -0,0 +1,403 @@ +package com.lagradost + +import com.lagradost.AniPlayProvider +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/kotlin/SoraItalianStream.kt b/SoraItalianStream/src/kotlin/SoraItalianStream.kt new file mode 100644 index 0000000..f5dd982 --- /dev/null +++ b/SoraItalianStream/src/kotlin/SoraItalianStream.kt @@ -0,0 +1,511 @@ +package com.lagradost + +import com.fasterxml.jackson.annotation.JsonProperty +import com.lagradost.SoraItalian.SoraItalianExtractor.invoGuardare +import com.lagradost.cloudstream3.* +import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer +import com.lagradost.cloudstream3.metaproviders.TmdbProvider +import com.lagradost.SoraItalian.SoraItalianExtractor.invoAltadefinizione +import com.lagradost.SoraItalian.SoraItalianExtractor.invoAniPlay +import com.lagradost.SoraItalian.SoraItalianExtractor.invoAnimeSaturn +import com.lagradost.SoraItalian.SoraItalianExtractor.invoAnimeWorld +import com.lagradost.SoraItalian.SoraItalianExtractor.invoCb01 +import com.lagradost.SoraItalian.SoraItalianExtractor.invoFilmpertutti +import com.lagradost.SoraItalian.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/kotlin/SoraItalianStreamPlugin.kt b/SoraItalianStream/src/kotlin/SoraItalianStreamPlugin.kt new file mode 100644 index 0000000..59ca414 --- /dev/null +++ b/SoraItalianStream/src/kotlin/SoraItalianStreamPlugin.kt @@ -0,0 +1,13 @@ +package com.hexated + +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/src/main/kotlin/com/lagradost/StreamingcommunityProvider.kt b/StreamingcommunityProvider/src/main/kotlin/com/lagradost/StreamingcommunityProvider.kt index 9c38e19..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.help" + override var mainUrl = "https://streamingcommunity.cheap" override var name = "StreamingCommunity" override val hasMainPage = true override val hasChromecastSupport = true diff --git a/TantiFilmProvider/src/main/kotlin/com/lagradost/TantiFilmProvider.kt b/TantiFilmProvider/src/main/kotlin/com/lagradost/TantiFilmProvider.kt index 500b1c8..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.tattoo" + override var mainUrl = "https://tantifilm.delivery" override var name = "Tantifilm" override val hasMainPage = true override val hasChromecastSupport = true