Eliminar varios proveedores y actualizar base64 en SoraStream

This commit is contained in:
divinitypoet@hotmail.com 2023-12-23 16:19:36 -04:00
parent 435ac3ebed
commit d471466e1f
274 changed files with 2 additions and 17984 deletions

View File

@ -1,42 +0,0 @@
import org.jetbrains.kotlin.konan.properties.Properties
// use an integer for version numbers
version = 9
android {
defaultConfig {
val properties = Properties()
properties.load(project.rootProject.file("local.properties").inputStream())
buildConfigField("String", "ANICHI_API", "\"${properties.getProperty("ANICHI_API")}\"")
buildConfigField("String", "ANICHI_SERVER", "\"${properties.getProperty("ANICHI_SERVER")}\"")
buildConfigField("String", "ANICHI_ENDPOINT", "\"${properties.getProperty("ANICHI_ENDPOINT")}\"")
buildConfigField("String", "ANICHI_APP", "\"${properties.getProperty("ANICHI_APP")}\"")
}
}
cloudstream {
language = "en"
// All of these properties are optional, you can safely remove them
// description = "Lorem Ipsum"
authors = listOf("Hexated")
/**
* Status int as the following:
* 0: Down
* 1: Ok
* 2: Slow
* 3: Beta only
* */
status = 1 // will be 3 if unspecified
tvTypes = listOf(
"AnimeMovie",
"Anime",
"OVA",
)
iconUrl = "https://media.discordapp.net/attachments/1059306855865782282/1123970193274712096/Anichi.png"
}

View File

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

View File

@ -1,263 +0,0 @@
package com.hexated
import com.hexated.AnichiExtractors.invokeExternalSources
import com.hexated.AnichiExtractors.invokeInternalSources
import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.LoadResponse.Companion.addActors
import com.lagradost.cloudstream3.LoadResponse.Companion.addAniListId
import com.lagradost.cloudstream3.LoadResponse.Companion.addMalId
import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer
import com.lagradost.cloudstream3.syncproviders.SyncIdName
import com.lagradost.cloudstream3.utils.*
import com.lagradost.cloudstream3.utils.AppUtils.parseJson
import com.lagradost.nicehttp.RequestBodyTypes
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.RequestBody.Companion.toRequestBody
open class Anichi : MainAPI() {
override var name = "Anichi"
override val instantLinkLoading = true
override val hasQuickSearch = false
override val hasMainPage = true
private fun getStatus(t: String): ShowStatus {
return when (t) {
"Finished" -> ShowStatus.Completed
"Releasing" -> ShowStatus.Ongoing
else -> ShowStatus.Completed
}
}
override val supportedSyncNames = setOf(SyncIdName.Anilist, SyncIdName.MyAnimeList)
override val supportedTypes = setOf(TvType.Anime, TvType.AnimeMovie)
private val popularTitle = "Popular"
private val animeRecentTitle = "Latest Anime"
private val donghuaRecentTitle = "Latest Donghua"
private val movieTitle = "Movie"
override val mainPage = mainPageOf(
"""$apiUrl?variables={"search":{"sortBy":"Latest_Update","allowAdult":${settingsForProvider.enableAdult},"allowUnknown":false},"limit":26,"page":%d,"translationType":"sub","countryOrigin":"JP"}&extensions={"persistedQuery":{"version":1,"sha256Hash":"$mainHash"}}""" to animeRecentTitle,
"""$apiUrl?variables={"search":{"sortBy":"Latest_Update","allowAdult":${settingsForProvider.enableAdult},"allowUnknown":false},"limit":26,"page":%d,"translationType":"sub","countryOrigin":"CN"}&extensions={"persistedQuery":{"version":1,"sha256Hash":"$mainHash"}}""" to donghuaRecentTitle,
"""$apiUrl?variables={"type":"anime","size":30,"dateRange":1,"page":%d,"allowAdult":${settingsForProvider.enableAdult},"allowUnknown":false}&extensions={"persistedQuery":{"version":1,"sha256Hash":"$popularHash"}}""" to popularTitle,
"""$apiUrl?variables={"search":{"slug":"movie-anime","format":"anime","tagType":"upcoming","name":"Trending Movies"}}&extensions={"persistedQuery":{"version":1,"sha256Hash":"$slugHash"}}""" to movieTitle
)
override suspend fun getMainPage(page: Int, request: MainPageRequest): HomePageResponse {
val url = request.data.format(page)
val res = app.get(url, headers = headers).parsedSafe<AnichiQuery>()?.data
val query = res?.shows ?: res?.queryPopular ?: res?.queryListForTag
val card = if(request.name == popularTitle) query?.recommendations?.map { it.anyCard } else query?.edges
val home = card?.filter {
// filtering in case there is an anime with 0 episodes available on the site.
!(it?.availableEpisodes?.raw == 0 && it.availableEpisodes.sub == 0 && it.availableEpisodes.dub == 0)
}?.mapNotNull { media ->
media?.toSearchResponse()
} ?: emptyList()
return newHomePageResponse(
list = HomePageList(
name = request.name,
list = home,
),
hasNext = request.name != movieTitle
)
}
private fun Edges.toSearchResponse(): AnimeSearchResponse? {
return newAnimeSearchResponse(
name ?: englishName ?: nativeName ?: "",
Id ?: return null,
fix = false
) {
this.posterUrl = thumbnail
this.year = airedStart?.year
this.otherName = englishName
addDub(availableEpisodes?.dub)
addSub(availableEpisodes?.sub)
}
}
override suspend fun search(query: String): List<SearchResponse>? {
val link =
"""$apiUrl?variables={"search":{"allowAdult":false,"allowUnknown":false,"query":"$query"},"limit":26,"page":1,"translationType":"sub","countryOrigin":"ALL"}&extensions={"persistedQuery":{"version":1,"sha256Hash":"$mainHash"}}"""
val res = app.get(
link,
headers = headers
).text.takeUnless { it.contains("PERSISTED_QUERY_NOT_FOUND") }
// Retries
?: app.get(
link,
headers = headers
).text.takeUnless { it.contains("PERSISTED_QUERY_NOT_FOUND") }
?: return emptyList()
val response = parseJson<AnichiQuery>(res)
val results = response.data?.shows?.edges?.filter {
// filtering in case there is an anime with 0 episodes available on the site.
!(it.availableEpisodes?.raw == 0 && it.availableEpisodes.sub == 0 && it.availableEpisodes.dub == 0)
}
return results?.map {
newAnimeSearchResponse(it.name ?: "", "${it.Id}", fix = false) {
this.posterUrl = it.thumbnail
this.year = it.airedStart?.year
this.otherName = it.englishName
addDub(it.availableEpisodes?.dub)
addSub(it.availableEpisodes?.sub)
}
}
}
override suspend fun getLoadUrl(name: SyncIdName, id: String): String? {
val syncId = id.split("/").last()
val malId = if (name == SyncIdName.MyAnimeList) {
syncId
} else {
aniToMal(syncId)
}
val media = app.get("$jikanApi/anime/$malId").parsedSafe<JikanResponse>()?.data
val link =
"""$apiUrl?variables={"search":{"allowAdult":false,"allowUnknown":false,"query":"${media?.title}"},"limit":26,"page":1,"translationType":"sub","countryOrigin":"ALL"}&extensions={"persistedQuery":{"version":1,"sha256Hash":"$mainHash"}}"""
val res = app.get(
link,
headers = headers
).parsedSafe<AnichiQuery>()?.data?.shows?.edges
return res?.find {
(it.name.equals(media?.title, true) || it.englishName.equals(
media?.title_english,
true
) || it.nativeName.equals(media?.title_japanese, true)) && it.airedStart?.year == media?.year
}?.Id
}
override suspend fun load(url: String): LoadResponse? {
val id = url.substringAfterLast("/")
// lazy to format
val body = """
{
"query": " query(\n ${'$'}_id: String!\n ) {\n show(\n _id: ${'$'}_id\n ) {\n _id\n name\n description\n thumbnail\n thumbnails\n lastEpisodeInfo\n lastEpisodeDate \n type\n genres\n score\n status\n season\n altNames \n averageScore\n rating\n episodeCount\n episodeDuration\n broadcastInterval\n banner\n airedEnd\n airedStart \n studios\n characters\n availableEpisodesDetail\n availableEpisodes\n prevideos\n nameOnlyString\n relatedShows\n relatedMangas\n musics\n isAdult\n \n tags\n countryOfOrigin\n\n pageStatus{\n _id\n notes\n pageId\n showId\n \n # ranks:[Object]\n views\n likesCount\n commentCount\n dislikesCount\n reviewCount\n userScoreCount\n userScoreTotalValue\n userScoreAverValue\n viewers{\n firstViewers{\n viewCount\n lastWatchedDate\n user{\n _id\n displayName\n picture\n # description\n hideMe\n # createdAt\n # badges\n brief\n }\n \n }\n recViewers{\n viewCount\n lastWatchedDate\n user{\n _id\n displayName\n picture\n # description\n hideMe\n # createdAt\n # badges\n brief\n }\n \n }\n }\n\n }\n }\n }",
"extensions": "{\"persistedQuery\":{\"version\":1,\"sha256Hash\":\"$detailHash\"}}",
"variables": "{\"_id\":\"$id\"}"
}
""".trimIndent().trim().toRequestBody(RequestBodyTypes.JSON.toMediaTypeOrNull())
val res = app.post(apiUrl, requestBody = body, headers = headers)
val showData = res.parsedSafe<Detail>()?.data?.show ?: return null
val title = showData.name
val description = showData.description
val poster = showData.thumbnail
val trackers = getTracker(
title,
showData.altNames?.firstOrNull(),
showData.airedStart?.year,
showData.season?.quarter,
showData.type
)
val episodes = showData.availableEpisodesDetail.let {
if (it == null) return@let Pair(null, null)
if (showData.Id == null) return@let Pair(null, null)
Pair(
it.getEpisode("sub", showData.Id, trackers?.idMal),
it.getEpisode("dub", showData.Id, trackers?.idMal),
)
}
val characters = showData.characters?.map {
val role = when (it.role) {
"Main" -> ActorRole.Main
"Supporting" -> ActorRole.Supporting
"Background" -> ActorRole.Background
else -> null
}
val name = it.name?.full ?: it.name?.native ?: ""
val image = it.image?.large ?: it.image?.medium
Pair(Actor(name, image), role)
}
return newAnimeLoadResponse(title ?: "", url, TvType.Anime) {
engName = showData.altNames?.firstOrNull()
posterUrl = trackers?.coverImage?.extraLarge ?: trackers?.coverImage?.large ?: poster
backgroundPosterUrl = trackers?.bannerImage ?: showData.banner
rating = showData.averageScore?.times(100)
tags = showData.genres
year = showData.airedStart?.year
duration = showData.episodeDuration?.div(60_000)
addTrailer(showData.prevideos.filter { it.isNotBlank() }
.map { "https://www.youtube.com/watch?v=$it" })
addEpisodes(DubStatus.Subbed, episodes.first)
addEpisodes(DubStatus.Dubbed, episodes.second)
addActors(characters)
//this.recommendations = recommendations
showStatus = getStatus(showData.status.toString())
addMalId(trackers?.idMal)
addAniListId(trackers?.id)
plot = description?.replace(Regex("""<(.*?)>"""), "")
}
}
override suspend fun loadLinks(
data: String,
isCasting: Boolean,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
): Boolean {
val loadData = parseJson<AnichiLoadData>(data)
argamap(
{
invokeInternalSources(
loadData.hash,
loadData.dubStatus,
loadData.episode,
subtitleCallback,
callback
)
},
{
invokeExternalSources(
loadData.idMal,
loadData.dubStatus,
loadData.episode,
subtitleCallback,
callback
)
}
)
return true
}
companion object {
const val apiUrl = BuildConfig.ANICHI_API
const val serverUrl = BuildConfig.ANICHI_SERVER
const val apiEndPoint = BuildConfig.ANICHI_ENDPOINT
const val anilistApi = "https://graphql.anilist.co"
const val jikanApi = "https://api.jikan.moe/v4"
const val marinHost = "https://marin.moe"
private const val mainHash = "e42a4466d984b2c0a2cecae5dd13aa68867f634b16ee0f17b380047d14482406"
private const val popularHash = "31a117653812a2547fd981632e8c99fa8bf8a75c4ef1a77a1567ef1741a7ab9c"
private const val slugHash = "bf603205eb2533ca21d0324a11f623854d62ed838a27e1b3fcfb712ab98b03f4"
private const val detailHash = "bb263f91e5bdd048c1c978f324613aeccdfe2cbc694a419466a31edb58c0cc0b"
const val serverHash = "5e7e17cdd0166af5a2d8f43133d9ce3ce9253d1fdb5160a0cfd515564f98d061"
val headers = mapOf(
"app-version" to "android_c-247",
"from-app" to BuildConfig.ANICHI_APP,
"platformstr" to "android_c",
)
}
}

View File

@ -1,218 +0,0 @@
package com.hexated
import com.lagradost.cloudstream3.SubtitleFile
import com.lagradost.cloudstream3.apmap
import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.argamap
import com.lagradost.cloudstream3.extractors.helper.GogoHelper
import com.lagradost.cloudstream3.mvvm.safeApiCall
import com.lagradost.cloudstream3.utils.AppUtils
import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.Qualities
import com.lagradost.cloudstream3.utils.SubtitleHelper
import com.lagradost.cloudstream3.utils.httpsify
import com.lagradost.cloudstream3.utils.loadExtractor
import java.net.URI
object AnichiExtractors : Anichi() {
suspend fun invokeInternalSources(
hash: String,
dubStatus: String,
episode: String,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit,
) {
val apiUrl =
"""$apiUrl?variables={"showId":"$hash","translationType":"$dubStatus","episodeString":"$episode"}&extensions={"persistedQuery":{"version":1,"sha256Hash":"$serverHash"}}"""
val apiResponse = app.get(apiUrl, headers = headers).parsed<LinksQuery>()
apiResponse.data?.episode?.sourceUrls?.apmap { source ->
safeApiCall {
val link = fixSourceUrls(source.sourceUrl ?: return@safeApiCall, source.sourceName)
?: return@safeApiCall
if (URI(link).isAbsolute || link.startsWith("//")) {
val fixedLink = if (link.startsWith("//")) "https:$link" else link
val host = link.getHost()
when {
fixedLink.contains(Regex("(?i)playtaku|gogo")) || source.sourceName == "Vid-mp4" -> {
invokeGogo(fixedLink, subtitleCallback, callback)
}
embedIsBlacklisted(fixedLink) -> {
loadExtractor(fixedLink, subtitleCallback, callback)
}
URI(fixedLink).path.contains(".m3u") -> {
getM3u8Qualities(fixedLink, serverUrl, host).forEach(callback)
}
else -> {
callback(
ExtractorLink(
name,
host,
fixedLink,
serverUrl,
Qualities.P1080.value,
false
)
)
}
}
} else {
val fixedLink = link.fixUrlPath()
val links = app.get(fixedLink).parsedSafe<AnichiVideoApiResponse>()?.links
?: emptyList()
links.forEach { server ->
val host = server.link.getHost()
when {
source.sourceName?.contains("Default") == true -> {
if (server.resolutionStr == "SUB" || server.resolutionStr == "Alt vo_SUB") {
getM3u8Qualities(
server.link,
"https://static.crunchyroll.com/",
host,
).forEach(callback)
}
}
server.hls != null && server.hls -> {
getM3u8Qualities(
server.link,
"$apiEndPoint/player?uri=" + (if (URI(server.link).host.isNotEmpty()) server.link else apiEndPoint + URI(
server.link
).path),
host
).forEach(callback)
}
else -> {
callback(
ExtractorLink(
host,
host,
server.link,
"$apiEndPoint/player?uri=" + (if (URI(server.link).host.isNotEmpty()) server.link else apiEndPoint + URI(
server.link
).path),
server.resolutionStr.removeSuffix("p").toIntOrNull()
?: Qualities.P1080.value,
false,
isDash = server.resolutionStr == "Dash 1"
)
)
server.subtitles?.map { sub ->
subtitleCallback.invoke(
SubtitleFile(
SubtitleHelper.fromTwoLettersToLanguage(sub.lang ?: "")
?: sub.lang ?: "",
httpsify(sub.src ?: return@map)
)
)
}
}
}
}
}
}
}
}
suspend fun invokeExternalSources(
idMal: Int? = null,
dubStatus: String,
episode: String,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit,
) {
val ids = app.get("https://api.malsync.moe/mal/anime/${idMal ?: return}")
.parsedSafe<MALSyncResponses>()?.sites
if (dubStatus == "sub") invokeMarin(ids?.marin?.keys?.firstOrNull(), episode, callback)
}
private suspend fun invokeMarin(
id: String? = null,
episode: String,
callback: (ExtractorLink) -> Unit
) {
val url = "$marinHost/anime/${id ?: return}/$episode"
val cookies = app.get(
"$marinHost/anime",
headers = mapOf(
"Cookie" to "__ddg1_=;__ddg2_=;"
),
referer = "$marinHost/anime",
).cookies.let {
decode(it["XSRF-TOKEN"].toString()) to decode(it["marin_session"].toString())
}
val json = app.get(
url,
headers = mapOf(
"Accept" to "text/html, application/xhtml+xml",
"Cookie" to "__ddg1=;__ddg2_=;XSRF-TOKEN=${cookies.first};marin_session=${cookies.second};",
"X-XSRF-TOKEN" to cookies.first
),
referer = "$marinHost/anime/$id"
).document.selectFirst("div#app")?.attr("data-page")
tryParseJson<MarinResponses>(json)?.props?.video?.data?.mirror?.map { video ->
callback.invoke(
ExtractorLink(
"Marin",
"Marin",
video.code?.file ?: return@map,
url,
video.code.height ?: Qualities.Unknown.value,
headers = mapOf(
"Accept" to "video/webm,video/ogg,video/*;q=0.9,application/ogg;q=0.7,audio/*;q=0.6,*/*;q=0.5",
"Accept-Language" to "en-US,en;q=0.5",
"Cookie" to "__ddg1=;__ddg2_=; XSRF-TOKEN=${cookies.first}; marin_session=${cookies.second};",
"Connection" to "keep-alive",
"Sec-Fetch-Dest" to "video",
"Sec-Fetch-Mode" to "cors",
"Sec-Fetch-Site" to "cross-site",
)
)
)
}
}
private suspend fun invokeGogo(
link: String,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
) {
val iframe = app.get(link)
val iframeDoc = iframe.document
argamap({
iframeDoc.select(".list-server-items > .linkserver")
.forEach { element ->
val status = element.attr("data-status") ?: return@forEach
if (status != "1") return@forEach
val extractorData = element.attr("data-video") ?: return@forEach
loadExtractor(extractorData, iframe.url, subtitleCallback, callback)
}
}, {
val iv = "3134003223491201"
val secretKey = "37911490979715163134003223491201"
val secretDecryptKey = "54674138327930866480207815084989"
GogoHelper.extractVidstream(
iframe.url,
"Gogoanime",
callback,
iv,
secretKey,
secretDecryptKey,
isUsingAdaptiveKeys = false,
isUsingAdaptiveData = true,
iframeDocument = iframeDoc
)
})
}
}

View File

