This commit is contained in:
yoyzo 2023-01-10 14:42:08 +03:00 committed by GitHub Actions
commit 9ea7b9e5cd
87 changed files with 4255 additions and 0 deletions

60
.github/workflows/build.yml vendored Normal file
View File

@ -0,0 +1,60 @@
name: Build
# https://docs.github.com/en/actions/learn-github-actions/workflow-syntax-for-github-actions#concurrency
concurrency:
group: "build"
cancel-in-progress: true
on:
push:
branches:
# choose your default branch
- master
# - main
paths-ignore:
- '*.md'
- '*.html'
- '*.js'
- '*.css'
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@master
with:
path: "src"
- name: Checkout builds
uses: actions/checkout@master
with:
ref: "builds"
path: "builds"
- name: Clean old builds
run: rm $GITHUB_WORKSPACE/builds/*.cs3 || true
- name: Setup JDK 11
uses: actions/setup-java@v1
with:
java-version: 11
- name: Setup Android SDK
uses: android-actions/setup-android@v2
- name: Build Plugins
run: |
cd $GITHUB_WORKSPACE/src
chmod +x gradlew
./gradlew make makePluginsJson
cp **/build/*.cs3 $GITHUB_WORKSPACE/builds
cp build/plugins.json $GITHUB_WORKSPACE/builds
- name: Push builds
run: |
cd $GITHUB_WORKSPACE/builds
git config --local user.email "actions@github.com"
git config --local user.name "GitHub Actions"
git add .
git commit --amend -m "Build $GITHUB_SHA" || exit 0 # do not error if nothing to commit
git push --force

12
.gitignore vendored Normal file
View File

@ -0,0 +1,12 @@
*.iml
.gradle
/local.properties
/.idea
.DS_Store
/build
**/build
/captures
.externalNativeBuild
.cxx
local.properties
.vscode

BIN
AkwamProvider.cs3 Normal file

Binary file not shown.

View File

@ -0,0 +1,14 @@
version = 1
cloudstream {
description = ""
authors = listOf( "Blatzar" )
language = "ar"
status = 1
tvTypes = listOf( "TvSeries" , "Movie" , "Anime" , "Cartoon" )
iconUrl = "https://www.google.com/s2/favicons?domain=akwam.to&sz=%size%"
}

View File

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

View File

@ -0,0 +1,11 @@
package com.akwam
import com.lagradost.cloudstream3.plugins.CloudstreamPlugin
import com.lagradost.cloudstream3.plugins.Plugin
import android.content.Context
@CloudstreamPlugin
class AkwamPlugin: Plugin() {
override fun load(context: Context) {
registerMainAPI(Akwam())
}
}

View File

