Merge Hexated

This commit is contained in:
KingLucius 2023-09-12 17:12:47 +03:00
commit 4566f065d1
119 changed files with 11999 additions and 2039 deletions

View file

@ -54,6 +54,7 @@ jobs:
ANICHI_SERVER: ${{ secrets.ANICHI_SERVER }} ANICHI_SERVER: ${{ secrets.ANICHI_SERVER }}
ANICHI_ENDPOINT: ${{ secrets.ANICHI_ENDPOINT }} ANICHI_ENDPOINT: ${{ secrets.ANICHI_ENDPOINT }}
ANICHI_APP: ${{ secrets.ANICHI_APP }} ANICHI_APP: ${{ secrets.ANICHI_APP }}
PRIMEWIRE_KEY: ${{ secrets.PRIMEWIRE_KEY }}
run: | run: |
cd $GITHUB_WORKSPACE/src cd $GITHUB_WORKSPACE/src
echo SORA_API=$SORA_API >> local.properties echo SORA_API=$SORA_API >> local.properties
@ -68,6 +69,7 @@ jobs:
echo ANICHI_SERVER=$ANICHI_SERVER >> local.properties echo ANICHI_SERVER=$ANICHI_SERVER >> local.properties
echo ANICHI_ENDPOINT=$ANICHI_ENDPOINT >> local.properties echo ANICHI_ENDPOINT=$ANICHI_ENDPOINT >> local.properties
echo ANICHI_APP=$ANICHI_APP >> local.properties echo ANICHI_APP=$ANICHI_APP >> local.properties
echo PRIMEWIRE_KEY=$PRIMEWIRE_KEY >> local.properties
- name: Build Plugins - name: Build Plugins
run: | run: |

42
Anichi/build.gradle.kts Normal file
View file

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

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

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

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

@ -0,0 +1,147 @@
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")
}
}

27
Animasu/build.gradle.kts Normal file
View file

@ -0,0 +1,27 @@
// use an integer for version numbers
version = 3
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

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

View file

@ -0,0 +1,174 @@
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.uno"
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")?.attr("src"))
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")?.attr("src")?.replace("\n", "")
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, 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) getIndexQuality(quality) else link.quality,
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

@ -0,0 +1,18 @@
package com.elostoratv
import com.lagradost.cloudstream3.plugins.CloudstreamPlugin
import com.lagradost.cloudstream3.plugins.Plugin
import android.content.Context
@CloudstreamPlugin
<<<<<<<< HEAD:ElOstora/src/main/kotlin/com/elostoratv/ElOstoraTVPlugin.kt
class ElOstoraTVPlugin: Plugin() {
override fun load(context: Context) {
registerMainAPI(ElOstoraTV())
========
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())
>>>>>>>> bf89248a7d2a64a6e7dfa4049ac908b967e111a0:Animasu/src/main/kotlin/com/hexated/AnimasuPlugin.kt
}
}

View file

@ -0,0 +1,27 @@
// use an integer for version numbers
version = 14
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

@ -0,0 +1,179 @@
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 url = "$mainUrl/${request.data}/page/$page"
val document = app.get(url).document
val home = document.select("main#main div.animposx").mapNotNull {
it.toSearchResult()
}
return newHomePageResponse(request.name, home)
}
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 link = "$mainUrl/page/$page/?s=$query"
val document = app.get(link).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

@ -0,0 +1,27 @@
// 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

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

27
Aniworld/build.gradle.kts Normal file
View file

@ -0,0 +1,27 @@
// 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

@ -0,0 +1,232 @@
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.M3u8Helper
import com.lagradost.cloudstream3.utils.loadExtractor
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import java.net.URI
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
)
companion object {
fun getType(t: String): TvType {
return when {
t.contains("Anime Ova") -> TvType.OVA
t.contains("Anime Movie") -> TvType.AnimeMovie
else -> TvType.Anime
}
}
fun getStatus(t: String): ShowStatus {
return when {
t.contains("/complete", true) -> ShowStatus.Completed
t.contains("/running", true) -> ShowStatus.Ongoing
else -> ShowStatus.Completed
}
}
}
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)
if (it.third == "VOE") {
invokeVoe(redirectUrl, lang, data, callback)
} else {
loadExtractor(redirectUrl, data, subtitleCallback) { link ->
val name = "${link.name} [${lang}]"
callback.invoke(
ExtractorLink(
name,
name,
link.url,
link.referer,
link.quality,
link.type,
link.headers,
link.extractorData
)
)
}
}
}
return true
}
private suspend fun invokeVoe(
url: String,
lang: String?,
referer: String,
callback: (ExtractorLink) -> Unit,
) {
val name = "Voe [${lang}]"
val request = app.get(url, referer = referer)
val baseUrl = getBaseUrl(request.url)
val res = request.document
val script = res.select("script").find { it.data().contains("sources =") }?.data()
val link =
Regex("[\"']hls[\"']:\\s*[\"'](.*)[\"']").find(script ?: return)?.groupValues?.get(1)
M3u8Helper.generateM3u8(
name,
link ?: return,
"$baseUrl/",
headers = mapOf("Origin" to "$baseUrl/")
).forEach(callback)
}
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 fun getBaseUrl(url: String): String {
return URI(url).let {
"${it.scheme}://${it.host}"
}
}
private data class AnimeSearch(
@JsonProperty("link") val link: String,
@JsonProperty("title") val title: String? = null,
)
}
class Dooood : DoodLaExtractor() {
override var mainUrl = "https://urochsunloath.com"
}
class Simpulumlamerop : Voe() {
override var mainUrl = "https://simpulumlamerop.com"
}
class Urochsunloath : Voe() {
override var mainUrl = "https://urochsunloath.com"
}

View file

@ -0,0 +1,18 @@
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(Urochsunloath())
registerExtractorAPI(Simpulumlamerop())
registerExtractorAPI(Dooood())
}
}

View file

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

@ -0,0 +1,130 @@
package com.hexated
import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.extractors.Filesim
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.loadExtractor
import org.jsoup.nodes.Element
class DramaSerial : MainAPI() {
override var mainUrl = "https://dramaserial.sbs"
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
}
}
}
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("div.gmr-server-wrap iframe").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 uLink = app.get(iLink, referer = iframe).document.select("script").find { it.data().contains("(document).ready") }?.data()?.substringAfter("replace(\"")?.substringBefore("\");") ?: return@apmap null
val link = app.get(uLink, referer = iLink).document.selectFirst("iframe")?.attr("src") ?: return@apmap null
loadExtractor(fixUrl(link), "https://juraganfilm.info/", subtitleCallback, callback)
}
}
return true
}
}
class Bk21 : Filesim() {
override val name = "Bk21"
override var mainUrl = "https://bk21.net"
}

View file

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

View file

@ -0,0 +1,26 @@
// use an integer for version numbers
version = 9
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

@ -0,0 +1,212 @@
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.best"
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)
val epNum = it.selectFirst(".epl-num")?.text()?.toIntOrNull()
Episode(
link,
name,
episode = epNum
)
}.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
}
}
class Vanfem : XStreamCdn() {
override val name: String = "Vanfem"
override val mainUrl: String = "https://vanfem.com"
}

View file

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

View file

@ -0,0 +1,13 @@
package com.hexated
import com.lagradost.cloudstream3.extractors.Filesim
class Oppadrama : DramaidProvider() {
override var mainUrl = "http://185.217.95.34"
override var name = "Oppadrama"
}
class Filelions : Filesim() {
override val name = "Filelions"
override var mainUrl = "https://filelions.live"
}

View file

@ -4,8 +4,15 @@ import com.lagradost.cloudstream3.plugins.Plugin
import android.content.Context import android.content.Context
@CloudstreamPlugin @CloudstreamPlugin
<<<<<<<< HEAD:ElOstora/src/main/kotlin/com/elostoratv/ElOstoraTVPlugin.kt
class ElOstoraTVPlugin: Plugin() { class ElOstoraTVPlugin: Plugin() {
override fun load(context: Context) { override fun load(context: Context) {
registerMainAPI(ElOstoraTV()) registerMainAPI(ElOstoraTV())
========
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())
>>>>>>>> bf89248a7d2a64a6e7dfa4049ac908b967e111a0:Animasu/src/main/kotlin/com/hexated/AnimasuPlugin.kt
} }
} }

View file

@ -0,0 +1,24 @@
// 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

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

View file

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

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

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

27
Gomov/build.gradle.kts Normal file
View file

@ -0,0 +1,27 @@
// use an integer for version numbers
version = 11
cloudstream {
language = "id"
// All of these properties are optional, you can safely remove them
description = "Includes: DutaMovie, Ngefilm, Nodrakorid, Multiplex"
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

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

View file

@ -0,0 +1,37 @@
package com.hexated
import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.httpsify
import com.lagradost.cloudstream3.utils.loadExtractor
open class DutaMovie : Gomov() {
override var mainUrl = "https://dutamovie21.live"
override var name = "DutaMovie"
override val mainPage = mainPageOf(
"category/box-office/page/%d/" to "Box Office",
"category/serial-tv/page/%d/" to "Serial TV",
"category/animation/page/%d/" to "Animasi",
"country/korea/page/%d/" to "Serial TV Korea",
"country/indonesia/page/%d/" to "Serial TV Indonesia",
)
override suspend fun loadLinks(
data: String,
isCasting: Boolean,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
): Boolean {
app.get(data).document.select("ul.muvipro-player-tabs li a").apmap {
val iframe = app.get(fixUrl(it.attr("href"))).document.selectFirst("div.gmr-embed-responsive iframe")
?.attr("src")
loadExtractor(httpsify(iframe ?: return@apmap ), "$mainUrl/", subtitleCallback, callback)
}
return true
}
}

View file

@ -0,0 +1,37 @@
package com.hexated
import com.lagradost.cloudstream3.extractors.*
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 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

@ -0,0 +1,182 @@
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")?.attr("src"))?.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")?.attr("src").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")?.attr("src"))?.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")
document.select("div.tab-content-ajax").apmap {
val server = app.post(
"$directUrl/wp-admin/admin-ajax.php",
data = mapOf("action" to "muvipro_player_content", "tab" to it.attr("id"), "post_id" to id)
).document.select("iframe").attr("src")
loadExtractor(httpsify(server), "$directUrl/", subtitleCallback, callback)
}
return true
}
private fun String?.fixImageQuality(): String? {
if(this == null) return null
val regex = Regex("(-\\d*x\\d*)").find(this)?.groupValues
if(regex?.isEmpty() == true) return this
return this.replace(regex?.get(0) ?: return null, "")
}
private fun getBaseUrl(url: String): String {
return URI(url).let {
"${it.scheme}://${it.host}"
}
}
}

View file

@ -0,0 +1,25 @@
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())
registerExtractorAPI(FilelionsTo())
registerExtractorAPI(Likessb())
registerExtractorAPI(DbGdriveplayer())
registerExtractorAPI(Dutamovie21())
registerExtractorAPI(Embedwish())
registerExtractorAPI(Doods())
registerExtractorAPI(Lylxan())
}
}

View file

@ -0,0 +1,15 @@
package com.hexated
import com.lagradost.cloudstream3.mainPageOf
class Multiplex : DutaMovie() {
override var mainUrl = "http://5.104.81.46"
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

@ -0,0 +1,22 @@
package com.hexated
import com.lagradost.cloudstream3.SubtitleFile
import com.lagradost.cloudstream3.apmap
import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.fixUrl
import com.lagradost.cloudstream3.mainPageOf
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.loadExtractor
class Ngefilm : DutaMovie() {
override var mainUrl = "https://ngefilm21.lat"
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

@ -0,0 +1,154 @@
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 : DutaMovie() {
override var mainUrl = "https://no-drak-or.xyz"
override var name = "Nodrakorid"
override val mainPage = mainPageOf(
"genre/movie/page/%d/" to "Film Terbaru",
"genre/korean-movie/page/%d/" to "Film Korea",
"genre/drama/page/%d/" to "Drama Korea",
"genre/c-drama/c-drama-c-drama/page/%d/" to "Drama China",
"genre/thai-drama/page/%d/" to "Drama Thailand",
)
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

@ -0,0 +1,26 @@
// use an integer for version numbers
version = 11
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(
"TvSeries",
"Movie",
)
iconUrl = "https://www.google.com/s2/favicons?domain=hdfilmcehennemi.live&sz=%size%"
}

View file

@ -0,0 +1,245 @@
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.mvvm.safeApiCall
import com.lagradost.cloudstream3.utils.*
import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
import org.jsoup.nodes.Element
class Hdfilmcehennemi : MainAPI() {
override var mainUrl = "https://www.hdfilmcehennemi.life"
override var name = "hdfilmcehennemi"
override val hasMainPage = true
override var lang = "tr"
override val hasQuickSearch = true
override val hasDownloadSupport = true
override val supportedTypes = setOf(
TvType.Movie,
TvType.TvSeries,
)
override val mainPage = mainPageOf(
"$mainUrl/category/tavsiye-filmler-izle2/page/" to "Tavsiye Filmler Kategorisi",
"$mainUrl/yabancidiziizle-1/page/" to "Son Eklenen Yabancı Diziler",
"$mainUrl/imdb-7-puan-uzeri-filmler/page/" to "Imdb 7+ Filmler",
"$mainUrl/en-cok-yorumlananlar/page/" to "En Çok Yorumlananlar",
"$mainUrl/en-cok-begenilen-filmleri-izle/page/" to "En Çok Beğenilenler",
)
override suspend fun getMainPage(
page: Int,
request: MainPageRequest
): HomePageResponse {
val document = app.get(request.data + page).document
val home = document.select("div.card-body div.row div.col-6.col-sm-3.poster-container")
.mapNotNull {
it.toSearchResult()
}
return newHomePageResponse(request.name, home)
}
private fun Element.toSearchResult(): SearchResponse? {
val title = this.selectFirst("h2.title")?.text() ?: return null
val href = fixUrlNull(this.selectFirst("a")?.attr("href")) ?: return null
val posterUrl = fixUrlNull(this.selectFirst("img")?.attr("data-src"))
return newMovieSearchResponse(title, href, TvType.Movie) {
this.posterUrl = posterUrl
}
}
private fun Media.toSearchResponse(): SearchResponse? {
return newMovieSearchResponse(
title ?: return null,
"$mainUrl/$slugPrefix$slug",
TvType.TvSeries,
) {
this.posterUrl = "$mainUrl/uploads/poster/$poster"
}
}
override suspend fun quickSearch(query: String): List<SearchResponse> = search(query)
override suspend fun search(query: String): List<SearchResponse> {
return app.post(
"$mainUrl/search/",
data = mapOf("query" to query),
referer = "$mainUrl/",
headers = mapOf(
"Accept" to "application/json, text/javascript, */*; q=0.01",
"X-Requested-With" to "XMLHttpRequest"
)
).parsedSafe<Result>()?.result?.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("div.card-header > h1, div.card-header > h2")?.text()
?.removeSuffix("Filminin Bilgileri")?.trim()
?: return null
val poster = fixUrlNull(document.select("img.img-fluid").lastOrNull()?.attr("src"))
val tags = document.select("div.mb-0.lh-lg div:nth-child(5) a").map { it.text() }
val year =
document.selectFirst("div.mb-0.lh-lg div:nth-child(4) a")?.text()?.trim()?.toIntOrNull()
val tvType = if (document.select("nav#seasonsTabs").isNullOrEmpty()
) TvType.Movie else TvType.TvSeries
val description = document.selectFirst("article.text-white > p")?.text()?.trim()
val rating = document.selectFirst("div.rating-votes div.rate span")?.text()?.toRatingInt()
val actors = document.select("div.mb-0.lh-lg div:last-child a.chip").map {
Actor(it.text(), it.select("img").attr("src"))
}
val recommendations =
document.select("div.swiper-wrapper div.poster.poster-pop").mapNotNull {
val recName = it.selectFirst("h2.title")?.text() ?: return@mapNotNull null
val recHref =
fixUrlNull(it.selectFirst("a")?.attr("href")) ?: return@mapNotNull null
val recPosterUrl = fixUrlNull(it.selectFirst("img")?.attr("data-src"))
newTvSeriesSearchResponse(recName, recHref, TvType.TvSeries) {
this.posterUrl = recPosterUrl
}
}
return if (tvType == TvType.TvSeries) {
val trailer =
document.selectFirst("button.btn.btn-fragman.btn-danger")?.attr("data-trailer")
?.let {
"https://www.youtube.com/embed/$it"
}
val episodes = document.select("div#seasonsTabs-tabContent div.card-list-item").map {
val href = it.select("a").attr("href")
val name = it.select("h3").text().trim()
val episode = it.select("h3").text().let { num ->
Regex("Sezon\\s?([0-9]+).").find(num)?.groupValues?.getOrNull(1)?.toIntOrNull()
}
val season = it.parents()[1].attr("id").substringAfter("-").toIntOrNull()
Episode(
href,
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 {
val trailer =
document.selectFirst("nav.nav.card-nav.nav-slider a[data-bs-toggle=\"modal\"]")
?.attr("data-trailer")?.let {
"https://www.youtube.com/embed/$it"
}
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)
}
}
}
private suspend fun invokeLocalSource(
source: String,
url: String,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
) {
val script = app.get(
url,
referer = "${mainUrl}/"
).document.select("script")
.find { it.data().contains("sources:") }?.data() ?: return
val videoData = getAndUnpack(script).substringAfter("file_link=\"").substringBefore("\";")
val subData = script.substringAfter("tracks: [").substringBefore("]")
callback.invoke(
ExtractorLink(
source,
source,
base64Decode(videoData),
"$mainUrl/",
Qualities.Unknown.value,
true
)
)
tryParseJson<List<SubSource>>("[${subData}]")
?.filter { it.kind == "captions" }?.map {
subtitleCallback.invoke(
SubtitleFile(
it.label.toString(),
fixUrl(it.file.toString())
)
)
}
}
override suspend fun loadLinks(
data: String,
isCasting: Boolean,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
): Boolean {
app.get(data).document.select("nav.nav.card-nav.nav-slider a.nav-link").map {
Pair(it.attr("href"), it.text())
}.apmap { (url, source) ->
safeApiCall {
app.get(url).document.select("div.card-video > iframe").attr("data-src")
.let { url ->
if (url.startsWith(mainUrl)) {
invokeLocalSource(source, url, subtitleCallback, callback)
} else {
loadExtractor(url, "$mainUrl/", subtitleCallback) { link ->
callback.invoke(
ExtractorLink(
source,
source,
link.url,
link.referer,
link.quality,
link.type,
link.headers,
link.extractorData
)
)
}
}
}
}
}
return true
}
private data class SubSource(
@JsonProperty("file") val file: String? = null,
@JsonProperty("label") val label: String? = null,
@JsonProperty("kind") val kind: String? = null,
)
data class Result(
@JsonProperty("result") val result: ArrayList<Media>? = arrayListOf(),
)
data class Media(
@JsonProperty("title") val title: String? = null,
@JsonProperty("poster") val poster: String? = null,
@JsonProperty("slug") val slug: String? = null,
@JsonProperty("slug_prefix") val slugPrefix: String? = null,
)
}

View file

@ -0,0 +1,28 @@
// 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(
"TvSeries",
"Movie",
"Anime",
"AsianDrama",
)
iconUrl = "https://t0.gstatic.com/faviconV2?client=SOCIAL&type=FAVICON&fallback_opts=TYPE,SIZE,URL&url=http://idlixian.com&size=16"
}

View file

@ -0,0 +1,317 @@
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.mvvm.safeApiCall
import com.lagradost.cloudstream3.network.CloudflareKiller
import com.lagradost.cloudstream3.utils.*
import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
import okhttp3.Interceptor
import okhttp3.Response
import org.jsoup.Jsoup
import org.jsoup.nodes.Element
import java.net.URI
class IdlixProvider : MainAPI() {
override var mainUrl = "https://tv.idlixplus.net"
private var directUrl = mainUrl
override var name = "Idlix"
override val hasMainPage = true
override var lang = "id"
override val hasDownloadSupport = true
private val cloudflareKiller by lazy { CloudflareKiller() }
private val interceptor by lazy { CloudflareInterceptor(cloudflareKiller) }
override val supportedTypes = setOf(
TvType.Movie,
TvType.TvSeries,
TvType.Anime,
TvType.AsianDrama
)
private val key = "\\x5a\\x6d\\x5a\\x6c\\x4e\\x7a\\x55\\x79\\x4d\\x54\\x56\\x6a\\x5a\\x47\\x52\\x69\\x5a\\x44\\x55\\x30\\x5a\\x6d\\x59\\x35\\x4f\\x57\\x45\\x33\\x4d\\x44\\x4a\\x69\\x4e\\x32\\x4a\\x6c\\x4f\\x54\\x42\\x6c\\x4e\\x7a\\x49\\x3d"
override val mainPage = mainPageOf(
"$mainUrl/" to "Featured",
"$mainUrl/trending/page/?get=movies" to "Trending Movies",
"$mainUrl/trending/page/?get=tv" to "Trending TV Series",
"$mainUrl/movie/page/" to "Movie Terbaru",
"$mainUrl/tvseries/page/" to "TV Series Terbaru",
"$mainUrl/network/netflix/page/" to "Netflix",
"$mainUrl/genre/anime/page/" to "Anime",
"$mainUrl/genre/drama-korea/page/" to "Drama Korea",
)
private fun getBaseUrl(url: String): String {
return URI(url).let {
"${it.scheme}://${it.host}"
}
}
override suspend fun getMainPage(
page: Int,
request: MainPageRequest
): HomePageResponse {
val url = request.data.split("?")
val nonPaged = request.name == "Featured" && page <= 1
val req = if (nonPaged) {
app.get(request.data, interceptor = interceptor)
} else {
app.get("${url.first()}$page/?${url.lastOrNull()}", interceptor = interceptor)
}
mainUrl = getBaseUrl(req.url)
val document = req.document
val home = (if (nonPaged) {
document.select("div.items.featured article")
} else {
document.select("div.items.full article, div#archive-content article")
}).mapNotNull {
it.toSearchResult()
}
return newHomePageResponse(request.name, home)
}
private fun getProperLink(uri: String): String {
return when {
uri.contains("/episode/") -> {
var title = uri.substringAfter("$mainUrl/episode/")
title = Regex("(.+?)-season").find(title)?.groupValues?.get(1).toString()
"$mainUrl/tvseries/$title"
}
uri.contains("/season/") -> {
var title = uri.substringAfter("$mainUrl/season/")
title = Regex("(.+?)-season").find(title)?.groupValues?.get(1).toString()
"$mainUrl/tvseries/$title"
}
else -> {
uri
}
}
}
private fun Element.toSearchResult(): SearchResponse {
val title = this.selectFirst("h3 > a")!!.text().replace(Regex("\\(\\d{4}\\)"), "").trim()
val href = getProperLink(this.selectFirst("h3 > a")!!.attr("href"))
val posterUrl = this.select("div.poster > img").attr("src").toString()
val quality = getQualityFromString(this.select("span.quality").text())
return newMovieSearchResponse(title, href, TvType.Movie) {
this.posterUrl = posterUrl
this.quality = quality
posterHeaders = cloudflareKiller.getCookieHeaders(mainUrl).toMap()
}
}
override suspend fun search(query: String): List<SearchResponse> {
val req = app.get("$mainUrl/search/$query", interceptor = interceptor)
mainUrl = getBaseUrl(req.url)
val document = req.document
return document.select("div.result-item").map {
val title =
it.selectFirst("div.title > a")!!.text().replace(Regex("\\(\\d{4}\\)"), "").trim()
val href = getProperLink(it.selectFirst("div.title > a")!!.attr("href"))
val posterUrl = it.selectFirst("img")!!.attr("src").toString()
newMovieSearchResponse(title, href, TvType.TvSeries) {
this.posterUrl = posterUrl
posterHeaders = cloudflareKiller.getCookieHeaders(mainUrl).toMap()
}
}
}
override suspend fun load(url: String): LoadResponse {
val request = app.get(url, interceptor = interceptor, referer = "$directUrl/")
directUrl = getBaseUrl(request.url)
val document = request.document
val title =
document.selectFirst("div.data > h1")?.text()?.replace(Regex("\\(\\d{4}\\)"), "")
?.trim().toString()
val poster = document.select("div.poster > img").attr("src").toString()
val tags = document.select("div.sgeneros > a").map { it.text() }
val year = Regex(",\\s?(\\d+)").find(
document.select("span.date").text().trim()
)?.groupValues?.get(1).toString().toIntOrNull()
val tvType = if (document.select("ul#section > li:nth-child(1)").text().contains("Episodes")
) TvType.TvSeries else TvType.Movie
val description = document.select("div.wp-content > p").text().trim()
val trailer = document.selectFirst("div.embed iframe")?.attr("src")
val rating =
document.selectFirst("span.dt_rating_vgs")?.text()?.toRatingInt()
val actors = document.select("div.persons > div[itemprop=actor]").map {
Actor(it.select("meta[itemprop=name]").attr("content"), it.select("img").attr("src"))
}
val recommendations = document.select("div.owl-item").map {
val recName =
it.selectFirst("a")!!.attr("href").toString().removeSuffix("/").split("/").last()
val recHref = it.selectFirst("a")!!.attr("href")
val recPosterUrl = it.selectFirst("img")?.attr("src").toString()
newTvSeriesSearchResponse(recName, recHref, TvType.TvSeries) {
this.posterUrl = recPosterUrl
posterHeaders = cloudflareKiller.getCookieHeaders(mainUrl).toMap()
}
}
return if (tvType == TvType.TvSeries) {
val episodes = document.select("ul.episodios > li").map {
val href = it.select("a").attr("href")
val name = fixTitle(it.select("div.episodiotitle > a").text().trim())
val image = it.select("div.imagen > img").attr("src")
val episode = it.select("div.numerando").text().replace(" ", "").split("-").last()
.toIntOrNull()
val season = it.select("div.numerando").text().replace(" ", "").split("-").first()
.toIntOrNull()
Episode(
href,
name,
season,
episode,
image
)
}
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)
posterHeaders = cloudflareKiller.getCookieHeaders(mainUrl).toMap()
}
} 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)
posterHeaders = cloudflareKiller.getCookieHeaders(mainUrl).toMap()
}
}
}
override suspend fun loadLinks(
data: String,
isCasting: Boolean,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
): Boolean {
val document = app.get(data, interceptor = interceptor, referer = "$directUrl/").document
val id = document.select("meta#dooplay-ajax-counter").attr("data-postid")
val type = if (data.contains("/movie/")) "movie" else "tv"
document.select("ul#playeroptionsul > li").map {
it.attr("data-nume")
}.apmap { nume ->
safeApiCall {
val source = app.post(
url = "$directUrl/wp-admin/admin-ajax.php", data = mapOf(
"action" to "doo_player_ajax", "post" to id, "nume" to nume, "type" to type
), headers = mapOf("X-Requested-With" to "XMLHttpRequest"), referer = data, interceptor = interceptor
).let { tryParseJson<ResponseHash>(it.text) } ?: return@safeApiCall
val password = if(source.key?.startsWith("\\x") == true) source.key else key
var decrypted = AesHelper.cryptoAESHandler(source.embed_url, password.toByteArray(), false)?.fixBloat() ?: return@safeApiCall
if (decrypted.startsWith("https://uservideo.xyz")) {
decrypted = app.get(decrypted).document.select("iframe").attr("src")
}
getUrl(decrypted, "$directUrl/", subtitleCallback, callback)
}
}
return true
}
class CloudflareInterceptor(private val cloudflareKiller: CloudflareKiller): Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val request = chain.request()
val response = chain.proceed(request)
val doc = Jsoup.parse(response.peekBody(1024 * 1024).string())
if (doc.select("title").text() == "Just a moment...") {
return cloudflareKiller.intercept(chain)
}
return response
}
}
private fun String.fixBloat() : String {
return this.replace("\"", "").replace("\\", "")
}
private suspend fun getUrl(
url: String,
referer: String?,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
) {
val document = app.get(url, referer = referer).document
val hash = url.split("/").last().substringAfter("data=")
val m3uLink = app.post(
url = "$mainUrl/player/index.php?data=$hash&do=getVideo",
data = mapOf("hash" to hash, "r" to "$referer"),
referer = referer,
headers = mapOf("X-Requested-With" to "XMLHttpRequest")
).parsed<ResponseSource>().videoSource
M3u8Helper.generateM3u8(
this.name,
m3uLink,
"$referer",
).forEach(callback)
document.select("script").map { script ->
if (script.data().contains("eval(function(p,a,c,k,e,d)")) {
val subData =
getAndUnpack(script.data()).substringAfter("\"tracks\":[").substringBefore("],")
tryParseJson<List<Tracks>>("[$subData]")?.map { subtitle ->
subtitleCallback.invoke(
SubtitleFile(
getLanguage(subtitle.label ?: ""),
subtitle.file
)
)
}
}
}
}
private fun getLanguage(str: String): String {
return when {
str.contains("indonesia", true) || str
.contains("bahasa", true) -> "Indonesian"
else -> str
}
}
data class ResponseSource(
@JsonProperty("hls") val hls: Boolean,
@JsonProperty("videoSource") val videoSource: String,
@JsonProperty("securedLink") val securedLink: String?,
)
data class Tracks(
@JsonProperty("kind") val kind: String?,
@JsonProperty("file") val file: String,
@JsonProperty("label") val label: String?,
)
data class ResponseHash(
@JsonProperty("embed_url") val embed_url: String,
@JsonProperty("key") val key: String?,
@JsonProperty("type") val type: String?,
)
}