@ -1,292 +0,0 @@
package com.hexated
import com.fasterxml.jackson.annotation.JsonProperty
data class AnichiLoadData(
val hash: String,
val dubStatus: String,
val episode: String,
val idMal: Int? = null,
)
data class JikanData(
@JsonProperty("title") val title: String? = null,
@JsonProperty("title_english") val title_english: String? = null,
@JsonProperty("title_japanese") val title_japanese: String? = null,
@JsonProperty("year") val year: Int? = null,
@JsonProperty("season") val season: String? = null,
@JsonProperty("type") val type: String? = null,
)
data class JikanResponse(
@JsonProperty("data") val data: JikanData? = null,
)
data class IdMal(
@JsonProperty("idMal") val idMal: String? = null,
)
data class MediaAni(
@JsonProperty("Media") val media: IdMal? = null,
)
data class DataAni(
@JsonProperty("data") val data: MediaAni? = null,
)
data class CoverImage(
@JsonProperty("extraLarge") var extraLarge: String? = null,
@JsonProperty("large") var large: String? = null,
)
data class AniMedia(
@JsonProperty("id") var id: Int? = null,
@JsonProperty("idMal") var idMal: Int? = null,
@JsonProperty("coverImage") var coverImage: CoverImage? = null,
@JsonProperty("bannerImage") var bannerImage: String? = null,
)
data class AniPage(
@JsonProperty("media") var media: ArrayList<AniMedia> = arrayListOf()
)
data class AniData(
@JsonProperty("Page") var Page: AniPage? = AniPage()
)
data class AniSearch(
@JsonProperty("data") var data: AniData? = AniData()
)
data class AkIframe(
@JsonProperty("idUrl") val idUrl: String? = null,
)
data class Stream(
@JsonProperty("format") val format: String? = null,
@JsonProperty("audio_lang") val audio_lang: String? = null,
@JsonProperty("hardsub_lang") val hardsub_lang: String? = null,
@JsonProperty("url") val url: String? = null,
)
data class PortData(
@JsonProperty("streams") val streams: ArrayList<Stream>? = arrayListOf(),
)
data class Subtitles(
@JsonProperty("lang") val lang: String?,
@JsonProperty("label") val label: String?,
@JsonProperty("src") val src: String?,
)
data class Links(
@JsonProperty("link") val link: String,
@JsonProperty("hls") val hls: Boolean?,
@JsonProperty("resolutionStr") val resolutionStr: String,
@JsonProperty("src") val src: String?,
@JsonProperty("portData") val portData: PortData? = null,
@JsonProperty("subtitles") val subtitles: ArrayList<Subtitles>? = arrayListOf(),
)
data class AnichiVideoApiResponse(
@JsonProperty("links") val links: List<Links>
)
data class Data(
@JsonProperty("shows") val shows: Shows? = null,
@JsonProperty("queryListForTag") val queryListForTag: Shows? = null,
@JsonProperty("queryPopular") val queryPopular: Shows? = null,
)
data class Shows(
@JsonProperty("edges") val edges: List<Edges>? = arrayListOf(),
@JsonProperty("recommendations") val recommendations: List<EdgesCard>? = arrayListOf(),
)
data class EdgesCard(
@JsonProperty("anyCard") val anyCard: Edges? = null,
)
data class CharacterImage(
@JsonProperty("large") val large: String?,
@JsonProperty("medium") val medium: String?
)
data class CharacterName(
@JsonProperty("full") val full: String?,
@JsonProperty("native") val native: String?
)
data class Characters(
@JsonProperty("image") val image: CharacterImage?,
@JsonProperty("role") val role: String?,
@JsonProperty("name") val name: CharacterName?,
)
data class Edges(
@JsonProperty("_id") val Id: String?,
@JsonProperty("name") val name: String?,
@JsonProperty("englishName") val englishName: String?,
@JsonProperty("nativeName") val nativeName: String?,
@JsonProperty("thumbnail") val thumbnail: String?,
@JsonProperty("type") val type: String?,
@JsonProperty("season") val season: Season?,
@JsonProperty("score") val score: Double?,
@JsonProperty("airedStart") val airedStart: AiredStart?,
@JsonProperty("availableEpisodes") val availableEpisodes: AvailableEpisodes?,
@JsonProperty("availableEpisodesDetail") val availableEpisodesDetail: AvailableEpisodesDetail?,
@JsonProperty("studios") val studios: List<String>?,
@JsonProperty("genres") val genres: List<String>?,
@JsonProperty("averageScore") val averageScore: Int?,
@JsonProperty("characters") val characters: List<Characters>?,
@JsonProperty("altNames") val altNames: List<String>?,
@JsonProperty("description") val description: String?,
@JsonProperty("status") val status: String?,
@JsonProperty("banner") val banner: String?,
@JsonProperty("episodeDuration") val episodeDuration: Int?,
@JsonProperty("prevideos") val prevideos: List<String> = emptyList(),
)
data class AvailableEpisodes(
@JsonProperty("sub") val sub: Int,
@JsonProperty("dub") val dub: Int,
@JsonProperty("raw") val raw: Int
)
data class AiredStart(
@JsonProperty("year") val year: Int,
@JsonProperty("month") val month: Int,
@JsonProperty("date") val date: Int
)
data class Season(
@JsonProperty("quarter") val quarter: String,
@JsonProperty("year") val year: Int
)
data class AnichiQuery(
@JsonProperty("data") val data: Data? = null
)
data class Detail(
@JsonProperty("data") val data: DetailShow
)
data class DetailShow(
@JsonProperty("show") val show: Edges
)
data class AvailableEpisodesDetail(
@JsonProperty("sub") val sub: List<String>,
@JsonProperty("dub") val dub: List<String>,
@JsonProperty("raw") val raw: List<String>
)
data class LinksQuery(
@JsonProperty("data") val data: LinkData? = LinkData()
)
data class LinkData(
@JsonProperty("episode") val episode: Episode? = Episode()
)
data class SourceUrls(
@JsonProperty("sourceUrl") val sourceUrl: String? = null,
@JsonProperty("priority") val priority: Int? = null,
@JsonProperty("sourceName") val sourceName: String? = null,
@JsonProperty("type") val type: String? = null,
@JsonProperty("className") val className: String? = null,
@JsonProperty("streamerId") val streamerId: String? = null
)
data class Episode(
@JsonProperty("sourceUrls") val sourceUrls: ArrayList<SourceUrls> = arrayListOf(),
)
data class Sub(
@JsonProperty("hour") val hour: Int? = null,
@JsonProperty("minute") val minute: Int? = null,
@JsonProperty("year") val year: Int? = null,
@JsonProperty("month") val month: Int? = null,
@JsonProperty("date") val date: Int? = null
)
data class LastEpisodeDate(
@JsonProperty("dub") val dub: Sub? = Sub(),
@JsonProperty("sub") val sub: Sub? = Sub(),
@JsonProperty("raw") val raw: Sub? = Sub()
)
data class AnyCard(
@JsonProperty("_id") val Id: String? = null,
@JsonProperty("name") val name: String? = null,
@JsonProperty("englishName") val englishName: String? = null,
@JsonProperty("nativeName") val nativeName: String? = null,
@JsonProperty("availableEpisodes") val availableEpisodes: AvailableEpisodes? = null,
@JsonProperty("score") val score: Double? = null,
@JsonProperty("lastEpisodeDate") val lastEpisodeDate: LastEpisodeDate? = LastEpisodeDate(),
@JsonProperty("thumbnail") val thumbnail: String? = null,
@JsonProperty("lastChapterDate") val lastChapterDate: String? = null,
@JsonProperty("availableChapters") val availableChapters: String? = null,
@JsonProperty("__typename") val _typename: String? = null
)
data class PageStatus(
@JsonProperty("_id") val Id: String? = null,
@JsonProperty("views") val views: String? = null,
@JsonProperty("showId") val showId: String? = null,
@JsonProperty("rangeViews") val rangeViews: String? = null,
@JsonProperty("isManga") val isManga: Boolean? = null,
@JsonProperty("__typename") val _typename: String? = null
)
data class Recommendations(
@JsonProperty("anyCard") val anyCard: AnyCard? = null,
@JsonProperty("pageStatus") val pageStatus: PageStatus? = PageStatus(),
@JsonProperty("__typename") val _typename: String? = null
)
data class QueryPopular(
@JsonProperty("total") val total: Int? = null,
@JsonProperty("recommendations") val recommendations: ArrayList<Recommendations> = arrayListOf(),
@JsonProperty("__typename") val _typename: String? = null
)
data class DataPopular(
@JsonProperty("queryPopular") val queryPopular: QueryPopular? = QueryPopular()
)
data class MALSyncSites(
@JsonProperty("Zoro") val zoro: HashMap<String?, HashMap<String, String?>>? = hashMapOf(),
@JsonProperty("Marin") val marin: HashMap<String?, HashMap<String, String?>>? = hashMapOf(),
)
data class MALSyncResponses(
@JsonProperty("Sites") val sites: MALSyncSites? = null,
)
data class MarinCode(
@JsonProperty("file") val file: String? = null,
@JsonProperty("height") val height: Int? = null,
)
data class MarinMirror(
@JsonProperty("code") val code: MarinCode? = null,
)
data class MarinData(
@JsonProperty("mirror") val mirror: ArrayList<MarinMirror>? = arrayListOf(),
)
data class MarinVideos(
@JsonProperty("data") val data: MarinData? = null,
)
data class MarinProps(
@JsonProperty("video") val video: MarinVideos? = null,
)
data class MarinResponses(
@JsonProperty("props") val props: MarinProps? = null,
)

View File

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

View File

@ -1,147 +0,0 @@
package com.hexated
import com.hexated.Anichi.Companion.anilistApi
import com.hexated.Anichi.Companion.apiEndPoint
import com.lagradost.cloudstream3.Episode
import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.base64Decode
import com.lagradost.cloudstream3.fixTitle
import com.lagradost.cloudstream3.mvvm.logError
import com.lagradost.cloudstream3.utils.AppUtils
import com.lagradost.cloudstream3.utils.AppUtils.toJson
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.M3u8Helper
import com.lagradost.nicehttp.RequestBodyTypes
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.RequestBody.Companion.toRequestBody
import java.net.URI
import java.net.URLDecoder
suspend fun getTracker(name: String?, altName: String?, year: Int?, season: String?, type: String?): AniMedia? {
return fetchId(name, year, season, type).takeIf { it?.id != null } ?: fetchId(
altName,
year,
season,
type
)
}
suspend fun fetchId(title: String?, year: Int?, season: String?, type: String?): AniMedia? {
val query = """
query (
${'$'}page: Int = 1
${'$'}search: String
${'$'}sort: [MediaSort] = [POPULARITY_DESC, SCORE_DESC]
${'$'}type: MediaType
${'$'}season: MediaSeason
${'$'}year: String
${'$'}format: [MediaFormat]
) {
Page(page: ${'$'}page, perPage: 20) {
media(
search: ${'$'}search
sort: ${'$'}sort
type: ${'$'}type
season: ${'$'}season
startDate_like: ${'$'}year
format_in: ${'$'}format
) {
id
idMal
coverImage { extraLarge large }
bannerImage
}
}
}
""".trimIndent().trim()
val variables = mapOf(
"search" to title,
"sort" to "SEARCH_MATCH",
"type" to "ANIME",
"season" to if(type.equals("ona", true)) "" else season?.uppercase(),
"year" to "$year%",
"format" to listOf(type?.uppercase())
).filterValues { value -> value != null && value.toString().isNotEmpty() }
val data = mapOf(
"query" to query,
"variables" to variables
).toJson().toRequestBody(RequestBodyTypes.JSON.toMediaTypeOrNull())
return try {
app.post(anilistApi, requestBody = data)
.parsedSafe<AniSearch>()?.data?.Page?.media?.firstOrNull()
} catch (t: Throwable) {
logError(t)
null
}
}
suspend fun aniToMal(id: String): String? {
return app.post(
anilistApi, data = mapOf(
"query" to "{Media(id:$id,type:ANIME){idMal}}",
)
).parsedSafe<DataAni>()?.data?.media?.idMal
}
fun decode(input: String): String = URLDecoder.decode(input, "utf-8")
private val embedBlackList = listOf(
"https://mp4upload.com/",
"https://streamsb.net/",
"https://dood.to/",
"https://videobin.co/",
"https://ok.ru",
"https://streamlare.com",
"https://filemoon",
"streaming.php",
)
fun embedIsBlacklisted(url: String): Boolean {
return embedBlackList.any { url.contains(it) }
}
fun AvailableEpisodesDetail.getEpisode(
lang: String,
id: String,
malId: Int?,
): List<Episode> {
val meta = if (lang == "sub") this.sub else this.dub
return meta.map { eps ->
Episode(
AnichiLoadData(id, lang, eps, malId).toJson(),
episode = eps.toIntOrNull()
)
}.reversed()
}
suspend fun getM3u8Qualities(
m3u8Link: String,
referer: String,
qualityName: String,
): List<ExtractorLink> {
return M3u8Helper.generateM3u8(
qualityName,
m3u8Link,
referer,
)
}
fun String.getHost(): String {
return fixTitle(URI(this).host.substringBeforeLast(".").substringAfterLast("."))
}
fun String.fixUrlPath() : String {
return if(this.contains(".json?")) apiEndPoint + this else apiEndPoint + URI(this).path + ".json?" + URI(this).query
}
fun fixSourceUrls(url: String, source: String?) : String? {
return if(source == "Ak" || url.contains("/player/vitemb")) {
AppUtils.tryParseJson<AkIframe>(base64Decode(url.substringAfter("=")))?.idUrl
} else {
url.replace(" ", "%20")
}
}

View File

@ -1,27 +0,0 @@
// use an integer for version numbers
version = 1
cloudstream {
language = "de"
// All of these properties are optional, you can safely remove them
// description = "Lorem Ipsum"
authors = listOf("Hexated")
/**
* Status int as the following:
* 0: Down
* 1: Ok
* 2: Slow
* 3: Beta only
* */
status = 0 // will be 3 if unspecified
tvTypes = listOf(
"AnimeMovie",
"Anime",
"OVA",
)
iconUrl = "https://www.google.com/s2/favicons?domain=anifreakz.com&sz=%size%"
}

View File

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

View File

@ -1,193 +0,0 @@
package com.hexated
import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.Qualities
import com.lagradost.cloudstream3.utils.getAndUnpack
import org.jsoup.nodes.Element
import java.net.URLDecoder
class Anifreakz : MainAPI() {
override var mainUrl = "https://anifreakz.com"
override var name = "Anifreakz"
override val hasMainPage = true
override var lang = "de"
override val hasDownloadSupport = true
override val supportedTypes = setOf(
TvType.Anime,
TvType.AnimeMovie,
TvType.OVA
)
override val mainPage = mainPageOf(
"$mainUrl/series?filter=null&page=" to "Anime Neuste",
"$mainUrl/series?filter={\"sorting\":\"popular\"}&page=" to "Anime Angesagt",
"$mainUrl/series?filter={\"sorting\":\"released\"}&page=" to "Anime Veröffentlicht",
"$mainUrl/kalender" to "Anime Kalender",
)
override suspend fun getMainPage(
page: Int,
request: MainPageRequest
): HomePageResponse {
val items = mutableListOf<HomePageList>()
val nonPaged = request.name == "Anime Kalender" && page <= 1
if (!nonPaged) {
val document = app.get(request.data + page).document
val home = document.select("div.app-section div.col").mapNotNull {
it.toSearchResult()
}
items.add(HomePageList(request.name, home))
}
if (nonPaged) {
val document = app.get(request.data).document
document.select("div.app-content div.app-section").forEach { block ->
val header = block.selectFirst("div.app-heading div.text")?.ownText() ?: ""
val home = block.select("div.col").mapNotNull {
it.toSearchResult()
}
items.add(HomePageList(header, home))
}
}
return newHomePageResponse(items)
}
private fun Element.toSearchResult(): AnimeSearchResponse? {
val href = fixUrl(this.selectFirst("a")?.attr("href") ?: return null)
val title = this.selectFirst("a.list-title")?.text()?.trim() ?: return null
val posterUrl = fixUrlNull(this.selectFirst("div.media-cover")?.attr("data-src"))
return newAnimeSearchResponse(title, href, TvType.Anime) {
this.posterUrl = posterUrl
}
}
override suspend fun search(query: String): List<SearchResponse> {
val document = app.get("$mainUrl/search/$query").document
return document.select("div.app-section div.col").mapNotNull {
it.toSearchResult()
}
}
private fun decode(input: String): String? = URLDecoder.decode(input, "utf-8")
override suspend fun load(url: String): LoadResponse? {
val document = app.get(url).document
val title =
document.selectFirst("div.pl-md-4 h1, div.caption-content h1")?.text() ?: return null
val poster = fixUrlNull(document.selectFirst("div.media.media-cover")?.attr("data-src"))
val tags = document.select("div.categories a").map { it.text() }
val rating = document.selectFirst("div.featured-box div:contains(IMDB) div.text")?.text()
.toRatingInt()
val year =
document.selectFirst("div.featured-box div:contains(Veröffentlicht) div.text")?.text()
?.trim()?.toIntOrNull()
val type = if (document.select("div.episodes.tab-content")
.isNullOrEmpty()
) TvType.Movie else TvType.TvSeries
val description =
document.select("div.detail-attr div.text-content, div.caption div:contains(Übersicht) div.text")
.text().trim()
val trailer = document.selectFirst("button:contains(Trailer)")?.attr("data-remote")
?.substringAfter("?trailer=")?.let {
decode(it)
}
return if (type == TvType.Movie) {
newMovieLoadResponse(title, url, type, url) {
posterUrl = poster
this.year = year
this.rating = rating
plot = description
this.tags = tags
addTrailer(trailer)
}
} else {
val subEpisodes = mutableListOf<Episode>()
document.select("div.episodes.tab-content div[id*=season-]").forEach { season ->
val seasonNum = season.attr("id").substringAfterLast("-").toIntOrNull()
season.select("a").map { eps ->
val href = eps.attr("href")
val name = eps.select("div.name").text()
val episode =
eps.select("div.episode").text().substringBefore(".").toIntOrNull()
val episodes = Episode(
href,
name,
seasonNum,
episode
)
subEpisodes.add(episodes)
}
}
newAnimeLoadResponse(title, url, type) {
posterUrl = poster
this.year = year
addEpisodes(DubStatus.Subbed, subEpisodes)
this.rating = rating
plot = description
this.tags = tags
addTrailer(trailer)
}
}
}
override suspend fun loadLinks(
data: String,
isCasting: Boolean,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
): Boolean {
val document = app.get(data).document
val servers = mutableListOf<Pair<String, String>>()
document.select("div[aria-labelledby=videoSource] button").map {
servers.add(it.attr("data-embed") to it.text())
}
document.select("div.nav-player-select a").map {
servers.add(it.attr("data-embed") to it.select("span").text())
}
servers.distinctBy { it.first }.apmap { (id, source) ->
val iframe = app.post(
"$mainUrl/ajax/embed",
data = mapOf("id" to id, "captcha" to ""),
headers = mapOf(
"X-Requested-With" to "XMLHttpRequest"
),
referer = data
).document.select("iframe").attr("src")
val doc = app.get(iframe, referer = "$mainUrl/").document
val link =
unpackJs(doc)?.substringAfter("file:\"")?.substringBefore("\"") ?: return@apmap null
callback.invoke(
ExtractorLink(
source,
source,
link,
"https://filemoon.sx/",
Qualities.Unknown.value,
isM3u8 = link.contains(".m3u8")
)
)
}
return true
}
private fun unpackJs(script: Element): String? {
return script.select("script").find { it.data().contains("eval(function(p,a,c,k,e,d)") }
?.data()?.let { getAndUnpack(it) }
}
}

View File

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

View File