@ -0,0 +1,225 @@
package com.akwam
import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.LoadResponse.Companion.addActors
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.Qualities
import org.jsoup.nodes.Element
class Akwam : MainAPI() {
override var lang = "ar"
override var mainUrl = "https://akwam.to"
override var name = "Akwam"
override val usesWebView = false
override val hasMainPage = true
override val supportedTypes = setOf(TvType.TvSeries, TvType.Movie, TvType.Anime, TvType.Cartoon)
private fun Element.toSearchResponse(): SearchResponse? {
val url = select("a.box").attr("href") ?: return null
if (url.contains("/games/") || url.contains("/programs/")) return null
val poster = select("picture > img")
val title = poster.attr("alt")
val posterUrl = poster.attr("data-src")
val year = select(".badge-secondary").text().toIntOrNull()
// If you need to differentiate use the url.
return MovieSearchResponse(
title,
url,
this@Akwam.name,
TvType.TvSeries,
posterUrl,
year,
null,
)
}
override val mainPage = mainPageOf(
"$mainUrl/movies?page=" to "Movies",
"$mainUrl/series?page=" to "Series",
"$mainUrl/shows?page=" to "Shows"
)
override suspend fun getMainPage(page: Int, request : MainPageRequest): HomePageResponse {
val doc = app.get(request.data + page).document
val list = doc.select("div.col-lg-auto.col-md-4.col-6.mb-12").mapNotNull { element ->
element.toSearchResponse()
}
return newHomePageResponse(request.name, list)
}
override suspend fun search(query: String): List<SearchResponse> {
val url = "$mainUrl/search?q=$query"
val doc = app.get(url).document
return doc.select("div.col-lg-auto").mapNotNull {
it.toSearchResponse()
}
}
private fun String.getIntFromText(): Int? {
return Regex("""\d+""").find(this)?.groupValues?.firstOrNull()?.toIntOrNull()
}
private fun Element.toEpisode(): Episode {
val a = select("a.text-white")
val url = a.attr("href")
val title = a.text()
val thumbUrl = select("picture > img").attr("src")
val date = select("p.entry-date").text()
return newEpisode(url) {
name = title
episode = title.getIntFromText()
posterUrl = thumbUrl
addDate(date)
}
}
override suspend fun load(url: String): LoadResponse {
val doc = app.get(url).document
val mesEl = doc.select("#downloads > h2 > span").isNotEmpty()
val mesSt = if(mesEl) true else false
val isMovie = mesSt//url.contains("/movie/")
val title = doc.select("h1.entry-title").text()
val posterUrl = doc.select("picture > img").attr("src")
val year =
doc.select("div.font-size-16.text-white.mt-2").firstOrNull {
it.text().contains("السنة")
}?.text()?.getIntFromText()
// A bit iffy to parse twice like this, but it'll do.
val duration =
doc.select("div.font-size-16.text-white.mt-2").firstOrNull {
it.text().contains("مدة الفيلم")
}?.text()?.getIntFromText()
val synopsis = doc.select("div.widget-body p:first-child").text()
val rating = doc.select("span.mx-2").text().split("/").lastOrNull()?.toRatingInt()
val tags = doc.select("div.font-size-16.d-flex.align-items-center.mt-3 > a").map {
it.text()
}
val actors = doc.select("div.widget-body > div > div.entry-box > a").mapNotNull {
val name = it?.selectFirst("div > .entry-title")?.text() ?: return@mapNotNull null
val image = it.selectFirst("div > img")?.attr("src") ?: return@mapNotNull null
Actor(name, image)
}
val recommendations =
doc.select("div > div.widget-body > div.row > div > div.entry-box").mapNotNull {
val recTitle = it?.selectFirst("div.entry-body > .entry-title > .text-white")
?: return@mapNotNull null
val href = recTitle.attr("href") ?: return@mapNotNull null
val name = recTitle.text() ?: return@mapNotNull null
val poster = it.selectFirst(".entry-image > a > picture > img")?.attr("data-src")
?: return@mapNotNull null
MovieSearchResponse(name, href, this.name, TvType.Movie, fixUrl(poster))
}
return if (isMovie) {
newMovieLoadResponse(
title,
url,
TvType.Movie,
url
) {
this.posterUrl = posterUrl
this.year = year
this.plot = synopsis
this.rating = rating
this.tags = tags
this.duration = duration
this.recommendations = recommendations
addActors(actors)
}
} else {
val episodes = doc.select("div.bg-primary2.p-4.col-lg-4.col-md-6.col-12").map {
it.toEpisode()
}.let {
val isReversed = (it.lastOrNull()?.episode ?: 1) < (it.firstOrNull()?.episode ?: 0)
if (isReversed)
it.reversed()
else it
}
newTvSeriesLoadResponse(title, url, TvType.TvSeries, episodes) {
this.duration = duration
this.posterUrl = posterUrl
this.tags = tags.filterNotNull()
this.rating = rating
this.year = year
this.plot = synopsis
this.recommendations = recommendations
addActors(actors)
}
}
}
// // Maybe possible to not use the url shortener but cba investigating that.
// private suspend fun skipUrlShortener(url: String): AppResponse {
// return app.get(app.get(url).document.select("a.download-link").attr("href"))
// }
private fun getQualityFromId(id: Int?): Qualities {
return when (id) {
2 -> Qualities.P360 // Extrapolated
3 -> Qualities.P480
4 -> Qualities.P720
5 -> Qualities.P1080
else -> Qualities.Unknown
}
}
override suspend fun loadLinks(
data: String,
isCasting: Boolean,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
): Boolean {
val doc = app.get(data).document
val links = doc.select("div.tab-content.quality").map { element ->
val quality = getQualityFromId(element.attr("id").getIntFromText())
element.select(".col-lg-6 > a:contains(تحميل)").map { linkElement ->
if (linkElement.attr("href").contains("/download/")) {
Pair(
linkElement.attr("href"),
quality,
)
} else {
val url = "$mainUrl/download${
linkElement.attr("href").split("/link")[1]
}${data.split("/movie|/episode|/shows|/show/episode".toRegex())[1]}"
Pair(
url,
quality,
)
// just in case if they add the shorts urls again
}
}
}.flatten()
links.map {
val linkDoc = app.get(it.first).document
val button = linkDoc.select("div.btn-loader > a")
val url = button.attr("href")
callback.invoke(
ExtractorLink(
this.name,
this.name,
url,
this.mainUrl,
it.second.value
)
)
}
return true
}
}

BIN
Anime4upPack.cs3 Normal file

Binary file not shown.

View File

@ -0,0 +1,14 @@
version = 1
cloudstream {
description = "This pack contains Anime4up and Witanime"
authors = listOf( "ImZaw" )
language = "ar"
status = 1
tvTypes = listOf( "Anime", "AnimeMovie", "Others" )
iconUrl = "https://www.google.com/s2/favicons?domain=anime4up.tv&sz=%size%"
}

View File

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

View File

@ -0,0 +1,13 @@
package com.anime4up
import com.lagradost.cloudstream3.plugins.CloudstreamPlugin
import com.lagradost.cloudstream3.plugins.Plugin
import android.content.Context
@CloudstreamPlugin
class Anime4upPlugin: Plugin() {
override fun load(context: Context) {
registerMainAPI(Anime4up())
registerMainAPI(WitAnime())
}
}

View File