View file

@ -0,0 +1,95 @@
package com.hexated
import com.fasterxml.jackson.annotation.JsonProperty
import com.lagradost.cloudstream3.ErrorLoadingException
import com.lagradost.cloudstream3.base64DecodeArray
import com.lagradost.cloudstream3.base64Encode
import com.lagradost.cloudstream3.utils.AppUtils
import java.security.DigestException
import java.security.MessageDigest
import javax.crypto.Cipher
import javax.crypto.spec.IvParameterSpec
import javax.crypto.spec.SecretKeySpec
object AesHelper {
fun cryptoAESHandler(
data: String,
pass: ByteArray,
encrypt: Boolean = true,
padding: String = "AES/CBC/PKCS5PADDING",
): String? {
val parse = AppUtils.tryParseJson<AesData>(data) ?: return null
val (key, iv) = generateKeyAndIv(pass, parse.s.hexToByteArray()) ?: throw ErrorLoadingException("failed to generate key")
val cipher = Cipher.getInstance(padding)
return if (!encrypt) {
cipher.init(Cipher.DECRYPT_MODE, SecretKeySpec(key, "AES"), IvParameterSpec(iv))
String(cipher.doFinal(base64DecodeArray(parse.ct)))
} else {
cipher.init(Cipher.ENCRYPT_MODE, SecretKeySpec(key, "AES"), IvParameterSpec(iv))
base64Encode(cipher.doFinal(parse.ct.toByteArray()))
}
}
// https://stackoverflow.com/a/41434590/8166854
private fun generateKeyAndIv(
password: ByteArray,
salt: ByteArray,
hashAlgorithm: String = "MD5",
keyLength: Int = 32,
ivLength: Int = 16,
iterations: Int = 1
): List<ByteArray>? {
val md = MessageDigest.getInstance(hashAlgorithm)
val digestLength = md.digestLength
val targetKeySize = keyLength + ivLength
val requiredLength = (targetKeySize + digestLength - 1) / digestLength * digestLength
val generatedData = ByteArray(requiredLength)
var generatedLength = 0
try {
md.reset()
while (generatedLength < targetKeySize) {
if (generatedLength > 0)
md.update(
generatedData,
generatedLength - digestLength,
digestLength
)
md.update(password)
md.update(salt, 0, 8)
md.digest(generatedData, generatedLength, digestLength)
for (i in 1 until iterations) {
md.update(generatedData, generatedLength, digestLength)
md.digest(generatedData, generatedLength, digestLength)
}
generatedLength += digestLength
}
return listOf(
generatedData.copyOfRange(0, keyLength),
generatedData.copyOfRange(keyLength, targetKeySize)
)
} catch (e: DigestException) {
return null
}
}
private fun String.hexToByteArray(): ByteArray {
check(length % 2 == 0) { "Must have an even length" }
return chunked(2)
.map { it.toInt(16).toByte() }
.toByteArray()
}
private data class AesData(
@JsonProperty("ct") val ct: String,
@JsonProperty("iv") val iv: String,
@JsonProperty("s") val s: String
)
}

View file

@ -0,0 +1,23 @@
// use an integer for version numbers
version = 3
cloudstream {
language = "en"
// All of these properties are optional, you can safely remove them
description = "Include: KissasianMx"
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=kissasian.pe&sz=%size%"
}

View file

@ -0,0 +1,146 @@
package com.hexated
import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.extractors.Filesim
import com.lagradost.cloudstream3.extractors.helper.GogoHelper
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.httpsify
import com.lagradost.cloudstream3.utils.loadExtractor
import org.jsoup.nodes.Element
open class Kissasian : MainAPI() {
override var mainUrl = "https://kissasian.pe"
override var name = "Kissasian"
override val hasMainPage = true
override val hasDownloadSupport = true
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
}
}
}
override val mainPage = mainPageOf(
"drama-list/ongoing.html?page=" to "Drama Ongoing",
"drama-list/completed.html?page=" to "Drama Completed",
"genre/variety/?page=" to "Variety Show",
"genre/romance/?page=" to "Romance",
"genre/action/?page=" to "Action",
"genre/mystery/?page=" to "Mystery",
)
override suspend fun getMainPage(page: Int, request: MainPageRequest): HomePageResponse {
val document = app.get("$mainUrl/${request.data}$page").document
val home = document.select("div.list-drama div.item").mapNotNull {
it.toSearchResult()
}
return newHomePageResponse(request.name, home)
}
private fun Element.toSearchResult(): SearchResponse? {
val href = fixUrl(this.selectFirst("a")?.attr("href") ?: return null)
val title = this.selectFirst("span.title")?.text()?.trim() ?: return null
val posterUrl = fixUrlNull(this.selectFirst("img")?.attr("src"))
return newTvSeriesSearchResponse(title, href, TvType.AsianDrama) {
this.posterUrl = posterUrl
}
}
override suspend fun search(query: String): List<SearchResponse> {
val document = app.get("$mainUrl/search.html?keyword=$query").document
return document.select("div.list-drama div.item").mapNotNull {
it.toSearchResult()
}
}
open val contentInfoClass = "barContentInfo"
override suspend fun load(url: String): LoadResponse? {
val document = app.get(url).document
val title = document.selectFirst("div.$contentInfoClass a")?.text()?.trim() ?: return null
val poster = fixUrlNull(document.select("div.$contentInfoClass img").last()?.attr("src"))
val tags = document.select("div.$contentInfoClass p:contains(Genres:) a").map { it.text().removePrefix(",").trim() }
val year = document.selectFirst("div.$contentInfoClass p.type.Releasea")?.text()?.trim()?.toIntOrNull()
val status = getStatus(document.selectFirst("div.$contentInfoClass p:contains(Status:)")?.ownText()?.trim())
val description = document.selectFirst("div.$contentInfoClass p.des, div.$contentInfoClass p:last-child")?.nextElementSiblings()?.select("p")?.text()
val episodes = document.select("ul.listing li, table.listing td.episodeSub").map {
val name = it.selectFirst("a")?.attr("title")
val link = fixUrlNull(it.selectFirst("a")?.attr("href"))
val epNum = Regex("Episode\\s(\\d+)").find("$name")?.groupValues?.getOrNull(1)?.toIntOrNull()
newEpisode(link) {
this.name = name
this.episode = epNum
}
}.reversed()
if (episodes.size == 1) {
return newMovieLoadResponse(title, url, TvType.Movie, episodes[0].data) {
posterUrl = poster
this.year = year
plot = description
this.tags = tags
}
} else {
return newTvSeriesLoadResponse(title, url, TvType.AsianDrama, episodes = episodes) {
posterUrl = poster
this.year = year
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
val server = document.selectFirst("select#selectServer option")?.attr("value")
val iframe = app.get(httpsify(server ?: return false))
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 = "9262859232435825"
val secretKey = "93422192433952489752342908585752"
val secretDecryptKey = secretKey
GogoHelper.extractVidstream(
iframe.url,
this.name,
callback,
iv,
secretKey,
secretDecryptKey,
isUsingAdaptiveKeys = false,
isUsingAdaptiveData = true,
iframeDocument = iframeDoc
)
})
return true
}
}
class Kswplayer : Filesim() {
override val name = "Kswplayer"
override var mainUrl = "https://kswplayer.info"
}

View file

@ -0,0 +1,58 @@
package com.hexated
import com.lagradost.cloudstream3.SearchResponse
import com.lagradost.cloudstream3.SubtitleFile
import com.lagradost.cloudstream3.TvType
import com.lagradost.cloudstream3.apmap
import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.fixUrl
import com.lagradost.cloudstream3.mainPageOf
import com.lagradost.cloudstream3.newTvSeriesSearchResponse
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.loadExtractor
class KissasianMx : Kissasian() {
override var mainUrl = "https://kissasian.mx"
override var name = "KissasianMx"
override val contentInfoClass = "barContent"
override val mainPage = mainPageOf(
"Status/Ongoing?page=" to "Drama Ongoing",
"Status/Completed?page=" to "Drama Completed",
"Status/Completed?page=" to "Drama Completed",
"Genre/Romance?page=" to "Drama Romance",
"Genre/Reality-TV?page=" to "Reality-TV",
"Genre/Mystery?page=" to "Drama Mystery",
"Genre/Movie?page=" to "Movie",
)
override suspend fun search(query: String): List<SearchResponse> {
val document = app.post(
"$mainUrl/Search/SearchSuggest", data = mapOf(
"type" to "Drama",
"keyword" to query,
), headers = mapOf("X-Requested-With" to "XMLHttpRequest")
).document
return document.select("a").mapNotNull {
val href = fixUrl(it.attr("href"))
val title = it.text()
newTvSeriesSearchResponse(title, href, TvType.AsianDrama)
}
}
override suspend fun loadLinks(
data: String,
isCasting: Boolean,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
): Boolean {
val document = app.get(data).document
document.select("select#selectServer option").apmap {
val server = it.attr("value")
val iframe = app.get(fixUrl(server ?: return@apmap)).document.selectFirst("div#centerDivVideo iframe")?.attr("src")
loadExtractor(iframe ?: return@apmap, "$mainUrl/", subtitleCallback, callback)
}
return true
}
}

View file

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

View file

@ -0,0 +1,27 @@
// 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",
"Anime",
"OVA",
)
iconUrl = "https://www.google.com/s2/favicons?domain=kuramanime.com&sz=%size%"
}

View file

@ -0,0 +1,217 @@
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.Qualities
import com.lagradost.cloudstream3.utils.loadExtractor
import org.jsoup.Jsoup
import org.jsoup.nodes.Element
class KuramanimeProvider : MainAPI() {
override var mainUrl = "https://kuramanime.pro"
override var name = "Kuramanime"
override val hasQuickSearch = false
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, s: Int): TvType {
return if (t.contains("OVA", true) || t.contains("Special")) TvType.OVA
else if (t.contains("Movie", true) && s == 1) TvType.AnimeMovie
else TvType.Anime
}
fun getStatus(t: String): ShowStatus {
return when (t) {
"Selesai Tayang" -> ShowStatus.Completed
"Sedang Tayang" -> ShowStatus.Ongoing
else -> ShowStatus.Completed
}
}
}
override val mainPage = mainPageOf(
"$mainUrl/anime/ongoing?order_by=updated&page=" to "Sedang Tayang",
"$mainUrl/anime/finished?order_by=updated&page=" to "Selesai Tayang",
"$mainUrl/properties/season/summer-2022?order_by=most_viewed&page=" to "Dilihat Terbanyak Musim Ini",
"$mainUrl/anime/movie?order_by=updated&page=" to "Film Layar Lebar",
)
override suspend fun getMainPage(
page: Int,
request: MainPageRequest
): HomePageResponse {
val document = app.get(request.data + page).document
val home = document.select("div.col-lg-4.col-md-6.col-sm-6").mapNotNull {
it.toSearchResult()
}
return newHomePageResponse(request.name, home)
}
private fun getProperAnimeLink(uri: String): String {
return if (uri.contains("/episode")) {
Regex("(.*)/episode/.+").find(uri)?.groupValues?.get(1).toString() + "/"
} else {
uri
}
}
private fun Element.toSearchResult(): AnimeSearchResponse? {
val href = getProperAnimeLink(fixUrl(this.selectFirst("a")!!.attr("href")))
val title = this.selectFirst("h5 a")?.text() ?: return null
val posterUrl = fixUrl(this.select("div.product__item__pic.set-bg").attr("data-setbg"))
val episode = this.select("div.ep span").text().let {
Regex("Ep\\s(\\d+)\\s/").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 link = "$mainUrl/anime?search=$query&order_by=latest"
val document = app.get(link).document
return document.select("div#animeList div.product__item").mapNotNull {
it.toSearchResult()
}
}
override suspend fun load(url: String): LoadResponse {
val document = app.get(url).document
val title = document.selectFirst(".anime__details__title > h3")!!.text().trim()
val poster = document.selectFirst(".anime__details__pic")?.attr("data-setbg")
val tags = document.select("div.anime__details__widget > div > div:nth-child(2) > ul > li:nth-child(1)")
.text().trim().replace("Genre: ", "").split(", ")
val year = Regex("\\D").replace(
document.select("div.anime__details__widget > div > div:nth-child(1) > ul > li:nth-child(5)")
.text().trim().replace("Musim: ", ""), ""
).toIntOrNull()
val status = getStatus(
document.select("div.anime__details__widget > div > div:nth-child(1) > ul > li:nth-child(3)")
.text().trim().replace("Status: ", "")
)
val description = document.select(".anime__details__text > p").text().trim()
val episodes = mutableListOf<Episode>()
for (i in 1..6) {
val doc = app.get("$url?page=$i").document
val eps = Jsoup.parse(doc.select("#episodeLists").attr("data-content")).select("a.btn.btn-sm.btn-danger")
.mapNotNull {
val name = it.text().trim()
val episode = Regex("(\\d+[.,]?\\d*)").find(name)?.groupValues?.getOrNull(0)
?.toIntOrNull()
val link = it.attr("href")
Episode(link, episode = episode)
}
if(eps.isEmpty()) break else episodes.addAll(eps)
}
val type = getType(document.selectFirst("div.col-lg-6.col-md-6 ul li:contains(Tipe:) a")?.text()?.lowercase() ?: "tv", episodes.size)
val recommendations = document.select("div#randomList > a").mapNotNull {
val epHref = it.attr("href")
val epTitle = it.select("h5.sidebar-title-h5.px-2.py-2").text()
val epPoster = it.select(".product__sidebar__view__item.set-bg").attr("data-setbg")
newAnimeSearchResponse(epTitle, epHref, TvType.Anime) {
this.posterUrl = epPoster
addDubStatus(dubExist = false, subExist = true)
}
}
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
addMalId(tracker?.malId)
addAniListId(tracker?.aniId?.toIntOrNull())
}
}
private suspend fun invokeLocalSource(
url: String,
server: String,
ref: String,
callback: (ExtractorLink) -> Unit
) {
val document = app.get(
url,
referer = ref,
headers = mapOf("X-Requested-With" to "XMLHttpRequest")
).document
document.select("video#player > source").map {
val link = fixUrl(it.attr("src"))
val quality = it.attr("size").toIntOrNull()
callback.invoke(
ExtractorLink(
fixTitle(server),
fixTitle(server),
link,
referer = "$mainUrl/",
quality = quality ?: 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",
"Range" to "bytes=0-",
"Sec-Fetch-Dest" to "video",
"Sec-Fetch-Mode" to "no-cors",
)
)
)
}
}
override suspend fun loadLinks(
data: String,
isCasting: Boolean,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
): Boolean {
val res = app.get(data).document
res.select("select#changeServer option").apmap { source ->
safeApiCall {
val server = source.attr("value")
val link = "$data?activate_stream=1&stream_server=$server"
if (server == "kuramadrive" || server == "archive") {
invokeLocalSource(link, server, data, callback)
} else {
app.get(
link,
referer = data,
headers = mapOf("X-Requested-With" to "XMLHttpRequest")
).document.select("div.iframe-container iframe").attr("src").let { videoUrl ->
loadExtractor(fixUrl(videoUrl), "$mainUrl/", subtitleCallback, callback)
}
}
}
}
return true
}
}

View file

@ -0,0 +1,27 @@
// use an integer for version numbers
version = 17
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=45.12.2.2&sz=%size%"
}

View file

@ -0,0 +1,299 @@
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.LoadResponse.Companion.addTrailer
import com.lagradost.cloudstream3.extractors.helper.AesHelper
import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.M3u8Helper
import com.lagradost.cloudstream3.utils.getQualityFromName
import com.lagradost.cloudstream3.utils.loadExtractor
import org.jsoup.nodes.Element
import java.net.URI
import java.util.ArrayList
class KuronimeProvider : MainAPI() {
override var mainUrl = "https://45.12.2.26"
private var animekuUrl = "https://animeku.org"
override var name = "Kuronime"
override val hasQuickSearch = true
override val hasMainPage = true
override var lang = "id"
override val supportedTypes = setOf(
TvType.Anime,
TvType.AnimeMovie,
TvType.OVA
)
companion object {
const val KEY = "3&!Z0M,VIZ;dZW=="
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(
"$mainUrl/page/" to "New Episodes",
"$mainUrl/popular-anime/page/" to "Popular Anime",
"$mainUrl/movies/page/" to "Movies",
// "$mainUrl/genres/donghua/page/" to "Donghua",
// "$mainUrl/live-action/page/" to "Live Action",
)
override suspend fun getMainPage(
page: Int,
request: MainPageRequest
): HomePageResponse {
val req = app.get(request.data + page)
mainUrl = getBaseUrl(req.url)
val document = req.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")) -> Regex("nonton-(.+)-episode").find(
title
)?.groupValues?.get(1).toString()
(title.contains("-movie")) -> Regex("nonton-(.+)-movie").find(title)?.groupValues?.get(
1
).toString()
else -> title
}
"$mainUrl/anime/$title"
}
}
private fun Element.toSearchResult(): AnimeSearchResponse {
val href = getProperAnimeLink(fixUrlNull(this.selectFirst("a")?.attr("href")).toString())
val title = this.select(".bsuxtt, .tt > h4").text().trim()
val posterUrl = fixUrlNull(
this.selectFirst("div.view,div.bt")?.nextElementSibling()?.select("img")
?.attr("data-src")
)
val epNum = this.select(".ep").text().replace(Regex("\\D"), "").trim().toIntOrNull()
val tvType = getType(this.selectFirst(".bt > span")?.text().toString())
return newAnimeSearchResponse(title, href, tvType) {
this.posterUrl = posterUrl
addSub(epNum)
}
}
override suspend fun quickSearch(query: String): List<SearchResponse>? = search(query)
override suspend fun search(query: String): List<SearchResponse>? {
mainUrl = app.get(mainUrl).url
return app.post(
"$mainUrl/wp-admin/admin-ajax.php", data = mapOf(
"action" to "ajaxy_sf",
"sf_value" to query,
"search" to "false"
), headers = mapOf("X-Requested-With" to "XMLHttpRequest")
).parsedSafe<Search>()?.anime?.firstOrNull()?.all?.mapNotNull {
newAnimeSearchResponse(
it.postTitle ?: "",
it.postLink ?: return@mapNotNull null,
TvType.Anime
) {
this.posterUrl = it.postImage
addSub(it.postLatest?.toIntOrNull())
}
}
}
override suspend fun load(url: String): LoadResponse {
val document = app.get(url).document
val title = document.selectFirst(".entry-title")?.text().toString().trim()
val poster = document.selectFirst("div.l[itemprop=image] > img")?.attr("data-src")
val tags = document.select(".infodetail > ul > li:nth-child(2) > a").map { it.text() }
val type =
getType(document.selectFirst(".infodetail > ul > li:nth-child(7)")?.ownText()?.removePrefix(":")
?.lowercase()?.trim() ?: "tv")
val trailer = document.selectFirst("div.tply iframe")?.attr("data-src")
val year = Regex("\\d, (\\d*)").find(
document.select(".infodetail > ul > li:nth-child(5)").text()
)?.groupValues?.get(1)?.toIntOrNull()
val status = getStatus(
document.selectFirst(".infodetail > ul > li:nth-child(3)")!!.ownText()
.replace(Regex("\\W"), "")
)
val description = document.select("span.const > p").text()
val episodes = document.select("div.bixbox.bxcl > ul > li").mapNotNull {
val link = it.selectFirst("a")?.attr("href") ?: return@mapNotNull null
val name = it.selectFirst("a")?.text() ?: return@mapNotNull null
val episode =
Regex("(\\d+[.,]?\\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) {
engName = title
posterUrl = tracker?.image ?: poster
backgroundPosterUrl = tracker?.cover
this.year = year
addEpisodes(DubStatus.Subbed, episodes)
showStatus = status
plot = description
addTrailer(trailer)
this.tags = tags
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
val id = document.selectFirst("div#content script:containsData(is_singular)")?.data()
?.substringAfter("\"")?.substringBefore("\";")
?: throw ErrorLoadingException("No id found")
val servers = app.post(
"$animekuUrl/afi.php", data = mapOf(
"id" to id
), referer = "$mainUrl/"
).parsedSafe<Servers>()
argamap(
{
val decrypt = AesHelper.cryptoAESHandler(
base64Decode(servers?.src ?: return@argamap),
KEY.toByteArray(),
false,
"AES/CBC/NoPadding"
)
val source =
tryParseJson<Sources>(decrypt?.toJsonFormat())?.src?.replace("\\", "")
M3u8Helper.generateM3u8(
this.name,
source ?: return@argamap,
"$animekuUrl/",
headers = mapOf("Origin" to animekuUrl)
).forEach(callback)
},
{
val decrypt = AesHelper.cryptoAESHandler(
base64Decode(servers?.mirror ?: return@argamap),
KEY.toByteArray(),
false,
"AES/CBC/NoPadding"
)
tryParseJson<Mirrors>(decrypt)?.embed?.map { embed ->
embed.value.apmap {
loadFixedExtractor(
it.value,
embed.key.removePrefix("v"),
"$mainUrl/",
subtitleCallback,
callback
)
}
}
}
)
return true
}
private fun String.toJsonFormat(): String {
return if (this.startsWith("\"")) this.substringAfter("\"").substringBeforeLast("\"")
.replace("\\\"", "\"") else this
}
private suspend fun loadFixedExtractor(
url: String? = null,
quality: String? = null,
referer: String? = null,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
) {
loadExtractor(url ?: return, referer, subtitleCallback) { link ->
callback.invoke(
ExtractorLink(
link.name,
link.name,
link.url,
link.referer,
getQualityFromName(quality),
link.type,
link.headers,
link.extractorData
)
)
}
}
private fun getBaseUrl(url: String): String {
return URI(url).let {
"${it.scheme}://${it.host}"
}
}
data class Mirrors(
@JsonProperty("embed") val embed: Map<String, Map<String, String>> = emptyMap(),
)
data class Sources(
@JsonProperty("src") var src: String? = null,
)
data class Servers(
@JsonProperty("src") var src: String? = null,
@JsonProperty("mirror") var mirror: String? = null,
)
data class All(
@JsonProperty("post_image") var postImage: String? = null,
@JsonProperty("post_image_html") var postImageHtml: String? = null,
@JsonProperty("ID") var ID: Int? = null,
@JsonProperty("post_title") var postTitle: String? = null,
@JsonProperty("post_genres") var postGenres: String? = null,
@JsonProperty("post_type") var postType: String? = null,
@JsonProperty("post_latest") var postLatest: String? = null,
@JsonProperty("post_sub") var postSub: String? = null,
@JsonProperty("post_link") var postLink: String? = null
)
data class Anime(
@JsonProperty("all") var all: ArrayList<All> = arrayListOf(),
)
data class Search(
@JsonProperty("anime") var anime: ArrayList<Anime> = arrayListOf()
)
}

View file

@ -0,0 +1,27 @@
// use an integer for version numbers
version = 16
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",
"TvSeries",
"Movie",
)
iconUrl = "https://www.google.com/s2/favicons?domain=lk21official.org&sz=%size%"
}