@ -1,27 +0,0 @@
// use an integer for version numbers
version = 2
cloudstream {
language = "ru"
// All of these properties are optional, you can safely remove them
// description = "Lorem Ipsum"
authors = listOf("Hexated")
/**
* Status int as the following:
* 0: Down
* 1: Ok
* 2: Slow
* 3: Beta only
* */
status = 1 // will be 3 if unspecified
tvTypes = listOf(
"AnimeMovie",
"OVA",
"Anime",
)
iconUrl = "https://raw.githubusercontent.com/hexated/cloudstream-extensions-hexated/master/Anilibria/icon.png"
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

View File

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

View File

@ -1,197 +0,0 @@
package com.hexated
import com.fasterxml.jackson.annotation.JsonProperty
import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.LoadResponse.Companion.addAniListId
import com.lagradost.cloudstream3.LoadResponse.Companion.addMalId
import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.getQualityFromName
import org.jsoup.Jsoup
import org.jsoup.nodes.Element
class Anilibria : MainAPI() {
override var mainUrl = "https://anilibria.tv"
override var name = "Anilibria"
override val hasMainPage = true
override var lang = "ru"
override val hasDownloadSupport = true
override val supportedTypes = setOf(
TvType.Anime,
TvType.AnimeMovie,
TvType.OVA
)
companion object {
fun getType(t: String): TvType {
return when {
t.contains("Фильм", true) -> TvType.Movie
t.contains("ТВ", true) -> TvType.Anime
else -> TvType.OVA
}
}
}
override val mainPage = mainPageOf(
"1" to "Новое",
"2" to "Популярное",
)
override suspend fun getMainPage(
page: Int,
request: MainPageRequest
): HomePageResponse {
val document = app.post(
"$mainUrl/public/catalog.php", data = mapOf(
"page" to "$page",
"xpage" to "catalog",
"sort" to request.data,
"finish" to "1",
"search" to "{\"year\":\"\",\"genre\":\"\",\"season\":\"\"}"
), headers = mapOf("X-Requested-With" to "XMLHttpRequest")
).parsedSafe<Home>()?.table?.let { Jsoup.parse(it) }
val home = document?.select("a")?.mapNotNull {
it.toSearchResult()
} ?: throw ErrorLoadingException("Invalid json responses")
return newHomePageResponse(request.name, home)
}
private fun Element.toSearchResult(): AnimeSearchResponse? {
val href = fixUrl(this.attr("href"))
val title = this.selectFirst("span")?.text() ?: return null
val posterUrl = fixUrlNull(this.selectFirst("img")?.attr("src"))
return newAnimeSearchResponse(title, href, TvType.Anime) {
this.posterUrl = posterUrl
addDubStatus(isDub = true)
}
}
override suspend fun search(query: String): List<SearchResponse> {
val document = app.post(
"$mainUrl/public/search.php",
data = mapOf("search" to query, "small" to "1"),
headers = mapOf("X-Requested-With" to "XMLHttpRequest")
).parsedSafe<Search>()?.mes?.let { Jsoup.parse(it) }
return document?.select("a")?.mapNotNull {
it.toSearchResult()
} ?: throw ErrorLoadingException("Invalid json responses")
}
override suspend fun load(url: String): LoadResponse? {
val document = app.get(url).document
val title = document.selectFirst("h1.release-title")?.text() ?: return null
val poster = fixUrlNull(document.selectFirst("img#adminPoster")?.attr("src"))
val trackTitle = (document.selectFirst("h1.release-title br")?.nextSibling()
?: document.selectFirst("h1.release-title")?.text()?.substringAfter("/")?.trim()).toString()
val type = document.selectFirst("div#xreleaseInfo b:contains(Тип:)")?.nextSibling()
.toString().substringBefore(",").trim()
val trackType = type.let {
if(it.contains("Фильм", true)) "movie" else "tv"
}
val year = document.selectFirst("div#xreleaseInfo b:contains(Сезон:)")?.nextElementSibling()
?.text()?.filter { it.isDigit() }?.toIntOrNull()
val (malId, anilistId, image, cover) = getTracker(trackTitle, trackType, year)
val episodes = document.select("script").find { it.data().contains("var player =") }?.data()
?.substringAfter("file:[")?.substringBefore("],")?.let { data ->
tryParseJson<List<Episodes>>("[$data]")?.mapNotNull { eps ->
Episode(
eps.file ?: return@mapNotNull null,
name = eps.title ?: return@mapNotNull null,
posterUrl = fixUrlNull(eps.poster),
)
}
}
return newAnimeLoadResponse(title, url, getType(type)) {
posterUrl = image ?: poster
backgroundPosterUrl = cover ?: image ?: poster
this.year = year
addEpisodes(DubStatus.Subbed, episodes)
plot = document.select("p.detail-description").text().trim()
this.tags = document.selectFirst("div#xreleaseInfo b:contains(Жанры:)")?.nextSibling()
.toString().split(",").map { it.trim() }
addMalId(malId)
addAniListId(anilistId?.toIntOrNull())
}
}
override suspend fun loadLinks(
data: String,
isCasting: Boolean,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
): Boolean {
data.split(",").map { it.trim() }.map { m3u ->
val quality = Regex("\\[([0-9]+p)]").find(m3u)?.groupValues?.getOrNull(1)
val link = m3u.removePrefix("[$quality]").trim()
callback.invoke(
ExtractorLink(
this.name,
this.name,
link,
"$mainUrl/",
getQualityFromName(quality),
true
)
)
}
return true
}
private suspend fun getTracker(title: String?, type: String?, year: Int?): Tracker {
val res = app.get("https://api.consumet.org/meta/anilist/$title")
.parsedSafe<AniSearch>()?.results?.find { media ->
(media.title?.english.equals(title, true) || media.title?.romaji.equals(
title,
true
)) || (media.type.equals(type, true) && media.releaseDate == year)
}
return Tracker(res?.malId, res?.aniId, res?.image, res?.cover)
}
data class Tracker(
val malId: Int? = null,
val aniId: String? = null,
val image: String? = null,
val cover: String? = null,
)
data class Title(
@JsonProperty("romaji") val romaji: String? = null,
@JsonProperty("english") val english: String? = null,
)
data class Results(
@JsonProperty("id") val aniId: String? = null,
@JsonProperty("malId") val malId: Int? = null,
@JsonProperty("title") val title: Title? = null,
@JsonProperty("releaseDate") val releaseDate: Int? = null,
@JsonProperty("type") val type: String? = null,
@JsonProperty("image") val image: String? = null,
@JsonProperty("cover") val cover: String? = null,
)
data class AniSearch(
@JsonProperty("results") val results: ArrayList<Results>? = arrayListOf(),
)
private data class Episodes(
@JsonProperty("file") val file: String? = null,
@JsonProperty("title") val title: String? = null,
@JsonProperty("poster") val poster: String? = null,
)
private data class Home(
@JsonProperty("table") val table: String? = null,
)
private data class Search(
@JsonProperty("mes") val mes: String? = null,
)
}

View File

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

View File

@ -1,27 +0,0 @@
// use an integer for version numbers
version = 9
cloudstream {
language = "id"
// All of these properties are optional, you can safely remove them
// description = "Lorem Ipsum"
authors = listOf("Hexated")
/**
* Status int as the following:
* 0: Down
* 1: Ok
* 2: Slow
* 3: Beta only
* */
status = 1 // will be 3 if unspecified
tvTypes = listOf(
"AnimeMovie",
"OVA",
"Anime",
)
iconUrl = "https://www.google.com/s2/favicons?domain=animasu.cc&sz=%size%"
}

View File

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

View File

@ -1,191 +0,0 @@
package com.hexated
import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.LoadResponse.Companion.addAniListId
import com.lagradost.cloudstream3.LoadResponse.Companion.addMalId
import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer
import com.lagradost.cloudstream3.utils.*
import org.jsoup.Jsoup
import org.jsoup.nodes.Element
class Animasu : MainAPI() {
override var mainUrl = "https://animasu.win"
override var name = "Animasu"
override val hasMainPage = true
override var lang = "id"
override val hasDownloadSupport = true
override val supportedTypes = setOf(
TvType.Anime,
TvType.AnimeMovie,
TvType.OVA
)
companion object {
fun getType(t: String?): TvType {
if(t == null) return TvType.Anime
return when {
t.contains("Tv", true) -> TvType.Anime
t.contains("Movie", true) -> TvType.AnimeMovie
t.contains("OVA", true) || t.contains("Special", true) -> TvType.OVA
else -> TvType.Anime
}
}
fun getStatus(t: String?): ShowStatus {
if(t == null) return ShowStatus.Completed
return when {
t.contains("Sedang Tayang", true) -> ShowStatus.Ongoing
else -> ShowStatus.Completed
}
}
}
override val mainPage = mainPageOf(
"urutan=update" to "Baru diupdate",
"status=&tipe=&urutan=publikasi" to "Baru ditambahkan",
"status=&tipe=&urutan=populer" to "Terpopuler",
"status=&tipe=&urutan=rating" to "Rating Tertinggi",
"status=&tipe=Movie&urutan=update" to "Movie Terbaru",
"status=&tipe=Movie&urutan=populer" to "Movie Terpopuler",
)
override suspend fun getMainPage(page: Int, request: MainPageRequest): HomePageResponse {
val document = app.get("$mainUrl/pencarian/?${request.data}&halaman=$page").document
val home = document.select("div.listupd div.bs").map {
it.toSearchResult()
}
return newHomePageResponse(request.name, home)
}
private fun getProperAnimeLink(uri: String): String {
return if (uri.contains("/anime/")) {
uri
} else {
var title = uri.substringAfter("$mainUrl/")
title = when {
(title.contains("-episode")) && !(title.contains("-movie")) -> title.substringBefore(
"-episode"
)
(title.contains("-movie")) -> title.substringBefore("-movie")
else -> title
}
"$mainUrl/anime/$title"
}
}
private fun Element.toSearchResult(): AnimeSearchResponse {
val href = getProperAnimeLink(fixUrlNull(this.selectFirst("a")?.attr("href")).toString())
val title = this.select("div.tt").text().trim()
val posterUrl = fixUrlNull(this.selectFirst("img")?.getImageAttr())
val epNum = this.selectFirst("span.epx")?.text()?.filter { it.isDigit() }?.toIntOrNull()
return newAnimeSearchResponse(title, href, TvType.Anime) {
this.posterUrl = posterUrl
addSub(epNum)
}
}
override suspend fun search(query: String): List<SearchResponse> {
return app.get("$mainUrl/?s=$query").document.select("div.listupd div.bs").map {
it.toSearchResult()
}
}
override suspend fun load(url: String): LoadResponse {
val document = app.get(url).document
val title = document.selectFirst("div.infox h1")?.text().toString().replace("Sub Indo", "").trim()
val poster = document.selectFirst("div.bigcontent img")?.getImageAttr()
val table = document.selectFirst("div.infox div.spe")
val type = getType(table?.selectFirst("span:contains(Jenis:)")?.ownText())
val year = table?.selectFirst("span:contains(Rilis:)")?.ownText()?.substringAfterLast(",")?.trim()?.toIntOrNull()
val status = table?.selectFirst("span:contains(Status:) font")?.text()
val trailer = document.selectFirst("div.trailer iframe")?.attr("src")
val episodes = document.select("ul#daftarepisode > li").map {
val link = fixUrl(it.selectFirst("a")!!.attr("href"))
val name = it.selectFirst("a")?.text() ?: ""
val episode = Regex("Episode\\s?(\\d+)").find(name)?.groupValues?.getOrNull(0)?.toIntOrNull()
Episode(link, episode = episode)
}.reversed()
val tracker = APIHolder.getTracker(listOf(title),TrackerType.getTypes(type),year,true)
return newAnimeLoadResponse(title, url, type) {
posterUrl = tracker?.image ?: poster
backgroundPosterUrl = tracker?.cover
this.year = year
addEpisodes(DubStatus.Subbed, episodes)
showStatus = getStatus(status)
plot = document.select("div.sinopsis p").text()
this.tags = table?.select("span:contains(Genre:) a")?.map { it.text() }
addTrailer(trailer)
addMalId(tracker?.malId)
addAniListId(tracker?.aniId?.toIntOrNull())
}
}
override suspend fun loadLinks(
data: String,
isCasting: Boolean,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
): Boolean {
val document = app.get(data).document
document.select(".mobius > .mirror > option").mapNotNull {
fixUrl(Jsoup.parse(base64Decode(it.attr("value"))).select("iframe").attr("src")) to it.text()
}.apmap { (iframe, quality) ->
loadFixedExtractor(iframe.fixIframe(), quality, "$mainUrl/", subtitleCallback, callback)
}
return true
}
private suspend fun loadFixedExtractor(
url: String,
quality: String?,
referer: String? = null,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
) {
loadExtractor(url, referer, subtitleCallback) { link ->
callback.invoke(
ExtractorLink(
link.name,
link.name,
link.url,
link.referer,
if(link.type == ExtractorLinkType.M3U8 || link.name == "Uservideo") link.quality else getIndexQuality(quality),
link.type,
link.headers,
link.extractorData
)
)
}
}
private fun String.fixIframe() : String {
return if(this.startsWith("https://dl.berkasdrive.com")) {
base64Decode(this.substringAfter("id="))
} else {
this
}
}
private fun getIndexQuality(str: String?): Int {
return Regex("(\\d{3,4})[pP]").find(str ?: "")?.groupValues?.getOrNull(1)?.toIntOrNull()
?: Qualities.Unknown.value
}
private fun Element.getImageAttr(): String? {
return when {
this.hasAttr("data-src") -> this.attr("abs:data-src")
this.hasAttr("data-lazy-src") -> this.attr("abs:data-lazy-src")
this.hasAttr("srcset") -> this.attr("abs:srcset").substringBefore(" ")
else -> this.attr("abs:src")
}
}
}

View File

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

View File

@ -1,108 +0,0 @@
package com.hexated
import com.fasterxml.jackson.annotation.JsonProperty
import com.lagradost.cloudstream3.SubtitleFile
import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.extractors.Filesim
import com.lagradost.cloudstream3.utils.AppUtils
import com.lagradost.cloudstream3.utils.ExtractorApi
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.INFER_TYPE
import com.lagradost.cloudstream3.utils.Qualities
class Archivd : ExtractorApi() {
override val name: String = "Archivd"
override val mainUrl: String = "https://archivd.net"
override val requiresReferer = true
override suspend fun getUrl(
url: String,
referer: String?,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
) {
val res = app.get(url).document
val json = res.select("div#app").attr("data-page")
val video = AppUtils.tryParseJson<Sources>(json)?.props?.datas?.data?.link?.media
callback.invoke(
ExtractorLink(
this.name,
this.name,
video ?: return,
"$mainUrl/",
Qualities.Unknown.value,
INFER_TYPE
)
)
}
data class Link(
@JsonProperty("media") val media: String? = null,
)
data class Data(
@JsonProperty("link") val link: Link? = null,
)
data class Datas(
@JsonProperty("data") val data: Data? = null,
)
data class Props(
@JsonProperty("datas") val datas: Datas? = null,
)
data class Sources(
@JsonProperty("props") val props: Props? = null,
)
}
class Newuservideo : ExtractorApi() {
override val name: String = "Uservideo"
override val mainUrl: String = "https://new.uservideo.xyz"
override val requiresReferer = true
override suspend fun getUrl(
url: String,
referer: String?,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
) {
val iframe = app.get(url,referer=referer).document.select("iframe#videoFrame").attr("src")
val doc = app.get(iframe,referer="$mainUrl/").text
val json = "VIDEO_CONFIG\\s?=\\s?(.*)".toRegex().find(doc)?.groupValues?.get(1)
AppUtils.tryParseJson<Sources>(json)?.streams?.map {
callback.invoke(
ExtractorLink(
this.name,
this.name,
it.playUrl ?: return@map,
"$mainUrl/",
when (it.formatId) {
18 -> Qualities.P360.value
22 -> Qualities.P720.value
else -> Qualities.Unknown.value
},
INFER_TYPE
)
)
}
}
data class Streams(
@JsonProperty("play_url") val playUrl: String? = null,
@JsonProperty("format_id") val formatId: Int? = null,
)
data class Sources(
@JsonProperty("streams") val streams: ArrayList<Streams>? = null,
)
}
class Vidhidepro : Filesim() {
override val mainUrl = "https://vidhidepro.com"
override val name = "Vidhidepro"
}

View File

@ -1,27 +0,0 @@
// use an integer for version numbers
version = 15
cloudstream {
language = "id"
// All of these properties are optional, you can safely remove them
// description = "Lorem Ipsum"
authors = listOf("Hexated")
/**
* Status int as the following:
* 0: Down
* 1: Ok
* 2: Slow
* 3: Beta only
* */
status = 1 // will be 3 if unspecified
tvTypes = listOf(
"AnimeMovie",
"OVA",
"Anime",
)
iconUrl = "https://www.google.com/s2/favicons?domain=animeindo.fun&sz=%size%"
}

View File

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

View File

@ -1,175 +0,0 @@
package com.hexated
import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.LoadResponse.Companion.addAniListId
import com.lagradost.cloudstream3.LoadResponse.Companion.addMalId
import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.httpsify
import com.lagradost.cloudstream3.utils.loadExtractor
import org.jsoup.Jsoup
import org.jsoup.nodes.Element
class AnimeIndoProvider : MainAPI() {
override var mainUrl = "https://animeindo.quest"
override var name = "AnimeIndo"
override val hasMainPage = true
override var lang = "id"
override val supportedTypes = setOf(
TvType.Anime,
TvType.AnimeMovie,
TvType.OVA
)
companion object {
fun getType(t: String): TvType {
return if (t.contains("OVA", true) || t.contains("Special")) TvType.OVA
else if (t.contains("Movie", true)) TvType.AnimeMovie
else TvType.Anime
}
fun getStatus(t: String): ShowStatus {
return when (t) {
"Finished Airing" -> ShowStatus.Completed
"Currently Airing" -> ShowStatus.Ongoing
else -> ShowStatus.Completed
}
}
}
override val mainPage = mainPageOf(
"episode-terbaru" to "Episode Terbaru",
"ongoing" to "Anime Ongoing",
"populer" to "Anime Populer",
"donghua-terbaru" to "Donghua Terbaru",
)
override suspend fun getMainPage(
page: Int,
request: MainPageRequest
): HomePageResponse {
val document = app.get("$mainUrl/${request.data}/page/$page").document
val home = document.select("main#main div.animposx").mapNotNull {
it.toSearchResult()
}
return newHomePageResponse(request.name, home)
}
private fun getProperAnimeLink(uri: String): String {
return if (uri.contains("/anime/")) {
uri
} else {
var title = uri.substringAfter("$mainUrl/")
title = when {
(title.contains("-episode")) && !(title.contains("-movie")) -> title.substringBefore(
"-episode"
)
(title.contains("-movie")) -> title.substringBefore("-movie")
else -> title
}
"$mainUrl/anime/$title"
}
}
private fun Element.toSearchResult(): AnimeSearchResponse {
val title = this.selectFirst("div.title, h2.entry-title, h4")?.text()?.trim() ?: ""
val href = getProperAnimeLink(this.selectFirst("a")!!.attr("href"))
val posterUrl = fixUrlNull(this.selectFirst("img")?.attr("src"))
val epNum = this.selectFirst("span.episode")?.ownText()?.replace(Regex("\\D"), "")?.trim()
?.toIntOrNull()
return newAnimeSearchResponse(title, href, TvType.Anime) {
this.posterUrl = posterUrl
addSub(epNum)
}
}
override suspend fun search(query: String): List<SearchResponse> {
val anime = mutableListOf<SearchResponse>()
(1..2).forEach { page ->
val document = app.get("$mainUrl/page/$page/?s=$query").document
val media = document.select(".site-main.relat > article").mapNotNull {
val title = it.selectFirst("div.title > h2")!!.ownText().trim()
val href = it.selectFirst("a")!!.attr("href")
val posterUrl = it.selectFirst("img")!!.attr("src").toString()
val type = getType(it.select("div.type").text().trim())
newAnimeSearchResponse(title, href, type) {
this.posterUrl = posterUrl
}
}
if(media.isNotEmpty()) anime.addAll(media)
}
return anime
}
override suspend fun load(url: String): LoadResponse? {
val document = app.get(url).document
val title = document.selectFirst("h1.entry-title")?.text()?.replace("Subtitle Indonesia", "")
?.trim() ?: return null
val poster = document.selectFirst("div.thumb > img[itemprop=image]")?.attr("src")
val tags = document.select("div.genxed > a").map { it.text() }
val type = getType(document.selectFirst("div.info-content > div.spe > span:contains(Type:)")?.ownText()
?.trim()?.lowercase() ?: "tv")
val year = document.selectFirst("div.info-content > div.spe > span:contains(Released:)")?.ownText()?.let {
Regex("\\d,\\s(\\d*)").find(it)?.groupValues?.get(1)?.toIntOrNull()
}
val status = getStatus(document.selectFirst("div.info-content > div.spe > span:nth-child(1)")!!.ownText().trim())
val description = document.select("div[itemprop=description] > p").text()
val trailer = document.selectFirst("div.player-embed iframe")?.attr("src")
val episodes = document.select("div.lstepsiode.listeps ul li").mapNotNull {
val header = it.selectFirst("span.lchx > a") ?: return@mapNotNull null
val episode = header.text().trim().replace("Episode", "").trim().toIntOrNull()
val link = fixUrl(header.attr("href"))
Episode(link, episode = episode)
}.reversed()
val recommendations = document.select("div.relat div.animposx").mapNotNull {
it.toSearchResult()
}
val tracker = APIHolder.getTracker(listOf(title),TrackerType.getTypes(type),year,true)
return newAnimeLoadResponse(title, url, type) {
engName = title
posterUrl = tracker?.image ?: poster
backgroundPosterUrl = tracker?.cover
this.year = year
addEpisodes(DubStatus.Subbed, episodes)
showStatus = status
plot = description
this.tags = tags
this.recommendations = recommendations
addTrailer(trailer)
addMalId(tracker?.malId)
addAniListId(tracker?.aniId?.toIntOrNull())
}
}
override suspend fun loadLinks(
data: String,
isCasting: Boolean,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
): Boolean {
val document = app.get(data).document
document.select("div.itemleft > .mirror > option").mapNotNull {
fixUrl(Jsoup.parse(base64Decode(it.attr("value"))).select("iframe").attr("src"))
}.apmap {
if (it.startsWith(mainUrl)) {
app.get(it, referer = "$mainUrl/").document.select("iframe").attr("src")
} else {
it
}
}.apmap {
loadExtractor(httpsify(it), data, subtitleCallback, callback)
}
return true
}
}

View File

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

View File

@ -1,27 +0,0 @@
// use an integer for version numbers
version = 10
cloudstream {
language = "id"
// All of these properties are optional, you can safely remove them
// description = "Lorem Ipsum"
authors = listOf("Hexated")
/**
* Status int as the following:
* 0: Down
* 1: Ok
* 2: Slow
* 3: Beta only
* */
status = 1 // will be 3 if unspecified
tvTypes = listOf(
"AnimeMovie",
"Anime",
"OVA",
)
iconUrl = "https://aghanim.xyz/wp-content/themes/animesail/assets/images/ico.png"
}

View File

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

View File

@ -1,230 +0,0 @@
package com.hexated
import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.LoadResponse.Companion.addAniListId
import com.lagradost.cloudstream3.LoadResponse.Companion.addMalId
import com.lagradost.cloudstream3.mvvm.safeApiCall
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.ExtractorLinkType
import com.lagradost.cloudstream3.utils.Qualities
import com.lagradost.cloudstream3.utils.loadExtractor
import com.lagradost.nicehttp.NiceResponse
import org.jsoup.Jsoup
import org.jsoup.nodes.Element
class AnimeSailProvider : MainAPI() {
override var mainUrl = "https://154.26.137.28"
override var name = "AnimeSail"
override val hasMainPage = true
override var lang = "id"
override val hasDownloadSupport = true
override val supportedTypes = setOf(
TvType.Anime,
TvType.AnimeMovie,
TvType.OVA
)
companion object {
fun getType(t: String): TvType {
return if (t.contains("OVA", true) || t.contains("Special")) TvType.OVA
else if (t.contains("Movie", true)) TvType.AnimeMovie
else TvType.Anime
}
fun getStatus(t: String): ShowStatus {
return when (t) {
"Completed" -> ShowStatus.Completed
"Ongoing" -> ShowStatus.Ongoing
else -> ShowStatus.Completed
}
}
}
private suspend fun request(url: String, ref: String? = null): NiceResponse {
return app.get(
url,
headers = mapOf("Accept" to "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8"),
cookies = mapOf("_as_ipin_ct" to "ID"),
referer = ref
)
}
override val mainPage = mainPageOf(
"$mainUrl/page/" to "Episode Terbaru",
"$mainUrl/movie-terbaru/page/" to "Movie Terbaru",
"$mainUrl/genres/donghua/page/" to "Donghua"
)
override suspend fun getMainPage(page: Int, request: MainPageRequest): HomePageResponse {
val document = request(request.data + page).document
val home = document.select("article").map {
it.toSearchResult()
}
return newHomePageResponse(request.name, home)
}
private fun getProperAnimeLink(uri: String): String {
return if (uri.contains("/anime/")) {
uri
} else {
var title = uri.substringAfter("$mainUrl/")
title = when {
(title.contains("-episode")) && !(title.contains("-movie")) -> title.substringBefore(
"-episode"
)
(title.contains("-movie")) -> title.substringBefore("-movie")
else -> title
}
"$mainUrl/anime/$title"
}
}
private fun Element.toSearchResult(): AnimeSearchResponse {
val href = getProperAnimeLink(fixUrlNull(this.selectFirst("a")?.attr("href")).toString())
val title = this.select(".tt > h2").text().trim()
val posterUrl = fixUrlNull(this.selectFirst("div.limit img")?.attr("src"))
val epNum = this.selectFirst(".tt > h2")?.text()?.let {
Regex("Episode\\s?(\\d+)").find(it)?.groupValues?.getOrNull(1)?.toIntOrNull()
}
return newAnimeSearchResponse(title, href, TvType.Anime) {
this.posterUrl = posterUrl
addSub(epNum)
}
}
override suspend fun search(query: String): List<SearchResponse> {
val link = "$mainUrl/?s=$query"
val document = request(link).document
return document.select("div.listupd article").map {
it.toSearchResult()
}
}
override suspend fun load(url: String): LoadResponse {
val document = request(url).document
val title = document.selectFirst("h1.entry-title")?.text().toString()
.replace("Subtitle Indonesia", "").trim()
val poster = document.selectFirst("div.entry-content > img")?.attr("src")
val type = getType(document.select("tbody th:contains(Tipe)").next().text().lowercase())
val year = document.select("tbody th:contains(Dirilis)").next().text().trim().toIntOrNull()
val episodes = document.select("ul.daftar > li").map {
val link = fixUrl(it.select("a").attr("href"))
val name = it.select("a").text()
val episode = Regex("Episode\\s?(\\d+)").find(name)?.groupValues?.getOrNull(0)?.toIntOrNull()
Episode(link, episode = episode)
}.reversed()
val tracker = APIHolder.getTracker(listOf(title),TrackerType.getTypes(type),year,true)
return newAnimeLoadResponse(title, url, type) {
posterUrl = tracker?.image ?: poster
backgroundPosterUrl = tracker?.cover
this.year = year
addEpisodes(DubStatus.Subbed, episodes)
showStatus =
getStatus(document.select("tbody th:contains(Status)").next().text().trim())
plot = document.selectFirst("div.entry-content > p")?.text()
this.tags =
document.select("tbody th:contains(Genre)").next().select("a").map { it.text() }
addMalId(tracker?.malId)
addAniListId(tracker?.aniId?.toIntOrNull())
}
}
override suspend fun loadLinks(
data: String,
isCasting: Boolean,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
): Boolean {
val document = request(data).document
document.select(".mobius > .mirror > option").apmap {
safeApiCall {
val iframe = fixUrl(
Jsoup.parse(base64Decode(it.attr("data-em"))).select("iframe").attr("src")
?: throw ErrorLoadingException("No iframe found")
)
val quality = getIndexQuality(it.text())
when {
iframe.startsWith("$mainUrl/utils/player/arch/") || iframe.startsWith(
"$mainUrl/utils/player/race/"
) -> request(iframe, ref = data).document.select("source").attr("src")
.let { link ->
val source =
when {
iframe.contains("/arch/") -> "Arch"
iframe.contains("/race/") -> "Race"
else -> this.name
}
callback.invoke(
ExtractorLink(
source = source,
name = source,
url = link,
referer = mainUrl,
quality = quality
)
)
}
// skip for now
// iframe.startsWith("$mainUrl/utils/player/fichan/") -> ""
// iframe.startsWith("$mainUrl/utils/player/blogger/") -> ""
iframe.startsWith("https://aghanim.xyz/tools/redirect/") -> {
val link = "https://rasa-cintaku-semakin-berantai.xyz/v/${
iframe.substringAfter("id=").substringBefore("&token")
}"
loadFixedExtractor(link, quality, mainUrl, subtitleCallback, callback)
}
iframe.startsWith("$mainUrl/utils/player/framezilla/") || iframe.startsWith("https://uservideo.xyz") -> {
request(iframe, ref = data).document.select("iframe").attr("src")
.let { link ->
loadFixedExtractor(fixUrl(link), quality, mainUrl, subtitleCallback, callback)
}
}
else -> {
loadFixedExtractor(iframe, quality, mainUrl, subtitleCallback, callback)
}
}
}
}
return true
}
private suspend fun loadFixedExtractor(
url: String,
quality: Int?,
referer: String? = null,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
) {
loadExtractor(url, referer, subtitleCallback) { link ->
callback.invoke(
ExtractorLink(
link.name,
link.name,
link.url,
link.referer,
if(link.type == ExtractorLinkType.M3U8) link.quality else quality ?: Qualities.Unknown.value,
link.type,
link.headers,
link.extractorData
)
)
}
}
private fun getIndexQuality(str: String): Int {
return Regex("(\\d{3,4})[pP]").find(str)?.groupValues?.getOrNull(1)?.toIntOrNull()
?: Qualities.Unknown.value
}
}

View File

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

View File

@ -1,27 +0,0 @@
// use an integer for version numbers
version = 7
cloudstream {
language = "en"
// All of these properties are optional, you can safely remove them
// description = "Lorem Ipsum"
authors = listOf("Hexated")
/**
* Status int as the following:
* 0: Down
* 1: Ok
* 2: Slow
* 3: Beta only
* */
status = 1 // will be 3 if unspecified
tvTypes = listOf(
"AnimeMovie",
"Anime",
"OVA",
)
iconUrl = "https://www.google.com/s2/favicons?domain=animixplay.to&sz=%size%"
}

View File

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

View File

