added Nekopoi and fix some providers

This commit is contained in:
sora 2023-07-19 20:54:20 +07:00
parent 4127d8f2c8
commit 4a1597dc2f
10 changed files with 331 additions and 14 deletions

View File

@ -1,5 +1,5 @@
// use an integer for version numbers
version = 3
version = 4
cloudstream {

View File

@ -1,6 +1,7 @@
package com.hexated
import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.extractors.Filesim
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.loadExtractor
import org.jsoup.nodes.Element
@ -113,7 +114,7 @@ class DramaSerial : MainAPI() {
mLink.attr("onclick").substringAfter("frame('").substringBefore("')").let { iLink ->
val uLink = app.get(iLink, referer = iframe).document.select("script").find { it.data().contains("(document).ready") }?.data()?.substringAfter("replace(\"")?.substringBefore("\");") ?: return@apmap null
val link = app.get(uLink, referer = iLink).document.selectFirst("iframe")?.attr("src") ?: return@apmap null
loadExtractor(fixUrl(link), "$mainUrl/", subtitleCallback, callback)
loadExtractor(fixUrl(link), "https://juraganfilm.info/", subtitleCallback, callback)
}
}
@ -122,3 +123,8 @@ class DramaSerial : MainAPI() {
}
}
class Bk21 : Filesim() {
override val name = "Bk21"
override var mainUrl = "https://bk21.net"
}

View File

@ -10,6 +10,6 @@ class DramaSerialPlugin: Plugin() {
override fun load(context: Context) {
// All providers should be added in this manner. Please don't edit the providers list directly.
registerMainAPI(DramaSerial())
registerExtractorAPI(Lkctwoone())
registerExtractorAPI(Bk21())
}
}

View File

@ -1,8 +0,0 @@
package com.hexated
import com.lagradost.cloudstream3.extractors.XStreamCdn
class Lkctwoone: XStreamCdn() {
override val name: String = "LKC21"
override val mainUrl: String = "https://lkc21.net"
}

25
Nekopoi/build.gradle.kts Normal file
View File