View file

@ -0,0 +1,202 @@
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.extractors.Filesim
import com.lagradost.cloudstream3.utils.*
import org.jsoup.nodes.Element
import java.net.URLDecoder
class LayarKacaProvider : MainAPI() {
override var mainUrl = "https://tv3.lk21official.pro"
private var seriesUrl = "https://tv1.nontondrama.click"
override var name = "LayarKaca"
override val hasMainPage = true
override var lang = "id"
override val supportedTypes = setOf(
TvType.Movie,
TvType.TvSeries,
TvType.AsianDrama
)
override val mainPage = mainPageOf(
"$mainUrl/populer/page/" to "Film Terplopuler",
"$mainUrl/rating/page/" to "Film Berdasarkan IMDb Rating",
"$mainUrl/most-commented/page/" to "Film Dengan Komentar Terbanyak",
"$seriesUrl/latest/page/" to "Series Terbaru",
"$seriesUrl/series/asian/page/" to "Film Asian Terbaru",
"$mainUrl/latest/page/" to "Film Upload Terbaru",
)
override suspend fun getMainPage(
page: Int,
request: MainPageRequest
): HomePageResponse {
val document = app.get(request.data + page).document
val home = document.select("article.mega-item").mapNotNull {
it.toSearchResult()
}
return newHomePageResponse(request.name, home)
}
private suspend fun getProperLink(url: String): String? {
val res = app.get(url).document
return if (res.select("title").text().contains("- Nontondrama", true)) {
res.selectFirst("div#content a")?.attr("href")
} else {
url
}
}
private fun Element.toSearchResult(): SearchResponse? {
val title = this.selectFirst("h1.grid-title > a")?.ownText()?.trim() ?: return null
val href = fixUrl(this.selectFirst("a")!!.attr("href"))
val posterUrl = fixUrlNull(this.selectFirst("img")?.attr("src"))
val type =
if (this.selectFirst("div.last-episode") == null) TvType.Movie else TvType.TvSeries
return if (type == TvType.TvSeries) {
val episode = this.selectFirst("div.last-episode span")?.text()?.filter { it.isDigit() }
?.toIntOrNull()
newAnimeSearchResponse(title, href, TvType.TvSeries) {
this.posterUrl = posterUrl
addSub(episode)
}
} else {
val quality = this.select("div.quality").text().trim()
newMovieSearchResponse(title, href, TvType.Movie) {
this.posterUrl = posterUrl
addQuality(quality)
}
}
}
override suspend fun search(query: String): List<SearchResponse> {
val document = app.get("$mainUrl/search.php?s=$query").document
return document.select("div.search-item").mapNotNull {
val title = it.selectFirst("a")?.attr("title") ?: ""
val href = fixUrl(it.selectFirst("a")?.attr("href") ?: return@mapNotNull null)
val posterUrl = fixUrlNull(it.selectFirst("img.img-thumbnail")?.attr("src"))
newTvSeriesSearchResponse(title, href, TvType.TvSeries) {
this.posterUrl = posterUrl
}
}
}
override suspend fun load(url: String): LoadResponse? {
val fixUrl = getProperLink(url)
val document = app.get(fixUrl ?: return null).document
val title = document.selectFirst("li.last > span[itemprop=name]")?.text()?.trim().toString()
val poster = fixUrl(document.select("img.img-thumbnail").attr("src").toString())
val tags = document.select("div.content > div:nth-child(5) > h3 > a").map { it.text() }
val year = Regex("\\d, (\\d+)").find(
document.select("div.content > div:nth-child(7) > h3").text().trim()
)?.groupValues?.get(1).toString().toIntOrNull()
val tvType = if (document.select("div.serial-wrapper")
.isNotEmpty()
) TvType.TvSeries else TvType.Movie
val description = document.select("div.content > blockquote").text().trim()
val trailer = document.selectFirst("div.action-player li > a.fancybox")?.attr("href")
val rating =
document.selectFirst("div.content > div:nth-child(6) > h3")?.text()?.toRatingInt()
val actors =
document.select("div.col-xs-9.content > div:nth-child(3) > h3 > a").map { it.text() }
val recommendations = document.select("div.row.item-media").map {
val recName = it.selectFirst("h3")?.text()?.trim().toString()
val recHref = it.selectFirst(".content-media > a")!!.attr("href")
val recPosterUrl =
fixUrl(it.selectFirst(".poster-media > a > img")?.attr("src").toString())
newTvSeriesSearchResponse(recName, recHref, TvType.TvSeries) {
this.posterUrl = recPosterUrl
}
}
return if (tvType == TvType.TvSeries) {
val episodes = document.select("div.episode-list > a:matches(\\d+)").map {
val href = fixUrl(it.attr("href"))
val episode = it.text().toIntOrNull()
val season =
it.attr("href").substringAfter("season-").substringBefore("-").toIntOrNull()
Episode(
href,
"Episode $episode",
season,
episode,
)
}.reversed()
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
document.select("ul#loadProviders > li").map {
fixUrl(it.select("a").attr("href"))
}.apmap {
loadExtractor(it.getIframe(), "https://nganunganu.sbs", subtitleCallback, callback)
}
return true
}
private suspend fun String.getIframe() : String {
return app.get(this, referer = "$seriesUrl/").document.select("div.embed iframe").attr("src")
}
}
open class Emturbovid : ExtractorApi() {
override val name = "Emturbovid"
override val mainUrl = "https://emturbovid.com"
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)
val m3u8 = Regex("[\"'](.*?master\\.m3u8.*?)[\"']").find(response.text)?.groupValues?.getOrNull(1)
M3u8Helper.generateM3u8(
name,
m3u8 ?: return,
mainUrl
).forEach(callback)
}
}
class Furher : Filesim() {
override val name = "Furher"
override var mainUrl = "https://furher.in"
}

View file

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

View file

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

View file

@ -0,0 +1,182 @@
package com.hexated
import com.fasterxml.jackson.annotation.JsonProperty
import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.network.CloudflareKiller
import com.lagradost.cloudstream3.utils.*
import okhttp3.Interceptor
import okhttp3.Response
import org.jsoup.Jsoup
import org.jsoup.nodes.Element
import java.net.URLDecoder
class Minioppai : MainAPI() {
override var mainUrl = "https://minioppai.org"
override var name = "Minioppai"
override val hasMainPage = true
override var lang = "id"
override val hasDownloadSupport = true
override val hasQuickSearch = true
private val cloudflareKiller by lazy { CloudflareKiller() }
private val interceptor by lazy { CloudflareInterceptor(cloudflareKiller) }
override val supportedTypes = setOf(
TvType.NSFW,
)
class CloudflareInterceptor(private val cloudflareKiller: CloudflareKiller): Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val request = chain.request()
val response = chain.proceed(request)
val doc = Jsoup.parse(response.peekBody(1024 * 1024).string())
if (doc.select("title").text() == "Just a moment...") {
return cloudflareKiller.intercept(chain)
}
return response
}
}
companion object {
fun getStatus(t: String?): ShowStatus {
return when (t) {
"Completed" -> ShowStatus.Completed
"Ongoing" -> ShowStatus.Ongoing
else -> ShowStatus.Completed
}
}
}
override val mainPage = mainPageOf(
"$mainUrl/watch" to "New Episode",
"$mainUrl/populars" to "Popular Hentai",
)
override suspend fun getMainPage(
page: Int,
request: MainPageRequest
): HomePageResponse {
val document = app.get("${request.data}/page/$page", interceptor = interceptor).document
val home = document.select("div.latest a").mapNotNull {
it.toSearchResult()
}
return newHomePageResponse(
list = HomePageList(
name = request.name,
list = home,
isHorizontalImages = request.name == "New Episode"
),
hasNext = true
)
}
private fun getProperAnimeLink(uri: String): String {
return if (uri.contains("-episode-")) {
uri.substringBefore("-episode-")
} else {
uri
}
}
private fun Element.toSearchResult(): AnimeSearchResponse? {
val title = this.selectFirst("h2.entry-title")?.text()?.trim() ?: return null
val href = getProperAnimeLink(this.attr("href"))
val posterUrl = fixUrlNull(this.selectFirst("img")?.attr("src"))
val epNum = this.selectFirst("i.dot")?.text()?.filter { it.isDigit() }?.toIntOrNull()
return newAnimeSearchResponse(title, href, TvType.NSFW) {
this.posterUrl = posterUrl
addSub(epNum)
posterHeaders = cloudflareKiller.getCookieHeaders(mainUrl).toMap()
}
}
override suspend fun quickSearch(query: String): List<SearchResponse>? = search(query)
override suspend fun search(query: String): List<SearchResponse>? {
return app.post(
"$mainUrl/wp-admin/admin-ajax.php", data = mapOf(
"action" to "ts_ac_do_search",
"ts_ac_query" to query,
), headers = mapOf("X-Requested-With" to "XMLHttpRequest"),
interceptor = interceptor
).parsedSafe<SearchResponses>()?.post?.firstOrNull()?.all?.mapNotNull { item ->
newAnimeSearchResponse(
item.postTitle ?: "",
item.postLink ?: return@mapNotNull null,
TvType.NSFW
) {
this.posterUrl = item.postImage
posterHeaders = cloudflareKiller.getCookieHeaders(mainUrl).toMap()
}
}
}
override suspend fun load(url: String): LoadResponse? {
val document = app.get(url, interceptor = interceptor).document
val title = document.selectFirst("h1.entry-title")?.text()?.trim() ?: return null
val poster = fixUrlNull(document.selectFirst("div.limage img")?.attr("src"))
val table = document.select("ul.data")
val tags = table.select("ul.data li:nth-child(1) a").map { it.text() }
val year =
document.selectFirst("ul.data time[itemprop=dateCreated]")?.text()?.substringBefore("-")
?.toIntOrNull()
val status = getStatus(document.selectFirst("ul.data li:nth-child(2) span")?.text()?.trim())
val description = document.select("div[itemprop=description] > p").text()
val episodes = document.select("div.epsdlist ul li").mapNotNull {
val name = it.selectFirst("div.epl-num")?.text()
val link = fixUrlNull(it.selectFirst("a")?.attr("href")) ?: return@mapNotNull null
Episode(link, name = name)
}.reversed()
return newAnimeLoadResponse(title, url, TvType.NSFW) {
engName = title
posterUrl = poster
this.year = year
addEpisodes(DubStatus.Subbed, episodes)
showStatus = status
plot = description
this.tags = tags
posterHeaders = cloudflareKiller.getCookieHeaders(mainUrl).toMap()
}
}
override suspend fun loadLinks(
data: String,
isCasting: Boolean,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
): Boolean {
val document = app.get(data, interceptor = interceptor).document
document.select("div.server ul.mirror li a").mapNotNull {
Jsoup.parse(base64Decode(it.attr("data-em"))).select("iframe").attr("src")
}.apmap { link ->
loadExtractor(
fixUrl(decode(link.substringAfter("data="))),
mainUrl,
subtitleCallback,
callback
)
}
return true
}
private fun decode(input: String): String = URLDecoder.decode(input, "utf-8")
data class SearchResponses(
@JsonProperty("post") var post: ArrayList<Post> = arrayListOf()
)
data class All(
@JsonProperty("ID") var ID: Int? = null,
@JsonProperty("post_image") var postImage: String? = null,
@JsonProperty("post_title") var postTitle: String? = null,
@JsonProperty("post_link") var postLink: String? = null,
)
data class Post(
@JsonProperty("all") var all: ArrayList<All> = arrayListOf(),
)
}

View file

@ -0,0 +1,26 @@
// use an integer for version numbers
version = 40
cloudstream {
language = "hi"
// All of these properties are optional, you can safely remove them
description = "Include: Hdmovie2"
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",
)
iconUrl = "https://www.google.com/s2/favicons?domain=movierulzhd.best&sz=%size%"
}

View file

@ -0,0 +1,181 @@
package com.hexated
import com.fasterxml.jackson.annotation.JsonProperty
import com.hexated.RabbitStream.extractRabbitStream
import com.lagradost.cloudstream3.APIHolder
import com.lagradost.cloudstream3.SubtitleFile
import com.lagradost.cloudstream3.apmap
import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.utils.*
import kotlin.random.Random
const val twoEmbedAPI = "https://www.2embed.to"
class Sbnmp : Sbflix() {
override val name = "Sbnmp"
override var mainUrl = "https://sbnmp.bar"
}
class Sbrulz : Sbflix() {
override val name = "Sbrulz"
override var mainUrl = "https://sbrulz.xyz"
}
class Sbmiz : Sbflix() {
override val name = "Sbmiz"
override var mainUrl = "https://sbmiz.site"
}
open class Sbflix : ExtractorApi() {
override val mainUrl = "https://sbflix.xyz"
override val name = "Sbflix"
override val requiresReferer = false
private val alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
override suspend fun getUrl(
url: String,
referer: String?,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
) {
val regexID =
Regex("(embed-[a-zA-Z\\d]{0,8}[a-zA-Z\\d_-]+|/e/[a-zA-Z\\d]{0,8}[a-zA-Z\\d_-]+)")
val id = regexID.findAll(url).map {
it.value.replace(Regex("(embed-|/e/)"), "")
}.first()
val master = "$mainUrl/375664356a494546326c4b797c7c6e756577776778623171737/${encodeId(id)}"
val headers = mapOf(
"watchsb" to "sbstream",
)
val mapped = app.get(
master.lowercase(),
headers = headers,
referer = url,
).parsedSafe<Main>()
callback.invoke(
ExtractorLink(
name,
name,
mapped?.streamData?.file ?: return,
url,
Qualities.P720.value,
isM3u8 = true,
headers = headers
)
)
mapped.streamData.subs?.map {sub ->
subtitleCallback.invoke(
SubtitleFile(
sub.label.toString(),
sub.file ?: return@map null,
)
)
}
}
private fun encodeId(id: String): String {
val code = "${createHashTable()}||$id||${createHashTable()}||streamsb"
return code.toCharArray().joinToString("") { char ->
char.code.toString(16)
}
}
private fun createHashTable(): String {
return buildString {
repeat(12) {
append(alphabet[Random.nextInt(alphabet.length)])
}
}
}
data class Subs (
@JsonProperty("file") val file: String? = null,
@JsonProperty("label") val label: String? = null,
)
data class StreamData (
@JsonProperty("file") val file: String,
@JsonProperty("cdn_img") val cdnImg: String,
@JsonProperty("hash") val hash: String,
@JsonProperty("subs") val subs: ArrayList<Subs>? = arrayListOf(),
@JsonProperty("length") val length: String,
@JsonProperty("id") val id: String,
@JsonProperty("title") val title: String,
@JsonProperty("backup") val backup: String,
)
data class Main (
@JsonProperty("stream_data") val streamData: StreamData,
@JsonProperty("status_code") val statusCode: Int,
)
}
open class Akamaicdn : ExtractorApi() {
override val name = "Akamaicdn"
override val mainUrl = "https://akamaicdn.life"
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).document
val mapper = res.select("script:containsData(sniff)").last()?.data()?.substringAfter("sniff(")
?.substringBefore(");")?.split(",")?.map { it.replace("\"", "").trim() } ?: return
callback.invoke(
ExtractorLink(
this.name,
this.name,
"$mainUrl/m3u8/${mapper[1]}/${mapper[2]}/master.txt?s=1&cache=1",
url,
Qualities.Unknown.value,
isM3u8 = true,
)
)
}
}
suspend fun invokeTwoEmbed(
url: String? = null,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
) {
val document = app.get(url ?: return).document
val captchaKey =
document.select("script[src*=https://www.google.com/recaptcha/api.js?render=]")
.attr("src").substringAfter("render=")
document.select(".dropdown-menu a[data-id]").map { it.attr("data-id") }.apmap { serverID ->
val token = APIHolder.getCaptchaToken(url, captchaKey)
app.get(
"${twoEmbedAPI}/ajax/embed/play?id=$serverID&_token=$token", referer = url
).parsedSafe<EmbedJson>()?.let { source ->
val link = source.link ?: return@let
if (link.contains("rabbitstream")) {
extractRabbitStream(
link,
subtitleCallback,
callback,
false,
decryptKey = RabbitStream.getKey()
) { it }
} else {
loadExtractor(
link, twoEmbedAPI, subtitleCallback, callback
)
}
}
}
}
data class EmbedJson(
@JsonProperty("type") val type: String? = null,
@JsonProperty("link") val link: String? = null,
@JsonProperty("sources") val sources: List<String?> = arrayListOf(),
@JsonProperty("tracks") val tracks: List<String>? = null,
)

View file

@ -0,0 +1,90 @@
package com.hexated
import com.fasterxml.jackson.annotation.JsonProperty
import com.lagradost.cloudstream3.SubtitleFile
import com.lagradost.cloudstream3.apmap
import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.mainPageOf
import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.loadExtractor
import org.jsoup.Jsoup
class Hdmovie2 : Movierulzhd() {
override var mainUrl = "https://hdmovie2.codes"
override var name = "Hdmovie2"
override val mainPage = mainPageOf(
"trending" to "Trending",
"movies" to "Movies",
"genre/tv-series" to "TV-Series",
"genre/netflix" to "Netflix",
"genre/zee5-tv-series" to "Zee5 TV Series",
)
override suspend fun loadLinks(
data: String,
isCasting: Boolean,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
): Boolean {
if (data.startsWith("{")) {
val loadData = tryParseJson<LinkData>(data)
val source = app.get(
url = "$directUrl/wp-json/dooplayer/v2/${loadData?.post}/${loadData?.type}/${loadData?.nume}",
referer = data,
headers = mapOf("X-Requested-With" to "XMLHttpRequest")
).parsed<ResponseHash>().embed_url.getIframe()
if (!source.contains("youtube")) loadExtractor(
source,
"$directUrl/",
subtitleCallback,
callback
)
} else {
var document = app.get(data).document
if (document.select("title").text() == "Just a moment...") {
document = app.get(data, interceptor = interceptor).document
}
val id = document.select("meta#dooplay-ajax-counter").attr("data-postid")
val type = if (data.contains("/movies/")) "movie" else "tv"
document.select("ul#playeroptionsul > li").map {
it.attr("data-nume")
}.apmap { nume ->
val source = app.get(
url = "$directUrl/wp-json/dooplayer/v2/${id}/${type}/${nume}",
referer = data,
headers = mapOf("X-Requested-With" to "XMLHttpRequest")
).parsed<ResponseHash>().embed_url.getIframe()
when {
!source.contains("youtube") -> loadExtractor(
source,
"$directUrl/",
subtitleCallback,
callback
)
else -> return@apmap
}
}
}
return true
}
private fun String.getIframe(): String {
return Jsoup.parse(this).select("iframe").attr("src")
}
data class LinkData(
val type: String? = null,
val post: String? = null,
val nume: String? = null,
)
data class ResponseHash(
@JsonProperty("embed_url") val embed_url: String,
@JsonProperty("type") val type: String?,
)
}

View file

@ -0,0 +1,283 @@
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.network.CloudflareKiller
import com.lagradost.cloudstream3.utils.*
import com.lagradost.cloudstream3.utils.AppUtils.toJson
import org.jsoup.nodes.Element
import java.net.URI
open class Movierulzhd : MainAPI() {
override var mainUrl = "https://movierulzvid.gold"
var directUrl = ""
override var name = "Movierulzhd"
override val hasMainPage = true
override var lang = "hi"
override val hasDownloadSupport = true
override val supportedTypes = setOf(
TvType.Movie,
TvType.TvSeries,
)
override val mainPage = mainPageOf(
"trending" to "Trending",
"movies" to "Movies",
"tvshows" to "TV Shows",
"genre/netflix" to "Netflix",
"genre/amazon-prime" to "Amazon Prime",
"genre/Zee5" to "Zee5",
"seasons" to "Season",
"episodes" to "Episode",
)
val interceptor = CloudflareKiller()
override suspend fun getMainPage(
page: Int,
request: MainPageRequest
): HomePageResponse {
var document = app.get("$mainUrl/${request.data}/page/$page").document
if (document.select("title").text() == "Just a moment...") {
document = app.get(request.data + page, interceptor = interceptor).document
}
val home =
document.select("div.items.normal article, div#archive-content article").mapNotNull {
it.toSearchResult()
}
return newHomePageResponse(request.name, home)
}
private fun getProperLink(uri: String): String {
return when {
uri.contains("/episodes/") -> {
var title = uri.substringAfter("$mainUrl/episodes/")
title = Regex("(.+?)-season").find(title)?.groupValues?.get(1).toString()
"$mainUrl/tvshows/$title"
}
uri.contains("/seasons/") -> {
var title = uri.substringAfter("$mainUrl/seasons/")
title = Regex("(.+?)-season").find(title)?.groupValues?.get(1).toString()
"$mainUrl/tvshows/$title"
}
else -> {
uri
}
}
}
private fun Element.toSearchResult(): SearchResponse? {
val title = this.selectFirst("h3 > a")?.text() ?: return null
val href = getProperLink(fixUrl(this.selectFirst("h3 > a")!!.attr("href")))
val posterUrl = fixUrlNull(this.select("div.poster img").last()?.attr("src"))
val quality = getQualityFromString(this.select("span.quality").text())
return newMovieSearchResponse(title, href, TvType.Movie) {
this.posterUrl = posterUrl
this.quality = quality
posterHeaders = interceptor.getCookieHeaders(mainUrl).toMap()
}
}
override suspend fun search(query: String): List<SearchResponse> {
val link = "$mainUrl/search/$query"
var document = app.get(link).document
if (document.select("title").text() == "Just a moment...") {
document = app.get(link, interceptor = interceptor).document
}
return document.select("div.result-item").map {
val title =
it.selectFirst("div.title > a")!!.text().replace(Regex("\\(\\d{4}\\)"), "").trim()
val href = getProperLink(it.selectFirst("div.title > a")!!.attr("href"))
val posterUrl = it.selectFirst("img")!!.attr("src").toString()
newMovieSearchResponse(title, href, TvType.TvSeries) {
this.posterUrl = posterUrl
posterHeaders = interceptor.getCookieHeaders(mainUrl).toMap()
}
}
}
override suspend fun load(url: String): LoadResponse {
val request = app.get(url)
var document = request.document
if (document.select("title").text() == "Just a moment...") {
document = app.get(url, interceptor = interceptor).document
}
directUrl = getBaseUrl(request.url)
val title =
document.selectFirst("div.data > h1")?.text()?.trim().toString()
val poster = fixUrlNull(document.select("div.poster img:last-child").attr("src"))
val tags = document.select("div.sgeneros > a").map { it.text() }
val year = Regex(",\\s?(\\d+)").find(
document.select("span.date").text().trim()
)?.groupValues?.get(1).toString().toIntOrNull()
val tvType = if (document.select("ul#section > li:nth-child(1)").text()
.contains("Episodes") || document.select("ul#playeroptionsul li span.title")
.text().contains(
Regex("Episode\\s+\\d+|EP\\d+|PE\\d+")
)
) TvType.TvSeries else TvType.Movie
val description = document.select("div.wp-content > p").text().trim()
val trailer = document.selectFirst("div.embed iframe")?.attr("src")
val rating =
document.selectFirst("span.dt_rating_vgs")?.text()?.toRatingInt()
val actors = document.select("div.persons > div[itemprop=actor]").map {
Actor(
it.select("meta[itemprop=name]").attr("content"),
it.select("img:last-child").attr("src")
)
}
val recommendations = document.select("div.owl-item").map {
val recName =
it.selectFirst("a")!!.attr("href").toString().removeSuffix("/").split("/").last()
val recHref = it.selectFirst("a")!!.attr("href")
val recPosterUrl = it.selectFirst("img")?.attr("src").toString()
newTvSeriesSearchResponse(recName, recHref, TvType.TvSeries) {
this.posterUrl = recPosterUrl
posterHeaders = interceptor.getCookieHeaders(url).toMap()
}
}
return if (tvType == TvType.TvSeries) {
val episodes = if (document.select("ul.episodios > li").isNotEmpty()) {
document.select("ul.episodios > li").map {
val href = it.select("a").attr("href")
val name = fixTitle(it.select("div.episodiotitle > a").text().trim())
val image = it.select("div.imagen > img").attr("src")
val episode =
it.select("div.numerando").text().replace(" ", "").split("-").last()
.toIntOrNull()
val season =
it.select("div.numerando").text().replace(" ", "").split("-").first()
.toIntOrNull()
Episode(
href,
name,
season,
episode,
image
)
}
} else {
document.select("ul#playeroptionsul > li").map {
val name = it.selectFirst("span.title")?.text()
val type = it.attr("data-type")
val post = it.attr("data-post")
val nume = it.attr("data-nume")
Episode(
LinkData(type, post, nume).toJson(),
name,
)
}
}
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)
posterHeaders = interceptor.getCookieHeaders(url).toMap()
}
} 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)
posterHeaders = interceptor.getCookieHeaders(url).toMap()
}
}
}
private fun getBaseUrl(url: String): String {
return URI(url).let {
"${it.scheme}://${it.host}"
}
}
override suspend fun loadLinks(
data: String,
isCasting: Boolean,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
): Boolean {
if (data.startsWith("{")) {
val loadData = AppUtils.tryParseJson<LinkData>(data)
val source = app.post(
url = "$directUrl/wp-admin/admin-ajax.php",
data = mapOf(
"action" to "doo_player_ajax",
"post" to "${loadData?.post}",
"nume" to "${loadData?.nume}",
"type" to "${loadData?.type}"
),
referer = data,
headers = mapOf("X-Requested-With" to "XMLHttpRequest")
).parsed<ResponseHash>().embed_url
if (!source.contains("youtube")) loadExtractor(source, data, subtitleCallback, callback)
} else {
var document = app.get(data).document
if (document.select("title").text() == "Just a moment...") {
document = app.get(data, interceptor = interceptor).document
}
val id = document.select("meta#dooplay-ajax-counter").attr("data-postid")
val type = if (data.contains("/movies/")) "movie" else "tv"
document.select("ul#playeroptionsul > li").map {
it.attr("data-nume")
}.apmap { nume ->
val source = app.post(
url = "$directUrl/wp-admin/admin-ajax.php",
data = mapOf(
"action" to "doo_player_ajax",
"post" to id,
"nume" to nume,
"type" to type
),
referer = data,
headers = mapOf("X-Requested-With" to "XMLHttpRequest")
).parsed<ResponseHash>().embed_url
when {
!source.contains("youtube") -> loadExtractor(
source,
data,
subtitleCallback,
callback
)
else -> return@apmap
}
}
}
return true
}
data class LinkData(
val type: String? = null,
val post: String? = null,
val nume: String? = null,
)
data class ResponseHash(
@JsonProperty("embed_url") val embed_url: String,
@JsonProperty("type") val type: String?,
)
}