@ -0,0 +1,167 @@
package com.anime4up
import com.fasterxml.jackson.annotation.JsonProperty
import com.lagradost.cloudstream3.utils.AppUtils.parseJson
import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.LoadResponse.Companion.addMalId
import com.lagradost.cloudstream3.utils.ExtractorLink
import okio.ByteString.Companion.decodeBase64
import com.lagradost.cloudstream3.utils.loadExtractor
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import java.net.URL
private fun String.getIntFromText(): Int? {
return Regex("""\d+""").find(this)?.groupValues?.firstOrNull()?.toIntOrNull()
}
class WitAnime : Anime4up() {
override var name = "WitAnime"
override var mainUrl = "https://witanime.com"
}
open class Anime4up : MainAPI() {
override var lang = "ar"
override var mainUrl = "https://anime4up.tv"
override var name = "Anime4up"
override val usesWebView = false
override val hasMainPage = true
override val supportedTypes =
setOf(TvType.Anime, TvType.AnimeMovie, TvType.OVA, TvType.Others )
private fun Element.toSearchResponse(): SearchResponse {
val imgElement = select("div.hover > img")
val url = select("div.hover > a").attr("href")
.replace("-%d8%a7%d9%84%d8%ad%d9%84%d9%82%d8%a9-.*".toRegex(), "")
.replace("episode", "anime")
val title = imgElement.attr("alt")
val posterUrl = imgElement.attr("src")
val typeText = select("div.anime-card-type > a").text()
val type =
if (typeText.contains("TV|Special".toRegex())) TvType.Anime
else if(typeText.contains("OVA|ONA".toRegex())) TvType.OVA
else if(typeText.contains("Movie")) TvType.AnimeMovie
else TvType.Others
return newAnimeSearchResponse(
title,
url,
type,
) {
this.posterUrl = posterUrl
}
}
override suspend fun getMainPage(page: Int, request: MainPageRequest): HomePageResponse {
val doc = app.get("$mainUrl/").document
val homeList = doc.select(".page-content-container")
.mapNotNull {
val title = it.select("div.main-didget-head h3").text()
val list =
it.select("div.anime-card-container, div.episodes-card-container").map {
anime -> anime.toSearchResponse()
}.distinct()
HomePageList(title, list, isHorizontalImages = title.contains("حلقات"))
}
return newHomePageResponse(homeList, hasNext = false)
}
override suspend fun search(query: String): List<SearchResponse> {
return app.get("$mainUrl/?search_param=animes&s=$query").document
.select("div.row.display-flex > div").mapNotNull {
it.toSearchResponse()
}
}
override suspend fun load(url: String): LoadResponse {
val doc = app.get(url).document
val title = doc.select("h1.anime-details-title").text()
val poster = doc.select("div.anime-thumbnail img").attr("src")
val description = doc.select("p.anime-story").text()
val year = doc.select("div.anime-info:contains(بداية العرض)").text().replace("بداية العرض: ", "").toIntOrNull()
val typeText = doc.select(".anime-info:contains(النوع) a").text()
val type =
if (typeText.contains("TV|Special".toRegex())) TvType.Anime
else if(typeText.contains("OVA|ONA".toRegex())) TvType.OVA
else if(typeText.contains("Movie")) TvType.AnimeMovie
else TvType.Others
val malId = doc.select("a.anime-mal").attr("href").replace(".*e\\/|\\/.*".toRegex(),"").toIntOrNull()
val episodes = doc.select("div#DivEpisodesList > div").apmap {
val episodeElement = it.select("h3 a")
val episodeUrl = episodeElement.attr("href")
val episodeTitle = episodeElement.text()
val posterUrl = it.select(".hover img").attr("src")
Episode(
episodeUrl,
episodeTitle,
episode = episodeTitle.getIntFromText(),
posterUrl = posterUrl
)
}
return newAnimeLoadResponse(title, url, type) {
this.apiName = this@Anime4up.name
addMalId(malId)
engName = title
posterUrl = poster
this.year = year
addEpisodes(if(title.contains("مدبلج")) DubStatus.Dubbed else DubStatus.Subbed, episodes)
plot = description
this.rating = rating
}
}
data class sources (
@JsonProperty("hd" ) var hd : Map<String, String>? = null,
@JsonProperty("fhd" ) var fhd : Map<String, String>? = null,
@JsonProperty("sd" ) var sd : Map<String, String>? = null
)
override suspend fun loadLinks(
data: String,
isCasting: Boolean,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
): Boolean {
val doc = app.get(data).document
if(data.contains("anime4up")) {
val watchJSON = parseJson<sources>(doc.select("input[name=\"wl\"]").attr("value").decodeBase64()?.utf8() ?: "")
watchJSON.let { source ->
source.fhd?.apmap {
loadExtractor(it.value, data, subtitleCallback, callback)
}
source.hd?.apmap {
loadExtractor(it.value, data, subtitleCallback, callback)
}
source.sd?.apmap {
loadExtractor(it.value, data, subtitleCallback, callback)
}
}
val moshahdaID = doc.select("input[name=\"moshahda\"]").attr("value").decodeBase64()?.utf8() ?: ""
if(moshahdaID.isNotEmpty()) {
mapOf(
"Original" to "download_o",
"720" to "download_x",
"480" to "download_h",
"360" to "download_n",
"240" to "download_l"
).apmap { (quality, qualityCode) ->
callback.invoke(
ExtractorLink(
this.name,
this.name + " Moshahda",
"https://moshahda.net/$moshahdaID.html?${qualityCode}",
"https://moshahda.net",
quality.toIntOrNull() ?: 1080
)
) }
}
} else if(data.contains("witanime")) { // witanime
doc.select("ul#episode-servers li a").apmap {
loadExtractor(it.attr("data-ep-url"), data, subtitleCallback, callback)
}
}
return true
}
}

BIN
AnimeBlkomProvider.cs3 Normal file

Binary file not shown.

View File