@ -1,446 +0,0 @@
package com.hexated
import com.fasterxml.jackson.annotation.JsonProperty
import com.hexated.GogoExtractor.extractVidstream
import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.LoadResponse.Companion.addAniListId
import com.lagradost.cloudstream3.LoadResponse.Companion.addMalId
import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.loadExtractor
import org.jsoup.Jsoup
import java.net.URI
class Animixplay : MainAPI() {
override var mainUrl = "https://animixplay.red"
override var name = "Animixplay"
override val hasMainPage = true
override var lang = "en"
override val hasQuickSearch = true
override val hasDownloadSupport = true
override val supportedTypes = setOf(
TvType.Anime,
TvType.AnimeMovie,
TvType.OVA
)
companion object {
fun getStatus(t: String?): ShowStatus {
return when (t) {
"Finished Airing" -> ShowStatus.Completed
"Currently Airing" -> ShowStatus.Ongoing
else -> ShowStatus.Completed
}
}
}
override val mainPage = mainPageOf(
"$mainUrl/api/search" to "Sub",
"$mainUrl/api/search" to "Dub",
"$mainUrl/a/XsWgdGCnKJfNvDFAM28EV" to "All",
"$mainUrl/api/search" to "Movie",
)
private var newPagination: String? = null
override suspend fun getMainPage(page: Int, request: MainPageRequest): HomePageResponse {
val items = mutableListOf<HomePageList>()
val paged = page.toString()
val pagination = if (request.name == "Movie") {
paged.replace(paged, "99999999")
} else {
paged.replace(paged, "3020-05-06 00:00:00")
}
if (page <= 1) {
val headers = when (request.name) {
"Sub" -> mapOf("seasonal" to pagination)
"Dub" -> mapOf("seasonaldub" to pagination)
"All" -> mapOf("recent" to pagination)
"Movie" -> mapOf("movie" to pagination)
else -> mapOf()
}
val res = app.post(
request.data,
data = headers,
referer = mainUrl,
headers = mapOf("X-Requested-With" to "XMLHttpRequest")
).parsedSafe<Result>()
newPagination = res?.last.toString()
val home = res?.result?.mapNotNull {
it.toSearchResponse()
} ?: throw ErrorLoadingException("No media found")
items.add(
HomePageList(
name = request.name,
list = home,
)
)
} else {
val headers = when (request.name) {
"Sub" -> mapOf("seasonal" to "$newPagination")
"Dub" -> mapOf("seasonaldub" to "$newPagination")
"All" -> mapOf("recent" to "$newPagination")
"Movie" -> mapOf("movie" to "$newPagination")
else -> mapOf()
}
val res = app.post(
request.data,
data = headers,
referer = mainUrl,
headers = mapOf("X-Requested-With" to "XMLHttpRequest")
).parsedSafe<Result>()
newPagination = res?.last.toString()
val home = res?.result?.mapNotNull {
it.toSearchResponse()
} ?: throw ErrorLoadingException("No media found")
items.add(
HomePageList(
name = request.name,
list = home,
)
)
}
return newHomePageResponse(items)
}
private fun Anime.toSearchResponse(): AnimeSearchResponse? {
return newAnimeSearchResponse(
title ?: return null,
fixUrl(url ?: return null),
TvType.TvSeries,
) {
this.posterUrl = img ?: picture
addDubStatus(
isDub = title.contains("Dub"),
episodes = Regex("EP\\s([0-9]+)/").find(
infotext ?: ""
)?.groupValues?.getOrNull(1)
?.toIntOrNull()
)
}
}
override suspend fun search(query: String): List<SearchResponse>? {
return app.post(
url = "https://v1.ij7p9towl8uj4qafsopjtrjk.workers.dev",
referer = mainUrl,
data = mapOf(
"q2" to query,
"origin" to "1",
"root" to "animixplay.to",
"d" to "gogoanime.tel"
)
).parsedSafe<FullSearch>()?.result?.let {
Jsoup.parse(it).select("div").map { elem ->
val href = fixUrl(elem.select("a").attr("href"))
val title = elem.select("a").attr("title")
newAnimeSearchResponse(title, href, TvType.Anime) {
this.posterUrl = elem.select("img").attr("src")
addDubStatus(isDub = title.contains("Dub"))
}
}
}
}
override suspend fun quickSearch(query: String): List<SearchResponse>? {
return app.post(
"https://cdn.animixplay.to/api/search",
data = mapOf("qfast" to query, "root" to URI(mainUrl).host)
).parsedSafe<Search>()?.result?.let {
Jsoup.parse(it).select("a").map { elem ->
val href = elem.attr("href")
val title = elem.select("p.name").text()
newAnimeSearchResponse(title, href, TvType.Anime) {
this.posterUrl = elem.select("img").attr("src")
addDubStatus(isDub = title.contains("Dub"))
}
}
}
}
private suspend fun loadMissingAnime(url: String): LoadResponse? {
val doc = app.get(url).document
val title = doc.selectFirst("span.animetitle")?.text()
val image = fixUrlNull(doc.selectFirst("meta[property=og:image]")?.attr("content"))
val genres = doc.selectFirst("span#genredata")?.text()?.split(",")?.map { it.trim() }
val subEpisodes = mutableListOf<Episode>()
val dubEpisodes = mutableListOf<Episode>()
val dataEps = doc.select("div#epslistplace")
.text().trim()
Regex("\"([0-9]+)\":\"(\\S+?)\"").findAll(dataEps).toList()
.map { it.groupValues[1] to it.groupValues[2] }.map { (ep, link) ->
val episode = Episode(fixUrl(link), episode = ep.toInt() + 1)
if (url.contains("-dub")) {
dubEpisodes.add(episode)
} else {
subEpisodes.add(episode)
}
}
return newAnimeLoadResponse(
title ?: return null,
url,
TvType.Anime
) {
this.posterUrl = image
this.tags = genres
if (subEpisodes.isNotEmpty()) addEpisodes(DubStatus.Subbed, subEpisodes)
if (dubEpisodes.isNotEmpty()) addEpisodes(DubStatus.Dubbed, dubEpisodes)
}
}
override suspend fun load(url: String): LoadResponse? {
val (fixUrl, malId) = if (url.contains("/anime/")) {
listOf(url, Regex("anime/([0-9]+)/?").find(url)?.groupValues?.get(1))
} else {
val malId = app.get(url).text.substringAfterLast("malid = '").substringBefore("';")
listOf("$mainUrl/anime/$malId", malId)
}
val anilistId = app.post(
"https://graphql.anilist.co/", data = mapOf(
"query" to "{Media(idMal:$malId,type:ANIME){id}}",
)
).parsedSafe<DataAni>()?.data?.media?.id
val res = app.get("$mainUrl/assets/mal/$malId.json").parsedSafe<AnimeDetail>()
?: return loadMissingAnime(url)
val subEpisodes = mutableListOf<Episode>()
val dubEpisodes = mutableListOf<Episode>()
app.post("$mainUrl/api/search", data = mapOf("recomended" to "$malId"))
.parsedSafe<Data>()?.data?.map { server ->
server.items?.apmap { data ->
val jsonData =
app.get(
fixUrl(
data.url ?: return@apmap null
)
).document.select("div#epslistplace")
.text().trim()
val episodeData = when (server.type) {
"AL" -> Regex("\"([0-9]+)\":\\[(.*?)]").findAll(jsonData).toList()
.map { it.groupValues[1] to it.groupValues[2] }.map { (ep, link) ->
Episode(link, episode = ep.toInt() + 1)
}
"RUSH" -> Regex("\"([0-9]+)\":\\[(.*?)]").findAll(jsonData).toList()
.map { it.groupValues[1] to it.groupValues[2] }.map { (ep, link) ->
val linkData =
Regex("\"vid\":\"(\\S+?)\"").findAll(link)
.map { it.groupValues[1] }
.toList().joinToString("")
Episode(linkData, episode = ep.toInt() + 1)
}
else -> {
Regex("\"([0-9]+)\":\"(\\S+?)\"").findAll(jsonData).toList()
.map { it.groupValues[1] to it.groupValues[2] }.map { (ep, link) ->
Episode(fixUrl(link), episode = ep.toInt() + 1)
}
}
}
episodeData.map {
if (data.url.contains("-dub")) {
dubEpisodes.add(it)
} else {
subEpisodes.add(it)
}
}
}
}
val recommendations = app.get("$mainUrl/assets/similar/$malId.json")
.parsedSafe<RecResult>()?.recommendations?.mapNotNull { rec ->
newAnimeSearchResponse(
rec.title ?: return@mapNotNull null,
"$mainUrl/anime/${rec.malId}/",
TvType.Anime
) {
this.posterUrl = rec.imageUrl
addDubStatus(dubExist = false, subExist = true)
}
}
return newAnimeLoadResponse(
res.title ?: return null,
url,
TvType.Anime
) {
engName = res.title
posterUrl = res.imageUrl
this.year = res.aired?.from?.split("-")?.firstOrNull()?.toIntOrNull()
showStatus = getStatus(res.status)
plot = res.synopsis
this.tags = res.genres?.mapNotNull { it.name }
this.recommendations = recommendations
addMalId(malId?.toIntOrNull())
addAniListId(anilistId?.toIntOrNull())
addTrailer(res.trailerUrl)
if (subEpisodes.isNotEmpty()) addEpisodes(DubStatus.Subbed, groupEpisodes(subEpisodes))
if (dubEpisodes.isNotEmpty()) addEpisodes(DubStatus.Dubbed, groupEpisodes(dubEpisodes))
}
}
override suspend fun loadLinks(
data: String,
isCasting: Boolean,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
): Boolean {
if (!data.contains("\"")) {
invokeGogo(data, subtitleCallback, callback)
} else {
data.split("http").apmap {
val link = it.replace("\"", "").let { url -> "http$url".trim() }
if (link.startsWith("https://gogohd.net")) {
invokeGogo(link, subtitleCallback, callback)
} else {
loadExtractor(link, "$mainUrl/", subtitleCallback) { links ->
val name =
if (link.startsWith("https://streamsb.net")) "StreamNet" else links.name
callback.invoke(
ExtractorLink(
name,
name,
links.url,
links.referer,
links.quality,
links.isM3u8,
links.headers,
links.extractorData
)
)
}
}
}
}
return true
}
private fun groupEpisodes(episodes: List<Episode>): List<Episode> {
return episodes.groupBy { it.episode }.map { eps ->
val epsNum = eps.key
val epsLink = eps.value.joinToString("") { it.data }.replace("\",\"", "")
Episode(epsLink, episode = epsNum)
}
}
private suspend fun invokeGogo(
link: String,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
) {
val iframe = app.get(link)
val iframeDoc = iframe.document
argamap({
iframeDoc.select(".list-server-items > .linkserver")
.forEach { element ->
val status = element.attr("data-status") ?: return@forEach
if (status != "1") return@forEach
val extractorData = element.attr("data-video") ?: return@forEach
loadExtractor(extractorData, iframe.url, subtitleCallback, callback)
}
}, {
val iv = "3134003223491201"
val secretKey = "37911490979715163134003223491201"
val secretDecryptKey = "54674138327930866480207815084989"
extractVidstream(
iframe.url,
this.name,
callback,
iv,
secretKey,
secretDecryptKey,
isUsingAdaptiveKeys = false,
isUsingAdaptiveData = true,
iframeDocument = iframeDoc
)
})
}
private data class IdAni(
@JsonProperty("id") val id: String? = null,
)
private data class MediaAni(
@JsonProperty("Media") val media: IdAni? = null,
)
private data class DataAni(
@JsonProperty("data") val data: MediaAni? = null,
)
private data class Items(
@JsonProperty("url") val url: String? = null,
@JsonProperty("title") val title: String? = null,
)
private data class Episodes(
@JsonProperty("type") val type: String? = null,
@JsonProperty("items") val items: ArrayList<Items>? = arrayListOf(),
)
private data class Data(
@JsonProperty("data") val data: ArrayList<Episodes>? = arrayListOf(),
)
private data class Aired(
@JsonProperty("from") val from: String? = null,
)
private data class Genres(
@JsonProperty("name") val name: String? = null,
)
private data class RecResult(
@JsonProperty("recommendations") val recommendations: ArrayList<Recommendations>? = arrayListOf(),
)
private data class Recommendations(
@JsonProperty("mal_id") val malId: String? = null,
@JsonProperty("image_url") val imageUrl: String? = null,
@JsonProperty("title") val title: String? = null,
)
private data class AnimeDetail(
@JsonProperty("title") val title: String? = null,
@JsonProperty("image_url") val imageUrl: String? = null,
@JsonProperty("type") val type: String? = null,
@JsonProperty("aired") val aired: Aired? = null,
@JsonProperty("status") val status: String? = null,
@JsonProperty("synopsis") val synopsis: String? = null,
@JsonProperty("trailer_url") val trailerUrl: String? = null,
@JsonProperty("genres") val genres: ArrayList<Genres>? = arrayListOf(),
)
private data class Search(
@JsonProperty("result") val result: String? = null,
)
private data class Result(
@JsonProperty("result") val result: ArrayList<Anime> = arrayListOf(),
@JsonProperty("last") val last: Any? = null,
)
private data class Anime(
@JsonProperty("title") val title: String? = null,
@JsonProperty("url") val url: String? = null,
@JsonProperty("img") val img: String? = null,
@JsonProperty("picture") val picture: String? = null,
@JsonProperty("infotext") val infotext: String? = null,
)
private data class FullSearch(
@JsonProperty("result") val result: String? = null,
)
}

View File

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

View File

@ -1,166 +0,0 @@
package com.hexated
import com.fasterxml.jackson.annotation.JsonProperty
import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.base64Decode
import com.lagradost.cloudstream3.base64DecodeArray
import com.lagradost.cloudstream3.base64Encode
import com.lagradost.cloudstream3.mvvm.normalSafeApiCall
import com.lagradost.cloudstream3.mvvm.safeApiCall
import com.lagradost.cloudstream3.utils.AppUtils
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.M3u8Helper
import com.lagradost.cloudstream3.utils.getQualityFromName
import org.jsoup.nodes.Document
import java.net.URI
import javax.crypto.Cipher
import javax.crypto.spec.IvParameterSpec
import javax.crypto.spec.SecretKeySpec
object GogoExtractor {
/**
* @param id base64Decode(show_id) + IV
* @return the encryption key
* */
private fun getKey(id: String): String? {
return normalSafeApiCall {
id.map {
it.code.toString(16)
}.joinToString("").substring(0, 32)
}
}
// https://github.com/saikou-app/saikou/blob/3e756bd8e876ad7a9318b17110526880525a5cd3/app/src/main/java/ani/saikou/anime/source/extractors/GogoCDN.kt#L60
// No Licence on the function
private fun cryptoHandler(
string: String,
iv: String,
secretKeyString: String,
encrypt: Boolean = true
): String {
//println("IV: $iv, Key: $secretKeyString, encrypt: $encrypt, Message: $string")
val ivParameterSpec = IvParameterSpec(iv.toByteArray())
val secretKey = SecretKeySpec(secretKeyString.toByteArray(), "AES")
val cipher = Cipher.getInstance("AES/CBC/PKCS5Padding")
return if (!encrypt) {
cipher.init(Cipher.DECRYPT_MODE, secretKey, ivParameterSpec)
String(cipher.doFinal(base64DecodeArray(string)))
} else {
cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivParameterSpec)
base64Encode(cipher.doFinal(string.toByteArray()))
}
}
/**
* @param iframeUrl something like https://gogoplay4.com/streaming.php?id=XXXXXX
* @param mainApiName used for ExtractorLink names and source
* @param iv secret iv from site, required non-null if isUsingAdaptiveKeys is off
* @param secretKey secret key for decryption from site, required non-null if isUsingAdaptiveKeys is off
* @param secretDecryptKey secret key to decrypt the response json, required non-null if isUsingAdaptiveKeys is off
* @param isUsingAdaptiveKeys generates keys from IV and ID, see getKey()
* @param isUsingAdaptiveData generate encrypt-ajax data based on $("script[data-name='episode']")[0].dataset.value
* */
suspend fun extractVidstream(
iframeUrl: String,
mainApiName: String,
callback: (ExtractorLink) -> Unit,
iv: String?,
secretKey: String?,
secretDecryptKey: String?,
// This could be removed, but i prefer it verbose
isUsingAdaptiveKeys: Boolean,
isUsingAdaptiveData: Boolean,
// If you don't want to re-fetch the document
iframeDocument: Document? = null
) = safeApiCall {
// https://github.com/saikou-app/saikou/blob/3e756bd8e876ad7a9318b17110526880525a5cd3/app/src/main/java/ani/saikou/anime/source/extractors/GogoCDN.kt
// No Licence on the following code
// Also modified of https://github.com/jmir1/aniyomi-extensions/blob/master/src/en/gogoanime/src/eu/kanade/tachiyomi/animeextension/en/gogoanime/extractors/GogoCdnExtractor.kt
// License on the code above https://github.com/jmir1/aniyomi-extensions/blob/master/LICENSE
if ((iv == null || secretKey == null || secretDecryptKey == null) && !isUsingAdaptiveKeys)
return@safeApiCall
val id = Regex("id=([^&]+)").find(iframeUrl)!!.value.removePrefix("id=")
var document: Document? = iframeDocument
val foundIv =
iv ?: (document ?: app.get(iframeUrl).document.also { document = it })
.select("""div.wrapper[class*=container]""")
.attr("class").split("-").lastOrNull() ?: return@safeApiCall
val foundKey = secretKey ?: getKey(base64Decode(id) + foundIv) ?: return@safeApiCall
val foundDecryptKey = secretDecryptKey ?: foundKey
val uri = URI(iframeUrl)
val mainUrl = "https://" + uri.host
val encryptedId = cryptoHandler(id, foundIv, foundKey)
val encryptRequestData = if (isUsingAdaptiveData) {
// Only fetch the document if necessary
val realDocument = document ?: app.get(iframeUrl).document
val dataEncrypted =
realDocument.select("script[data-name='episode']").attr("data-value")
val headers = cryptoHandler(dataEncrypted, foundIv, foundKey, false)
"id=$encryptedId&alias=$id&" + headers.substringAfter("&")
} else {
"id=$encryptedId&alias=$id"
}
val jsonResponse =
app.get(
"$mainUrl/encrypt-ajax.php?$encryptRequestData",
headers = mapOf("X-Requested-With" to "XMLHttpRequest")
)
val dataencrypted =
jsonResponse.text.substringAfter("{\"data\":\"").substringBefore("\"}")
val datadecrypted = cryptoHandler(dataencrypted, foundIv, foundDecryptKey, false)
val sources = AppUtils.parseJson<GogoSources>(datadecrypted)
suspend fun invokeGogoSource(
source: GogoSource,
sourceCallback: (ExtractorLink) -> Unit
) {
if (source.file.contains(".m3u8")) {
M3u8Helper.generateM3u8(
mainApiName,
source.file,
mainUrl,
headers = mapOf("Origin" to "https://plyr.link")
).forEach(sourceCallback)
} else {
sourceCallback.invoke(
ExtractorLink(
mainApiName,
mainApiName,
source.file,
mainUrl,
getQualityFromName(source.label),
)
)
}
}
sources.source?.forEach {
invokeGogoSource(it, callback)
}
sources.sourceBk?.forEach {
invokeGogoSource(it, callback)
}
}
data class GogoSources(
@JsonProperty("source") val source: List<GogoSource>?,
@JsonProperty("sourceBk") val sourceBk: List<GogoSource>?,
//val track: List<Any?>,
//val advertising: List<Any?>,
//val linkiframe: String
)
data class GogoSource(
@JsonProperty("file") val file: String,
@JsonProperty("label") val label: String?,
@JsonProperty("type") val type: String?,
@JsonProperty("default") val default: String? = null
)
}

View File

@ -1,27 +0,0 @@
// use an integer for version numbers
version = 6
cloudstream {
language = "de"
// All of these properties are optional, you can safely remove them
description = "Include: Serienstream"
authors = listOf("Hexated")
/**
* Status int as the following:
* 0: Down
* 1: Ok
* 2: Slow
* 3: Beta only
* */
status = 1 // will be 3 if unspecified
tvTypes = listOf(
"AnimeMovie",
"Anime",
"OVA",
)
iconUrl = "https://www.google.com/s2/favicons?domain=aniworld.to&sz=%size%"
}

View File

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

View File

@ -1,189 +0,0 @@
package com.hexated
import com.fasterxml.jackson.annotation.JsonProperty
import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.LoadResponse.Companion.addActors
import com.lagradost.cloudstream3.extractors.DoodLaExtractor
import com.lagradost.cloudstream3.extractors.Voe
import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.loadExtractor
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
open class Aniworld : MainAPI() {
override var mainUrl = "https://aniworld.to"
override var name = "Aniworld"
override val hasMainPage = true
override var lang = "de"
override val supportedTypes = setOf(
TvType.Anime,
TvType.AnimeMovie,
TvType.OVA
)
override suspend fun getMainPage(
page: Int,
request: MainPageRequest
): HomePageResponse {
val document = app.get(mainUrl).document
val item = arrayListOf<HomePageList>()
document.select("div.carousel").map { ele ->
val header = ele.selectFirst("h2")?.text() ?: return@map
val home = ele.select("div.coverListItem").mapNotNull {
it.toSearchResult()
}
if (home.isNotEmpty()) item.add(HomePageList(header, home))
}
return HomePageResponse(item)
}
override suspend fun search(query: String): List<SearchResponse> {
val json = app.post(
"$mainUrl/ajax/search",
data = mapOf("keyword" to query),
referer = "$mainUrl/search",
headers = mapOf(
"x-requested-with" to "XMLHttpRequest"
)
)
return tryParseJson<List<AnimeSearch>>(json.text)?.filter {
!it.link.contains("episode-") && it.link.contains(
"/stream"
)
}?.map {
newAnimeSearchResponse(
it.title?.replace(Regex("</?em>"), "") ?: "",
fixUrl(it.link),
TvType.Anime
) {
}
} ?: throw ErrorLoadingException()
}
override suspend fun load(url: String): LoadResponse? {
val document = app.get(url).document
val title = document.selectFirst("div.series-title span")?.text() ?: return null
val poster = fixUrlNull(document.selectFirst("div.seriesCoverBox img")?.attr("data-src"))
val tags = document.select("div.genres li a").map { it.text() }
val year = document.selectFirst("span[itemprop=startDate] a")?.text()?.toIntOrNull()
val description = document.select("p.seri_des").text()
val actor =
document.select("li:contains(Schauspieler:) ul li a").map { it.select("span").text() }
val episodes = mutableListOf<Episode>()
document.select("div#stream > ul:first-child li").map { ele ->
val page = ele.selectFirst("a")
val epsDocument = app.get(fixUrl(page?.attr("href") ?: return@map)).document
epsDocument.select("div#stream > ul:nth-child(4) li").mapNotNull { eps ->
episodes.add(
Episode(
fixUrl(eps.selectFirst("a")?.attr("href") ?: return@mapNotNull null),
episode = eps.selectFirst("a")?.text()?.toIntOrNull(),
season = page.text().toIntOrNull()
)
)
}
}
return newAnimeLoadResponse(
title,
url,
TvType.Anime
) {
engName = title
posterUrl = poster
this.year = year
addEpisodes(
DubStatus.Subbed,
episodes
)
addActors(actor)
plot = description
this.tags = tags
}
}
override suspend fun loadLinks(
data: String,
isCasting: Boolean,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
): Boolean {
val document = app.get(data).document
document.select("div.hosterSiteVideo ul li").map {
Triple(
it.attr("data-lang-key"),
it.attr("data-link-target"),
it.select("h4").text()
)
}.filter {
it.third != "Vidoza"
}.apmap {
val redirectUrl = app.get(fixUrl(it.second)).url
val lang = it.first.getLanguage(document)
val name = "${it.third} [${lang}]"
if (it.third == "VOE") {
Voe().getUrl(redirectUrl, data, subtitleCallback) { link ->
callback.invoke(
ExtractorLink(
name,
name,
link.url,
link.referer,
link.quality,
link.type,
link.headers,
link.extractorData
)
)
}
} else {
loadExtractor(redirectUrl, data, subtitleCallback) { link ->
callback.invoke(
ExtractorLink(
name,
name,
link.url,
link.referer,
link.quality,
link.type,
link.headers,
link.extractorData
)
)
}
}
}
return true
}
private fun Element.toSearchResult(): AnimeSearchResponse? {
val href = fixUrlNull(this.selectFirst("a")?.attr("href")) ?: return null
val title = this.selectFirst("h3")?.text() ?: return null
val posterUrl = fixUrlNull(this.selectFirst("img")?.attr("data-src"))
return newAnimeSearchResponse(title, href, TvType.Anime) {
this.posterUrl = posterUrl
}
}
private fun String.getLanguage(document: Document): String? {
return document.selectFirst("div.changeLanguageBox img[data-lang-key=$this]")?.attr("title")
?.removePrefix("mit")?.trim()
}
private data class AnimeSearch(
@JsonProperty("link") val link: String,
@JsonProperty("title") val title: String? = null,
)
}
class Dooood : DoodLaExtractor() {
override var mainUrl = "https://urochsunloath.com"
}