View file

@ -0,0 +1,20 @@
package com.hexated
import com.lagradost.cloudstream3.plugins.CloudstreamPlugin
import com.lagradost.cloudstream3.plugins.Plugin
import android.content.Context
@CloudstreamPlugin
class MovierulzhdPlugin: Plugin() {
override fun load(context: Context) {
// All providers should be added in this manner. Please don't edit the providers list directly.
registerMainAPI(Movierulzhd())
registerMainAPI(Hdmovie2())
registerExtractorAPI(Sbflix())
registerExtractorAPI(Sbrulz())
registerExtractorAPI(Sbmiz())
registerExtractorAPI(Sbnmp())
registerExtractorAPI(Akamaicdn())
}
}

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

@ -0,0 +1,25 @@
// 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("Sora")
/**
* Status int as the following:
* 0: Down
* 1: Ok
* 2: Slow
* 3: Beta only
* */
status = 1 // will be 3 if unspecified
tvTypes = listOf(
"NSFW",
)
iconUrl = "https://www.google.com/s2/favicons?domain=nekopoi.care&sz=%size%"
}

View file

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

View file

@ -0,0 +1,32 @@
package com.hexated
import com.lagradost.cloudstream3.SubtitleFile
import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.utils.ExtractorApi
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.Qualities
open class ZippyShare : ExtractorApi() {
override val name = "ZippyShare"
override val mainUrl = "https://zippysha.re"
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).document
val video = res.selectFirst("a#download-url")?.attr("href")
callback.invoke(
ExtractorLink(
this.name,
this.name,
video ?: return,
"$mainUrl/",
Qualities.Unknown.value
)
)
}
}

View file

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

View file

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

View file

@ -0,0 +1,28 @@
// use an integer for version numbers
version = 8
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",
"Movie",
"OVA",
)
iconUrl = "https://www.google.com/s2/favicons?domain=neonime.watch&sz=%size%"
}

View file

@ -0,0 +1,195 @@
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.loadExtractor
import org.jsoup.nodes.Element
import java.net.URI
class NeonimeProvider : MainAPI() {
override var mainUrl = "https://neonime.ink"
private var baseUrl = mainUrl
override var name = "Neonime"
override val hasQuickSearch = false
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", true)) TvType.OVA
else if (t.contains("Movie", true)) TvType.AnimeMovie
else TvType.Anime
}
fun getStatus(t: String): ShowStatus {
return when (t) {
"Ended" -> ShowStatus.Completed
"OnGoing" -> ShowStatus.Ongoing
"Ongoing" -> ShowStatus.Ongoing
"In Production" -> ShowStatus.Ongoing
"Returning Series" -> ShowStatus.Ongoing
else -> ShowStatus.Completed
}
}
}
override val mainPage = mainPageOf(
"$mainUrl/episode/page/" to "Episode Terbaru",
"$mainUrl/tvshows/page/" to "Anime Terbaru",
"$mainUrl/movies/page/" to "Movie",
)
override suspend fun getMainPage(page: Int, request: MainPageRequest): HomePageResponse {
val req = app.get(request.data + page)
baseUrl = getBaseUrl(req.url)
val home = req.document.select("tbody tr,div.item").mapNotNull {
it.toSearchResult()
}
return newHomePageResponse(request.name, home)
}
private fun getProperAnimeLink(uri: String): String {
return when {
uri.contains("/episode") -> {
val title = uri.substringAfter("$baseUrl/episode/").let { tt ->
val fixTitle = Regex("(.*)-\\d{1,2}x\\d+").find(tt)?.groupValues?.getOrNull(1).toString()
when {
!tt.contains("-season") && !tt.contains(Regex("-1x\\d+")) && !tt.contains("one-piece") -> "$fixTitle-season-${Regex("-(\\d{1,2})x\\d+").find(tt)?.groupValues?.getOrNull(1).toString()}"
tt.contains("-special") -> fixTitle.replace(Regex("-x\\d+"), "")
!fixTitle.contains("-subtitle-indonesia") -> "$fixTitle-subtitle-indonesia"
else -> fixTitle
}
}
// title = when {
// title.contains("youkoso-jitsuryoku") && !title.contains("-season") -> title.replace("-e-", "-e-tv-")
// else -> title
// }
"$baseUrl/tvshows/$title"
}
else -> uri
}
}
private fun Element.toSearchResult(): AnimeSearchResponse? {
val title = this.selectFirst("td.bb a")?.ownText() ?: this.selectFirst("h2")?.text() ?: return null
val href = getProperAnimeLink(fixUrl(this.select("a").attr("href")))
val posterUrl = fixUrl(this.select("img").attr("data-src"))
val epNum = this.selectFirst("td.bb span")?.text()?.let { eps ->
Regex("Episode\\s?(\\d+)").find(eps)?.groupValues?.getOrNull(1)?.toIntOrNull()
}
return newAnimeSearchResponse(title, href, TvType.Anime) {
this.posterUrl = posterUrl
addSub(epNum)
}
}
override suspend fun search(query: String): List<SearchResponse> {
val document = app.get("$baseUrl/?s=$query").document
return document.select("div.item.episode-home").mapNotNull {
val title = it.selectFirst("div.judul-anime > span")!!.text()
val poster = it.select("img").attr("data-src").toString().trim()
val episodes = it.selectFirst("div.fixyear > h2.text-center")!!
.text().replace(Regex("\\D"), "").trim().toIntOrNull()
val tvType = getType(it.selectFirst("span.calidad2.episode")?.text().toString())
val href = getProperAnimeLink(fixUrl(it.selectFirst("a")!!.attr("href")))
newAnimeSearchResponse(title, href, tvType) {
this.posterUrl = poster
addSub(episodes)
}
}
}
override suspend fun load(url: String): LoadResponse {
val document = app.get(url).document
if (url.contains("movie") || url.contains("live-action")) {
val mTitle = document.selectFirst(".sbox > .data > h1[itemprop = name]")?.text().toString().replace("Subtitle Indonesia", "").trim()
val mPoster = document.selectFirst(".sbox > .imagen > .fix > img[itemprop = image]")?.attr("data-src")
val mTrailer = document.selectFirst("div.youtube_id iframe")?.attr("data-wpfc-original-src")?.substringAfterLast("html#")?.let{ "https://www.youtube.com/embed/$it"}
val year = document.selectFirst("a[href*=release-year]")!!.text().toIntOrNull()
val tracker = APIHolder.getTracker(listOf(mTitle),TrackerType.getTypes(TvType.Movie),year,true)
return newMovieLoadResponse(name = mTitle, url = url, type = TvType.Movie, dataUrl = url) {
posterUrl = tracker?.image ?: mPoster
backgroundPosterUrl = tracker?.cover
this.year = year
plot = document.select("div[itemprop = description]").text().trim()
rating = document.select("span[itemprop = ratingValue]").text().toIntOrNull()
tags = document.select("p.meta_dd > a").map { it.text() }
addTrailer(mTrailer)
addMalId(tracker?.malId)
addAniListId(tracker?.aniId?.toIntOrNull())
}
}
else {
val title = document.select("h1[itemprop = name]").text().replace("Subtitle Indonesia", "").trim()
val poster = document.selectFirst(".imagen > img")?.attr("data-src")
val trailer = document.selectFirst("div.youtube_id_tv iframe")?.attr("data-wpfc-original-src")?.substringAfterLast("html#")?.let{ "https://www.youtube.com/embed/$it"}
val year = document.select("#info a[href*=\"-year/\"]").text().toIntOrNull()
val episodes = document.select("ul.episodios > li").mapNotNull {
val link = fixUrl(it.selectFirst(".episodiotitle > a")!!.attr("href"))
val name = it.selectFirst(".episodiotitle > a")?.ownText().toString()
val episode = Regex("(\\d+[.,]?\\d*)").find(name)?.groupValues?.getOrNull(0)?.toIntOrNull()
Episode(link, episode = episode)
}.reversed()
val tracker = APIHolder.getTracker(listOf(title),TrackerType.getTypes(TvType.Anime),year,true)
return newAnimeLoadResponse(title, url, TvType.Anime) {
engName = title
posterUrl = tracker?.image ?: poster
backgroundPosterUrl = tracker?.cover
this.year = year
addEpisodes(DubStatus.Subbed, episodes)
showStatus = getStatus(document.select("div.metadatac > span").last()!!.text().trim())
plot = document.select("div[itemprop = description] > p").text().trim()
tags = document.select("#info a[href*=\"-genre/\"]").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 source = if(data.contains("movie") || data.contains("live-action")) {
app.get(data).document.select("#player2-1 > div[id*=div]").mapNotNull {
fixUrl(it.select("iframe").attr("data-src"))
}
} else {
app.get(data).document.select(".player2 > .embed2 > div[id*=player]").mapNotNull {
fixUrl(it.select("iframe").attr("data-src"))
}
}
source.apmap {
loadExtractor(it, data, subtitleCallback, callback)
}
return true
}
private fun getBaseUrl(url: String): String {
return URI(url).let {
"${it.scheme}://${it.host}"
}
}
}

27
Nimegami/build.gradle.kts Normal file
View file

@ -0,0 +1,27 @@
// 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(
"AnimeMovie",
"Anime",
"OVA",
)
iconUrl = "https://www.google.com/s2/favicons?domain=nimegami.id&sz=%size%"
}

View file

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

View file

@ -0,0 +1,55 @@
package com.hexated
import com.fasterxml.jackson.annotation.JsonProperty
import com.lagradost.cloudstream3.SubtitleFile
import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.utils.ExtractorApi
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.Qualities
open class Mitedrive : ExtractorApi() {
override val name = "Mitedrive"
override val mainUrl = "https://mitedrive.com"
override val requiresReferer = false
override suspend fun getUrl(
url: String,
referer: String?,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
) {
val id = url.substringAfterLast("/")
val video = app.post(
"$mainUrl/api/generate",
referer = "$mainUrl/",
data = mapOf(
"short_url" to id
)
).parsedSafe<Responses>()?.data?.url
callback.invoke(
ExtractorLink(
this.name,
this.name,
video ?: return,
"$mainUrl/",
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",
"Sec-Fetch-Dest" to "video",
"Sec-Fetch-Mode" to "no-cors",
)
)
)
}
data class Data(
@JsonProperty("url") val url: String? = null,
)
data class Responses(
@JsonProperty("data") val data: Data? = null,
)
}

View file

@ -0,0 +1,208 @@
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.LoadResponse.Companion.addTrailer
import com.lagradost.cloudstream3.utils.*
import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
import org.jsoup.nodes.Element
import org.jsoup.select.Elements
import java.net.URI
class Nimegami : MainAPI() {
override var mainUrl = "https://nimegami.id"
override var name = "Nimegami"
override val hasMainPage = true
override var lang = "id"
override val supportedTypes = setOf(
TvType.Anime,
TvType.AnimeMovie,
TvType.OVA
)
companion object {
fun getType(t: String): TvType {
return 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 {
return when {
t?.contains("On-Going", true) == true -> ShowStatus.Ongoing
else -> ShowStatus.Completed
}
}
}
override val mainPage = mainPageOf(
"" to "Updated Anime",
"/type/tv" to "Anime",
"/type/movie" to "Movie",
"/type/ona" to "ONA",
"/type/live-action" to "Live Action",
)
override suspend fun getMainPage(
page: Int,
request: MainPageRequest
): HomePageResponse {
val document = app.get("$mainUrl${request.data}/page/$page").document
val home = document.select("div.post-article article, div.archive article").mapNotNull {
it.toSearchResult()
}
return newHomePageResponse(
list = HomePageList(
name = request.name,
list = home,
isHorizontalImages = request.name != "Updated Anime"
),
hasNext = true
)
}
private fun Element.toSearchResult(): AnimeSearchResponse? {
val href = fixUrl(this.selectFirst("a")!!.attr("href"))
val title = this.selectFirst("h2 a")?.text() ?: return null
val posterUrl = (this.selectFirst("noscript img") ?: this.selectFirst("img"))?.attr("src")
val episode = this.selectFirst("ul li:contains(Episode), div.eps-archive")?.ownText()
?.filter { it.isDigit() }?.toIntOrNull()
return newAnimeSearchResponse(title, href, TvType.Anime) {
this.posterUrl = posterUrl
addSub(episode)
}
}
override suspend fun search(query: String): List<SearchResponse> {
return app.get("$mainUrl/?s=$query&post_type=post").document.select("div.archive article")
.mapNotNull {
it.toSearchResult()
}
}
override suspend fun load(url: String): LoadResponse {
val document = app.get(url).document
val table = document.select("div#Info table tbody")
val title = table.getContent("Judul :").text()
val poster = document.selectFirst("div.coverthumbnail img")?.attr("src")
val bgPoster = document.selectFirst("div.thumbnail-a img")?.attr("src")
val tags = table.getContent("Kategori").select("a").map { it.text() }
val year = table.getContent("Musim / Rilis").text().filter { it.isDigit() }.toIntOrNull()
val status = getStatus(document.selectFirst("h1[itemprop=headline]")?.text())
val type = getType(table.getContent("Type").text())
val description = document.select("div#Sinopsis p").text().trim()
val trailer = document.selectFirst("div#Trailer iframe")?.attr("src")
val episodes = document.select("div.list_eps_stream li")
.mapNotNull {
val episode = Regex("Episode\\s?(\\d+)").find(it.text())?.groupValues?.getOrNull(0)?.toIntOrNull()
val link = it.attr("data")
Episode(link, episode = episode)
}
val recommendations = document.select("div#randomList > a").mapNotNull {
val epHref = it.attr("href")
val epTitle = it.select("h5.sidebar-title-h5.px-2.py-2").text()
val epPoster = it.select(".product__sidebar__view__item.set-bg").attr("data-setbg")
newAnimeSearchResponse(epTitle, epHref, TvType.Anime) {
this.posterUrl = epPoster
addDubStatus(dubExist = false, subExist = true)
}
}
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 ?: bgPoster
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 {
tryParseJson<ArrayList<Sources>>(base64Decode(data))?.map { sources ->
sources.url?.apmap { url ->
loadFixedExtractor(url.fixIframe(), sources.format, "$mainUrl/", subtitleCallback, callback)
}
}
return true
}
private suspend fun loadFixedExtractor(
url: String,
quality: String?,
referer: String? = null,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
) {
loadExtractor(url, referer, subtitleCallback) { link ->
callback.invoke(
ExtractorLink(
link.name,
link.name,
link.url,
link.referer,
getQualityFromName(quality),
link.type,
link.headers,
link.extractorData
)
)
}
}
private fun getBaseUrl(url: String): String {
return URI(url).let {
"${it.scheme}://${it.host}"
}
}
private fun Elements.getContent(css: String) : Elements {
return this.select("tr:contains($css) td:last-child")
}
private fun String.fixIframe() : String {
val url = base64Decode(this.substringAfter("url=").substringAfter("id="))
val host = getBaseUrl(url)
return when {
url.contains("hxfile") -> {
val id = url.substringAfterLast("/")
"$host/embed-$id.html"
}
else -> fixUrl(url)
}
}
data class Sources(
@JsonProperty("format") val format: String? = null,
@JsonProperty("url") val url: ArrayList<String>? = arrayListOf(),
)
}

View file

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

View file

@ -0,0 +1,27 @@
// use an integer for version numbers
version = 17
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=nontonanimeid.site&sz=%size%"
}

View file

@ -0,0 +1,257 @@
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.LoadResponse.Companion.addTrailer
import com.lagradost.cloudstream3.extractors.Hxfile
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.loadExtractor
import org.jsoup.Jsoup
import org.jsoup.nodes.Element
import java.net.URI
class NontonAnimeIDProvider : MainAPI() {
override var mainUrl = "https://nontonanimeid.top"
override var name = "NontonAnimeID"
override val hasQuickSearch = false
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 when {
t.contains("TV",true) -> TvType.Anime
t.contains("Movie",true) -> TvType.AnimeMovie
else -> TvType.OVA
}
}
fun getStatus(t: String): ShowStatus {
return when (t) {
"Finished Airing" -> ShowStatus.Completed
"Currently Airing" -> ShowStatus.Ongoing
else -> ShowStatus.Completed
}
}
}
override suspend fun getMainPage(page: Int, request : MainPageRequest): HomePageResponse {
val document = app.get(mainUrl).document
val homePageList = ArrayList<HomePageList>()
document.select("section#postbaru").forEach { block ->
val header = block.selectFirst("h2")!!.text().trim()
val animes = block.select("article.animeseries").mapNotNull {
it.toSearchResult()
}
if (animes.isNotEmpty()) homePageList.add(HomePageList(header, animes))
}
document.select("aside#sidebar_right > div.side").forEach { block ->
val header = block.selectFirst("h3")!!.ownText().trim()
val animes = block.select("ul li.fullwdth").mapNotNull {
it.toSearchResultPopular()
}
if (animes.isNotEmpty()) homePageList.add(HomePageList(header, animes))
}
return HomePageResponse(homePageList)
}
private fun Element.toSearchResult(): AnimeSearchResponse? {
val href = fixUrl(this.selectFirst("a")!!.attr("href"))
val title = this.selectFirst("h3.title")?.text() ?: return null
val posterUrl = fixUrl(this.select("img").attr("data-src"))
return newAnimeSearchResponse(title, href, TvType.Anime) {
this.posterUrl = posterUrl
addDubStatus(dubExist = false, subExist = true)
}
}
private fun Element.toSearchResultPopular(): AnimeSearchResponse? {
val href = fixUrl(this.selectFirst("a")!!.attr("href"))
val title = this.selectFirst("h4")?.text()?.trim() ?: return null
val posterUrl = fixUrl(this.select("img").attr("data-src"))
return newAnimeSearchResponse(title, href, TvType.Anime) {
this.posterUrl = posterUrl
addDubStatus(dubExist = false, subExist = true)
}
}
override suspend fun search(query: String): List<SearchResponse> {
val link = "$mainUrl/?s=$query"
val document = app.get(link).document
return document.select(".result > ul > li").mapNotNull {
val title = it.selectFirst("h2")!!.text().trim()
val poster = it.selectFirst("img")!!.attr("src")
val tvType = getType(
it.selectFirst(".boxinfores > span.typeseries")!!.text().toString()
)
val href = fixUrl(it.selectFirst("a")!!.attr("href"))
newAnimeSearchResponse(title, href, tvType) {
this.posterUrl = poster
addDubStatus(dubExist = false, subExist = true)
}
}
}
override suspend fun load(url: String): LoadResponse? {
val fixUrl = if (url.contains("/anime/")) {
url
} else {
app.get(url).document.selectFirst("div.nvs.nvsc a")?.attr("href")
}
val req = app.get(fixUrl ?: return null)
mainUrl = getBaseUrl(req.url)
val document = req.document
val title = document.selectFirst("h1.entry-title.cs")!!.text().removeSurrounding("Nonton Anime", "Sub Indo").trim()
val poster = document.selectFirst(".poster > img")?.attr("data-src")
val tags = document.select(".tagline > a").map { it.text() }
val year = Regex("\\d, (\\d*)").find(
document.select(".bottomtitle > span:nth-child(5)").text()
)?.groupValues?.get(1)?.toIntOrNull()
val status = getStatus(
document.select("span.statusseries").text().trim()
)
val type = getType(document.select("span.typeseries").text().trim().lowercase())
val rating = document.select("span.nilaiseries").text().trim().toIntOrNull()
val description = document.select(".entry-content.seriesdesc > p").text().trim()
val trailer = document.selectFirst("a.trailerbutton")?.attr("href")
val episodes = if (document.select("button.buttfilter").isNotEmpty()) {
val id = document.select("input[name=series_id]").attr("value")
val numEp =
document.selectFirst(".latestepisode > a")?.text()?.replace(Regex("\\D"), "")
.toString()
Jsoup.parse(
app.post(
url = "$mainUrl/wp-admin/admin-ajax.php",
data = mapOf(
"misha_number_of_results" to numEp,
"misha_order_by" to "date-DESC",
"action" to "mishafilter",
"series_id" to id
)
).parsed<EpResponse>().content
).select("li").map {
val episode = Regex("Episode\\s?(\\d+)").find(
it.selectFirst("a")?.text().toString()
)?.groupValues?.getOrNull(0) ?: it.selectFirst("a")?.text()
val link = fixUrl(it.selectFirst("a")!!.attr("href"))
Episode(link, episode = episode?.toIntOrNull())
}.reversed()
} else {
document.select("ul.misha_posts_wrap2 > li").map {
val episode = Regex("Episode\\s?(\\d+)").find(
it.selectFirst("a")?.text().toString()
)?.groupValues?.getOrNull(0) ?: it.selectFirst("a")?.text()
val link = it.select("a").attr("href")
Episode(link, episode = episode?.toIntOrNull())
}.reversed()
}
val recommendations = document.select(".result > li").mapNotNull {
val epHref = it.selectFirst("a")!!.attr("href")
val epTitle = it.selectFirst("h3")!!.text()
val epPoster = it.select(".top > img").attr("data-src")
newAnimeSearchResponse(epTitle, epHref, TvType.Anime) {
this.posterUrl = epPoster
addDubStatus(dubExist = false, subExist = true)
}
}
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
this.rating = rating
plot = description
addTrailer(trailer)
this.tags = tags
this.recommendations = recommendations
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
val sources = ArrayList<String>()
document.select(".container1 > ul > li:not(.boxtab)").apmap {
val dataPost = it.attr("data-post")
val dataNume = it.attr("data-nume")
val dataType = it.attr("data-type")
val iframe = app.post(
url = "$mainUrl/wp-admin/admin-ajax.php",
data = mapOf(
"action" to "player_ajax",
"post" to dataPost,
"nume" to dataNume,
"type" to dataType
),
referer = data,
headers = mapOf("X-Requested-With" to "XMLHttpRequest")
).document.select("iframe").attr("src")
sources.add(fixUrl(iframe))
}
sources.apmap {
loadExtractor(it, "$mainUrl/", subtitleCallback, callback)
}
return true
}
private fun getBaseUrl(url: String): String {
return URI(url).let {
"${it.scheme}://${it.host}"
}
}
private data class EpResponse(
@JsonProperty("posts") val posts: String?,
@JsonProperty("max_page") val max_page: Int?,
@JsonProperty("found_posts") val found_posts: Int?,
@JsonProperty("content") val content: String
)
}
class KotakAnimeid2 : Hxfile() {
override val name = "KotakAnimeid2"
override val mainUrl = "https://embed2.kotakanimeid.com"
override val requiresReferer = true
}