@ -0,0 +1,14 @@
version = 2
cloudstream {
description = ""
authors = listOf( "ImZaw" )
language = "ar"
status = 1
tvTypes = listOf( "Anime" , "AnimeMovie" , "OVA" )
iconUrl = "https://www.google.com/s2/favicons?domain=animeblkom.net&sz=%size%"
}

View File

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

View File

@ -0,0 +1,11 @@
package com.animeblkom
import com.lagradost.cloudstream3.plugins.CloudstreamPlugin
import com.lagradost.cloudstream3.plugins.Plugin
import android.content.Context
@CloudstreamPlugin
class AnimeBlkomPlugin: Plugin() {
override fun load(context: Context) {
registerMainAPI(AnimeBlkom())
}
}

View File

@ -0,0 +1,164 @@
package com.animeblkom
import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.LoadResponse.Companion.addMalId
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.Qualities
import com.lagradost.cloudstream3.utils.loadExtractor
import org.jsoup.nodes.Element
class AnimeBlkom : MainAPI() {
override var mainUrl = "https://animeblkom.net"
override var name = "AnimeBlkom"
override var lang = "ar"
override val hasMainPage = true
override val supportedTypes = setOf(
TvType.Anime,
TvType.AnimeMovie,
TvType.OVA,
)
private fun Element.toSearchResponse(): SearchResponse {
val url = select("div.poster a").attr("href")
val name = select("div.name a").text()
val poster = mainUrl + select("div.poster img").attr("data-original")
val year = select("div[title=\"سنة الانتاج\"]").text().toIntOrNull()
val episodesNumber = select("div[title=\"عدد الحلقات\"]").text().toIntOrNull()
val tvType = select("div[title=\"النوع\"]").text().let { if(it.contains("فيلم|خاصة".toRegex())) TvType.AnimeMovie else if(it.contains("أوفا|أونا".toRegex())) TvType.OVA else TvType.Anime }
return newAnimeSearchResponse(
name,
url,
tvType,
) {
addDubStatus(false, episodesNumber)
this.year = year
this.posterUrl = poster
}
}
override val mainPage = mainPageOf(
"$mainUrl/anime-list?sort_by=rate&page=" to "Most rated",
"$mainUrl/anime-list?sort_by=created_at&page=" to "Recently added",
"$mainUrl/anime-list?states=finished&page=" to "Completed"
)
override suspend fun getMainPage(page: Int, request: MainPageRequest): HomePageResponse {
val doc = app.get(request.data + page).document
val list = doc.select("div.content-inner")
.mapNotNull { element ->
element.toSearchResponse()
}
return newHomePageResponse(request.name, list)
}
override suspend fun search(query: String): List<SearchResponse> {
val q = query.replace(" ","+")
return app.get("$mainUrl/search?query=$q").document.select("div.content.ratable").map {
it.toSearchResponse()
}
}
override suspend fun load(url: String): LoadResponse {
val doc = app.get(url).document
val title = doc.select("span h1").text().replace("\\(.*".toRegex(),"")
val poster = mainUrl + doc.select("div.poster img").attr("data-original")
val description = doc.select(".story p").text()
val genre = doc.select("p.genres a").map {
it.text()
}
val year = doc.select(".info-table div:contains(تاريخ الانتاج) span.info").text().split("-")[0].toIntOrNull()
val status = doc.select(".info-table div:contains(حالة الأنمي) span.info").text().let { if(it.contains("مستمر")) ShowStatus.Ongoing else ShowStatus.Completed }
val nativeName = doc.select("span[title=\"الاسم باليابانية\"]").text().replace(".*:".toRegex(),"")
val type = doc.select("h1 small").text().let {
if (it.contains("movie")) TvType.AnimeMovie
if (it.contains("ova|ona".toRegex())) TvType.OVA
else TvType.Anime
}
val malId = doc.select("a.blue.cta:contains(المزيد من المعلومات)").attr("href").replace(".*e\\/|\\/.*".toRegex(),"").toInt()
val episodes = arrayListOf<Episode>()
val episodeElements = doc.select(".episode-link")
if(episodeElements.isEmpty()) {
episodes.add(Episode(
url,
"Watch",
))
} else {
episodeElements.map {
val a = it.select("a")
episodes.add(Episode(
mainUrl + a.attr("href"),
a.text().replace(":"," "),
episode = a.select("span").not(".pull-left").last()?.text()?.toIntOrNull()
))
}
}
return newAnimeLoadResponse(title, url, type) {
addMalId(malId)
japName = nativeName
engName = title
posterUrl = poster
this.year = year
addEpisodes(DubStatus.Subbed, episodes) // TODO CHECK
plot = description
tags = genre
showStatus = status
}
}
override suspend fun loadLinks(
data: String,
isCasting: Boolean,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
): Boolean {
val doc = app.get(data).document
doc.select("div.item a[data-src]").map {
it.attr("data-src").let { url ->
if(url.startsWith("https://animetitans.net/")) {
val iframe = app.get(url).document
callback.invoke(
ExtractorLink(
this.name,
"Animetitans " + it.text(),
iframe.select("script").last()?.data()?.substringAfter("source: \"")?.substringBefore("\"").toString(),
this.mainUrl,
Qualities.Unknown.value,
isM3u8 = true
)
)
} else if(it.text() == "Blkom") {
val iframe = app.get(url).document
iframe.select("source").forEach { source ->
callback.invoke(
ExtractorLink(
this.name,
it.text(),
source.attr("src"),
this.mainUrl,
source.attr("res").toInt()
)
)
}
} else {
var sourceUrl = url
if(it.text().contains("Google")) sourceUrl = "http://gdriveplayer.to/embed2.php?link=$url"
loadExtractor(sourceUrl, mainUrl, subtitleCallback, callback)
}
}
}
doc.select(".panel .panel-body a").apmap {
println(it.text())
callback.invoke(
ExtractorLink(
this.name,
it.attr("title") + " " + it.select("small").text() + " Download Source",
it.attr("href"),
this.mainUrl,
it.text().replace("p.*| ".toRegex(),"").toInt(),
)
)
}
return true
}
}