View File

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

View File

@ -1,17 +0,0 @@
package com.hexated
import com.lagradost.cloudstream3.LoadResponse
import com.lagradost.cloudstream3.TvType
class Serienstream : Aniworld() {
override var mainUrl = "https://s.to"
override var name = "Serienstream"
override val supportedTypes = setOf(
TvType.Movie,
TvType.TvSeries,
)
override suspend fun load(url: String): LoadResponse? {
return super.load(url).apply { this?.type = TvType.TvSeries }
}
}

View File

@ -1,27 +0,0 @@
// use an integer for version numbers
version = 1
cloudstream {
language = "tr"
// All of these properties are optional, you can safely remove them
// description = "Lorem Ipsum"
authors = listOf("Hexated")
/**
* Status int as the following:
* 0: Down
* 1: Ok
* 2: Slow
* 3: Beta only
* */
status = 0 // will be 3 if unspecified
tvTypes = listOf(
"AnimeMovie",
"Anime",
"OVA",
)
iconUrl = "https://www.google.com/s2/favicons?domain=anizm.net&sz=%size%"
}

View File

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

View File

@ -1,195 +0,0 @@
package com.hexated
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.mvvm.safeApiCall
import com.lagradost.cloudstream3.utils.*
import org.jsoup.Jsoup
import org.jsoup.nodes.Element
class Anizm : MainAPI() {
override var mainUrl = "https://anizm.net"
override var name = "Anizm"
override val hasMainPage = true
override var lang = "tr"
override val hasDownloadSupport = true
override val supportedTypes = setOf(
TvType.Anime,
TvType.AnimeMovie,
TvType.OVA
)
companion object {
private const val mainServer = "https://anizmplayer.com"
}
override val mainPage = mainPageOf(
"$mainUrl/anime-izle?sayfa=" to "Son Eklenen Animeler",
)
override suspend fun getMainPage(
page: Int,
request: MainPageRequest
): HomePageResponse {
val document = app.get(request.data + page).document
val home = document.select("div.restrictedWidth div#episodesMiddle").mapNotNull {
it.toSearchResult()
}
return newHomePageResponse(request.name, home)
}
private fun getProperAnimeLink(uri: String): String {
return if (uri.contains("-bolum")) {
"$mainUrl/${uri.substringAfter("$mainUrl/").replace(Regex("-[0-9]+-bolum.*"), "")}"
} else {
uri
}
}
private fun Element.toSearchResult(): AnimeSearchResponse? {
val href = getProperAnimeLink(this.selectFirst("a")!!.attr("href"))
val title = this.selectFirst("div.title, h5.animeTitle a")?.text() ?: return null
val posterUrl = fixUrlNull(this.selectFirst("img")?.attr("src"))
val episode = this.selectFirst("div.truncateText")?.text()?.let {
Regex("([0-9]+).\\s?Bölüm").find(it)?.groupValues?.getOrNull(1)?.toIntOrNull()
}
return newAnimeSearchResponse(title, href, TvType.Anime) {
this.posterUrl = posterUrl
addSub(episode)
}
}
override suspend fun search(query: String): List<SearchResponse> {
val document = app.get(
"$mainUrl/fullViewSearch?search=$query&skip=0",
headers = mapOf("X-Requested-With" to "XMLHttpRequest")
).document
return document.select("div.searchResultItem").mapNotNull {
it.toSearchResult()
}
}
override suspend fun load(url: String): LoadResponse {
val document = app.get(url).document
val title = document.selectFirst("h2.anizm_pageTitle a")!!.text().trim()
val type =
if (document.select("div.ui.grid div.four.wide").size == 1) TvType.Movie else TvType.Anime
val trailer = document.select("div.yt-hd-thumbnail-inner-container iframe").attr("src")
val episodes = document.select("div.ui.grid div.four.wide").map {
val name = it.select("div.episodeBlock").text()
val link = fixUrl(it.selectFirst("a")?.attr("href").toString())
Episode(link, name)
}
return newAnimeLoadResponse(title, url, type) {
posterUrl = fixUrlNull(document.selectFirst("div.infoPosterImg > img")?.attr("src"))
this.year = document.select("div.infoSta ul li:first-child").text().trim().toIntOrNull()
addEpisodes(DubStatus.Subbed, episodes)
plot = document.select("div.infoDesc").text().trim()
this.tags = document.select("span.dataValue span.ui.label").map { it.text() }
addTrailer(trailer)
}
}
private suspend fun invokeLokalSource(
url: String,
translator: String,
sourceCallback: (ExtractorLink) -> Unit
) {
app.get(url, referer = "$mainUrl/").document.select("script").find { script ->
script.data().contains("eval(function(p,a,c,k,e,d)")
}?.let {
val key = getAndUnpack(it.data()).substringAfter("FirePlayer(\"").substringBefore("\",")
val referer = "$mainServer/video/$key"
val link = "$mainServer/player/index.php?data=$key&do=getVideo"
Log.i("hexated", link)
app.post(
link,
data = mapOf("hash" to key, "r" to "$mainUrl/"),
referer = referer,
headers = mapOf(
"Accept" to "*/*",
"Origin" to mainServer,
"Content-Type" to "application/x-www-form-urlencoded; charset=UTF-8",
"X-Requested-With" to "XMLHttpRequest"
)
).parsedSafe<Source>()?.videoSource?.let { m3uLink ->
M3u8Helper.generateM3u8(
"${this.name} ($translator)",
m3uLink,
referer
).forEach(sourceCallback)
}
}
}
override suspend fun loadLinks(
data: String,
isCasting: Boolean,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
): Boolean {
val document = app.get(data).document
document.select("div.episodeTranslators div#fansec").map {
Pair(it.select("a").attr("translator"), it.select("div.title").text())
}.apmap { (url, translator) ->
safeApiCall {
app.get(
url,
referer = data,
headers = mapOf(
"Accept" to "application/json, text/javascript, */*; q=0.01",
"X-Requested-With" to "XMLHttpRequest"
)
).parsedSafe<Translators>()?.data?.let {
Jsoup.parse(it).select("a").apmap { video ->
app.get(
video.attr("video"),
referer = data,
headers = mapOf(
"Accept" to "application/json, text/javascript, */*; q=0.01",
"X-Requested-With" to "XMLHttpRequest"
)
).parsedSafe<Videos>()?.player?.let { iframe ->
Jsoup.parse(iframe).select("iframe").attr("src").let { link ->
when {
link.startsWith(mainServer) -> {
invokeLokalSource(link, translator, callback)
}
else -> {
loadExtractor(
fixUrl(link),
"$mainUrl/",
subtitleCallback,
callback
)
}
}
}
}
}
}
}
}
return true
}
data class Source(
@JsonProperty("videoSource") val videoSource: String?,
)
data class Videos(
@JsonProperty("player") val player: String?,
)
data class Translators(
@JsonProperty("data") val data: String?,
)
}

View File

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

View File

@ -1,26 +0,0 @@
// use an integer for version numbers
version = 2
cloudstream {
language = "pt-pt"
// All of these properties are optional, you can safely remove them
// description = "Lorem Ipsum"
authors = listOf("Hexated")
/**
* Status int as the following:
* 0: Down
* 1: Ok
* 2: Slow
* 3: Beta only
* */
status = 1 // will be 3 if unspecified
tvTypes = listOf(
"Anime",
"AnimeMovie",
"OVA",
)
iconUrl = "https://www.google.com/s2/favicons?domain=www.anroll.net&sz=%size%"
}

View File

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

View File

@ -1,241 +0,0 @@
package com.hexated
import com.fasterxml.jackson.annotation.JsonProperty
import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.utils.AppUtils.toJson
import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.Qualities
import org.jsoup.nodes.Element
class Anroll : MainAPI() {
override var mainUrl = "https://www.anroll.net"
override var name = "Anroll"
override val hasMainPage = true
override var lang = "pt"
override val hasDownloadSupport = true
override val hasQuickSearch = true
override val supportedTypes = setOf(
TvType.Anime,
TvType.AnimeMovie,
TvType.OVA
)
companion object {
private const val searchUrl = "https://apiv2-prd.anroll.net"
private const val episodeUrl = "https://apiv3-prd.anroll.net"
private const val posterUrl = "https://static.anroll.net"
private const val videoUrl = "https://cdn-zenitsu.gamabunta.xyz"
}
override suspend fun getMainPage(
page: Int,
request: MainPageRequest
): HomePageResponse {
val document = app.get("$mainUrl/home").document
val home = mutableListOf<HomePageList>()
document.select("div.hAbQAe").map { div ->
val header = div.selectFirst("h2")?.text() ?: return@map
val child = HomePageList(
header,
div.select("ul li").mapNotNull {
it.toSearchResult()
},
header == "Últimos Laçamentos"
)
home.add(child)
}
return HomePageResponse(home)
}
private fun Element.toSearchResult(): AnimeSearchResponse? {
val title = this.selectFirst("h1")?.text()?.trim() ?: ""
val href = fixUrl(this.selectFirst("a")?.attr("href") ?: return null)
val posterUrl = fixUrlNull(this.select("img").attr("src"))
val epNum = this.selectFirst("span.sc-f5d5b250-3.fsTgnD b")?.text()?.toIntOrNull()
val isDub = this.selectFirst("div.sc-9dbd1f1d-5.efznig")?.text() == "DUB"
return newAnimeSearchResponse(title, href, TvType.Anime) {
this.posterUrl = posterUrl
addDubStatus(isDub, epNum)
}
}
override suspend fun quickSearch(query: String): List<SearchResponse> = search(query)
override suspend fun search(query: String): List<SearchResponse> {
val res = app.get("$searchUrl/search?q=$query").parsedSafe<SearchAnime>()
val collection = mutableListOf<SearchResponse>()
val anime = res?.data_anime?.mapNotNull {
addAnimeSearch(
it.titulo ?: return@mapNotNull null,
"a/${it.generate_id}",
it.slug_serie ?: return@mapNotNull null,
Image.Anime
)
}
if (anime?.isNotEmpty() == true) collection.addAll(anime)
val filme = res?.data_filme?.mapNotNull {
addAnimeSearch(
it.nome_filme ?: return@mapNotNull null,
"f/${it.generate_id}",
it.slug_filme ?: return@mapNotNull null,
Image.Filme
)
}
if (filme?.isNotEmpty() == true) collection.addAll(filme)
return collection
}
override suspend fun load(url: String): LoadResponse? {
val fixUrl = getProperAnimeLink(url) ?: throw ErrorLoadingException()
val document = app.get(fixUrl).document
val article = document.selectFirst("article.animedetails") ?: return null
val title = article.selectFirst("h2")?.text() ?: return null
val poster = fixUrlNull(document.select("section.animecontent img").attr("src"))
val tags = article.select("div#generos a").map { it.text() }
val year = article.selectFirst("div.dfuefM")?.nextElementSibling()?.text()
?.toIntOrNull()
val description = document.select("div.sinopse").text().trim()
val type = if (fixUrl.contains("/a/")) TvType.Anime else TvType.AnimeMovie
val episodes = mutableListOf<Episode>()
if (type == TvType.Anime) {
for (i in 1..10) {
val dataEpisode = app.get("$episodeUrl/animes/${fixUrl.substringAfterLast("/")}/episodes?page=$i&order=desc")
.parsedSafe<LoadAnime>()?.data?.map {
Episode(
Load(it.anime?.get("slug_serie"), it.n_episodio, "animes").toJson(),
it.titulo_episodio,
episode = it.n_episodio?.toIntOrNull(),
posterUrl = it.anime?.get("slug_serie")?.fixImageUrl(Image.Episode),
description = it.sinopse_episodio
)
}?.reversed() ?: emptyList()
if(dataEpisode.isEmpty()) break else episodes.addAll(dataEpisode)
}
} else {
val dataEpisode = listOf(
Episode(
Load(
document.selectFirst("script:containsData(slug_filme)")?.data()?.let {
Regex("[\"']slug_filme[\"']:[\"'](\\S+?)[\"']").find(it)?.groupValues?.get(1)
} ?: return null, "movie", "movies"
).toJson()
)
)
episodes.addAll(dataEpisode)
}
return newAnimeLoadResponse(title, url, type) {
engName = title
posterUrl = poster
this.year = year
addEpisodes(DubStatus.Subbed, episodes)
plot = description
this.tags = tags
}
}
override suspend fun loadLinks(
data: String,
isCasting: Boolean,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
): Boolean {
val load = tryParseJson<Load>(data)
callback.invoke(
ExtractorLink(
this.name,
this.name,
if(load?.type == "movies") {
"$videoUrl/hls/${load.type}/${load.slug_serie}/${load.n_episodio}.mp4/media-1/stream.m3u8"
} else {
"$videoUrl/cf/hls/${load?.type}/${load?.slug_serie}/${load?.n_episodio}.mp4/media-1/stream.m3u8"
},
"$mainUrl/",
Qualities.Unknown.value,
true
)
)
return true
}
private suspend fun getProperAnimeLink(uri: String): String? {
return if (uri.contains("/e/")) {
app.get(uri).document.selectFirst("div.epcontrol2 a[href*=/a/]")?.attr("href")?.let {
fixUrl(it)
}
} else {
uri
}
}
private fun addAnimeSearch(titulo: String, id: String, slug: String, type: Image): AnimeSearchResponse {
return newAnimeSearchResponse(titulo, "$mainUrl/$id", TvType.Anime) {
this.posterUrl = slug.fixImageUrl(type)
}
}
private fun String.fixImageUrl(param: Image): String {
return when (param) {
Image.Episode -> {
"$posterUrl/images/animes/screens/$this/130x74/007.jpg"
}
Image.Anime -> {
"$mainUrl/_next/image?url=$posterUrl/images/animes/capas/130x209/$this.jpg&w=384&q=75"
}
Image.Filme -> {
"$mainUrl/_next/image?url=$posterUrl/images/filmes/capas/130x209/$this.jpg&w=384&q=75"
}
}
}
enum class Image {
Episode,
Anime,
Filme,
}
data class Load(
val slug_serie: String? = null,
val n_episodio: String? = null,
val type: String? = null,
)
data class DataEpisode(
@JsonProperty("id_series_episodios") val id_series_episodios: Int? = null,
@JsonProperty("n_episodio") val n_episodio: String? = null,
@JsonProperty("titulo_episodio") val titulo_episodio: String? = null,
@JsonProperty("sinopse_episodio") val sinopse_episodio: String? = null,
@JsonProperty("generate_id") val generate_id: String? = null,
@JsonProperty("anime") val anime: HashMap<String, String>? = null,
)
data class LoadAnime(
@JsonProperty("data") val data: ArrayList<DataEpisode>? = arrayListOf()
)
data class DataAnime(
@JsonProperty("titulo") val titulo: String? = null,
@JsonProperty("generate_id") val generate_id: String? = null,
@JsonProperty("slug_serie") val slug_serie: String? = null,
@JsonProperty("total_eps_anime") val total_eps_anime: Int? = null,
)
data class DataFilme(
@JsonProperty("nome_filme") val nome_filme: String? = null,
@JsonProperty("generate_id") val generate_id: String? = null,
@JsonProperty("slug_filme") val slug_filme: String? = null,
)
data class SearchAnime(
@JsonProperty("data_anime") val data_anime: ArrayList<DataAnime>? = arrayListOf(),
@JsonProperty("data_filme") val data_filme: ArrayList<DataFilme>? = arrayListOf(),
)
}

View File

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

View File

@ -1,23 +0,0 @@
// use an integer for version numbers
version = 1
cloudstream {
language = "tr"
// All of these properties are optional, you can safely remove them
// description = "Lorem Ipsum"
authors = listOf("Hexated")
/**
* Status int as the following:
* 0: Down
* 1: Ok
* 2: Slow
* 3: Beta only
* */
status = 1 // will be 3 if unspecified
tvTypes = listOf("AsianDrama",)
iconUrl = "https://www.google.com/s2/favicons?domain=dizikorea.com&sz=%size%"
}

View File

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

View File

@ -1,203 +0,0 @@
package com.hexated
import com.fasterxml.jackson.annotation.JsonProperty
import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.LoadResponse.Companion.addActors
import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer
import com.lagradost.cloudstream3.utils.*
import org.jsoup.nodes.Element
import java.net.URI
class Dizikorea : MainAPI() {
override var mainUrl = "https://dizikorea.com"
override var name = "Dizikorea"
override val hasMainPage = true
override var lang = "tr"
override val hasDownloadSupport = true
override val hasQuickSearch = true
override val supportedTypes = setOf(TvType.AsianDrama)
override val mainPage = mainPageOf(
"$mainUrl/diziler/page/" to "Kore Dizileri",
"$mainUrl/kore-filmleri-izle/page/" to "Son Eklenen Filmler",
)
override suspend fun getMainPage(page: Int, request: MainPageRequest): HomePageResponse {
val document = app.get(request.data + page).document
val home = document.select("ul li.segment-poster").mapNotNull {
it.toSearchResult()
}
return newHomePageResponse(request.name, home)
}
private fun Element.toSearchResult(): SearchResponse? {
val href = fixUrl(this.selectFirst("a")!!.attr("href"))
val title = this.selectFirst("h2.truncate")?.text()?.trim() ?: return null
val posterUrl = fixUrlNull(this.selectFirst("img")?.attr("data-src"))
return newTvSeriesSearchResponse(title, href, TvType.AsianDrama) {
this.posterUrl = posterUrl
}
}
override suspend fun quickSearch(query: String): List<SearchResponse>? = search(query)
override suspend fun search(query: String): List<SearchResponse>? {
return app.post("$mainUrl/ajax.php?qr=$query")
.parsedSafe<Search>()?.data?.result?.mapNotNull { item ->
newTvSeriesSearchResponse(
item.s_name ?: return@mapNotNull null,
item.s_link ?: return@mapNotNull null,
TvType.AsianDrama
) {
this.posterUrl = fixUrlNull(item.s_image)
}
}
}
override suspend fun load(url: String): LoadResponse? {
val document = app.get(url).document
val title = document.selectFirst("h1.page-title")?.ownText()?.trim() ?: return null
val poster = fixUrlNull(document.selectFirst("a.ui.image img")?.attr("data-src"))
val tags = document.select("div.nano-content div:contains(Tür:) a").map { it.text() }
val year = document.selectFirst("table.ui.unstackable tr td:contains(Yapım Yılı) a")?.text()
?.trim()
?.toIntOrNull()
val description = document.selectFirst("p#tv-series-desc")?.text()?.trim()
val rating =
document.selectFirst("table.ui.unstackable tr td:contains(IMDb Puanı) .color-imdb")
?.text()?.trim()
.toRatingInt()
val actors = document.select("div.global-box div.item").map {
Actor(
it.select("h5.truncate").text().trim(),
fixUrlNull(it.selectFirst("img")?.attr("src"))
)
}
val type = if (document.select("div.all-seriespart")
.isNullOrEmpty()
) TvType.Movie else TvType.TvSeries
val trailer = document.selectFirst("a.prettyPhoto")?.attr("href")
return when (type) {
TvType.Movie -> {
newMovieLoadResponse(title, url, TvType.Movie, url) {
this.posterUrl = poster
this.year = year
this.plot = description
this.tags = tags
this.rating = rating
addActors(actors)
addTrailer(trailer)
}
}
else -> {
val episodes = document.select("div.all-seriespart div.el-item").map { ep ->
Episode(
fixUrl(ep.selectFirst("a")!!.attr("href")),
episode = ep.attr("data-epnumber").toIntOrNull(),
season = ep.selectFirst("span.season-name")?.text()?.filter { it.isDigit() }
?.toIntOrNull()
)
}
newTvSeriesLoadResponse(title, url, TvType.TvSeries, episodes) {
this.posterUrl = poster
this.year = year
this.plot = description
this.tags = tags
this.rating = rating
addActors(actors)
addTrailer(trailer)
}
}
}
}
private fun getBaseUrl(url: String): String {
return URI(url).let {
"${it.scheme}://${it.host}"
}
}
private suspend fun invokeLokalSource(
url: String,
source: String,
callback: (ExtractorLink) -> Unit
) {
val script = app.get(url, referer = "$mainUrl/").document.select("script")
.find { it.data().contains("sources:") }?.data()?.substringAfter("sources: [")
?.substringBefore("],")?.replace(Regex("\"?file\"?"), "\"file\"")
AppUtils.tryParseJson<Source>(script)?.file?.let { link ->
if (link.contains(".m3u8")) {
M3u8Helper.generateM3u8(
source,
fixUrl(link),
getBaseUrl(url)
).forEach(callback)
} else {
callback.invoke(
ExtractorLink(
source,
source,
fixUrl(link),
"$mainUrl/",
Qualities.Unknown.value,
)
)
}
}
}
override suspend fun loadLinks(
data: String,
isCasting: Boolean,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
): Boolean {
val document = app.get(data).document
val sources: MutableList<String> = mutableListOf()
val mainServer = document.select("div#singlePlay iframe").attr("src")
sources.add(mainServer)
document.select("ul.linkler li").apmap {
val server =
app.get(it.select("a").attr("href")).document.select("div#singlePlay iframe")
.attr("src")
if (sources.isNotEmpty()) sources.add(fixUrl(server))
}
sources.distinct().apmap { link ->
when {
link.startsWith("https://playerkorea") -> invokeLokalSource(link, this.name, callback)
link.startsWith("https://vidmoly") -> invokeLokalSource(link, "Vidmoly", callback)
else -> loadExtractor(link, "$mainUrl/", subtitleCallback, callback)
}
}
return true
}
private data class SearchItem(
@JsonProperty("s_link") val s_link: String? = null,
@JsonProperty("s_image") val s_image: String? = null,
@JsonProperty("s_name") val s_name: String? = null,
)
private data class Result(
@JsonProperty("result") val result: ArrayList<SearchItem> = arrayListOf(),
)
private data class Search(
@JsonProperty("data") val data: Result? = null,
)
private data class Source(
@JsonProperty("file") val file: String? = null,
)
}

View File

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

View File

@ -1,25 +0,0 @@
// use an integer for version numbers
version = 5
cloudstream {
language = "id"
// All of these properties are optional, you can safely remove them
// description = "Lorem Ipsum"
authors = listOf("Hexated")
/**
* Status int as the following:
* 0: Down
* 1: Ok
* 2: Slow
* 3: Beta only
* */
status = 1 // will be 3 if unspecified
tvTypes = listOf(
"AsianDrama",
)
iconUrl = "https://www.google.com/s2/favicons?domain=149.3.170.35&sz=%size%"
}

View File

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

View File

