mirror of
https://github.com/yoyzo/arab
synced 2024-08-15 03:15:00 +00:00
Build a27d8587c0
This commit is contained in:
commit
9ea7b9e5cd
87 changed files with 4255 additions and 0 deletions
60
.github/workflows/build.yml
vendored
Normal file
60
.github/workflows/build.yml
vendored
Normal 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
12
.gitignore
vendored
Normal 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
BIN
AkwamProvider.cs3
Normal file
Binary file not shown.
14
AkwamProvider/build.gradle.kts
Normal file
14
AkwamProvider/build.gradle.kts
Normal 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%"
|
||||
}
|
2
AkwamProvider/src/main/AndroidManifest.xml
Normal file
2
AkwamProvider/src/main/AndroidManifest.xml
Normal file
|
@ -0,0 +1,2 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest package="com.akwam"/>
|
11
AkwamProvider/src/main/kotlin/com/akwam/AkwamPlugin.kt
Normal file
11
AkwamProvider/src/main/kotlin/com/akwam/AkwamPlugin.kt
Normal 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())
|
||||
}
|
||||
}
|
225
AkwamProvider/src/main/kotlin/com/akwam/AkwamProvider.kt
Normal file
225
AkwamProvider/src/main/kotlin/com/akwam/AkwamProvider.kt
Normal 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
BIN
Anime4upPack.cs3
Normal file
Binary file not shown.
14
Anime4upPack/build.gradle.kts
Normal file
14
Anime4upPack/build.gradle.kts
Normal 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%"
|
||||
}
|
2
Anime4upPack/src/main/AndroidManifest.xml
Normal file
2
Anime4upPack/src/main/AndroidManifest.xml
Normal file
|
@ -0,0 +1,2 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest package="com.anime4up"/>
|
13
Anime4upPack/src/main/kotlin/com/anime4up/Anime4upPlugin.kt
Normal file
13
Anime4upPack/src/main/kotlin/com/anime4up/Anime4upPlugin.kt
Normal 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())
|
||||
}
|
||||
}
|
167
Anime4upPack/src/main/kotlin/com/anime4up/Anime4upProvider.kt
Normal file
167
Anime4upPack/src/main/kotlin/com/anime4up/Anime4upProvider.kt
Normal 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
BIN
AnimeBlkomProvider.cs3
Normal file
Binary file not shown.
14
AnimeBlkomProvider/build.gradle.kts
Normal file
14
AnimeBlkomProvider/build.gradle.kts
Normal 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%"
|
||||
}
|
2
AnimeBlkomProvider/src/main/AndroidManifest.xml
Normal file
2
AnimeBlkomProvider/src/main/AndroidManifest.xml
Normal file
|
@ -0,0 +1,2 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest package="com.animeblkom"/>
|
|
@ -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())
|
||||
}
|
||||
}
|
|
@ -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
BIN
AnimeiatProvider.cs3
Normal file
Binary file not shown.
14
AnimeiatProvider/build.gradle.kts
Normal file
14
AnimeiatProvider/build.gradle.kts
Normal 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%"
|
||||
}
|
2
AnimeiatProvider/src/main/AndroidManifest.xml
Normal file
2
AnimeiatProvider/src/main/AndroidManifest.xml
Normal file
|
@ -0,0 +1,2 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest package="com.animeiat"/>
|
|
@ -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())
|
||||
}
|
||||
}
|
|
@ -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
BIN
ArabSeedProvider.cs3
Normal file
Binary file not shown.
14
ArabSeedProvider/build.gradle.kts
Normal file
14
ArabSeedProvider/build.gradle.kts
Normal 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%"
|
||||
}
|
2
ArabSeedProvider/src/main/AndroidManifest.xml
Normal file
2
ArabSeedProvider/src/main/AndroidManifest.xml
Normal file
|
@ -0,0 +1,2 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest package="com.arabseed"/>
|
|
@ -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())
|
||||
}
|
||||
}
|
|
@ -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
BIN
CimaNowProvider.cs3
Normal file
Binary file not shown.
14
CimaNowProvider/build.gradle.kts
Normal file
14
CimaNowProvider/build.gradle.kts
Normal 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%"
|
||||
}
|
2
CimaNowProvider/src/main/AndroidManifest.xml
Normal file
2
CimaNowProvider/src/main/AndroidManifest.xml
Normal file
|
@ -0,0 +1,2 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest package="com.cimanow"/>
|
11
CimaNowProvider/src/main/kotlin/com/cimanow/CimaNowPlugin.kt
Normal file
11
CimaNowProvider/src/main/kotlin/com/cimanow/CimaNowPlugin.kt
Normal 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())
|
||||
}
|
||||
}
|
164
CimaNowProvider/src/main/kotlin/com/cimanow/CimaNowProvider.kt
Normal file
164
CimaNowProvider/src/main/kotlin/com/cimanow/CimaNowProvider.kt
Normal 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(" ", "")
|
||||
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 }
|
||||
}
|
||||