Merge remote-tracking branch 'origin/NoodleMagazine' into NoodleMagazine

This commit is contained in:
KillerDogeEmpire 2024-02-12 23:26:12 -08:00
commit 8f8033178d
44 changed files with 1553 additions and 336 deletions

View File

@ -1,9 +0,0 @@
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
}

View File

@ -0,0 +1,18 @@
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%"
}

View File

@ -1,2 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest package="com.lagradost"/>
<manifest package="com.coxjud"/>

View File

@ -0,0 +1,162 @@
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<SearchResponse> {
val searchResponse = mutableListOf<SearchResponse>()
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<String, String>
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("<video" + iframeDocument.selectXpath("//script[contains(text(),'\$(\"#jw\").html(')]")[0]?.toString()?.replace("\\", "")?.substringAfter("<video")?.substringBefore("</video>") + "</video>")
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<ExtractorLink>()
if (iframeUrl.contains("videoh")) {
val iframeDocument = app.get(iframeUrl, interceptor = WebViewResolver(Regex("""mydaddy"""))).document
val videoDocument = Jsoup.parse("<video" + iframeDocument.selectXpath("//script[contains(text(),'\$(\"#jw\").html(')]").first()?.toString()?.replace("\\", "")?.substringAfter("<video")?.substringAfter("<video")?.substringBefore("</video>") + "</video>")
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("<video" + iframeDocument.selectXpath("//script[contains(text(),'\$(\"#jw\").html(')]").first()?.toString()?.replace("\\", "")?.substringAfter("<video")?.substringBefore("</video>") + "</video>")
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
}
}

View File

@ -0,0 +1,12 @@
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())
}
}

28
GoodPorn/build.gradle.kts Normal file
View File

@ -0,0 +1,28 @@
// 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"
}

View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest package="com.KillerDogeEmpire"/>

View File

@ -0,0 +1,127 @@
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<SearchResponse> {
val searchResponse = mutableListOf<SearchResponse>()
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<ExtractorLink>()
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
}
}

View File

@ -0,0 +1,14 @@
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())
}
}

View File