@ -1,181 +0,0 @@
package com.hexated
import com.fasterxml.jackson.annotation.JsonProperty
import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.extractors.Filesim
import com.lagradost.cloudstream3.utils.AppUtils
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.INFER_TYPE
import com.lagradost.cloudstream3.utils.getQualityFromName
import com.lagradost.cloudstream3.utils.loadExtractor
import org.jsoup.nodes.Element
class DramaSerial : MainAPI() {
override var mainUrl = "https://tv3.dramaserial.id"
private var serverUrl = "http://31.220.73.179/"
override var name = "DramaSerial"
override val hasMainPage = true
override var lang = "id"
override val hasDownloadSupport = true
override val supportedTypes = setOf(TvType.AsianDrama)
override val mainPage = mainPageOf(
"$mainUrl/page/" to "Latest Movie",
"$mainUrl/Genre/ongoing/page/" to "Ongoing",
"$mainUrl/Genre/drama-serial-korea/page/" to "Drama Serial Korea",
"$mainUrl/Genre/drama-serial-jepang/page/" to "Drama Serial Jepang",
"$mainUrl/Genre/drama-serial-mandarin/page/" to "Drama Serial Mandarin",
"$mainUrl/Genre/drama-serial-filipina/page/" to "Drama Serial Filipina",
"$mainUrl/Genre/drama-serial-india/page/" to "Drama Serial India",
)
override suspend fun getMainPage(page: Int, request: MainPageRequest): HomePageResponse {
val document = app.get(request.data + page).document
val home = document.select("main#main article").mapNotNull {
it.toSearchResult()
}
return newHomePageResponse(request.name, home)
}
private fun Element.toSearchResult(): SearchResponse? {
val href = fixUrl(this.selectFirst("a")!!.attr("href"))
val title = this.selectFirst("h2.entry-title a")?.text()?.trim() ?: return null
val posterUrl = fixUrlNull(this.selectFirst("img")?.attr("src"))
val episode =
this.selectFirst("div.gmr-episode-item")?.text()?.filter { it.isDigit() }?.toIntOrNull()
return newAnimeSearchResponse(title, href, TvType.AsianDrama) {
this.posterUrl = posterUrl
addSub(episode)
}
}
override suspend fun search(query: String): List<SearchResponse> {
val link = "$mainUrl/?s=$query&post_type[]=post&post_type[]=tv"
val document = app.get(link).document
return document.select("main#main article").mapNotNull {
it.toSearchResult()
}
}
override suspend fun load(url: String): LoadResponse {
val document = app.get(url).document
val title = document.selectFirst("h1.entry-title")!!.text().trim()
val poster = fixUrlNull(document.selectFirst("figure.pull-left img")?.attr("src"))
val tags =
document.select("div.gmr-movie-innermeta span:contains(Genre:) a").map { it.text() }
val year =
document.selectFirst("div.gmr-movie-innermeta span:contains(Year:) a")!!.text().trim()
.toIntOrNull()
val duration =
document.selectFirst("div.gmr-movie-innermeta span:contains(Duration:)")?.text()
?.filter { it.isDigit() }?.toIntOrNull()
val description = document.select("div.entry-content.entry-content-single div.entry-content.entry-content-single").text().trim()
val type = if(document.select("div.page-links").isNullOrEmpty()) TvType.Movie else TvType.AsianDrama
if (type == TvType.Movie) {
return newMovieLoadResponse(title, url, TvType.Movie, url) {
posterUrl = poster
this.year = year
plot = description
this.tags = tags
this.duration = duration
}
} else {
val episodes = document.select("div.page-links span.page-link-number").mapNotNull { eps ->
val episode = eps.text().filter { it.isDigit() }.toIntOrNull()
val link = if(episode == 1) {
url
} else {
eps.parent()?.attr("href")
}
Episode(
link ?: return@mapNotNull null,
episode = episode,
)
}
return newTvSeriesLoadResponse(title, url, TvType.AsianDrama, episodes = episodes) {
posterUrl = poster
this.year = year
this.duration = duration
plot = description
this.tags = tags
}
}
}
private suspend fun invokeGetbk(
url: String,
callback: (ExtractorLink) -> Unit
) {
val script = app.get(
url,
referer = "$serverUrl/"
).document.selectFirst("script:containsData(sources)")?.data() ?: return
val json = "\"sources\":\\s*\\[(.*)]".toRegex().find(script)?.groupValues?.get(1)
AppUtils.tryParseJson<ArrayList<Sources>>("[$json]")?.map {
callback.invoke(
ExtractorLink(
"Getbk",
"Getbk",
it.file ?: return@map,
"$serverUrl/",
getQualityFromName(it.label),
INFER_TYPE,
)
)
}
}
override suspend fun loadLinks(
data: String,
isCasting: Boolean,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
): Boolean {
val document = app.get(data).document
val iframe = document.select("iframe[name=juraganfilm]").attr("src")
app.get(iframe, referer = "$mainUrl/").document.select("div#header-slider ul li")
.apmap { mLink ->
mLink.attr("onclick").substringAfter("frame('").substringBefore("')").let { iLink ->
val iMovie = iLink.substringAfter("movie=").substringBefore("&")
val mIframe = iLink.substringAfter("iframe=")
val iUrl = "$serverUrl/stream/$mIframe.php?movie=$iMovie"
if(mIframe == "getbk") {
invokeGetbk(iUrl, callback)
} else {
val link = app.get(
iUrl,
referer = "$serverUrl/"
).document.selectFirst("iframe")?.attr("src") ?: return@apmap null
loadExtractor(fixUrl(link), "$serverUrl/", subtitleCallback, callback)
}
}
}
return true
}
private data class Sources(
@JsonProperty("file") val file: String? = null,
@JsonProperty("label") val label: String? = null,
)
}
class Bk21 : Filesim() {
override val name = "Bk21"
override var mainUrl = "https://bk21.net"
}
class Lkc21 : Filesim() {
override val name = "Lkc21"
override var mainUrl = "https://lkc21.net"
}

View File

@ -1,16 +0,0 @@
package com.hexated
import com.lagradost.cloudstream3.plugins.CloudstreamPlugin
import com.lagradost.cloudstream3.plugins.Plugin
import android.content.Context
@CloudstreamPlugin
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(Bk21())
registerExtractorAPI(Lkc21())
}
}

View File

@ -1,26 +0,0 @@
// use an integer for version numbers
version = 10
cloudstream {
language = "id"
// All of these properties are optional, you can safely remove them
description = "Include: Oppadrama"
authors = listOf("Hexated")
/**
* Status int as the following:
* 0: Down
* 1: Ok
* 2: Slow
* 3: Beta only
* */
status = 1 // will be 3 if unspecified
tvTypes = listOf(
"AsianDrama",
"Movie",
)
iconUrl = "https://www.google.com/s2/favicons?domain=dramaid.asia&sz=%size%"
}

View File

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

View File

@ -1,205 +0,0 @@
package com.hexated
import com.fasterxml.jackson.annotation.JsonProperty
import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.extractors.XStreamCdn
import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.getQualityFromName
import com.lagradost.cloudstream3.utils.loadExtractor
import org.jsoup.Jsoup
import org.jsoup.nodes.Element
open class DramaidProvider : MainAPI() {
override var mainUrl = "https://dramaid.skin"
override var name = "DramaId"
override val hasMainPage = true
override var lang = "id"
override val supportedTypes = setOf(TvType.AsianDrama)
companion object {
fun getStatus(t: String): ShowStatus {
return when (t) {
"Completed" -> ShowStatus.Completed
"Ongoing" -> ShowStatus.Ongoing
else -> ShowStatus.Completed
}
}
fun getType(t: String?): TvType {
return when {
t?.contains("Movie", true) == true -> TvType.Movie
t?.contains("Anime", true) == true -> TvType.Anime
else -> TvType.AsianDrama
}
}
}
override val mainPage = mainPageOf(
"&status=&type=&order=update" to "Drama Terbaru",
"&order=latest" to "Baru Ditambahkan",
"&status=&type=&order=popular" to "Drama Popular",
)
override suspend fun getMainPage(page: Int, request: MainPageRequest): HomePageResponse {
val document = app.get("$mainUrl/series/?page=$page${request.data}").document
val home = document.select("article[itemscope=itemscope]").mapNotNull {
it.toSearchResult()
}
return newHomePageResponse(request.name, home)
}
private fun getProperDramaLink(uri: String): String {
return if (uri.contains("-episode-")) {
"$mainUrl/series/" + Regex("$mainUrl/(.+)-ep.+").find(uri)?.groupValues?.get(1)
} else {
uri
}
}
private fun Element.toSearchResult(): SearchResponse? {
val href = getProperDramaLink(this.selectFirst("a.tip")!!.attr("href"))
val title = this.selectFirst("h2[itemprop=headline]")?.text()?.trim() ?: return null
val posterUrl = fixUrlNull(this.select("img:last-child").attr("src"))
return newTvSeriesSearchResponse(title, href, TvType.AsianDrama) {
this.posterUrl = posterUrl
}
}
override suspend fun search(query: String): List<SearchResponse> {
val document = app.get("$mainUrl/?s=$query").document
return document.select("article[itemscope=itemscope]").mapNotNull {
it.toSearchResult()
}
}
override suspend fun load(url: String): LoadResponse {
val document = app.get(url).document
val title = document.selectFirst("h1.entry-title")?.text()?.trim() ?: ""
val poster = fixUrlNull(document.select("div.thumb img:last-child").attr("src"))
val tags = document.select(".genxed > a").map { it.text() }
val type = document.selectFirst(".info-content .spe span:contains(Tipe:)")?.ownText()
val year = Regex("\\d, ([0-9]*)").find(
document.selectFirst(".info-content > .spe > span > time")!!.text().trim()
)?.groupValues?.get(1).toString().toIntOrNull()
val status = getStatus(
document.select(".info-content > .spe > span:nth-child(1)")
.text().trim().replace("Status: ", "")
)
val description = document.select(".entry-content > p").text().trim()
val episodes = document.select(".eplister > ul > li").mapNotNull {
val name = it.selectFirst("a > .epl-title")?.text()
val link = fixUrl(it.selectFirst("a")?.attr("href") ?: return@mapNotNull null)
Episode(
link,
name,
)
}.reversed()
val recommendations =
document.select(".listupd > article[itemscope=itemscope]").mapNotNull { rec ->
rec.toSearchResult()
}
return newTvSeriesLoadResponse(
title,
url,
getType(type),
episodes = episodes
) {
posterUrl = poster
this.year = year
showStatus = status
plot = description
this.tags = tags
this.recommendations = recommendations
}
}
private data class Sources(
@JsonProperty("file") val file: String,
@JsonProperty("label") val label: String,
@JsonProperty("type") val type: String,
@JsonProperty("default") val default: Boolean?
)
private data class Tracks(
@JsonProperty("file") val file: String,
@JsonProperty("label") val label: String,
@JsonProperty("kind") val type: String,
@JsonProperty("default") val default: Boolean?
)
private suspend fun invokeDriveSource(
url: String,
name: String,
subCallback: (SubtitleFile) -> Unit,
sourceCallback: (ExtractorLink) -> Unit
) {
val server = app.get(url).document.selectFirst(".picasa")?.nextElementSibling()?.data()
val source = "[${server!!.substringAfter("sources: [").substringBefore("],")}]".trimIndent()
val trackers = server.substringAfter("tracks:[").substringBefore("],")
.replace("//language", "")
.replace("file", "\"file\"")
.replace("label", "\"label\"")
.replace("kind", "\"kind\"").trimIndent()
tryParseJson<List<Sources>>(source)?.map {
sourceCallback(
ExtractorLink(
name,
"Drive",
fixUrl(it.file),
referer = "https://motonews.club/",
quality = getQualityFromName(it.label)
)
)
}
tryParseJson<Tracks>(trackers)?.let {
subCallback.invoke(
SubtitleFile(
if (it.label.contains("Indonesia")) "${it.label}n" else it.label,
it.file
)
)
}
}
override suspend fun loadLinks(
data: String,
isCasting: Boolean,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
): Boolean {
val document = app.get(data).document
val sources = document.select(".mobius > .mirror > option").mapNotNull {
fixUrl(Jsoup.parse(base64Decode(it.attr("value"))).select("iframe").attr("src"))
}
sources.map {
it.replace("https://ndrama.xyz", "https://www.fembed.com")
}.apmap {
when {
it.contains("motonews") -> invokeDriveSource(
it,
this.name,
subtitleCallback,
callback
)
else -> loadExtractor(it, "$mainUrl/", subtitleCallback, callback)
}
}
return true
}
}

View File

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

View File

@ -1,71 +0,0 @@
package com.hexated
import com.fasterxml.jackson.annotation.JsonProperty
import com.lagradost.cloudstream3.APIHolder
import com.lagradost.cloudstream3.SubtitleFile
import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.extractors.Filesim
import com.lagradost.cloudstream3.extractors.XStreamCdn
import com.lagradost.cloudstream3.utils.ExtractorApi
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.M3u8Helper
open class Gcam : ExtractorApi() {
override val name = "Gcam"
override val mainUrl = "https://gdrive.cam"
override val requiresReferer = true
override suspend fun getUrl(
url: String,
referer: String?,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
) {
val response = app.get(url, referer = referer).text
val kaken = "kaken\\s*=\\s*\"(.*)\"".toRegex().find(response)?.groupValues?.get(1)
val json = app.get("https://cdn2.gdrive.cam/api/?${kaken ?: return}=&_=${APIHolder.unixTimeMS}").parsedSafe<Response>()
json?.sources?.map {
M3u8Helper.generateM3u8(
name,
it.file ?: return@map,
""
).forEach(callback)
}
json?.tracks?.map {
subtitleCallback.invoke(
SubtitleFile(
it.label ?: return@map,
it.file ?: return@map
)
)
}
}
data class Tracks(
@JsonProperty("file") val file: String? = null,
@JsonProperty("label") val label: String? = null,
)
data class Sources(
@JsonProperty("file") val file: String? = null,
)
data class Response(
@JsonProperty("sources") val sources: ArrayList<Sources>? = arrayListOf(),
@JsonProperty("tracks") val tracks: ArrayList<Tracks>? = arrayListOf(),
)
}
class Vanfem : XStreamCdn() {
override val name: String = "Vanfem"
override val mainUrl: String = "https://vanfem.com"
}
class Filelions : Filesim() {
override val name = "Filelions"
override var mainUrl = "https://filelions.live"
}

View File

@ -1,8 +0,0 @@
package com.hexated
import com.lagradost.cloudstream3.extractors.Filesim
class Oppadrama : DramaidProvider() {
override var mainUrl = "http://185.217.95.30"
override var name = "Oppadrama"
}

View File

@ -1,27 +0,0 @@
// use an integer for version numbers
version = 1
cloudstream {
language = "id"
// All of these properties are optional, you can safely remove them
// description = "Lorem Ipsum"
authors = listOf("Hexated")
/**
* Status int as the following:
* 0: Down
* 1: Ok
* 2: Slow
* 3: Beta only
* */
status = 1 // will be 3 if unspecified
tvTypes = listOf(
"TvSeries",
"Movie",
"Cartoon",
"Anime",
)
iconUrl = "https://www.google.com/s2/favicons?domain=www.dubbindo.xyz&sz=%size%"
}

View File

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

View File