View file

@ -0,0 +1,27 @@
// use an integer for version numbers
version = 24
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=oploverz.care&sz=%size%"
}

View file

@ -0,0 +1,45 @@
package com.hexated
import com.lagradost.cloudstream3.SubtitleFile
import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.utils.*
open class Qiwi : ExtractorApi() {
override val name = "Qiwi"
override val mainUrl = "https://qiwi.gg"
override val requiresReferer = true
override suspend fun getUrl(
url: String,
referer: String?,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
) {
val document = app.get(url, referer = referer).document
val title = document.select("title").text()
val source = document.select("video source").attr("src")
callback.invoke(
ExtractorLink(
this.name,
this.name,
source,
"$mainUrl/",
getIndexQuality(title),
headers = mapOf(
"Accept" to "video/webm,video/ogg,video/*;q=0.9,application/ogg;q=0.7,audio/*;q=0.6,*/*;q=0.5",
"Range" to "bytes=0-",
"Sec-Fetch-Dest" to "video",
"Sec-Fetch-Mode" to "no-cors",
)
)
)
}
private fun getIndexQuality(str: String): Int {
return Regex("(\\d{3,4})[pP]").find(str)?.groupValues?.getOrNull(1)?.toIntOrNull()
?: Qualities.Unknown.value
}
}

View file

@ -0,0 +1,228 @@
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.utils.*
import org.jsoup.nodes.Element
class OploverzProvider : MainAPI() {
override var mainUrl = "https://oploverz.red"
override var name = "Oploverz"
override val hasMainPage = true
override var lang = "id"
override val hasDownloadSupport = true
override val supportedTypes = setOf(
TvType.Anime,
TvType.AnimeMovie,
TvType.OVA
)
companion object {
const val acefile = "https://acefile.co"
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
"Completed" -> ShowStatus.Completed
"Currently Airing" -> ShowStatus.Ongoing
"Ongoing" -> ShowStatus.Ongoing
else -> ShowStatus.Completed
}
}
}
override val mainPage = mainPageOf(
"update" to "Latest Update",
"latest" to "Latest Added",
"popular" to "Popular Anime",
"rating" to "Top Rated",
)
override suspend fun getMainPage(
page: Int,
request: MainPageRequest
): HomePageResponse {
val document = app.get("$mainUrl/anime-list/page/$page/?title&order=${request.data}&status&type").document
val home = document.select("div.relat > article").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")) -> Regex("(.+)-episode").find(
title
)?.groupValues?.get(1).toString()
(title.contains("-movie")) -> Regex("(.+)-movie").find(title)?.groupValues?.get(
1
).toString()
else -> title
}
"$mainUrl/anime/$title"
}
}
private fun Element.toSearchResult(): AnimeSearchResponse? {
val title = this.selectFirst("div.title")?.text()?.trim() ?: return null
val href = getProperAnimeLink(this.selectFirst("a")!!.attr("href"))
val posterUrl = this.select("img[itemprop=image]").attr("src").toString()
val type = getType(this.select("div.type").text().trim())
val epNum =
this.selectFirst("span.episode")?.ownText()?.replace(Regex("\\D"), "")?.trim()
?.toIntOrNull()
return newAnimeSearchResponse(title, href, type) {
this.posterUrl = posterUrl
addSub(epNum)
}
}
override suspend fun search(query: String): List<SearchResponse> {
val anime = mutableListOf<SearchResponse>()
(1..2).forEach { page ->
val link = "$mainUrl/page/$page/?s=$query"
val document = app.get(link).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() ?: ""
val type = getType(document.selectFirst("div.alternati span.type")?.text() ?: "")
val year = document.selectFirst("div.alternati a")?.text()?.filter { it.isDigit() }?.toIntOrNull()
val episodes = document.select("div.lstepsiode.listeps ul li").mapNotNull {
val header = it.selectFirst("a") ?: return@mapNotNull null
val episode = header.text().trim().toIntOrNull()
val link = fixUrl(header.attr("href"))
Episode(link, episode = episode)
}.reversed()
val tracker = APIHolder.getTracker(listOf(title),TrackerType.getTypes(type),year,true)
return newAnimeLoadResponse(title, url, type) {
posterUrl = tracker?.image ?: document.selectFirst("div.thumb > img")?.attr("src")
backgroundPosterUrl = tracker?.cover
this.year = year
addEpisodes(DubStatus.Subbed, episodes)
showStatus =
getStatus(
document.selectFirst("div.alternati span:nth-child(2)")?.text()?.trim()
)
plot = document.selectFirst("div.entry-content > p")?.text()?.trim()
this.tags =
document.select("div.genre-info 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 = app.get(data).document
argamap(
{
document.select("div#server ul li div").apmap {
val dataPost = it.attr("data-post")
val dataNume = it.attr("data-nume")
val dataType = it.attr("data-type")
val iframe = app.post(
url = "$mainUrl/wp-admin/admin-ajax.php",
data = mapOf(
"action" to "player_ajax",
"post" to dataPost,
"nume" to dataNume,
"type" to dataType
),
referer = data,
headers = mapOf("X-Requested-With" to "XMLHttpRequest")
).document.select("iframe").attr("src")
loadExtractor(fixedIframe(iframe), "$mainUrl/", subtitleCallback, callback)
}
},
{
document.select("div#download tr").map { el ->
el.select("a").apmap {
loadFixedExtractor(fixedIframe(it.attr("href")), el.select("strong").text(), "$mainUrl/", subtitleCallback, callback)
}
}
}
)
return true
}
private suspend fun loadFixedExtractor(
url: String,
name: 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,
name.fixQuality(),
link.type,
link.headers,
link.extractorData
)
)
}
}
private fun String.fixQuality() : Int {
return when(this) {
"MP4HD" -> Qualities.P720.value
"FULLHD" -> Qualities.P1080.value
else -> Regex("(\\d{3,4})p").find(this)?.groupValues?.get(1)?.toIntOrNull() ?: Qualities.Unknown.value
}
}
private fun fixedIframe(url: String): String {
val id = Regex("""(?:/f/|/file/)(\w+)""").find(url)?.groupValues?.getOrNull(1)
return when {
url.startsWith(acefile) -> "${acefile}/player/$id"
else -> fixUrl(url)
}
}
}

View file

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

View file

@ -0,0 +1,27 @@
// 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",
"Anime",
"OVA",
)
iconUrl = "https://www.google.com/s2/favicons?domain=otakudesu.watch&sz=%size%"
}

View file

@ -0,0 +1,284 @@
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.extractors.JWPlayer
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.Jsoup
import org.jsoup.nodes.Element
class OtakudesuProvider : MainAPI() {
override var mainUrl = "https://otakudesu.lol"
override var name = "Otakudesu"
override val hasMainPage = true
override var lang = "id"
override val hasDownloadSupport = true
override val supportedTypes = setOf(
TvType.Anime,
TvType.AnimeMovie,
TvType.OVA
)
companion object {
const val acefile = "https://acefile.co"
val mirrorBlackList = arrayOf(
"Mega",
"MegaUp",
"Otakufiles",
)
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
}
}
}
override val mainPage = mainPageOf(
"$mainUrl/ongoing-anime/page/" to "Anime Ongoing",
"$mainUrl/complete-anime/page/" to "Anime Completed"
)
override suspend fun getMainPage(
page: Int,
request: MainPageRequest
): HomePageResponse {
val document = app.get(request.data + page).document
val home = document.select("div.venz > ul > li").mapNotNull {
it.toSearchResult()
}
return newHomePageResponse(request.name, home)
}
private fun Element.toSearchResult(): AnimeSearchResponse? {
val title = this.selectFirst("h2.jdlflm")?.text()?.trim() ?: return null
val href = this.selectFirst("a")!!.attr("href")
val posterUrl = this.select("div.thumbz > img").attr("src").toString()
val epNum = this.selectFirst("div.epz")?.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> {
return app.get("$mainUrl/?s=$query&post_type=anime").document.select("ul.chivsrc > li")
.map {
val title = it.selectFirst("h2 > a")!!.ownText().trim()
val href = it.selectFirst("h2 > a")!!.attr("href")
val posterUrl = it.selectFirst("img")!!.attr("src").toString()
newAnimeSearchResponse(title, href, TvType.Anime) {
this.posterUrl = posterUrl
}
}
}
override suspend fun load(url: String): LoadResponse {
val document = app.get(url).document
val title = document.selectFirst("div.infozingle > p:nth-child(1) > span")?.ownText()
?.replace(":", "")?.trim().toString()
val poster = document.selectFirst("div.fotoanime > img")?.attr("src")
val tags = document.select("div.infozingle > p:nth-child(11) > span > a").map { it.text() }
val type = getType(document.selectFirst("div.infozingle > p:nth-child(5) > span")?.ownText()
?.replace(":", "")?.trim() ?: "tv")
val year = Regex("\\d, (\\d*)").find(
document.select("div.infozingle > p:nth-child(9) > span").text()
)?.groupValues?.get(1)?.toIntOrNull()
val status = getStatus(
document.selectFirst("div.infozingle > p:nth-child(6) > span")!!.ownText()
.replace(":", "")
.trim()
)
val description = document.select("div.sinopc > p").text()
val episodes = document.select("div.episodelist")[1].select("ul > li").mapNotNull {
val name = it.selectFirst("a")?.text() ?: return@mapNotNull null
val episode = Regex("Episode\\s?(\\d+)").find(name)?.groupValues?.getOrNull(0)
?: it.selectFirst("a")?.text()
val link = fixUrl(it.selectFirst("a")!!.attr("href"))
Episode(link, episode = episode?.toIntOrNull())
}.reversed()
val recommendations =
document.select("div.isi-recommend-anime-series > div.isi-konten").map {
val recName = it.selectFirst("span.judul-anime > a")!!.text()
val recHref = it.selectFirst("a")!!.attr("href")
val recPosterUrl = it.selectFirst("a > img")?.attr("src").toString()
newAnimeSearchResponse(recName, recHref, TvType.Anime) {
this.posterUrl = recPosterUrl
}
}
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
addMalId(tracker?.malId)
addAniListId(tracker?.aniId?.toIntOrNull())
}
}
data class ResponseSources(
@JsonProperty("id") val id: String,
@JsonProperty("i") val i: String,
@JsonProperty("q") val q: String,
)
data class ResponseData(
@JsonProperty("data") val data: String
)
override suspend fun loadLinks(
data: String,
isCasting: Boolean,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
): Boolean {
val document = app.get(data).document
argamap(
{
val scriptData =
document.select("script:containsData(action:)").lastOrNull()?.data()
val token =
scriptData?.substringAfter("{action:\"")?.substringBefore("\"}").toString()
val nonce =
app.post("$mainUrl/wp-admin/admin-ajax.php", data = mapOf("action" to token))
.parsed<ResponseData>().data
val action =
scriptData?.substringAfter(",action:\"")?.substringBefore("\"}").toString()
val mirrorData = document.select("div.mirrorstream > ul > li").mapNotNull {
base64Decode(it.select("a").attr("data-content"))
}.toString()
tryParseJson<List<ResponseSources>>(mirrorData)?.apmap { res ->
val id = res.id
val i = res.i
val q = res.q
val sources = Jsoup.parse(
base64Decode(
app.post(
"${mainUrl}/wp-admin/admin-ajax.php", data = mapOf(
"id" to id,
"i" to i,
"q" to q,
"nonce" to nonce,
"action" to action
)
).parsed<ResponseData>().data
)
).select("iframe").attr("src")
loadCustomExtractor(sources, data, subtitleCallback, callback, getQuality(q))
}
},
{
document.select("div.download li").map { ele ->
val quality = getQuality(ele.select("strong").text())
ele.select("a").map {
it.attr("href") to it.text()
}.filter {
!inBlacklist(it.first) && quality != Qualities.P360.value
}.apmap {
val link = app.get(it.first, referer = "$mainUrl/").url
loadCustomExtractor(
fixedIframe(link),
data,
subtitleCallback,
callback,
quality
)
}
}
}
)
return true
}
private suspend fun loadCustomExtractor(
url: String,
referer: String? = null,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit,
quality: Int = Qualities.Unknown.value,
) {
loadExtractor(url, referer, subtitleCallback) { link ->
callback.invoke(
ExtractorLink(
link.name,
link.name,
link.url,
link.referer,
quality,
link.type,
link.headers,
link.extractorData
)
)
}
}
private fun fixedIframe(url: String): String {
return when {
url.startsWith(acefile) -> {
val id = Regex("""(?:/f/|/file/)(\w+)""").find(url)?.groupValues?.getOrNull(1)
"${acefile}/player/$id"
}
else -> fixUrl(url)
}
}
private fun inBlacklist(host: String?): Boolean {
return mirrorBlackList.any { it.equals(host, true) }
}
private fun getQuality(str: String?): Int {
return Regex("(\\d{3,4})[pP]").find(str ?: "")?.groupValues?.getOrNull(1)?.toIntOrNull()
?: Qualities.Unknown.value
}
}
class Moedesu : JWPlayer() {
override val name = "Moedesu"
override val mainUrl = "https://desustream.me/moedesu/"
}
class DesuBeta : JWPlayer() {
override val name = "DesuBeta"
override val mainUrl = "https://desustream.me/beta/"
}

View file

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

28
Phim1080/build.gradle.kts Normal file
View file