BIN
AnimeiatProvider.cs3 Normal file

Binary file not shown.

View File

@ -0,0 +1,14 @@
version = 2
cloudstream {
description = ""
authors = listOf( "ImZaw" )
language = "ar"
status = 1
tvTypes = listOf( "Anime" )
iconUrl = "https://www.google.com/s2/favicons?domain=animeiat.tv&sz=%size%"
}

View File

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

View File

@ -0,0 +1,11 @@
package com.animeiat
import com.lagradost.cloudstream3.plugins.CloudstreamPlugin
import com.lagradost.cloudstream3.plugins.Plugin
import android.content.Context
@CloudstreamPlugin
class AnimeiatPlugin: Plugin() {
override fun load(context: Context) {
registerMainAPI(Animeiat())
}
}

View File

@ -0,0 +1,172 @@
package com.animeiat
import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.loadExtractor
import com.fasterxml.jackson.annotation.JsonProperty
import com.lagradost.cloudstream3.utils.AppUtils.parseJson
import com.lagradost.nicehttp.Requests
class Animeiat : MainAPI() {
override var lang = "ar"
override var mainUrl = "https://api.animeiat.co/v1"
val pageUrl = "https://www.animeiat.tv"
override var name = "Animeiat"
override val usesWebView = false
override val hasMainPage = true
override val supportedTypes =
setOf(TvType.Anime, TvType.AnimeMovie)
data class Data (
@JsonProperty("anime_name" ) var animeName : String? = null,
@JsonProperty("title" ) var title : String? = null,
@JsonProperty("slug" ) var slug : String? = null,
@JsonProperty("story" ) var story : String? = null,
@JsonProperty("other_names" ) var otherNames : String? = null,
@JsonProperty("total_episodes" ) var totalEpisodes : Int? = null,
@JsonProperty("number" ) var number : Int? = null,
@JsonProperty("age" ) var age : String? = null,
@JsonProperty("type" ) var type : String? = null,
@JsonProperty("status" ) var status : String? = null,
@JsonProperty("poster_path" ) var posterPath : String? = null,
)
data class All (
@JsonProperty("data" ) var data : ArrayList<Data> = arrayListOf(),
)
override val mainPage = mainPageOf(
"$mainUrl/home/sticky-episodes?page=" to "Episodes (H)",
"$mainUrl/anime?status=completed&page=" to "Completed",
"$mainUrl/anime?status=ongoing&page=" to "Ongoing",
)
override suspend fun getMainPage(page: Int, request: MainPageRequest): HomePageResponse {
val json = parseJson<All>(app.get(request.data + page).text)
val list = json.data.map {
newAnimeSearchResponse(
it.animeName ?: it.title.toString(),
mainUrl + "/anime/" + it.slug.toString().replace("-episode.*".toRegex(),""),
if (it.type == "movie") TvType.AnimeMovie else if (it.type == "tv") TvType.Anime else TvType.OVA,
) {
addDubStatus(false, it.totalEpisodes ?: it.number)
this.otherName = it.otherNames?.split("\n")?.last()
this.posterUrl = "https://api.animeiat.co/storage/" + it.posterPath
}
}
return if(request.name.contains("(H)")) HomePageResponse(
arrayListOf(HomePageList(request.name.replace(" (H)",""), list, request.name.contains("(H)")))
) else newHomePageResponse(request.name, list)
}
override suspend fun search(query: String): List<SearchResponse> {
val json = parseJson<All>(app.get("$mainUrl/anime?q=$query").text)
return json.data.map {
newAnimeSearchResponse(
it.animeName.toString(),
mainUrl + "/anime/" + it.slug.toString(),
if(it.type == "movie") TvType.AnimeMovie else if(it.type == "tv") TvType.Anime else TvType.OVA,
) {
addDubStatus(false, it.totalEpisodes)
this.otherName = it.otherNames?.split("\n")?.last()
this.posterUrl = "https://api.animeiat.co/storage/" + it.posterPath
}
}
}
data class Year (
@JsonProperty("name" ) var name : String? = null,
)
data class Genres (
@JsonProperty("name" ) var name : String? = null,
)
data class LoadData (
@JsonProperty("anime_name" ) var animeName : String? = null,
@JsonProperty("slug" ) var slug : String? = null,
@JsonProperty("story" ) var story : String? = null,
@JsonProperty("other_names" ) var otherNames : String? = null,
@JsonProperty("age" ) var age : String? = null,
@JsonProperty("type" ) var type : String? = null,
@JsonProperty("status" ) var status : String? = null,
@JsonProperty("poster_path" ) var posterPath : String? = null,
@JsonProperty("year" ) var year : Year? = Year(),
@JsonProperty("genres" ) var genres : ArrayList<Genres> = arrayListOf(),
)
data class Load (
@JsonProperty("data" ) var data : LoadData? = LoadData()
)
data class Meta (
@JsonProperty("last_page" ) var lastPage : Int? = null,
)
data class EpisodeData (
@JsonProperty("title" ) var title : String? = null,
@JsonProperty("slug" ) var slug : String? = null,
@JsonProperty("number" ) var number : Int? = null,
@JsonProperty("video_id" ) var videoId : Int? = null,
@JsonProperty("poster_path" ) var posterPath : String? = null,
)
data class Episodes (
@JsonProperty("data" ) var data : ArrayList<EpisodeData> = arrayListOf(),
@JsonProperty("meta" ) var meta : Meta = Meta()
)
override suspend fun load(url: String): LoadResponse {
val loadSession = Requests()
val request = loadSession.get(url.replace(pageUrl, mainUrl)).text
val json = parseJson<Load>(request)
val episodes = arrayListOf<Episode>()
(1..parseJson<Episodes>(loadSession.get("$url/episodes").text).meta.lastPage!!).map { pageNumber ->
parseJson<Episodes>(loadSession.get("$url/episodes?page=$pageNumber").text).data.map {
episodes.add(
Episode(
"$pageUrl/watch/"+json.data?.slug,
it.title,
null,
it.number,
"https://api.animeiat.co/storage/" + it.posterPath,
)
)
}
}
return newAnimeLoadResponse(json.data?.animeName.toString(), "$pageUrl/watch/"+json.data?.slug, if(json.data?.type == "movie") TvType.AnimeMovie else if(json.data?.type == "tv") TvType.Anime else TvType.OVA) {
japName = json.data?.otherNames?.replace("\\n.*".toRegex(), "")
engName = json.data?.animeName
posterUrl = "https://api.animeiat.co/storage/" + json.data?.posterPath
this.year = json.data?.year?.name?.toIntOrNull()
addEpisodes(DubStatus.Subbed, episodes)
plot = json.data?.story
tags = json.data?.genres?.map { it.name.toString() }
this.showStatus = if(json.data?.status == "completed") ShowStatus.Completed else ShowStatus.Ongoing
}
}
override suspend fun loadLinks(
data: String,
isCasting: Boolean,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
): Boolean {
val url = if(data.contains("-episode")) data else "$data-episode-1"
val doc = app.get(url).document
val script = doc.select("body > script").first()?.html()
val id = script?.replace(".*4\",slug:\"|\",duration:.*".toRegex(),"")
val player = app.get("$pageUrl/player/$id").document
player.select("source").map {
callback.invoke(
ExtractorLink(
this.name,
this.name,
it.attr("src"),
pageUrl,
it.attr("size").toInt(),
)
)
}
return true
}
}