@ -1,136 +0,0 @@
package com.hexated
import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.utils.AppUtils.toJson
import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.Qualities
import com.lagradost.cloudstream3.utils.loadExtractor
import org.jsoup.nodes.Element
class Dubbindo : MainAPI() {
override var mainUrl = "https://www.dubbindo.site"
override var name = "Dubbindo"
override val hasMainPage = true
override var lang = "id"
override val hasDownloadSupport = true
override val supportedTypes = setOf(
TvType.TvSeries,
TvType.Movie,
TvType.Cartoon,
TvType.Anime,
)
override val mainPage = mainPageOf(
"$mainUrl/videos/category/1" to "Movie",
"$mainUrl/videos/category/3" to "TV Series",
"$mainUrl/videos/category/5" to "Anime Series",
"$mainUrl/videos/category/4" to "Anime Movie",
"$mainUrl/videos/category/other" to "Other",
)
override suspend fun getMainPage(
page: Int,
request: MainPageRequest
): HomePageResponse {
val document = app.get("${request.data}?page_id=$page").document
val home = document.select("div.videos-latest-list.pt_timeline_vids div.video-wrapper")
.mapNotNull {
it.toSearchResult()
}
return newHomePageResponse(
list = HomePageList(
name = request.name,
list = home,
isHorizontalImages = true
),
hasNext = true
)
}
private fun Element.toSearchResult(): TvSeriesSearchResponse? {
val title = this.selectFirst("h4,div.video-title")?.text()?.trim() ?: ""
val href = this.selectFirst("a")?.attr("href") ?: return null
val posterUrl = fixUrlNull(this.selectFirst("img")?.attr("src"))
return newTvSeriesSearchResponse(title, href, TvType.TvSeries) {
this.posterUrl = posterUrl
}
}
override suspend fun search(query: String): List<SearchResponse> {
val searchResponse = mutableListOf<SearchResponse>()
for (i in 1..10) {
val document =
app.get(
"$mainUrl/search?keyword=$query&page_id=$i",
).document
val results = document.select("div.videos-latest-list.row div.video-wrapper")
.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-big-title h1")?.text() ?: return null
val poster = document.selectFirst("meta[property=og:image]")?.attr("content")
val tags = document.select("div.pt_categories li a").map { it.text() }
val description = document.select("div.watch-video-description p").text()
val recommendations = document.select("div.related-video-wrapper").mapNotNull {
it.toSearchResult()
}
val video = document.select("video#my-video source").map {
Video(
it.attr("src"),
it.attr("size"),
it.attr("type"),
)
}
return newMovieLoadResponse(title, url, TvType.Movie, video.toJson()) {
posterUrl = poster
plot = description
this.tags = tags
this.recommendations = recommendations
}
}
override suspend fun loadLinks(
data: String,
isCasting: Boolean,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
): Boolean {
tryParseJson<List<Video>>(data)?.map { video ->
if(video.type == "video/mp4" || video.type == "video/x-msvideo" || video.type == "video/x-matroska") {
callback.invoke(
ExtractorLink(
this.name,
this.name,
video.src ?: return@map,
"",
video.res?.toIntOrNull() ?: Qualities.Unknown.value,
)
)
} else {
loadExtractor(video.src ?: return@map, "", subtitleCallback, callback)
}
}
return true
}
data class Video(
val src: String? = null,
val res: String? = null,
val type: String? = null,
)
}

View File

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

View File

@ -1,27 +0,0 @@
// use an integer for version numbers
version = 1
cloudstream {
language = "zh"
// All of these properties are optional, you can safely remove them
// description = "Lorem Ipsum"
authors = listOf("Hexated")
/**
* Status int as the following:
* 0: Down
* 1: Ok
* 2: Slow
* 3: Beta only
* */
status = 1 // will be 3 if unspecified
tvTypes = listOf(
"AsianDrama",
"TvSeries",
"Movie",
)
iconUrl = "https://www.google.com/s2/favicons?domain=www.duboku.tv&sz=%size%"
}

View File

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

View File

@ -1,133 +0,0 @@
package com.hexated
import com.fasterxml.jackson.annotation.JsonProperty
import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.LoadResponse.Companion.addActors
import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.M3u8Helper
import org.jsoup.nodes.Element
class DubokuProvider : MainAPI() {
override var mainUrl = "https://www.duboku.tv"
override var name = "Duboku"
override val hasMainPage = true
override var lang = "zh"
override val hasDownloadSupport = true
override val supportedTypes = setOf(
TvType.Movie,
TvType.TvSeries,
TvType.AsianDrama,
)
override val mainPage = mainPageOf(
"$mainUrl/vodshow/2--time------" to "连续剧 时间",
"$mainUrl/vodshow/2--hits------" to "连续剧 人气",
"$mainUrl/vodshow/13--time------" to "陆剧 时间",
"$mainUrl/vodshow/13--hits------" to "陆剧 人气",
"$mainUrl/vodshow/15--time------" to "日韩剧 时间",
"$mainUrl/vodshow/15--hits------" to "日韩剧 人气",
"$mainUrl/vodshow/21--time------" to "短剧 时间",
"$mainUrl/vodshow/21--hits------" to "短剧 人气",
"$mainUrl/vodshow/16--time------" to "英美剧 时间",
"$mainUrl/vodshow/16--hits------" to "英美剧 人气",
"$mainUrl/vodshow/14--time------" to "台泰剧 时间",
"$mainUrl/vodshow/14--hits------" to "台泰剧 人气",
"$mainUrl/vodshow/20--time------" to "港剧 时间",
"$mainUrl/vodshow/20--hits------" to "港剧 人气",
)
override suspend fun getMainPage(
page: Int,
request: MainPageRequest
): HomePageResponse {
val document = app.get("${request.data}$page---.html").document
val home = document.select("ul.myui-vodlist.clearfix li").mapNotNull {
it.toSearchResult()
}
return newHomePageResponse(request.name, home)
}
private fun Element.toSearchResult(): SearchResponse? {
val title = this.selectFirst("h4.title a")?.text()?.trim() ?: return null
val href = fixUrl(this.selectFirst("a")?.attr("href").toString())
val posterUrl = fixUrlNull(this.selectFirst("a")?.attr("data-original"))
val episode = this.selectFirst("span.pic-text.text-right")?.text()?.filter { it.isDigit() }
?.toIntOrNull()
return newAnimeSearchResponse(title, href, TvType.Movie) {
this.posterUrl = posterUrl
addSub(episode)
}
}
override suspend fun search(query: String): List<SearchResponse> {
val document = app.get("$mainUrl/vodsearch/-------------.html?wd=$query&submit=").document
return document.select("ul#searchList li").mapNotNull {
it.toSearchResult()
}
}
override suspend fun load(url: String): LoadResponse? {
val document = app.get(url).document
val title = document.selectFirst("h1.title")?.text()?.trim() ?: return null
val tvType = if (document.select("ul.myui-content__list li").size == 1
) TvType.Movie else TvType.TvSeries
val actors = document.select("p.data")[2].select("a").map { it.text() }
val episodes = document.select("ul.myui-content__list li").map {
val href = fixUrl(it.select("a").attr("href"))
val name = it.select("a").text().trim()
Episode(
data = href,
name = name,
)
}
return newTvSeriesLoadResponse(title, url, tvType, episodes) {
this.posterUrl = fixUrlNull(
document.selectFirst("a.myui-vodlist__thumb.picture img")?.attr("data-original")
)
this.year =
document.select("p.data")[0].select("a").last()?.text()?.trim()?.toIntOrNull()
this.plot = document.selectFirst("span.sketch.content")?.text()?.trim()
this.tags = document.select("p.data")[0].select("a").map { it.text() }
this.rating = document.select("div#rating span.branch").text().toRatingInt()
addActors(actors)
}
}
override suspend fun loadLinks(
data: String,
isCasting: Boolean,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
): Boolean {
app.get(data).document.select("script").map { script ->
if (script.data().contains("var player_data={")) {
val dataJson =
script.data().substringAfter("var player_data={").substringBefore("}")
tryParseJson<Sources>("{$dataJson}")?.let { source ->
M3u8Helper.generateM3u8(
this.name,
source.url ?: return@map,
referer = "https://w.duboku.io/",
headers = mapOf("Origin" to "https://w.duboku.io")
).forEach(callback)
}
}
}
return true
}
data class Sources(
@JsonProperty("url") val url: String?,
)
}

View File

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

View File

@ -1,24 +0,0 @@
// use an integer for version numbers
version = 1
cloudstream {
// All of these properties are optional, you can safely remove them
description = "German Filmpalast provider"
authors = listOf("Bnyro")
/**
* 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("TvSeries", "Movie")
}

View File

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

View File

@ -1,30 +0,0 @@
package com.example
import com.lagradost.cloudstream3.extractors.Filesim
import com.lagradost.cloudstream3.extractors.StreamTape
import com.lagradost.cloudstream3.extractors.Streamhub
import com.lagradost.cloudstream3.extractors.Voe
class StreamTapeTo : StreamTape() {
override var mainUrl = "https://streamtape.com"
}
class StreamHubGg : Streamhub() {
override var name = "Streamhub Gg"
override var mainUrl = "https://streamhub.gg"
}
class VoeSx: Voe() {
override val name = "Voe Sx"
override val mainUrl = "https://voe.sx"
}
class MetaGnathTuggers : Voe() {
override val name = "Metagnathtuggers"
override val mainUrl = "https://metagnathtuggers.com"
}
class FileLions : Filesim() {
override val name = "Filelions"
override var mainUrl = "https://filelions.to"
}

View File

@ -1,18 +0,0 @@
package com.example
import com.lagradost.cloudstream3.plugins.CloudstreamPlugin
import com.lagradost.cloudstream3.plugins.Plugin
import android.content.Context
@CloudstreamPlugin
class FilmpalastPlugin: Plugin() {
override fun load(context: Context) {
// All providers should be added in this manner. Please don't edit the providers list directly.
registerMainAPI(FilmpalastProvider())
registerExtractorAPI(StreamTapeTo())
registerExtractorAPI(StreamHubGg())
registerExtractorAPI(VoeSx())
registerExtractorAPI(MetaGnathTuggers())
registerExtractorAPI(FileLions())
}
}

View File

@ -1,82 +0,0 @@
package com.example
import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.utils.AppUtils.parseJson
import com.lagradost.cloudstream3.utils.AppUtils.toJson
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.loadExtractor
import org.jsoup.nodes.Element
import org.jsoup.select.Elements
class FilmpalastProvider : MainAPI() {
override var mainUrl = "https://filmpalast.to"
override var name = "Filmpalast"
override val supportedTypes = setOf(TvType.Movie, TvType.TvSeries)
override var lang = "de"
override val hasMainPage = true
private fun Element.toSearchResponse(): SearchResponse {
val title = select("cite a.rb").text()
val url = select("a.rb").attr("href")
val posterPath = select("img.cover-opacity").attr("src")
return newMovieSearchResponse(title, type = TvType.Movie, url = url).apply {
this.posterUrl = "$mainUrl$posterPath"
}
}
override suspend fun getMainPage(page: Int, request: MainPageRequest): HomePageResponse {
val movies = app.get("$mainUrl/movies/top").document
val movieResults = movies.select("#content .liste.rb").mapNotNull {
it.toSearchResponse()
}
val series = app.get("$mainUrl/serien/view").document
val seriesResults = series.select("#content .liste.rb").mapNotNull {
it.toSearchResponse()
}
val homePageLists = listOf(HomePageList("Movies", movieResults), HomePageList("Series", seriesResults))
return newHomePageResponse(homePageLists, hasNext = false)
}
override suspend fun search(query: String): List<SearchResponse> {
val document = app.get("$mainUrl/search/title/$query").document
return document.select("#content .glowliste").mapNotNull {
it.toSearchResponse()
}
}
override suspend fun load(url: String): LoadResponse {
val document = app.get(url).document.select("#content")
val title = document.select("h2.rb.bgDark").text()
val imagePath = document.select(".detail.rb img.cover2").attr("src")
val description = document.select("span[itemprop=description]").text()
val details = document.select("detail-content-list li")
val year = details.first()?.html()?.split("<br>")?.getOrNull(1)?.filter { it.isDigit() }?.toIntOrNull()
val duration = details.select("em").first()?.ownText()?.filter { it.isDigit() }?.toIntOrNull()
val links = document.select(".currentStreamLinks a.iconPlay").mapNotNull {
it.attr("href") ?: it.attr("data-player-url")
}
return newMovieLoadResponse(title, url, TvType.Movie, links.toJson()).apply {
this.posterUrl = "$mainUrl$imagePath"
this.plot = description
this.duration = duration
this.year = year
}
}
override suspend fun loadLinks(
data: String,
isCasting: Boolean,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
): Boolean {
val links = parseJson<List<String>>(data)
links.apmap {
val link = fixUrlNull(it) ?: return@apmap null
loadExtractor(link, "$mainUrl/", subtitleCallback, callback)
}
return links.isNotEmpty()
}
}

View File

@ -1,36 +0,0 @@
import org.jetbrains.kotlin.konan.properties.Properties
// use an integer for version numbers
version = 29
android {
defaultConfig {
val properties = Properties()
properties.load(project.rootProject.file("local.properties").inputStream())
buildConfigField("String", "ZSHOW_API", "\"${properties.getProperty("ZSHOW_API")}\"")
}
}
cloudstream {
language = "id"
// All of these properties are optional, you can safely remove them
description = "Includes: DutaMovie, Ngefilm, Nodrakorid, Multiplex, Pusatfilm"
authors = listOf("Hexated")
/**
* Status int as the following:
* 0: Down
* 1: Ok
* 2: Slow
* 3: Beta only
* */
status = 1 // will be 3 if unspecified
tvTypes = listOf(
"AsianDrama",
"TvSeries",
"Movie",
)
iconUrl = "https://www.google.com/s2/favicons?domain=gomov.bio&sz=%size%"
}

View File

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

View File

@ -1,19 +0,0 @@
package com.hexated
import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.httpsify
import com.lagradost.cloudstream3.utils.loadExtractor
class DutaMovie : Gomov() {
override var mainUrl = "https://drama.dutamovie21.tech/"
override var name = "DutaMovie"
override val mainPage = mainPageOf(
"category/box-office/page/%d/" to "Box Office",
"category/serial-tv/page/%d/" to "Serial TV",
"category/animation/page/%d/" to "Animasi",
"country/korea/page/%d/" to "Serial TV Korea",
"country/indonesia/page/%d/" to "Serial TV Indonesia",
)
}

View File

@ -1,90 +0,0 @@
package com.hexated
import com.lagradost.cloudstream3.SubtitleFile
import com.lagradost.cloudstream3.apmap
import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.base64Decode
import com.lagradost.cloudstream3.extractors.*
import com.lagradost.cloudstream3.utils.ExtractorApi
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.M3u8Helper
import com.lagradost.cloudstream3.utils.loadExtractor
open class Uplayer : ExtractorApi() {
override val name = "Uplayer"
override val mainUrl = "https://uplayer.xyz"
override val requiresReferer = true
override suspend fun getUrl(
url: String,
referer: String?,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
) {
val res = app.get(url,referer=referer).text
val m3u8 = Regex("file:\\s*\"(.*?m3u8.*?)\"").find(res)?.groupValues?.getOrNull(1)
M3u8Helper.generateM3u8(
name,
m3u8 ?: return,
mainUrl
).forEach(callback)
}
}
open class Kotakajaib : ExtractorApi() {
override val name = "Kotakajaib"
override val mainUrl = "https://kotakajaib.me"
override val requiresReferer = true
override suspend fun getUrl(
url: String,
referer: String?,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
) {
app.get(url,referer=referer).document.select("ul#dropdown-server li a").apmap {
loadExtractor(base64Decode(it.attr("data-frame")), "$mainUrl/", subtitleCallback, callback)
}
}
}
class Doods : DoodLaExtractor() {
override var name = "Doods"
override var mainUrl = "https://doods.pro"
}
class Dutamovie21 : StreamSB() {
override var name = "Dutamovie21"
override var mainUrl = "https://dutamovie21.xyz"
}
class FilelionsTo : Filesim() {
override val name = "Filelions"
override var mainUrl = "https://filelions.to"
}
class FilelionsOn : Filesim() {
override val name = "Filelions"
override var mainUrl = "https://filelions.online"
}
class Lylxan : Filesim() {
override val name = "Lylxan"
override var mainUrl = "https://lylxan.com"
}
class Embedwish : Filesim() {
override val name = "Embedwish"
override var mainUrl = "https://embedwish.com"
}
class Likessb : StreamSB() {
override var name = "Likessb"
override var mainUrl = "https://likessb.com"
}
class DbGdriveplayer : Gdriveplayer() {
override var mainUrl = "https://database.gdriveplayer.us"
}

View File

@ -1,204 +0,0 @@
package com.hexated
import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.LoadResponse.Companion.addActors
import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.httpsify
import com.lagradost.cloudstream3.utils.loadExtractor
import org.jsoup.nodes.Element
import java.net.URI
open class Gomov : MainAPI() {
override var mainUrl = "https://gomov.bio"
private var directUrl: String? = null
override var name = "Gomov"
override val hasMainPage = true
override var lang = "id"
override val supportedTypes = setOf(
TvType.Movie,
TvType.TvSeries,
TvType.AsianDrama
)
override val mainPage = mainPageOf(
"page/%d/?s&search=advanced&post_type=movie" to "Movies",
"category/western-series/page/%d/" to "Western Series",
"tv/page/%d/" to "Tv Shows",
"category/korean-series/page/%d/" to "Korean Series",
"category/chinese-series/page/%d/" to "Chinese Series",
"category/india-series/page/%d/" to "India Series",
)
override suspend fun getMainPage(
page: Int,
request: MainPageRequest
): HomePageResponse {
val data = request.data.format(page)
val document = app.get("$mainUrl/$data").document
val home = document.select("article.item").mapNotNull {
it.toSearchResult()
}
return newHomePageResponse(request.name, home)
}
private fun Element.toSearchResult(): SearchResponse? {
val title = this.selectFirst("h2.entry-title > a")?.text()?.trim() ?: return null
val href = fixUrl(this.selectFirst("a")!!.attr("href"))
val posterUrl = fixUrlNull(this.selectFirst("a > img")?.getImageAttr()).fixImageQuality()
val quality = this.select("div.gmr-qual, div.gmr-quality-item > a").text().trim().replace("-", "")
return if (quality.isEmpty()) {
val episode =
Regex("Episode\\s?([0-9]+)").find(title)?.groupValues?.getOrNull(1)?.toIntOrNull()
?: this.select("div.gmr-numbeps > span").text().toIntOrNull()
newAnimeSearchResponse(title, href, TvType.TvSeries) {
this.posterUrl = posterUrl
addSub(episode)
}
} else {
newMovieSearchResponse(title, href, TvType.Movie) {
this.posterUrl = posterUrl
addQuality(quality)
}
}
}
private fun Element.toRecommendResult(): SearchResponse? {
val title = this.selectFirst("a > span.idmuvi-rp-title")?.text()?.trim() ?: return null
val href = this.selectFirst("a")!!.attr("href")
val posterUrl = fixUrlNull(this.selectFirst("a > img")?.getImageAttr().fixImageQuality())
return newMovieSearchResponse(title, href, TvType.Movie) {
this.posterUrl = posterUrl
}
}
override suspend fun search(query: String): List<SearchResponse> {
return app.get("$mainUrl/?s=$query&post_type[]=post&post_type[]=tv").document.select("article.item")
.mapNotNull {
it.toSearchResult()
}
}
override suspend fun load(url: String): LoadResponse {
val fetch = app.get(url)
directUrl = getBaseUrl(fetch.url)
val document = fetch.document
val title =
document.selectFirst("h1.entry-title")?.text()?.substringBefore("Season")?.substringBefore("Episode")?.trim()
.toString()
val poster =
fixUrlNull(document.selectFirst("figure.pull-left > img")?.getImageAttr())?.fixImageQuality()
val tags = document.select("span.gmr-movie-genre:contains(Genre:) > a").map { it.text() }
val year =
document.select("span.gmr-movie-genre:contains(Year:) > a").text().trim().toIntOrNull()
val tvType = if (url.contains("/tv/")) TvType.TvSeries else TvType.Movie
val description = document.selectFirst("div[itemprop=description] > p")?.text()?.trim()
val trailer = document.selectFirst("ul.gmr-player-nav li a.gmr-trailer-popup")?.attr("href")
val rating =
document.selectFirst("div.gmr-meta-rating > span[itemprop=ratingValue]")?.text()
?.toRatingInt()
val actors = document.select("div.gmr-moviedata").last()?.select("span[itemprop=actors]")
?.map { it.select("a").text() }
val recommendations = document.select("div.idmuvi-rp ul li").mapNotNull {
it.toRecommendResult()
}
return if (tvType == TvType.TvSeries) {
val episodes = document.select("div.vid-episodes a, div.gmr-listseries a").map { eps ->
val href = fixUrl(eps.attr("href"))
val name = eps.text()
val episode = name.split(" ").lastOrNull()?.filter { it.isDigit() }?.toIntOrNull()
val season = name.split(" ").firstOrNull()?.filter { it.isDigit() }?.toIntOrNull()
Episode(
href,
name,
season = if(name.contains(" ")) season else null,
episode = episode,
)
}.filter { it.episode != null }
newTvSeriesLoadResponse(title, url, TvType.TvSeries, episodes) {
this.posterUrl = poster
this.year = year
this.plot = description
this.tags = tags
this.rating = rating
addActors(actors)
this.recommendations = recommendations
addTrailer(trailer)
}
} else {
newMovieLoadResponse(title, url, TvType.Movie, url) {
this.posterUrl = poster
this.year = year
this.plot = description
this.tags = tags
this.rating = rating
addActors(actors)
this.recommendations = recommendations
addTrailer(trailer)
}
}
}
override suspend fun loadLinks(
data: String,
isCasting: Boolean,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
): Boolean {
val document = app.get(data).document
val id = document.selectFirst("div#muvipro_player_content_id")?.attr("data-id")
if(id.isNullOrEmpty()) {
document.select("ul.muvipro-player-tabs li a").apmap { ele ->
val iframe = app.get(fixUrl(ele.attr("href"))).document.selectFirst("div.gmr-embed-responsive iframe")
.getIframeAttr()?.let { httpsify(it) } ?: return@apmap
loadExtractor(iframe, "$directUrl/", subtitleCallback, callback)
}
} else {
document.select("div.tab-content-ajax").apmap { ele ->
val server = app.post(
"$directUrl/wp-admin/admin-ajax.php",
data = mapOf("action" to "muvipro_player_content", "tab" to ele.attr("id"), "post_id" to "$id")
).document.select("iframe").attr("src").let { httpsify(it) }
loadExtractor(server, "$directUrl/", subtitleCallback, callback)
}
}
return true
}
private fun Element.getImageAttr(): String? {
return when {
this.hasAttr("data-src") -> this.attr("abs:data-src")
this.hasAttr("data-lazy-src") -> this.attr("abs:data-lazy-src")
this.hasAttr("srcset") -> this.attr("abs:srcset").substringBefore(" ")
else -> this.attr("abs:src")
}
}
private fun Element?.getIframeAttr() : String? {
return this?.attr("data-litespeed-src").takeIf { it?.isNotEmpty() == true } ?: this?.attr("src")
}
private fun String?.fixImageQuality(): String? {
if (this == null) return null
val regex = Regex("(-\\d*x\\d*)").find(this)?.groupValues?.get(0) ?: return this
return this.replace(regex, "")
}
private fun getBaseUrl(url: String): String {
return URI(url).let {
"${it.scheme}://${it.host}"
}
}
}

View File

@ -1,29 +0,0 @@
package com.hexated
import com.lagradost.cloudstream3.plugins.CloudstreamPlugin
import com.lagradost.cloudstream3.plugins.Plugin
import android.content.Context
@CloudstreamPlugin
class GomovPlugin: Plugin() {
override fun load(context: Context) {
// All providers should be added in this manner. Please don't edit the providers list directly.
registerMainAPI(Gomov())
registerMainAPI(DutaMovie())
registerMainAPI(Ngefilm())
registerMainAPI(Nodrakorid())
registerMainAPI(Multiplex())
registerMainAPI(Pusatfilm())
registerExtractorAPI(FilelionsTo())
registerExtractorAPI(Likessb())
registerExtractorAPI(DbGdriveplayer())
registerExtractorAPI(Dutamovie21())
registerExtractorAPI(Embedwish())
registerExtractorAPI(Doods())
registerExtractorAPI(Lylxan())
registerExtractorAPI(FilelionsOn())
registerExtractorAPI(Kotakajaib())
registerExtractorAPI(Uplayer())
}
}

View File

@ -1,14 +0,0 @@
package com.hexated
import com.lagradost.cloudstream3.mainPageOf
class Multiplex : Gomov() {
override var mainUrl = "http://5.189.181.147"
override var name = "Multiplex"
override val mainPage = mainPageOf(
"country/usa/page/%d/" to "Movie",
"west-series/page/%d/" to "West Series",
"nonton-drama-korea/page/%d/" to "Drama Korea",
)
}

View File

@ -1,15 +0,0 @@
package com.hexated
import com.lagradost.cloudstream3.mainPageOf
class Ngefilm : Gomov() {
override var mainUrl = "https://tv.ngefilm21.homes"
override var name = "Ngefilm"
override val mainPage = mainPageOf(
"/page/%d/?s&search=advanced&post_type=movie&index&orderby&genre&movieyear&country&quality=" to "Movies Terbaru",
"/page/%d/?s=&search=advanced&post_type=tv&index=&orderby=&genre=&movieyear=&country=&quality=" to "Series Terbaru",
"/page/%d/?s=&search=advanced&post_type=tv&index=&orderby=&genre=drakor&movieyear=&country=&quality=" to "Series Korea",
"/page/%d/?s=&search=advanced&post_type=tv&index=&orderby=&genre=&movieyear=&country=indonesia&quality=" to "Series Indonesia",
)
}

View File

@ -1,154 +0,0 @@
package com.hexated
import com.fasterxml.jackson.annotation.JsonProperty
import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.utils.*
import com.lagradost.cloudstream3.utils.AppUtils.toJson
import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
import org.jsoup.nodes.Element
import java.net.URI
class Nodrakorid : Gomov() {
override var mainUrl = "https://no-dra-kor-id.shop"
override var name = "Nodrakorid"
override val mainPage = mainPageOf(
"genre/movie/page/%d/" to "Film Terbaru",
"genre/korean-movie/page/%d/" to "Film Korea",
"genre/drama/page/%d/" to "Drama Korea",
"genre/c-drama/c-drama-c-drama/page/%d/" to "Drama China",
"genre/thai-drama/page/%d/" to "Drama Thailand",
)
override suspend fun load(url: String): LoadResponse {
return super.load(url).apply {
when (this) {
is TvSeriesLoadResponse -> {
val doc = app.get(url).document
this.comingSoon = false
this.episodes = when {
doc.select("div.vid-episodes a, div.gmr-listseries a").isNotEmpty() -> this.episodes
doc.select("div#download").isEmpty() -> {
doc.select("div.entry-content p:contains(Episode)").distinctBy {
it.text()
}.mapNotNull { eps ->
val endSibling = eps.nextElementSiblings().select("p:contains(Episode)").firstOrNull() ?: eps.nextElementSiblings().select("div.content-moviedata").firstOrNull()
val siblings = eps.nextElementSiblingsUntil(endSibling).map { ele ->
ele.ownText().filter { it.isDigit() }.toIntOrNull() to ele.select("a")
.map { it.attr("href") to it.text() }
}.filter { it.first != null }
Episode(siblings.toJson(), episode = eps.text().toEpisode())
}
}
else -> {
doc.select("div#download h3.title-download").mapNotNull { eps ->
val siblings = eps.nextElementSibling()?.select("li")?.map { ele ->
ele.text().filter { it.isDigit() }.toIntOrNull() to ele.select("a").map {
it.attr("href") to it.text().split(" ").first()
}
}?.filter { it.first != null }
Episode(siblings?.toJson() ?: return@mapNotNull null, episode = eps.text().toEpisode())
}
}
}
}
}
}
}
override suspend fun loadLinks(
data: String,
isCasting: Boolean,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
): Boolean {
return if (data.startsWith("[")) {
tryParseJson<ArrayList<LinkData>>(data)?.filter { it.first != 360 }?.map {
it.second.apmap { link ->
loadFixedExtractor(
fixEmbed(link.first, link.second),
it.first,
"$mainUrl/",
subtitleCallback,
callback
)
}
}
true
} else {
super.loadLinks(data, isCasting, subtitleCallback, callback)
}
}
private fun fixEmbed(url: String, server: String): String {
return when {
server.contains("streamsb", true) -> {
val host = getBaseUrl(url)
url.replace("$host/", "$host/e/")
}
server.contains("hxfile", true) -> {
val host = getBaseUrl(url)
val id = url.substringAfterLast("/")
"$host/embed-$id.html"
}
else -> url
}
}
private fun String.toEpisode() : Int? {
return Regex("(?i)Episode\\s?([0-9]+)").find(this)?.groupValues?.getOrNull(1)?.toIntOrNull()
}
private fun getBaseUrl(url: String): String {
return URI(url).let {
"${it.scheme}://${it.host}"
}
}
private suspend fun loadFixedExtractor(
url: String,
quality: Int?,
referer: String? = null,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
) {
loadExtractor(url, referer, subtitleCallback) { link ->
callback.invoke(
ExtractorLink(
link.name,
link.name,
link.url,
link.referer,
if(link.type == ExtractorLinkType.M3U8) link.quality else quality ?: Qualities.Unknown.value,
link.type,
link.headers,
link.extractorData
)
)
}
}
private fun Element.nextElementSiblingsUntil(untilElement: Element?): List<Element> {
val siblings = mutableListOf<Element>()
var currentElement = this.nextElementSibling()
while (currentElement != null && currentElement != untilElement) {
siblings.add(currentElement)
currentElement = currentElement.nextElementSibling()
}
return siblings
}
data class LinkData(
@JsonProperty("first") var first: Int? = null,
@JsonProperty("second") var second: ArrayList<Second> = arrayListOf()
)
data class Second(
@JsonProperty("first") var first: String,
@JsonProperty("second") var second: String
)
}

View File

@ -1,40 +0,0 @@
package com.hexated
import com.lagradost.cloudstream3.Episode
import com.lagradost.cloudstream3.LoadResponse
import com.lagradost.cloudstream3.TvSeriesLoadResponse
import com.lagradost.cloudstream3.*
class Pusatfilm : Gomov() {
override var mainUrl = "https://tv2.pusatfilm21.art"
override var name = "Pusatfilm"
override val mainPage = mainPageOf(
"film-terbaru/page/%d/" to "Film Terbaru",
"series-terbaru/page/%d/" to "Series Terbaru",
"drama-korea/page/%d/" to "Drama Korea",
"drama-china/page/%d/" to "Drama China",
)
override suspend fun load(url: String): LoadResponse {
return super.load(url).apply {
when (this) {
is TvSeriesLoadResponse -> {
val document = app.get(url).document
this.episodes = document.select("div.vid-episodes a, div.gmr-listseries a").map { eps ->
val href = fixUrl(eps.attr("href"))
val name = eps.attr("title")
val episode = "Episode\\s*(\\d+)".toRegex().find(name)?.groupValues?.get(1)
val season = "Season\\s*(\\d+)".toRegex().find(name)?.groupValues?.get(1)
Episode(
href,
name,
season = season?.toIntOrNull(),
episode = episode?.toIntOrNull(),
)
}.filter { it.episode != null }
}
}
}
}
}

View File

@ -1,27 +0,0 @@
// use an integer for version numbers
version = 2
cloudstream {
language = "id"
// All of these properties are optional, you can safely remove them
// description = "Lorem Ipsum"
authors = listOf("Hexated")
/**
* Status int as the following:
* 0: Down
* 1: Ok
* 2: Slow
* 3: Beta only
* */
status = 0 // will be 3 if unspecified
tvTypes = listOf(
"AnimeMovie",
"Anime",
"OVA",
)
iconUrl = "https://www.google.com/s2/favicons?domain=185.231.223.76&sz=%size%"
}

View File

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

View File

@ -1,238 +0,0 @@
package com.hexated
import com.fasterxml.jackson.annotation.JsonProperty
import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer
import com.lagradost.cloudstream3.mvvm.safeApiCall
import com.lagradost.cloudstream3.utils.AppUtils.parseJson
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.M3u8Helper
import com.lagradost.cloudstream3.utils.Qualities
import com.lagradost.cloudstream3.utils.loadExtractor
import org.jsoup.Jsoup
class GomunimeProvider : MainAPI() {
override var mainUrl = "https://185.231.223.76"
override var name = "Gomunime"
override val hasMainPage = true
override var lang = "id"
override val hasDownloadSupport = true
override val supportedTypes = setOf(
TvType.Anime,
TvType.AnimeMovie,
TvType.OVA
)
companion object {
private const val mainServer = "https://path.onicdn.xyz/app/rapi.php"
fun getType(t: String): TvType {
return if (t.contains("OVA") || t.contains("Special")) TvType.OVA
else if (t.contains("Movie")) TvType.AnimeMovie
else TvType.Anime
}
fun getStatus(t: String): ShowStatus {
return when (t) {
"Completed" -> ShowStatus.Completed
"Ongoing" -> ShowStatus.Ongoing
else -> ShowStatus.Completed
}
}
}
override val mainPage = mainPageOf(
"e" to "Episode Baru",
"c" to "Completed",
"la" to "Live Action",
"t" to "Trending"
)
override suspend fun getMainPage(
page: Int,
request: MainPageRequest
): HomePageResponse {
val home = Jsoup.parse(
(app.post(
url = "$mainUrl/wp-admin/admin-ajax.php/wp-admin/admin-ajax.php",
headers = mapOf("Referer" to mainUrl),
data = mapOf(
"action" to "home_ajax",
"fungsi" to request.data,
"pag" to "$page"
)
).parsedSafe<Response>()?.html ?: throw ErrorLoadingException("Invalid Json reponse"))
).select("li").mapNotNull {
val title = it.selectFirst("a.name")?.text()?.trim() ?: return@mapNotNull null
val href = getProperAnimeLink(it.selectFirst("a")!!.attr("href"))
val posterUrl = it.selectFirst("img")?.attr("src")
val type = getType(it.selectFirst(".taglist > span")!!.text().trim())
val epNum = it.select(".tag.ep").text().replace(Regex("[^0-9]"), "").trim()
.toIntOrNull()
newAnimeSearchResponse(title, href, type) {
this.posterUrl = posterUrl
addSub(epNum)
}
}
return newHomePageResponse(request.name, home)
}
private fun getProperAnimeLink(uri: String): String {
return if (uri.contains("-episode")) {
val href =
"$mainUrl/anime/" + Regex("\\w\\d/(.*)-episode.*").find(uri)?.groupValues?.get(1)
.toString()
when {
href.contains("pokemon") -> href.replace(Regex("-[0-9]+"), "")
else -> href
}
} else {
uri
}
}
override suspend fun search(query: String): List<SearchResponse> {
val link = "$mainUrl/?s=$query"
val document = app.get(link).document
return document.select(".anime-list > li").map {
val title = it.selectFirst("a.name")!!.text()
val poster = it.selectFirst("img")!!.attr("src")
val tvType = getType(it.selectFirst(".taglist > span")?.text().toString())
val href = fixUrl(it.selectFirst("a.name")!!.attr("href"))
newAnimeSearchResponse(title, href, tvType) {
this.posterUrl = poster
addDubStatus(dubExist = false, subExist = true)
}
}
}
override suspend fun load(url: String): LoadResponse {
val document = app.get(url).document
val title = document.selectFirst(".entry-title")?.text().toString()
val poster = document.selectFirst(".thumbposter > img")?.attr("data-lazy-src")
val tags = document.select(".genxed > a").map { it.text() }
val year = Regex("\\d, ([0-9]*)").find(
document.select("time[itemprop = datePublished]").text()
)?.groupValues?.get(1)?.toIntOrNull()
val status = getStatus(document.selectFirst(".spe > span")!!.ownText())
val description = document.select("div[itemprop = description] > p").text()
val trailer = document.selectFirst("div.embed-responsive noscript iframe")?.attr("src")
val episodes = parseJson<List<EpisodeElement>>(
Regex("var episodelist = (\\[.*])").find(
document.select(".bixbox.bxcl.epcheck > script").toString().trim()
)?.groupValues?.get(1).toString().replace(Regex("""\\"""), "").trim()
).map {
val name =
Regex("(Episode\\s?[0-9]+)").find(it.epTitle.toString())?.groupValues?.getOrNull(0)
?: it.epTitle
val link = it.epLink
Episode(link, name)
}.reversed()
return newAnimeLoadResponse(title, url, TvType.Anime) {
engName = title
posterUrl = poster
this.year = year
addEpisodes(DubStatus.Subbed, episodes)
showStatus = status
plot = description
this.tags = tags
addTrailer(trailer)
}
}
override suspend fun loadLinks(
data: String,
isCasting: Boolean,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
): Boolean {
val document = app.get(data).document
val scriptData = document.select("aside.sidebar > script").dataNodes().toString()
val key = scriptData.substringAfter("var a_ray = '").substringBefore("';")
val title = scriptData.substringAfter("var judul_postingan = \"").substringBefore("\";")
.replace(" ", "+")
val image = document.select("img#tempvid").last()?.attr("src").toString()
val sources: List<Pair<String, String>> = app.post(
url = mainServer,
data = mapOf("data" to key, "gambar" to image, "judul" to title, "func" to "mirror"),
referer = "$mainUrl/"
).document.select("div.gomunime-server-mirror").map {
Pair(
it.attr("data-vhash"),
it.attr("data-type")
)
}
sources.apmap {
safeApiCall {
when {
it.second.contains("frame") -> {
loadExtractor(it.first, mainUrl, subtitleCallback, callback)
}
// Skip for now
// it.second.contains("hls") -> {
// app.post(
// url = mainServer,
// data = mapOf("fid" to it.first, "func" to "hls")
// ).text.let { link ->
// M3u8Helper.generateM3u8(
// this.name,
// link,
// "$mainUrl/",
// headers = mapOf("Origin" to mainUrl)
// ).forEach(callback)
// }
// }
it.second.contains("mp4") -> {
app.post(
url = mainServer,
data = mapOf("data" to it.first, "func" to "blogs")
).parsed<List<MobiSource>>().map {
callback.invoke(
ExtractorLink(
source = name,
name = "Mobi SD",
url = it.file,
referer = "$mainUrl/",
quality = Qualities.P360.value
)
)
}
}
else -> null
}
}
}
return true
}
private data class Response(
@JsonProperty("status") val status: Boolean,
@JsonProperty("html") val html: String
)
data class MobiSource(
@JsonProperty("file") val file: String,
@JsonProperty("label") val label: String,
@JsonProperty("type") val type: String
)
private data class EpisodeElement(
@JsonProperty("data-index") val dataIndex: Long?,
@JsonProperty("ep-num") val epNum: String?,
@JsonProperty("ep-title") val epTitle: String?,
@JsonProperty("ep-link") val epLink: String,
@JsonProperty("ep-date") val epDate: String?
)
}

View File

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

View File

@ -1,27 +0,0 @@
// use an integer for version numbers
version = 6
cloudstream {
language = "id"
// All of these properties are optional, you can safely remove them
// description = "Lorem Ipsum"
authors = listOf("Hexated")
/**
* Status int as the following:
* 0: Down
* 1: Ok
* 2: Slow
* 3: Beta only
* */
status = 1 // will be 3 if unspecified
tvTypes = listOf(
"AnimeMovie",
"Anime",
"OVA",
)
iconUrl = "https://www.google.com/s2/favicons?domain=gomunime.is&sz=%size%"
}

View File

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

View File

@ -1,163 +0,0 @@
package com.hexated
import com.fasterxml.jackson.annotation.JsonProperty
import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.utils.*
import java.util.ArrayList
class Gomunimeis : MainAPI() {
override var mainUrl = "https://anoboy.life"
override var name = "Gomunime.is"
override val hasMainPage = true
override var lang = "id"
override val hasQuickSearch = true
override val hasDownloadSupport = true
override val supportedTypes = setOf(
TvType.Anime,
TvType.AnimeMovie,
TvType.OVA
)
companion object {
private const val mainImageUrl = "https://upload.anoboy.life"
fun getType(t: String): TvType {
return if (t.contains("OVA", true) || t.contains("Special", true)) TvType.OVA
else if (t.contains("Movie", true)) TvType.AnimeMovie
else TvType.Anime
}
fun getStatus(t: String): ShowStatus {
return when (t) {
"Completed" -> ShowStatus.Completed
"Ongoing" -> ShowStatus.Ongoing
else -> ShowStatus.Completed
}
}
}
override val mainPage = mainPageOf(
"&limit=12&action=load_movie_last_update&status=Ongoing" to "Episode Baru",
"&limit=15&action=load_movie_last_update&status=Completed" to "Completed",
"&limit=15&action=load_movie_last_update&type=Live Action" to "Live Action",
"&limit=15&action=load_movie_trending" to "Trending"
)
override suspend fun getMainPage(
page: Int,
request: MainPageRequest
): HomePageResponse {
val home = app.get(
"$mainUrl/my-ajax?page=$page${request.data}",
headers = mapOf("X-Requested-With" to "XMLHttpRequest")
)
.parsedSafe<Responses>()?.data
?.mapNotNull { media ->
media.toSearchResponse()
} ?: throw ErrorLoadingException("Invalid Json reponse")
return newHomePageResponse(request.name, home)
}
private fun Anime.toSearchResponse(): SearchResponse? {
return newAnimeSearchResponse(
postTitle ?: return null,
"$mainUrl/anime/$postName",
TvType.TvSeries,
) {
this.posterUrl = "$mainImageUrl/$image"
addSub(totalEpisode?.toIntOrNull())
}
}
override suspend fun quickSearch(query: String): List<SearchResponse> = search(query)
override suspend fun search(query: String): List<SearchResponse> {
return app.get(
"$mainUrl/my-ajax?page=1&limit=10&action=load_search_movie&keyword=$query",
referer = "$mainUrl/search/?keyword=$query",
headers = mapOf("X-Requested-With" to "XMLHttpRequest")
).parsedSafe<Responses>()?.data
?.mapNotNull { media ->
media.toSearchResponse()
} ?: throw ErrorLoadingException("Invalid Json reponse")
}
override suspend fun load(url: String): LoadResponse {
val document = app.get(url).document
val title = document.selectFirst(".entry-title")?.text().toString()
val poster = document.selectFirst(".thumbposter > img")?.attr("src")
val tags = document.select(".genxed > a").map { it.text() }
val type = document.selectFirst("div.info-content .spe span:last-child")?.ownText()?.lowercase() ?: "tv"
val year = Regex("\\d, (\\d*)").find(
document.selectFirst("div.info-content .spe span.split")?.ownText().toString()
)?.groupValues?.get(1)?.toIntOrNull()
val status = getStatus(document.selectFirst(".spe > span")!!.ownText())
val description = document.select("div[itemprop = description] > p").text()
val episodes = document.select(".eplister > ul > li").map {
val episode = Regex("Episode\\s?(\\d+)").find(
it.select(".epl-title").text()
)?.groupValues?.getOrNull(0)
val link = it.select("a").attr("href")
Episode(link, episode = episode?.toIntOrNull())
}.reversed()
return newAnimeLoadResponse(title, url, getType(type)) {
engName = title
posterUrl = poster
this.year = year
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 document = app.get(data).document
document.select("div.player-container iframe").attr("src").substringAfter("html#")
.let { id ->
app.get("https://gomunimes.com/stream?id=$id")
.parsedSafe<Sources>()?.server?.streamsb?.link?.let { link ->
loadExtractor(link.replace("vidgomunimesb.xyz", "watchsb.com"), mainUrl, subtitleCallback, callback)
}
}
return true
}
data class Streamsb(
@JsonProperty("link") val link: String?,
)
data class Server(
@JsonProperty("streamsb") val streamsb: Streamsb?,
)
data class Sources(
@JsonProperty("server") val server: Server?,
)
data class Responses(
@JsonProperty("data") val data: ArrayList<Anime>? = arrayListOf(),
)
data class Anime(
@JsonProperty("post_title") val postTitle: String?,
@JsonProperty("post_name") val postName: String?,
@JsonProperty("image") val image: String?,
@JsonProperty("total_episode") val totalEpisode: String?,
@JsonProperty("salt") val salt: String?,
)
}

View File

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

View File

@ -1,25 +0,0 @@
// use an integer for version numbers
version = 7
cloudstream {
language = "en"
// All of these properties are optional, you can safely remove them
description = "Premium porn with 4K support (use VPN if links not working)"
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=goodporn.to&sz=%size%"
}

View File

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

View File

@ -1,126 +0,0 @@
package com.hexated
import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.LoadResponse.Companion.addActors
import com.lagradost.cloudstream3.utils.*
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/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
document.select("div.info div:last-child a").map { res ->
callback.invoke(
ExtractorLink(
this.name,
this.name,
res.attr("href")
.replace(Regex("\\?download\\S+.mp4&"), "?") + "&rnd=${Date().time}",
referer = data,
quality = Regex("([0-9]+p),").find(res.text())?.groupValues?.get(1)
.let { getQualityFromName(it) },
headers = mapOf("Range" to "bytes=0-"),
)
)
}
return true
}
}