@ -0,0 +1,28 @@
// use an integer for version numbers
version = 2
cloudstream {
language = "vi"
// All of these properties are optional, you can safely remove them
description = "Xem Phim Online Chất Lượng Cao"
authors = listOf("TuaSan")
/**
* 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=xem1080.com"
}

View file

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

View file

@ -0,0 +1,267 @@
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.*
import com.lagradost.cloudstream3.utils.ExtractorLink
import org.jsoup.nodes.Element
class Phim1080Provider : MainAPI() {
override var mainUrl = "https://phimnhanh2.com"
override var name = "Phim1080"
override val hasMainPage = true
override var lang = "vi"
override val hasDownloadSupport = true
override val supportedTypes = setOf(
TvType.Movie,
TvType.TvSeries,
TvType.Anime,
TvType.AsianDrama
)
private fun decodeString(e: String, t: Int): String {
var a = ""
for (i in 0 until e.length) {
val r = e[i].code
val o = r xor t
a += o.toChar()
}
return a
}
override val mainPage = mainPageOf(
"$mainUrl/phim-de-cu?page=" to "Phim Đề Cử",
"$mainUrl/the-loai/hoat-hinh?page=" to "Phim Hoạt Hình",
"$mainUrl/phim-chieu-rap?page=" to "Phim Chiếu Rạp",
"$mainUrl/phim-bo?page=" to "Phim Bộ",
"$mainUrl/phim-le?page=" to "Phim Lẻ",
"$mainUrl/bang-xep-hang?page=" to "Bảng Xếp Hạng",
"$mainUrl/bo-suu-tap/disney-plus?page=" to "Disney+",
"$mainUrl/bo-suu-tap/netflix-original?page=" to "Netflix",
"$mainUrl/hom-nay-xem-gi?page=" to "Hôm Nay Xem Gì",
"$mainUrl/phim-sap-chieu?page=" to "Phim Sắp Chiếu",
)
override suspend fun getMainPage(
page: Int,
request: MainPageRequest
): HomePageResponse {
val document = app.get(request.data + page).document
val home = document.select("div.tray-item").mapNotNull {
it.toSearchResult()
}
return newHomePageResponse(
list = HomePageList(
name = request.name,
list = home,
),
hasNext = true
)
}
private fun Element.toSearchResult(): SearchResponse {
val title = this.selectFirst("div.tray-item-title")?.text()?.trim().toString()
val href = fixUrl(this.selectFirst("a")!!.attr("href"))
val posterUrl = this.selectFirst("img")!!.attr("data-src")
val temp = this.select("div.tray-film-likes").text()
return if (temp.contains("/")) {
val episode = Regex("((\\d+)\\s)").find(temp)?.groupValues?.map { num ->
num.replace(Regex("\\s"), "")
}?.distinct()?.firstOrNull()?.toIntOrNull()
newAnimeSearchResponse(title, href, TvType.TvSeries) {
this.posterUrl = posterUrl
addSub(episode)
}
} else {
val quality = this.select("span.tray-item-quality").text().replace("FHD", "HD").trim()
newMovieSearchResponse(title, href, TvType.Movie) {
this.posterUrl = posterUrl
addQuality(quality)
}
}
}
override suspend fun search(query: String): List<SearchResponse> {
val link = "$mainUrl/tim-kiem/$query"
val document = app.get(link).document
return document.select("div.tray-item").map {
it.toSearchResult()
}
}
override suspend fun load( url: String ): LoadResponse {
val document = app.get(
url = url,
referer = "$mainUrl/",
headers = mapOf(
"Sec-Ch-Ua-Mobile" to "?1",
"Sec-Ch-Ua-Platform" to "\"Android\"",
"User-Agent" to "Mozilla/5.0 (Linux; Android 10; SM-G981B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.162 Mobile Safari/537.36 Edg/114.0.0.0",
)
).document
val fId = document.select("div.container").attr("data-id")
val filmInfo = app.get(
"$mainUrl/api/v2/films/$fId",
referer = url,
headers = mapOf(
"Content-Type" to "application/json",
"X-Requested-With" to "XMLHttpRequest"
)
).parsedSafe<filmInfo>()
val title = filmInfo?.name?.trim().toString()
val poster = filmInfo?.thumbnail
val background = filmInfo?.poster
val slug = filmInfo?.slug
val link = "$mainUrl/$slug"
val tags = document.select("div.film-content div.film-info-genre:nth-child(7) a").map { it.text() }
val year = filmInfo?.year
val tvType = if (document.select("div.episode-group-tab").isNotEmpty()) TvType.TvSeries else TvType.Movie
val description = document.select("div.film-info-description").text().trim()
val comingSoon = document.select("button.direction-trailer").isNotEmpty()
val trailerCode = filmInfo?.trailer?.original?.id
val trailer = "https://www.youtube.com/embed/$trailerCode"
val recommendations = document.select("section.tray.index.related div.tray-content.carousel div.tray-item").map {
it.toSearchResult()
}
return if (tvType == TvType.TvSeries) {
val epsInfo = app.get(
"$mainUrl/api/v2/films/$fId/episodes?sort=name",
referer = link,
headers = mapOf(
"Content-Type" to "application/json",
"X-Requested-With" to "XMLHttpRequest",
)
).parsedSafe<MediaDetailEpisodes>()?.eps?.map { ep ->
Episode(
data = fixUrl(ep.link.toString()),
name = ep.detailname,
episode = ep.episodeNumber,
)
} ?: listOf()
newTvSeriesLoadResponse(title, url, TvType.TvSeries, epsInfo) {
this.posterUrl = poster
this.backgroundPosterUrl = background
this.year = year
this.plot = description
this.tags = tags
this.comingSoon = comingSoon
addTrailer(trailer)
this.recommendations = recommendations
}
} else {
newMovieLoadResponse(title, url, TvType.Movie, link) {
this.posterUrl = poster
this.backgroundPosterUrl = background
this.year = year
this.plot = description
this.tags = tags
this.comingSoon = comingSoon
addTrailer(trailer)
this.recommendations = recommendations
}
}
}
override suspend fun loadLinks(
data: String,
isCasting: Boolean,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
): Boolean {
val document = app.get(data).document
val fId = document.select("div.container").attr("data-id")
val epId = document.select("div.container").attr("data-episode-id")
val doc = app.get(
"$mainUrl/api/v2/films/$fId/episodes/$epId",
referer = data,
headers = mapOf(
"Content-Type" to "application/json",
"cookie" to "phimnhanh=%3D",
"X-Requested-With" to "XMLHttpRequest"
)
)
val optEncode = if (doc.text.indexOf("\"opt\":\"") != -1) {
doc.text.substringAfter("\"opt\":\"").substringBefore("\"},")
} else { "" }
val opt = decodeString(optEncode as String, 69).replace("0uut$", "_").replace("index.m3u8", "3000k/hls/mixed.m3u8")
val hlsEncode = if (doc.text.indexOf(":{\"hls\":\"") != -1) {
doc.text.substringAfter(":{\"hls\":\"").substringBefore("\"},")
} else { "" }
val hls = decodeString(hlsEncode as String, 69)
val fb = if (doc.text.indexOf("\"fb\":[{\"src\":\"") != -1) {
doc.text.substringAfter("\"fb\":[{\"src\":\"").substringBefore("\",").replace("\\", "")
} else { "" }
listOfNotNull(
if (hls.contains(".m3u8")) {Triple("$hls", "HS", true)} else null,
if (fb.contains(".mp4")) {Triple("$fb", "FB", false)} else null,
if (opt.contains(".m3u8")) {Triple("$opt", "OP", true)} else null,
).apmap { (link, source, isM3u8) ->
safeApiCall {
callback.invoke(
ExtractorLink(
source,
source,
link,
referer = data,
quality = Qualities.Unknown.value,
isM3u8,
)
)
}
}
val subId = doc.parsedSafe<Media>()?.subtitle?.vi
val isSubIdEmpty = subId.isNullOrBlank()
if (!isSubIdEmpty) {
subtitleCallback.invoke(
SubtitleFile(
"Vietnamese",
"$mainUrl/subtitle/$subId.vtt"
)
)
}
return true
}
data class filmInfo(
@JsonProperty("name") val name: String? = null,
@JsonProperty("poster") val poster: String? = null,
@JsonProperty("thumbnail") val thumbnail: String? = null,
@JsonProperty("slug") val slug: String? = null,
@JsonProperty("year") val year: Int? = null,
@JsonProperty("trailer") val trailer: TrailerInfo? = null,
)
data class TrailerInfo(
@JsonProperty("original") val original: TrailerKey? = null,
)
data class TrailerKey(
@JsonProperty("id") val id: String? = null,
)
data class MediaDetailEpisodes(
@JsonProperty("data") val eps: ArrayList<Episodes>? = arrayListOf(),
)
data class Episodes(
@JsonProperty("link") val link: String? = null,
@JsonProperty("detail_name") val detailname: String? = null,
@JsonProperty("name") val episodeNumber: Int? = null,
)
data class Media(
@JsonProperty("subtitle") val subtitle: SubInfo? = null,
)
data class SubInfo(
@JsonProperty("vi") val vi: String? = null,
)
}

View file

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

View file

@ -0,0 +1,197 @@
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.mvvm.safeApiCall
import com.lagradost.cloudstream3.utils.*
import org.jsoup.nodes.Element
import java.net.URLDecoder
class PhimmoichillProvider : MainAPI() {
override var mainUrl = "https://phimmoichillg.net"
override var name = "Phimmoichill"
override val hasMainPage = true
override var lang = "vi"
override val hasDownloadSupport = true
override val supportedTypes = setOf(
TvType.Movie,
TvType.TvSeries,
TvType.Anime,
TvType.AsianDrama
)
override val mainPage = mainPageOf(
"$mainUrl/genre/phim-chieu-rap/page-" to "Phim Chiếu Rạp",
"$mainUrl/list/phim-le/page-" to "Phim Lẻ",
"$mainUrl/list/phim-bo/page-" to "Phim Bộ",
"$mainUrl/genre/phim-hoat-hinh/page-" to "Phim Hoạt Hình",
"$mainUrl/genre/phim-anime/page-" to "Phim Anime",
"$mainUrl/country/phim-han-quoc/page-" to "Phim Hàn Quốc",
"$mainUrl/country/phim-trung-quoc/page-" to "Phim Trung Quốc",
"$mainUrl/country/phim-thai-lan/page-" to "Phim Thái Lan",
"$mainUrl/genre/phim-sap-chieu/page-" to "Phim Sắp Chiếu",
)
override suspend fun getMainPage(
page: Int,
request: MainPageRequest
): HomePageResponse {
val document = app.get(request.data + page).document
val home = document.select("li.item").mapNotNull {
it.toSearchResult()
}
return newHomePageResponse(
list = HomePageList(
name = request.name,
list = home,
isHorizontalImages = true
),
hasNext = true
)
}
private fun decode(input: String): String? = URLDecoder.decode(input, "utf-8")
private fun Element.toSearchResult(): SearchResponse {
val title = this.selectFirst("p,h3")?.text()?.trim().toString()
val href = fixUrl(this.selectFirst("a")!!.attr("href"))
val posterUrl = decode(this.selectFirst("img")!!.attr("src").substringAfter("url="))
val temp = this.select("span.label").text()
return if (temp.contains(Regex("\\d"))) {
val episode = Regex("(\\((\\d+))|(\\s(\\d+))").find(temp)?.groupValues?.map { num ->
num.replace(Regex("\\(|\\s"), "")
}?.distinct()?.firstOrNull()?.toIntOrNull()
newAnimeSearchResponse(title, href, TvType.TvSeries) {
this.posterUrl = posterUrl
addSub(episode)
}
} else if (temp.contains(Regex("Trailer"))) {
newMovieSearchResponse(title, href, TvType.Movie) {
this.posterUrl = posterUrl
}
} else {
val quality =
temp.replace(Regex("(-.*)|(\\|.*)|(?i)(VietSub.*)|(?i)(Thuyết.*)"), "").trim()
newMovieSearchResponse(title, href, TvType.Movie) {
this.posterUrl = posterUrl
addQuality(quality)
}
}
}
override suspend fun search(query: String): List<SearchResponse> {
val link = "$mainUrl/tim-kiem/$query"
val document = app.get(link).document
return document.select("ul.list-film li").map {
it.toSearchResult()
}
}
override suspend fun load( url: String ): LoadResponse {
val document = app.get(url).document
val title = document.selectFirst("h1[itemprop=name]")?.text()?.trim().toString()
val link = document.select("ul.list-button li:last-child a").attr("href")
val poster = document.selectFirst("div.image img[itemprop=image]")?.attr("src")
val tags = document.select("ul.entry-meta.block-film li:nth-child(4) a").map { it.text()!!.substringAfter("Phim") }
val year = document.select("ul.entry-meta.block-film li:nth-child(2) a").text().trim()
.toIntOrNull()
val tvType = if (document.select("div.latest-episode").isNotEmpty()
) TvType.TvSeries else TvType.Movie
val description = document.select("div#film-content").text().substringAfter("Full HD Vietsub Thuyết Minh").substringBefore("@phimmoi").trim()
val trailer = document.select("body script")
.find { it.data().contains("youtube.com") }?.data()?.substringAfterLast("file: \"")?.substringBefore("\",")
val rating =
document.select("ul.entry-meta.block-film li:nth-child(7) span").text().toRatingInt()
val actors = document.select("ul.entry-meta.block-film li:last-child a").map { it.text() }
val recommendations = document.select("ul#list-film-realted li.item").map {
it.toSearchResult().apply {
this.posterUrl = decode(it.selectFirst("img")!!.attr("data-src").substringAfter("url="))
}
}
return if (tvType == TvType.TvSeries) {
val docEpisodes = app.get(link).document
val episodes = docEpisodes.select("ul#list_episodes > li").map {
val href = it.select("a").attr("href")
val episode =
it.select("a").text().replace(Regex("[^0-9]"), "").trim().toIntOrNull()
val name = "Episode $episode"
Episode(
data = href,
name = name,
episode = 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 {
newMovieLoadResponse(title, url, TvType.Movie, link) {
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 key = document.select("div#content script")
.find { it.data().contains("filmInfo.episodeID =") }?.data()?.let { script ->
val id = script.substringAfter("filmInfo.episodeID = parseInt('")
app.post(
url = "${this.mainUrl}/chillsplayer.php",
data = mapOf("qcao" to id, "sv" to "0"),
referer = data,
headers = mapOf(
"X-Requested-With" to "XMLHttpRequest",
"Content-Type" to "application/x-www-form-urlencoded; charset=UTF-8"
)
).text.substringAfterLast("iniPlayers(\"")
.substringBefore("\",")
}
listOf(
Pair("https://so-trym.topphimmoi.org/raw/$key/index.m3u8", "PMFAST"),
Pair("https://dash.megacdn.xyz/raw/$key/index.m3u8", "PMHLS"),
Pair("https://so-trym.phimchill.net/dash/$key/index.m3u8", "PMPRO"),
Pair("https://dash.megacdn.xyz/dast/$key/index.m3u8", "PMBK")
).apmap { (link, source) ->
safeApiCall {
callback.invoke(
ExtractorLink(
source,
source,
link,
referer = "$mainUrl/",
quality = Qualities.P1080.value,
isM3u8 = true,
)
)
}
}
return true
}
}

View file

@ -0,0 +1,29 @@
// use an integer for version numbers
version = 7
cloudstream {
language = "id"
// All of these properties are optional, you can safely remove them
description = "Includes: Cgvindo, Kitanonton"
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=104.237.198.194&sz=%size%"
}

View file

@ -0,0 +1,9 @@
package com.hexated
import com.lagradost.cloudstream3.TvType
class Cgvindo : RebahinProvider() {
override var mainUrl = "http://cgvindo.click"
override var name = "Cgvindo"
}

View file

@ -0,0 +1,314 @@
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.mvvm.logError
import com.lagradost.cloudstream3.mvvm.safeApiCall
import com.lagradost.cloudstream3.network.WebViewResolver
import com.lagradost.cloudstream3.utils.*
import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
import org.jsoup.nodes.Element
import java.net.URI
open class RebahinProvider : MainAPI() {
override var mainUrl = "http://179.43.163.50"
override var name = "Rebahin"
override val hasMainPage = true
override var lang = "id"
open var mainServer = "http://172.96.161.72"
override val supportedTypes = setOf(
TvType.Movie,
TvType.TvSeries,
TvType.Anime,
TvType.AsianDrama
)
override suspend fun getMainPage(page: Int, request: MainPageRequest): HomePageResponse {
val urls = listOf(
Pair("Featured", "xtab1"),
Pair("Film Terbaru", "xtab2"),
Pair("Romance", "xtab3"),
Pair("Drama", "xtab4"),
Pair("Action", "xtab5"),
Pair("Scifi", "xtab6"),
Pair("Tv Series Terbaru", "stab1"),
Pair("Anime Series", "stab2"),
Pair("Drakor Series", "stab3"),
Pair("West Series", "stab4"),
Pair("China Series", "stab5"),
Pair("Japan Series", "stab6"),
)
val items = ArrayList<HomePageList>()
for ((header, tab) in urls) {
try {
val home =
app.get("$mainUrl/wp-content/themes/indoxxi/ajax-top-$tab.php").document.select(
"div.ml-item"
).mapNotNull {
it.toSearchResult()
}
items.add(HomePageList(header, home))
} catch (e: Exception) {
logError(e)
}
}
if (items.size <= 0) throw ErrorLoadingException()
return HomePageResponse(items)
}
fun Element.toSearchResult(): SearchResponse? {
val title = this.selectFirst("span.mli-info > h2")?.text() ?: return null
val href = this.selectFirst("a")!!.attr("href")
val type =
if (this.select("span.mli-quality").isNotEmpty()) TvType.Movie else TvType.TvSeries
return if (type == TvType.Movie) {
val posterUrl = fixUrlNull(this.select("img").attr("src"))
val quality = getQualityFromString(this.select("span.mli-quality").text().trim())
newMovieSearchResponse(title, href, TvType.Movie) {
this.posterUrl = posterUrl
this.quality = quality
}
} else {
val posterUrl =
fixUrlNull(
this.select("img").attr("src")
.ifEmpty { this.select("img").attr("data-original") })
val episode =
this.select("div.mli-eps > span").text().replace(Regex("[^0-9]"), "").toIntOrNull()
newAnimeSearchResponse(title, href, TvType.TvSeries) {
this.posterUrl = posterUrl
addSub(episode)
}
}
}
override suspend fun search(query: String): List<SearchResponse> {
val link = "$mainUrl/?s=$query"
val document = app.get(link).document
return document.select("div.ml-item").mapNotNull {
it.toSearchResult()
}
}
override suspend fun load(url: String): LoadResponse {
val document = app.get(url).document
val title = document.selectFirst("h3[itemprop=name]")!!.ownText().trim()
val poster = document.select(".mvic-desc > div.thumb.mvic-thumb").attr("style")
.substringAfter("url(").substringBeforeLast(")")
val tags = document.select("span[itemprop=genre]").map { it.text() }
val year = Regex("([0-9]{4}?)-").find(
document.selectFirst(".mvici-right > p:nth-child(3)")!!.ownText().trim()
)?.groupValues?.get(1).toString().toIntOrNull()
val tvType = if (url.contains("/series/")) TvType.TvSeries else TvType.Movie
val description = document.select("span[itemprop=reviewBody] > p").text().trim()
val trailer = fixUrlNull(document.selectFirst("div.modal-body-trailer iframe")?.attr("src"))
val rating = document.selectFirst("span[itemprop=ratingValue]")?.text()?.toRatingInt()
val duration = document.selectFirst(".mvici-right > p:nth-child(1)")!!
.ownText().replace(Regex("[^0-9]"), "").toIntOrNull()
val actors = document.select("span[itemprop=actor] > a").map { it.select("span").text() }
val baseLink = fixUrl(document.select("div#mv-info > a").attr("href").toString())
return if (tvType == TvType.TvSeries) {
val episodes = app.get(baseLink).document.select("div#list-eps > a").map {
Pair(it.text(), it.attr("data-iframe"))
}.groupBy { it.first }.map { eps ->
Episode(
data = eps.value.map { fixUrl(base64Decode(it.second)) }.toString(),
name = eps.key,
episode = eps.key.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
this.duration = duration
addActors(actors)
addTrailer(trailer)
}
} else {
val links =
app.get(baseLink).document.select("div#server-list div.server-wrapper div[id*=episode]")
.map {
fixUrl(base64Decode(it.attr("data-iframe")))
}.toString()
newMovieLoadResponse(title, url, TvType.Movie, links) {
this.posterUrl = poster
this.year = year
this.plot = description
this.tags = tags
this.rating = rating
this.duration = duration
addActors(actors)
addTrailer(trailer)
}
}
}
private fun getLanguage(str: String): String {
return when {
str.contains("indonesia", true) || str.contains("bahasa", true) -> "Indonesian"
else -> str
}
}
private suspend fun invokeLokalSource(
url: String,
subCallback: (SubtitleFile) -> Unit,
sourceCallback: (ExtractorLink) -> Unit
) {
val document = app.get(
url,
allowRedirects = false,
referer = mainUrl,
headers = mapOf("Accept" to "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8")
).document
document.select("script").find { it.data().contains("config =") }?.data()?.let { script ->
Regex("\"file\":\\s?\"(.+.m3u8)\"").find(script)?.groupValues?.getOrNull(1)
?.let { link ->
M3u8Helper.generateM3u8(
name,
link,
referer = "$mainServer/",
headers = mapOf("Accept" to "*/*", "Origin" to mainServer)
).forEach(sourceCallback)
}
val subData =
Regex("\"?tracks\"?:\\s\\n?\\[(.*)],").find(script)?.groupValues?.getOrNull(1)
?: Regex("\"?tracks\"?:\\s\\n?\\[\\s*(?s:(.+)],\\n\\s*\"sources)").find(script)?.groupValues?.getOrNull(
1
)
tryParseJson<List<Tracks>>("[$subData]")?.map {
subCallback.invoke(
SubtitleFile(
getLanguage(it.label ?: return@map null),
if (it.file?.contains(".srt") == true) it.file else return@map null
)
)
}
}
}
private suspend fun invokeKotakAjairSource(
url: String,
subCallback: (SubtitleFile) -> Unit,
sourceCallback: (ExtractorLink) -> Unit
) {
val domainUrl = "https://kotakajair.xyz"
val id = url.trimEnd('/').split("/").last()
val sources = app.post(
url = "$domainUrl/api/source/$id",
data = mapOf("r" to mainUrl, "d" to URI(url).host)
).parsed<ResponseKotakAjair>()
sources.data?.map {
sourceCallback.invoke(
ExtractorLink(
name,
"KotakAjair",
fixUrl(it.file),
referer = url,
quality = getQualityFromName(it.label)
)
)
}
val userData = sources.player.poster_file.split("/")[2]
sources.captions?.map {
subCallback.invoke(
SubtitleFile(
getLanguage(it.language),
"$domainUrl/asset/userdata/$userData/caption/${it.hash}/${it.id}.srt"
)
)
}
}
override suspend fun loadLinks(
data: String,
isCasting: Boolean,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
): Boolean {
data.removeSurrounding("[", "]").split(",").map { it.trim() }.apmap { link ->
safeApiCall {
when {
link.startsWith(mainServer) -> invokeLokalSource(
link,
subtitleCallback,
callback
)
link.startsWith("https://kotakajair.xyz") -> invokeKotakAjairSource(
link,
subtitleCallback,
callback
)
else -> {
loadExtractor(link, "$mainUrl/", subtitleCallback, callback)
if (link.startsWith("https://sbfull.com")) {
val response = app.get(
link, interceptor = WebViewResolver(
Regex("""\.srt""")
)
)
subtitleCallback.invoke(
SubtitleFile(
"Indonesian",
response.url
)
)
}
}
}
}
}
return true
}
private data class Tracks(
@JsonProperty("file") val file: String? = null,
@JsonProperty("label") val label: String? = null,
@JsonProperty("kind") val kind: String? = null
)
private data class Captions(
@JsonProperty("id") val id: String,
@JsonProperty("hash") val hash: String,
@JsonProperty("language") val language: String,
)
private data class Data(
@JsonProperty("file") val file: String,
@JsonProperty("label") val label: String,
)
private data class Player(
@JsonProperty("poster_file") val poster_file: String,
)
private data class ResponseKotakAjair(
@JsonProperty("success") val success: Boolean,
@JsonProperty("player") val player: Player,
@JsonProperty("data") val data: List<Data>?,
@JsonProperty("captions") val captions: List<Captions>?
)
}

View file

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

View file

@ -0,0 +1,27 @@
// 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=https://samehadaku.world&sz=%size%"
}

View file

@ -0,0 +1,241 @@
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.Qualities
import com.lagradost.cloudstream3.utils.loadExtractor
import org.jsoup.nodes.Element
class Samehadaku : MainAPI() {
override var mainUrl = "https://samehadaku.bond"
override var name = "Samehadaku"
override val hasMainPage = true
override var lang = "id"
override val hasDownloadSupport = true
override val supportedTypes = setOf(
TvType.Anime,
TvType.AnimeMovie,
TvType.OVA
)
companion object {
const val acefile = "https://acefile.co"
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(
"$mainUrl/page/" to "Episode Terbaru",
"$mainUrl/" to "HomePage",
)
override suspend fun getMainPage(
page: Int,
request: MainPageRequest
): HomePageResponse {
val items = mutableListOf<HomePageList>()
if (request.name != "Episode Terbaru" && page <= 1) {
val doc = app.get(request.data).document
doc.select("div.widget_senction:not(:contains(Baca Komik))").forEach { block ->
val header = block.selectFirst("div.widget-title h3")?.ownText() ?: return@forEach
val home = block.select("div.animepost").mapNotNull {
it.toSearchResult()
}
if (home.isNotEmpty()) items.add(HomePageList(header, home))
}
}
if (request.name == "Episode Terbaru") {
val home =
app.get(request.data + page).document.selectFirst("div.post-show")?.select("ul li")
?.mapNotNull {
it.toSearchResult()
} ?: throw ErrorLoadingException("No Media Found")
items.add(HomePageList(request.name, home, true))
}
return newHomePageResponse(items)
}
private fun Element.toSearchResult(): AnimeSearchResponse? {
val title = this.selectFirst("div.title, h2.entry-title a, div.lftinfo h2")?.text()?.trim()
?: return null
val href = fixUrlNull(this.selectFirst("a")?.attr("href") ?: return null)
val posterUrl = fixUrlNull(this.select("img").attr("src"))
val epNum = this.selectFirst("div.dtla author")?.text()?.toIntOrNull()
return newAnimeSearchResponse(title, href ?: return null, TvType.Anime) {
this.posterUrl = posterUrl
addSub(epNum)
}
}
override suspend fun search(query: String): List<SearchResponse> {
val document = app.get("$mainUrl/?s=$query").document
return document.select("main#main div.animepost").mapNotNull {
it.toSearchResult()
}
}
override suspend fun load(url: String): LoadResponse? {
val fixUrl = if (url.contains("/anime/")) {
url
} else {
app.get(url).document.selectFirst("div.nvs.nvsc a")?.attr("href")
}
val document = app.get(fixUrl ?: return null).document
val title = document.selectFirst("h1.entry-title")?.text()?.removeBloat() ?: return null
val poster = document.selectFirst("div.thumb > img")?.attr("src")
val tags = document.select("div.genre-info > a").map { it.text() }
val year = document.selectFirst("div.spe > span:contains(Rilis)")?.ownText()?.let {
Regex("\\d,\\s(\\d*)").find(it)?.groupValues?.getOrNull(1)?.toIntOrNull()
}
val status = getStatus(
document.selectFirst("div.spe > span:contains(Status)")?.ownText() ?: return null
)
val type =
getType(document.selectFirst("div.spe > span:contains(Type)")?.ownText()?.trim()?.lowercase()
?: "tv")
val rating = document.selectFirst("span.ratingValue")?.text()?.trim()?.toRatingInt()
val description = document.select("div.desc p").text().trim()
val trailer = document.selectFirst("div.trailer-anime 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 = Regex("Episode\\s?(\\d+)").find(header.text())?.groupValues?.getOrNull(1)
?.toIntOrNull()
val link = fixUrl(header.attr("href"))
Episode(link, episode = episode)
}.reversed()
val recommendations = document.select("aside#sidebar ul li").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
this.rating = rating
plot = description
addTrailer(trailer)
this.tags = tags
this.recommendations = recommendations
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
argamap(
{
document.select("div#server ul li div").apmap {
val dataPost = it.attr("data-post")
val dataNume = it.attr("data-nume")
val dataType = it.attr("data-type")
val iframe = app.post(
url = "$mainUrl/wp-admin/admin-ajax.php",
data = mapOf(
"action" to "player_ajax",
"post" to dataPost,
"nume" to dataNume,
"type" to dataType
),
referer = data,
headers = mapOf("X-Requested-With" to "XMLHttpRequest")
).document.select("iframe").attr("src")
loadFixedExtractor(fixedIframe(iframe), it.text(), "$mainUrl/", subtitleCallback, callback)
}
},
{
document.select("div#downloadb li").map { el ->
el.select("a").apmap {
loadFixedExtractor(fixedIframe(it.attr("href")), el.select("strong").text(), "$mainUrl/", subtitleCallback, callback)
}
}
}
)
return true
}
private suspend fun loadFixedExtractor(
url: String,
name: 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,
name.fixQuality(),
link.type,
link.headers,
link.extractorData
)
)
}
}
private fun String.fixQuality() : Int {
return when(this) {
"MP4HD" -> Qualities.P720.value
"FULLHD" -> Qualities.P1080.value
else -> this.filter { it.isDigit() }.toIntOrNull() ?: Qualities.Unknown.value
}
}
private fun fixedIframe(url: String): String {
val id = Regex("""(?:/f/|/file/)(\w+)""").find(url)?.groupValues?.getOrNull(1)
return when {
url.startsWith(acefile) -> "${acefile}/player/$id"
else -> fixUrl(url)
}
}
private fun String.removeBloat(): String {
return this.replace(Regex("(Nonton)|(Anime)|(Subtitle\\sIndonesia)"), "").trim()
}
}

View file