BIN
ArabSeedProvider.cs3 Normal file

Binary file not shown.

View File

@ -0,0 +1,14 @@
version = 2
cloudstream {
description = ""
authors = listOf( "ImZaw" )
language = "ar"
status = 1
tvTypes = listOf( "TvSeries" , "Movie" )
iconUrl = "https://www.google.com/s2/favicons?domain=arabseed.ink&sz=%size%"
}

View File

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

View File

@ -0,0 +1,11 @@
package com.arabseed
import com.lagradost.cloudstream3.plugins.CloudstreamPlugin
import com.lagradost.cloudstream3.plugins.Plugin
import android.content.Context
@CloudstreamPlugin
class ArabSeedPlugin: Plugin() {
override fun load(context: Context) {
registerMainAPI(ArabSeed())
}
}

View File

@ -0,0 +1,217 @@
package com.arabseed
import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.loadExtractor
import org.jsoup.nodes.Element
class ArabSeed : MainAPI() {
override var lang = "ar"
override var mainUrl = "https://m5.arabseed.ink"
override var name = "ArabSeed"
override val usesWebView = false
override val hasMainPage = true
override val supportedTypes = setOf(TvType.TvSeries, TvType.Movie)
private fun String.getIntFromText(): Int? {
return Regex("""\d+""").find(this)?.groupValues?.firstOrNull()?.toIntOrNull()
}
private fun Element.toSearchResponse(): SearchResponse? {
val title = select("h4").text()
val posterUrl = select("img.imgOptimzer").attr("data-image").ifEmpty { select("div.Poster img").attr("data-src") }
val tvType = if (select("span.category").text().contains("مسلسلات")) TvType.TvSeries else TvType.Movie
return MovieSearchResponse(
title,
select("a").attr("href"),
this@ArabSeed.name,
tvType,
posterUrl,
)
}
override val mainPage = mainPageOf(
"$mainUrl/movies/?offset=" to "Movies",
"$mainUrl/series/?offset=" to "Series",
)
override suspend fun getMainPage(
page: Int,
request: MainPageRequest
): HomePageResponse {
val document = app.get(request.data + page, timeout = 120).document
val home = document.select("ul.Blocks-UL > div").mapNotNull {
it.toSearchResponse()
}
return newHomePageResponse(request.name, home)
}
override suspend fun search(query: String): List<SearchResponse> {
val list = arrayListOf<SearchResponse>()
arrayListOf(
mainUrl to "series",
mainUrl to "movies"
).apmap { (url, type) ->
val doc = app.post(
"$url/wp-content/themes/Elshaikh2021/Ajaxat/SearchingTwo.php",
data = mapOf("search" to query, "type" to type),
referer = mainUrl
).document
doc.select("ul.Blocks-UL > div").mapNotNull {
it.toSearchResponse()?.let { it1 -> list.add(it1) }
}
}
return list
}
override suspend fun load(url: String): LoadResponse {
val doc = app.get(url, timeout = 120).document
val title = doc.select("h1.Title").text().ifEmpty { doc.select("div.Title").text() }
val isMovie = title.contains("فيلم")
val posterUrl = doc.select("div.Poster > img").let{ it.attr("data-src").ifEmpty { it.attr("src") } }
val rating = doc.select("div.RatingImdb em").text().getIntFromText()
val synopsis = doc.select("p.descrip").last()?.text()
val year = doc.select("li:contains(السنه) a").text().getIntFromText()
val tags = doc.select("li:contains(النوع) > a, li:contains(التصنيف) > a")?.map { it.text() }
val actors = doc.select("div.WorkTeamIteM").mapNotNull {
val name = it.selectFirst("h4 > em")?.text() ?: return@mapNotNull null
val image = it.selectFirst("div.Icon img")?.attr("src") ?: return@mapNotNull null
val roleString = it.select("h4 > span").text()
val mainActor = Actor(name, image)
ActorData(actor = mainActor, roleString = roleString)
}
val recommendations = doc.select("ul.Blocks-UL > div").mapNotNull { element ->
element.toSearchResponse()
}
return if (isMovie) {
newMovieLoadResponse(
title,
url,
TvType.Movie,
url
) {
this.posterUrl = posterUrl
this.recommendations = recommendations
this.plot = synopsis
this.tags = tags
this.actors = actors
this.rating = rating
this.year = year
}
} else {
val seasonList = doc.select("div.SeasonsListHolder ul > li")
val episodes = arrayListOf<Episode>()
if(seasonList.isNotEmpty()) {
seasonList.apmap { season ->
app.post(
"$mainUrl/wp-content/themes/Elshaikh2021/Ajaxat/Single/Episodes.php",
data = mapOf("season" to season.attr("data-season"), "post_id" to season.attr("data-id"))
).document.select("a").apmap {
episodes.add(Episode(
it.attr("href"),
it.text(),
season.attr("data-season")[0].toString().toIntOrNull(),
it.text().getIntFromText()
))
}
}
} else {
doc.select("div.ContainerEpisodesList > a").apmap {
episodes.add(Episode(
it.attr("href"),
it.text(),
0,
it.text().getIntFromText()
))
}
}
newTvSeriesLoadResponse(title, url, TvType.TvSeries, episodes.distinct().sortedBy { it.episode }) {
this.posterUrl = posterUrl
this.tags = tags
this.plot = synopsis
this.actors = actors
this.recommendations = recommendations
this.rating = rating
this.year = year
}
}
}
override suspend fun loadLinks(
data: String,
isCasting: Boolean,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
): Boolean {
val doc = app.get(data).document
val watchUrl = doc.select("a.watchBTn").attr("href")
val watchDoc = app.get(watchUrl, headers = mapOf("Referer" to mainUrl)).document
val indexOperators = arrayListOf<Int>()
val list: List<Element> = watchDoc.select("ul > li[data-link], ul > h3").mapIndexed { index, element ->
if(element.`is`("h3")) {
indexOperators.add(index)
element
} else element
}
var watchLinks: List<Pair<Int, List<Element>>>;
if(indexOperators.isNotEmpty()) {
watchLinks = indexOperators.mapIndexed { index, it ->
var endIndex = list.size
if (index != indexOperators.size - 1) endIndex = (indexOperators[index + 1]) - 1
list[it].text().getIntFromText() as Int to list.subList(it + 1, endIndex) as List<Element>
}
} else {
watchLinks = arrayListOf(0 to list)
}
watchLinks.apmap { (quality, links) ->
links.apmap {
val iframeUrl = it.attr("data-link")
println(iframeUrl)
if(it.text().contains("عرب سيد")) {
val sourceElement = app.get(iframeUrl).document.select("source")
callback.invoke(
ExtractorLink(
this.name,
"ArabSeed",
sourceElement.attr("src"),
data,
if(quality != 0) quality else it.text().replace(".*- ".toRegex(), "").replace("\\D".toRegex(),"").toInt(),
!sourceElement.attr("type").contains("mp4")
)
)
} else if (iframeUrl.contains("voe.sx")) {
val doc = app.get(iframeUrl).document
val script = doc.select("script").map { it.data() }.first { it.contains("sources") }
val m3u8 = script.substringAfter("'hls': '").substringBefore("'")
val mp4 = script.substringAfter("'mp4': '").substringBefore("'")
val voeSxquality = script.substringAfter("'video_height': ").substringBefore(",").toInt()
callback.invoke(
ExtractorLink(
this.name,
"Voe.sx m3u8",
m3u8,
data,
voeSxquality,
true
)
)
callback.invoke(
ExtractorLink(
this.name,
"Voe.sx mp4",
mp4,
data,
voeSxquality,
)
)
} else loadExtractor(iframeUrl, data, subtitleCallback, callback)
}
}
return true
}
}

