diff --git a/Anichi/build.gradle.kts b/Anichi/build.gradle.kts index 1a2f6d64..dcc2cb7b 100644 --- a/Anichi/build.gradle.kts +++ b/Anichi/build.gradle.kts @@ -1,7 +1,7 @@ import org.jetbrains.kotlin.konan.properties.Properties // use an integer for version numbers -version = 6 +version = 7 android { defaultConfig { diff --git a/Anichi/src/main/kotlin/com/hexated/AnichiExtractors.kt b/Anichi/src/main/kotlin/com/hexated/AnichiExtractors.kt index 5fe9ab9f..d5811278 100644 --- a/Anichi/src/main/kotlin/com/hexated/AnichiExtractors.kt +++ b/Anichi/src/main/kotlin/com/hexated/AnichiExtractors.kt @@ -6,6 +6,8 @@ import com.lagradost.cloudstream3.app import com.lagradost.cloudstream3.argamap import com.lagradost.cloudstream3.extractors.helper.GogoHelper import com.lagradost.cloudstream3.mvvm.safeApiCall +import com.lagradost.cloudstream3.utils.AppUtils +import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson import com.lagradost.cloudstream3.utils.ExtractorLink import com.lagradost.cloudstream3.utils.Qualities import com.lagradost.cloudstream3.utils.SubtitleHelper @@ -146,20 +148,19 @@ object AnichiExtractors : Anichi() { ), referer = "$marinHost/anime", ).cookies.let { - it["XSRF-TOKEN"] to it["marin_session"] + decode(it["XSRF-TOKEN"].toString()) to decode(it["marin_session"].toString()) } - app.get( + val json = app.get( url, headers = mapOf( - "Referer" to "$marinHost/", - "Cookie" to "__ddg1=;__ddg2_=; XSRF-TOKEN=${cookies.first}; marin_session=${cookies.second};", - "x-inertia" to "true", - "x-inertia-version" to "5ee7503af8c9844b1e8d34466b727694", - "X-Requested-With" to "XMLHttpRequest", - "X-XSRF-TOKEN" to decode(cookies.first.toString()) - ) - ).parsedSafe()?.props?.video?.data?.mirror?.map { video -> + "Accept" to "text/html, application/xhtml+xml", + "Cookie" to "__ddg1=;__ddg2_=;XSRF-TOKEN=${cookies.first};marin_session=${cookies.second};", + "X-XSRF-TOKEN" to cookies.first + ), + referer = "$marinHost/anime/$id" + ).document.selectFirst("div#app")?.attr("data-page") + tryParseJson(json)?.props?.video?.data?.mirror?.map { video -> callback.invoke( ExtractorLink( "Marin", diff --git a/Anichi/src/main/kotlin/com/hexated/AnichiUtils.kt b/Anichi/src/main/kotlin/com/hexated/AnichiUtils.kt index 0656e2d2..2c34e9f7 100644 --- a/Anichi/src/main/kotlin/com/hexated/AnichiUtils.kt +++ b/Anichi/src/main/kotlin/com/hexated/AnichiUtils.kt @@ -87,6 +87,7 @@ private val embedBlackList = listOf( "https://videobin.co/", "https://ok.ru", "https://streamlare.com", + "https://filemoon", "streaming.php", ) diff --git a/AnimeIndoProvider/build.gradle.kts b/AnimeIndoProvider/build.gradle.kts index 1b1a9869..297bbcc1 100644 --- a/AnimeIndoProvider/build.gradle.kts +++ b/AnimeIndoProvider/build.gradle.kts @@ -1,5 +1,5 @@ // use an integer for version numbers -version = 10 +version = 11 cloudstream { diff --git a/AnimeIndoProvider/src/main/kotlin/com/hexated/AnimeIndoProvider.kt b/AnimeIndoProvider/src/main/kotlin/com/hexated/AnimeIndoProvider.kt index 4c40ad78..b518016b 100644 --- a/AnimeIndoProvider/src/main/kotlin/com/hexated/AnimeIndoProvider.kt +++ b/AnimeIndoProvider/src/main/kotlin/com/hexated/AnimeIndoProvider.kt @@ -13,7 +13,6 @@ class AnimeIndoProvider : MainAPI() { override var name = "AnimeIndo" override val hasMainPage = true override var lang = "id" - override val hasDownloadSupport = true override val supportedTypes = setOf( TvType.Anime, @@ -39,18 +38,19 @@ class AnimeIndoProvider : MainAPI() { } override val mainPage = mainPageOf( - "$mainUrl/anime-terbaru/page/" to "Anime Terbaru", - "$mainUrl/ongoing/page/" to "Anime Ongoing", - "$mainUrl/populer/page/" to "Anime Populer", - "$mainUrl/donghua-terbaru/page/" to "Donghua Terbaru", + "episode-terbaru" to "Episode Terbaru", + "ongoing" to "Anime Ongoing", + "populer" to "Anime Populer", + "donghua-terbaru" to "Donghua Terbaru", ) override suspend fun getMainPage( page: Int, request: MainPageRequest ): HomePageResponse { - val document = app.get(request.data + page).document - val home = document.select("div.post-show > article, div.relat > article").mapNotNull { + val url = "$mainUrl/pages/${request.data}/page/$page" + val document = app.get(url).document + val home = document.select("main#main div.animposx").mapNotNull { it.toSearchResult() } return newHomePageResponse(request.name, home) @@ -60,7 +60,7 @@ class AnimeIndoProvider : MainAPI() { return if (uri.contains("/anime/")) { uri } else { - var title = uri.substringAfter("$mainUrl/") + var title = uri.substringAfter("nonton/") title = when { (title.contains("-episode")) && !(title.contains("-movie")) -> Regex("(.+)-episode").find( title @@ -74,15 +74,13 @@ class AnimeIndoProvider : MainAPI() { } } - private fun Element.toSearchResult(): AnimeSearchResponse? { - val title = this.selectFirst("div.title")?.text()?.trim() ?: return null + private fun Element.toSearchResult(): AnimeSearchResponse { + val title = this.selectFirst("div.titlex, h2.entry-title, h4")?.text()?.trim() ?: "" val href = getProperAnimeLink(this.selectFirst("a")!!.attr("href")) - val posterUrl = this.select("img[itemprop=image]").attr("src").toString() - val type = getType(this.select("div.type").text().trim()) - val epNum = - this.selectFirst("span.episode")?.ownText()?.replace(Regex("\\D"), "")?.trim() - ?.toIntOrNull() - return newAnimeSearchResponse(title, href, type) { + val posterUrl = fixUrlNull(this.selectFirst("img")?.attr("src")) + val epNum = this.selectFirst("span.episode")?.ownText()?.replace(Regex("\\D"), "")?.trim() + ?.toIntOrNull() + return newAnimeSearchResponse(title, href, TvType.Anime) { this.posterUrl = posterUrl addSub(epNum) } @@ -131,6 +129,10 @@ class AnimeIndoProvider : MainAPI() { Episode(link, header.text(), episode = episode) }.reversed() + val recommendations = document.select("div.relat div.animposx").mapNotNull { + it.toSearchResult() + } + return newAnimeLoadResponse(title, url, getType(type)) { engName = title posterUrl = poster @@ -139,6 +141,7 @@ class AnimeIndoProvider : MainAPI() { showStatus = status plot = description this.tags = tags + this.recommendations = recommendations addTrailer(trailer) } } diff --git a/DramaidProvider/build.gradle.kts b/DramaidProvider/build.gradle.kts index 42fd4171..a1beeb4d 100644 --- a/DramaidProvider/build.gradle.kts +++ b/DramaidProvider/build.gradle.kts @@ -1,12 +1,12 @@ // use an integer for version numbers -version = 6 +version = 8 cloudstream { language = "id" // All of these properties are optional, you can safely remove them - // description = "Lorem Ipsum" + description = "Include: Oppadrama" authors = listOf("Hexated") /** diff --git a/DramaidProvider/src/main/kotlin/com/hexated/DramaidProvider.kt b/DramaidProvider/src/main/kotlin/com/hexated/DramaidProvider.kt index d1e90376..ab50f5b4 100644 --- a/DramaidProvider/src/main/kotlin/com/hexated/DramaidProvider.kt +++ b/DramaidProvider/src/main/kotlin/com/hexated/DramaidProvider.kt @@ -3,6 +3,7 @@ package com.hexated import com.fasterxml.jackson.annotation.JsonProperty import com.lagradost.cloudstream3.* import com.lagradost.cloudstream3.extractors.XStreamCdn +import com.lagradost.cloudstream3.utils.AppUtils import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson import com.lagradost.cloudstream3.utils.ExtractorLink import com.lagradost.cloudstream3.utils.getQualityFromName @@ -10,14 +11,11 @@ import com.lagradost.cloudstream3.utils.loadExtractor import org.jsoup.Jsoup import org.jsoup.nodes.Element -class DramaidProvider : MainAPI() { +open class DramaidProvider : MainAPI() { override var mainUrl = "https://dramaid.best" override var name = "DramaId" - override val hasQuickSearch = false override val hasMainPage = true override var lang = "id" - override val hasDownloadSupport = true - override val hasChromecastSupport = false override val supportedTypes = setOf(TvType.AsianDrama) companion object { @@ -28,6 +26,14 @@ class DramaidProvider : MainAPI() { else -> ShowStatus.Completed } } + + fun getType(t: String?): TvType { + return when { + t?.contains("Movie", true) == true -> TvType.Movie + t?.contains("Anime", true) == true -> TvType.Anime + else -> TvType.AsianDrama + } + } } override val mainPage = mainPageOf( @@ -45,18 +51,17 @@ class DramaidProvider : MainAPI() { } private fun getProperDramaLink(uri: String): String { - return if (uri.contains("/series/")) { - uri - } else { + return if (uri.contains("-episode-")) { "$mainUrl/series/" + Regex("$mainUrl/(.+)-ep.+").find(uri)?.groupValues?.get(1) - .toString() + } else { + uri } } private fun Element.toSearchResult(): SearchResponse? { val href = getProperDramaLink(this.selectFirst("a.tip")!!.attr("href")) val title = this.selectFirst("h2[itemprop=headline]")?.text()?.trim() ?: return null - val posterUrl = fixUrlNull(this.selectFirst(".limit > noscript > img")?.attr("src")) + val posterUrl = fixUrlNull(this.select("img:last-child").attr("src")) return newTvSeriesSearchResponse(title, href, TvType.AsianDrama) { this.posterUrl = posterUrl @@ -64,27 +69,19 @@ class DramaidProvider : MainAPI() { } override suspend fun search(query: String): List { - val link = "$mainUrl/?s=$query" - val document = app.get(link).document - - return document.select("article[itemscope=itemscope]").map { - val title = it.selectFirst("h2[itemprop=headline]")!!.text().trim() - val poster = it.selectFirst(".limit > noscript > img")!!.attr("src") - val href = it.selectFirst("a.tip")!!.attr("href") - - newTvSeriesSearchResponse(title, href, TvType.AsianDrama) { - this.posterUrl = poster - } + val document = app.get("$mainUrl/?s=$query").document + return document.select("article[itemscope=itemscope]").mapNotNull { + it.toSearchResult() } } override suspend fun load(url: String): LoadResponse { val document = app.get(url).document - val title = document.selectFirst("h1.entry-title")!!.text().trim() - val poster = document.select(".thumb > noscript > img").attr("src") + val title = document.selectFirst("h1.entry-title")?.text()?.trim() ?: "" + val poster = fixUrlNull(document.select("div.thumb img:last-child").attr("src")) val tags = document.select(".genxed > a").map { it.text() } - + val type = document.selectFirst(".info-content .spe span:contains(Tipe:)")?.ownText() val year = Regex("\\d, ([0-9]*)").find( document.selectFirst(".info-content > .spe > span > time")!!.text().trim() )?.groupValues?.get(1).toString().toIntOrNull() @@ -94,44 +91,34 @@ class DramaidProvider : MainAPI() { ) val description = document.select(".entry-content > p").text().trim() - val episodes = document.select(".eplister > ul > li").map { - val name = it.selectFirst("a > .epl-title")!!.text().trim() - val link = it.select("a").attr("href") - val epNum = it.selectFirst("a > .epl-num")!!.text().trim().toIntOrNull() - newEpisode(link) { - this.name = name - this.episode = epNum - } + val episodes = document.select(".eplister > ul > li").mapNotNull { + val name = it.selectFirst("a > .epl-title")?.text() + val link = fixUrl(it.selectFirst("a")?.attr("href") ?: return@mapNotNull null) + val epNum = it.selectFirst(".epl-num")?.text()?.toIntOrNull() + Episode( + link, + name, + episode = epNum + ) }.reversed() val recommendations = - document.select(".listupd > article[itemscope=itemscope]").map { rec -> - val epTitle = rec.selectFirst("h2[itemprop=headline]")!!.text().trim() - val epPoster = rec.selectFirst(".limit > noscript > img")!!.attr("src") - val epHref = fixUrl(rec.selectFirst("a.tip")!!.attr("href")) - - newTvSeriesSearchResponse(epTitle, epHref, TvType.AsianDrama) { - this.posterUrl = epPoster - } + document.select(".listupd > article[itemscope=itemscope]").mapNotNull { rec -> + rec.toSearchResult() } - if (episodes.size == 1) { - return newMovieLoadResponse(title, url, TvType.Movie, episodes[0].data) { - posterUrl = poster - this.year = year - plot = description - this.tags = tags - this.recommendations = recommendations - } - } else { - return newTvSeriesLoadResponse(title, url, TvType.AsianDrama, episodes = episodes) { - posterUrl = poster - this.year = year - showStatus = status - plot = description - this.tags = tags - this.recommendations = recommendations - } + return newTvSeriesLoadResponse( + title, + url, + getType(type), + episodes = episodes + ) { + posterUrl = poster + this.year = year + showStatus = status + plot = description + this.tags = tags + this.recommendations = recommendations } } @@ -203,12 +190,13 @@ class DramaidProvider : MainAPI() { it.replace("https://ndrama.xyz", "https://www.fembed.com") }.apmap { when { - it.contains("motonews.club") -> invokeDriveSource( + it.contains("motonews") -> invokeDriveSource( it, this.name, subtitleCallback, callback ) + else -> loadExtractor(it, data, subtitleCallback, callback) } } diff --git a/DramaidProvider/src/main/kotlin/com/hexated/DramaidProviderPlugin.kt b/DramaidProvider/src/main/kotlin/com/hexated/DramaidProviderPlugin.kt index 78c28ae2..bcf9ac4f 100644 --- a/DramaidProvider/src/main/kotlin/com/hexated/DramaidProviderPlugin.kt +++ b/DramaidProvider/src/main/kotlin/com/hexated/DramaidProviderPlugin.kt @@ -10,6 +10,7 @@ class DramaidProviderPlugin: Plugin() { override fun load(context: Context) { // All providers should be added in this manner. Please don't edit the providers list directly. registerMainAPI(DramaidProvider()) + registerMainAPI(Oppadrama()) registerExtractorAPI(Vanfem()) } } \ No newline at end of file diff --git a/DramaidProvider/src/main/kotlin/com/hexated/Oppadrama.kt b/DramaidProvider/src/main/kotlin/com/hexated/Oppadrama.kt new file mode 100644 index 00000000..44dcb365 --- /dev/null +++ b/DramaidProvider/src/main/kotlin/com/hexated/Oppadrama.kt @@ -0,0 +1,6 @@ +package com.hexated + +class Oppadrama : DramaidProvider() { + override var mainUrl = "http://185.217.95.34" + override var name = "Oppadrama" +} \ No newline at end of file diff --git a/Ngefilm/build.gradle.kts b/Gomov/build.gradle.kts similarity index 73% rename from Ngefilm/build.gradle.kts rename to Gomov/build.gradle.kts index 0903f827..326a8138 100644 --- a/Ngefilm/build.gradle.kts +++ b/Gomov/build.gradle.kts @@ -1,12 +1,12 @@ // use an integer for version numbers -version = 4 +version = 3 cloudstream { language = "id" // All of these properties are optional, you can safely remove them - // description = "Lorem Ipsum" + description = "Include: DutaMovie, Ngefilm, Nodrakorid" authors = listOf("Hexated") /** @@ -23,5 +23,5 @@ cloudstream { "Movie", ) - iconUrl = "https://www.google.com/s2/favicons?domain=ngefilm21.club&sz=%size%" + iconUrl = "https://www.google.com/s2/favicons?domain=gomov.bio&sz=%size%" } \ No newline at end of file diff --git a/Ngefilm/src/main/AndroidManifest.xml b/Gomov/src/main/AndroidManifest.xml similarity index 100% rename from Ngefilm/src/main/AndroidManifest.xml rename to Gomov/src/main/AndroidManifest.xml diff --git a/Gomov/src/main/kotlin/com/hexated/DutaMovie.kt b/Gomov/src/main/kotlin/com/hexated/DutaMovie.kt new file mode 100644 index 00000000..08bf2b87 --- /dev/null +++ b/Gomov/src/main/kotlin/com/hexated/DutaMovie.kt @@ -0,0 +1,37 @@ +package com.hexated + +import com.lagradost.cloudstream3.* +import com.lagradost.cloudstream3.utils.ExtractorLink +import com.lagradost.cloudstream3.utils.httpsify +import com.lagradost.cloudstream3.utils.loadExtractor + +open class DutaMovie : Gomov() { + override var mainUrl = "https://dutamovie21.live" + override var name = "DutaMovie" + + override val mainPage = mainPageOf( + "category/box-office/page/%d/" to "Box Office", + "category/serial-tv/page/%d/" to "Serial TV", + "category/animation/page/%d/" to "Animasi", + "country/korea/page/%d/" to "Serial TV Korea", + "country/indonesia/page/%d/" to "Serial TV Indonesia", + ) + + override suspend fun loadLinks( + data: String, + isCasting: Boolean, + subtitleCallback: (SubtitleFile) -> Unit, + callback: (ExtractorLink) -> Unit + ): Boolean { + + app.get(data).document.select("ul.muvipro-player-tabs li a").apmap { + val iframe = app.get(fixUrl(it.attr("href"))).document.selectFirst("div.gmr-embed-responsive iframe") + ?.attr("src") + loadExtractor(httpsify(iframe ?: return@apmap ), "$mainUrl/", subtitleCallback, callback) + } + + return true + } + + +} \ No newline at end of file diff --git a/Gomov/src/main/kotlin/com/hexated/Extractors.kt b/Gomov/src/main/kotlin/com/hexated/Extractors.kt new file mode 100644 index 00000000..25bd9f11 --- /dev/null +++ b/Gomov/src/main/kotlin/com/hexated/Extractors.kt @@ -0,0 +1,24 @@ +package com.hexated + +import com.lagradost.cloudstream3.extractors.Filesim +import com.lagradost.cloudstream3.extractors.Gdriveplayer +import com.lagradost.cloudstream3.extractors.StreamSB + +class Dutamovie21 : StreamSB() { + override var name = "Dutamovie21" + override var mainUrl = "https://dutamovie21.xyz" +} + +class Filelions : Filesim() { + override val name = "Filelions" + override var mainUrl = "https://filelions.to" +} + +class Likessb : StreamSB() { + override var name = "Likessb" + override var mainUrl = "https://likessb.com" +} + +class DbGdriveplayer : Gdriveplayer() { + override var mainUrl = "https://database.gdriveplayer.us" +} \ No newline at end of file diff --git a/Ngefilm/src/main/kotlin/com/hexated/Ngefilm.kt b/Gomov/src/main/kotlin/com/hexated/Gomov.kt similarity index 60% rename from Ngefilm/src/main/kotlin/com/hexated/Ngefilm.kt rename to Gomov/src/main/kotlin/com/hexated/Gomov.kt index 84a14d7d..36128fb2 100644 --- a/Ngefilm/src/main/kotlin/com/hexated/Ngefilm.kt +++ b/Gomov/src/main/kotlin/com/hexated/Gomov.kt @@ -4,15 +4,15 @@ import com.lagradost.cloudstream3.* import com.lagradost.cloudstream3.LoadResponse.Companion.addActors import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer import com.lagradost.cloudstream3.utils.ExtractorLink +import com.lagradost.cloudstream3.utils.httpsify import com.lagradost.cloudstream3.utils.loadExtractor import org.jsoup.nodes.Element -class Ngefilm : MainAPI() { - override var mainUrl = "https://ngefilm21.cfd" - override var name = "Ngefilm" +open class Gomov : MainAPI() { + override var mainUrl = "https://gomov.bio" + override var name = "Gomov" override val hasMainPage = true override var lang = "id" - override val hasDownloadSupport = true override val supportedTypes = setOf( TvType.Movie, TvType.TvSeries, @@ -20,39 +20,69 @@ class Ngefilm : MainAPI() { ) override val mainPage = mainPageOf( - "?s&search=advanced&post_type=movie&index&orderby&genre&movieyear&country&quality=" to "Movies Terbaru", - "?s=&search=advanced&post_type=tv&index=&orderby=&genre=&movieyear=&country=&quality=" to "Series Terbaru", - "?s=&search=advanced&post_type=tv&index=&orderby=&genre=drakor&movieyear=&country=&quality=" to "Series Korea", - "?s=&search=advanced&post_type=tv&index=&orderby=&genre=&movieyear=&country=indonesia&quality=" to "Series Indonesia", + "page/%d/?s&search=advanced&post_type=movie" to "Movies", + "category/western-series/page/%d/" to "Western Series", + "tv/page/%d/" to "Tv Shows", + "category/korean-series/page/%d/" to "Korean Series", + "category/chinese-series/page/%d/" to "Chinese Series", + "category/india-series/page/%d/" to "India Series", ) override suspend fun getMainPage( page: Int, request: MainPageRequest ): HomePageResponse { - val document = app.get("$mainUrl/page/$page/${request.data}").document - val home = document.select("main#main article").mapNotNull { + val data = request.data.format(page) + val document = app.get("$mainUrl/$data").document + val home = document.select("article.item").mapNotNull { it.toSearchResult() } return newHomePageResponse(request.name, home) } - override suspend fun search(query: String): List { - val link = "$mainUrl/?s=$query&post_type[]=post&post_type[]=tv" - val document = app.get(link).document - return document.select("main#main article").mapNotNull { - it.toSearchResult() + private fun Element.toSearchResult(): SearchResponse? { + val title = this.selectFirst("h2.entry-title > a")?.text()?.trim() ?: return null + val href = fixUrl(this.selectFirst("a")!!.attr("href")) + val posterUrl = fixUrlNull(this.selectFirst("a > img")?.attr("src"))?.fixImageQuality() + val quality = this.select("div.gmr-qual, div.gmr-quality-item > a").text().trim().replace("-", "") + return if (quality.isEmpty()) { + val episode = this.select("div.gmr-numbeps > span").text().toIntOrNull() + newAnimeSearchResponse(title, href, TvType.TvSeries) { + this.posterUrl = posterUrl + addSub(episode) + } + } else { + newMovieSearchResponse(title, href, TvType.Movie) { + this.posterUrl = posterUrl + addQuality(quality) + } } } + private fun Element.toRecommendResult(): SearchResponse? { + val title = this.selectFirst("a > span.idmuvi-rp-title")?.text()?.trim() ?: return null + val href = this.selectFirst("a")!!.attr("href") + val posterUrl = fixUrlNull(this.selectFirst("a > img")?.attr("src").fixImageQuality()) + return newMovieSearchResponse(title, href, TvType.Movie) { + this.posterUrl = posterUrl + } + } + + override suspend fun search(query: String): List { + return app.get("$mainUrl/?s=$query&post_type[]=post&post_type[]=tv").document.select("article.item") + .mapNotNull { + it.toSearchResult() + } + } + override suspend fun load(url: String): LoadResponse { val document = app.get(url).document val title = - document.selectFirst("h1.entry-title")?.text()?.substringBefore("Season")?.trim() ?: "" - val poster = fixUrlNull( - document.selectFirst("figure.pull-left > img")?.attr("src")?.fixImageQuality() - ) + document.selectFirst("h1.entry-title")?.text()?.substringBefore("Season")?.trim() + .toString() + val poster = + fixUrlNull(document.selectFirst("figure.pull-left > img")?.attr("src"))?.fixImageQuality() val tags = document.select("span.gmr-movie-genre:contains(Genre:) > a").map { it.text() } val year = @@ -71,19 +101,18 @@ class Ngefilm : MainAPI() { } return if (tvType == TvType.TvSeries) { - val episodes = document.select("div.gmr-listseries > a") - .filter { element -> !element.text().contains("Pilih Episode", true) } - .map { eps -> - val href = fixUrl(eps.attr("href")) - val episode = eps.text().substringAfter("Eps").toIntOrNull() - val season = - eps.text().split(" ").first().substringAfter("S").toIntOrNull() ?: 1 - Episode( - href, - season = season, - episode = episode, - ) - } + val episodes = document.select("div.vid-episodes a, div.gmr-listseries a").map { eps -> + val href = fixUrl(eps.attr("href")) + val name = eps.text() + val episode = name.split(" ").lastOrNull()?.filter { it.isDigit() }?.toIntOrNull() + val season = name.split(" ").firstOrNull()?.filter { it.isDigit() }?.toIntOrNull() + Episode( + href, + name, + season = if(name.contains(" ")) season else null, + episode = episode, + ) + }.filter { it.episode != null } newTvSeriesLoadResponse(title, url, TvType.TvSeries, episodes) { this.posterUrl = poster this.year = year @@ -116,49 +145,26 @@ class Ngefilm : MainAPI() { ): Boolean { val document = app.get(data).document + val id = document.selectFirst("div#muvipro_player_content_id")!!.attr("data-id") - document.select("ul.muvipro-player-tabs li a").apmap { server -> - val iframe = app.get(fixUrl(server.attr("href"))).document.selectFirst("div.gmr-embed-responsive iframe") - ?.attr("src")?.let { fixUrl(it) } ?: return@apmap - loadExtractor(iframe, "$mainUrl/", subtitleCallback, callback) + document.select("div.tab-content-ajax").apmap { + val server = app.post( + "$mainUrl/wp-admin/admin-ajax.php", + data = mapOf("action" to "muvipro_player_content", "tab" to it.attr("id"), "post_id" to id) + ).document.select("iframe").attr("src") + + loadExtractor(httpsify(server), "$mainUrl/", subtitleCallback, callback) } return true } - private fun Element.toSearchResult(): SearchResponse? { - val title = this.selectFirst("h2.entry-title > a")?.text()?.trim() ?: return null - val href = fixUrl(this.selectFirst("a")?.attr("href") ?: return null) - val posterUrl = fixUrlNull(this.selectFirst("a > img")?.attr("src").fixImageQuality()) - val quality = this.select("div.gmr-quality-item > a").text().trim() - return if (quality.isEmpty()) { - val episode = - this.select("div.gmr-numbeps > span").text().filter { it.isDigit() }.toIntOrNull() - newAnimeSearchResponse(title, href, TvType.TvSeries) { - this.posterUrl = posterUrl - addSub(episode) - } - } else { - newMovieSearchResponse(title, href, TvType.Movie) { - this.posterUrl = posterUrl - addQuality(quality.replace("-", "")) - } - } - } - - private fun Element.toRecommendResult(): SearchResponse? { - val title = this.selectFirst("a > span.idmuvi-rp-title")?.text()?.trim() ?: return null - val href = this.selectFirst("a")!!.attr("href") - val posterUrl = fixUrlNull(this.selectFirst("a > img")?.attr("src").fixImageQuality()) - return newMovieSearchResponse(title, href, TvType.Movie) { - this.posterUrl = posterUrl - } - } - private fun String?.fixImageQuality(): String? { - val quality = Regex("(-\\d*x\\d*)").find(this ?: return null)?.groupValues?.get(0) - return this.replace(quality ?: return null, "") + if(this == null) return null + val regex = Regex("(-\\d*x\\d*)").find(this)?.groupValues + if(regex?.isEmpty() == true) return this + return this.replace(regex?.get(0) ?: return null, "") } } \ No newline at end of file diff --git a/Gomov/src/main/kotlin/com/hexated/GomovPlugin.kt b/Gomov/src/main/kotlin/com/hexated/GomovPlugin.kt new file mode 100644 index 00000000..bd11fd67 --- /dev/null +++ b/Gomov/src/main/kotlin/com/hexated/GomovPlugin.kt @@ -0,0 +1,21 @@ + +package com.hexated + +import com.lagradost.cloudstream3.plugins.CloudstreamPlugin +import com.lagradost.cloudstream3.plugins.Plugin +import android.content.Context + +@CloudstreamPlugin +class GomovPlugin: Plugin() { + override fun load(context: Context) { + // All providers should be added in this manner. Please don't edit the providers list directly. + registerMainAPI(Gomov()) + registerMainAPI(DutaMovie()) + registerMainAPI(Ngefilm()) + registerMainAPI(Nodrakorid()) + registerExtractorAPI(Filelions()) + registerExtractorAPI(Likessb()) + registerExtractorAPI(DbGdriveplayer()) + registerExtractorAPI(Dutamovie21()) + } +} \ No newline at end of file diff --git a/Gomov/src/main/kotlin/com/hexated/Ngefilm.kt b/Gomov/src/main/kotlin/com/hexated/Ngefilm.kt new file mode 100644 index 00000000..00c20195 --- /dev/null +++ b/Gomov/src/main/kotlin/com/hexated/Ngefilm.kt @@ -0,0 +1,22 @@ +package com.hexated + +import com.lagradost.cloudstream3.SubtitleFile +import com.lagradost.cloudstream3.apmap +import com.lagradost.cloudstream3.app +import com.lagradost.cloudstream3.fixUrl +import com.lagradost.cloudstream3.mainPageOf +import com.lagradost.cloudstream3.utils.ExtractorLink +import com.lagradost.cloudstream3.utils.loadExtractor + +class Ngefilm : DutaMovie() { + override var mainUrl = "https://ngefilm21.lol" + override var name = "Ngefilm" + + override val mainPage = mainPageOf( + "/page/%d/?s&search=advanced&post_type=movie&index&orderby&genre&movieyear&country&quality=" to "Movies Terbaru", + "/page/%d/?s=&search=advanced&post_type=tv&index=&orderby=&genre=&movieyear=&country=&quality=" to "Series Terbaru", + "/page/%d/?s=&search=advanced&post_type=tv&index=&orderby=&genre=drakor&movieyear=&country=&quality=" to "Series Korea", + "/page/%d/?s=&search=advanced&post_type=tv&index=&orderby=&genre=&movieyear=&country=indonesia&quality=" to "Series Indonesia", + ) + +} \ No newline at end of file diff --git a/Gomov/src/main/kotlin/com/hexated/Nodrakorid.kt b/Gomov/src/main/kotlin/com/hexated/Nodrakorid.kt new file mode 100644 index 00000000..1e383927 --- /dev/null +++ b/Gomov/src/main/kotlin/com/hexated/Nodrakorid.kt @@ -0,0 +1,16 @@ +package com.hexated + +import com.lagradost.cloudstream3.mainPageOf + +class Nodrakorid : DutaMovie() { + override var mainUrl = "https://no-drak-or.xyz" + override var name = "Nodrakorid" + + override val mainPage = mainPageOf( + "genre/movie/page/%d/" to "Film Terbaru", + "genre/korean-movie/page/%d/" to "Film Korea", + "genre/drama/page/%d/" to "Drama Korea", + "genre/c-drama/c-drama-c-drama/page/%d/" to "Drama China", + "genre/thai-drama/page/%d/" to "Drama Thailand", + ) +} \ No newline at end of file diff --git a/KuramanimeProvider/build.gradle.kts b/KuramanimeProvider/build.gradle.kts index 31e82f6a..e9c83545 100644 --- a/KuramanimeProvider/build.gradle.kts +++ b/KuramanimeProvider/build.gradle.kts @@ -1,5 +1,5 @@ // use an integer for version numbers -version = 12 +version = 13 cloudstream { diff --git a/KuramanimeProvider/src/main/kotlin/com/hexated/KuramanimeProvider.kt b/KuramanimeProvider/src/main/kotlin/com/hexated/KuramanimeProvider.kt index 5d24fcad..989740bb 100644 --- a/KuramanimeProvider/src/main/kotlin/com/hexated/KuramanimeProvider.kt +++ b/KuramanimeProvider/src/main/kotlin/com/hexated/KuramanimeProvider.kt @@ -9,7 +9,7 @@ import org.jsoup.Jsoup import org.jsoup.nodes.Element class KuramanimeProvider : MainAPI() { - override var mainUrl = "https://kuramanime.net" + override var mainUrl = "https://kuramanime.xyz" override var name = "Kuramanime" override val hasQuickSearch = false override val hasMainPage = true diff --git a/MultiplexProvider/build.gradle.kts b/MultiplexProvider/build.gradle.kts index aaeb74f5..51ca5d94 100644 --- a/MultiplexProvider/build.gradle.kts +++ b/MultiplexProvider/build.gradle.kts @@ -1,5 +1,5 @@ // use an integer for version numbers -version = 1 +version = 2 cloudstream { diff --git a/MultiplexProvider/src/main/kotlin/com/hexated/MultiplexProvider.kt b/MultiplexProvider/src/main/kotlin/com/hexated/MultiplexProvider.kt index 851c267e..7a76be91 100644 --- a/MultiplexProvider/src/main/kotlin/com/hexated/MultiplexProvider.kt +++ b/MultiplexProvider/src/main/kotlin/com/hexated/MultiplexProvider.kt @@ -10,7 +10,7 @@ import com.lagradost.cloudstream3.utils.getQualityFromName import org.jsoup.nodes.Element class MultiplexProvider : MainAPI() { - override var mainUrl = "https://146.19.24.137" + override var mainUrl = "http://5.104.81.46" override var name = "Multiplex" override val hasMainPage = true override var lang = "id" diff --git a/Nekopoi/build.gradle.kts b/Nekopoi/build.gradle.kts index 2eb99748..a8c9601a 100644 --- a/Nekopoi/build.gradle.kts +++ b/Nekopoi/build.gradle.kts @@ -1,5 +1,5 @@ // use an integer for version numbers -version = 1 +version = 3 cloudstream { diff --git a/Nekopoi/src/main/kotlin/com/hexated/Nekopoi.kt b/Nekopoi/src/main/kotlin/com/hexated/Nekopoi.kt index 9c0a4cb7..27ecc2e8 100644 --- a/Nekopoi/src/main/kotlin/com/hexated/Nekopoi.kt +++ b/Nekopoi/src/main/kotlin/com/hexated/Nekopoi.kt @@ -30,6 +30,7 @@ class Nekopoi : MainAPI() { "SendCm", "GoogleDrive", ) + const val mirroredHost = "https://www.mirrored.to" fun getStatus(t: String?): ShowStatus { return when (t) { @@ -155,7 +156,7 @@ class Nekopoi : MainAPI() { ) to ele.selectFirst("a:contains(ouo)") ?.attr("href") }.filter { it.first != Qualities.P360.value }.map { - val bypassedAds = bypassMirrored(bypassOuo(it.second ?: return@map) ?: return@map) + val bypassedAds = bypassMirrored(bypassOuo(it.second)) bypassedAds.apmap ads@{ adsLink -> loadExtractor( fixEmbed(adsLink) ?: return@ads, @@ -225,21 +226,20 @@ class Nekopoi : MainAPI() { return res.headers["location"] } - private suspend fun bypassMirrored(url: String): List { - val request = app.get(url) - val hostUrl = getBaseUrl(request.url) + private suspend fun bypassMirrored(url: String?): List { + val request = app.get(url ?: return emptyList()) var nextUrl = request.document.selectFirst("div.row div.centered a")?.attr("href") nextUrl = app.get(nextUrl ?: return emptyList()).text.substringAfter("\"GET\", \"") .substringBefore("\"") - return app.get(fixUrl(nextUrl, hostUrl)).document.select("table.hoverable tbody tr") + return app.get(fixUrl(nextUrl, mirroredHost)).document.select("table.hoverable tbody tr") .filter { mirror -> !mirrorIsBlackList(mirror.selectFirst("img")?.attr("alt")) }.apmap { val fileLink = it.selectFirst("a")?.attr("href") app.get( fixUrl( - fileLink.toString(), - hostUrl + fileLink ?: return@apmap null, + mirroredHost ) ).document.selectFirst("div.code_wrap code")?.text() } diff --git a/Nimegami/build.gradle.kts b/Nimegami/build.gradle.kts new file mode 100644 index 00000000..82d96dc1 --- /dev/null +++ b/Nimegami/build.gradle.kts @@ -0,0 +1,27 @@ +// use an integer for version numbers +version = 1 + + +cloudstream { + language = "id" + // All of these properties are optional, you can safely remove them + + // description = "Lorem Ipsum" + authors = listOf("Hexated") + + /** + * Status int as the following: + * 0: Down + * 1: Ok + * 2: Slow + * 3: Beta only + * */ + status = 1 // will be 3 if unspecified + tvTypes = listOf( + "AnimeMovie", + "Anime", + "OVA", + ) + + iconUrl = "https://www.google.com/s2/favicons?domain=nimegami.id&sz=%size%" +} \ No newline at end of file diff --git a/Nimegami/src/main/AndroidManifest.xml b/Nimegami/src/main/AndroidManifest.xml new file mode 100644 index 00000000..c98063f8 --- /dev/null +++ b/Nimegami/src/main/AndroidManifest.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Nimegami/src/main/kotlin/com/hexated/Extractors.kt b/Nimegami/src/main/kotlin/com/hexated/Extractors.kt new file mode 100644 index 00000000..aed3ac15 --- /dev/null +++ b/Nimegami/src/main/kotlin/com/hexated/Extractors.kt @@ -0,0 +1,60 @@ +package com.hexated + +import com.fasterxml.jackson.annotation.JsonProperty +import com.lagradost.cloudstream3.SubtitleFile +import com.lagradost.cloudstream3.app +import com.lagradost.cloudstream3.utils.ExtractorApi +import com.lagradost.cloudstream3.utils.ExtractorLink +import com.lagradost.cloudstream3.utils.Qualities + +open class Mitedrive : ExtractorApi() { + override val name = "Mitedrive" + override val mainUrl = "https://mitedrive.com" + override val requiresReferer = false + + override suspend fun getUrl( + url: String, + referer: String?, + subtitleCallback: (SubtitleFile) -> Unit, + callback: (ExtractorLink) -> Unit + ) { + val id = url.substringAfterLast("/") + val video = app.post( + "$mainUrl/api/generate", + referer = "$mainUrl/", + data = mapOf( + "short_url" to id + ) + ).parsedSafe()?.data?.url + + val headers = mapOf( + "Accept" to "*/*", + "Connection" to "keep-alive", + "Sec-Fetch-Dest" to "empty", + "Sec-Fetch-Mode" to "cors", + "Sec-Fetch-Site" to "cross-site", + "Origin" to mainUrl, + ) + + callback.invoke( + ExtractorLink( + this.name, + this.name, + video ?: return, + "$mainUrl/", + Qualities.Unknown.value, + headers = headers + ) + ) + + } + + data class Data( + @JsonProperty("url") val url: String? = null, + ) + + data class Responses( + @JsonProperty("data") val data: Data? = null, + ) + +} \ No newline at end of file diff --git a/Nimegami/src/main/kotlin/com/hexated/Nimegami.kt b/Nimegami/src/main/kotlin/com/hexated/Nimegami.kt new file mode 100644 index 00000000..69541e2e --- /dev/null +++ b/Nimegami/src/main/kotlin/com/hexated/Nimegami.kt @@ -0,0 +1,197 @@ +package com.hexated + +import com.fasterxml.jackson.annotation.JsonProperty +import com.lagradost.cloudstream3.* +import com.lagradost.cloudstream3.utils.* +import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson +import org.jsoup.nodes.Element +import org.jsoup.select.Elements +import java.net.URI + +class Nimegami : MainAPI() { + override var mainUrl = "https://nimegami.id" + override var name = "Nimegami" + override val hasMainPage = true + override var lang = "id" + override val supportedTypes = setOf( + TvType.Anime, + TvType.AnimeMovie, + TvType.OVA + ) + + companion object { + fun getType(t: String): TvType { + return if (t.contains("OVA", true) || t.contains("Special", true)) TvType.OVA + else if (t.contains("Movie", true)) TvType.AnimeMovie + else TvType.Anime + } + + fun getStatus(t: String?): ShowStatus { + return when { + t?.contains("On-Going", true) == true -> ShowStatus.Ongoing + else -> ShowStatus.Completed + } + } + } + + override val mainPage = mainPageOf( + "" to "Updated Anime", + "/type/tv" to "Anime", + "/type/movie" to "Movie", + "/type/ona" to "ONA", + "/type/live-action" to "Live Action", + ) + + override suspend fun getMainPage( + page: Int, + request: MainPageRequest + ): HomePageResponse { + val document = app.get("$mainUrl${request.data}/page/$page").document + val home = document.select("div.post-article article, div.archive article").mapNotNull { + it.toSearchResult() + } + return newHomePageResponse( + list = HomePageList( + name = request.name, + list = home, + isHorizontalImages = request.name != "Updated Anime" + ), + hasNext = true + ) + } + + private fun Element.toSearchResult(): AnimeSearchResponse? { + val href = fixUrl(this.selectFirst("a")!!.attr("href")) + val title = this.selectFirst("h2 a")?.text() ?: return null + val posterUrl = (this.selectFirst("noscript img") ?: this.selectFirst("img"))?.attr("src") + val episode = this.selectFirst("ul li:contains(Episode), div.eps-archive")?.ownText() + ?.filter { it.isDigit() }?.toIntOrNull() + + return newAnimeSearchResponse(title, href, TvType.Anime) { + this.posterUrl = posterUrl + addSub(episode) + } + + } + + override suspend fun search(query: String): List { + return app.get("$mainUrl/?s=$query&post_type=post").document.select("div.archive article") + .mapNotNull { + it.toSearchResult() + } + } + + override suspend fun load(url: String): LoadResponse { + val document = app.get(url).document + + val table = document.select("div#Info table tbody") + val title = table.getContent("Judul :").text() + val poster = document.selectFirst("div.coverthumbnail img")?.attr("src") + val bgPoster = document.selectFirst("div.thumbnail-a img")?.attr("src") + val tags = table.getContent("Kategori").select("a").map { it.text() } + + val year = table.getContent("Musim / Rilis").text().filter { it.isDigit() }.toIntOrNull() + val status = getStatus(document.selectFirst("h1[itemprop=headline]")?.text()) + val type = table.getContent("Type").text() + val description = document.select("div#Sinopsis p").text().trim() + + + val episodes = document.select("div.list_eps_stream li") + .mapNotNull { + val name = it.text() + val link = it.attr("data") + Episode(link, name) + } + + val recommendations = document.select("div#randomList > a").mapNotNull { + val epHref = it.attr("href") + val epTitle = it.select("h5.sidebar-title-h5.px-2.py-2").text() + val epPoster = it.select(".product__sidebar__view__item.set-bg").attr("data-setbg") + + newAnimeSearchResponse(epTitle, epHref, TvType.Anime) { + this.posterUrl = epPoster + addDubStatus(dubExist = false, subExist = true) + } + } + + return newAnimeLoadResponse(title, url, getType(type)) { + engName = title + posterUrl = poster + backgroundPosterUrl = bgPoster + this.year = year + addEpisodes(DubStatus.Subbed, episodes) + showStatus = status + plot = description + this.tags = tags + this.recommendations = recommendations + } + + } + + override suspend fun loadLinks( + data: String, + isCasting: Boolean, + subtitleCallback: (SubtitleFile) -> Unit, + callback: (ExtractorLink) -> Unit + ): Boolean { + + tryParseJson>(base64Decode(data))?.map { sources -> + sources.url?.apmap { url -> + loadFixedExtractor(url.fixIframe(), sources.format, "$mainUrl/", subtitleCallback, callback) + } + } + + return true + } + + private suspend fun loadFixedExtractor( + url: String, + quality: String?, + referer: String? = null, + subtitleCallback: (SubtitleFile) -> Unit, + callback: (ExtractorLink) -> Unit + ) { + loadExtractor(url, referer, subtitleCallback) { link -> + callback.invoke( + ExtractorLink( + link.name, + link.name, + link.url, + link.referer, + getQualityFromName(quality), + link.isM3u8, + link.headers, + link.extractorData + ) + ) + } + } + + private fun getBaseUrl(url: String): String { + return URI(url).let { + "${it.scheme}://${it.host}" + } + } + + private fun Elements.getContent(css: String) : Elements { + return this.select("tr:contains($css) td:last-child") + } + + private fun String.fixIframe() : String { + val url = base64Decode(this.substringAfter("url=").substringAfter("id=")) + val host = getBaseUrl(url) + return when { + url.contains("hxfile") -> { + val id = url.substringAfterLast("/") + "$host/embed-$id.html" + } + else -> fixUrl(url) + } + } + + data class Sources( + @JsonProperty("format") val format: String? = null, + @JsonProperty("url") val url: ArrayList? = arrayListOf(), + ) + +} diff --git a/Nimegami/src/main/kotlin/com/hexated/NimegamiPlugin.kt b/Nimegami/src/main/kotlin/com/hexated/NimegamiPlugin.kt new file mode 100644 index 00000000..8ab01378 --- /dev/null +++ b/Nimegami/src/main/kotlin/com/hexated/NimegamiPlugin.kt @@ -0,0 +1,15 @@ + +package com.hexated + +import com.lagradost.cloudstream3.plugins.CloudstreamPlugin +import com.lagradost.cloudstream3.plugins.Plugin +import android.content.Context + +@CloudstreamPlugin +class NimegamiPlugin: Plugin() { + override fun load(context: Context) { + // All providers should be added in this manner. Please don't edit the providers list directly. + registerMainAPI(Nimegami()) + registerExtractorAPI(Mitedrive()) + } +} \ No newline at end of file diff --git a/NontonAnimeIDProvider/build.gradle.kts b/NontonAnimeIDProvider/build.gradle.kts index 3da1506d..cff263d4 100644 --- a/NontonAnimeIDProvider/build.gradle.kts +++ b/NontonAnimeIDProvider/build.gradle.kts @@ -1,5 +1,5 @@ // use an integer for version numbers -version = 15 +version = 16 cloudstream { diff --git a/NontonAnimeIDProvider/src/main/kotlin/com/hexated/NontonAnimeIDProvider.kt b/NontonAnimeIDProvider/src/main/kotlin/com/hexated/NontonAnimeIDProvider.kt index aa54f212..2912e7a2 100644 --- a/NontonAnimeIDProvider/src/main/kotlin/com/hexated/NontonAnimeIDProvider.kt +++ b/NontonAnimeIDProvider/src/main/kotlin/com/hexated/NontonAnimeIDProvider.kt @@ -11,7 +11,7 @@ import org.jsoup.nodes.Element import java.net.URI class NontonAnimeIDProvider : MainAPI() { - override var mainUrl = "https://nontonanimeid.bio" + override var mainUrl = "https://nontonanimeid.lol" override var name = "NontonAnimeID" override val hasQuickSearch = false override val hasMainPage = true diff --git a/Phim1080/src/main/kotlin/com/hexated/Phim1080Provider.kt b/Phim1080/src/main/kotlin/com/hexated/Phim1080Provider.kt new file mode 100644 index 00000000..edadf591 --- /dev/null +++ b/Phim1080/src/main/kotlin/com/hexated/Phim1080Provider.kt @@ -0,0 +1,247 @@ +package com.hexated + +import com.fasterxml.jackson.annotation.JsonProperty +import com.lagradost.cloudstream3.* +import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer +import com.lagradost.cloudstream3.utils.* +import com.lagradost.cloudstream3.utils.ExtractorLink +import org.jsoup.nodes.Element + +class Phim1080Provider : MainAPI() { + override var mainUrl = "https://xem1080.com" + override var name = "Phim1080" + override val hasMainPage = true + override var lang = "vi" + override val hasDownloadSupport = true + override val supportedTypes = setOf( + TvType.Movie, + TvType.TvSeries, + TvType.Anime, + TvType.AsianDrama + ) + + private fun encodeString(e: String, t: Int): String { + var a = "" + for (element in e) { + val r = element.code + val o = r xor t + a += o.toChar() + } + return a + } + + override val mainPage = mainPageOf( + "$mainUrl/phim-de-cu?page=" to "Phim Đề Cử", + "$mainUrl/the-loai/hoat-hinh?page=" to "Phim Hoạt Hình", + "$mainUrl/phim-chieu-rap?page=" to "Phim Chiếu Rạp", + "$mainUrl/phim-bo?page=" to "Phim Bộ", + "$mainUrl/phim-le?page=" to "Phim Lẻ", + "$mainUrl/bang-xep-hang?page=" to "Bảng Xếp Hạng", + "$mainUrl/bo-suu-tap/disney-plus?page=" to "Disney+", + "$mainUrl/bo-suu-tap/netflix-original?page=" to "Netflix", + "$mainUrl/hom-nay-xem-gi?page=" to "Hôm Nay Xem Gì", + "$mainUrl/phim-sap-chieu?page=" to "Phim Sắp Chiếu", + ) + + override suspend fun getMainPage( + page: Int, + request: MainPageRequest + ): HomePageResponse { + val document = app.get(request.data + page).document + val home = document.select("div.tray-item").mapNotNull { + it.toSearchResult() + } + return newHomePageResponse( + list = HomePageList( + name = request.name, + list = home, + ), + hasNext = true + ) + } + + private fun Element.toSearchResult(): SearchResponse { + val title = this.selectFirst("div.tray-item-title")?.text()?.trim().toString() + val href = fixUrl(this.selectFirst("a")!!.attr("href")) + val posterUrl = this.selectFirst("img")!!.attr("data-src") + val temp = this.select("div.tray-film-likes").text() + return if (temp.contains("/")) { + val episode = Regex("((\\d+)\\s)").find(temp)?.groupValues?.map { num -> + num.replace(Regex("\\s"), "") + }?.distinct()?.firstOrNull()?.toIntOrNull() + newAnimeSearchResponse(title, href, TvType.TvSeries) { + this.posterUrl = posterUrl + addSub(episode) + } + } else { + val quality = this.select("span.tray-item-quality").text().replace("FHD", "HD").trim() + newMovieSearchResponse(title, href, TvType.Movie) { + this.posterUrl = posterUrl + addQuality(quality) + } + } + } + + override suspend fun search(query: String): List { + val link = "$mainUrl/tim-kiem/$query" + val document = app.get(link).document + + return document.select("div.tray-item").map { + it.toSearchResult() + } + } + + override suspend fun load( url: String ): LoadResponse { + val document = app.get( + url = url, + referer = "$mainUrl/", + headers = mapOf( + "Sec-Ch-Ua-Mobile" to "?1", + "Sec-Ch-Ua-Platform" to "\"Android\"", + "User-Agent" to "Mozilla/5.0 (Linux; Android 10; SM-G981B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.162 Mobile Safari/537.36 Edg/114.0.0.0", + ) + ).document + val fId = document.select("div.container").attr("data-id") + val filmInfo = app.get( + "$mainUrl/api/v2/films/$fId", + referer = url, + headers = mapOf( + "Content-Type" to "application/json", + "X-Requested-With" to "XMLHttpRequest" + ) + ).parsedSafe() + val title = filmInfo?.name?.trim().toString() + val poster = filmInfo?.thumbnail + val background = filmInfo?.poster + val slug = filmInfo?.slug + val link = "$mainUrl/$slug" + val tags = document.select("div.film-content div.film-info-genre:nth-child(7) a").map { it.text() } + val year = filmInfo?.year + val tvType = if (document.select("div.episode-group-tab").isNotEmpty()) TvType.TvSeries else TvType.Movie + val description = document.select("div.film-info-description").text().trim() + val comingSoon = document.select("button.direction-trailer").isNotEmpty() + val trailerCode = filmInfo?.trailer?.original?.id + val trailer = "https://www.youtube.com/embed/$trailerCode" + val recommendations = document.select("section.tray.index.related div.tray-content.carousel div.tray-item").map { + it.toSearchResult() + } + + return if (tvType == TvType.TvSeries) { + val epsInfo = app.get( + "$mainUrl/api/v2/films/$fId/episodes?sort=name", + referer = link, + headers = mapOf( + "Content-Type" to "application/json", + "X-Requested-With" to "XMLHttpRequest", + ) + ).parsedSafe()?.eps?.map { ep -> + Episode( + data = fixUrl(ep.link.toString()), + name = ep.detailname, + episode = ep.episodeNumber, + ) + } ?: listOf() + newTvSeriesLoadResponse(title, url, TvType.TvSeries, epsInfo) { + this.posterUrl = poster + this.backgroundPosterUrl = background + this.year = year + this.plot = description + this.tags = tags + this.comingSoon = comingSoon + addTrailer(trailer) + this.recommendations = recommendations + } + } else { + newMovieLoadResponse(title, url, TvType.Movie, link) { + this.posterUrl = poster + this.backgroundPosterUrl = background + this.year = year + this.plot = description + this.tags = tags + this.comingSoon = comingSoon + addTrailer(trailer) + this.recommendations = recommendations + } + } + } + + override suspend fun loadLinks( + data: String, + isCasting: Boolean, + subtitleCallback: (SubtitleFile) -> Unit, + callback: (ExtractorLink) -> Unit + ): Boolean { + + val document = app.get(data).document + val fId = document.select("div.container").attr("data-id") + val epId = document.select("div.container").attr("data-episode-id") + val doc = app.get( + "$mainUrl/api/v2/films/$fId/episodes/$epId", + referer = data, + headers = mapOf( + "Content-Type" to "application/json", + "cookie" to "xem1080=%3D", + "X-Requested-With" to "XMLHttpRequest" + ) + ) + val source = doc.text.substringAfter(":{\"hls\":\"").substringBefore("\"},") + val link = encodeString(source, 69) + callback.invoke( + ExtractorLink( + "HS", + "HS", + link, + referer = data, + quality = Qualities.Unknown.value, + isM3u8 = true, + ) + ) + val subId = doc.parsedSafe()?.subtitle?.vi + val isSubIdEmpty = subId.isNullOrBlank() + if (!isSubIdEmpty) { + subtitleCallback.invoke( + SubtitleFile( + "Vietnamese", + "$mainUrl/subtitle/$subId.vtt" + ) + ) + } + return true + } + + data class FilmInfo( + @JsonProperty("name") val name: String? = null, + @JsonProperty("poster") val poster: String? = null, + @JsonProperty("thumbnail") val thumbnail: String? = null, + @JsonProperty("slug") val slug: String? = null, + @JsonProperty("year") val year: Int? = null, + @JsonProperty("trailer") val trailer: TrailerInfo? = null, + ) + + data class TrailerInfo( + @JsonProperty("original") val original: TrailerKey? = null, + ) + + data class TrailerKey( + @JsonProperty("id") val id: String? = null, + ) + + data class MediaDetailEpisodes( + @JsonProperty("data") val eps: ArrayList? = arrayListOf(), + ) + + data class Episodes( + @JsonProperty("link") val link: String? = null, + @JsonProperty("detail_name") val detailname: String? = null, + @JsonProperty("name") val episodeNumber: Int? = null, + ) + + data class Media( + @JsonProperty("subtitle") val subtitle: SubInfo? = null, + ) + + data class SubInfo( + @JsonProperty("vi") val vi: String? = null, + ) + +} diff --git a/Ngefilm/src/main/kotlin/com/hexated/NgefilmPlugin.kt b/Phim1080/src/main/kotlin/com/hexated/Phim1080ProviderPlugin.kt similarity index 79% rename from Ngefilm/src/main/kotlin/com/hexated/NgefilmPlugin.kt rename to Phim1080/src/main/kotlin/com/hexated/Phim1080ProviderPlugin.kt index 8fc845f8..a521b6ac 100644 --- a/Ngefilm/src/main/kotlin/com/hexated/NgefilmPlugin.kt +++ b/Phim1080/src/main/kotlin/com/hexated/Phim1080ProviderPlugin.kt @@ -6,9 +6,9 @@ import com.lagradost.cloudstream3.plugins.Plugin import android.content.Context @CloudstreamPlugin -class NgefilmPlugin: Plugin() { +class Phim1080ProviderPlugin: Plugin() { override fun load(context: Context) { // All providers should be added in this manner. Please don't edit the providers list directly. - registerMainAPI(Ngefilm()) + registerMainAPI(Phim1080Provider()) } -} \ No newline at end of file +} diff --git a/RebahinProvider/build.gradle.kts b/RebahinProvider/build.gradle.kts index 32b9dd7e..0c5b2fdf 100644 --- a/RebahinProvider/build.gradle.kts +++ b/RebahinProvider/build.gradle.kts @@ -1,12 +1,12 @@ // use an integer for version numbers -version = 6 +version = 7 cloudstream { language = "id" // All of these properties are optional, you can safely remove them - // description = "Lorem Ipsum" + description = "Include: Cgvindo, Kitanonton" authors = listOf("Hexated") /** diff --git a/RebahinProvider/src/main/kotlin/com/hexated/Cgvindo.kt b/RebahinProvider/src/main/kotlin/com/hexated/Cgvindo.kt new file mode 100644 index 00000000..328f0a06 --- /dev/null +++ b/RebahinProvider/src/main/kotlin/com/hexated/Cgvindo.kt @@ -0,0 +1,9 @@ +package com.hexated + +import com.lagradost.cloudstream3.TvType + +class Cgvindo : RebahinProvider() { + override var mainUrl = "http://cgvindo.click" + override var name = "Cgvindo" + +} \ No newline at end of file diff --git a/RebahinProvider/src/main/kotlin/com/hexated/RebahinProvider.kt b/RebahinProvider/src/main/kotlin/com/hexated/RebahinProvider.kt index e8e5ad1e..fcb63f6e 100644 --- a/RebahinProvider/src/main/kotlin/com/hexated/RebahinProvider.kt +++ b/RebahinProvider/src/main/kotlin/com/hexated/RebahinProvider.kt @@ -13,11 +13,10 @@ import org.jsoup.nodes.Element import java.net.URI open class RebahinProvider : MainAPI() { - override var mainUrl = "http://104.237.198.198" + override var mainUrl = "http://179.43.163.50" override var name = "Rebahin" override val hasMainPage = true override var lang = "id" - override val hasDownloadSupport = true open var mainServer = "http://172.96.161.72" override val supportedTypes = setOf( TvType.Movie, diff --git a/RebahinProvider/src/main/kotlin/com/hexated/RebahinProviderPlugin.kt b/RebahinProvider/src/main/kotlin/com/hexated/RebahinProviderPlugin.kt index ab58bb2d..e051cc41 100644 --- a/RebahinProvider/src/main/kotlin/com/hexated/RebahinProviderPlugin.kt +++ b/RebahinProvider/src/main/kotlin/com/hexated/RebahinProviderPlugin.kt @@ -1,4 +1,3 @@ - package com.hexated import com.lagradost.cloudstream3.plugins.CloudstreamPlugin @@ -6,10 +5,11 @@ import com.lagradost.cloudstream3.plugins.Plugin import android.content.Context @CloudstreamPlugin -class RebahinProviderPlugin: Plugin() { +class RebahinProviderPlugin : Plugin() { override fun load(context: Context) { // All providers should be added in this manner. Please don't edit the providers list directly. registerMainAPI(RebahinProvider()) -registerMainAPI(Kitanonton()) + registerMainAPI(Kitanonton()) + registerMainAPI(Cgvindo()) } } \ No newline at end of file diff --git a/SoraStream/build.gradle.kts b/SoraStream/build.gradle.kts index c770eba3..cc49bd00 100644 --- a/SoraStream/build.gradle.kts +++ b/SoraStream/build.gradle.kts @@ -1,7 +1,7 @@ import org.jetbrains.kotlin.konan.properties.Properties // use an integer for version numbers -version = 144 +version = 147 android { defaultConfig { diff --git a/SoraStream/src/main/kotlin/com/hexated/SoraExtractor.kt b/SoraStream/src/main/kotlin/com/hexated/SoraExtractor.kt index 933475ca..8b3819d5 100644 --- a/SoraStream/src/main/kotlin/com/hexated/SoraExtractor.kt +++ b/SoraStream/src/main/kotlin/com/hexated/SoraExtractor.kt @@ -930,10 +930,7 @@ object SoraExtractor : SoraStream() { argamap( { - invokeZoro(aniId, episode, subtitleCallback, callback) - }, - { - invokeAnimeKaizoku(malId, epsTitle, season, episode, callback) + invokeAniwatch(malId, episode, subtitleCallback, callback) }, { invokeBiliBili(aniId, episode, subtitleCallback, callback) @@ -1004,28 +1001,26 @@ object SoraExtractor : SoraStream() { } - private suspend fun invokeZoro( - aniId: Int? = null, + private suspend fun invokeAniwatch( + malId: Int? = null, episode: Int? = null, subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit ) { - val animeId = - app.get("https://raw.githubusercontent.com/MALSync/MAL-Sync-Backup/master/data/anilist/anime/${aniId ?: return}.json") - .parsedSafe()?.pages?.zoro?.keys?.map { it } val headers = mapOf( "X-Requested-With" to "XMLHttpRequest", ) + val animeId = app.get("$malsyncAPI/mal/anime/${malId ?: return}").parsedSafe()?.sites?.zoro?.keys?.map { it } animeId?.apmap { id -> - val episodeId = app.get("$zoroAPI/ajax/episode/list/${id ?: return@apmap}", headers = headers) - .parsedSafe()?.html?.let { + val episodeId = app.get("$aniwatchAPI/ajax/v2/episode/list/${id ?: return@apmap}", headers = headers) + .parsedSafe()?.html?.let { Jsoup.parse(it) }?.select("div.ss-list a")?.find { it.attr("data-number") == "${episode ?: 1}" } ?.attr("data-id") val servers = - app.get("$zoroAPI/ajax/episode/servers?episodeId=${episodeId ?: return@apmap}", headers = headers) - .parsedSafe()?.html?.let { Jsoup.parse(it) } + app.get("$aniwatchAPI/ajax/v2/episode/servers?episodeId=${episodeId ?: return@apmap}", headers = headers) + .parsedSafe()?.html?.let { Jsoup.parse(it) } ?.select("div.item.server-item")?.map { Triple( it.text(), @@ -1035,22 +1030,21 @@ object SoraExtractor : SoraStream() { } servers?.apmap servers@{ server -> - val iframe = - app.get("$zoroAPI/ajax/episode/sources?id=${server.second ?: return@servers}", headers = headers) - .parsedSafe()?.link ?: return@servers + val iframe = app.get("$aniwatchAPI/ajax/v2/episode/sources?id=${server.second ?: return@servers}", headers = headers) + .parsedSafe()?.link ?: return@servers val audio = if (server.third == "sub") "Raw" else "English Dub" if (server.first.contains(Regex("Vidstreaming|MegaCloud|Vidcloud"))) { extractRabbitStream( "${server.first} [$audio]", iframe, - "$zoroAPI/", + "$aniwatchAPI/", subtitleCallback, callback, false, decryptKey = RabbitStream.getZoroKey() ) { it } } else { - loadExtractor(iframe, "$zoroAPI/", subtitleCallback, callback) + loadExtractor(iframe, "$aniwatchAPI/", subtitleCallback, callback) } } @@ -1491,7 +1485,13 @@ object SoraExtractor : SoraStream() { extractGdflix(gdBotLink ?: return@apmap null) } type.contains("oiya") -> { - extractOiya(fdLink ?: return@apmap null, qualities) + val oiyaLink = extractOiya(fdLink ?: return@apmap null, qualities) + if(oiyaLink?.contains("gdtot") == true) { + val gdBotLink = extractGdbot(oiyaLink) + extractGdflix(gdBotLink ?: return@apmap null) + } else { + oiyaLink + } } else -> { return@apmap null @@ -2041,6 +2041,9 @@ object SoraExtractor : SoraStream() { it.first.contains("/rip") -> { invokeSmashyRip(it.second, it.first, subtitleCallback, callback) } + it.first.contains("/im.php") && !isAnime -> { + invokeSmashyIm(it.second, it.first, subtitleCallback, callback) + } else -> return@apmap } } @@ -2692,7 +2695,15 @@ object SoraExtractor : SoraStream() { epsDoc.select("ul.group-links-list li:nth-child($episode) a").attr("data-embed-src") } - loadExtractor(iframe, ask4MoviesAPI, subtitleCallback, callback) + val iframeDoc = app.get(iframe, referer = "$ask4MoviesAPI/").text + val script = Regex("""eval\(function\(p,a,c,k,e,.*\)\)""").findAll(iframeDoc).lastOrNull()?.value + val unpacked = getAndUnpack(script ?: return) + val m3u8 = Regex("file:\\s*\"(.*?m3u8.*?)\"").find(unpacked)?.groupValues?.getOrNull(1) + M3u8Helper.generateM3u8( + "Ask4movie", + m3u8 ?: return, + mainUrl + ).forEach(callback) } diff --git a/SoraStream/src/main/kotlin/com/hexated/SoraParser.kt b/SoraStream/src/main/kotlin/com/hexated/SoraParser.kt index 9646b846..a1e91094 100644 --- a/SoraStream/src/main/kotlin/com/hexated/SoraParser.kt +++ b/SoraStream/src/main/kotlin/com/hexated/SoraParser.kt @@ -336,16 +336,12 @@ data class VizcloudSources( @JsonProperty("file") val file: String? = null, ) -data class VizcloudMedia( +data class VizcloudResult( @JsonProperty("sources") val sources: ArrayList? = arrayListOf(), ) -data class VizcloudData( - @JsonProperty("media") val media: VizcloudMedia? = null, -) - data class VizcloudResponses( - @JsonProperty("data") val data: VizcloudData? = null, + @JsonProperty("result") val result: VizcloudResult? = null, ) data class AnilistExternalLinks( @@ -405,15 +401,15 @@ data class CrunchyrollSourcesResponses( @JsonProperty("meta") val meta: CrunchyrollMeta? = null, ) -data class MALSyncPages( +data class MALSyncSites( @JsonProperty("Zoro") val zoro: HashMap>? = hashMapOf(), ) data class MALSyncResponses( - @JsonProperty("Pages") val pages: MALSyncPages? = null, + @JsonProperty("Sites") val sites: MALSyncSites? = null, ) -data class ZoroResponses( +data class AniwatchResponses( @JsonProperty("html") val html: String? = null, @JsonProperty("link") val link: String? = null, ) diff --git a/SoraStream/src/main/kotlin/com/hexated/SoraStream.kt b/SoraStream/src/main/kotlin/com/hexated/SoraStream.kt index e0744b10..16d00b6b 100644 --- a/SoraStream/src/main/kotlin/com/hexated/SoraStream.kt +++ b/SoraStream/src/main/kotlin/com/hexated/SoraStream.kt @@ -16,7 +16,6 @@ import com.hexated.SoraExtractor.invokeMovieHab import com.hexated.SoraExtractor.invokeNoverse import com.hexated.SoraExtractor.invokeSeries9 import com.hexated.SoraExtractor.invokeVidSrc -import com.hexated.SoraExtractor.invokeXmovies import com.lagradost.cloudstream3.* import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer import com.lagradost.cloudstream3.metaproviders.TmdbProvider @@ -100,7 +99,7 @@ open class SoraStream : TmdbProvider() { const val filmxyAPI = "https://www.filmxy.vip" const val kimcartoonAPI = "https://kimcartoon.li" const val xMovieAPI = "https://xemovies.to" - const val zoroAPI = "https://kaido.to" + const val aniwatchAPI = "https://aniwatch.to" const val crunchyrollAPI = "https://beta-api.crunchyroll.com" const val kissKhAPI = "https://kisskh.co" const val lingAPI = "https://ling-online.net" @@ -120,7 +119,7 @@ open class SoraStream : TmdbProvider() { const val smashyStreamAPI = "https://embed.smashystream.com" const val watchSomuchAPI = "https://watchsomuch.tv" // sub only val gomoviesAPI = base64DecodeAPI("bQ==Y28=ZS4=aW4=bmw=LW8=ZXM=dmk=bW8=Z28=Ly8=czo=dHA=aHQ=") - const val ask4MoviesAPI = "https://ask4movie.net" + const val ask4MoviesAPI = "https://ask4movie.nl" const val biliBiliAPI = "https://api-vn.otakuz.live/server" const val watchOnlineAPI = "https://watchonline.ag" const val nineTvAPI = "https://api.9animetv.live" diff --git a/SoraStream/src/main/kotlin/com/hexated/SoraUtils.kt b/SoraStream/src/main/kotlin/com/hexated/SoraUtils.kt index 524470c6..5f2ae0fd 100644 --- a/SoraStream/src/main/kotlin/com/hexated/SoraUtils.kt +++ b/SoraStream/src/main/kotlin/com/hexated/SoraUtils.kt @@ -21,6 +21,7 @@ import com.lagradost.cloudstream3.APIHolder.getCaptchaToken import com.lagradost.cloudstream3.APIHolder.unixTimeMS import com.lagradost.cloudstream3.mvvm.suspendSafeApiCall import com.lagradost.cloudstream3.utils.* +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.Coroutines.ioSafe @@ -417,7 +418,7 @@ suspend fun invokeVizcloud( ) { val id = Regex("(?:/embed[-/]|/e/)([^?/]*)").find(url)?.groupValues?.getOrNull(1) app.get("$consumetHelper?query=${id ?: return}&action=vizcloud") - .parsedSafe()?.data?.media?.sources?.map { + .parsedSafe()?.result?.sources?.map { M3u8Helper.generateM3u8( "Vizcloud", it.file ?: return@map, @@ -563,6 +564,39 @@ suspend fun invokeSmashyRip( } +suspend fun invokeSmashyIm( + name: String, + url: String, + subtitleCallback: (SubtitleFile) -> Unit, + callback: (ExtractorLink) -> Unit, +) { + val script = + app.get(url).document.selectFirst("script:containsData(player =)")?.data() ?: return + + val sources = + Regex("['\"]?file['\"]?:\\s*\"([^\"]+)").find(script)?.groupValues?.get(1) ?: return + val subtitles = + Regex("['\"]?subtitle['\"]?:\\s*\"([^\"]+)").find(script)?.groupValues?.get(1) ?: return + + M3u8Helper.generateM3u8( + "Smashy [$name]", + sources, + "" + ).forEach(callback) + + subtitles.split(",").map { sub -> + val lang = Regex("\\[(.*?)]").find(sub)?.groupValues?.getOrNull(1)?.trim() + val trimmedSubLink = sub.removePrefix("[$lang]").trim().substringAfter("?url=") + subtitleCallback.invoke( + SubtitleFile( + lang.takeIf { !it.isNullOrEmpty() } ?: return@map, + trimmedSubLink + ) + ) + } + +} + suspend fun getDumpIdAndType(title: String?, year: Int?, season: Int?): Pair { val res = tryParseJson( queryApi( @@ -922,7 +956,7 @@ suspend fun searchWatchOnline( } //modified code from https://github.com/jmir1/aniyomi-extensions/blob/master/src/all/kamyroll/src/eu/kanade/tachiyomi/animeextension/all/kamyroll/AccessTokenInterceptor.kt -fun getCrunchyrollToken(): Map { +suspend fun getCrunchyrollToken(): Map { val client = app.baseClient.newBuilder() .proxy(Proxy(Proxy.Type.SOCKS, InetSocketAddress("cr-unblocker.us.to", 1080))) .build() @@ -942,7 +976,7 @@ fun getCrunchyrollToken(): Map { "Authorization" to "Basic ${BuildConfig.CRUNCHYROLL_BASIC_TOKEN}" ), data = mapOf( - "refresh_token" to BuildConfig.CRUNCHYROLL_REFRESH_TOKEN, + "refresh_token" to app.get(BuildConfig.CRUNCHYROLL_REFRESH_TOKEN).text, "grant_type" to "refresh_token", "scope" to "offline_access" ) @@ -1807,8 +1841,8 @@ object RabbitStream { if (sources == null || encryptedMap.encrypted == false) { response.parsedSafe() } else { - val decrypted = - decryptMapped>(sources, decryptKey) + val (realKey, encData) = extractRealKey(sources, decryptKey) + val decrypted = decryptMapped>(encData, realKey) SourceObject( sources = decrypted, tracks = encryptedMap.tracks @@ -1951,7 +1985,21 @@ object RabbitStream { } suspend fun getZoroKey(): String { - return app.get("https://raw.githubusercontent.com/enimax-anime/key/e0/key.txt").text + return app.get("https://raw.githubusercontent.com/enimax-anime/key/e6/key.txt").text + } + + private fun extractRealKey(originalString: String?, stops: String) : Pair { + val table = parseJson>>(stops) + val decryptedKey = StringBuilder() + var offset = 0 + var encryptedString = originalString + + table.forEach { (start, end) -> + decryptedKey.append(encryptedString?.substring(start - offset, end - offset)) + encryptedString = encryptedString?.substring(0, start - offset) + encryptedString?.substring(end - offset) + offset += end - start + } + return decryptedKey.toString() to encryptedString.toString() } private inline fun decryptMapped(input: String, key: String): T? { diff --git a/TimefourTv/build.gradle.kts b/TimefourTv/build.gradle.kts index fa742b08..3fb6e15e 100644 --- a/TimefourTv/build.gradle.kts +++ b/TimefourTv/build.gradle.kts @@ -1,5 +1,5 @@ // use an integer for version numbers -version = 14 +version = 16 cloudstream { diff --git a/TimefourTv/src/main/kotlin/com/hexated/TimefourTv.kt b/TimefourTv/src/main/kotlin/com/hexated/TimefourTv.kt index d1a32510..7b68e7a7 100644 --- a/TimefourTv/src/main/kotlin/com/hexated/TimefourTv.kt +++ b/TimefourTv/src/main/kotlin/com/hexated/TimefourTv.kt @@ -19,8 +19,11 @@ open class TimefourTv : MainAPI() { ) companion object { - const val daddyUrl = "https://daddylive.watch" - val daddyHost: String = URI(daddyUrl).host.split(".").first() + const val daddyUrl = "https://daddylivehd.com" + val daddyHost: String = daddyUrl.getHost() + private fun String.getHost(): String { + return URI(this).host.substringBeforeLast(".").substringAfterLast(".") + } } override val mainPage = mainPageOf( diff --git a/TimefourTv/src/main/kotlin/com/hexated/TimefourTvExtractor.kt b/TimefourTv/src/main/kotlin/com/hexated/TimefourTvExtractor.kt index c56fae01..57d484a2 100644 --- a/TimefourTv/src/main/kotlin/com/hexated/TimefourTvExtractor.kt +++ b/TimefourTv/src/main/kotlin/com/hexated/TimefourTvExtractor.kt @@ -72,7 +72,7 @@ object TimefourTvExtractor : TimefourTv() { return getSportLink(url) } - if(url.contains(daddyHost)) { + if(url.contains(daddyHost, true)) { mainServer = getBaseUrl(url) return getFinalLink(app.get(url, referer = daddyUrl)) } diff --git a/YomoviesProvider/build.gradle.kts b/YomoviesProvider/build.gradle.kts index 8b53037f..f5249c1c 100644 --- a/YomoviesProvider/build.gradle.kts +++ b/YomoviesProvider/build.gradle.kts @@ -1,12 +1,12 @@ // use an integer for version numbers -version = 15 +version = 17 cloudstream { language = "hi" // All of these properties are optional, you can safely remove them - // description = "Lorem Ipsum" + description = "Include: Watchomovies" authors = listOf("Hexated") /** diff --git a/YomoviesProvider/src/main/kotlin/com/hexated/Watchomovies.kt b/YomoviesProvider/src/main/kotlin/com/hexated/Watchomovies.kt new file mode 100644 index 00000000..cca19de1 --- /dev/null +++ b/YomoviesProvider/src/main/kotlin/com/hexated/Watchomovies.kt @@ -0,0 +1,27 @@ +package com.hexated + +import com.lagradost.cloudstream3.LoadResponse +import com.lagradost.cloudstream3.TvType +import com.lagradost.cloudstream3.mainPageOf + +class Watchomovies : YomoviesProvider() { + override var mainUrl = "https://watchomovies.mom" + override var name = "Watchomovies" + override var lang = "en" + override val supportedTypes = setOf( + TvType.NSFW, + ) + + override val mainPage = mainPageOf( + "most-favorites" to "Most Viewed", + "genre/xxx-scenes" to "XXX Scenes", + "genre/18" to "18+ Movies", + "genre/erotic-movies" to "Erotic Movies Movies", + "genre/parody" to "Parody Movies", + "genre/tv-shows" to "TV Shows Movies", + ) + + override suspend fun load(url: String): LoadResponse? { + return super.load(url).apply { this?.type = TvType.NSFW } + } +} \ No newline at end of file diff --git a/YomoviesProvider/src/main/kotlin/com/hexated/YomoviesProvider.kt b/YomoviesProvider/src/main/kotlin/com/hexated/YomoviesProvider.kt index ac5e991f..1b2bd2a0 100644 --- a/YomoviesProvider/src/main/kotlin/com/hexated/YomoviesProvider.kt +++ b/YomoviesProvider/src/main/kotlin/com/hexated/YomoviesProvider.kt @@ -9,37 +9,32 @@ import com.lagradost.cloudstream3.utils.loadExtractor import org.jsoup.nodes.Element import java.net.URI -class YomoviesProvider : MainAPI() { +open class YomoviesProvider : MainAPI() { override var mainUrl = "https://yomovies.baby" - private var directUrl = mainUrl + private var directUrl = "" override var name = "Yomovies" override val hasMainPage = true override var lang = "hi" - override val hasDownloadSupport = true override val supportedTypes = setOf( TvType.Movie, TvType.TvSeries, ) override val mainPage = mainPageOf( - "$mainUrl/most-favorites/page/" to "Most Viewed", - "$mainUrl/genre/web-series/page/" to "Web Series Movies", - "$mainUrl/genre/dual-audio/page/" to "Dual Audio Movies", - "$mainUrl/genre/bollywood/page/" to "Bollywood Movies", - "$mainUrl/genre/tv-shows/page/" to "TV Shows Movies", - "$mainUrl/genre/hollywood/page/" to "Hollywood Movies", - "$mainUrl/series/page/" to "All TV Series", + "most-favorites" to "Most Viewed", + "genre/web-series" to "Web Series Movies", + "genre/dual-audio" to "Dual Audio Movies", + "genre/bollywood" to "Bollywood Movies", + "genre/tv-shows" to "TV Shows Movies", + "genre/hollywood" to "Hollywood Movies", + "series" to "All TV Series", ) override suspend fun getMainPage( page: Int, request: MainPageRequest ): HomePageResponse { - val document = if (page == 1) { - app.get(request.data.removeSuffix("page/")).document - } else { - app.get(request.data + page).document - } + val document = app.get("$mainUrl/${request.data}/page/$page").document val home = document.select("div.ml-item").mapNotNull { it.toSearchResult() } @@ -129,12 +124,6 @@ class YomoviesProvider : MainAPI() { } } - private fun getBaseUrl(url: String): String { - return URI(url).let { - "${it.scheme}://${it.host}" - } - } - override suspend fun loadLinks( data: String, isCasting: Boolean, @@ -175,4 +164,10 @@ class YomoviesProvider : MainAPI() { return fixTitle(URI(this).host.substringBeforeLast(".").substringAfterLast(".")) } + private fun getBaseUrl(url: String): String { + return URI(url).let { + "${it.scheme}://${it.host}" + } + } + } diff --git a/YomoviesProvider/src/main/kotlin/com/hexated/YomoviesProviderPlugin.kt b/YomoviesProvider/src/main/kotlin/com/hexated/YomoviesProviderPlugin.kt index 72cbcd16..45bf3e5a 100644 --- a/YomoviesProvider/src/main/kotlin/com/hexated/YomoviesProviderPlugin.kt +++ b/YomoviesProvider/src/main/kotlin/com/hexated/YomoviesProviderPlugin.kt @@ -10,5 +10,6 @@ class YomoviesProviderPlugin: Plugin() { override fun load(context: Context) { // All providers should be added in this manner. Please don't edit the providers list directly. registerMainAPI(YomoviesProvider()) + registerMainAPI(Watchomovies()) } } \ No newline at end of file