@ -1,7 +1,7 @@
import org.jetbrains.kotlin.konan.properties.Properties import org.jetbrains.kotlin.konan.properties.Properties
// use an integer for version numbers // use an integer for version numbers
version = 144 version = 167
android { android {
defaultConfig { defaultConfig {
@ -14,6 +14,7 @@ android {
buildConfigField("String", "SORATED", "\"${properties.getProperty("SORATED")}\"") buildConfigField("String", "SORATED", "\"${properties.getProperty("SORATED")}\"")
buildConfigField("String", "DUMP_API", "\"${properties.getProperty("DUMP_API")}\"") buildConfigField("String", "DUMP_API", "\"${properties.getProperty("DUMP_API")}\"")
buildConfigField("String", "DUMP_KEY", "\"${properties.getProperty("DUMP_KEY")}\"") buildConfigField("String", "DUMP_KEY", "\"${properties.getProperty("DUMP_KEY")}\"")
buildConfigField("String", "PRIMEWIRE_KEY", "\"${properties.getProperty("PRIMEWIRE_KEY")}\"")
buildConfigField("String", "CRUNCHYROLL_BASIC_TOKEN", "\"${properties.getProperty("CRUNCHYROLL_BASIC_TOKEN")}\"") buildConfigField("String", "CRUNCHYROLL_BASIC_TOKEN", "\"${properties.getProperty("CRUNCHYROLL_BASIC_TOKEN")}\"")
buildConfigField("String", "CRUNCHYROLL_REFRESH_TOKEN", "\"${properties.getProperty("CRUNCHYROLL_REFRESH_TOKEN")}\"") buildConfigField("String", "CRUNCHYROLL_REFRESH_TOKEN", "\"${properties.getProperty("CRUNCHYROLL_REFRESH_TOKEN")}\"")

View file

@ -0,0 +1,162 @@
package com.hexated
import com.lagradost.cloudstream3.extractors.Filesim
import com.lagradost.cloudstream3.extractors.GMPlayer
import com.lagradost.cloudstream3.extractors.StreamSB
import com.lagradost.cloudstream3.extractors.Voe
import com.fasterxml.jackson.annotation.JsonProperty
import com.lagradost.cloudstream3.APIHolder.getCaptchaToken
import com.lagradost.cloudstream3.SubtitleFile
import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.utils.*
import java.math.BigInteger
import java.security.MessageDigest
open class Playm4u : ExtractorApi() {
override val name = "Playm4u"
override val mainUrl = "https://play9str.playm4u.xyz"
override val requiresReferer = true
private val password = "plhq@@@22"
override suspend fun getUrl(
url: String,
referer: String?,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
) {
val document = app.get(url, referer = referer).document
val script = document.selectFirst("script:containsData(idfile =)")?.data() ?: return
val passScript = document.selectFirst("script:containsData(domain_ref =)")?.data() ?: return
val pass = passScript.substringAfter("CryptoJS.MD5('").substringBefore("')")
val amount = passScript.substringAfter(".toString()), ").substringBefore("));").toInt()
val idFile = "idfile".findIn(script)
val idUser = "idUser".findIn(script)
val domainApi = "DOMAIN_API".findIn(script)
val nameKeyV3 = "NameKeyV3".findIn(script)
val dataEnc = caesarShift(
mahoa(
"Win32|$idUser|$idFile|$referer",
md5(pass)
), amount
).toHex()
val captchaKey =
document.select("script[src*=https://www.google.com/recaptcha/api.js?render=]")
.attr("src").substringAfter("render=")
val token = getCaptchaToken(
url,
captchaKey,
referer = referer
)
val source = app.post(
domainApi, data = mapOf(
"namekey" to nameKeyV3,
"token" to "$token",
"referrer" to "$referer",
"data" to "$dataEnc|${md5(dataEnc + password)}",
), referer = "$mainUrl/"
).parsedSafe<Source>()
callback.invoke(
ExtractorLink(
this.name,
this.name,
source?.data ?: return,
"$mainUrl/",
Qualities.P1080.value,
INFER_TYPE
)
)
subtitleCallback.invoke(
SubtitleFile(
source.sub?.substringBefore("|")?.toLanguage() ?: return,
source.sub.substringAfter("|"),
)
)
}
private fun caesarShift(str: String, amount: Int): String {
var output = ""
val adjustedAmount = if (amount < 0) amount + 26 else amount
for (element in str) {
var c = element
if (c.isLetter()) {
val code = c.code
c = when (code) {
in 65..90 -> ((code - 65 + adjustedAmount) % 26 + 65).toChar()
in 97..122 -> ((code - 97 + adjustedAmount) % 26 + 97).toChar()
else -> c
}
}
output += c
}
return output
}
private fun mahoa(input: String, key: String): String {
val a = CryptoJS.encrypt(key, input)
return a.replace("U2FsdGVkX1", "")
.replace("/", "|a")
.replace("+", "|b")
.replace("=", "|c")
.replace("|", "-z")
}
private fun md5(input: String): String {
val md = MessageDigest.getInstance("MD5")
return BigInteger(1, md.digest(input.toByteArray())).toString(16).padStart(32, '0')
}
private fun String.toHex(): String {
return this.toByteArray().joinToString("") { "%02x".format(it) }
}
private fun String.findIn(data: String): String {
return "$this\\s*=\\s*[\"'](\\S+)[\"'];".toRegex().find(data)?.groupValues?.get(1) ?: ""
}
private fun String.toLanguage() : String {
return if(this == "EN") "English" else this
}
data class Source(
@JsonProperty("data") val data: String? = null,
@JsonProperty("sub") val sub: String? = null,
)
}
class TravelR : GMPlayer() {
override val name = "TravelR"
override val mainUrl = "https://travel-russia.xyz"
}
class Mwish : Filesim() {
override val name = "Mwish"
override var mainUrl = "https://mwish.pro"
}
class Animefever : Filesim() {
override val name = "Animefever"
override var mainUrl = "https://animefever.fun"
}
class Multimovies : Filesim() {
override val name = "Multimovies"
override var mainUrl = "https://multimovies.cloud"
}
class MultimoviesSB : StreamSB() {
override var name = "Multimovies"
override var mainUrl = "https://multimovies.website"
}
class Yipsu : Voe() {
override val name = "Yipsu"
override var mainUrl = "https://yip.su"
}

File diff suppressed because it is too large Load diff

View file

@ -9,12 +9,6 @@ data class FDMovieIFrame(
val type: String, val type: String,
) )
data class BaymoviesConfig(
val country: String,
val downloadTime: String,
val workers: List<String>
)
data class AniIds( data class AniIds(
var id: Int? = null, var id: Int? = null,
var idMal: Int? = null var idMal: Int? = null
@ -37,26 +31,7 @@ data class AniSearch(
@JsonProperty("data") var data: AniData? = AniData() @JsonProperty("data") var data: AniData? = AniData()
) )
data class Tmdb2Anilist( data class PrimewireSources(
@JsonProperty("tmdb_id") val tmdb_id: String? = null,
@JsonProperty("anilist_id") val anilist_id: String? = null,
@JsonProperty("mal_id") val mal_id: String? = null,
)
data class Movie123Media(
@JsonProperty("url") val url: String? = null,
)
data class Movie123Data(
@JsonProperty("t") val t: String? = null,
@JsonProperty("s") val s: String? = null,
)
data class Movie123Search(
@JsonProperty("data") val data: ArrayList<Movie123Data>? = arrayListOf(),
)
data class GomoviesSources(
@JsonProperty("src") val src: String, @JsonProperty("src") val src: String,
@JsonProperty("file") val file: String? = null, @JsonProperty("file") val file: String? = null,
@JsonProperty("label") val label: Int? = null, @JsonProperty("label") val label: Int? = null,
@ -72,25 +47,10 @@ data class MoviesbayValues(
@JsonProperty("values") val values: List<List<String>>? = arrayListOf(), @JsonProperty("values") val values: List<List<String>>? = arrayListOf(),
) )
data class HdMovieBoxTracks(
@JsonProperty("label") val label: String? = null,
@JsonProperty("file") val file: String? = null,
)
data class HdMovieBoxSource(
@JsonProperty("videoUrl") val videoUrl: String? = null,
@JsonProperty("videoServer") val videoServer: String? = null,
@JsonProperty("videoDisk") val videoDisk: Any? = null,
@JsonProperty("tracks") val tracks: ArrayList<HdMovieBoxTracks>? = arrayListOf(),
)
data class HdMovieBoxIframe(
@JsonProperty("api_iframe") val apiIframe: String? = null,
)
data class ResponseHash( data class ResponseHash(
@JsonProperty("embed_url") val embed_url: String, @JsonProperty("embed_url") val embed_url: String,
@JsonProperty("type") val type: String?, @JsonProperty("key") val key: String? = null,
@JsonProperty("type") val type: String? = null,
) )
data class KisskhSources( data class KisskhSources(
@ -98,6 +58,20 @@ data class KisskhSources(
@JsonProperty("ThirdParty") val thirdParty: String?, @JsonProperty("ThirdParty") val thirdParty: String?,
) )
data class OmegaSource(
@JsonProperty("quality") val quality: String? = null,
@JsonProperty("url") val url: String? = null,
)
data class OmegaSources(
@JsonProperty("label") val label: String? = null,
@JsonProperty("sources") val sources: ArrayList<OmegaSource>? = arrayListOf(),
)
data class OmegaResponse(
@JsonProperty("sources") val sources: ArrayList<OmegaSources>? = arrayListOf(),
)
data class KisskhSubtitle( data class KisskhSubtitle(
@JsonProperty("src") val src: String?, @JsonProperty("src") val src: String?,
@JsonProperty("label") val label: String?, @JsonProperty("label") val label: String?,
@ -112,11 +86,41 @@ data class KisskhDetail(
@JsonProperty("episodes") val episodes: ArrayList<KisskhEpisodes>? = arrayListOf(), @JsonProperty("episodes") val episodes: ArrayList<KisskhEpisodes>? = arrayListOf(),
) )
data class SusflixSrtfiles(
@JsonProperty("caption") val caption: String? = null,
@JsonProperty("url") val url: String? = null,
)
data class SusflixQualities(
@JsonProperty("path") val path: String? = null,
@JsonProperty("quality") val quality: String? = null,
)
data class SusflixSources(
@JsonProperty("Qualities") val qualities: ArrayList<SusflixQualities>? = arrayListOf(),
@JsonProperty("Srtfiles") val srtfiles: ArrayList<SusflixSrtfiles>? = arrayListOf(),
)
data class KisskhResults( data class KisskhResults(
@JsonProperty("id") val id: Int?, @JsonProperty("id") val id: Int?,
@JsonProperty("title") val title: String?, @JsonProperty("title") val title: String?,
) )
data class Jump1Episodes(
@JsonProperty("id") val id: Any? = null,
@JsonProperty("episodeNumber") val episodeNumber: Int? = null,
@JsonProperty("videoId") val videoId: String? = null,
)
data class Jump1Season(
@JsonProperty("seasonNumber") val seasonNumber: Int? = null,
@JsonProperty("id") val id: String? = null,
)
data class Jump1Movies(
@JsonProperty("movies") val movies: ArrayList<Jump1Episodes>? = arrayListOf(),
)
data class EpisodesFwatayako( data class EpisodesFwatayako(
@JsonProperty("id") val id: String? = null, @JsonProperty("id") val id: String? = null,
@JsonProperty("file") val file: String? = null, @JsonProperty("file") val file: String? = null,
@ -202,53 +206,18 @@ data class IndexSearch(
@JsonProperty("data") val data: IndexData? = null, @JsonProperty("data") val data: IndexData? = null,
) )
data class TgarMedia( data class JikanExternal(
@JsonProperty("_id") val _id: Int? = null,
@JsonProperty("name") val name: String? = null, @JsonProperty("name") val name: String? = null,
@JsonProperty("size") val size: Double? = null, @JsonProperty("url") val url: String? = null,
@JsonProperty("file_unique_id") val file_unique_id: String? = null,
@JsonProperty("mime_type") val mime_type: String? = null,
) )
data class TgarData( data class JikanData(
@JsonProperty("documents") val documents: ArrayList<TgarMedia>? = arrayListOf(), @JsonProperty("title") val title: String? = null,
@JsonProperty("external") val external: ArrayList<JikanExternal>? = arrayListOf(),
) )
data class SorastreamResponse( data class JikanResponse(
@JsonProperty("data") val data: SorastreamVideos? = null, @JsonProperty("data") val data: JikanData? = null,
)
data class SorastreamVideos(
@JsonProperty("mediaUrl") val mediaUrl: String? = null,
@JsonProperty("currentDefinition") val currentDefinition: String? = null,
)
data class BiliBiliEpisodes(
@JsonProperty("id") val id: Int? = null,
@JsonProperty("sourceId") val sourceId: String? = null,
@JsonProperty("sourceEpisodeId") val sourceEpisodeId: String? = null,
@JsonProperty("sourceMediaId") val sourceMediaId: String? = null,
@JsonProperty("episodeNumber") val episodeNumber: Int? = null,
)
data class BiliBiliDetails(
@JsonProperty("episodes") val episodes: ArrayList<BiliBiliEpisodes>? = arrayListOf(),
)
data class BiliBiliSubtitles(
@JsonProperty("file") val file: String? = null,
@JsonProperty("lang") val lang: String? = null,
@JsonProperty("language") val language: String? = null,
)
data class BiliBiliSources(
@JsonProperty("file") val file: String? = null,
@JsonProperty("type") val type: String? = null,
)
data class BiliBiliSourcesResponse(
@JsonProperty("sources") val sources: ArrayList<BiliBiliSources>? = arrayListOf(),
@JsonProperty("subtitles") val subtitles: ArrayList<BiliBiliSubtitles>? = arrayListOf(),
) )
data class WatchOnlineItems( data class WatchOnlineItems(
@ -266,33 +235,6 @@ data class WatchOnlineResponse(
@JsonProperty("subtitles") val subtitles: Any? = null, @JsonProperty("subtitles") val subtitles: Any? = null,
) )
data class PutlockerEpisodes(
@JsonProperty("html") val html: String? = null,
)
data class PutlockerEmbed(
@JsonProperty("src") val src: String? = null,
)
data class PutlockerSources(
@JsonProperty("file") val file: String,
@JsonProperty("label") val label: String? = null,
@JsonProperty("type") val type: String? = null,
)
data class PutlockerResponses(
@JsonProperty("sources") val sources: ArrayList<PutlockerSources>? = arrayListOf(),
@JsonProperty("backupLink") val backupLink: String? = null,
)
data class ShivamhwSources(
@JsonProperty("id") val id: String? = null,
@JsonProperty("stream_link") val stream_link: String? = null,
@JsonProperty("process_link") val process_link: String? = null,
@JsonProperty("name") val name: String,
@JsonProperty("size") val size: String,
)
data class CryMoviesProxyHeaders( data class CryMoviesProxyHeaders(
@JsonProperty("request") val request: Map<String, String>?, @JsonProperty("request") val request: Map<String, String>?,
) )
@ -336,16 +278,12 @@ data class VizcloudSources(
@JsonProperty("file") val file: String? = null, @JsonProperty("file") val file: String? = null,
) )
data class VizcloudMedia( data class VizcloudResult(
@JsonProperty("sources") val sources: ArrayList<VizcloudSources>? = arrayListOf(), @JsonProperty("sources") val sources: ArrayList<VizcloudSources>? = arrayListOf(),
) )
data class VizcloudData(
@JsonProperty("media") val media: VizcloudMedia? = null,
)
data class VizcloudResponses( data class VizcloudResponses(
@JsonProperty("data") val data: VizcloudData? = null, @JsonProperty("result") val result: VizcloudResult? = null,
) )
data class AnilistExternalLinks( data class AnilistExternalLinks(
@ -405,15 +343,15 @@ data class CrunchyrollSourcesResponses(
@JsonProperty("meta") val meta: CrunchyrollMeta? = null, @JsonProperty("meta") val meta: CrunchyrollMeta? = null,
) )
data class MALSyncPages( data class MALSyncSites(
@JsonProperty("Zoro") val zoro: HashMap<String?, HashMap<String, String?>>? = hashMapOf(), @JsonProperty("Zoro") val zoro: HashMap<String?, HashMap<String, String?>>? = hashMapOf(),
) )
data class MALSyncResponses( data class MALSyncResponses(
@JsonProperty("Pages") val pages: MALSyncPages? = null, @JsonProperty("Sites") val sites: MALSyncSites? = null,
) )
data class ZoroResponses( data class AniwatchResponses(
@JsonProperty("html") val html: String? = null, @JsonProperty("html") val html: String? = null,
@JsonProperty("link") val link: String? = null, @JsonProperty("link") val link: String? = null,
) )

View file

@ -1,62 +1,58 @@
package com.hexated package com.hexated
import com.fasterxml.jackson.annotation.JsonProperty import com.fasterxml.jackson.annotation.JsonProperty
import com.hexated.SoraExtractor.invoke2embed
import com.hexated.SoraExtractor.invokeAnimes import com.hexated.SoraExtractor.invokeAnimes
import com.hexated.SoraExtractor.invokeAsk4Movies import com.hexated.SoraExtractor.invokeAsk4Movies
import com.hexated.SoraExtractor.invokeBlackmovies
import com.hexated.SoraExtractor.invokeBollyMaza import com.hexated.SoraExtractor.invokeBollyMaza
import com.hexated.SoraExtractor.invokeCodexmovies
import com.hexated.SoraExtractor.invokeCryMovies import com.hexated.SoraExtractor.invokeCryMovies
import com.hexated.SoraExtractor.invokeDbgo import com.hexated.SoraExtractor.invokeDbgo
import com.hexated.SoraExtractor.invokeFilmxy import com.hexated.SoraExtractor.invokeFilmxy
import com.hexated.SoraExtractor.invokeHDMovieBox
import com.hexated.SoraExtractor.invokeIdlix import com.hexated.SoraExtractor.invokeIdlix
import com.hexated.SoraExtractor.invokeKimcartoon import com.hexated.SoraExtractor.invokeKimcartoon
import com.hexated.SoraExtractor.invokeMovieHab import com.hexated.SoraExtractor.invokeMovieHab
import com.hexated.SoraExtractor.invokeNoverse
import com.hexated.SoraExtractor.invokeSeries9
import com.hexated.SoraExtractor.invokeVidSrc import com.hexated.SoraExtractor.invokeVidSrc
import com.hexated.SoraExtractor.invokeXmovies
import com.lagradost.cloudstream3.* import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer
import com.lagradost.cloudstream3.metaproviders.TmdbProvider import com.lagradost.cloudstream3.metaproviders.TmdbProvider
import com.hexated.SoraExtractor.invokeDahmerMovies import com.hexated.SoraExtractor.invokeDahmerMovies
import com.hexated.SoraExtractor.invokeDoomovies
import com.hexated.SoraExtractor.invokeDramaday
import com.hexated.SoraExtractor.invokeDreamfilm import com.hexated.SoraExtractor.invokeDreamfilm
import com.hexated.SoraExtractor.invokeEdithxmovies
import com.hexated.SoraExtractor.invokeFDMovies import com.hexated.SoraExtractor.invokeFDMovies
import com.hexated.SoraExtractor.invokeFlixon import com.hexated.SoraExtractor.invokeFlixon
import com.hexated.SoraExtractor.invokeFmovies
import com.hexated.SoraExtractor.invokeFwatayako import com.hexated.SoraExtractor.invokeFwatayako
import com.hexated.SoraExtractor.invokeGMovies import com.hexated.SoraExtractor.invokeGMovies
import com.hexated.SoraExtractor.invokeGdbotMovies
import com.hexated.SoraExtractor.invokeGoku import com.hexated.SoraExtractor.invokeGoku
import com.hexated.SoraExtractor.invokeGomovies
import com.hexated.SoraExtractor.invokeJmdkhMovies
import com.hexated.SoraExtractor.invokeKisskh import com.hexated.SoraExtractor.invokeKisskh
import com.hexated.SoraExtractor.invokeLing import com.hexated.SoraExtractor.invokeLing
import com.hexated.SoraExtractor.invokeM4uhd import com.hexated.SoraExtractor.invokeM4uhd
import com.hexated.SoraExtractor.invokeMovie123Net
import com.hexated.SoraExtractor.invokeMoviesbay import com.hexated.SoraExtractor.invokeMoviesbay
import com.hexated.SoraExtractor.invokeMoviezAdd import com.hexated.SoraExtractor.invokeMoviezAdd
import com.hexated.SoraExtractor.invokeNavy import com.hexated.SoraExtractor.invokeNavy
import com.hexated.SoraExtractor.invokeNinetv import com.hexated.SoraExtractor.invokeNinetv
import com.hexated.SoraExtractor.invokeNowTv import com.hexated.SoraExtractor.invokeNowTv
import com.hexated.SoraExtractor.invokePutlocker
import com.hexated.SoraExtractor.invokeRStream import com.hexated.SoraExtractor.invokeRStream
import com.hexated.SoraExtractor.invokeRidomovies import com.hexated.SoraExtractor.invokeRidomovies
import com.hexated.SoraExtractor.invokeRubyMovies
import com.hexated.SoraExtractor.invokeShinobiMovies import com.hexated.SoraExtractor.invokeShinobiMovies
import com.hexated.SoraExtractor.invokeShivamhw
import com.hexated.SoraExtractor.invokeSmashyStream import com.hexated.SoraExtractor.invokeSmashyStream
import com.hexated.SoraExtractor.invokeDumpStream import com.hexated.SoraExtractor.invokeDumpStream
import com.hexated.SoraExtractor.invokeEmovies import com.hexated.SoraExtractor.invokeEmovies
import com.hexated.SoraExtractor.invokeFourCartoon import com.hexated.SoraExtractor.invokeFourCartoon
import com.hexated.SoraExtractor.invokeJump1
import com.hexated.SoraExtractor.invokeMoment
import com.hexated.SoraExtractor.invokeMultimovies
import com.hexated.SoraExtractor.invokeNetmovies
import com.hexated.SoraExtractor.invokeOmega
import com.hexated.SoraExtractor.invokePobmovies import com.hexated.SoraExtractor.invokePobmovies
import com.hexated.SoraExtractor.invokePrimewire
import com.hexated.SoraExtractor.invokeTvMovies import com.hexated.SoraExtractor.invokeTvMovies
import com.hexated.SoraExtractor.invokeUhdmovies import com.hexated.SoraExtractor.invokeUhdmovies
import com.hexated.SoraExtractor.invokeVitoenMovies import com.hexated.SoraExtractor.invokeVidsrcto
import com.hexated.SoraExtractor.invokeWatchOnline import com.hexated.SoraExtractor.invokeWatchOnline
import com.hexated.SoraExtractor.invokeWatchsomuch import com.hexated.SoraExtractor.invokeWatchsomuch
import com.lagradost.cloudstream3.LoadResponse.Companion.addImdbId
import com.lagradost.cloudstream3.LoadResponse.Companion.addTMDbId
import com.lagradost.cloudstream3.extractors.VidSrcExtractor import com.lagradost.cloudstream3.extractors.VidSrcExtractor
import com.lagradost.cloudstream3.utils.AppUtils.parseJson import com.lagradost.cloudstream3.utils.AppUtils.parseJson
import com.lagradost.cloudstream3.utils.AppUtils.toJson import com.lagradost.cloudstream3.utils.AppUtils.toJson
@ -83,48 +79,41 @@ open class SoraStream : TmdbProvider() {
const val anilistAPI = "https://graphql.anilist.co" const val anilistAPI = "https://graphql.anilist.co"
const val malsyncAPI = "https://api.malsync.moe" const val malsyncAPI = "https://api.malsync.moe"
const val consumetHelper = "https://api.consumet.org/anime/9anime/helper" const val consumetHelper = "https://api.consumet.org/anime/9anime/helper"
const val jikanAPI = "https://api.jikan.moe/v4"
val apiKey = val apiKey =
base64DecodeAPI("ZTM=NTg=MjM=MjM=ODc=MzI=OGQ=MmE=Nzk=Nzk=ZjI=NTA=NDY=NDA=MzA=YjA=") // PLEASE DON'T STEAL base64DecodeAPI("ZTM=NTg=MjM=MjM=ODc=MzI=OGQ=MmE=Nzk=Nzk=ZjI=NTA=NDY=NDA=MzA=YjA=") // PLEASE DON'T STEAL
/** ALL SOURCES */ /** ALL SOURCES */
const val twoEmbedAPI = "https://www.2embed.cc"
const val vidSrcAPI = "https://v2.vidsrc.me" const val vidSrcAPI = "https://v2.vidsrc.me"
const val dbgoAPI = "https://dbgo.fun" const val dbgoAPI = "https://dbgo.fun"
const val movieHabAPI = "https://moviehab.com" const val movieHabAPI = "https://moviehab.com"
const val hdMovieBoxAPI = "https://hdmoviebox.net"
const val dreamfilmAPI = "https://dreamfilmsw.net" const val dreamfilmAPI = "https://dreamfilmsw.net"
const val series9API = "https://series9.sh" const val idlixAPI = "https://tv.idlixplus.net"
const val idlixAPI = "https://idlixian.com"
const val noverseAPI = "https://www.nollyverse.com" const val noverseAPI = "https://www.nollyverse.com"
const val uniqueStreamAPI = "https://uniquestream.net"
const val filmxyAPI = "https://www.filmxy.vip" const val filmxyAPI = "https://www.filmxy.vip"
const val kimcartoonAPI = "https://kimcartoon.li" const val kimcartoonAPI = "https://kimcartoon.li"
const val xMovieAPI = "https://xemovies.to" const val aniwatchAPI = "https://aniwatch.to"
const val zoroAPI = "https://kaido.to"
const val crunchyrollAPI = "https://beta-api.crunchyroll.com" const val crunchyrollAPI = "https://beta-api.crunchyroll.com"
const val kissKhAPI = "https://kisskh.co" const val kissKhAPI = "https://kisskh.co"
const val lingAPI = "https://ling-online.net" const val lingAPI = "https://ling-online.net"
const val uhdmoviesAPI = "https://uhdmovies.life" const val uhdmoviesAPI = "https://uhdmovies.wiki"
const val fwatayakoAPI = "https://5100.svetacdn.in" const val fwatayakoAPI = "https://5100.svetacdn.in"
const val gMoviesAPI = "https://gdrivemovies.xyz" const val gMoviesAPI = "https://gdrivemovies.xyz"
const val fdMoviesAPI = "https://freedrivemovie.lol" const val fdMoviesAPI = "https://freedrivemovie.lol"
const val m4uhdAPI = "https://m4uhd.tv" const val m4uhdAPI = "https://ww2.m4ufree.com"
const val tvMoviesAPI = "https://www.tvseriesnmovies.com" const val tvMoviesAPI = "https://www.tvseriesnmovies.com"
const val moviezAddAPI = "https://ww2.moviezaddiction.click" const val moviezAddAPI = "https://ww2.moviezaddiction.click"
const val bollyMazaAPI = "https://m.bollymaza.click" const val bollyMazaAPI = "https://m.bollymaza.click"
const val moviesbayAPI = "https://moviesbay.live" const val moviesbayAPI = "https://moviesbay.live"
const val rStreamAPI = "https://remotestre.am" const val rStreamAPI = "https://remotestre.am"
const val flixonAPI = "https://flixon.lol" const val flixonAPI = "https://flixon.lol"
const val animeKaizokuAPI = "https://animekaizoku.com"
const val movie123NetAPI = "https://ww8.0123movie.net"
const val smashyStreamAPI = "https://embed.smashystream.com" const val smashyStreamAPI = "https://embed.smashystream.com"
const val watchSomuchAPI = "https://watchsomuch.tv" // sub only const val watchSomuchAPI = "https://watchsomuch.tv" // sub only
val gomoviesAPI = base64DecodeAPI("bQ==Y28=ZS4=aW4=bmw=LW8=ZXM=dmk=bW8=Z28=Ly8=czo=dHA=aHQ=") const val ask4MoviesAPI = "https://ask4movie.nl"
const val ask4MoviesAPI = "https://ask4movie.net"
const val biliBiliAPI = "https://api-vn.otakuz.live/server"
const val watchOnlineAPI = "https://watchonline.ag" const val watchOnlineAPI = "https://watchonline.ag"
const val nineTvAPI = "https://api.9animetv.live" const val nineTvAPI = "https://moviesapi.club"
const val putlockerAPI = "https://ww7.putlocker.vip"
const val fmoviesAPI = "https://fmovies.to" const val fmoviesAPI = "https://fmovies.to"
const val nowTvAPI = "https://myfilestorage.xyz" const val nowTvAPI = "https://myfilestorage.xyz"
const val gokuAPI = "https://goku.sx" const val gokuAPI = "https://goku.sx"
@ -133,32 +122,24 @@ open class SoraStream : TmdbProvider() {
const val emoviesAPI = "https://emovies.si" const val emoviesAPI = "https://emovies.si"
const val pobmoviesAPI = "https://pobmovies.cam" const val pobmoviesAPI = "https://pobmovies.cam"
const val fourCartoonAPI = "https://4cartoon.net" const val fourCartoonAPI = "https://4cartoon.net"
const val multimoviesAPI = "https://multi-movies.xyz"
const val netmoviesAPI = "https://web.netmovies.to"
const val momentAPI = "https://moment-explanation-i-244.site"
const val doomoviesAPI = "https://doomovies.net"
const val primewireAPI = "https://real-primewire.club"
const val vidsrctoAPI = "https://vidsrc.to"
const val dramadayAPI = "https://dramaday.me"
const val animetoshoAPI = "https://animetosho.org"
const val susflixAPI = "https://susflix.tv"
const val jump1API = "https://ca.jump1.net"
const val omegaAPI = "https://prod.omega.themoviearchive.site"
// INDEX SITE // INDEX SITE
const val blackMoviesAPI = "https://dl.blacklistedbois.workers.dev/0:"
const val codexMoviesAPI = "https://packs.codexcloudx.tech/0:"
const val edithxMoviesAPI = "https://index.edithx.ga/0:"
const val dahmerMoviesAPI = "https://edytjedhgmdhm.abfhaqrhbnf.workers.dev" const val dahmerMoviesAPI = "https://edytjedhgmdhm.abfhaqrhbnf.workers.dev"
const val jmdkhMovieAPI = "https://tg.jmdkh.eu.org/0:"
const val rubyMovieAPI = "https://upload.rubyshare111.workers.dev/0:"
const val shinobiMovieAPI = "https://home.shinobicloud.cf/0:" const val shinobiMovieAPI = "https://home.shinobicloud.cf/0:"
const val vitoenMovieAPI = "https://openmatte.vitoencodes.workers.dev/0:"
const val shivamhwAPI = "https://foogle.shivamhw.me"
val cryMoviesAPI = val cryMoviesAPI =
base64DecodeAPI("ZXY=LmQ=cnM=a2U=b3I=Lnc=ZXI=ZGQ=bGE=cy0=b2I=YWM=Lmo=YWw=aW4=LWY=cm4=Ym8=cmU=Ly8=czo=dHA=aHQ=") base64DecodeAPI("ZXY=LmQ=cnM=a2U=b3I=Lnc=ZXI=ZGQ=bGE=cy0=b2I=YWM=Lmo=YWw=aW4=LWY=cm4=Ym8=cmU=Ly8=czo=dHA=aHQ=")
// DEAD SITE
const val rinzryMoviesAPI = "https://rinzry.stream/0:"
const val chillmovies0API = "https://chill.aicirou.workers.dev/0:"
const val chillmovies1API = "https://chill.aicirou.workers.dev/1:"
const val gamMoviesAPI = "https://drive.gamick.workers.dev/0:"
const val jsMoviesAPI = "https://jsupload.jnsbot.workers.dev/0:"
const val xtremeMoviesAPI = "https://kartik19.xtrememirror0.workers.dev/0:"
const val tgarMovieAPI = "https://tgarchive.eu.org"
const val baymoviesAPI = "https://opengatewayindex.pages.dev"
const val papaonMovies1API = "https://m.papaonwork.workers.dev/0:"
const val papaonMovies2API = "https://m.papaonwork.workers.dev/1:"
fun getType(t: String?): TvType { fun getType(t: String?): TvType {
return when (t) { return when (t) {
"movie" -> TvType.Movie "movie" -> TvType.Movie
@ -267,7 +248,9 @@ open class SoraStream : TmdbProvider() {
val year = releaseDate?.split("-")?.first()?.toIntOrNull() val year = releaseDate?.split("-")?.first()?.toIntOrNull()
val rating = res.vote_average.toString().toRatingInt() val rating = res.vote_average.toString().toRatingInt()
val genres = res.genres?.mapNotNull { it.name } val genres = res.genres?.mapNotNull { it.name }
val isAnime = genres?.contains("Animation") == true && (res.original_language == "zh" || res.original_language == "ja") val isAnime =
genres?.contains("Animation") == true && (res.original_language == "zh" || res.original_language == "ja")
val isAsian = !isAnime && (res.original_language == "zh" || res.original_language == "ko")
val keywords = res.keywords?.results?.mapNotNull { it.name }.orEmpty() val keywords = res.keywords?.results?.mapNotNull { it.name }.orEmpty()
.ifEmpty { res.keywords?.keywords?.mapNotNull { it.name } } .ifEmpty { res.keywords?.keywords?.mapNotNull { it.name } }
@ -295,6 +278,7 @@ open class SoraStream : TmdbProvider() {
LinkData( LinkData(
data.id, data.id,
res.external_ids?.imdb_id, res.external_ids?.imdb_id,
res.external_ids?.tvdb_id,
data.type, data.type,
eps.seasonNumber, eps.seasonNumber,
eps.episodeNumber, eps.episodeNumber,
@ -308,6 +292,7 @@ open class SoraStream : TmdbProvider() {
jpTitle = res.alternative_titles?.results?.find { it.iso_3166_1 == "JP" }?.title, jpTitle = res.alternative_titles?.results?.find { it.iso_3166_1 == "JP" }?.title,
date = season.airDate, date = season.airDate,
airedDate = res.releaseDate ?: res.firstAirDate, airedDate = res.releaseDate ?: res.firstAirDate,
isAsian = isAsian,
).toJson(), ).toJson(),
name = eps.name + if (isUpcoming(eps.airDate)) " - [UPCOMING]" else "", name = eps.name + if (isUpcoming(eps.airDate)) " - [UPCOMING]" else "",
season = eps.seasonNumber, season = eps.seasonNumber,
@ -336,6 +321,8 @@ open class SoraStream : TmdbProvider() {
this.recommendations = recommendations this.recommendations = recommendations
this.actors = actors this.actors = actors
addTrailer(trailer) addTrailer(trailer)
addTMDbId(data.id.toString())
addImdbId(res.external_ids?.imdb_id)
} }
} else { } else {
newMovieLoadResponse( newMovieLoadResponse(
@ -345,6 +332,7 @@ open class SoraStream : TmdbProvider() {
LinkData( LinkData(
data.id, data.id,
res.external_ids?.imdb_id, res.external_ids?.imdb_id,
res.external_ids?.tvdb_id,
data.type, data.type,
title = title, title = title,
year = year, year = year,
@ -352,6 +340,7 @@ open class SoraStream : TmdbProvider() {
isAnime = isAnime, isAnime = isAnime,
jpTitle = res.alternative_titles?.results?.find { it.iso_3166_1 == "JP" }?.title, jpTitle = res.alternative_titles?.results?.find { it.iso_3166_1 == "JP" }?.title,
airedDate = res.releaseDate ?: res.firstAirDate, airedDate = res.releaseDate ?: res.firstAirDate,
isAsian = isAsian,
).toJson(), ).toJson(),
) { ) {
this.posterUrl = poster this.posterUrl = poster
@ -365,6 +354,8 @@ open class SoraStream : TmdbProvider() {
this.recommendations = recommendations this.recommendations = recommendations
this.actors = actors this.actors = actors
addTrailer(trailer) addTrailer(trailer)
addTMDbId(data.id.toString())
addImdbId(res.external_ids?.imdb_id)
} }
} }
} }
@ -395,7 +386,15 @@ open class SoraStream : TmdbProvider() {
) )
}, },
{ {
invokeGoku(res.title, res.year, res.season, res.lastSeason, res.episode, subtitleCallback, callback) invokeGoku(
res.title,
res.year,
res.season,
res.lastSeason,
res.episode,
subtitleCallback,
callback
)
}, },
{ {
invokeVidSrc(res.id, res.season, res.episode, subtitleCallback, callback) invokeVidSrc(res.id, res.season, res.episode, subtitleCallback, callback)
@ -406,15 +405,6 @@ open class SoraStream : TmdbProvider() {
{ {
invokeMovieHab(res.imdbId, res.season, res.episode, subtitleCallback, callback) invokeMovieHab(res.imdbId, res.season, res.episode, subtitleCallback, callback)
}, },
// {
// invokeDatabaseGdrive(
// res.imdbId,
// res.season,
// res.episode,
// subtitleCallback,
// callback
// )
// },
{ {
if (res.isAnime) invokeAnimes( if (res.isAnime) invokeAnimes(
res.title, res.title,
@ -427,25 +417,6 @@ open class SoraStream : TmdbProvider() {
callback callback
) )
}, },
// {
// if (res.season != null && res.isAnime) invokeCrunchyroll(
// res.title,
// res.epsTitle,
// res.season,
// res.episode,
// subtitleCallback,
// callback
// )
// },
{
if (!res.isAnime) invokeHDMovieBox(
res.title,
res.season,
res.episode,
subtitleCallback,
callback
)
},
{ {
if (!res.isAnime) invokeDreamfilm( if (!res.isAnime) invokeDreamfilm(
res.title, res.title,
@ -455,16 +426,6 @@ open class SoraStream : TmdbProvider() {
callback callback
) )
}, },
{
invokeSeries9(
res.title,
res.year,
res.season,
res.episode,
subtitleCallback,
callback
)
},
{ {
invokeIdlix( invokeIdlix(
res.title, res.title,
@ -475,18 +436,8 @@ open class SoraStream : TmdbProvider() {
callback callback
) )
}, },
{
invokeNoverse(res.title, res.season, res.episode, callback)
},
// { // {
// invokeUniqueStream( // invokeNoverse(res.title, res.season, res.episode, callback)
// res.title,
// res.year,
// res.season,
// res.episode,
// subtitleCallback,
// callback
// )
// }, // },
{ {
if (!res.isAnime) invokeFilmxy( if (!res.isAnime) invokeFilmxy(
@ -498,22 +449,8 @@ open class SoraStream : TmdbProvider() {
) )
}, },
{ {
if(!res.isAnime) invokeKimcartoon(res.title, res.season, res.episode, subtitleCallback, callback) if (!res.isAnime) invokeKimcartoon(
},
// {
// invokeXmovies(
// res.title,
// res.year,
// res.season,
// res.episode,
// subtitleCallback,
// callback
// )
// },
{
if (!res.isAnime) invokeFmovies(
res.title, res.title,
res.airedYear ?: res.year,
res.season, res.season,
res.episode, res.episode,
subtitleCallback, subtitleCallback,
@ -521,7 +458,24 @@ open class SoraStream : TmdbProvider() {
) )
}, },
{ {
invokeKisskh(res.title, res.season, res.episode, res.isAnime, res.lastSeason, subtitleCallback, callback) if (!res.isAnime) invokeVidsrcto(
res.imdbId,
res.season,
res.episode,
subtitleCallback,
callback
)
},
{
invokeKisskh(
res.title,
res.season,
res.episode,
res.isAnime,
res.lastSeason,
subtitleCallback,
callback
)
}, },
{ {
invokeLing( invokeLing(
@ -564,18 +518,15 @@ open class SoraStream : TmdbProvider() {
) )
}, },
{ {
invokeM4uhd( if (!res.isAnime) invokeM4uhd(
res.title, res.title,
res.year, res.airedYear ?: res.year,
res.season, res.season,
res.episode, res.episode,
subtitleCallback, subtitleCallback,
callback callback
) )
}, },
{
invokePutlocker(res.title, res.year, res.season, res.episode, callback)
},
{ {
invokeTvMovies(res.title, res.season, res.episode, callback) invokeTvMovies(res.title, res.season, res.episode, callback)
}, },
@ -614,9 +565,6 @@ open class SoraStream : TmdbProvider() {
{ {
invokeFlixon(res.id, res.imdbId, res.season, res.episode, callback) invokeFlixon(res.id, res.imdbId, res.season, res.episode, callback)
}, },
{
invokeMovie123Net(res.title, res.season, res.episode, subtitleCallback, callback)
},
{ {
invokeSmashyStream( invokeSmashyStream(
res.imdbId, res.imdbId,
@ -644,52 +592,6 @@ open class SoraStream : TmdbProvider() {
callback callback
) )
}, },
{
if (!res.isAnime) invokeBlackmovies(
blackMoviesAPI,
"BlackMovies",
res.title,
res.year,
res.season,
res.episode,
callback
)
},
// {
// invokeRinzrymovies(
// rinzryMoviesAPI,
// "RinzryMovies",
// res.title,
// res.year,
// res.season,
// res.episode,
// callback,
// )
// },
{
if (!res.isAnime) invokeCodexmovies(
codexMoviesAPI,
"CodexMovies",
res.title,
res.year,
res.season,
res.episode,
callback,
"Basic Y29kZXg6Y29kZXhjbG91ZA=="
)
},
{
if (!res.isAnime) invokeEdithxmovies(
edithxMoviesAPI,
"EdithxMovies",
res.title,
res.year,
res.season,
res.episode,
callback,
"Basic ZWRpdGg6amFydmlz"
)
},
{ {
invokeDahmerMovies( invokeDahmerMovies(
res.title, res.title,
@ -700,31 +602,17 @@ open class SoraStream : TmdbProvider() {
) )
}, },
{ {
invokeGomovies(res.title, res.year, res.season, res.episode, callback) invokePrimewire(res.title, res.year, res.season, res.episode, callback)
}, },
// { // {
// if (!res.isAnime) invokeTgarMovies(res.title, res.year, res.season, res.episode, callback) // if (!res.isAnime) invokeGdbotMovies(
// res.title,
// res.year,
// res.season,
// res.episode,
// callback
// )
// }, // },
{
if (!res.isAnime) invokeGdbotMovies(
res.title,
res.year,
res.season,
res.episode,
callback
)
},
{
if (!res.isAnime) invokeJmdkhMovies(
jmdkhMovieAPI,
"JmdkhMovies",
res.title,
res.year,
res.season,
res.episode,
callback
)
},
{ {
if (!res.isAnime) invokeShinobiMovies( if (!res.isAnime) invokeShinobiMovies(
shinobiMovieAPI, shinobiMovieAPI,
@ -736,35 +624,12 @@ open class SoraStream : TmdbProvider() {
callback callback
) )
}, },
{
if (!res.isAnime) invokeRubyMovies(
rubyMovieAPI,
"RubyMovies",
res.title,
res.year,
res.season,
res.episode,
callback
)
},
{
if (!res.isAnime) invokeVitoenMovies(
vitoenMovieAPI,
"VitoenMovies",
res.title,
res.year,
res.season,
res.episode,
callback
)
},
{ {
if (!res.isAnime) invokeAsk4Movies( if (!res.isAnime) invokeAsk4Movies(
res.title, res.title,
res.year, res.year,
res.season, res.season,
res.episode, res.episode,
subtitleCallback,
callback callback
) )
}, },
@ -780,21 +645,11 @@ open class SoraStream : TmdbProvider() {
callback callback
) )
}, },
{
if (!res.isAnime) invokeShivamhw(
res.title,
res.year,
res.season,
res.episode,
callback
)
},
{ {
if (!res.isAnime && res.season == null) invokeCryMovies( if (!res.isAnime && res.season == null) invokeCryMovies(
res.imdbId, res.imdbId,
res.title, res.title,
res.year, res.year,
res.season,
res.episode, res.episode,
callback callback
) )
@ -809,14 +664,87 @@ open class SoraStream : TmdbProvider() {
invokeNavy(res.imdbId, res.season, res.episode, callback) invokeNavy(res.imdbId, res.season, res.episode, callback)
}, },
{ {
if (!res.isAnime) invokeEmovies(res.title, res.year, res.season, res.episode, subtitleCallback, callback) invokeMoment(res.imdbId, res.season, res.episode, callback)
}, },
{ {
if(!res.isAnime && res.season == null) invokePobmovies(res.title, res.year, callback) if (!res.isAnime) invokeEmovies(
res.title,
res.year,
res.season,
res.episode,
subtitleCallback,
callback
)
}, },
{ {
if(!res.isAnime) invokeFourCartoon(res.title, res.year, res.season, res.episode, callback) if (!res.isAnime && res.season == null) invokePobmovies(
} res.title,
res.year,
callback
)
},
{
if (!res.isAnime) invokeFourCartoon(
res.title,
res.year,
res.season,
res.episode,
callback
)
},
{
invokeMultimovies(res.title, res.season, res.episode, subtitleCallback, callback)
},
{
invokeNetmovies(
res.title,
res.year,
res.season,
res.episode,
subtitleCallback,
callback
)
},
{
if (!res.isAnime && res.season == null) invokeDoomovies(
res.title,
subtitleCallback,
callback
)
},
{
if (res.isAsian) invokeDramaday(
res.title,
res.year,
res.season,
res.episode,
subtitleCallback,
callback
)
},
{
if (!res.isAnime) invoke2embed(res.imdbId, res.season, res.episode, callback)
},
// {
// invokeSusflix(res.id,res.season,res.episode,subtitleCallback,callback)
// },
{
if (!res.isAnime) invokeJump1(
res.id,
res.tvdbId,
res.title,
res.year,
res.season,
res.episode,
callback
)
},
{
if (!res.isAnime && res.season == null) invokeOmega(
res.id,
callback
)
},
) )
return true return true
@ -825,6 +753,7 @@ open class SoraStream : TmdbProvider() {
data class LinkData( data class LinkData(
val id: Int? = null, val id: Int? = null,
val imdbId: String? = null, val imdbId: String? = null,
val tvdbId: Int? = null,
val type: String? = null, val type: String? = null,
val season: Int? = null, val season: Int? = null,
val episode: Int? = null, val episode: Int? = null,
@ -840,6 +769,7 @@ open class SoraStream : TmdbProvider() {
val jpTitle: String? = null, val jpTitle: String? = null,
val date: String? = null, val date: String? = null,
val airedDate: String? = null, val airedDate: String? = null,
val isAsian: Boolean = false,
) )
data class Data( data class Data(
@ -928,7 +858,7 @@ open class SoraStream : TmdbProvider() {
data class ExternalIds( data class ExternalIds(
@JsonProperty("imdb_id") val imdb_id: String? = null, @JsonProperty("imdb_id") val imdb_id: String? = null,
@JsonProperty("tvdb_id") val tvdb_id: String? = null, @JsonProperty("tvdb_id") val tvdb_id: Int? = null,
) )
data class Credits( data class Credits(
@ -971,13 +901,6 @@ open class SoraStream : TmdbProvider() {
@JsonProperty("alternative_titles") val alternative_titles: ResultsAltTitles? = null, @JsonProperty("alternative_titles") val alternative_titles: ResultsAltTitles? = null,
) )
data class EmbedJson(
@JsonProperty("type") val type: String? = null,
@JsonProperty("link") val link: String? = null,
@JsonProperty("sources") val sources: List<String?> = arrayListOf(),
@JsonProperty("tracks") val tracks: List<String>? = null,
)
data class MovieHabData( data class MovieHabData(
@JsonProperty("link") val link: String? = null, @JsonProperty("link") val link: String? = null,
@JsonProperty("token") val token: String? = null, @JsonProperty("token") val token: String? = null,

View file

@ -1,38 +1,41 @@
package com.hexated package com.hexated
import com.hexated.SoraExtractor.invoke2embed
import com.hexated.SoraExtractor.invokeAnimes import com.hexated.SoraExtractor.invokeAnimes
import com.hexated.SoraExtractor.invokeAsk4Movies import com.hexated.SoraExtractor.invokeAsk4Movies
import com.hexated.SoraExtractor.invokeDbgo import com.hexated.SoraExtractor.invokeDbgo
import com.hexated.SoraExtractor.invokeDoomovies
import com.hexated.SoraExtractor.invokeDramaday
import com.hexated.SoraExtractor.invokeDreamfilm import com.hexated.SoraExtractor.invokeDreamfilm
import com.hexated.SoraExtractor.invokeFilmxy import com.hexated.SoraExtractor.invokeFilmxy
import com.hexated.SoraExtractor.invokeFlixon import com.hexated.SoraExtractor.invokeFlixon
import com.hexated.SoraExtractor.invokeFmovies
import com.hexated.SoraExtractor.invokeFwatayako import com.hexated.SoraExtractor.invokeFwatayako
import com.hexated.SoraExtractor.invokeGoku import com.hexated.SoraExtractor.invokeGoku
import com.hexated.SoraExtractor.invokeGomovies
import com.hexated.SoraExtractor.invokeHDMovieBox
import com.hexated.SoraExtractor.invokeIdlix import com.hexated.SoraExtractor.invokeIdlix
import com.hexated.SoraExtractor.invokeKimcartoon import com.hexated.SoraExtractor.invokeKimcartoon
import com.hexated.SoraExtractor.invokeKisskh import com.hexated.SoraExtractor.invokeKisskh
import com.hexated.SoraExtractor.invokeLing import com.hexated.SoraExtractor.invokeLing
import com.hexated.SoraExtractor.invokeM4uhd import com.hexated.SoraExtractor.invokeM4uhd
import com.hexated.SoraExtractor.invokeMovie123Net
import com.hexated.SoraExtractor.invokeMovieHab import com.hexated.SoraExtractor.invokeMovieHab
import com.hexated.SoraExtractor.invokeNavy import com.hexated.SoraExtractor.invokeNavy
import com.hexated.SoraExtractor.invokeNinetv import com.hexated.SoraExtractor.invokeNinetv
import com.hexated.SoraExtractor.invokeNowTv import com.hexated.SoraExtractor.invokeNowTv
import com.hexated.SoraExtractor.invokePutlocker
import com.hexated.SoraExtractor.invokeRStream import com.hexated.SoraExtractor.invokeRStream
import com.hexated.SoraExtractor.invokeRidomovies import com.hexated.SoraExtractor.invokeRidomovies
import com.hexated.SoraExtractor.invokeSeries9
import com.hexated.SoraExtractor.invokeSmashyStream import com.hexated.SoraExtractor.invokeSmashyStream
import com.hexated.SoraExtractor.invokeDumpStream import com.hexated.SoraExtractor.invokeDumpStream
import com.hexated.SoraExtractor.invokeEmovies import com.hexated.SoraExtractor.invokeEmovies
import com.hexated.SoraExtractor.invokeFourCartoon import com.hexated.SoraExtractor.invokeFourCartoon
import com.hexated.SoraExtractor.invokeJump1
import com.hexated.SoraExtractor.invokeMoment
import com.hexated.SoraExtractor.invokeMultimovies
import com.hexated.SoraExtractor.invokeNetmovies
import com.hexated.SoraExtractor.invokeOmega
import com.hexated.SoraExtractor.invokePrimewire
import com.hexated.SoraExtractor.invokeVidSrc import com.hexated.SoraExtractor.invokeVidSrc
import com.hexated.SoraExtractor.invokeVidsrcto
import com.hexated.SoraExtractor.invokeWatchOnline import com.hexated.SoraExtractor.invokeWatchOnline
import com.hexated.SoraExtractor.invokeWatchsomuch import com.hexated.SoraExtractor.invokeWatchsomuch
import com.hexated.SoraExtractor.invokeXmovies
import com.lagradost.cloudstream3.SubtitleFile import com.lagradost.cloudstream3.SubtitleFile
import com.lagradost.cloudstream3.argamap import com.lagradost.cloudstream3.argamap
import com.lagradost.cloudstream3.utils.AppUtils import com.lagradost.cloudstream3.utils.AppUtils
@ -52,14 +55,17 @@ class SoraStreamLite : SoraStream() {
argamap( argamap(
{ {
invokePutlocker( if(!res.isAnime) invokeJump1(res.id,res.tvdbId,res.title,res.year,res.season,res.episode,callback)
res.title,
res.year,
res.season,
res.episode,
callback
)
}, },
// {
// invokeSusflix(
// res.id,
// res.season,
// res.episode,
// subtitleCallback,
// callback
// )
// },
{ {
invokeWatchsomuch( invokeWatchsomuch(
res.imdbId, res.imdbId,
@ -88,7 +94,15 @@ class SoraStreamLite : SoraStream() {
) )
}, },
{ {
invokeGoku(res.title, res.year, res.season, res.lastSeason, res.episode, subtitleCallback, callback) invokeGoku(
res.title,
res.year,
res.season,
res.lastSeason,
res.episode,
subtitleCallback,
callback
)
}, },
{ {
invokeVidSrc(res.id, res.season, res.episode, subtitleCallback, callback) invokeVidSrc(res.id, res.season, res.episode, subtitleCallback, callback)
@ -96,15 +110,6 @@ class SoraStreamLite : SoraStream() {
{ {
invokeDbgo(res.imdbId, res.season, res.episode, subtitleCallback, callback) invokeDbgo(res.imdbId, res.season, res.episode, subtitleCallback, callback)
}, },
{
invokeMovie123Net(
res.title,
res.season,
res.episode,
subtitleCallback,
callback
)
},
{ {
invokeMovieHab(res.imdbId, res.season, res.episode, subtitleCallback, callback) invokeMovieHab(res.imdbId, res.season, res.episode, subtitleCallback, callback)
}, },
@ -120,25 +125,6 @@ class SoraStreamLite : SoraStream() {
callback callback
) )
}, },
// {
// if (res.season != null && res.isAnime) invokeCrunchyroll(
// res.title,
// res.epsTitle,
// res.season,
// res.episode,
// subtitleCallback,
// callback
// )
// },
{
if (!res.isAnime) invokeHDMovieBox(
res.title,
res.season,
res.episode,
subtitleCallback,
callback
)
},
{ {
if (!res.isAnime) invokeDreamfilm( if (!res.isAnime) invokeDreamfilm(
res.title, res.title,
@ -148,16 +134,6 @@ class SoraStreamLite : SoraStream() {
callback callback
) )
}, },
{
invokeSeries9(
res.title,
res.year,
res.season,
res.episode,
subtitleCallback,
callback
)
},
{ {
invokeIdlix( invokeIdlix(
res.title, res.title,
@ -188,7 +164,13 @@ class SoraStreamLite : SoraStream() {
) )
}, },
{ {
if(!res.isAnime) invokeKimcartoon(res.title, res.season, res.episode, subtitleCallback, callback) if (!res.isAnime) invokeKimcartoon(
res.title,
res.season,
res.episode,
subtitleCallback,
callback
)
}, },
{ {
invokeSmashyStream( invokeSmashyStream(
@ -211,9 +193,8 @@ class SoraStreamLite : SoraStream() {
// ) // )
// }, // },
{ {
if (!res.isAnime) invokeFmovies( if (!res.isAnime) invokeVidsrcto(
res.title, res.imdbId,
res.airedYear ?: res.year,
res.season, res.season,
res.episode, res.episode,
subtitleCallback, subtitleCallback,
@ -221,7 +202,15 @@ class SoraStreamLite : SoraStream() {
) )
}, },
{ {
invokeKisskh(res.title, res.season, res.episode, res.isAnime, res.lastSeason, subtitleCallback, callback) invokeKisskh(
res.title,
res.season,
res.episode,
res.isAnime,
res.lastSeason,
subtitleCallback,
callback
)
}, },
{ {
invokeLing( invokeLing(
@ -237,15 +226,21 @@ class SoraStreamLite : SoraStream() {
invokeFwatayako(res.imdbId, res.season, res.episode, callback) invokeFwatayako(res.imdbId, res.season, res.episode, callback)
}, },
{ {
invokeM4uhd( if(!res.isAnime) invokeM4uhd(
res.title, res.title,
res.year, res.airedYear ?: res.year,
res.season, res.season,
res.episode, res.episode,
subtitleCallback, subtitleCallback,
callback callback
) )
}, },
{
if (!res.isAnime && res.season == null) invokeOmega(
res.id,
callback
)
},
{ {
invokeRStream(res.id, res.season, res.episode, callback) invokeRStream(res.id, res.season, res.episode, callback)
}, },
@ -253,7 +248,7 @@ class SoraStreamLite : SoraStream() {
invokeFlixon(res.id, res.imdbId, res.season, res.episode, callback) invokeFlixon(res.id, res.imdbId, res.season, res.episode, callback)
}, },
{ {
invokeGomovies(res.title, res.year, res.season, res.episode, callback) invokePrimewire(res.title, res.year, res.season, res.episode, callback)
}, },
{ {
if (!res.isAnime) invokeAsk4Movies( if (!res.isAnime) invokeAsk4Movies(
@ -261,7 +256,6 @@ class SoraStreamLite : SoraStream() {
res.year, res.year,
res.season, res.season,
res.episode, res.episode,
subtitleCallback,
callback callback
) )
}, },
@ -308,7 +302,48 @@ class SoraStreamLite : SoraStream() {
res.episode, res.episode,
callback callback
) )
} },
{
invokeMultimovies(res.title, res.season, res.episode, subtitleCallback, callback)
},
{
invokeNetmovies(
res.title,
res.year,
res.season,
res.episode,
subtitleCallback,
callback
)
},
{
invokeMoment(res.imdbId, res.season, res.episode, callback)
},
{
if (!res.isAnime && res.season == null) invokeDoomovies(
res.title,
subtitleCallback,
callback
)
},
{
if(res.isAsian) invokeDramaday(
res.title,
res.year,
res.season,
res.episode,
subtitleCallback,
callback
)
},
{
if(!res.isAnime) invoke2embed(
res.imdbId,
res.season,
res.episode,
callback
)
},
) )
return true return true

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