@ -1,12 +1,12 @@
// use an integer for version numbers
version = 5
version = 6
cloudstream {
// All of these properties are optional, you can safely remove them
description = ""
authors = listOf("Jace")
authors = listOf("KillerDogeEmpire, Jace")
/**
* Status int as the following:

View File

@ -1,101 +1,99 @@
package com.jacekun
import android.util.Log
import com.fasterxml.jackson.annotation.JsonProperty
import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.mvvm.logError
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.getQualityFromName
import org.jsoup.select.Elements
import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer
import com.lagradost.cloudstream3.utils.*
import okhttp3.FormBody
import org.jsoup.nodes.Element
class HentaiHaven : MainAPI() {
private val globalTvType = TvType.NSFW
override var name = "Hentai Haven"
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 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 suspend fun getMainPage(
page: Int,
request: MainPageRequest
): HomePageResponse {
val doc = app.get(mainUrl).document
val all = ArrayList<HomePageList>()
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
)
)
}
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()
}
return HomePageResponse(all)
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)
}
}
override suspend fun search(query: String): List<SearchResponse> {
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)
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()
}
}
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()
override suspend fun load(url: String): LoadResponse? {
val document = app.get(url).document
val body = doc.getElementsByTag("body")
val episodes = body.select("div.page-content-listing.single-page")
.first()?.select("li")
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 year = episodes?.last()
?.selectFirst("span.chapter-release-date")
?.text()?.trim()?.takeLast(4)?.toIntOrNull()
val description = document.select("div.description-summary p").text().trim()
val trailer = document.selectFirst("a.trailerbutton")?.attr("href")
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()
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)
}
//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(
@ -105,120 +103,66 @@ class HentaiHaven : MainAPI() {
callback: (ExtractorLink) -> Unit
): Boolean {
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 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)
app.get(data).document.selectFirst("div.player_logic_item iframe")
?.attr("src")?.let { epLink ->
val body = FormBody.Builder()
.addEncoded("action", "zarat_get_data_player_ajax")
.addEncoded("a", "$en")
.addEncoded("b", "$iv")
.build()
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<ResponseJson?>(doc.text)
doc.parsedSafe<ResponseJson>()?.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
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<Response>()?.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
)
)
}
}
return true
}
private fun Elements?.getResults(apiName: String): List<AnimeSearchResponse> {
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") ?: "<No 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 Response(
@JsonProperty("data") val data: Data? = null,
)
private data class ResponseData(
@JsonProperty("sources") val sources: List<ResponseSources>? = listOf()
data class Data(
@JsonProperty("sources") val sources: ArrayList<Sources>? = arrayListOf(),
)
private data class ResponseSources(
@JsonProperty("src") val src: String?,
@JsonProperty("type") val type: String?,
@JsonProperty("label") val label: String?
data class Sources(
@JsonProperty("src") val src: String? = null,
@JsonProperty("type") val type: String? = null,
@JsonProperty("label") val label: String? = null,
)
}

View File

@ -15,7 +15,7 @@ cloudstream {
* 2: Slow
* 3: Beta only
* */
status = 3 // 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:

View File

@ -15,7 +15,7 @@ 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:

View File

@ -15,7 +15,7 @@ cloudstream {
* 2: Slow
* 3: Beta only
* */
status = 3 // 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:

View File

@ -15,7 +15,7 @@ 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:

View File

@ -15,7 +15,7 @@ cloudstream {
* 2: Slow
* 3: Beta only
* */
status = 3 // 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:

View File

@ -15,7 +15,7 @@ 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:

View File

@ -15,7 +15,7 @@ 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:

View File

@ -1,2 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest package="com.lagradost"/>
<manifest package="com.lagradost"/>

View File

@ -38,18 +38,22 @@ class NoodleMagazineProvider : MainAPI() { // all providers must be an instance
return newHomePageResponse(request.name, home)
}
private fun Element.toSearchResult(): MovieSearchResponse? {
val href = fixUrl(this.selectFirst("a")?.attr("href") ?: return null)
val title = this.selectFirst("a div.i_info div.title")?.text() ?: return null
val posterUrl = fixUrlNull(this.selectFirst("a div.i_img img")?.attr("data-src"))
return newMovieSearchResponse(title, href, TvType.Movie) {
this.posterUrl = posterUrl
}
}
override suspend fun search(query: String): List<MovieSearchResponse> {
val searchresult = mutableListOf<MovieSearchResponse>()
(0..10).toList().apmap { page ->
val doc = app.get("$mainUrl/video/$query?p=$page").document
//return document.select("div.post-filter-image").mapNotNull {

View File

@ -15,7 +15,7 @@ cloudstream {
* 2: Slow
* 3: Beta only
* */
status = 2 // 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:

28
Pornhits/build.gradle.kts Normal file
View File

@ -0,0 +1,28 @@
// 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"
}

View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest package="com.KillerDogeEmpire"/>

View File

@ -0,0 +1,216 @@
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<SearchResponse> {
val searchResponse = mutableListOf<SearchResponse>()
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<ExtractorLink>()
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
}
}
}

View File

@ -0,0 +1,14 @@
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())
}
}

View File