@ -0,0 +1,25 @@
// use an integer for version numbers
version = 1
cloudstream {
language = "id"
// All of these properties are optional, you can safely remove them
// description = "Lorem Ipsum"
authors = listOf("Sora")
/**
* 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=nekopoi.care&sz=%size%"
}

View File

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

View File

@ -0,0 +1,276 @@
package com.hexated
import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.utils.*
import com.lagradost.nicehttp.Requests
import com.lagradost.nicehttp.Session
import org.jsoup.nodes.Element
import java.net.URI
class Nekopoi : MainAPI() {
override var mainUrl = "https://nekopoi.care"
override var name = "Nekopoi"
override val hasMainPage = true
override var lang = "id"
override val supportedTypes = setOf(
TvType.NSFW,
)
companion object {
val session = Session(Requests().baseClient)
val mirrorBlackList = arrayOf(
"MegaupNet",
"DropApk",
"Racaty",
"ZippyShare",
"ZippySha",
"VideobinCo",
"DropApk",
"SendCm",
"GoogleDrive",
)
fun getStatus(t: String?): ShowStatus {
return when (t) {
"Completed" -> ShowStatus.Completed
"Ongoing" -> ShowStatus.Ongoing
else -> ShowStatus.Completed
}
}
}
override val mainPage = mainPageOf(
"$mainUrl/category/hentai/" to "Hentai",
"$mainUrl/category/jav/" to "Jav",
"$mainUrl/category/3d-hentai/" to "3D Hentai",
"$mainUrl/category/jav-cosplay/" to "Jav Cosplay",
)
override suspend fun getMainPage(
page: Int,
request: MainPageRequest
): HomePageResponse {
val document = app.get("${request.data}/page/$page").document
val home = document.select("div.result ul li").mapNotNull {
it.toSearchResult()
}
return newHomePageResponse(
list = HomePageList(
name = request.name,
list = home,
isHorizontalImages = true
),
hasNext = true
)
}
private fun getProperAnimeLink(uri: String): String {
return if (uri.contains("-episode-")) {
val title = uri.substringAfter("$mainUrl/").substringBefore("-episode-")
.removePrefix("new-release-").removePrefix("uncensored-")
"$mainUrl/hentai/$title"
} else {
uri
}
}
private fun Element.toSearchResult(): AnimeSearchResponse? {
val title = this.selectFirst("h2 a")?.text()?.trim() ?: return null
val href = getProperAnimeLink(this.selectFirst("a")?.attr("href") ?: return null)
val posterUrl = fixUrlNull(this.selectFirst("img")?.attr("src"))
val epNum = this.selectFirst("i.dot")?.text()?.filter { it.isDigit() }?.toIntOrNull()
return newAnimeSearchResponse(title, href, TvType.NSFW) {
this.posterUrl = posterUrl
addSub(epNum)
}
}
override suspend fun search(query: String): List<SearchResponse> {
return app.get("$mainUrl/search/$query").document.select("div.result ul li")
.mapNotNull {
it.toSearchResult()
}
}
override suspend fun load(url: String): LoadResponse {
val document = app.get(url).document
val title = document.selectFirst("span.desc b, div.eroinfo h1")?.text()?.trim() ?: ""
val poster = fixUrlNull(document.selectFirst("div.imgdesc img, div.thm img")?.attr("src"))
val table = document.select("div.listinfo ul, div.konten")
val tags =
table.select("li:contains(Genres) a").map { it.text() }.takeIf { it.isNotEmpty() }
?: table.select("p:contains(Genre)").text().substringAfter(":").split(",")
.map { it.trim() }
val year =
document.selectFirst("li:contains(Tayang)")?.text()?.substringAfterLast(",")
?.filter { it.isDigit() }?.toIntOrNull()
val status = getStatus(
document.selectFirst("li:contains(Status)")?.text()?.substringAfter(":")?.trim()
)
val duration = document.selectFirst("li:contains(Durasi)")?.text()?.substringAfterLast(":")
?.filter { it.isDigit() }?.toIntOrNull()
val description = document.selectFirst("span.desc p")?.text()
val episodes = document.select("div.episodelist ul li").mapNotNull {
val name = it.selectFirst("a")?.text()
val link = fixUrlNull(it.selectFirst("a")?.attr("href")) ?: return@mapNotNull null
Episode(link, name = name)
}.takeIf { it.isNotEmpty() } ?: listOf(Episode(url, title))
return newAnimeLoadResponse(title, url, TvType.NSFW) {
engName = title
posterUrl = poster
this.year = year
this.duration = duration
addEpisodes(DubStatus.Subbed, episodes)
showStatus = status
plot = description
this.tags = tags
}
}
override suspend fun loadLinks(
data: String,
isCasting: Boolean,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
): Boolean {
val res = app.get(data).document
argamap(
{
res.select("div#show-stream iframe").apmap { iframe ->
loadExtractor(iframe.attr("src"), "$mainUrl/", subtitleCallback, callback)
}
},
{
res.select("div.boxdownload div.liner").map { ele ->
getIndexQuality(
ele.select("div.name").text()
) to ele.selectFirst("a:contains(ouo)")
?.attr("href")
}.filter { it.first != Qualities.P360.value }.map {
val bypassedAds = bypassMirrored(bypassOuo(it.second ?: return@map) ?: return@map)
bypassedAds.apmap ads@{ adsLink ->
loadExtractor(
fixEmbed(adsLink) ?: return@ads,
"$mainUrl/",
subtitleCallback,
) { link ->
callback.invoke(
ExtractorLink(
link.name,
link.name,
link.url,
link.referer,
if(link.isM3u8) link.quality else it.first,
link.isM3u8,
link.headers,
link.extractorData
)
)
}
}
}
}
)
return true
}
private fun fixEmbed(url: String?): String? {
if (url == null) return null
val host = getBaseUrl(url)
return when {
url.contains("streamsb", true) -> url.replace("$host/", "$host/e/")
else -> url
}
}
private fun getBaseUrl(url: String): String {
return URI(url).let {
"${it.scheme}://${it.host}"
}
}
private suspend fun bypassOuo(url: String?): String? {
var res = session.get(url ?: return null)
run lit@{
(1..2).forEach { _ ->
if (res.headers["location"] != null) return@lit
val document = res.document
val nextUrl = document.select("form").attr("action")
val data = document.select("form input").mapNotNull {
it.attr("name") to it.attr("value")
}.toMap().toMutableMap()
val captchaKey =
document.select("script[src*=https://www.google.com/recaptcha/api.js?render=]")
.attr("src").substringAfter("render=")
val token = APIHolder.getCaptchaToken(url, captchaKey)
data["x-token"] = token ?: ""
res = session.post(
nextUrl,
data = data,
headers = mapOf("content-type" to "application/x-www-form-urlencoded"),
allowRedirects = false
)
}
}
return res.headers["location"]
}
private suspend fun bypassMirrored(url: String): List<String?> {
val request = app.get(url)
val hostUrl = getBaseUrl(request.url)
var nextUrl = request.document.selectFirst("div.row div.centered a")?.attr("href")
nextUrl = app.get(nextUrl ?: return emptyList()).text.substringAfter("\"GET\", \"")
.substringBefore("\"")
return app.get(fixUrl(nextUrl, hostUrl)).document.select("table.hoverable tbody tr")
.filter { mirror ->
!mirrorIsBlackList(mirror.selectFirst("img")?.attr("alt"))
}.apmap {
val fileLink = it.selectFirst("a")?.attr("href")
app.get(
fixUrl(
fileLink.toString(),
hostUrl
)
).document.selectFirst("div.code_wrap code")?.text()
}
}
private fun mirrorIsBlackList(host: String?) : Boolean {
return mirrorBlackList.any { it.equals(host, true) }
}
private fun fixUrl(url: String, domain: String): String {
if (url.startsWith("http")) {
return url
}
if (url.isEmpty()) {
return ""
}
val startsWithNoHttp = url.startsWith("//")
if (startsWithNoHttp) {
return "https:$url"
} else {
if (url.startsWith('/')) {
return domain + url
}
return "$domain/$url"
}
}
private fun getIndexQuality(str: String?): Int {
return Regex("(\\d{3,4})[pP]").find(str ?: "")?.groupValues?.getOrNull(1)?.toIntOrNull()
?: Qualities.Unknown.value
}
}

View File

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

View File

@ -1,5 +1,5 @@
// use an integer for version numbers
version = 14
version = 15
cloudstream {

View File

@ -10,7 +10,7 @@ import org.jsoup.nodes.Element
import java.net.URI
class YomoviesProvider : MainAPI() {
override var mainUrl = "https://yomovies.team"
override var mainUrl = "https://yomovies.baby"
private var directUrl = mainUrl
override var name = "Yomovies"
override val hasMainPage = true
@ -142,7 +142,7 @@ class YomoviesProvider : MainAPI() {
callback: (ExtractorLink) -> Unit
): Boolean {
if (data.contains("yomovies")) {
if (data.contains(directUrl.getHost(), true)) {
val doc = app.get(data).document
doc.select("div.movieplay iframe").map { fixUrl(it.attr("src")) }
.apmap { source ->
@ -171,5 +171,8 @@ class YomoviesProvider : MainAPI() {
return true
}
private fun String.getHost(): String {
return fixTitle(URI(this).host.substringBeforeLast(".").substringAfterLast("."))
}
}