View File

@ -1,13 +0,0 @@
package com.hexated
import com.lagradost.cloudstream3.plugins.CloudstreamPlugin
import com.lagradost.cloudstream3.plugins.Plugin
import android.content.Context
@CloudstreamPlugin
class GoodPornPlugin: 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,28 +0,0 @@
// use an integer for version numbers
version = 3
cloudstream {
language = "ru"
// All of these properties are optional, you can safely remove them
// description = "Lorem Ipsum"
authors = listOf("Hexated")
/**
* Status int as the following:
* 0: Down
* 1: Ok
* 2: Slow
* 3: Beta only
* */
status = 1 // will be 3 if unspecified
tvTypes = listOf(
"AsianDrama",
"Anime",
"TvSeries",
"Movie",
)
iconUrl = "https://www.google.com/s2/favicons?domain=hdrezka19139.org&sz=%size%"
}

View File

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

View File

@ -1,395 +0,0 @@
package com.hexated
import com.fasterxml.jackson.annotation.JsonProperty
import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.LoadResponse.Companion.addActors
import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer
import com.lagradost.cloudstream3.utils.AppUtils.toJson
import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.Qualities
import com.lagradost.cloudstream3.utils.getQualityFromName
import org.jsoup.Jsoup
import org.jsoup.nodes.Element
import java.util.*
class HDrezkaProvider : MainAPI() {
override var mainUrl = "https://rezka.ag"
override var name = "HDrezka"
override val hasMainPage = true
override var lang = "ru"
override val hasDownloadSupport = true
override val supportedTypes = setOf(
TvType.Movie,
TvType.TvSeries,
TvType.Anime,
TvType.AsianDrama
)
override val mainPage = mainPageOf(
"$mainUrl/films/?filter=watching" to "фильмы",
"$mainUrl/series/?filter=watching" to "сериалы",
"$mainUrl/cartoons/?filter=watching" to "мультфильмы",
"$mainUrl/animation/?filter=watching" to "аниме",
)
override suspend fun getMainPage(
page: Int,
request: MainPageRequest
): HomePageResponse {
val url = request.data.split("?")
val home = app.get("${url.first()}page/$page/?${url.last()}").document.select(
"div.b-content__inline_items div.b-content__inline_item"
).map {
it.toSearchResult()
}
return newHomePageResponse(request.name, home)
}
private fun Element.toSearchResult(): SearchResponse {
val title =
this.selectFirst("div.b-content__inline_item-link > a")?.text()?.trim().toString()
val href = this.selectFirst("a")?.attr("href").toString()
val posterUrl = this.select("img").attr("src")
val type = if (this.select("span.info").isNotEmpty()) TvType.TvSeries else TvType.Movie
return if (type == TvType.Movie) {
newMovieSearchResponse(title, href, TvType.Movie) {
this.posterUrl = posterUrl
}
} else {
val episode =
this.select("span.info").text().substringAfter(",").replace(Regex("[^0-9]"), "")
.toIntOrNull()
newAnimeSearchResponse(title, href, TvType.TvSeries) {
this.posterUrl = posterUrl
addDubStatus(
dubExist = true,
dubEpisodes = episode,
subExist = true,
subEpisodes = episode
)
}
}
}
override suspend fun search(query: String): List<SearchResponse> {
val link = "$mainUrl/search/?do=search&subaction=search&q=$query"
val document = app.get(link).document
return document.select("div.b-content__inline_items div.b-content__inline_item").map {
it.toSearchResult()
}
}
override suspend fun load(url: String): LoadResponse {
val document = app.get(url).document
val id = url.split("/").last().split("-").first()
val title = (document.selectFirst("div.b-post__origtitle")?.text()?.trim()
?: document.selectFirst("div.b-post__title h1")?.text()?.trim()).toString()
val poster = fixUrlNull(document.selectFirst("div.b-sidecover img")?.attr("src"))
val tags =
document.select("table.b-post__info > tbody > tr:contains(Жанр) span[itemprop=genre]")
.map { it.text() }
val year = document.select("div.film-info > div:nth-child(2) a").text().toIntOrNull()
val tvType = if (document.select("div#simple-episodes-tabs")
.isNullOrEmpty()
) TvType.Movie else TvType.TvSeries
val description = document.selectFirst("div.b-post__description_text")?.text()?.trim()
val trailer = app.post(
"$mainUrl/engine/ajax/gettrailervideo.php",
data = mapOf("id" to id),
referer = url
).parsedSafe<Trailer>()?.code.let {
Jsoup.parse(it.toString()).select("iframe").attr("src")
}
val rating =
document.selectFirst("table.b-post__info > tbody > tr:nth-child(1) span.bold")?.text()
.toRatingInt()
val actors =
document.select("table.b-post__info > tbody > tr:last-child span.item").mapNotNull {
Actor(
it.selectFirst("span[itemprop=name]")?.text() ?: return@mapNotNull null,
it.selectFirst("span[itemprop=actor]")?.attr("data-photo")
)
}
val recommendations = document.select("div.b-sidelist div.b-content__inline_item").map {
it.toSearchResult()
}
val data = HashMap<String, Any>()
val server = ArrayList<Map<String, String>>()
data["id"] = id
data["favs"] = document.selectFirst("input#ctrl_favs")?.attr("value").toString()
data["ref"] = url
return if (tvType == TvType.TvSeries) {
document.select("ul#translators-list li").map { res ->
server.add(
mapOf(
"translator_name" to res.text(),
"translator_id" to res.attr("data-translator_id"),
)
)
}
val episodes = document.select("div#simple-episodes-tabs ul li").map {
val season = it.attr("data-season_id").toIntOrNull()
val episode = it.attr("data-episode_id").toIntOrNull()
val name = "Episode $episode"
data["season"] = "$season"
data["episode"] = "$episode"
data["server"] = server
data["action"] = "get_stream"
Episode(
data.toJson(),
name,
season,
episode,
)
}
newTvSeriesLoadResponse(title, url, TvType.TvSeries, episodes) {
this.posterUrl = poster
this.year = year
this.plot = description
this.tags = tags
this.rating = rating
addActors(actors)
this.recommendations = recommendations
addTrailer(trailer)
}
} else {
document.select("ul#translators-list li").map { res ->
server.add(
mapOf(
"translator_name" to res.text(),
"translator_id" to res.attr("data-translator_id"),
"camrip" to res.attr("data-camrip"),
"ads" to res.attr("data-ads"),
"director" to res.attr("data-director")
)
)
}
data["server"] = server
data["action"] = "get_movie"
newMovieLoadResponse(title, url, TvType.Movie, data.toJson()) {
this.posterUrl = poster
this.year = year
this.plot = description
this.tags = tags
this.rating = rating
addActors(actors)
this.recommendations = recommendations
addTrailer(trailer)
}
}
}
private fun decryptStreamUrl(data: String): String {
fun getTrash(arr: List<String>, item: Int): List<String> {
val trash = ArrayList<List<String>>()
for (i in 1..item) {
trash.add(arr)
}
return trash.reduce { acc, list ->
val temp = ArrayList<String>()
acc.forEach { ac ->
list.forEach { li ->
temp.add(ac.plus(li))
}
}
return@reduce temp
}
}
val trashList = listOf("@", "#", "!", "^", "$")
val trashSet = getTrash(trashList, 2) + getTrash(trashList, 3)
var trashString = data.replace("#h", "").split("//_//").joinToString("")
trashSet.forEach {
val temp = base64Encode(it.toByteArray())
trashString = trashString.replace(temp, "")
}
return base64Decode(trashString)
}
private fun cleanCallback(
source: String,
url: String,
quality: String,
isM3u8: Boolean,
sourceCallback: (ExtractorLink) -> Unit
) {
sourceCallback.invoke(
ExtractorLink(
source,
source,
url,
"$mainUrl/",
getQuality(quality),
isM3u8,
headers = mapOf(
"Origin" to mainUrl
)
)
)
}
private fun getLanguage(str: String): String {
return when (str) {
"Русский" -> "Russian"
"Українська" -> "Ukrainian"
else -> str
}
}
private fun getQuality(str: String): Int {
return when (str) {
"360p" -> Qualities.P240.value
"480p" -> Qualities.P360.value
"720p" -> Qualities.P480.value
"1080p" -> Qualities.P720.value
"1080p Ultra" -> Qualities.P1080.value
else -> getQualityFromName(str)
}
}
private fun invokeSources(
source: String,
url: String,
subtitle: String,
subCallback: (SubtitleFile) -> Unit,
sourceCallback: (ExtractorLink) -> Unit
) {
decryptStreamUrl(url).split(",").map { links ->
val quality =
Regex("\\[([0-9]{3,4}p\\s?\\w*?)]").find(links)?.groupValues?.getOrNull(1)
?.trim() ?: return@map null
links.replace("[$quality]", "").split(" or ")
.map {
val link = it.trim()
val type = if(link.contains(".m3u8")) "(Main)" else "(Backup)"
cleanCallback(
"$source $type",
link,
quality,
link.contains(".m3u8"),
sourceCallback,
)
}
}
subtitle.split(",").map { sub ->
val language =
Regex("\\[(.*)]").find(sub)?.groupValues?.getOrNull(1) ?: return@map null
val link = sub.replace("[$language]", "").trim()
subCallback.invoke(
SubtitleFile(
getLanguage(language),
link
)
)
}
}
override suspend fun loadLinks(
data: String,
isCasting: Boolean,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
): Boolean {
tryParseJson<Data>(data)?.let { res ->
if (res.server?.isEmpty() == true) {
val document = app.get(res.ref ?: return@let).document
document.select("script").map { script ->
if (script.data().contains("sof.tv.initCDNMoviesEvents(")) {
val dataJson =
script.data().substringAfter("false, {").substringBefore("});")
tryParseJson<LocalSources>("{$dataJson}")?.let { source ->
invokeSources(
this.name,
source.streams,
source.subtitle.toString(),
subtitleCallback,
callback
)
}
}
}
} else {
res.server?.apmap { server ->
app.post(
url = "$mainUrl/ajax/get_cdn_series/?t=${Date().time}",
data = mapOf(
"id" to res.id,
"translator_id" to server.translator_id,
"favs" to res.favs,
"is_camrip" to server.camrip,
"is_ads" to server.ads,
"is_director" to server.director,
"season" to res.season,
"episode" to res.episode,
"action" to res.action,
).filterValues { it != null }.mapValues { it.value as String },
referer = res.ref
).parsedSafe<Sources>()?.let { source ->
invokeSources(
server.translator_name.toString(),
source.url,
source.subtitle.toString(),
subtitleCallback,
callback
)
}
}
}
}
return true
}
data class LocalSources(
@JsonProperty("streams") val streams: String,
@JsonProperty("subtitle") val subtitle: Any?,
)
data class Sources(
@JsonProperty("url") val url: String,
@JsonProperty("subtitle") val subtitle: Any?,
)
data class Server(
@JsonProperty("translator_name") val translator_name: String?,
@JsonProperty("translator_id") val translator_id: String?,
@JsonProperty("camrip") val camrip: String?,
@JsonProperty("ads") val ads: String?,
@JsonProperty("director") val director: String?,
)
data class Data(
@JsonProperty("id") val id: String?,
@JsonProperty("favs") val favs: String?,
@JsonProperty("server") val server: List<Server>?,
@JsonProperty("season") val season: String?,
@JsonProperty("episode") val episode: String?,
@JsonProperty("action") val action: String?,
@JsonProperty("ref") val ref: String?,
)
data class Trailer(
@JsonProperty("success") val success: Boolean?,
@JsonProperty("code") val code: String?,
)
}

View File

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

Some files were not shown because too many files have changed in this diff Show More