@ -1,12 +1,12 @@
// use an integer for version numbers
version = 5
version = 6
cloudstream {
// All of these properties are optional, you can safely remove them
description = "Cornhub"
authors = listOf("Stormunblessed", "Jace")
authors = listOf("KillerDogeEmpire, Stormunblessed, Jace ,Hexated, Coxju")
/**
* Status int as the following:

View File

@ -1,142 +1,117 @@
package com.jacekun
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 android.util.Log
import org.jsoup.nodes.Element
import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.utils.*
import com.lagradost.cloudstream3.LoadResponse.Companion.addActors
class Pornhub : MainAPI() {
private val globalTvType = TvType.NSFW
override var mainUrl = "https://www.pornhub.com"
override var name = "Pornhub"
override val hasMainPage = true
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
override val hasChromecastSupport = true
override val hasDownloadSupport = true
override val vpnStatus = VPNStatus.MightBeNeeded //Cause it's a big site
override val supportedTypes = setOf(TvType.NSFW)
override val supportedTypes = setOf(TvType.NSFW)
override val vpnStatus = VPNStatus.MightBeNeeded
override val mainPage = mainPageOf(
"$mainUrl/video?page=" to "Main Page",
"${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",
)
override suspend fun getMainPage(page: Int, request: MainPageRequest): HomePageResponse {
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()
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 }
}
override suspend fun search(query: String): List<SearchResponse> {
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 }
val document = app.get("${mainUrl}/video/search?search=${query}").document
return document.select("li.pcVideoListItem").mapNotNull { it.toSearchResult() }
}
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
)
)
override suspend fun quickSearch(query: String): List<SearchResponse> = 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
}
}
return 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)
}
}
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 }
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
}
}

28
Porntrex/build.gradle.kts Normal file
View File

@ -0,0 +1,28 @@
// 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"
}

View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest package="com.KillerDogeEmpire"/>

View File

@ -0,0 +1,183 @@
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<SearchResponse> {
val searchResponse = mutableListOf<SearchResponse>()
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<ExtractorLink>()
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
}
}

View File

@ -0,0 +1,14 @@
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())
}
}

View File

@ -1,12 +1,12 @@
// use an integer for version numbers
version = 1
version = 6
cloudstream {
// All of these properties are optional, you can safely remove them
description = ""
authors = listOf("Jace")
description = "sxyprn"
authors = listOf("Coxju")
/**
* Status int as the following:
@ -15,12 +15,14 @@ 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:
// 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=example.com&sz=%size%"
iconUrl = "https://www.google.com/s2/favicons?domain=sxyprn.com&sz=%size%"
language = "en"
}

View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest package="com.KillerDogeEmpire"/>

View File

@ -0,0 +1,143 @@
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<SearchResponse> {
val searchResponse = mutableListOf<SearchResponse>()
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<String>): MutableList<String> {
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<Map<String, String>>(
document.select("span.vidsnfo").attr("data-vnfo")
)
parsed[parsed.keys.toList()[0]]
var url = parsed[parsed.keys.toList()[0]].toString()
var tmp = url.split("/").toMutableList()
tmp[1] += "8"
tmp = updateUrl(tmp)
url = fixUrl(tmp.joinToString("/"))
callback.invoke(
ExtractorLink(
this.name, this.name, url, referer = data, quality = Qualities.Unknown.value
)
)
return true
}
}

View File

@ -0,0 +1,14 @@
package com.KillerDogeEmpire
import android.content.Context
import com.KillerDogeEmpire.SxyPrn
import com.lagradost.cloudstream3.plugins.CloudstreamPlugin
import com.lagradost.cloudstream3.plugins.Plugin
@CloudstreamPlugin
class SxyPrnProvider : Plugin() {
override fun load(context: Context) {
// All providers should be added in this manner. Please don't edit the providers list directly.
registerMainAPI(SxyPrn())
}
}

View File

@ -0,0 +1,28 @@
// use an integer for version numbers
version = 5
cloudstream {
// All of these properties are optional, you can safely remove them
description = "Uncutmaza"
authors = listOf("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=uncutmaza.com&sz=%size%"
language = "en"
}

View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest package="com.KillerDogeEmpire"/>

View File

@ -0,0 +1,118 @@
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.fixTitle
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.jsoup.nodes.Element
class UncutMaza : MainAPI() {
override var mainUrl = "https://uncutmaza.com"
override var name = "Uncutmaza"
override val hasMainPage = true
override val hasDownloadSupport = true
override val vpnStatus = VPNStatus.MightBeNeeded
override val supportedTypes = setOf(TvType.NSFW)
override val mainPage = mainPageOf(
"$mainUrl/page/" to "Home", "$mainUrl/category/niks-indian-porn/page/" to "Niks Indian"
)
override suspend fun getMainPage(
page: Int, request: MainPageRequest
): HomePageResponse {
val document = app.get(request.data + page).document
val home = document.select("div.videos-list > article.post").mapNotNull {
it.toSearchResult()
}
return newHomePageResponse(
list = HomePageList(
name = request.name, list = home, isHorizontalImages = true
), hasNext = true
)
}
private fun Element.toSearchResult(): SearchResponse {
val title = fixTitle(this.select("a").attr("title"))
val href = fixUrl(this.select("a").attr("href"))
val posterUrl = fixUrlNull(
this.select("a > div.post-thumbnail>div.post-thumbnail-container>img").attr("data-src")
)
return newMovieSearchResponse(title, href, TvType.Movie) {
this.posterUrl = posterUrl
}
}
override suspend fun search(query: String): List<SearchResponse> {
val searchResponse = mutableListOf<SearchResponse>()
for (i in 1..5) {
val document = app.get(
"$mainUrl/page/$i?s=$query"
).document
val results = document.select("article.post").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("meta[property=og:title]")?.attr("content")?.trim().toString()
val poster =
fixUrlNull(document.selectFirst("meta[property=og:image]")?.attr("content").toString())
val description =
document.selectFirst("meta[property=og:description]")?.attr("content")?.trim()
return newMovieLoadResponse(title, url, TvType.NSFW, url) {
this.posterUrl = poster
this.plot = description
}
}
override suspend fun loadLinks(
data: String,
isCasting: Boolean,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
): Boolean {
val document = app.get(data).document
document.select("div.video-player").map { res ->
callback.invoke(
ExtractorLink(
this.name, this.name, fixUrl(
res.selectFirst("meta[itemprop=contentURL]")?.attr("content")?.trim()
.toString()
), referer = data, quality = Qualities.Unknown.value
)
)
}
return true
}
}

View File

@ -0,0 +1,14 @@
package com.KillerDogeEmpire
import com.lagradost.cloudstream3.plugins.CloudstreamPlugin
import com.lagradost.cloudstream3.plugins.Plugin
import android.content.Context
import com.KillerDogeEmpire.UncutMaza
@CloudstreamPlugin
class UncutMazaProvider: Plugin() {
override fun load(context: Context) {
// All providers should be added in this manner. Please don't edit the providers list directly.
registerMainAPI(UncutMaza())
}
}

View File

@ -15,7 +15,7 @@ cloudstream {
* 2: Slow
* 3: Beta only
* */
status = 3 // 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:

28
Xhamster/build.gradle.kts Normal file
View File

@ -0,0 +1,28 @@
// use an integer for version numbers
version = 5
cloudstream {
// All of these properties are optional, you can safely remove them
description = "Xhamster"
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=xhamster.com&sz=%size%"
language = "en"
}

View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest package="com.KillerDogeEmpire"/>

View File

@ -0,0 +1,100 @@
package com.KillerDogeEmpire
import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.Qualities
import org.jsoup.nodes.Element
class Xhamster : MainAPI() {
override var mainUrl = "https://xhamster.com"
override var name = "xHamster"
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}/newest/" to "Newest",
"${mainUrl}/most-viewed/weekly/" to "Most viewed weekly",
"${mainUrl}/most-viewed/monthly/" to "Most viewed monthly",
"${mainUrl}/most-viewed" to "Most viewed all time",
"${mainUrl}/most-viewed/weekly/" to "Most viewed weekly"
)
override suspend fun getMainPage(page: Int, request: MainPageRequest): HomePageResponse {
val document = app.get(request.data + page + "?x_platform_switch=desktop").document
val home = document.select("div.thumb-list div.thumb-list__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("a.video-thumb-info__name")?.text() ?: return null
val href = fixUrl(this.selectFirst("a.video-thumb-info__name")!!.attr("href"))
val posterUrl = fixUrlNull(this.select("img.thumb-image-container__image").attr("src"))
return newMovieSearchResponse(title, href, TvType.Movie) { this.posterUrl = posterUrl }
}
override suspend fun search(query: String): List<SearchResponse> {
val searchResponse = mutableListOf<SearchResponse>()
for (i in 0 until 15) {
val document = app.get("${mainUrl}/search/${query.replace(" ", "+")}/?page=$i&x_platform_switch=desktop").document
val results = document.select("div.thumb-list div.thumb-list__item").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.with-player-container h1")?.text()?.trim().toString()
val poster = fixUrlNull(document.selectFirst("div.xp-preload-image")?.attr("style")?.substringAfter("https:")?.substringBefore("\');"))
val tags = document.select(" nav#video-tags-list-container ul.root-8199e.video-categories-tags.collapsed-8199e li.item-8199e a.video-tag").map { it.text() }
val recommendations = document.select("div.related-container div.thumb-list div.thumb-list__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 {
app.get(url = data).let { response ->
callback(
ExtractorLink(
source = name,
name = name,
url = fixUrl(response.document.selectXpath("//link[contains(@href,'.m3u8')]")[0]?.attr("href").toString()),
referer = mainUrl,
quality = Qualities.Unknown.value,
isM3u8 = true
)
)
}
return true
}
}

View File

@ -1,13 +1,13 @@
package com.jacekun
package com.KillerDogeEmpire
import com.lagradost.cloudstream3.plugins.CloudstreamPlugin
import com.lagradost.cloudstream3.plugins.Plugin
import android.content.Context
@CloudstreamPlugin
class ExamplePlugin: Plugin() {
class XhamsterProvider: Plugin() {
override fun load(context: Context) {
// All providers should be added in this manner. Please don't edit the providers list directly.
registerMainAPI(Example())
registerMainAPI(Xhamster())
}
}