diff --git a/SxyPrn/build.gradle.kts b/Example/build.gradle.kts
similarity index 71%
rename from SxyPrn/build.gradle.kts
rename to Example/build.gradle.kts
index 9100e9b..aad9fd6 100644
--- a/SxyPrn/build.gradle.kts
+++ b/Example/build.gradle.kts
@@ -1,12 +1,12 @@
// use an integer for version numbers
-version = 6
+version = 1
cloudstream {
// All of these properties are optional, you can safely remove them
- description = "sxyprn"
- authors = listOf("Coxju")
+ description = ""
+ authors = listOf("Jace")
/**
* Status int as the following:
@@ -15,14 +15,12 @@ cloudstream {
* 2: Slow
* 3: Beta only
* */
- status = 1 // will be 3 if unspecified
+ status = 0 // will be 3 if unspecified
// List of video source types. Users are able to filter for extensions in a given category.
// You can find a list of avaliable types here:
// https://recloudstream.github.io/cloudstream/html/app/com.lagradost.cloudstream3/-tv-type/index.html
tvTypes = listOf("NSFW")
- iconUrl = "https://www.google.com/s2/favicons?domain=sxyprn.com&sz=%size%"
-
- language = "en"
+ iconUrl = "https://www.google.com/s2/favicons?domain=example.com&sz=%size%"
}
diff --git a/FullPorner/src/main/AndroidManifest.xml b/Example/src/main/AndroidManifest.xml
similarity index 52%
rename from FullPorner/src/main/AndroidManifest.xml
rename to Example/src/main/AndroidManifest.xml
index 3f4d39b..29aec9d 100644
--- a/FullPorner/src/main/AndroidManifest.xml
+++ b/Example/src/main/AndroidManifest.xml
@@ -1,2 +1,2 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/Example/src/main/kotlin/com/jacekun/Example.kt b/Example/src/main/kotlin/com/jacekun/Example.kt
new file mode 100644
index 0000000..1aad8d1
--- /dev/null
+++ b/Example/src/main/kotlin/com/jacekun/Example.kt
@@ -0,0 +1,9 @@
+package com.jacekun
+
+import com.lagradost.cloudstream3.MainAPI
+import com.lagradost.cloudstream3.TvType
+
+class Example : MainAPI() {
+ private val DEV = "DevDebug"
+ private val globaltvType = TvType.Movie
+}
\ No newline at end of file
diff --git a/Xhamster/src/main/kotlin/com/KillerDogeEmpire/XhamsterProvider.kt b/Example/src/main/kotlin/com/jacekun/ExamplePlugin.kt
similarity index 75%
rename from Xhamster/src/main/kotlin/com/KillerDogeEmpire/XhamsterProvider.kt
rename to Example/src/main/kotlin/com/jacekun/ExamplePlugin.kt
index 6dc7711..bdef9af 100644
--- a/Xhamster/src/main/kotlin/com/KillerDogeEmpire/XhamsterProvider.kt
+++ b/Example/src/main/kotlin/com/jacekun/ExamplePlugin.kt
@@ -1,13 +1,13 @@
-package com.KillerDogeEmpire
+package com.jacekun
import com.lagradost.cloudstream3.plugins.CloudstreamPlugin
import com.lagradost.cloudstream3.plugins.Plugin
import android.content.Context
@CloudstreamPlugin
-class XhamsterProvider: Plugin() {
+class ExamplePlugin: Plugin() {
override fun load(context: Context) {
// All providers should be added in this manner. Please don't edit the providers list directly.
- registerMainAPI(Xhamster())
+ registerMainAPI(Example())
}
}
\ No newline at end of file
diff --git a/FullPorner/build.gradle.kts b/FullPorner/build.gradle.kts
deleted file mode 100644
index 1dce6ab..0000000
--- a/FullPorner/build.gradle.kts
+++ /dev/null
@@ -1,18 +0,0 @@
-version = 4
-
-cloudstream {
- authors = listOf("KillerDogeEmpire, Coxju")
- language = "en"
- description = "FullPorner is the best free full length porn video site. Choose from millions of hardcore videos that stream quickly and in high quality and only full length"
-
- /**
- * Status int as the following:
- * 0: Down
- * 1: Ok
- * 2: Slow
- * 3: Beta only
- **/
- status = 1 // will be 3 if unspecified
- tvTypes = listOf("NSFW")
- iconUrl = "https://www.google.com/s2/favicons?domain=fullporner.com&sz=%size%"
-}
diff --git a/FullPorner/src/main/kotlin/com/KillerDogeEmpire/FullPorner.kt b/FullPorner/src/main/kotlin/com/KillerDogeEmpire/FullPorner.kt
deleted file mode 100644
index 071e9eb..0000000
--- a/FullPorner/src/main/kotlin/com/KillerDogeEmpire/FullPorner.kt
+++ /dev/null
@@ -1,162 +0,0 @@
-package com.KillerDogeEmpire
-
-import org.jsoup.nodes.Element
-import com.lagradost.cloudstream3.*
-import com.lagradost.cloudstream3.utils.*
-import com.lagradost.cloudstream3.network.WebViewResolver
-import com.lagradost.cloudstream3.LoadResponse.Companion.addActors
-import org.jsoup.Jsoup
-
-class FullPorner : MainAPI() {
- override var mainUrl = "https://fullporner.com"
- override var name = "FullPorner"
- override val hasMainPage = true
- override var lang = "en"
- override val hasQuickSearch = false
- override val hasDownloadSupport = true
- override val hasChromecastSupport = true
- override val supportedTypes = setOf(TvType.NSFW)
- override val vpnStatus = VPNStatus.MightBeNeeded
-
- override val mainPage = mainPageOf(
- "${mainUrl}/home/" to "Featured",
- "${mainUrl}/category/amateur/" to "Amateur",
- "${mainUrl}/category/teen/" to "Teen",
- "${mainUrl}/category/cumshot/" to "CumShot",
- "${mainUrl}/category/deepthroat/" to "DeepThroat",
- "${mainUrl}/category/orgasm/" to "Orgasm",
- "${mainUrl}/category/threesome/" to "ThreeSome",
- "${mainUrl}/category/group-sex/" to "Group Sex",
- )
-
- override suspend fun getMainPage(page: Int, request: MainPageRequest): HomePageResponse {
- val document = app.get("${request.data}${page}").document
- val home = document.select("div.video-block div.video-card").mapNotNull { it.toSearchResult() }
-
- return newHomePageResponse(
- list = HomePageList(
- name = request.name,
- list = home,
- isHorizontalImages = true
- ),
- hasNext = true
- )
- }
-
- private fun Element.toSearchResult(): SearchResponse? {
- val title = this.selectFirst("div.video-card div.video-card-body div.video-title a")?.text() ?: return null
- val href = fixUrl(this.selectFirst("div.video-card div.video-card-body div.video-title a")!!.attr("href"))
- val posterUrl = fixUrlNull(this.select("div.video-card div.video-card-image a img").attr("data-src"))
-
- return newMovieSearchResponse(title, href, TvType.Movie) { this.posterUrl = posterUrl }
- }
-
- override suspend fun search(query: String): List {
- val searchResponse = mutableListOf()
-
- for (i in 1..15) {
- val document = app.get("${mainUrl}/search?q=${query.replace(" ", "+")}&p=$i").document
-
- val results = document.select("div.video-block div.video-card").mapNotNull { it.toSearchResult() }
-
- searchResponse.addAll(results)
-
- if (results.isEmpty()) break
- }
-
- return searchResponse
- }
-
- override suspend fun load(url: String): LoadResponse {
- val document = app.get(url).document
-
- val title = document.selectFirst("div.video-block div.single-video-left div.single-video-title h2")?.text()?.trim().toString()
- val iframeUrl = fixUrlNull(document.selectFirst("div.video-block div.single-video-left div.single-video iframe")?.attr("src")) ?: ""
-
- val poster: String?
- val posterHeaders: Map
- if (iframeUrl.contains("videoh")) {
- val iframeDocument = app.get(iframeUrl, interceptor = WebViewResolver(Regex("""mydaddy"""))).document
-
- val videoHtml = iframeDocument.selectXpath("//script[contains(text(),'poster')]").first()?.html()?.substringAfter("else{ \$(\"#jw\").html(\"")?.substringBefore("\");}if(hasAdblock)")?.replace("\\", "")
- val video = Jsoup.parse(videoHtml.toString()).selectFirst("video")
-
- poster = fixUrlNull(video?.attr("poster"))
- posterHeaders = mapOf(Pair("referer", "https://mydaddy.cc/"))
- } else {
- val iframeDocument = app.get(iframeUrl).document
- val videoDocument = Jsoup.parse("")
-
- poster = fixUrlNull(videoDocument.selectFirst("video")?.attr("poster").toString())
- posterHeaders = mapOf(Pair("referer", "https://xiaoshenke.net/"))
- }
-
- val tags = document.select("div.video-blockdiv.single-video-left div.single-video-title p.tag-link span a").map { it.text() }
- val description = document.selectFirst("div.video-block div.single-video-left div.single-video-title h2")?.text()?.trim().toString()
- val actors = document.select("div.video-block div.single-video-left div.single-video-info-content p a").map { it.text() }
- val recommendations = document.select("div.video-block div.video-recommendation div.video-card").mapNotNull { it.toSearchResult() }
-
- return newMovieLoadResponse(title, url, TvType.NSFW, url) {
- this.posterUrl = poster
- this.posterHeaders = posterHeaders
- this.plot = description
- this.tags = tags
- this.recommendations = recommendations
- addActors(actors)
- }
- }
-
- override suspend fun loadLinks(data: String, isCasting: Boolean, subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit): Boolean {
- val document = app.get(data).document
-
- val iframeUrl = fixUrlNull(document.selectFirst("div.video-block div.single-video-left div.single-video iframe")?.attr("src")) ?: ""
-
- val extlinkList = mutableListOf()
- if (iframeUrl.contains("videoh")) {
- val iframeDocument = app.get(iframeUrl, interceptor = WebViewResolver(Regex("""mydaddy"""))).document
- val videoDocument = Jsoup.parse("")
-
- videoDocument.select("source").map { res ->
- extlinkList.add(ExtractorLink(
- name,
- name,
- fixUrl(res.attr("src")),
- referer = data,
- quality = Regex("(\\d+.)").find(res.attr("title"))?.groupValues?.get(1).let { getQualityFromName(it) }
- ))
- }
- } else if (iframeUrl.contains("xiaoshenke")) {
- val iframeDocument = app.get(iframeUrl).document
- val videoID = Regex("""var id = \"(.+?)\"""").find(iframeDocument.html())?.groupValues?.get(1)
-
- val pornTrexDocument = app.get("https://www.porntrex.com/embed/${videoID}").document
- val video_url = fixUrlNull(Regex("""video_url: \'(.+?)\',""").find(pornTrexDocument.html())?.groupValues?.get(1))
- if (video_url != null) {
- extlinkList.add(ExtractorLink(
- name,
- name,
- video_url,
- referer = data,
- quality = Qualities.Unknown.value
- ))
- }
- } else {
- val iframeDocument = app.get(iframeUrl).document
- val videoDocument = Jsoup.parse("")
-
- videoDocument.select("source").map { res ->
- extlinkList.add(ExtractorLink(
- this.name,
- this.name,
- fixUrl(res.attr("src")),
- referer = mainUrl,
- quality = Regex("(\\d+.)").find(res.attr("title"))?.groupValues?.get(1).let { getQualityFromName(it) }
- ))
- }
- }
-
- extlinkList.forEach(callback)
-
- return true
- }
-}
\ No newline at end of file
diff --git a/FullPorner/src/main/kotlin/com/KillerDogeEmpire/FullPornerProvider.kt b/FullPorner/src/main/kotlin/com/KillerDogeEmpire/FullPornerProvider.kt
deleted file mode 100644
index 5ff8087..0000000
--- a/FullPorner/src/main/kotlin/com/KillerDogeEmpire/FullPornerProvider.kt
+++ /dev/null
@@ -1,12 +0,0 @@
-package com.KillerDogeEmpire
-
-import android.content.Context
-import com.lagradost.cloudstream3.plugins.CloudstreamPlugin
-import com.lagradost.cloudstream3.plugins.Plugin
-
-@CloudstreamPlugin
-class FullPornerProvider : Plugin() {
- override fun load(context: Context) {
- registerMainAPI(FullPorner())
- }
-}
\ No newline at end of file
diff --git a/GoodPorn/build.gradle.kts b/GoodPorn/build.gradle.kts
deleted file mode 100644
index fc3c883..0000000
--- a/GoodPorn/build.gradle.kts
+++ /dev/null
@@ -1,28 +0,0 @@
-// use an integer for version numbers
-version = 5
-
-
-cloudstream {
- // All of these properties are optional, you can safely remove them
-
- description = "GoodPorn"
- authors = listOf(" KillerDogeEmpire, Stormunblessed, Jace, Hexated, Coxju")
-
- /**
- * Status int as the following:
- * 0: Down
- * 1: Ok
- * 2: Slow
- * 3: Beta only
- * */
- status = 1 // will be 3 if unspecified
-
- // List of video source types. Users are able to filter for extensions in a given category.
- // You can find a list of avaliable types here:
- // https://recloudstream.github.io/cloudstream/html/app/com.lagradost.cloudstream3/-tv-type/index.html
- tvTypes = listOf("NSFW")
-
- iconUrl = "https://www.google.com/s2/favicons?domain=goodporn.to&sz=%size%"
-
- language = "en"
-}
diff --git a/GoodPorn/src/main/AndroidManifest.xml b/GoodPorn/src/main/AndroidManifest.xml
deleted file mode 100644
index 0862a59..0000000
--- a/GoodPorn/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,2 +0,0 @@
-
-
\ No newline at end of file
diff --git a/GoodPorn/src/main/kotlin/com/KillerDogeEmpire/GoodPorn.kt b/GoodPorn/src/main/kotlin/com/KillerDogeEmpire/GoodPorn.kt
deleted file mode 100644
index 06e462d..0000000
--- a/GoodPorn/src/main/kotlin/com/KillerDogeEmpire/GoodPorn.kt
+++ /dev/null
@@ -1,127 +0,0 @@
-package com.KillerDogeEmpire
-
-import com.lagradost.cloudstream3.*
-import com.lagradost.cloudstream3.LoadResponse.Companion.addActors
-import com.lagradost.cloudstream3.utils.ExtractorLink
-import com.lagradost.cloudstream3.utils.getQualityFromName
-import org.jsoup.nodes.Element
-import java.util.*
-
-class GoodPorn : MainAPI() {
- override var mainUrl = "https://goodporn.to"
- override var name = "GoodPorn"
- override val hasMainPage = true
- override val hasDownloadSupport = true
- override val vpnStatus = VPNStatus.MightBeNeeded
- override val supportedTypes = setOf(TvType.NSFW)
-
- override val mainPage = mainPageOf(
- "$mainUrl/?mode=async&function=get_block&block_id=list_videos_most_recent_videos&sort_by=post_date&from=" to "New Videos",
- "$mainUrl/?mode=async&function=get_block&block_id=list_videos_most_recent_videos&sort_by=video_viewed&from=" to "Most Viewed Videos",
- "$mainUrl/?mode=async&function=get_block&block_id=list_videos_most_recent_videos&sort_by=rating&from=" to "Top Rated Videos ",
- "$mainUrl/?mode=async&function=get_block&block_id=list_videos_most_recent_videos&sort_by=most_commented&from=" to "Most Commented Videos",
- "$mainUrl/?mode=async&function=get_block&block_id=list_videos_most_recent_videos&sort_by=duration&from=" to "Longest Videos",
- "$mainUrl/sites/fitness-rooms/?mode=async&function=get_block&block_id=list_videos_common_videos_list&sort_by=post_date&from=" to "Fitness Rooms",
- "$mainUrl/sites/public-agent/?mode=async&function=get_block&block_id=list_videos_common_videos_list&sort_by=post_date&from=" to "Public Agent",
- "$mainUrl/sites/massage-rooms/?mode=async&function=get_block&block_id=list_videos_common_videos_list&sort_by=post_date&from=" to "Massage Rooms",
- "$mainUrl/sites/dane-jones/?mode=async&function=get_block&block_id=list_videos_common_videos_list&sort_by=post_date&from=" to "Dane Jones",
- "$mainUrl/channels/brazzers/?mode=async&function=get_block&block_id=list_videos_common_videos_list&sort_by=post_date&from=" to "Brazzers",
- "$mainUrl/channels/digitalplayground/?mode=async&function=get_block&block_id=list_videos_common_videos_list&sort_by=post_date&from=" to "Digital Playground",
- "$mainUrl/channels/realitykings/?mode=async&function=get_block&block_id=list_videos_common_videos_list&sort_by=post_date&from=" to "Realitykings",
- "$mainUrl/channels/babes-network/?mode=async&function=get_block&block_id=list_videos_common_videos_list&sort_by=post_date&from=" to "Babes Network",
- )
-
- override suspend fun getMainPage(
- page: Int, request: MainPageRequest
- ): HomePageResponse {
- val document = app.get(request.data + page).document
- val home =
- document.select("div#list_videos_most_recent_videos_items div.item, div#list_videos_common_videos_list_items div.item")
- .mapNotNull {
- it.toSearchResult()
- }
- return newHomePageResponse(
- list = HomePageList(
- name = request.name, list = home, isHorizontalImages = true
- ), hasNext = true
- )
- }
-
- private fun Element.toSearchResult(): SearchResponse? {
- val title = this.selectFirst("strong.title")?.text() ?: return null
- val href = fixUrl(this.selectFirst("a")!!.attr("href"))
- val posterUrl = fixUrlNull(this.select("div.img > img").attr("data-original"))
- return newMovieSearchResponse(title, href, TvType.Movie) {
- this.posterUrl = posterUrl
- }
-
- }
-
- override suspend fun search(query: String): List {
- val searchResponse = mutableListOf()
- for (i in 1..15) {
- val document = app.get(
- "$mainUrl/search/nikki-benz/?mode=async&function=get_block&block_id=list_videos_videos_list_search_result&q=$query&category_ids=&sort_by=&from_videos=$i&from_albums=$i",
- headers = mapOf("X-Requested-With" to "XMLHttpRequest")
- ).document
- val results =
- document.select("div#list_videos_videos_list_search_result_items div.item")
- .mapNotNull {
- it.toSearchResult()
- }
- searchResponse.addAll(results)
- if (results.isEmpty()) break
- }
- return searchResponse
- }
-
- override suspend fun load(url: String): LoadResponse {
- val document = app.get(url).document
-
- val title = document.selectFirst("div.headline > h1")?.text()?.trim().toString()
- val poster =
- fixUrlNull(document.selectFirst("meta[property=og:image]")?.attr("content").toString())
- val tags = document.select("div.info div:nth-child(5) > a").map { it.text() }
- val description = document.select("div.info div:nth-child(2)").text().trim()
- val actors = document.select("div.info div:nth-child(6) > a").map { it.text() }
- val recommendations =
- document.select("div#list_videos_related_videos_items div.item").mapNotNull {
- it.toSearchResult()
- }
-
- return newMovieLoadResponse(title, url, TvType.NSFW, url) {
- this.posterUrl = poster
- this.plot = description
- this.tags = tags
- addActors(actors)
- 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 extlinkList = mutableListOf()
- document.select("div.info div:last-child a").map { res ->
- extlinkList.add(
- ExtractorLink(
- this.name,
- this.name,
- res.attr("href")
- .replace(Regex("\\?download\\S+.mp4&"), "?") + "&rnd=${Date().time}",
- referer = data,
- quality = Regex("(\\d+.),").find(res.text())?.groupValues?.get(1)
- .let { getQualityFromName(it) },
- headers = mapOf("Range" to "bytes=0-"),
- )
- )
- }
- extlinkList.forEach(callback)
- return true
- }
-
-}
\ No newline at end of file
diff --git a/GoodPorn/src/main/kotlin/com/KillerDogeEmpire/GoodPornProvider.kt b/GoodPorn/src/main/kotlin/com/KillerDogeEmpire/GoodPornProvider.kt
deleted file mode 100644
index 2622474..0000000
--- a/GoodPorn/src/main/kotlin/com/KillerDogeEmpire/GoodPornProvider.kt
+++ /dev/null
@@ -1,14 +0,0 @@
-package com.KillerDogeEmpire
-
-import android.content.Context
-import com.KillerDogeEmpire.GoodPorn
-import com.lagradost.cloudstream3.plugins.CloudstreamPlugin
-import com.lagradost.cloudstream3.plugins.Plugin
-
-@CloudstreamPlugin
-class GoodPornProvider : Plugin() {
- override fun load(context: Context) {
- // All providers should be added in this manner. Please don't edit the providers list directly.
- registerMainAPI(GoodPorn())
- }
-}
\ No newline at end of file
diff --git a/HentaiHaven/build.gradle.kts b/HentaiHaven/build.gradle.kts
index 7fa8fcf..9f1c8b3 100644
--- a/HentaiHaven/build.gradle.kts
+++ b/HentaiHaven/build.gradle.kts
@@ -1,12 +1,12 @@
// use an integer for version numbers
-version = 6
+version = 5
cloudstream {
// All of these properties are optional, you can safely remove them
description = ""
- authors = listOf("KillerDogeEmpire, Jace")
+ authors = listOf("Jace")
/**
* Status int as the following:
diff --git a/HentaiHaven/src/main/kotlin/com/jacekun/HentaiHaven.kt b/HentaiHaven/src/main/kotlin/com/jacekun/HentaiHaven.kt
index 24d2c19..e88f9fe 100644
--- a/HentaiHaven/src/main/kotlin/com/jacekun/HentaiHaven.kt
+++ b/HentaiHaven/src/main/kotlin/com/jacekun/HentaiHaven.kt
@@ -1,99 +1,101 @@
package com.jacekun
-
+import android.util.Log
import com.fasterxml.jackson.annotation.JsonProperty
import com.lagradost.cloudstream3.*
-import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer
-import com.lagradost.cloudstream3.utils.*
-import okhttp3.FormBody
-import org.jsoup.nodes.Element
-
+import com.lagradost.cloudstream3.mvvm.logError
+import com.lagradost.cloudstream3.utils.ExtractorLink
+import com.lagradost.cloudstream3.utils.getQualityFromName
+import org.jsoup.select.Elements
class HentaiHaven : MainAPI() {
- override var mainUrl = "https://hentaihaven.xxx"
+ private val globalTvType = TvType.NSFW
override var name = "Hentai Haven"
- override val hasMainPage = true
- override var lang = "en"
- override val hasDownloadSupport = true
-
- override val supportedTypes = setOf(
- TvType.NSFW)
-
- override val mainPage = mainPageOf(
- "?m_orderby=new-manga" to "New",
- "?m_orderby=views" to "Most Views",
- "?m_orderby=rating" to "Rating",
- "?m_orderby=alphabet" to "A-Z",
- )
+ override var mainUrl = "https://hentaihaven.xxx"
+ override val supportedTypes = setOf(TvType.NSFW)
+ override val hasDownloadSupport = false
+ override val hasMainPage= true
+ override val hasQuickSearch = false
override suspend fun getMainPage(
page: Int,
request: MainPageRequest
): HomePageResponse {
- val document = app.get("$mainUrl/page/$page/${request.data}").document
- val home =
- document.select("div.page-listing-item div.col-6.col-md-zarat.badge-pos-1").mapNotNull {
- it.toSearchResult()
+ val doc = app.get(mainUrl).document
+ val all = ArrayList()
+
+ doc.getElementsByTag("body").select("div.c-tabs-item")
+ .select("div.vraven_home_slider").forEach { it2 ->
+ // Fetch row title
+ val title = it2?.select("div.home_slider_header")?.text() ?: "Unnamed Row"
+ // Fetch list of items and map
+ it2.select("div.page-content-listing div.item.vraven_item.badge-pos-1").let { inner ->
+
+ all.add(
+ HomePageList(
+ name = title,
+ list = inner.getResults(this.name),
+ isHorizontalImages = false
+ )
+ )
+ }
}
- return newHomePageResponse(request.name, home)
- }
-
- private fun Element.toSearchResult(): AnimeSearchResponse? {
- val href = fixUrl(this.selectFirst("a")!!.attr("href"))
- val title =
- this.selectFirst("h3 a, h5 a")?.text()?.trim() ?: this.selectFirst("a")?.attr("title")
- ?: return null
- val posterUrl = fixUrlNull(this.selectFirst("img")?.attr("src"))
- val episode = this.selectFirst("span.chapter.font-meta a")?.text()?.filter { it.isDigit() }
- ?.toIntOrNull()
-
- return newAnimeSearchResponse(title, href, TvType.Anime) {
- this.posterUrl = posterUrl
- addSub(episode)
- }
+ return HomePageResponse(all)
}
override suspend fun search(query: String): List {
- val link = "$mainUrl/?s=$query&post_type=wp-manga"
- val document = app.get(link).document
-
- return document.select("div.c-tabs-item > div.c-tabs-item__content").mapNotNull {
- it.toSearchResult()
- }
+ val searchUrl = "${mainUrl}/?s=${query}&post_type=wp-manga"
+ return app.get(searchUrl).document
+ .select("div.c-tabs-item div.row.c-tabs-item__content")
+ .getResults(this.name)
}
- override suspend fun load(url: String): LoadResponse? {
- val document = app.get(url).document
+ override suspend fun load(url: String): LoadResponse {
+ //TODO: Load polishing
+ val doc = app.get(url).document
+ //Log.i(this.name, "Result => (url) ${url}")
+ val poster = doc.select("meta[property=og:image]")
+ .firstOrNull()?.attr("content")
+ val title = doc.select("meta[name=title]")
+ .firstOrNull()?.attr("content")
+ ?.toString() ?: ""
+ val descript = doc.select("div.description-summary").text()
- val title = document.selectFirst("div.post-title h1")?.text()?.trim() ?: return null
- val poster = document.select("div.summary_image img").attr("src")
- val tags = document.select("div.genres-content > a").map { it.text() }
+ val body = doc.getElementsByTag("body")
+ val episodes = body.select("div.page-content-listing.single-page")
+ .first()?.select("li")
- val description = document.select("div.description-summary p").text().trim()
- val trailer = document.selectFirst("a.trailerbutton")?.attr("href")
+ val year = episodes?.last()
+ ?.selectFirst("span.chapter-release-date")
+ ?.text()?.trim()?.takeLast(4)?.toIntOrNull()
- val episodes = document.select("div.listing-chapters_wrap ul li").mapNotNull {
- val name = it.selectFirst("a")?.text() ?: return@mapNotNull null
- val image = fixUrlNull(it.selectFirst("a img")?.attr("src"))
- val link = fixUrlNull(it.selectFirst("a")?.attr("href")) ?: return@mapNotNull null
- Episode(link, name, posterUrl = image)
- }.reversed()
-
- val recommendations =
- document.select("div.row div.col-6.col-md-zarat").mapNotNull {
- it.toSearchResult()
- }
-
- return newAnimeLoadResponse(title, url, TvType.NSFW) {
- engName = title
- posterUrl = poster
- addEpisodes(DubStatus.Subbed, episodes)
- plot = description
- this.tags = tags
- this.recommendations = recommendations
- addTrailer(trailer)
- }
+ val episodeList = episodes?.mapNotNull {
+ val innerA = it?.selectFirst("a") ?: return@mapNotNull null
+ val eplink = innerA.attr("href") ?: return@mapNotNull null
+ val epCount = innerA.text().trim().filter { a -> a.isDigit() }.toIntOrNull()
+ val imageEl = innerA.selectFirst("img")
+ val epPoster = imageEl?.attr("src") ?: imageEl?.attr("data-src")
+ Episode(
+ name = innerA.text(),
+ data = eplink,
+ posterUrl = epPoster,
+ episode = epCount,
+ )
+ } ?: listOf()
+ //Log.i(this.name, "Result => (id) ${id}")
+ return AnimeLoadResponse(
+ name = title,
+ url = url,
+ apiName = this.name,
+ type = globalTvType,
+ posterUrl = poster,
+ year = year,
+ plot = descript,
+ episodes = mutableMapOf(
+ Pair(DubStatus.Subbed, episodeList.reversed())
+ )
+ )
}
override suspend fun loadLinks(
@@ -103,66 +105,120 @@ class HentaiHaven : MainAPI() {
callback: (ExtractorLink) -> Unit
): Boolean {
- val doc = app.get(data).document
- val meta = doc.selectFirst("meta[itemprop=thumbnailUrl]")?.attr("content")?.substringAfter("/hh/")?.substringBefore("/") ?: return false
- doc.select("div.player_logic_item iframe").attr("src").let { iframe ->
- val document = app.get(iframe, referer = data).text
- val en = Regex("var\\sen\\s=\\s'(\\S+)';").find(document)?.groupValues?.getOrNull(1)
- val iv = Regex("var\\siv\\s=\\s'(\\S+)';").find(document)?.groupValues?.getOrNull(1)
+ try {
+ Log.i(name, "Loading iframe")
+ val requestLink = "${mainUrl}/wp-content/plugins/player-logic/api.php"
+ val action = "zarat_get_data_player_ajax"
+ val reA = Regex("(?<=var en =)(.*?)(?=';)", setOf(RegexOption.DOT_MATCHES_ALL))
+ val reB = Regex("(?<=var iv =)(.*?)(?=';)", setOf(RegexOption.DOT_MATCHES_ALL))
- val body = FormBody.Builder()
- .addEncoded("action", "zarat_get_data_player_ajax")
- .addEncoded("a", "$en")
- .addEncoded("b", "$iv")
- .build()
+ app.get(data).document.selectFirst("div.player_logic_item iframe")
+ ?.attr("src")?.let { epLink ->
- app.post(
- "$mainUrl/wp-content/plugins/player-logic/api.php",
-// data = mapOf(
-// "action" to "zarat_get_data_player_ajax",
-// "a" to "$en",
-// "b" to "$iv"
-// ),
- requestBody = body,
-// headers = mapOf("Sec-Fetch-Mode" to "cors")
- ).parsedSafe()?.data?.sources?.map { res ->
-// M3u8Helper.generateM3u8(
-// this.name,
-// res.src ?: return@map null,
-// referer = "$mainUrl/",
-// headers = mapOf(
-// "Origin" to mainUrl,
-// )
-// ).forEach(callback)
- callback.invoke(
- ExtractorLink(
- this.name,
- this.name,
- res.src?.replace("/hh//", "/hh/$meta/") ?: return@map null,
- referer = "",
- quality = Qualities.Unknown.value,
- isM3u8 = true
- )
- )
- }
+ Log.i(name, "Loading ep link => $epLink")
+ val scrAppGet = app.get(epLink, referer = data)
+ val scrDoc = scrAppGet.document.getElementsByTag("script").toString()
+ //Log.i(name, "Loading scrDoc => (${scrAppGet.code}) $scrDoc")
+ if (scrDoc.isNotBlank()) {
+ //en
+ val a = reA.find(scrDoc)?.groupValues?.getOrNull(1)
+ ?.trim()?.removePrefix("'") ?: ""
+ //iv
+ val b = reB.find(scrDoc)?.groupValues?.getOrNull(1)
+ ?.trim()?.removePrefix("'") ?: ""
+
+ Log.i(name, "a => $a")
+ Log.i(name, "b => $b")
+
+ val doc = app.post(
+ url = requestLink,
+ headers = mapOf(
+// Pair("mode", "cors"),
+// Pair("Content-Type", "multipart/form-data"),
+// Pair("Origin", mainUrl),
+// Pair("Host", mainUrl.split("//").last()),
+ Pair("User-Agent", USER_AGENT),
+ Pair("Sec-Fetch-Mode", "cors")
+ ),
+ data = mapOf(
+ Pair("action", action),
+ Pair("a", a),
+ Pair("b", b)
+ )
+ )
+ Log.i(name, "Response (${doc.code}) => ${doc.text}")
+ //AppUtils.tryParseJson(doc.text)
+ doc.parsedSafe()?.data?.sources?.map { m3src ->
+ val m3srcFile = m3src.src ?: return@map null
+ val label = m3src.label ?: ""
+ Log.i(name, "M3u8 link: $m3srcFile")
+ callback.invoke(
+ ExtractorLink(
+ name = "$name m3u8",
+ source = "$name m3u8",
+ url = m3srcFile,
+ referer = "$mainUrl/",
+ quality = getQualityFromName(label),
+ isM3u8 = true
+ )
+ )
+ }
+ }
+ }
+ } catch (e: Exception) {
+ Log.i(name, "Error => $e")
+ logError(e)
+ return false
}
-
return true
}
- data class Response(
- @JsonProperty("data") val data: Data? = null,
+ private fun Elements?.getResults(apiName: String): List {
+ return this?.mapNotNull {
+ val innerDiv = it.select("div").firstOrNull()
+ val firstA = innerDiv?.selectFirst("a")
+ val link = fixUrlNull(firstA?.attr("href")) ?: return@mapNotNull null
+ val name = firstA?.attr("title") ?: ""
+ val year = innerDiv?.selectFirst("span.c-new-tag")?.selectFirst("a")
+ ?.attr("title")?.takeLast(4)?.toIntOrNull()
+
+ val imageDiv = firstA?.selectFirst("img")
+ var image = imageDiv?.attr("src")
+ if (image.isNullOrBlank()) {
+ image = imageDiv?.attr("data-src")
+ }
+
+ val latestEp = innerDiv?.selectFirst("div.list-chapter")
+ ?.selectFirst("div.chapter-item")
+ ?.selectFirst("a")
+ ?.text()
+ ?.filter { a -> a.isDigit() }
+ ?.toIntOrNull() ?: 0
+ val dubStatus = mutableMapOf(
+ Pair(DubStatus.Subbed, latestEp)
+ )
+
+ AnimeSearchResponse(
+ name = name,
+ url = link,
+ apiName = apiName,
+ type = globalTvType,
+ posterUrl = image,
+ year = year,
+ episodes = dubStatus
+ )
+ } ?: listOf()
+ }
+
+ private data class ResponseJson(
+ @JsonProperty("data") val data: ResponseData?
)
-
- data class Data(
- @JsonProperty("sources") val sources: ArrayList? = arrayListOf(),
+ private data class ResponseData(
+ @JsonProperty("sources") val sources: List? = listOf()
)
-
- data class Sources(
- @JsonProperty("src") val src: String? = null,
- @JsonProperty("type") val type: String? = null,
- @JsonProperty("label") val label: String? = null,
+ private data class ResponseSources(
+ @JsonProperty("src") val src: String?,
+ @JsonProperty("type") val type: String?,
+ @JsonProperty("label") val label: String?
)
-
-
}
\ No newline at end of file
diff --git a/HpJav/build.gradle.kts b/HpJav/build.gradle.kts
index 53a2c6b..c113cb4 100644
--- a/HpJav/build.gradle.kts
+++ b/HpJav/build.gradle.kts
@@ -15,7 +15,7 @@ cloudstream {
* 2: Slow
* 3: Beta only
* */
- status = 0 // will be 3 if unspecified
+ status = 3 // will be 3 if unspecified
// List of video source types. Users are able to filter for extensions in a given category.
// You can find a list of avaliable types here:
diff --git a/JavFreeProvider/build.gradle.kts b/JavFreeProvider/build.gradle.kts
index ec05bb4..6dd6026 100644
--- a/JavFreeProvider/build.gradle.kts
+++ b/JavFreeProvider/build.gradle.kts
@@ -15,7 +15,7 @@ cloudstream {
* 2: Slow
* 3: Beta only
* */
- status = 0 // will be 3 if unspecified
+ status = 1 // will be 3 if unspecified
// List of video source types. Users are able to filter for extensions in a given category.
// You can find a list of avaliable types here:
diff --git a/JavGuru/build.gradle.kts b/JavGuru/build.gradle.kts
index 53e8da0..9d51744 100644
--- a/JavGuru/build.gradle.kts
+++ b/JavGuru/build.gradle.kts
@@ -15,7 +15,7 @@ cloudstream {
* 2: Slow
* 3: Beta only
* */
- status = 0 // will be 3 if unspecified
+ status = 3 // will be 3 if unspecified
// List of video source types. Users are able to filter for extensions in a given category.
// You can find a list of avaliable types here:
diff --git a/JavHD/build.gradle.kts b/JavHD/build.gradle.kts
index aa4a24a..2c0a3d0 100644
--- a/JavHD/build.gradle.kts
+++ b/JavHD/build.gradle.kts
@@ -15,7 +15,7 @@ cloudstream {
* 2: Slow
* 3: Beta only
* */
- status = 0 // will be 3 if unspecified
+ status = 1 // will be 3 if unspecified
// List of video source types. Users are able to filter for extensions in a given category.
// You can find a list of avaliable types here:
diff --git a/JavMost/build.gradle.kts b/JavMost/build.gradle.kts
index 5d248cc..08fb73c 100644
--- a/JavMost/build.gradle.kts
+++ b/JavMost/build.gradle.kts
@@ -15,7 +15,7 @@ cloudstream {
* 2: Slow
* 3: Beta only
* */
- status = 0 // will be 3 if unspecified
+ status = 3 // will be 3 if unspecified
// List of video source types. Users are able to filter for extensions in a given category.
// You can find a list of avaliable types here:
diff --git a/JavSubProvider/build.gradle.kts b/JavSubProvider/build.gradle.kts
index 53ed9ee..b828aca 100644
--- a/JavSubProvider/build.gradle.kts
+++ b/JavSubProvider/build.gradle.kts
@@ -15,7 +15,7 @@ cloudstream {
* 2: Slow
* 3: Beta only
* */
- status = 0 // will be 3 if unspecified
+ status = 1 // will be 3 if unspecified
// List of video source types. Users are able to filter for extensions in a given category.
// You can find a list of avaliable types here:
diff --git a/JavTube/build.gradle.kts b/JavTube/build.gradle.kts
index 1b89210..917a3e9 100644
--- a/JavTube/build.gradle.kts
+++ b/JavTube/build.gradle.kts
@@ -15,7 +15,7 @@ cloudstream {
* 2: Slow
* 3: Beta only
* */
- status = 0 // will be 3 if unspecified
+ status = 1 // will be 3 if unspecified
// List of video source types. Users are able to filter for extensions in a given category.
// You can find a list of avaliable types here:
diff --git a/OpJav/build.gradle.kts b/OpJav/build.gradle.kts
index 46cdcac..67dd0a2 100644
--- a/OpJav/build.gradle.kts
+++ b/OpJav/build.gradle.kts
@@ -15,7 +15,7 @@ cloudstream {
* 2: Slow
* 3: Beta only
* */
- status = 0 // will be 3 if unspecified
+ status = 2 // will be 3 if unspecified
// List of video source types. Users are able to filter for extensions in a given category.
// You can find a list of avaliable types here:
diff --git a/Pornhits/build.gradle.kts b/Pornhits/build.gradle.kts
deleted file mode 100644
index 5b5c045..0000000
--- a/Pornhits/build.gradle.kts
+++ /dev/null
@@ -1,28 +0,0 @@
-// use an integer for version numbers
-version = 5
-
-
-cloudstream {
- // All of these properties are optional, you can safely remove them
-
- description = "Pornhits"
- authors = listOf("KillerDogeEmpire, Coxju")
-
- /**
- * Status int as the following:
- * 0: Down
- * 1: Ok
- * 2: Slow
- * 3: Beta only
- * */
- status = 1 // will be 3 if unspecified
-
- // List of video source types. Users are able to filter for extensions in a given category.
- // You can find a list of avaliable types here:
- // https://recloudstream.github.io/cloudstream/html/app/com.lagradost.cloudstream3/-tv-type/index.html
- tvTypes = listOf("NSFW")
-
- iconUrl = "https://www.google.com/s2/favicons?domain=pornhits.com&sz=%size%"
-
- language = "en"
-}
diff --git a/Pornhits/src/main/AndroidManifest.xml b/Pornhits/src/main/AndroidManifest.xml
deleted file mode 100644
index 0862a59..0000000
--- a/Pornhits/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,2 +0,0 @@
-
-
\ No newline at end of file
diff --git a/Pornhits/src/main/kotlin/com/KillerDogeEmpire/Pornhits.kt b/Pornhits/src/main/kotlin/com/KillerDogeEmpire/Pornhits.kt
deleted file mode 100644
index a8f34c9..0000000
--- a/Pornhits/src/main/kotlin/com/KillerDogeEmpire/Pornhits.kt
+++ /dev/null
@@ -1,216 +0,0 @@
-package com.KillerDogeEmpire
-
-import com.lagradost.cloudstream3.HomePageList
-import com.lagradost.cloudstream3.HomePageResponse
-import com.lagradost.cloudstream3.LoadResponse
-import com.lagradost.cloudstream3.MainAPI
-import com.lagradost.cloudstream3.MainPageRequest
-import com.lagradost.cloudstream3.SearchResponse
-import com.lagradost.cloudstream3.SubtitleFile
-import com.lagradost.cloudstream3.TvType
-import com.lagradost.cloudstream3.VPNStatus
-import com.lagradost.cloudstream3.app
-import com.lagradost.cloudstream3.fixUrl
-import com.lagradost.cloudstream3.fixUrlNull
-import com.lagradost.cloudstream3.mainPageOf
-import com.lagradost.cloudstream3.newHomePageResponse
-import com.lagradost.cloudstream3.newMovieLoadResponse
-import com.lagradost.cloudstream3.newMovieSearchResponse
-import com.lagradost.cloudstream3.utils.ExtractorLink
-import com.lagradost.cloudstream3.utils.Qualities
-import org.json.JSONObject
-import org.jsoup.nodes.Element
-
-class Pornhits : MainAPI() {
- override var mainUrl = "https://www.pornhits.com"
- override var name = "Pornhits"
- override val hasMainPage = true
- override val hasDownloadSupport = true
- override val vpnStatus = VPNStatus.MightBeNeeded
- override val supportedTypes = setOf(TvType.NSFW)
-
- override val mainPage = mainPageOf(
- "$mainUrl/videos.php?p=%d&s=l" to "Latest",
- "$mainUrl/videos.php?p=%d&s=pd" to "Popular last day",
- "$mainUrl/videos.php?p=%d&s=bd" to "Top Rated (day)",
- "$mainUrl/videos.php?p=%d&s=pw" to "Popular last week",
- "$mainUrl/videos.php?p=%d&s=bw" to "Top Rated (week)",
- "$mainUrl/videos.php?p=%d&s=pm" to "Popular last month",
- "$mainUrl/videos.php?p=%d&s=bm" to "Top Rated (month)",
- )
-
- override suspend fun getMainPage(
- page: Int, request: MainPageRequest
- ): HomePageResponse {
- val document = app.get(request.data.format(page)).document
- val home =
- document.select("div.main-content section.main-container div.list-videos article.item")
- .mapNotNull {
- it.toSearchResult()
- }
- return newHomePageResponse(
- list = HomePageList(
- name = request.name, list = home, isHorizontalImages = true
- ), hasNext = true
- )
- }
-
- private fun Element.toSearchResult(): SearchResponse? {
- val title = this.selectFirst("div.item-info h2.title")?.text() ?: return null
- val href = fixUrl(this.selectFirst("a")!!.attr("href"))
- val posterUrl = fixUrlNull(this.select("a div.img img").attr("data-original"))
- return newMovieSearchResponse(title, href, TvType.Movie) {
- this.posterUrl = posterUrl
- }
-
- }
-
- override suspend fun search(query: String): List {
- val searchResponse = mutableListOf()
- for (i in 1..15) {
- val document = app.get(
- "$mainUrl/videos.php?p=${i}&q=${query.trim().replace(" ", "+")}"
- ).document
- val results =
- document.select("div.main-content section.main-container div.list-videos article.item")
- .mapNotNull {
- it.toSearchResult()
- }
- searchResponse.addAll(results)
- if (results.isEmpty()) break
- }
- return searchResponse
- }
-
- override suspend fun load(url: String): LoadResponse {
- val document = app.get(url).document
-
- val title =
- document.selectFirst("section.video-holder div.video-info div.info-holder article#tab_video_info.tab-content div.headline h1")
- ?.text()
- ?: ""
- val poster = fixUrlNull(
- document.selectXpath("//script[contains(text(),'var schemaJson')]").first()?.data()
- ?.replace("\"", "")
- ?.substringAfter("thumbnailUrl:")
- ?.substringBefore(",uploadDate:")
- ?.trim() ?: ""
- )
- val tags =
- document.select(" section.video-holder div.video-info div.info-holder article#tab_video_info.tab-content div.block-details div.info h3.item a")
- .map { it.text() }
- val recommendations =
- document.select("div.related-videos div.list-videos article.item")
- .mapNotNull {
- it.toSearchResult()
- }
-
- return newMovieLoadResponse(title, url, TvType.NSFW, url) {
- this.posterUrl = poster
- this.tags = tags
- 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 script =
- document.selectXpath("//script[contains(text(),'let vpage_data')]").first()?.html()
- var isVHQ = false
- if (script != null && script.contains("VHQ")) {
- isVHQ = true
- }
- val pattern = Regex("""window\.initPlayer\((.*])\);""")
- val matchResult = pattern.find(script ?: "")
-
- val jsonArray = matchResult?.groups?.get(1)?.value
-
- val encodedString = getEncodedString(jsonArray) ?: ""
-
- val decodedString = customBase64Decoder(encodedString)
-
- val videos = JSONObject("{ videos:$decodedString}").getJSONArray("videos")
- val externalLinkList = mutableListOf()
- for (i in 0 until videos.length()) {
- val video = videos.getJSONObject(i)
- var quality = Qualities.Unknown.value
- var isM3u8 = false
- if (video.getString("format").contains("lq")) {
- quality = Qualities.P480.value
- }
- if (video.getString("format").contains("hq")) {
- quality = Qualities.P720.value
- }
- var url = customBase64Decoder(video.getString("video_url"))
- if (isVHQ) {
- url = "$url&f=video.m3u8"
- isM3u8 = true
- quality = Qualities.Unknown.value
- }
- externalLinkList.add(
- ExtractorLink(
- this.name,
- this.name,
- fixUrl(url),
- referer = mainUrl,
- quality = quality,
- isM3u8 = isM3u8
- )
- )
- if (isVHQ) break
- }
-
- externalLinkList.forEach(callback)
- return true
- }
-
- private fun customBase64Decoder(encodedString: String): String {
- val base64CharacterSet = "АВСDЕFGHIJKLМNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.,~"
- var decodedString = ""
- var currentIndex = 0
-
- Regex("[^АВСЕМA-Za-z0-9.,~]").find(encodedString)?.let {
- println("Error decoding URL")
- }
-
- val sanitizedString = encodedString.replace("[^АВСЕМA-Za-z0-9.,~]".toRegex(), "")
-
- do {
- val firstCharIndex = base64CharacterSet.indexOf(sanitizedString[currentIndex++])
- val secondCharIndex = base64CharacterSet.indexOf(sanitizedString[currentIndex++])
- val thirdCharIndex = base64CharacterSet.indexOf(sanitizedString[currentIndex++])
- val fourthCharIndex = base64CharacterSet.indexOf(sanitizedString[currentIndex++])
-
- val reconstructedFirstChar = (firstCharIndex shl 2) or (secondCharIndex shr 4)
- val reconstructedSecondChar = ((15 and secondCharIndex) shl 4) or (thirdCharIndex shr 2)
- val lastPart = ((3 and thirdCharIndex) shl 6) or fourthCharIndex
-
- decodedString += reconstructedFirstChar.toChar().toString()
- if (64 != thirdCharIndex) {
- decodedString += reconstructedSecondChar.toChar().toString()
- }
- if (64 != fourthCharIndex) {
- decodedString += lastPart.toChar().toString()
- }
- } while (currentIndex < sanitizedString.length)
- return java.net.URLDecoder.decode(decodedString, "UTF-8")
- }
-
- private fun getEncodedString(json: String?): String? {
- val stringPattern = Regex("""'([^']+)',""")
-
- val stringMatch = stringPattern.find(json ?: "")
-
- return when {
- stringMatch != null -> stringMatch.groups[1]?.value
- else -> null
- }
- }
-
-}
\ No newline at end of file
diff --git a/Pornhits/src/main/kotlin/com/KillerDogeEmpire/PornhitsProvider.kt b/Pornhits/src/main/kotlin/com/KillerDogeEmpire/PornhitsProvider.kt
deleted file mode 100644
index f4df368..0000000
--- a/Pornhits/src/main/kotlin/com/KillerDogeEmpire/PornhitsProvider.kt
+++ /dev/null
@@ -1,14 +0,0 @@
-package com.KillerDogeEmpire
-
-import com.lagradost.cloudstream3.plugins.CloudstreamPlugin
-import com.lagradost.cloudstream3.plugins.Plugin
-import android.content.Context
-import com.KillerDogeEmpire.Pornhits
-
-@CloudstreamPlugin
-class PornhitsProvider: Plugin() {
- override fun load(context: Context) {
- // All providers should be added in this manner. Please don't edit the providers list directly.
- registerMainAPI(Pornhits())
- }
-}
\ No newline at end of file
diff --git a/Pornhub/build.gradle.kts b/Pornhub/build.gradle.kts
index 724c29c..e627ac2 100644
--- a/Pornhub/build.gradle.kts
+++ b/Pornhub/build.gradle.kts
@@ -1,12 +1,12 @@
// use an integer for version numbers
-version = 6
+version = 5
cloudstream {
// All of these properties are optional, you can safely remove them
description = "Cornhub"
- authors = listOf("KillerDogeEmpire, Stormunblessed, Jace ,Hexated, Coxju")
+ authors = listOf("Stormunblessed", "Jace")
/**
* Status int as the following:
diff --git a/Pornhub/src/main/kotlin/com/jacekun/Pornhub.kt b/Pornhub/src/main/kotlin/com/jacekun/Pornhub.kt
index f7b1379..4ab7001 100644
--- a/Pornhub/src/main/kotlin/com/jacekun/Pornhub.kt
+++ b/Pornhub/src/main/kotlin/com/jacekun/Pornhub.kt
@@ -1,117 +1,142 @@
package com.jacekun
-import android.util.Log
-import org.jsoup.nodes.Element
+import com.lagradost.cloudstream3.MainAPI
+import com.lagradost.cloudstream3.TvType
import com.lagradost.cloudstream3.*
+import com.lagradost.cloudstream3.mvvm.logError
+import com.lagradost.cloudstream3.network.WebViewResolver
import com.lagradost.cloudstream3.utils.*
-import com.lagradost.cloudstream3.LoadResponse.Companion.addActors
+import org.jsoup.nodes.Element
-class PornHub : MainAPI() {
- override var mainUrl = "https://www.pornhub.com"
- override var name = "PornHub"
- override val hasMainPage = true
- override var lang = "en"
- override val hasQuickSearch = false
- override val hasDownloadSupport = true
+class Pornhub : MainAPI() {
+ private val globalTvType = TvType.NSFW
+
+ override var mainUrl = "https://www.pornhub.com"
+ override var name = "Pornhub"
+ override val hasMainPage = true
override val hasChromecastSupport = true
- override val supportedTypes = setOf(TvType.NSFW)
- override val vpnStatus = VPNStatus.MightBeNeeded
+ override val hasDownloadSupport = true
+ override val vpnStatus = VPNStatus.MightBeNeeded //Cause it's a big site
+ override val supportedTypes = setOf(TvType.NSFW)
override val mainPage = mainPageOf(
- "${mainUrl}/video?o=mr&hd=1&page=" to "Recently Featured",
- "${mainUrl}/video?o=tr&t=w&hd=1&page=" to "Top Rated",
- "${mainUrl}/video?o=mv&t=w&hd=1&page=" to "Most Viewed",
- "${mainUrl}/video?o=ht&t=w&hd=1&page=" to "Hottest",
- "${mainUrl}/video?p=professional&hd=1&page=" to "Professional",
- "${mainUrl}/video?o=lg&hd=1&page=" to "Longest",
- "${mainUrl}/video?p=homemade&hd=1&page=" to "Homemade",
- "${mainUrl}/video?o=cm&t=w&hd=1&page=" to "Newest",
+ "$mainUrl/video?page=" to "Main Page",
)
override suspend fun getMainPage(page: Int, request: MainPageRequest): HomePageResponse {
- val document = app.get(request.data + page).document
- val home = document.select("li.pcVideoListItem").mapNotNull { it.toSearchResult() }
-
- return newHomePageResponse(
- list = HomePageList(
- name = request.name,
- list = home,
- isHorizontalImages = true
- ),
- hasNext = true
- )
- }
-
- private fun Element.toSearchResult(): SearchResponse? {
- val title = this.selectFirst("a")?.attr("title") ?: return null
- val link = this.selectFirst("a")?.attr("href") ?: return null
- val posterUrl = fixUrlNull(this.selectFirst("img.thumb")?.attr("src"))
-
- return newMovieSearchResponse(title, link, TvType.Movie) { this.posterUrl = posterUrl }
+ try {
+ val categoryData = request.data
+ val categoryName = request.name
+ val pagedLink = if (page > 0) categoryData + page else categoryData
+ val soup = app.get(pagedLink).document
+ val home = soup.select("div.sectionWrapper div.wrap").mapNotNull {
+ if (it == null) { return@mapNotNull null }
+ val title = it.selectFirst("span.title a")?.text() ?: ""
+ val link = fixUrlNull(it.selectFirst("a")?.attr("href")) ?: return@mapNotNull null
+ val img = fetchImgUrl(it.selectFirst("img"))
+ MovieSearchResponse(
+ name = title,
+ url = link,
+ apiName = this.name,
+ type = globalTvType,
+ posterUrl = img
+ )
+ }
+ if (home.isNotEmpty()) {
+ return newHomePageResponse(
+ list = HomePageList(
+ name = categoryName,
+ list = home,
+ isHorizontalImages = true
+ ),
+ hasNext = true
+ )
+ } else {
+ throw ErrorLoadingException("No homepage data found!")
+ }
+ } catch (e: Exception) {
+ //e.printStackTrace()
+ logError(e)
+ }
+ throw ErrorLoadingException()
}
override suspend fun search(query: String): List {
- val document = app.get("${mainUrl}/video/search?search=${query}").document
-
- return document.select("li.pcVideoListItem").mapNotNull { it.toSearchResult() }
+ val url = "$mainUrl/video/search?search=${query}"
+ val document = app.get(url).document
+ return document.select("div.sectionWrapper div.wrap").mapNotNull {
+ if (it == null) { return@mapNotNull null }
+ val title = it.selectFirst("span.title a")?.text() ?: return@mapNotNull null
+ val link = fixUrlNull(it.selectFirst("a")?.attr("href")) ?: return@mapNotNull null
+ val image = fetchImgUrl(it.selectFirst("img"))
+ MovieSearchResponse(
+ name = title,
+ url = link,
+ apiName = this.name,
+ type = globalTvType,
+ posterUrl = image
+ )
+ }.distinctBy { it.url }
}
- override suspend fun quickSearch(query: String): List = search(query)
-
- override suspend fun load(url: String): LoadResponse? {
- val document = app.get(url).document
-
- val title = document.selectFirst("h1.title span[class='inlineFree']")?.text()?.trim() ?: return null
- val description = title
- val poster = fixUrlNull(document.selectFirst("div.mainPlayerDiv img")?.attr("src"))
- val year = Regex("""uploadDate\": \"(\d+)""").find(document.html())?.groupValues?.get(1)?.toIntOrNull()
- val tags = document.select("div.categoriesWrapper a[data-label='Category']").map { it?.text()?.trim().toString().replace(", ","") }
- val rating = document.selectFirst("span.percent")?.text()?.first()?.toString()?.toRatingInt()
- val duration = Regex("duration' : '(.*)',").find(document.html())?.groupValues?.get(1)?.toIntOrNull()
- val actors = document.select("div.pornstarsWrapper a[data-label='Pornstar']").mapNotNull {
- Actor(it.text().trim(), it.select("img").attr("src"))
- }
-
- val recommendations = document.selectXpath("//a[contains(@class, 'img')]").mapNotNull {
- val recName = it?.attr("title")?.trim() ?: return@mapNotNull null
- val recHref = fixUrlNull(it.attr("href")) ?: return@mapNotNull null
- val recPosterUrl = fixUrlNull(it.selectFirst("img")?.attr("src"))
- newMovieSearchResponse(recName, recHref, TvType.NSFW) {
- this.posterUrl = recPosterUrl
+ override suspend fun load(url: String): LoadResponse {
+ val soup = app.get(url).document
+ val title = soup.selectFirst(".title span")?.text() ?: ""
+ val poster: String? = soup.selectFirst("div.video-wrapper .mainPlayerDiv img")?.attr("src") ?:
+ soup.selectFirst("head meta[property=og:image]")?.attr("content")
+ val tags = soup.select("div.categoriesWrapper a")
+ .map { it?.text()?.trim().toString().replace(", ","") }
+ return MovieLoadResponse(
+ name = title,
+ url = url,
+ apiName = this.name,
+ type = globalTvType,
+ dataUrl = url,
+ posterUrl = poster,
+ tags = tags,
+ plot = title
+ )
+ }
+ override suspend fun loadLinks(
+ data: String,
+ isCasting: Boolean,
+ subtitleCallback: (SubtitleFile) -> Unit,
+ callback: (ExtractorLink) -> Unit
+ ): Boolean {
+ app.get(
+ url = data,
+ interceptor = WebViewResolver(
+ Regex("(master\\.m3u8\\?.*)")
+ )
+ ).let { response ->
+ M3u8Helper().m3u8Generation(
+ M3u8Helper.M3u8Stream(
+ response.url,
+ headers = response.headers.toMap()
+ ), true
+ ).apmap { stream ->
+ callback(
+ ExtractorLink(
+ source = name,
+ name = "${this.name} m3u8",
+ url = stream.streamUrl,
+ referer = mainUrl,
+ quality = getQualityFromName(stream.quality?.toString()),
+ isM3u8 = true
+ )
+ )
}
}
-
- return newMovieLoadResponse(title, url, TvType.NSFW, url) {
- this.posterUrl = poster
- this.year = year
- this.plot = description
- this.tags = tags
- this.rating = rating
- this.duration = duration
- this.recommendations = recommendations
- addActors(actors)
- }
- }
-
- override suspend fun loadLinks(data: String, isCasting: Boolean, subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit): Boolean {
- Log.d("PHub", "url » ${data}")
- val source = app.get(data).text
- val extracted_value = Regex("""([^\"]*master.m3u8?.[^\"]*)""").find(source)?.groups?.last()?.value ?: return false
- val m3u_link = extracted_value.replace("\\", "")
- Log.d("PHub", "extracted_value » ${extracted_value}")
- Log.d("PHub", "m3u_link » ${m3u_link}")
-
- callback.invoke(
- ExtractorLink(
- source = this.name,
- name = this.name,
- url = m3u_link,
- referer = "${mainUrl}/",
- quality = Qualities.Unknown.value,
- isM3u8 = true
- )
- )
-
return true
}
+
+ private fun fetchImgUrl(imgsrc: Element?): String? {
+ return try { imgsrc?.attr("data-src")
+ ?: imgsrc?.attr("data-mediabook")
+ ?: imgsrc?.attr("alt")
+ ?: imgsrc?.attr("data-mediumthumb")
+ ?: imgsrc?.attr("data-thumb_url")
+ ?: imgsrc?.attr("src")
+ } catch (e:Exception) { null }
+ }
}
\ No newline at end of file
diff --git a/Porntrex/build.gradle.kts b/Porntrex/build.gradle.kts
deleted file mode 100644
index 4154860..0000000
--- a/Porntrex/build.gradle.kts
+++ /dev/null
@@ -1,28 +0,0 @@
-// use an integer for version numbers
-version = 5
-
-
-cloudstream {
- // All of these properties are optional, you can safely remove them
-
- description = "Porntrex"
- authors = listOf("KillerDogeEmpire, Coxju")
-
- /**
- * Status int as the following:
- * 0: Down
- * 1: Ok
- * 2: Slow
- * 3: Beta only
- * */
- status = 1 // will be 3 if unspecified
-
- // List of video source types. Users are able to filter for extensions in a given category.
- // You can find a list of avaliable types here:
- // https://recloudstream.github.io/cloudstream/html/app/com.lagradost.cloudstream3/-tv-type/index.html
- tvTypes = listOf("NSFW")
-
- iconUrl = "https://www.google.com/s2/favicons?domain=www.porntrex.com&sz=%size%"
-
- language = "en"
-}
diff --git a/Porntrex/src/main/AndroidManifest.xml b/Porntrex/src/main/AndroidManifest.xml
deleted file mode 100644
index 0862a59..0000000
--- a/Porntrex/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,2 +0,0 @@
-
-
\ No newline at end of file
diff --git a/Porntrex/src/main/kotlin/com/KillerDogeEmpire/Porntrex.kt b/Porntrex/src/main/kotlin/com/KillerDogeEmpire/Porntrex.kt
deleted file mode 100644
index c224379..0000000
--- a/Porntrex/src/main/kotlin/com/KillerDogeEmpire/Porntrex.kt
+++ /dev/null
@@ -1,183 +0,0 @@
-package com.KillerDogeEmpire
-
-import com.lagradost.cloudstream3.HomePageList
-import com.lagradost.cloudstream3.HomePageResponse
-import com.lagradost.cloudstream3.LoadResponse
-import com.lagradost.cloudstream3.MainAPI
-import com.lagradost.cloudstream3.MainPageRequest
-import com.lagradost.cloudstream3.SearchResponse
-import com.lagradost.cloudstream3.SubtitleFile
-import com.lagradost.cloudstream3.TvType
-import com.lagradost.cloudstream3.VPNStatus
-import com.lagradost.cloudstream3.app
-import com.lagradost.cloudstream3.fixUrl
-import com.lagradost.cloudstream3.fixUrlNull
-import com.lagradost.cloudstream3.mainPageOf
-import com.lagradost.cloudstream3.newHomePageResponse
-import com.lagradost.cloudstream3.newMovieLoadResponse
-import com.lagradost.cloudstream3.newMovieSearchResponse
-import com.lagradost.cloudstream3.utils.ExtractorLink
-import com.lagradost.cloudstream3.utils.getQualityFromName
-import org.json.JSONObject
-import org.jsoup.internal.StringUtil
-import org.jsoup.nodes.Element
-
-class Porntrex : MainAPI() {
- override var mainUrl = "https://www.porntrex.com"
- override var name = "Porntrex"
- override val hasMainPage = true
- override val hasDownloadSupport = true
- override val vpnStatus = VPNStatus.MightBeNeeded
- override val supportedTypes = setOf(TvType.NSFW)
-
- override val mainPage = mainPageOf(
- "latest-updates" to "Latest Videos",
- "most-popular/daily/?mode=async&function=get_block&block_id=list_videos_common_videos_list_norm&sort_by=video_viewed_today&from4=" to "Most popular daily",
- "top-rated/daily/?mode=async&function=get_block&block_id=list_videos_common_videos_list_norm&sort_by=rating_today&from4=" to "Top rated daily",
- "most-popular/weekly/?mode=async&function=get_block&block_id=list_videos_common_videos_list_norm&sort_by=video_viewed_week&from4=" to "Most popular weekly",
- "top-rated/weekly/?mode=async&function=get_block&block_id=list_videos_common_videos_list_norm&sort_by=rating_week&from4=" to "Top rated weekly",
- "most-popular/monthly/?mode=async&function=get_block&block_id=list_videos_common_videos_list_norm&sort_by=video_viewed_month&from4=" to "Most popular monthly",
- "top-rated/monthly/?mode=async&function=get_block&block_id=list_videos_common_videos_list_norm&sort_by=rating_month&from4=" to "Top rated monthly",
- "most-popular/?mode=async&function=get_block&block_id=list_videos_common_videos_list_norm&sort_by=video_viewed&from4=" to "Most popular all time",
- "top-rated/?mode=async&function=get_block&block_id=list_videos_common_videos_list_norm&sort_by=rating&from4=" to "Top rated all time",
- )
-
- override suspend fun getMainPage(
- page: Int,
- request: MainPageRequest
- ): HomePageResponse {
- var url: String
- url = if (page == 1) {
- "$mainUrl/${request.data}/"
- } else {
- "$mainUrl/${request.data}/${page}/"
- }
- if (request.data.contains("mode=async")) {
- url = "$mainUrl/${request.data}${page}"
- }
- val document = app.get(url).document
- val home =
- document.select("div.video-list div.video-item")
- .mapNotNull {
- it.toSearchResult()
- }
- return newHomePageResponse(
- list = HomePageList(
- name = request.name,
- list = home,
- isHorizontalImages = true
- ),
- hasNext = true
- )
- }
-
- private fun Element.toSearchResult(): SearchResponse? {
- val title = this.selectFirst("p.inf a")?.text() ?: return null
- val href = fixUrl(this.selectFirst("p.inf a")!!.attr("href"))
- val posterUrl = fixUrlNull(this.select("a.thumb img.cover").attr("data-src"))
- return newMovieSearchResponse(title, href, TvType.Movie) {
- this.posterUrl = posterUrl
- this.posterHeaders = mapOf(Pair("referer", "${mainUrl}/"))
- }
-
- }
-
- override suspend fun search(query: String): List {
- val searchResponse = mutableListOf()
- for (i in 1..15) {
- val url: String = if (i == 1) {
- "$mainUrl/search/${query.replace(" ", "-")}/"
- } else {
- "$mainUrl/search/${query.replace(" ", "-")}/$i/"
- }
- val document =
- app.get(url).document
- val results =
- document.select("div.video-list div.video-item")
- .mapNotNull {
- it.toSearchResult()
- }
- searchResponse.addAll(results)
- if (results.isEmpty()) break
- }
- return searchResponse
- }
-
- override suspend fun load(url: String): LoadResponse {
- val document = app.get(url).document
-
- val jsonObject = JSONObject(document.selectXpath("//script[contains(text(),'var flashvars')]").first()?.data()
- ?.substringAfter("var flashvars = ")
- ?.substringBefore("var player_obj")
- ?.replace(";", "") ?: "")
-
- val title = jsonObject.getString("video_title")
- val poster =
- fixUrlNull(jsonObject.getString("preview_url"))
-
- val tags = jsonObject.getString("video_tags").split(", ").map { it.replace("-", "") }.filter { it.isNotBlank() && !StringUtil.isNumeric(it) }
- val description = jsonObject.getString("video_title")
-
- val recommendations =
- document.select("div#list_videos_related_videos div.video-list div.video-item").mapNotNull {
- it.toSearchResult()
- }
-
- return newMovieLoadResponse(title, url, TvType.NSFW, url) {
- this.posterUrl = poster
- this.posterHeaders = mapOf(Pair("referer", "${mainUrl}/"))
- this.plot = description
- this.tags = tags
- 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 jsonObject = JSONObject(document.selectXpath("//script[contains(text(),'var flashvars')]").first()?.data()
- ?.substringAfter("var flashvars = ")
- ?.substringBefore("var player_obj")
- ?.replace(";", "") ?: "")
- val extlinkList = mutableListOf()
- for (i in 0 until 7) {
- var url: String
- var quality: String
- if (i == 0) {
- url = jsonObject.optString("video_url") ?: ""
- quality = jsonObject.optString("video_url_text") ?: ""
- } else {
- if (i == 1) {
- url = jsonObject.optString("video_alt_url") ?: ""
- quality = jsonObject.optString("video_alt_url_text") ?: ""
- } else {
- url = jsonObject.optString("video_alt_url${i}") ?: ""
- quality = jsonObject.optString("video_alt_url${i}_text") ?: ""
- }
- }
- if (url == "") {
- continue
- }
- extlinkList.add(
- ExtractorLink(
- name,
- name,
- fixUrl(url),
- referer = "${mainUrl}/",
- quality =
- Regex("(\\d+.)").find(quality)?.groupValues?.get(1)
- .let { getQualityFromName(it) }
- )
- )
- }
- extlinkList.forEach(callback)
- return true
- }
-
-}
-
diff --git a/Porntrex/src/main/kotlin/com/KillerDogeEmpire/PorntrexProvider.kt b/Porntrex/src/main/kotlin/com/KillerDogeEmpire/PorntrexProvider.kt
deleted file mode 100644
index d13c510..0000000
--- a/Porntrex/src/main/kotlin/com/KillerDogeEmpire/PorntrexProvider.kt
+++ /dev/null
@@ -1,14 +0,0 @@
-package com.KillerDogeEmpire
-
-import android.content.Context
-import com.KillerDogeEmpire.Porntrex
-import com.lagradost.cloudstream3.plugins.CloudstreamPlugin
-import com.lagradost.cloudstream3.plugins.Plugin
-
-@CloudstreamPlugin
-class PorntrexProvider : Plugin() {
- override fun load(context: Context) {
- // All providers should be added in this manner. Please don't edit the providers list directly.
- registerMainAPI(Porntrex())
- }
-}
\ No newline at end of file
diff --git a/SxyPrn/src/main/AndroidManifest.xml b/SxyPrn/src/main/AndroidManifest.xml
deleted file mode 100644
index 0862a59..0000000
--- a/SxyPrn/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,2 +0,0 @@
-
-
\ No newline at end of file
diff --git a/SxyPrn/src/main/kotlin/com/KillerDogeEmpire/SxyPrn.kt b/SxyPrn/src/main/kotlin/com/KillerDogeEmpire/SxyPrn.kt
deleted file mode 100644
index b5b50dc..0000000
--- a/SxyPrn/src/main/kotlin/com/KillerDogeEmpire/SxyPrn.kt
+++ /dev/null
@@ -1,143 +0,0 @@
-package com.KillerDogeEmpire
-
-import com.lagradost.cloudstream3.*
-import com.lagradost.cloudstream3.utils.AppUtils
-import com.lagradost.cloudstream3.utils.ExtractorLink
-import com.lagradost.cloudstream3.utils.Qualities
-import org.jsoup.nodes.Element
-
-class SxyPrn : MainAPI() {
- override var mainUrl = "https://sxyprn.com"
- override var name = "Sxyprn"
- override val hasMainPage = true
- override val hasDownloadSupport = true
- override val vpnStatus = VPNStatus.MightBeNeeded
- override val supportedTypes = setOf(TvType.NSFW)
-
- override val mainPage = mainPageOf(
- "$mainUrl/new.html?page=" to "New Videos",
- "$mainUrl/new.html?sm=trending&page=" to "Trending",
- "$mainUrl/new.html?sm=views&page=" to "Most Viewed",
- "$mainUrl/popular/top-viewed.html?p=day" to "Popular - Day",
- "$mainUrl/popular/top-viewed.html" to "Popular - Week",
- "$mainUrl/popular/top-viewed.html?p=month" to "Popular - Month",
- "$mainUrl/popular/top-viewed.html?p=all" to "Popular - All Time"
- )
-
- override suspend fun getMainPage(
- page: Int, request: MainPageRequest
- ): HomePageResponse {
- var pageStr = ((page - 1) * 30).toString()
-
- val document = if ("page=" in request.data) {
- app.get(request.data + pageStr).document
- } else if ("/blog/" in request.data) {
- pageStr = ((page - 1) * 20).toString()
- app.get(request.data.replace(".html", "$pageStr.html")).document
- } else {
- app.get(request.data.replace(".html", ".html/$pageStr")).document
- }
- val home = document.select("div.main_content div.post_el_small").mapNotNull {
- it.toSearchResult()
- }
- return newHomePageResponse(
- list = HomePageList(
- name = request.name, list = home, isHorizontalImages = true
- ), hasNext = true
- )
- }
-
- private fun Element.toSearchResult(): SearchResponse? {
- val title = this.selectFirst("div.post_text")?.text() ?: return null
- val href = fixUrl(this.selectFirst("a.js-pop")!!.attr("href"))
- var posterUrl = fixUrl(this.select("div.vid_container div.post_vid_thumb img").attr("src"))
- if (posterUrl == "") {
- posterUrl =
- fixUrl(this.select("div.vid_container div.post_vid_thumb img").attr("data-src"))
- }
- return newMovieSearchResponse(title, href, TvType.Movie) {
- this.posterUrl = posterUrl
- }
- }
-
- override suspend fun search(query: String): List {
- val searchResponse = mutableListOf()
- for (i in 0 until 15) {
- val document = app.get(
- "$mainUrl/${query.replace(" ", "-")}.html?page=${i * 30}"
- ).document
- val results = document.select("div.main_content div.post_el_small").mapNotNull {
- it.toSearchResult()
- }
- if (!searchResponse.containsAll(results)) {
- searchResponse.addAll(results)
- } else {
- break
- }
- if (results.isEmpty()) break
- }
- return searchResponse
- }
-
- override suspend fun load(url: String): LoadResponse {
- val document = app.get(url).document
- val title = document.selectFirst("div.post_text")?.text()?.trim().toString()
- val poster = fixUrlNull(
- document.selectFirst("div#vid_container_id meta[itemprop=thumbnailUrl]")
- ?.attr("content")
- )
-
- val recommendations = document.select("div.main_content div div.post_el_small").mapNotNull {
- it.toSearchResult()
- }
-
- return newMovieLoadResponse(title, url, TvType.NSFW, url) {
- this.posterUrl = poster
- this.recommendations = recommendations
- }
- }
-
- private fun updateUrl(arg: MutableList): MutableList {
- arg[5] =
- (Integer.parseInt(arg[5]) - (generateNumber(arg[6]) + generateNumber(arg[7]))).toString()
- return arg
- }
-
- private fun generateNumber(arg: String): Int {
- val str = arg.replace(Regex("\\D"), "")
- var sut = 0
- for (element in str) {
- sut += Integer.parseInt(element.toString(), 10)
- }
- return sut
- }
-
- override suspend fun loadLinks(
- data: String,
- isCasting: Boolean,
- subtitleCallback: (SubtitleFile) -> Unit,
- callback: (ExtractorLink) -> Unit
- ): Boolean {
- val document = app.get(data).document
- val parsed = AppUtils.parseJson