BIN
CimaNowProvider.cs3 Normal file

Binary file not shown.

View File

@ -0,0 +1,14 @@
version = 1
cloudstream {
description = ""
authors = listOf( "ImZaw" )
language = "ar"
status = 1
tvTypes = listOf( "TvSeries" , "Movie" )
iconUrl = "https://www.google.com/s2/favicons?domain=cimanow.cc&sz=%size%"
}

View File

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

View File

@ -0,0 +1,11 @@
package com.cimanow
import com.lagradost.cloudstream3.plugins.CloudstreamPlugin
import com.lagradost.cloudstream3.plugins.Plugin
import android.content.Context
@CloudstreamPlugin
class CimaNowPlugin: Plugin() {
override fun load(context: Context) {
registerMainAPI(CimaNow())
}
}

View File

@ -0,0 +1,164 @@
package com.cimanow
import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.Qualities
import org.jsoup.nodes.Element
class CimaNow : MainAPI() {
override var lang = "ar"
override var mainUrl = "https://cimanow.cc"
override var name = "CimaNow"
override val usesWebView = false
override val hasMainPage = true
override val supportedTypes = setOf(TvType.TvSeries, TvType.Movie)
private fun String.getIntFromText(): Int? {
return Regex("""\d+""").find(this)?.groupValues?.firstOrNull()?.toIntOrNull()
}
private fun Element.toSearchResponse(): SearchResponse? {
val url = this.attr("href")
val posterUrl = select("img")?.attr("data-src")
var title = select("li[aria-label=\"title\"]").html().replace(" <em>.*|\\\\n".toRegex(), "").replace("&nbsp;", "")
val year = select("li[aria-label=\"year\"]").text().toIntOrNull()
val tvType = if (url.contains("فيلم|مسرحية|حفلات".toRegex())) TvType.Movie else TvType.TvSeries
val quality = select("li[aria-label=\"ribbon\"]").first()?.text()?.replace(" |-|1080|720".toRegex(), "")
val dubEl = select("li[aria-label=\"ribbon\"]:nth-child(2)").isNotEmpty()
val dubStatus = if(dubEl) select("li[aria-label=\"ribbon\"]:nth-child(2)").text().contains("مدبلج")
else select("li[aria-label=\"ribbon\"]:nth-child(1)").text().contains("مدبلج")
if(dubStatus) title = "$title (مدبلج)"
return MovieSearchResponse(
"$title ${select("li[aria-label=\"ribbon\"]:contains(الموسم)").text()}",
url,
this@CimaNow.name,
tvType,
posterUrl,
year,
null,
quality = getQualityFromString(quality)
)
}
override suspend fun getMainPage(page: Int, request : MainPageRequest): HomePageResponse {
val doc = app.get("$mainUrl/home", headers = mapOf("user-agent" to "MONKE")).document
val pages = doc.select("section").not("section:contains(أختر وجهتك المفضلة)").not("section:contains(تم اضافته حديثاً)").apmap {
val name = it.select("span").html().replace("<em>.*| <i c.*".toRegex(), "")
val list = it.select("a").mapNotNull {
if(it.attr("href").contains("$mainUrl/category/|$mainUrl/الاكثر-مشاهدة/".toRegex())) return@mapNotNull null
it.toSearchResponse()
}
HomePageList(name, list)
}
return HomePageResponse(pages)
}
override suspend fun search(query: String): List<SearchResponse> {
val result = arrayListOf<SearchResponse>()
val doc = app.get("$mainUrl/page/1/?s=$query").document
val paginationElement = doc.select("ul[aria-label=\"pagination\"]")
doc.select("section article a").map {
val postUrl = it.attr("href")
if(it.select("li[aria-label=\"episode\"]").isNotEmpty()) return@map
if(postUrl.contains("$mainUrl/expired-download/|$mainUrl/افلام-اون-لاين/".toRegex())) return@map
result.add(it.toSearchResponse()!!)
}
if(paginationElement.isNotEmpty()) {
val max = paginationElement.select("li").not("li.active").last()?.text()?.toIntOrNull()
if (max != null) {
if(max > 5) return result.distinct().sortedBy { it.name }
(2..max!!).toList().apmap {
app.get("$mainUrl/page/$it/?s=$query\"").document.select("section article a").map { element ->
val postUrl = element.attr("href")
if(element.select("li[aria-label=\"episode\"]").isNotEmpty()) return@map
if(postUrl.contains("$mainUrl/expired-download/|$mainUrl/افلام-اون-لاين/".toRegex())) return@map
result.add(element.toSearchResponse()!!)
}
}
}
}
return result.distinct().sortedBy { it.name }
}
override suspend fun load(url: String): LoadResponse {
val doc = app.get(url).document
val posterUrl = doc.select("body > script:nth-child(3)").html().replace(".*,\"image\":\"|\".*".toRegex(),"").ifEmpty { doc.select("meta[property=\"og:image\"]").attr("content") }
val year = doc.select("article ul:nth-child(1) li a").last()?.text()?.toIntOrNull()
val title = doc.select("title").text().split(" | ")[0]
val isMovie = title.contains("فيلم|حفلات|مسرحية".toRegex())
val youtubeTrailer = doc.select("iframe")?.attr("src")
val synopsis = doc.select("ul#details li:contains(لمحة) p").text()
val tags = doc.select("article ul").first()?.select("li")?.map { it.text() }
val recommendations = doc.select("ul#related li").map { element ->
MovieSearchResponse(
apiName = this@CimaNow.name,
url = element.select("a").attr("href"),