Compare commits
No commits in common. "master" and "builds" have entirely different histories.
|
@ -1,60 +0,0 @@
|
|||
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
|
|
@ -1,12 +0,0 @@
|
|||
*.iml
|
||||
.gradle
|
||||
/local.properties
|
||||
/.idea
|
||||
.DS_Store
|
||||
/build
|
||||
**/build
|
||||
/captures
|
||||
.externalNativeBuild
|
||||
.cxx
|
||||
local.properties
|
||||
.vscode
|
Binary file not shown.
|
@ -1,14 +0,0 @@
|
|||
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%"
|
||||
}
|
|
@ -1,2 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest package="com.akwam"/>
|
|
@ -1,11 +0,0 @@
|
|||
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())
|
||||
}
|
||||
}
|
|
@ -1,225 +0,0 @@
|
|||
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
|
||||
}
|
||||
}
|
Binary file not shown.
|
@ -1,14 +0,0 @@
|
|||
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%"
|
||||
}
|
|
@ -1,2 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest package="com.anime4up"/>
|
|
@ -1,13 +0,0 @@
|
|||
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())
|
||||
}
|
||||
}
|
|
@ -1,167 +0,0 @@
|
|||
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
|
||||
}
|
||||
}
|
Binary file not shown.
|
@ -1,14 +0,0 @@
|
|||
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%"
|
||||
}
|
|
@ -1,2 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest package="com.animeblkom"/>
|
|
@ -1,11 +0,0 @@
|
|||
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())
|
||||
}
|
||||
}
|
|
@ -1,164 +0,0 @@
|
|||
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
|
||||
}
|
||||
}
|
Binary file not shown.
|
@ -1,14 +0,0 @@
|
|||
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%"
|
||||
}
|
|
@ -1,2 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest package="com.animeiat"/>
|
|
@ -1,11 +0,0 @@
|
|||
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())
|
||||
}
|
||||
}
|
|
@ -1,172 +0,0 @@
|
|||
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
|
||||
}
|
||||
}
|
Binary file not shown.
|
@ -1,14 +0,0 @@
|
|||
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%"
|
||||
}
|
|
@ -1,2 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest package="com.arabseed"/>
|
|
@ -1,11 +0,0 @@
|
|||
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())
|
||||
}
|
||||
}
|
|
@ -1,217 +0,0 @@
|
|||
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
|
||||
}
|
||||
}
|
Binary file not shown.
|
@ -1,14 +0,0 @@
|
|||
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%"
|
||||
}
|
|
@ -1,2 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest package="com.cimanow"/>
|
|
@ -1,11 +0,0 @@
|
|||
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())
|
||||
}
|
||||
}
|
|
@ -1,164 +0,0 @@
|
|||
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 }
|
||||
}
|
||||
|
||||
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"),
|
||||
name = element.select("img:nth-child(2)").attr("alt"),
|
||||
posterUrl = element.select("img:nth-child(2)").attr("src")
|
||||
)
|
||||
}
|
||||
|
||||
return if (isMovie) {
|
||||
newMovieLoadResponse(
|
||||
title,
|
||||
url,
|
||||
TvType.Movie,
|
||||
"$url/watching"
|
||||
) {
|
||||
this.posterUrl = posterUrl
|
||||
this.year = year
|
||||
this.recommendations = recommendations
|
||||
this.plot = synopsis
|
||||
this.tags = tags
|
||||
addTrailer(youtubeTrailer)
|
||||
}
|
||||
} else {
|
||||
val episodes = doc.select("ul#eps li").map { episode ->
|
||||
Episode(
|
||||
episode.select("a").attr("href")+"/watching",
|
||||
episode.select("a img:nth-child(2)").attr("alt"),
|
||||
doc.select("span[aria-label=\"season-title\"]").html().replace("<p>.*|\n".toRegex(), "").getIntFromText(),
|
||||
episode.select("a em").text().toIntOrNull(),
|
||||
episode.select("a img:nth-child(2)").attr("src")
|
||||
)
|
||||
}
|
||||
newTvSeriesLoadResponse(title, url, TvType.TvSeries, episodes.distinct().sortedBy { it.episode }) {
|
||||
this.posterUrl = posterUrl
|
||||
this.tags = tags
|
||||
this.year = year
|
||||
this.plot = synopsis
|
||||
this.recommendations = recommendations
|
||||
addTrailer(youtubeTrailer)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun loadLinks(
|
||||
data: String,
|
||||
isCasting: Boolean,
|
||||
subtitleCallback: (SubtitleFile) -> Unit,
|
||||
callback: (ExtractorLink) -> Unit
|
||||
): Boolean {
|
||||
app.get("$data").document.select("ul#download [aria-label=\"quality\"]").forEach {
|
||||
val name = if(it.select("span").text().contains("فائق السرعة")) "Fast Servers" else "Servers"
|
||||
it.select("a").forEach { media ->
|
||||
callback.invoke(
|
||||
ExtractorLink(
|
||||
source = this.name,
|
||||
name = name,
|
||||
url = media.attr("href"),
|
||||
referer = this.mainUrl,
|
||||
quality = media.text().getIntFromText() ?: Qualities.Unknown.value
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
version = 7
|
||||
|
||||
cloudstream {
|
||||
description = "Egybest is broken"
|
||||
authors = listOf( "ImZaw" )
|
||||
|
||||
language = "ar"
|
||||
|
||||
status = 0
|
||||
|
||||
tvTypes = listOf( "TvSeries" , "Movie" , "Anime" )
|
||||
|
||||
iconUrl = "https://www.google.com/s2/favicons?domain=www.egy.best&sz=%size%"
|
||||
}
|
|
@ -1,2 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest package="com.egybest"/>
|
|
@ -1,11 +0,0 @@
|
|||
package com.egybest
|
||||
import com.lagradost.cloudstream3.plugins.CloudstreamPlugin
|
||||
import com.lagradost.cloudstream3.plugins.Plugin
|
||||
import android.content.Context
|
||||
|
||||
@CloudstreamPlugin
|
||||
class EgyBestPlugin: Plugin() {
|
||||
override fun load(context: Context) {
|
||||
registerMainAPI(EgyBest())
|
||||
}
|
||||
}
|
|
@ -1,275 +0,0 @@
|
|||
package com.egybest
|
||||
|
||||
|
||||
import android.annotation.TargetApi
|
||||
import android.os.Build
|
||||
import com.lagradost.cloudstream3.*
|
||||
import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.M3u8Helper
|
||||
import com.lagradost.nicehttp.Requests
|
||||
import com.lagradost.nicehttp.Session
|
||||
import okhttp3.HttpUrl.Companion.toHttpUrl
|
||||
import org.jsoup.nodes.Element
|
||||
import java.util.Base64
|
||||
import org.mozilla.javascript.Context
|
||||
import org.mozilla.javascript.Scriptable
|
||||
|
||||
fun String.runJS(variableName: String): String {
|
||||
val rhino = Context.enter()
|
||||
rhino.initSafeStandardObjects()
|
||||
rhino.optimizationLevel = -1
|
||||
val scope: Scriptable = rhino.initSafeStandardObjects()
|
||||
val script = this
|
||||
val result: String
|
||||
try {
|
||||
var js = ""
|
||||
for (i in script.indices) {
|
||||
js += script[i]
|
||||
}
|
||||
rhino.evaluateString(scope, js, "JavaScript", 1, null)
|
||||
result = Context.toString(scope.get(variableName, scope))
|
||||
} finally {
|
||||
Context.exit()
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
class EgyBest : MainAPI() {
|
||||
override var lang = "ar"
|
||||
override var mainUrl = "https://egybest.org"
|
||||
override var name = "EgyBest"
|
||||
var pssid = ""
|
||||
override val usesWebView = false
|
||||
override val hasMainPage = true
|
||||
override val supportedTypes = setOf(TvType.TvSeries, TvType.Movie, TvType.Anime)
|
||||
|
||||
private fun String.getIntFromText(): Int? {
|
||||
return Regex("""\d+""").find(this)?.groupValues?.firstOrNull()?.toIntOrNull()
|
||||
}
|
||||
|
||||
private fun Element.toSearchResponse(): SearchResponse? {
|
||||
val url = this.attr("href") ?: return null
|
||||
val posterUrl = select("img")?.attr("src")
|
||||
var title = select("span.title").text()
|
||||
val year = title.getYearFromTitle()
|
||||
val isMovie = Regex(".*/movie/.*|.*/masrahiya/.*").matches(url)
|
||||
val tvType = if (isMovie) TvType.Movie else TvType.TvSeries
|
||||
title = if (year !== null) title else title.split(" (")[0].trim()
|
||||
val quality = select("span.ribbon span").text().replace("-", "")
|
||||
// If you need to differentiate use the url.
|
||||
return MovieSearchResponse(
|
||||
title,
|
||||
mainUrl + url,
|
||||
this@EgyBest.name,
|
||||
tvType,
|
||||
posterUrl,
|
||||
year,
|
||||
null,
|
||||
quality = getQualityFromString(quality)
|
||||
)
|
||||
}
|
||||
|
||||
override val mainPage = mainPageOf(
|
||||
"$mainUrl/trending/?page=" to "الأفلام الأكثر مشاهدة",
|
||||
"$mainUrl/movies/?page=" to "أفلام جديدة",
|
||||
"$mainUrl/tv/?page=" to "مسلسلات جديدة ",
|
||||
"$mainUrl/tv/korean?page=" to "الدراما الكورية ",
|
||||
"$mainUrl/animes/popular?page=" to "مسلسلات الانمي",
|
||||
"$mainUrl/wwe/?page=" to "عروض المصارعة ",
|
||||
"$mainUrl/movies/latest-bluray-2020-2019?page=" to "أفلام جديدة BluRay",
|
||||
"$mainUrl/masrahiyat/?page=" to "مسرحيات ",
|
||||
"$mainUrl/movies/latest?page=" to "أحدث الاضافات",
|
||||
"$mainUrl/movies/comedy?page=" to "أفلام كوميدية",
|
||||
"$mainUrl/explore/?q=superhero/" to "أفلام سوبر هيرو",
|
||||
"$mainUrl/movies/animation?page=" to "أفلام انمي و كرتون",
|
||||
"$mainUrl/movies/romance?page=" to "أفلام رومانسية",
|
||||
"$mainUrl/movies/drama?page=" to "أفلام دراما",
|
||||
"$mainUrl/movies/horror?page=" to "أفلام رعب",
|
||||
"$mainUrl/movies/documentary?page=" to "أفلام وثائقية",
|
||||
"$mainUrl/World-War-Movies/?page=" to "أفلام عن الحرب العالمية ☢",
|
||||
"$mainUrl/End-Of-The-World-Movies/?page=" to "أفلام عن نهاية العالم",
|
||||
"$mainUrl/movies/arab?page=" to "أفلام عربية ",
|
||||
)
|
||||
|
||||
override suspend fun getMainPage(page: Int, request : MainPageRequest): HomePageResponse {
|
||||
val doc = app.get(request.data + page).document
|
||||
val list = doc.select(".movie")
|
||||
.mapNotNull { element ->
|
||||
element.toSearchResponse()
|
||||
}
|
||||
return newHomePageResponse(request.name, list)
|
||||
}
|
||||
|
||||
override suspend fun search(query: String): List<SearchResponse> {
|
||||
val result = arrayListOf<SearchResponse>()
|
||||
listOf("$mainUrl/explore/?q=$query").apmap { url ->
|
||||
val d = app.get(url).document
|
||||
d.select("div.movies a").not("a.auto.load.btn.b").mapNotNull {
|
||||
it.toSearchResponse()?.let { it1 -> result.add(it1) }
|
||||
}
|
||||
}
|
||||
return result.distinct().sortedBy { it.name }
|
||||
}
|
||||
|
||||
private fun String.getYearFromTitle(): Int? {
|
||||
return Regex("""\(\d{4}\)""").find(this)?.groupValues?.firstOrNull()?.toIntOrNull()
|
||||
}
|
||||
|
||||
override suspend fun load(url: String): LoadResponse {
|
||||
val doc = app.get(url).document
|
||||
val isMovie = Regex(".*/movie/.*|.*/masrahiya/.*").matches(url)
|
||||
val posterUrl = doc.select("div.movie_img a img")?.attr("src")
|
||||
val year = doc.select("div.movie_title h1 a")?.text()?.toIntOrNull()
|
||||
val title = doc.select("div.movie_title h1 span").text()
|
||||
val youtubeTrailer = doc.select("div.play")?.attr("url")
|
||||
|
||||
val synopsis = doc.select("div.mbox").firstOrNull {
|
||||
it.text().contains("القصة")
|
||||
}?.text()?.replace("القصة ", "")
|
||||
|
||||
val tags = doc.select("table.movieTable tbody tr").firstOrNull {
|
||||
it.text().contains("النوع")
|
||||
}?.select("a")?.map { it.text() }
|
||||
|
||||
val actors = doc.select("div.cast_list .cast_item").mapNotNull {
|
||||
val name = it.selectFirst("div > a > img")?.attr("alt") ?: return@mapNotNull null
|
||||
val image = it.selectFirst("div > a > img")?.attr("src") ?: return@mapNotNull null
|
||||
val roleString = it.selectFirst("div > span")!!.text()
|
||||
val mainActor = Actor(name, image)
|
||||
ActorData(actor = mainActor, roleString = roleString)
|
||||
}
|
||||
|
||||
return if (isMovie) {
|
||||
val recommendations = doc.select(".movies_small .movie").mapNotNull { element ->
|
||||
element.toSearchResponse()
|
||||
}
|
||||
|
||||
newMovieLoadResponse(
|
||||
title,
|
||||
url,
|
||||
TvType.Movie,
|
||||
url
|
||||
) {
|
||||
this.posterUrl = posterUrl
|
||||
this.year = year
|
||||
this.recommendations = recommendations
|
||||
this.plot = synopsis
|
||||
this.tags = tags
|
||||
this.actors = actors
|
||||
addTrailer(youtubeTrailer)
|
||||
}
|
||||
} else {
|
||||
val episodes = ArrayList<Episode>()
|
||||
doc.select("#mainLoad > div:nth-child(2) > div.h_scroll > div a").map {
|
||||
it.attr("href")
|
||||
}.apmap {
|
||||
val d = app.get(it).document
|
||||
val season = Regex("season-(.....)").find(it)?.groupValues?.getOrNull(1)?.getIntFromText()
|
||||
if(d.select("tr.published").isNotEmpty()) {
|
||||
d.select("tr.published").map { element ->
|
||||
val ep = Regex("ep-(.....)").find(element.select(".ep_title a").attr("href"))?.groupValues?.getOrNull(1)?.getIntFromText()
|
||||
episodes.add(
|
||||
Episode(
|
||||
mainUrl + element.select(".ep_title a").attr("href"),
|
||||
name = element.select("td.ep_title").html().replace(".*</span>|</a>".toRegex(), ""),
|
||||
season,
|
||||
ep,
|
||||
rating = element.select("td.tam:not(.date, .ep_len)").text().getIntFromText()
|
||||
)
|
||||
)
|
||||
}
|
||||
} else {
|
||||
d.select("#mainLoad > div:nth-child(3) > div.movies_small a").map { eit ->
|
||||
val ep = Regex("ep-(.....)").find(eit.attr("href"))?.groupValues?.getOrNull(1)?.getIntFromText()
|
||||
episodes.add(
|
||||
Episode(
|
||||
mainUrl + eit.attr("href"),
|
||||
eit.select("span.title").text(),
|
||||
season,
|
||||
ep,
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
newTvSeriesLoadResponse(title, url, TvType.TvSeries, episodes.distinct().sortedBy { it.episode }) {
|
||||
this.posterUrl = posterUrl
|
||||
this.tags = tags
|
||||
this.year = year
|
||||
this.plot = synopsis
|
||||
this.actors = actors
|
||||
addTrailer(youtubeTrailer)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.O)
|
||||
override suspend fun loadLinks(
|
||||
data: String,
|
||||
isCasting: Boolean,
|
||||
subtitleCallback: (SubtitleFile) -> Unit,
|
||||
callback: (ExtractorLink) -> Unit
|
||||
): Boolean {
|
||||
val baseURL = data.split("/")[0] + "//" + data.split("/")[2]
|
||||
val client = Requests().baseClient
|
||||
val session = Session(client)
|
||||
println(baseURL)
|
||||
println(data)
|
||||
val doc = session.get(data).document
|
||||
|
||||
val vidstreamURL = baseURL + doc.select("iframe.auto-size").attr("src")
|
||||
|
||||
val videoSoup = session.get(vidstreamURL, cookies = mapOf(
|
||||
"PSSID" to this@EgyBest.pssid,
|
||||
)).document
|
||||
videoSoup.select("source").firstOrNull { it.hasAttr("src") }?.attr("src")?.let {
|
||||
M3u8Helper.generateM3u8(
|
||||
this.name,
|
||||
it,
|
||||
referer = mainUrl,
|
||||
headers = mapOf("range" to "bytes=0-")
|
||||
).forEach(callback)
|
||||
} ?: run {
|
||||
var jsCode = videoSoup.select("script")[1].html()
|
||||
val function = videoSoup.select("script")[2].attr("onload")
|
||||
val verificationToken = Regex("\\{'[0-9a-zA-Z_]*':'ok'\\}").findAll(jsCode).first().value.replace("\\{'|':.*".toRegex(), "")
|
||||
val encodedAdLinkVar = Regex("\\([0-9a-zA-Z_]{2,12}\\[Math").findAll(jsCode).first().value.replace("\\(|\\[M.*".toRegex(),"")
|
||||
val encodingArraysRegEx = Regex(",[0-9a-zA-Z_]{2,12}=\\[]").findAll(jsCode).toList()
|
||||
val firstEncodingArray = encodingArraysRegEx[1].value.replace(",|=.*".toRegex(),"")
|
||||
val secondEncodingArray = encodingArraysRegEx[2].value.replace(",|=.*".toRegex(),"")
|
||||
|
||||
jsCode = jsCode.replace("^<script type=\"text/javascript\">".toRegex(),"")
|
||||
jsCode = jsCode.replace(",\\\$\\('\\*'\\).*".toRegex(),";")
|
||||
jsCode = jsCode.replace(",ismob=(.*)\\(navigator\\[(.*)\\]\\)[,;]".toRegex(),";")
|
||||
jsCode = jsCode.replace("var a0b=\\(function\\(\\)(.*)a0a\\(\\);".toRegex(),"")
|
||||
jsCode = "$jsCode var link = ''; for (var i = 0; i <= $secondEncodingArray['length']; i++) { link += $firstEncodingArray[$secondEncodingArray[i]] || ''; } return [link, $encodedAdLinkVar[0]] };var result = $function"
|
||||
|
||||
val javascriptResult = jsCode.runJS("result").split(",")
|
||||
val verificationPath = javascriptResult[0]
|
||||
val encodedAdPath = javascriptResult[1]
|
||||
println(javascriptResult)
|
||||
|
||||
val encodedString = encodedAdPath + "=".repeat(encodedAdPath.length % 4)
|
||||
val decodedPath = String(Base64.getDecoder().decode(encodedString))
|
||||
println("String( $encodedString ) -> Decoded( $decodedPath )")
|
||||
val adLink = "$baseURL/$decodedPath"
|
||||
println(adLink)
|
||||
val verificationLink = "$baseURL/tvc.php?verify=$verificationPath"
|
||||
session.get(adLink)
|
||||
session.post(verificationLink, data=mapOf(verificationToken to "ok"))
|
||||
|
||||
val vidstreamResponse = session.get(vidstreamURL).document
|
||||
val mediaLink = baseURL + vidstreamResponse.select("source").attr("src")
|
||||
println("mediaLink: $mediaLink")
|
||||
println("Cookies: ${session.baseClient.cookieJar.loadForRequest(data.toHttpUrl())}")
|
||||
M3u8Helper.generateM3u8(
|
||||
this.name,
|
||||
mediaLink,
|
||||
referer = mainUrl,
|
||||
headers = mapOf("range" to "bytes=0-")
|
||||
).forEach(callback)
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
Binary file not shown.
|
@ -1,14 +0,0 @@
|
|||
version = 2
|
||||
|
||||
cloudstream {
|
||||
description = "Some LinkBox links are broken idk why"
|
||||
authors = listOf( "ImZaw" )
|
||||
|
||||
language = "ar"
|
||||
|
||||
status = 1
|
||||
|
||||
tvTypes = listOf( "TvSeries" , "Movie", "Anime" )
|
||||
|
||||
iconUrl = "https://www.google.com/s2/favicons?domain=tv.egydead.live&sz=%size%"
|
||||
}
|
|
@ -1,2 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest package="com.egydead"/>
|
|
@ -1,11 +0,0 @@
|
|||
package com.egydead
|
||||
import com.lagradost.cloudstream3.plugins.CloudstreamPlugin
|
||||
import com.lagradost.cloudstream3.plugins.Plugin
|
||||
import android.content.Context
|
||||
|
||||
@CloudstreamPlugin
|
||||
class EgyDeadPlugin: Plugin() {
|
||||
override fun load(context: Context) {
|
||||
registerMainAPI(EgyDead())
|
||||
}
|
||||
}
|
|
@ -1,180 +0,0 @@
|
|||
package com.egydead
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty
|
||||
import com.lagradost.cloudstream3.*
|
||||
import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.Qualities
|
||||
import com.lagradost.cloudstream3.utils.loadExtractor
|
||||
import org.jsoup.nodes.Element
|
||||
import java.net.URI
|
||||
|
||||
class EgyDead : MainAPI() {
|
||||
override var lang = "ar"
|
||||
override var mainUrl = "https://tv.egydead.live"
|
||||
override var name = "EgyDead"
|
||||
override val usesWebView = false
|
||||
override val hasMainPage = true
|
||||
override val supportedTypes = setOf(TvType.TvSeries, TvType.Movie, TvType.Anime)
|
||||
|
||||
private fun String.getIntFromText(): Int? {
|
||||
return Regex("""\d+""").find(this)?.groupValues?.firstOrNull()?.toIntOrNull()
|
||||
}
|
||||
private fun String.cleanTitle(): String {
|
||||
return this.replace("جميع مواسم مسلسل|مترجم كامل|مشاهدة فيلم|مترجم|انمي|الموسم.*|مترجمة كاملة|مسلسل|كاملة".toRegex(), "")
|
||||
}
|
||||
private fun Element.toSearchResponse(): SearchResponse {
|
||||
val title = select("h1.BottomTitle").text().cleanTitle()
|
||||
val posterUrl = select("img").attr("src")
|
||||
val tvType = if (select("span.cat_name").text().contains("افلام")) TvType.Movie else TvType.TvSeries
|
||||
return MovieSearchResponse(
|
||||
title,
|
||||
select("a").attr("href"),
|
||||
this@EgyDead.name,
|
||||
tvType,
|
||||
posterUrl,
|
||||
)
|
||||
}
|
||||
|
||||
override val mainPage = mainPageOf(
|
||||
"$mainUrl/category/افلام-اجنبي/?page=" to "English Movies",
|
||||
"$mainUrl/category/افلام-اسيوية/?page=" to "Asian Movies",
|
||||
"$mainUrl/season/?page=" to "Series",
|
||||
)
|
||||
|
||||
override suspend fun getMainPage(
|
||||
page: Int,
|
||||
request: MainPageRequest
|
||||
): HomePageResponse {
|
||||
val document = app.get(request.data + page).document
|
||||
val home = document.select("li.movieItem").mapNotNull {
|
||||
it.toSearchResponse()
|
||||
}
|
||||
return newHomePageResponse(request.name, home)
|
||||
}
|
||||
|
||||
override suspend fun search(query: String): List<SearchResponse> {
|
||||
val doc = app.get("$mainUrl/?s=$query").document
|
||||
return doc.select("li.movieItem").mapNotNull {
|
||||
if(it.select("a").attr("href").contains("/episode/")) return@mapNotNull null
|
||||
it.toSearchResponse()
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun load(url: String): LoadResponse {
|
||||
val doc = app.get(url).document
|
||||
val title = doc.select("div.singleTitle em").text().cleanTitle()
|
||||
val isMovie = !url.contains("/serie/|/season/".toRegex())
|
||||
|
||||
val posterUrl = doc.select("div.single-thumbnail > img").attr("src")
|
||||
val rating = doc.select("a.IMDBRating em").text().getIntFromText()
|
||||
val synopsis = doc.select("div.extra-content:contains(القصه) p").text()
|
||||
val year = doc.select("ul > li:contains(السنه) > a").text().getIntFromText()
|
||||
val tags = doc.select("ul > li:contains(النوع) > a").map { it.text() }
|
||||
val recommendations = doc.select("div.related-posts > ul > li").mapNotNull { element ->
|
||||
element.toSearchResponse()
|
||||
}
|
||||
val youtubeTrailer = doc.select("div.popupContent > iframe").attr("src")
|
||||
return if (isMovie) {
|
||||
newMovieLoadResponse(
|
||||
title,
|
||||
url,
|
||||
TvType.Movie,
|
||||
url
|
||||
) {
|
||||
this.posterUrl = posterUrl
|
||||
this.recommendations = recommendations
|
||||
this.plot = synopsis
|
||||
this.tags = tags
|
||||
this.rating = rating
|
||||
this.year = year
|
||||
addTrailer(youtubeTrailer)
|
||||
}
|
||||
} else {
|
||||
val seasonList = doc.select("div.seasons-list ul > li > a").reversed()
|
||||
val episodes = arrayListOf<Episode>()
|
||||
if(seasonList.isNotEmpty()) {
|
||||
seasonList.apmapIndexed { index, season ->
|
||||
app.get(
|
||||
season.attr("href"),
|
||||
).document.select("div.EpsList > li > a").map {
|
||||
episodes.add(Episode(
|
||||
it.attr("href"),
|
||||
it.attr("title"),
|
||||
index+1,
|
||||
it.text().getIntFromText()
|
||||
))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
doc.select("div.EpsList > li > a").map {
|
||||
episodes.add(Episode(
|
||||
it.attr("href"),
|
||||
it.attr("title"),
|
||||
0,
|
||||
it.text().getIntFromText()
|
||||
))
|
||||
}
|
||||
}
|
||||
newTvSeriesLoadResponse(title, url, TvType.TvSeries, episodes.distinct().sortedBy { it.episode }) {
|
||||
this.posterUrl = posterUrl
|
||||
this.tags = tags
|
||||
this.plot = synopsis
|
||||
this.recommendations = recommendations
|
||||
this.rating = rating
|
||||
this.year = year
|
||||
addTrailer(youtubeTrailer)
|
||||
}
|
||||
}
|
||||
}
|
||||
data class LinkBox (
|
||||
@JsonProperty("data" ) var data : Data? = Data(),
|
||||
)
|
||||
data class Data (
|
||||
@JsonProperty("rList" ) var rList : ArrayList<RList> = arrayListOf(),
|
||||
)
|
||||
data class RList (
|
||||
@JsonProperty("resolution" ) var resolution : String? = null,
|
||||
@JsonProperty("size" ) var size : Double? = null,
|
||||
// @JsonProperty("sub_type" ) var subType : String? = null,
|
||||
@JsonProperty("url" ) var url : String? = null,
|
||||
|
||||
)
|
||||
private fun bytesToHumanReadableSize(bytes: Double) = when {
|
||||
bytes >= 1 shl 30 -> "%.1f GB".format(bytes / (1 shl 30))
|
||||
bytes >= 1 shl 20 -> "%.1f MB".format(bytes / (1 shl 20))
|
||||
bytes >= 1 shl 10 -> "%.0f kB".format(bytes / (1 shl 10))
|
||||
else -> "$bytes bytes"
|
||||
}
|
||||
override suspend fun loadLinks(
|
||||
data: String,
|
||||
isCasting: Boolean,
|
||||
subtitleCallback: (SubtitleFile) -> Unit,
|
||||
callback: (ExtractorLink) -> Unit
|
||||
): Boolean {
|
||||
val doc = app.post(data, data = mapOf("View" to "1")).document
|
||||
val watchList = doc.select("ul.serversList > li")
|
||||
watchList.apmap { li ->
|
||||
val iframeUrl = li.attr("data-link")
|
||||
val quality = li.select("small").text().getIntFromText() ?: Qualities.Unknown.value
|
||||
if(iframeUrl.contains("www.linkbox.to")) {
|
||||
val apiUrl = "https://" + URI(iframeUrl).host + "/api/open/get_url?itemId=" + iframeUrl.substringAfter("id=").substringBefore("&")
|
||||
val json = app.get(apiUrl).parsed<LinkBox>()
|
||||
json.data?.rList?.forEach {
|
||||
callback.invoke(
|
||||
ExtractorLink(
|
||||
this.name,
|
||||
"LinkBox " + bytesToHumanReadableSize(it.size ?: 0.0),
|
||||
it.url ?: return@forEach,
|
||||
mainUrl,
|
||||
quality,
|
||||
false
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
else loadExtractor(iframeUrl, data, subtitleCallback, callback)
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
Binary file not shown.
|
@ -1,14 +0,0 @@
|
|||
version = 2
|
||||
|
||||
cloudstream {
|
||||
description = ""
|
||||
authors = listOf( "ImZaw" )
|
||||
|
||||
language = "ar"
|
||||
|
||||
status = 1
|
||||
|
||||
tvTypes = listOf( "TvSeries" , "Movie" )
|
||||
|
||||
iconUrl = "https://www.google.com/s2/favicons?domain=https://fajer.show&sz=%size%"
|
||||
}
|
|
@ -1,2 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest package="com.fajershow"/>
|
|
@ -1,11 +0,0 @@
|
|||
package com.fajershow
|
||||
import com.lagradost.cloudstream3.plugins.CloudstreamPlugin
|
||||
import com.lagradost.cloudstream3.plugins.Plugin
|
||||
import android.content.Context
|
||||
|
||||
@CloudstreamPlugin
|
||||
class FajerShowPlugin: Plugin() {
|
||||
override fun load(context: Context) {
|
||||
registerMainAPI(FajerShow())
|
||||
}
|
||||
}
|
|
@ -1,247 +0,0 @@
|
|||
package com.fajershow
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty
|
||||
import com.lagradost.cloudstream3.*
|
||||
import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.parseJson
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.Qualities
|
||||
import com.lagradost.cloudstream3.utils.loadExtractor
|
||||
import org.jsoup.nodes.Element
|
||||
import java.net.URI
|
||||
import java.util.*
|
||||
import kotlin.collections.ArrayList
|
||||
|
||||
class FajerShow : MainAPI() {
|
||||
override var lang = "ar"
|
||||
override var mainUrl = "https://fajer.show"
|
||||
override var name = "FajerShow"
|
||||
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(home: Boolean): SearchResponse? {
|
||||
val quality = select("span.quality").text().replace("-|p".toRegex(), "")
|
||||
if(home == true) {
|
||||
val titleElement = select("div.data h3 a")
|
||||
val posterUrl = select("img").attr("src")
|
||||
val tvType = if (titleElement.attr("href").contains("/movies/")) TvType.Movie else TvType.TvSeries
|
||||
// If you need to differentiate use the url.
|
||||
return MovieSearchResponse(
|
||||
titleElement.text().replace(".*\\|".toRegex(), ""),
|
||||
titleElement.attr("href"),
|
||||
this@FajerShow.name,
|
||||
tvType,
|
||||
posterUrl,
|
||||
quality = getQualityFromString(quality)
|
||||
)
|
||||
} else {
|
||||
val posterElement = select("img")
|
||||
val url = select("div.thumbnail > a").attr("href")
|
||||
return MovieSearchResponse(
|
||||
posterElement.attr("alt"),
|
||||
url,
|
||||
this@FajerShow.name,
|
||||
if (url.contains("/movies/")) TvType.Movie else TvType.TvSeries,
|
||||
posterElement.attr("src"),
|
||||
quality = getQualityFromString(quality)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override val mainPage = mainPageOf(
|
||||
"$mainUrl/genre/english-movies/page/" to "English Movies",
|
||||
"$mainUrl/genre/arabic-movies/page/" to "Arabic Movies",
|
||||
"$mainUrl/genre/turkish-movies/page/" to "Turkish Movies",
|
||||
"$mainUrl/genre/animation/page/" to "Animation Movies",
|
||||
"$mainUrl/genre/english-series/page/" to "English Series",
|
||||
"$mainUrl/genre/arabic-series/page/" to "Arabic Series",
|
||||
"$mainUrl/genre/turkish-series/page/" to "Turkish Series",
|
||||
"$mainUrl/genre/indian-series/page/" to "Indian Series",
|
||||
)
|
||||
|
||||
override suspend fun getMainPage(
|
||||
page: Int,
|
||||
request: MainPageRequest
|
||||
): HomePageResponse {
|
||||
val document = app.get(request.data + page).document
|
||||
val home = document.select("article.item").mapNotNull {
|
||||
it.toSearchResponse(true)
|
||||
}
|
||||
return newHomePageResponse(request.name, home)
|
||||
}
|
||||
|
||||
override suspend fun search(query: String): List<SearchResponse> {
|
||||
val doc = app.get("$mainUrl/?s=$query").document
|
||||
return doc.select(".result-item > article").mapNotNull {
|
||||
it.toSearchResponse(false)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun load(url: String): LoadResponse {
|
||||
val doc = app.get(url).document
|
||||
val isMovie = url.contains("/movies/")
|
||||
|
||||
val posterUrl = doc.select("div.poster > img").attr("src")
|
||||
val rating = doc.select("span[itemprop=\"ratingValue\"]").text().toIntOrNull()
|
||||
val title = doc.select("div.data > h1").text()
|
||||
val synopsis = doc.select("div.wp-content > p").text()
|
||||
|
||||
val tags = doc.select("a[rel=\"tag\"]")?.map { it.text() }
|
||||
|
||||
val actors = doc.select("div.person").mapNotNull {
|
||||
val name = it.selectFirst("div > a > img")?.attr("alt") ?: return@mapNotNull null
|
||||
val image = it.selectFirst("div > a > img")?.attr("src") ?: return@mapNotNull null
|
||||
val roleString = it.select("div.data > div.caracter").text()
|
||||
val mainActor = Actor(name, image)
|
||||
ActorData(actor = mainActor, roleString = roleString)
|
||||
}
|
||||
|
||||
return if (isMovie) {
|
||||
val recommendations = doc.select(".owl-item article").mapNotNull { element ->
|
||||
element.toSearchResponse(true)
|
||||
}
|
||||
|
||||
newMovieLoadResponse(
|
||||
title,
|
||||
url,
|
||||
TvType.Movie,
|
||||
url
|
||||
) {
|
||||
this.posterUrl = posterUrl
|
||||
this.recommendations = recommendations
|
||||
this.plot = synopsis
|
||||
this.tags = tags
|
||||
this.actors = actors
|
||||
this.rating = rating
|
||||
}
|
||||
} else {
|
||||
val episodes = doc.select(".se-c ul > li").map {
|
||||
Episode(
|
||||
it.select("div.episodiotitle > a").attr("href"),
|
||||
it.select("div.episodiotitle > a").text(),
|
||||
it.select("div.numerando").text().split(" - ")[0].toInt(),
|
||||
it.select("div.numerando").text().split(" - ")[1].toInt(),
|
||||
it.select("div.imagen a img").attr("src")
|
||||
)
|
||||
}
|
||||
newTvSeriesLoadResponse(title, url, TvType.TvSeries, episodes.distinct().sortedBy { it.episode }) {
|
||||
this.posterUrl = posterUrl
|
||||
this.tags = tags
|
||||
this.plot = synopsis
|
||||
this.actors = actors
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data class FajerLive (
|
||||
@JsonProperty("success" ) var success : Boolean? = null,
|
||||
@JsonProperty("data" ) var data : ArrayList<Data> = arrayListOf(),
|
||||
)
|
||||
data class Data (
|
||||
@JsonProperty("file" ) var file : String? = null,
|
||||
@JsonProperty("label" ) var label : String? = null,
|
||||
@JsonProperty("type" ) var type : String? = null
|
||||
)
|
||||
override suspend fun loadLinks(
|
||||
data: String,
|
||||
isCasting: Boolean,
|
||||
subtitleCallback: (SubtitleFile) -> Unit,
|
||||
callback: (ExtractorLink) -> Unit
|
||||
): Boolean {
|
||||
val doc = app.get(data).document
|
||||
doc.select("li.vid_source_option").not("[data-nume=\"trailer\"]").apmap { source ->
|
||||
app.post(
|
||||
"$mainUrl/wp-admin/admin-ajax.php",
|
||||
data = mapOf(
|
||||
"action" to "doo_player_ajax",
|
||||
"post" to source.attr("data-post"),
|
||||
"nume" to source.attr("data-nume"),
|
||||
"type" to source.attr("data-type")
|
||||
)
|
||||
).document.select("iframe").attr("src").let {
|
||||
val hostname = URI(it).host
|
||||
if (it.contains("show.alfajertv.com")) {
|
||||
val url = URI(it)
|
||||
callback.invoke(
|
||||
ExtractorLink(
|
||||
this.name,
|
||||
"AlfajerTV Palestine",
|
||||
url.query.replace("&.*|source=".toRegex(), ""),
|
||||
data,
|
||||
Qualities.Unknown.value,
|
||||
url.query.replace("&.*|source=".toRegex(), "").contains(".m3u8")
|
||||
)
|
||||
)
|
||||
println("Palestine\n" + url.query.replace("&.*|source=".toRegex(), "") + "\n")
|
||||
}
|
||||
else if (it.contains("fajer.live")) {
|
||||
val id = it.split("/v/").last().split('/')[0];
|
||||
val response = parseJson<FajerLive>(app.post("https://$hostname/api/source/$id", data = mapOf("r" to "", "d" to hostname)).text)
|
||||
response.data.forEach {
|
||||
callback.invoke(
|
||||
ExtractorLink(
|
||||
this.name,
|
||||
"FajerLive",
|
||||
it.file ?: "",
|
||||
data,
|
||||
it.label?.getIntFromText() ?: Qualities.Unknown.value,
|
||||
it.type != "mp4"
|
||||
)
|
||||
)
|
||||
}
|
||||
println("FajerLive\n$response\n") // parse using FajerLive data class
|
||||
}
|
||||
else if (it.contains("vidmoly.to")) {
|
||||
val doc = app.get(it).document
|
||||
val m3u8 = doc.select("body > script").map { it.data() }.first { it.contains("sources") }.substringAfter("sources: [{file:\"").substringBefore("\"}],")
|
||||
callback.invoke(
|
||||
ExtractorLink(
|
||||
this.name,
|
||||
"Vidmoly",
|
||||
m3u8,
|
||||
data,
|
||||
Qualities.Unknown.value,
|
||||
m3u8.contains(".m3u8")
|
||||
)
|
||||
)
|
||||
println("VIDMOLY.TO\n$m3u8\n")
|
||||
}
|
||||
else if (it.contains("voe.sx")) {
|
||||
val doc = app.get(it).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 quality = script.substringAfter("'video_height': ").substringBefore(",").toInt()
|
||||
callback.invoke(
|
||||
ExtractorLink(
|
||||
this.name,
|
||||
"Voe.sx m3u8",
|
||||
m3u8,
|
||||
data,
|
||||
quality,
|
||||
true
|
||||
)
|
||||
)
|
||||
callback.invoke(
|
||||
ExtractorLink(
|
||||
this.name,
|
||||
"Voe.sx mp4",
|
||||
mp4,
|
||||
data,
|
||||
quality,
|
||||
)
|
||||
)
|
||||
println("VOE.SX\n$m3u8\n$mp4\n$quality\n")
|
||||
}
|
||||
else loadExtractor(it, data, subtitleCallback, callback)
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
Binary file not shown.
|
@ -1,14 +0,0 @@
|
|||
version = 6
|
||||
|
||||
cloudstream {
|
||||
description = ""
|
||||
authors = listOf( "ImZaw" )
|
||||
|
||||
language = "ar"
|
||||
|
||||
status = 1
|
||||
|
||||
tvTypes = listOf( "TvSeries" , "Movie" , "Anime" , "AsianDrama" )
|
||||
|
||||
iconUrl = "https://www.google.com/s2/favicons?domain=faselhd.io&sz=%size%"
|
||||
}
|
|
@ -1,2 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest package="com.faselhd"/>
|
|
@ -1,11 +0,0 @@
|
|||
package com.faselhd
|
||||
import com.lagradost.cloudstream3.plugins.CloudstreamPlugin
|
||||
import com.lagradost.cloudstream3.plugins.Plugin
|
||||
import android.content.Context
|
||||
|
||||
@CloudstreamPlugin
|
||||
class FaselHDPlugin: Plugin() {
|
||||
override fun load(context: Context) {
|
||||
registerMainAPI(FaselHD())
|
||||
}
|
||||
}
|
|
@ -1,203 +0,0 @@
|
|||
package com.faselhd
|
||||
|
||||
|
||||
import com.lagradost.cloudstream3.*
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.nicehttp.requestCreator
|
||||
import com.lagradost.cloudstream3.network.WebViewResolver
|
||||
import com.lagradost.cloudstream3.utils.M3u8Helper
|
||||
import com.lagradost.cloudstream3.utils.Qualities
|
||||
import com.lagradost.cloudstream3.network.CloudflareKiller
|
||||
import org.jsoup.nodes.Element
|
||||
|
||||
class FaselHD : MainAPI() {
|
||||
override var lang = "ar"
|
||||
override var mainUrl = "https://faselhd.io"
|
||||
private val alternativeUrl = "https://www.faselhd.club"
|
||||
override var name = "FaselHD"
|
||||
override val usesWebView = false
|
||||
override val hasMainPage = true
|
||||
override val supportedTypes = setOf(TvType.TvSeries, TvType.Movie, TvType.AsianDrama, TvType.Anime)
|
||||
private val cfKiller = CloudflareKiller()
|
||||
|
||||
private fun String.getIntFromText(): Int? {
|
||||
return Regex("""\d+""").find(this)?.groupValues?.firstOrNull()?.toIntOrNull()
|
||||
}
|
||||
|
||||
private fun Element.toSearchResponse(): SearchResponse? {
|
||||
val url = select("div.postDiv a").attr("href") ?: return null
|
||||
val posterUrl = select("div.postDiv a div img").attr("data-src") ?:
|
||||
select("div.postDiv a div img").attr("src")
|
||||
val title = select("div.postDiv a div img").attr("alt")
|
||||
val quality = select(".quality").first()?.text()?.replace("1080p |-".toRegex(), "")
|
||||
val type = if(title.contains("فيلم")) TvType.Movie else TvType.TvSeries
|
||||
return MovieSearchResponse(
|
||||
title.replace("الموسم الأول|برنامج|فيلم|مترجم|اون لاين|مسلسل|مشاهدة|انمي|أنمي".toRegex(),""),
|
||||
url,
|
||||
this@FaselHD.name,
|
||||
type,
|
||||
posterUrl,
|
||||
null,
|
||||
null,
|
||||
quality = getQualityFromString(quality),
|
||||
posterHeaders = cfKiller.getCookieHeaders(alternativeUrl).toMap()
|
||||
)
|
||||
}
|
||||
override val mainPage = mainPageOf(
|
||||
"$mainUrl/all-movies/page/" to "Movies",
|
||||
"$mainUrl/series/page/" to "Series",
|
||||
"$mainUrl/movies_top_imdb/page/" to "Top Movies IMDB",
|
||||
)
|
||||
|
||||
override suspend fun getMainPage(page: Int, request : MainPageRequest): HomePageResponse {
|
||||
var doc = app.get(request.data + page).document
|
||||
if(doc.select("title").text() == "Just a moment...") {
|
||||
doc = app.get(request.data.replace(mainUrl, alternativeUrl) + page, interceptor = cfKiller, timeout = 120).document
|
||||
}
|
||||
val list = doc.select("div[id=\"postList\"] div[class=\"col-xl-2 col-lg-2 col-md-3 col-sm-3\"]")
|
||||
.mapNotNull { element ->
|
||||
element.toSearchResponse()
|
||||
}
|
||||
return newHomePageResponse(request.name, list)
|
||||
}
|
||||
|
||||
override suspend fun search(query: String): List<SearchResponse> {
|
||||
val q = query.replace(" ","+")
|
||||
var d = app.get("$mainUrl/?s=$q").document
|
||||
if(d.select("title").text() == "Just a moment...") {
|
||||
d = app.get("$alternativeUrl/?s=$q", interceptor = cfKiller, timeout = 120).document
|
||||
}
|
||||
return d.select("div[id=\"postList\"] div[class=\"col-xl-2 col-lg-2 col-md-3 col-sm-3\"]")
|
||||
.mapNotNull {
|
||||
it.toSearchResponse()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override suspend fun load(url: String): LoadResponse {
|
||||
var doc = app.get(url).document
|
||||
if(doc.select("title").text() == "Just a moment...") {
|
||||
doc = app.get(url, interceptor = cfKiller, timeout = 120).document
|
||||
}
|
||||
val isMovie = doc.select("div.epAll").isEmpty()
|
||||
val posterUrl = doc.select("div.posterImg img").attr("src")
|
||||
.ifEmpty { doc.select("div.seasonDiv.active img").attr("data-src") }
|
||||
|
||||
val year = doc.select("div[id=\"singleList\"] div[class=\"col-xl-6 col-lg-6 col-md-6 col-sm-6\"]").firstOrNull {
|
||||
it.text().contains("سنة|موعد".toRegex())
|
||||
}?.text()?.getIntFromText()
|
||||
|
||||
val title =
|
||||
doc.select("title").text().replace(" - فاصل إعلاني", "")
|
||||
.replace("الموسم الأول|برنامج|فيلم|مترجم|اون لاين|مسلسل|مشاهدة|انمي|أنمي|$year".toRegex(),"")
|
||||
// A bit iffy to parse twice like this, but it'll do.
|
||||
val duration = doc.select("div[id=\"singleList\"] div[class=\"col-xl-6 col-lg-6 col-md-6 col-sm-6\"]").firstOrNull {
|
||||
it.text().contains("مدة|توقيت".toRegex())
|
||||
}?.text()?.getIntFromText()
|
||||
|
||||
val tags = doc.select("div[id=\"singleList\"] div[class=\"col-xl-6 col-lg-6 col-md-6 col-sm-6\"]:contains(تصنيف الفيلم) a").map {
|
||||
it.text()
|
||||
}
|
||||
val recommendations = doc.select("div#postList div.postDiv").mapNotNull {
|
||||
it.toSearchResponse()
|
||||
}
|
||||
val synopsis = doc.select("div.singleDesc p").text()
|
||||
return if (isMovie) {
|
||||
newMovieLoadResponse(
|
||||
title,
|
||||
url,
|
||||
TvType.Movie,
|
||||
url
|
||||
) {
|
||||
this.posterUrl = posterUrl
|
||||
this.year = year
|
||||
this.plot = synopsis
|
||||
this.duration = duration
|
||||
this.tags = tags
|
||||
this.recommendations = recommendations
|
||||
this.posterHeaders = cfKiller.getCookieHeaders(alternativeUrl).toMap()
|
||||
}
|
||||
} else {
|
||||
val episodes = ArrayList<Episode>()
|
||||
doc.select("div.epAll a").map {
|
||||
episodes.add(
|
||||
Episode(
|
||||
it.attr("href"),
|
||||
it.text(),
|
||||
doc.select("div.seasonDiv.active div.title").text().getIntFromText() ?: 1,
|
||||
it.text().getIntFromText(),
|
||||
)
|
||||
)
|
||||
}
|
||||
doc.select("div[id=\"seasonList\"] div[class=\"col-xl-2 col-lg-3 col-md-6\"] div.seasonDiv")
|
||||
.not(".active").apmap { it ->
|
||||
var s = app.get("$mainUrl/?p="+it.attr("data-href")).document
|
||||
if(s.select("title").text() == "Just a moment...") {
|
||||
s = app.get("$alternativeUrl/?p="+it.attr("data-href"), interceptor = cfKiller).document
|
||||
}
|
||||
s.select("div.epAll a").map {
|
||||
episodes.add(
|
||||
Episode(
|
||||
it.attr("href"),
|
||||
it.text(),
|
||||
s.select("div.seasonDiv.active div.title").text().getIntFromText(),
|
||||
it.text().getIntFromText(),
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
newTvSeriesLoadResponse(title, url, TvType.TvSeries, episodes.distinct().sortedBy { it.episode }) {
|
||||
this.duration = duration
|
||||
this.posterUrl = posterUrl
|
||||
this.year = year
|
||||
this.plot = synopsis
|
||||
this.tags = tags
|
||||
this.recommendations = recommendations
|
||||
this.posterHeaders = cfKiller.getCookieHeaders(alternativeUrl).toMap()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun loadLinks(
|
||||
data: String,
|
||||
isCasting: Boolean,
|
||||
subtitleCallback: (SubtitleFile) -> Unit,
|
||||
callback: (ExtractorLink) -> Unit
|
||||
): Boolean {
|
||||
var doc = app.get(data).document
|
||||
if(doc.select("title").text() == "Just a moment...") {
|
||||
doc = app.get(data, interceptor = cfKiller).document
|
||||
}
|
||||
listOf(
|
||||
doc.select(".downloadLinks a").attr("href") to "download",
|
||||
doc.select("iframe[name=\"player_iframe\"]").attr("src") to "iframe"
|
||||
).apmap { (url, method) ->
|
||||
if(method == "download") {
|
||||
val player = app.post(url, interceptor = cfKiller, referer = mainUrl, timeout = 120).document
|
||||
callback.invoke(
|
||||
ExtractorLink(
|
||||
this.name,
|
||||
this.name + " Download Source",
|
||||
player.select("div.dl-link a").attr("href"),
|
||||
this.mainUrl,
|
||||
Qualities.Unknown.value
|
||||
)
|
||||
)
|
||||
} else if(method == "iframe") {
|
||||
val webView = WebViewResolver(
|
||||
Regex("""master\.m3u8""")
|
||||
).resolveUsingWebView(
|
||||
requestCreator(
|
||||
"GET", url, referer = mainUrl
|
||||
)
|
||||
).first
|
||||
M3u8Helper.generateM3u8(
|
||||
this.name,
|
||||
webView?.url.toString(),
|
||||
referer = mainUrl
|
||||
).toList().forEach(callback)
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
Binary file not shown.
|
@ -1,12 +0,0 @@
|
|||
version = 1
|
||||
|
||||
cloudstream {
|
||||
description = ""
|
||||
authors = listOf( "Spoonge" )
|
||||
language = "ar"
|
||||
status = 1
|
||||
|
||||
tvTypes = listOf( "Movie")
|
||||
|
||||
iconUrl = "https://www.google.com/s2/favicons?domain=www.fushaar.com&sz=%size%"
|
||||
}
|
|
@ -1,2 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest package="com.fushaar"/>
|
|
@ -1,11 +0,0 @@
|
|||
package com.fushaar
|
||||
import com.lagradost.cloudstream3.plugins.CloudstreamPlugin
|
||||
import com.lagradost.cloudstream3.plugins.Plugin
|
||||
import android.content.Context
|
||||
|
||||
@CloudstreamPlugin
|
||||
class FushaarPlugin: Plugin() {
|
||||
override fun load(context: Context) {
|
||||
registerMainAPI(Fushaar())
|
||||
}
|
||||
}
|
|
@ -1,137 +0,0 @@
|
|||
package com.fushaar
|
||||
|
||||
import com.lagradost.cloudstream3.*
|
||||
import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.Qualities
|
||||
import com.lagradost.cloudstream3.utils.getQualityFromName
|
||||
import com.lagradost.cloudstream3.utils.loadExtractor
|
||||
import org.jsoup.nodes.Element
|
||||
|
||||
class Fushaar : MainAPI() {
|
||||
override var lang = "ar"
|
||||
override var mainUrl = "https://www.fushaar.com"
|
||||
override var name = "Fushaar"
|
||||
override val usesWebView = false
|
||||
override val hasMainPage = true
|
||||
override val supportedTypes = setOf(TvType.Movie)
|
||||
|
||||
|
||||
private fun String.getIntFromText(): Int? {
|
||||
return Regex("""\d+""").find(this)?.groupValues?.firstOrNull()?.toIntOrNull()
|
||||
}
|
||||
|
||||
private fun Element.toSearchResponse(): SearchResponse? {
|
||||
val url = select("article.poster")
|
||||
val posterUrl = select("img").attr("data-lazy-src")
|
||||
val year = select("ul.labels li.year").text()?.getIntFromText()
|
||||
var quality = select("div").first()?.attr("class")?.replace("hdd","hd")?.replace("caam","cam")
|
||||
val title = select("div.info h3").text()+"\n"+select("div.info h4").text()
|
||||
|
||||
return MovieSearchResponse(
|
||||
title,
|
||||
url.select("a").attr("href"),
|
||||
this@Fushaar.name,
|
||||
TvType.Movie,
|
||||
posterUrl,
|
||||
year,
|
||||
null,
|
||||
quality = getQualityFromString(quality),
|
||||
)
|
||||
}
|
||||
|
||||
override val mainPage = mainPageOf(
|
||||
"$mainUrl/page/" to "Movies | أفلام",
|
||||
"$mainUrl/gerne/action/page/" to "Action | أكشن",
|
||||
"$mainUrl/gerne/adventure/page/" to "Adventure | مغامرة",
|
||||
"$mainUrl/gerne/animation/page/" to "Animation | أنيمايشن",
|
||||
"$mainUrl/gerne/biography/page/" to "Biography | سيرة",
|
||||
"$mainUrl/gerne/comedy/page/" to "Comedy | كوميديا",
|
||||
"$mainUrl/gerne/crime/page/" to "Crime | جريمة",
|
||||
"$mainUrl/gerne/documentary/page/" to "Documentary | وثائقي",
|
||||
"$mainUrl/gerne/drama/page/" to "Drama | دراما",
|
||||
"$mainUrl/gerne/family/page/" to "Family | عائلي",
|
||||
"$mainUrl/gerne/fantasy/page/" to "Fantasy | فنتازيا",
|
||||
"$mainUrl/gerne/herror/page/" to "Herror | رعب",
|
||||
"$mainUrl/gerne/history/page/" to "History |تاريخي",
|
||||
"$mainUrl/gerne/music/page/" to "Music | موسيقى",
|
||||
"$mainUrl/gerne/musical/page/" to "Musical | موسيقي",
|
||||
"$mainUrl/gerne/mystery/page/" to "Mystery | غموض",
|
||||
"$mainUrl/gerne/romance/page/" to "Romance | رومنسي",
|
||||
"$mainUrl/gerne/sci-fi/page/" to "Sci-fi | خيال علمي",
|
||||
"$mainUrl/gerne/short/page/" to "Short | قصير",
|
||||
"$mainUrl/gerne/sport/page/" to "Sport | رياضة",
|
||||
"$mainUrl/gerne/thriller/page/" to "Thriller | إثارة",
|
||||
"$mainUrl/gerne/war/page/" to "War | حرب",
|
||||
"$mainUrl/gerne/western/page/" to "Western | غربي",
|
||||
)
|
||||
|
||||
override suspend fun getMainPage(page: Int, request : MainPageRequest): HomePageResponse {
|
||||
val doc = app.get(request.data + page).document
|
||||
val list = doc.select("article.poster").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/?s=$q").document.select("article.poster").mapNotNull {
|
||||
it.toSearchResponse()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override suspend fun load(url: String): LoadResponse {
|
||||
var doc = app.get(url).document
|
||||
val posterUrl = doc.select("figure.poster noscript img").attr("src")
|
||||
val year = doc.select("header span.yearz").text()?.getIntFromText()
|
||||
val title = doc.select("header h1").text()+" | "+doc.select("header h2").text()
|
||||
val synopsis = doc.select("div.postz").text()
|
||||
val trailer = doc.select("#new-stream > div > div.ytb > a").attr("href")
|
||||
val tags = doc.select("div.zoomInUp a").map{it.text()}//doc.select("li.iifo").map { it.select("span.z-s-i").text()+" "+it.select("h8").text() }
|
||||
val rating = doc.select("body > div.new-info.hide-mobile > div > div.z-imdb > div").text()?.toRatingInt()
|
||||
val recommendations = doc.select("article.poster").mapNotNull { element ->
|
||||
element.toSearchResponse()
|
||||
}
|
||||
|
||||
return newMovieLoadResponse(
|
||||
title,
|
||||
url,
|
||||
TvType.Movie,
|
||||
url
|
||||
) {
|
||||
this.posterUrl = posterUrl
|
||||
this.year = year
|
||||
this.tags = tags
|
||||
this.plot = synopsis
|
||||
this.rating = rating
|
||||
this.recommendations = recommendations
|
||||
addTrailer(trailer)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override suspend fun loadLinks(
|
||||
data: String,
|
||||
isCasting: Boolean,
|
||||
subtitleCallback: (SubtitleFile) -> Unit,
|
||||
callback: (ExtractorLink) -> Unit
|
||||
): Boolean {
|
||||
val doc = app.get(data).document
|
||||
var sourceUrl = doc.select("div:nth-child(10) > a").attr("href")
|
||||
loadExtractor(sourceUrl, data, subtitleCallback, callback)
|
||||
doc.select("#fancyboxID-download > center > a:nth-child(n+19),#fancyboxID-1 > center > a:nth-child(n+16)").map {
|
||||
callback.invoke(
|
||||
ExtractorLink(
|
||||
source = this.name,
|
||||
name = name,
|
||||
url = it.attr("href"),
|
||||
referer = this.mainUrl,
|
||||
quality = it.text().getIntFromText() ?: Qualities.Unknown.value,
|
||||
)
|
||||
)
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
Binary file not shown.
|
@ -1,14 +0,0 @@
|
|||
version = 3
|
||||
|
||||
cloudstream {
|
||||
description = ""
|
||||
authors = listOf( "ImZaw" )
|
||||
|
||||
language = "ar"
|
||||
|
||||
status = 1
|
||||
|
||||
tvTypes = listOf( "Anime", "AnimeMovie", "Cartoon" )
|
||||
|
||||
iconUrl = "https://b.gateanime.cam/wp-content/uploads/2020/12/cropped-Favicon-192x192.png"
|
||||
}
|
|
@ -1,2 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest package="com.gateanime"/>
|
|
@ -1,11 +0,0 @@
|
|||
package com.gateanime
|
||||
import com.lagradost.cloudstream3.plugins.CloudstreamPlugin
|
||||
import com.lagradost.cloudstream3.plugins.Plugin
|
||||
import android.content.Context
|
||||
|
||||
@CloudstreamPlugin
|
||||
class GateAnimePlugin: Plugin() {
|
||||
override fun load(context: Context) {
|
||||
registerMainAPI(GateAnime())
|
||||
}
|
||||
}
|
|
@ -1,139 +0,0 @@
|
|||
package com.gateanime
|
||||
|
||||
|
||||
import com.lagradost.cloudstream3.*
|
||||
import com.lagradost.cloudstream3.LoadResponse.Companion.addMalId
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.loadExtractor
|
||||
import org.jsoup.nodes.Element
|
||||
|
||||
class GateAnime : MainAPI() {
|
||||
override var lang = "ar"
|
||||
override var mainUrl = "https://b.gateanime.cam"
|
||||
override var name = "GateAnime"
|
||||
override val usesWebView = false
|
||||
override val hasMainPage = true
|
||||
override val supportedTypes =
|
||||
setOf(TvType.Anime, TvType.AnimeMovie, TvType.Cartoon )
|
||||
|
||||
fun hasEnglishLetters(string: String): Boolean {
|
||||
for (c in string)
|
||||
{
|
||||
if (c !in 'A'..'Z' && c !in 'a'..'z') {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
private fun Element.toSearchResponse(): SearchResponse? {
|
||||
val url = select("a").attr("href")
|
||||
val title = select("h3.Title").text()
|
||||
val posterUrl = select("img").attr("src")
|
||||
val type =
|
||||
if (select("span.TpTv.BgA").isNotEmpty()) TvType.Anime else TvType.AnimeMovie
|
||||
val year = select("span.Year").text().toIntOrNull()
|
||||
return newAnimeSearchResponse(
|
||||
title,
|
||||
url,
|
||||
type,
|
||||
) {
|
||||
addDubStatus(title.contains("مدبلج") || !hasEnglishLetters(title))
|
||||
this.year = year
|
||||
this.posterUrl = posterUrl
|
||||
}
|
||||
}
|
||||
override val mainPage = mainPageOf(
|
||||
"$mainUrl/movies/page/" to "Anime Movies",
|
||||
"$mainUrl/series/page/" to "Anime",
|
||||
"$mainUrl/category/مدبلج/page/" to "Dubbed"
|
||||
)
|
||||
|
||||
override suspend fun getMainPage(page: Int, request: MainPageRequest): HomePageResponse {
|
||||
val doc = app.get(request.data + page).document
|
||||
val list = doc.select("ul li.TPostMv")
|
||||
.mapNotNull { element ->
|
||||
element.toSearchResponse()
|
||||
}
|
||||
return newHomePageResponse(request.name, list)
|
||||
}
|
||||
|
||||
override suspend fun search(query: String): List<SearchResponse> {
|
||||
return app.get("$mainUrl/?s=$query").document.select("ul li.TPostMv").mapNotNull {
|
||||
it.toSearchResponse()
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun load(url: String): LoadResponse {
|
||||
val doc = app.get(url).document
|
||||
|
||||
val title = doc.select("h1.Title").text()
|
||||
val poster = doc.select("div.Image img").attr("src")
|
||||
val description = doc.select("p:contains(قصة)").first()?.text()
|
||||
val genre = doc.select("p:contains(التصنيفات)").text().replace("التصنيفات : ", "").split("،")
|
||||
val year = doc.select(".Date").text().toIntOrNull()
|
||||
val rating = doc.select("span.AAIco-star").text().toIntOrNull()
|
||||
|
||||
val nativeName = doc.select(".SubTitle").text()
|
||||
val type = if(url.contains("movie")) TvType.AnimeMovie else TvType.Anime
|
||||
|
||||
val malId = doc.select("a:contains(myanimelist)").attr("href").replace(".*e\\/|\\/.*".toRegex(),"").toIntOrNull()
|
||||
|
||||
val episodes = arrayListOf<Episode>()
|
||||
val backgroundImage = doc.select("img.TPostBg").first()?.attr("src")
|
||||
val seasonsElements = doc.select("div.Wdgt.AABox")
|
||||
if(seasonsElements.isEmpty()) {
|
||||
episodes.add(Episode(
|
||||
url,
|
||||
"Watch",
|
||||
posterUrl = backgroundImage
|
||||
))
|
||||
} else {
|
||||
seasonsElements.map { season ->
|
||||
val seasonNumber = season.select("div.Title").attr("data-tab").toIntOrNull()
|
||||
season.select("tr").forEach {
|
||||
val titleTd = it.select("td.MvTbTtl a")
|
||||
episodes.add(Episode(
|
||||
titleTd.attr("href"),
|
||||
titleTd.text(),
|
||||
seasonNumber,
|
||||
it.select("span.Num").text().toIntOrNull()
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
return newAnimeLoadResponse(title, url, type) {
|
||||
addMalId(malId)
|
||||
japName = nativeName
|
||||
engName = title
|
||||
posterUrl = poster
|
||||
this.year = year
|
||||
addEpisodes(if(title.contains("مدبلج")) DubStatus.Dubbed else DubStatus.Subbed, episodes) // TODO CHECK
|
||||
plot = description
|
||||
tags = genre
|
||||
this.rating = rating
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun loadLinks(
|
||||
data: String,
|
||||
isCasting: Boolean,
|
||||
subtitleCallback: (SubtitleFile) -> Unit,
|
||||
callback: (ExtractorLink) -> Unit
|
||||
): Boolean {
|
||||
println("URL: $data")
|
||||
val doc = app.get(data).document
|
||||
doc.select(
|
||||
"li:contains(Fembed), li:contains(خيارات 1), li:contains(Uptostream), li:contains(Dood), li:contains(Uqload), li:contains(Drive)"
|
||||
).apmap {
|
||||
val id = it.attr("data-tplayernv")
|
||||
val iframeLink = doc.select("div#$id").html().replace(".*src=\"|\".*|#038;|amp;".toRegex(), "").replace("<noscript>.*".toRegex(),"")
|
||||
var sourceUrl = app.get(iframeLink).document.select("iframe").attr("src")
|
||||
if(sourceUrl.contains("ok.ru")) sourceUrl = "https:$sourceUrl"
|
||||
if(sourceUrl.contains("drive.google.com")) sourceUrl = "https://gdriveplayer.to/embed2.php?link=$sourceUrl"
|
||||
loadExtractor(sourceUrl, data, subtitleCallback, callback)
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
Binary file not shown.
|
@ -1,14 +0,0 @@
|
|||
version = 3
|
||||
|
||||
cloudstream {
|
||||
description = "Not recommended for series."
|
||||
authors = listOf( "Spoonge" )
|
||||
|
||||
language = "ar"
|
||||
|
||||
status = 1
|
||||
|
||||
tvTypes = listOf( "Movie" )
|
||||
|
||||
iconUrl = "https://www.google.com/s2/favicons?domain=movizland.cyou&sz=%size%"
|
||||
}
|
|
@ -1,2 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest package="com.movizland"/>
|
|
@ -1,11 +0,0 @@
|
|||
package com.movizland
|
||||
import com.lagradost.cloudstream3.plugins.CloudstreamPlugin
|
||||
import com.lagradost.cloudstream3.plugins.Plugin
|
||||
import android.content.Context
|
||||
|
||||
@CloudstreamPlugin
|
||||
class MovizlandPlugin: Plugin() {
|
||||
override fun load(context: Context) {
|
||||
registerMainAPI(Movizland())
|
||||
}
|
||||
}
|
|
@ -1,223 +0,0 @@
|
|||
package com.movizland
|
||||
|
||||
import com.lagradost.cloudstream3.*
|
||||
import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.Qualities
|
||||
import com.lagradost.cloudstream3.utils.getQualityFromName
|
||||
import com.lagradost.cloudstream3.utils.loadExtractor
|
||||
import org.jsoup.nodes.Element
|
||||
|
||||
class Movizland : MainAPI() {
|
||||
override var lang = "ar"
|
||||
override var mainUrl = "https://movizland.online"
|
||||
override var name = "Movizland"
|
||||
override val usesWebView = false
|
||||
override val hasMainPage = true
|
||||
override val supportedTypes = setOf(TvType.TvSeries, TvType.Movie, TvType.AsianDrama, TvType.Anime)
|
||||
|
||||
private fun String.getIntFromText(): Int? {
|
||||
return Regex("""\d+""").find(this)?.groupValues?.firstOrNull()?.toIntOrNull()
|
||||
}
|
||||
|
||||
private fun String.cleanTitle(): String {
|
||||
val prefix = setOf("مشاهدة فيلم","مشاهدة وتحميل فيلم","تحميل","فيلم","انمي","إنمي","مسلسل","برنامج")
|
||||
val suffix = setOf("مدبلج للعربية","اون لاين","مترجم")
|
||||
this.let{ clean ->
|
||||
var aa = clean
|
||||
prefix.forEach{ pre ->
|
||||
aa = if (aa.contains(pre)) aa.replace(pre,"") else aa }
|
||||
var bb = aa
|
||||
suffix.mapNotNull{ suf ->
|
||||
bb = if (bb.contains(suf)) bb.replace(suf,"") else bb }
|
||||
return bb
|
||||
}
|
||||
}
|
||||
|
||||
private fun Element.toSearchResponse(): SearchResponse? {
|
||||
val url = select(".BlockItem")
|
||||
val title = url.select(".BlockTitle").text().cleanTitle()
|
||||
val img = url.select("img:last-of-type")
|
||||
val posterUrl = img?.attr("src")?.ifEmpty { img?.attr("data-src") }
|
||||
val year = select(".InfoEndBlock li").last()?.text()?.getIntFromText()
|
||||
var quality = select(".RestInformation li").last()?.text()?.replace(" |-|1080p|720p".toRegex(), "")
|
||||
?.replace("WEB DL","WEBDL")?.replace("BluRay","BLURAY")
|
||||
return MovieSearchResponse(
|
||||
title.replace("$year",""),
|
||||
url.select("a").attr("href"),
|
||||
this@Movizland.name,
|
||||
TvType.TvSeries,
|
||||
posterUrl,
|
||||
year,
|
||||
null,
|
||||
quality = getQualityFromString(quality),
|
||||
)
|
||||
}
|
||||
|
||||
override val mainPage = mainPageOf(
|
||||
"$mainUrl/page/" to "الحلقات و الافلام المضافة حديثا",
|
||||
"$mainUrl/category/movies/page/" to "أفلام",
|
||||
"$mainUrl/series/page/" to "مسلسلات",
|
||||
)
|
||||
|
||||
override suspend fun getMainPage(page: Int, request : MainPageRequest): HomePageResponse {
|
||||
val doc = app.get(request.data + page).document
|
||||
val list = doc.select(".BlockItem").mapNotNull { element ->
|
||||
element.toSearchResponse()
|
||||
}
|
||||
return newHomePageResponse(request.name, list)
|
||||
}
|
||||
|
||||
override suspend fun search(query: String): List<SearchResponse> {
|
||||
val d = app.get("$mainUrl/?s=$query").document
|
||||
return d.select(".BlockItem").mapNotNull {
|
||||
if(it.select(".BlockTitle").text().contains("الحلقة")) return@mapNotNull null;
|
||||
it.toSearchResponse()
|
||||
}
|
||||
}
|
||||
|
||||
private fun getSeasonFromString(sName: String): Int {
|
||||
return when (sName.isNotEmpty()) {
|
||||
sName.contains("الموسم الاول|الموسم 1".toRegex()) -> 1
|
||||
sName.contains("الموسم الحادي عشر|الموسم 11".toRegex()) -> 11
|
||||
sName.contains("الموسم الثاني عشر|الموسم 12".toRegex()) -> 12
|
||||
sName.contains("الموسم الثالث عشر|الموسم 13".toRegex()) -> 13
|
||||
sName.contains("الموسم الرابع عشر|الموسم 14".toRegex()) -> 14
|
||||
sName.contains("الموسم الخامس عشر|الموسم 15".toRegex()) -> 15
|
||||
sName.contains("الموسم السادس عشر|الموسم 16".toRegex()) -> 16
|
||||
sName.contains("الموسم السابع عشر|الموسم 17".toRegex()) -> 17
|
||||
sName.contains("الموسم الثامن عشر|الموسم 18".toRegex()) -> 18
|
||||
sName.contains("الموسم التاسع عشر|الموسم 19".toRegex()) -> 19
|
||||
sName.contains("الموسم الثاني|الموسم 2".toRegex()) -> 2
|
||||
sName.contains("الموسم الثالث|الموسم 3".toRegex()) -> 3
|
||||
sName.contains("الموسم الرابع|الموسم 4".toRegex()) -> 4
|
||||
sName.contains("الموسم الخامس|الموسم 5".toRegex()) -> 5
|
||||
sName.contains("الموسم السادس|الموسم 6".toRegex()) -> 6
|
||||
sName.contains("الموسم السابع|الموسم 7".toRegex()) -> 7
|
||||
sName.contains("الموسم الثامن|الموسم 8".toRegex()) -> 8
|
||||
sName.contains("الموسم التاسع|الموسم 9".toRegex()) -> 9
|
||||
sName.contains("الموسم العاشر|الموسم 10".toRegex()) -> 10
|
||||
sName.contains("الموسم العشرون|الموسم 20".toRegex()) -> 20
|
||||
else -> 1
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun load(url: String): LoadResponse {
|
||||
var doc = app.get(url).document
|
||||
val sdetails = doc.select(".SingleDetails")
|
||||
val posterUrl = sdetails.select(".Poster img").attr("data-src").ifEmpty {
|
||||
sdetails.select(".BlockItem").last()?.select(".Poster img")?.attr("src")
|
||||
}
|
||||
val year = sdetails.select("li:has(.fa-clock) a").text()?.getIntFromText()
|
||||
val title = doc.select("h2.postTitle").text().cleanTitle().replace("$year","")
|
||||
val isMovie = doc.select("h2.postTitle").text().contains("عرض|فيلم".toRegex())
|
||||
val synopsis = doc.select("section.story").text()
|
||||
val trailer = doc.select("div.InnerTrailer iframe").attr("data-src")
|
||||
val tags = sdetails.select("li:has(.fa-film) a").map{ it.text() }
|
||||
|
||||
return if (isMovie) {
|
||||
newMovieLoadResponse(
|
||||
title,
|
||||
url,
|
||||
TvType.Movie,
|
||||
url
|
||||
) {
|
||||
this.posterUrl = posterUrl
|
||||
this.year = year
|
||||
this.tags = tags
|
||||
this.plot = synopsis
|
||||
addTrailer(trailer)
|
||||
}
|
||||
} else {
|
||||
val episodes = ArrayList<Episode>()
|
||||
val pageUrl = doc.select("meta[property='og:url']").attr("content")
|
||||
val refererUrl = doc.select("body > header > div > div.Logo > a").attr("href")
|
||||
if(doc.select(".BlockItem a").attr("href").contains("/series/")){//seasons
|
||||
doc.select(".BlockItem").map { seas ->
|
||||
seas.select("a").attr("href") }.apmap{ pageIt ->
|
||||
val Sedoc = app.get(pageIt).document
|
||||
val pagEl = Sedoc.select(".pagination > div > ul > li").isNotEmpty()
|
||||
if(pagEl) {
|
||||
Sedoc.select(".pagination > div > ul > li:nth-child(n):not(:last-child) a").apmap {
|
||||
val epidoc = app.get(it.attr("href")).document
|
||||
epidoc.select("div.BlockItem").map{ element ->
|
||||
episodes.add(
|
||||
Episode(
|
||||
element.select("a").attr("href"),
|
||||
element.select(".BlockTitle").text(),
|
||||
getSeasonFromString(element.select(".BlockTitle").text()),
|
||||
element.select(".EPSNumber").text().getIntFromText(),
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}else{
|
||||
Sedoc.select(".BlockItem").map{ el ->
|
||||
episodes.add(
|
||||
Episode(
|
||||
el.select("a").attr("href"),
|
||||
el.select(".BlockTitle").text(),
|
||||
getSeasonFromString(el.select(".BlockTitle").text()),
|
||||
el.select(".EPSNumber").text().getIntFromText(),
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else {//episodes
|
||||
val pagEl = doc.select(".pagination > div > ul > li.active > a").isNotEmpty()
|
||||
val pagSt = if(pagEl) true else false
|
||||
if(pagSt){
|
||||
doc.select(".pagination > div > ul > li:nth-child(n):not(:last-child) a").map{ eppages ->
|
||||
eppages.attr("href") }.apmap{
|
||||
val epidoc = app.get(it).document
|
||||
epidoc.select("div.BlockItem").map{ element ->
|
||||
episodes.add(
|
||||
Episode(
|
||||
element.select("a").attr("href"),
|
||||
element.select(".BlockTitle").text(),
|
||||
getSeasonFromString(element.select(".BlockTitle").text()),
|
||||
element.select(".EPSNumber").text().getIntFromText(),
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}else{
|
||||
doc.select("div.BlockItem").map{ el ->
|
||||
episodes.add(
|
||||
Episode(
|
||||
el.select("a").attr("href"),
|
||||
el.select(".BlockTitle").text(),
|
||||
getSeasonFromString(el.select(".BlockTitle").text()),
|
||||
el.select(".EPSNumber").text().getIntFromText(),
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
newTvSeriesLoadResponse(title, url, TvType.TvSeries, episodes) {
|
||||
/*this.posterUrl = posterUrl
|
||||
this.year = year
|
||||
this.tags = tags
|
||||
this.plot = synopsis
|
||||
addTrailer(trailer)*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun loadLinks(
|
||||
data: String,
|
||||
isCasting: Boolean,
|
||||
subtitleCallback: (SubtitleFile) -> Unit,
|
||||
callback: (ExtractorLink) -> Unit
|
||||
): Boolean {
|
||||
val doc = app.get(data).document
|
||||
doc.select("code[id*='Embed'] iframe").apmap {
|
||||
var sourceUrl = it.attr("data-srcout")
|
||||
loadExtractor(sourceUrl, data, subtitleCallback, callback)
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
Binary file not shown.
|
@ -1,14 +0,0 @@
|
|||
version = 3
|
||||
|
||||
cloudstream {
|
||||
description = ""
|
||||
authors = listOf( "ImZaw" )
|
||||
|
||||
language = "ar"
|
||||
|
||||
status = 1
|
||||
|
||||
tvTypes = listOf( "TvSeries" , "Movie" , "Anime" )
|
||||
|
||||
iconUrl = "https://www.google.com/s2/favicons?domain=mycima.tv&sz=%size%"
|
||||
}
|
|
@ -1,2 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest package="com.mycima"/>
|
|
@ -1,11 +0,0 @@
|
|||
package com.mycima
|
||||
import com.lagradost.cloudstream3.plugins.CloudstreamPlugin
|
||||
import com.lagradost.cloudstream3.plugins.Plugin
|
||||
import android.content.Context
|
||||
|
||||
@CloudstreamPlugin
|
||||
class MyCimaPlugin: Plugin() {
|
||||
override fun load(context: Context) {
|
||||
registerMainAPI(MyCima())
|
||||
}
|
||||
}
|
|
@ -1,327 +0,0 @@
|
|||
package com.mycima
|
||||
|
||||
|
||||
import com.lagradost.cloudstream3.*
|
||||
import com.lagradost.cloudstream3.LoadResponse.Companion.addActors
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.parseJson
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import org.jsoup.Jsoup
|
||||
import org.jsoup.nodes.Element
|
||||
|
||||
class MyCima : MainAPI() {
|
||||
override var lang = "ar"
|
||||
override var mainUrl = "https://myciima.motorcycles"
|
||||
override var name = "MyCima"
|
||||
override val usesWebView = false
|
||||
override val hasMainPage = true
|
||||
override val supportedTypes = setOf(TvType.TvSeries, TvType.Movie, TvType.Anime)
|
||||
|
||||
private fun String.getImageURL(): String? {
|
||||
return this.replace("--im(age|g):url\\(|\\);".toRegex(), "")
|
||||
}
|
||||
|
||||
private fun String.getIntFromText(): Int? {
|
||||
return Regex("""\d+""").find(this)?.groupValues?.firstOrNull()?.toIntOrNull()
|
||||
}
|
||||
|
||||
private fun Element.toSearchResponse(): SearchResponse? {
|
||||
val url = select("div.Thumb--GridItem a")
|
||||
val posterUrl = select("span.BG--GridItem")?.attr("data-lazy-style")
|
||||
?.getImageURL()
|
||||
val year = select("div.GridItem span.year")?.text()
|
||||
val title = select("div.Thumb--GridItem strong").text()
|
||||
.replace("$year", "")
|
||||
.replace("مشاهدة|فيلم|مسلسل|مترجم".toRegex(), "")
|
||||
.replace("( نسخة مدبلجة )", " ( نسخة مدبلجة ) ")
|
||||
// If you need to differentiate use the url.
|
||||
return MovieSearchResponse(
|
||||
title,
|
||||
url.attr("href"),
|
||||
this@MyCima.name,
|
||||
if(url.attr("title").contains("فيلم")) TvType.Movie else TvType.TvSeries,
|
||||
posterUrl,
|
||||
year?.getIntFromText(),
|
||||
null,
|
||||
)
|
||||
}
|
||||
override val mainPage = mainPageOf(
|
||||
"$mainUrl/movies/top/page/" to "Top Movies",
|
||||
"$mainUrl/movies/page/" to "New Movies",
|
||||
"$mainUrl/movies/recent/page/" to "Recently Added Movies",
|
||||
"$mainUrl/seriestv/top/page/" to "Top Series",
|
||||
"$mainUrl/seriestv/new/page/" to "New Series",
|
||||
)
|
||||
|
||||
override suspend fun getMainPage(page: Int, request : MainPageRequest): HomePageResponse {
|
||||
val doc = app.get(request.data + page).document
|
||||
val list = doc.select("div.Grid--MycimaPosts div.GridItem").mapNotNull { element ->
|
||||
element.toSearchResponse()
|
||||
}
|
||||
return newHomePageResponse(request.name, list)
|
||||
}
|
||||
|
||||
override suspend fun search(query: String): List<SearchResponse> {
|
||||
val q = query.replace(" ", "%20")
|
||||
val result = arrayListOf<SearchResponse>()
|
||||
listOf(
|
||||
"$mainUrl/search/$q",
|
||||
"$mainUrl/search/$q/list/series/",
|
||||
"$mainUrl/search/$q/list/anime/"
|
||||
).apmap { url ->
|
||||
val d = app.get(url).document
|
||||
d.select("div.Grid--MycimaPosts div.GridItem").mapNotNull {
|
||||
if (it.text().contains("اعلان")) return@mapNotNull null
|
||||
it.toSearchResponse()?.let { it1 -> result.add(it1) }
|
||||
}
|
||||
}
|
||||
return result.distinct().sortedBy { it.name }
|
||||
}
|
||||
|
||||
data class MoreEPS(
|
||||
val output: String
|
||||
)
|
||||
|
||||
override suspend fun load(url: String): LoadResponse {
|
||||
val doc = app.get(url).document
|
||||
val isMovie = doc.select("ol li:nth-child(3)").text().contains("افلام")
|
||||
val posterUrl =
|
||||
doc.select("mycima.separated--top")?.attr("data-lazy-style")?.getImageURL()
|
||||
?.ifEmpty { doc.select("meta[itemprop=\"thumbnailUrl\"]")?.attr("content") }
|
||||
?.ifEmpty { doc.select("mycima.separated--top")?.attr("style")?.getImageURL() }
|
||||
val year =
|
||||
doc.select("div.Title--Content--Single-begin h1 a.unline")?.text()?.getIntFromText()
|
||||
val title = doc.select("div.Title--Content--Single-begin h1").text()
|
||||
.replace("($year)", "")
|
||||
.replace("مشاهدة|فيلم|مسلسل|مترجم|انمي".toRegex(), "")
|
||||
// A bit iffy to parse twice like this, but it'll do.
|
||||
val duration =
|
||||
doc.select("ul.Terms--Content--Single-begin li").firstOrNull {
|
||||
it.text().contains("المدة")
|
||||
}?.text()?.getIntFromText()
|
||||
|
||||
val synopsis = doc.select("div.StoryMovieContent").text()
|
||||
.ifEmpty { doc.select("div.PostItemContent").text() }
|
||||
|
||||
val tags = doc.select("li:nth-child(3) > p > a").map { it.text() }
|
||||
|
||||
val actors = doc.select("div.List--Teamwork > ul.Inner--List--Teamwork > li")?.mapNotNull {
|
||||
val name = it?.selectFirst("a > div.ActorName > span")?.text() ?: return@mapNotNull null
|
||||
val image = it.attr("style")
|
||||
?.getImageURL()
|
||||
?: return@mapNotNull null
|
||||
Actor(name, image)
|
||||
}
|
||||
val recommendations =
|
||||
doc.select("div.Grid--MycimaPosts div.GridItem")?.mapNotNull { element ->
|
||||
element.toSearchResponse()
|
||||
}
|
||||
|
||||
return if (isMovie) {
|
||||
newMovieLoadResponse(
|
||||
title,
|
||||
url,
|
||||
TvType.Movie,
|
||||
url
|
||||
) {
|
||||
this.posterUrl = posterUrl
|
||||
this.year = year
|
||||
this.plot = synopsis
|
||||
this.tags = tags
|
||||
this.duration = duration
|
||||
this.recommendations = recommendations
|
||||
addActors(actors)
|
||||
}
|
||||
} else {
|
||||
val episodes = ArrayList<Episode>()
|
||||
val seasons = doc.select("div.List--Seasons--Episodes a").not(".selected").map {
|
||||
it.attr("href")
|
||||
}
|
||||
val moreButton = doc.select("div.MoreEpisodes--Button")
|
||||
val season =
|
||||
doc.select("div.List--Seasons--Episodes a.selected").text().getIntFromText()
|
||||
doc.select("div.Seasons--Episodes div.Episodes--Seasons--Episodes a")
|
||||
.apmap {
|
||||
episodes.add(
|
||||
Episode(
|
||||
it.attr("href"),
|
||||
it.text(),
|
||||
season,
|
||||
it.text().getIntFromText(),
|
||||
)
|
||||
)
|
||||
}
|
||||
if (moreButton.isNotEmpty()) {
|
||||
val n = doc.select("div.Seasons--Episodes div.Episodes--Seasons--Episodes a").size
|
||||
val totals =
|
||||
doc.select("div.Episodes--Seasons--Episodes a").first()!!.text().getIntFromText()
|
||||
val mEPS = arrayListOf(
|
||||
n,
|
||||
n + 40,
|
||||
n + 80,
|
||||
n + 120,
|
||||
n + 160,
|
||||
n + 200,
|
||||
n + 240,
|
||||
n + 280,
|
||||
n + 320,
|
||||
n + 360,
|
||||
n + 400,
|
||||
n + 440,
|
||||
n + 480,
|
||||
n + 520,
|
||||
n + 660,
|
||||
n + 700,
|
||||
n + 740,
|
||||
n + 780,
|
||||
n + 820,
|
||||
n + 860,
|
||||
n + 900,
|
||||
n + 940,
|
||||
n + 980,
|
||||
n + 1020,
|
||||
n + 1060,
|
||||
n + 1100,
|
||||
n + 1140,
|
||||
n + 1180,
|
||||
n + 1220,
|
||||
totals
|
||||
)
|
||||
mEPS.apmap { it ->
|
||||
if (it != null) {
|
||||
if (it > totals!!) return@apmap
|
||||
val ajaxURL =
|
||||
"$mainUrl/AjaxCenter/MoreEpisodes/${moreButton.attr("data-term")}/$it"
|
||||
val jsonResponse = app.get(ajaxURL)
|
||||
val json = parseJson<MoreEPS>(jsonResponse.text)
|
||||
val document = Jsoup.parse(json.output?.replace("""\""", ""))
|
||||
document.select("a").map {
|
||||
episodes.add(
|
||||
Episode(
|
||||
it.attr("href"),
|
||||
it.text(),
|
||||
season,
|
||||
it.text().getIntFromText(),
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (seasons.isNotEmpty()) {
|
||||
seasons.apmap { surl ->
|
||||
if (surl.contains("%d9%85%d8%af%d8%a8%d9%84%d8%ac")) return@apmap
|
||||
val seasonsite = app.get(surl).document
|
||||
val fmoreButton = seasonsite.select("div.MoreEpisodes--Button")
|
||||
val fseason = seasonsite.select("div.List--Seasons--Episodes a.selected").text()
|
||||
.getIntFromText() ?: 1
|
||||
seasonsite.select("div.Seasons--Episodes div.Episodes--Seasons--Episodes a")
|
||||
.map {
|
||||
episodes.add(
|
||||
Episode(
|
||||
it.attr("href"),
|
||||
it.text(),
|
||||
fseason,
|
||||
it.text().getIntFromText(),
|
||||
)
|
||||
)
|
||||
}
|
||||
if (fmoreButton.isNotEmpty()) {
|
||||
val n =
|
||||
seasonsite.select("div.Seasons--Episodes div.Episodes--Seasons--Episodes a").size
|
||||
val totals =
|
||||
seasonsite.select("div.Episodes--Seasons--Episodes a").first()!!.text()
|
||||
.getIntFromText()
|
||||
val mEPS = arrayListOf(
|
||||
n,
|
||||
n + 40,
|
||||
n + 80,
|
||||
n + 120,
|
||||
n + 160,
|
||||
n + 200,
|
||||
n + 240,
|
||||
n + 280,
|
||||
n + 320,
|
||||
n + 360,
|
||||
n + 400,
|
||||
n + 440,
|
||||
n + 480,
|
||||
n + 520,
|
||||
n + 660,
|
||||
n + 700,
|
||||
n + 740,
|
||||
n + 780,
|
||||
n + 820,
|
||||
n + 860,
|
||||
n + 900,
|
||||
n + 940,
|
||||
n + 980,
|
||||
n + 1020,
|
||||
n + 1060,
|
||||
n + 1100,
|
||||
n + 1140,
|
||||
n + 1180,
|
||||
n + 1220,
|
||||
totals
|
||||
)
|
||||
mEPS.apmap { it ->
|
||||
if (it != null) {
|
||||
if (it > totals!!) return@apmap
|
||||
val ajaxURL =
|
||||
"$mainUrl/AjaxCenter/MoreEpisodes/${fmoreButton.attr("data-term")}/$it"
|
||||
val jsonResponse = app.get(ajaxURL)
|
||||
val json = parseJson<MoreEPS>(jsonResponse.text)
|
||||
val document = Jsoup.parse(json.output?.replace("""\""", ""))
|
||||
document.select("a").map {
|
||||
episodes.add(
|
||||
Episode(
|
||||
it.attr("href"),
|
||||
it.text(),
|
||||
fseason,
|
||||
it.text().getIntFromText(),
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else return@apmap
|
||||
}
|
||||
}
|
||||
newTvSeriesLoadResponse(
|
||||
title,
|
||||
url,
|
||||
TvType.TvSeries,
|
||||
episodes.distinct().sortedBy { it.episode }) {
|
||||
this.duration = duration
|
||||
this.posterUrl = posterUrl
|
||||
this.tags = tags
|
||||
this.year = year
|
||||
this.plot = synopsis
|
||||
this.recommendations = recommendations
|
||||
addActors(actors)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun loadLinks(
|
||||
data: String,
|
||||
isCasting: Boolean,
|
||||
subtitleCallback: (SubtitleFile) -> Unit,
|
||||
callback: (ExtractorLink) -> Unit
|
||||
): Boolean {
|
||||
app.get(data).document
|
||||
.select("ul.List--Download--Mycima--Single:nth-child(2) li").map {
|
||||
it.select("a").map { linkElement ->
|
||||
callback.invoke(
|
||||
ExtractorLink(
|
||||
this.name,
|
||||
this.name,
|
||||
linkElement.attr("href"),
|
||||
this.mainUrl,
|
||||
quality = linkElement.select("resolution").text().getIntFromText() ?: 0
|
||||
)
|
||||
)
|
||||
}
|
||||
}.flatten()
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
# Arabic providers repository for CloudStream
|
||||
|
||||
[Download](https://cutt.ly/dirar)
|
||||
|
||||
[Site request](https://github.com/ImZaw/cloudstream-extensions-arabic/issues/8)
|
Binary file not shown.
|
@ -1,14 +0,0 @@
|
|||
version = 6
|
||||
|
||||
cloudstream {
|
||||
description = ""
|
||||
authors = listOf( "ImZaw" )
|
||||
|
||||
language = "ar"
|
||||
|
||||
status = 1
|
||||
|
||||
tvTypes = listOf( "TvSeries" , "Movie" , "Anime" , "AsianDrama" )
|
||||
|
||||
iconUrl = "https://www.google.com/s2/favicons?domain=shahid4u.cc&sz=%size%"
|
||||
}
|
|
@ -1,2 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest package="com.shahid4u"/>
|
|
@ -1,67 +0,0 @@
|
|||
package com.shahid4u
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty
|
||||
import com.lagradost.cloudstream3.app
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
|
||||
import com.lagradost.cloudstream3.utils.ExtractorApi
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.getQualityFromName
|
||||
|
||||
open class JWPlayer : ExtractorApi() {
|
||||
override val name = "JWPlayer"
|
||||
override val mainUrl = "https://www.jwplayer.com"
|
||||
override val requiresReferer = false
|
||||
|
||||
override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink>? {
|
||||
val sources = mutableListOf<ExtractorLink>()
|
||||
with(app.get(url).document) {
|
||||
val data = this.select("script").mapNotNull { script ->
|
||||
if (script.data().contains("sources: [")) {
|
||||
script.data().substringAfter("sources: [")
|
||||
.substringBefore("],").replace("'", "\"")
|
||||
} else if (script.data().contains("otakudesu('")) {
|
||||
script.data().substringAfter("otakudesu('")
|
||||
.substringBefore("');")
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
tryParseJson<List<ResponseSource>>("$data")?.map {
|
||||
sources.add(
|
||||
ExtractorLink(
|
||||
name,
|
||||
name,
|
||||
it.file,
|
||||
referer = url,
|
||||
quality = getQualityFromName(
|
||||
Regex("(\\d{3,4}p)").find(it.file)?.groupValues?.get(
|
||||
1
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
return sources
|
||||
}
|
||||
|
||||
private data class ResponseSource(
|
||||
@JsonProperty("file") val file: String,
|
||||
@JsonProperty("type") val type: String?,
|
||||
@JsonProperty("label") val label: String?
|
||||
)
|
||||
|
||||
}
|
||||
class VidHD : JWPlayer() {
|
||||
override val name = "VidHD"
|
||||
override val mainUrl = "https://vidhd.fun"
|
||||
}
|
||||
class GoStream : JWPlayer() {
|
||||
override val name = "GoStream"
|
||||
override val mainUrl = "https://gostream.pro"
|
||||
}
|
||||
class Vidbom : JWPlayer() {
|
||||
override val name = "Vidbom"
|
||||
override val mainUrl = "https://vidbom.com"
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
package com.shahid4u
|
||||
import com.lagradost.cloudstream3.plugins.CloudstreamPlugin
|
||||
import com.lagradost.cloudstream3.plugins.Plugin
|
||||
import android.content.Context
|
||||
|
||||
@CloudstreamPlugin
|
||||
class Shahid4uPlugin: Plugin() {
|
||||
override fun load(context: Context) {
|
||||
registerMainAPI(Shahid4u())
|
||||
registerExtractorAPI(VidHD())
|
||||
registerExtractorAPI(GoStream())
|
||||
registerExtractorAPI(Vidbom())
|
||||
}
|
||||
}
|
|
@ -1,177 +0,0 @@
|
|||
package com.shahid4u
|
||||
|
||||
|
||||
import com.lagradost.cloudstream3.*
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.loadExtractor
|
||||
import org.jsoup.nodes.Element
|
||||
|
||||
class Shahid4u : MainAPI() {
|
||||
override var lang = "ar"
|
||||
override var mainUrl = "https://shahed4u.vip"
|
||||
override var name = "Shahid4u"
|
||||
override val usesWebView = false
|
||||
override val hasMainPage = true
|
||||
override val supportedTypes =
|
||||
setOf(TvType.TvSeries, TvType.Movie, TvType.Anime, TvType.AsianDrama)
|
||||
|
||||
private fun String.getDomainFromUrl(): String? {
|
||||
return Regex("""^(?:https?:\/\/)?(?:[^@\n]+@)?(?:www\.)?([^:\/\n\?\=]+)""").find(this)?.groupValues?.firstOrNull()
|
||||
}
|
||||
private fun Element.toSearchResponse(): SearchResponse? {
|
||||
val urlElement = select("a.fullClick")
|
||||
val posterUrl =
|
||||
select("a.image img").let { it.attr("data-src").ifEmpty { it.attr("data-image") } }
|
||||
val quality = select("span.quality").text().replace("1080p |-".toRegex(), "")
|
||||
val type =
|
||||
if (select(".category").text().contains("افلام")) TvType.Movie else TvType.TvSeries
|
||||
return MovieSearchResponse(
|
||||
urlElement.attr("title")
|
||||
.replace("برنامج|فيلم|مترجم|اون لاين|مسلسل|مشاهدة|انمي|أنمي".toRegex(), ""),
|
||||
urlElement.attr("href") ?: return null,
|
||||
this@Shahid4u.name,
|
||||
type,
|
||||
posterUrl,
|
||||
null,
|
||||
null,
|
||||
quality = getQualityFromString(quality)
|
||||
)
|
||||
}
|
||||
override val mainPage = mainPageOf(
|
||||
"$mainUrl/movies-3/page/" to "Movies",
|
||||
"$mainUrl/netflix/page/" to "Series & Anime",
|
||||
)
|
||||
|
||||
override suspend fun getMainPage(page: Int, request: MainPageRequest): HomePageResponse {
|
||||
val doc = app.get(request.data + page).document
|
||||
val list = doc.select("div.content-box")
|
||||
.mapNotNull { element ->
|
||||
element.toSearchResponse()
|
||||
}
|
||||
return newHomePageResponse(request.name, list)
|
||||
}
|
||||
|
||||
override suspend fun search(query: String): List<SearchResponse> {
|
||||
val finalResult = arrayListOf<SearchResponse>()
|
||||
listOf(
|
||||
"$mainUrl/?s=$query&category=&type=movie",
|
||||
"$mainUrl/?s=$query&type=series"
|
||||
).apmap { url ->
|
||||
app.get(url).document.select("div.content-box").mapNotNull {
|
||||
finalResult.add(it.toSearchResponse() ?: return@mapNotNull null)
|
||||
}
|
||||
}
|
||||
return finalResult
|
||||
}
|
||||
|
||||
override suspend fun load(url: String): LoadResponse {
|
||||
val doc = app.get(url).document
|
||||
val isMovie =
|
||||
doc.select("ul.half-tags:contains(القسم) li:nth-child(2)").text().contains("افلام")
|
||||
val posterUrl =
|
||||
doc.select("a.poster-image").attr("style").replace(".*url\\(|\\);".toRegex(), "")
|
||||
|
||||
val year = doc.select("ul.half-tags:contains(السنة) li:nth-child(2)").text().toIntOrNull()
|
||||
|
||||
val title =
|
||||
doc.select("div.breadcrumb a:nth-child(3)").text()
|
||||
.replace(
|
||||
"الموسم الأول|برنامج|فيلم|مترجم|اون لاين|مسلسل|مشاهدة|انمي|أنمي|$year".toRegex(),
|
||||
""
|
||||
)
|
||||
|
||||
val tags = doc.select("ul.half-tags:contains(النوع) li").not(":nth-child(1)").map {
|
||||
it.text()
|
||||
}
|
||||
val recommendations =
|
||||
doc.select("div.MediaGrid").first()?.select("div.content-box")?.mapNotNull {
|
||||
it.toSearchResponse()
|
||||
}
|
||||
val synopsis = doc.select("div.post-story:contains(قصة) p").text()
|
||||
|
||||
val rating = doc.select("div.imdbR div span").text().toRatingInt()
|
||||
return if (isMovie) {
|
||||
newMovieLoadResponse(
|
||||
title,
|
||||
url,
|
||||
TvType.Movie,
|
||||
url
|
||||
) {
|
||||
this.posterUrl = posterUrl
|
||||
this.year = year
|
||||
this.plot = synopsis
|
||||
this.tags = tags
|
||||
this.recommendations = recommendations
|
||||
this.rating = rating
|
||||
}
|
||||
} else {
|
||||
val episodes = ArrayList<Episode>()
|
||||
val episodeElement = doc.select("div.MediaGrid")
|
||||
val allEpisodesUrl = doc.select("div.btns:contains(جميع الحلقات) a").attr("href")
|
||||
if(allEpisodesUrl.isNotEmpty()) {
|
||||
app.get(allEpisodesUrl).document.select("div.row > div").let {
|
||||
it.mapIndexedNotNull { index, element ->
|
||||
episodes.add(
|
||||
Episode(
|
||||
element.select("a.fullClick").attr("href"),
|
||||
element.select("a.fullClick").attr("title"),
|
||||
1,
|
||||
it.size - index
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
episodeElement[1].select("div.content-box").apmap {
|
||||
val seasonNumber = it.select("div.number em").text().toIntOrNull()
|
||||
val seasonUrl = it.select("a.fullClick").attr("href")
|
||||
app.get(seasonUrl).document.select(".episode-block").map { episode ->
|
||||
episodes.add(
|
||||
Episode(
|
||||
episode.select("a").attr("href"),
|
||||
episode.select("div.title").text(),
|
||||
seasonNumber,
|
||||
episode.select("div.number em").text().toIntOrNull(),
|
||||
episode.select("div.poster img").attr("data-image")
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
newTvSeriesLoadResponse(
|
||||
title,
|
||||
url,
|
||||
TvType.TvSeries,
|
||||
episodes.distinct().sortedBy { it.episode }) {
|
||||
this.posterUrl = posterUrl
|
||||
this.year = year
|
||||
this.plot = synopsis
|
||||
this.tags = tags
|
||||
this.recommendations = recommendations
|
||||
this.rating = rating
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun loadLinks(
|
||||
data: String,
|
||||
isCasting: Boolean,
|
||||
subtitleCallback: (SubtitleFile) -> Unit,
|
||||
callback: (ExtractorLink) -> Unit
|
||||
): Boolean {
|
||||
val watchUrl = "$data/watch"
|
||||
app.get(watchUrl).document.select(
|
||||
".servers-list li:contains(ok), li:contains(Streamtape), li:contains(DoodStream), li:contains(Uqload), li:contains(Voe), li:contains(VIDBOM), li:contains(Upstream), li:contains(السيرفر الخاص), li:contains(GoStream), li:contains(الخاص 1080p), li:contains(vidbom), li:contains(Vidbom)"
|
||||
).apmap {
|
||||
val id = it.attr("data-id")
|
||||
val i = it.attr("data-i")
|
||||
val sourceUrl = app.post(
|
||||
"${data.getDomainFromUrl()}/wp-content/themes/Shahid4u-WP_HOME/Ajaxat/Single/Server.php",
|
||||
headers = mapOf("referer" to watchUrl, "x-requested-with" to "XMLHttpRequest"),
|
||||
data = mapOf("id" to id, "i" to i)
|
||||
).document.select("iframe").attr("src").replace(" ", "")
|
||||
loadExtractor(sourceUrl, watchUrl, subtitleCallback, callback)
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -1,87 +0,0 @@
|
|||
import com.lagradost.cloudstream3.gradle.CloudstreamExtension
|
||||
import com.android.build.gradle.BaseExtension
|
||||
|
||||
buildscript {
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
// Shitpack repo which contains our tools and dependencies
|
||||
maven("https://jitpack.io")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
classpath("com.android.tools.build:gradle:7.0.4")
|
||||
// Cloudstream gradle plugin which makes everything work and builds plugins
|
||||
classpath("com.github.recloudstream:gradle:master-SNAPSHOT")
|
||||
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.10")
|
||||
}
|
||||
}
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
maven("https://jitpack.io")
|
||||
}
|
||||
}
|
||||
|
||||
fun Project.cloudstream(configuration: CloudstreamExtension.() -> Unit) = extensions.getByName<CloudstreamExtension>("cloudstream").configuration()
|
||||
|
||||
fun Project.android(configuration: BaseExtension.() -> Unit) = extensions.getByName<BaseExtension>("android").configuration()
|
||||
|
||||
subprojects {
|
||||
apply(plugin = "com.android.library")
|
||||
apply(plugin = "kotlin-android")
|
||||
apply(plugin = "com.lagradost.cloudstream3.gradle")
|
||||
|
||||
cloudstream {
|
||||
// when running through github workflow, GITHUB_REPOSITORY should contain current repository name
|
||||
setRepo(System.getenv("GITHUB_REPOSITORY") ?: "user/repo")
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdkVersion(30)
|
||||
|
||||
defaultConfig {
|
||||
minSdk = 21
|
||||
targetSdk = 30
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
targetCompatibility = JavaVersion.VERSION_1_8
|
||||
}
|
||||
|
||||
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
|
||||
kotlinOptions {
|
||||
jvmTarget = "1.8" // Required
|
||||
// Disables some unnecessary features
|
||||
freeCompilerArgs = freeCompilerArgs +
|
||||
"-Xno-call-assertions" +
|
||||
"-Xno-param-assertions" +
|
||||
"-Xno-receiver-assertions"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
val apk by configurations
|
||||
val implementation by configurations
|
||||
|
||||
// Stubs for all Cloudstream classes
|
||||
apk("com.lagradost:cloudstream3:pre-release")
|
||||
|
||||
// these dependencies can include any of those which are added by the app,
|
||||
// but you dont need to include any of them if you dont need them
|
||||
// https://github.com/recloudstream/cloudstream/blob/master/app/build.gradle
|
||||
implementation(kotlin("stdlib")) // adds standard kotlin features, like listOf, mapOf etc
|
||||
implementation("com.github.Blatzar:NiceHttp:0.3.2") // http library
|
||||
implementation("org.jsoup:jsoup:1.13.1") // html parser
|
||||
implementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.13.+")
|
||||
implementation("org.mozilla:rhino:1.7.14")
|
||||
}
|
||||
}
|
||||
|
||||
task<Delete>("clean") {
|
||||
delete(rootProject.buildDir)
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en" style="overflow-x:hidden;">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>All Sites</title>
|
||||
<link rel="stylesheet" href="./css/index.css">
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
|
||||
<script src="./js/all.js" defer></script>
|
||||
</head>
|
||||
<body class="bg-slate-800 text-white m-0 mx-5">
|
||||
<div class="m-0 my-4">
|
||||
<div class="repoInfo p-4 h-20 bg-slate-900 rounded-full my-4 text-center border-black border-2 drop-shadow-lg">
|
||||
<h1 id="title" class="text-xl"></h1>
|
||||
</div>
|
||||
<div class="plugins">
|
||||
<div id="grid" class="grid gap-1 grid-cols-1 sm:grid-cols-4 grid-rows-3 w-10/12 m-auto">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -1,734 +0,0 @@
|
|||
/*
|
||||
! tailwindcss v3.1.8 | MIT License | https://tailwindcss.com
|
||||
*/
|
||||
|
||||
/*
|
||||
1. Prevent padding and border from affecting element width. (https://github.com/mozdevs/cssremedy/issues/4)
|
||||
2. Allow adding a border to an element by just adding a border-width. (https://github.com/tailwindcss/tailwindcss/pull/116)
|
||||
*/
|
||||
|
||||
*,
|
||||
::before,
|
||||
::after {
|
||||
box-sizing: border-box;
|
||||
/* 1 */
|
||||
border-width: 0;
|
||||
/* 2 */
|
||||
border-style: solid;
|
||||
/* 2 */
|
||||
border-color: #e5e7eb;
|
||||
/* 2 */
|
||||
}
|
||||
|
||||
::before,
|
||||
::after {
|
||||
--tw-content: '';
|
||||
}
|
||||
|
||||
/*
|
||||
1. Use a consistent sensible line-height in all browsers.
|
||||
2. Prevent adjustments of font size after orientation changes in iOS.
|
||||
3. Use a more readable tab size.
|
||||
4. Use the user's configured `sans` font-family by default.
|
||||
*/
|
||||
|
||||
html {
|
||||
line-height: 1.5;
|
||||
/* 1 */
|
||||
-webkit-text-size-adjust: 100%;
|
||||
/* 2 */
|
||||
-moz-tab-size: 4;
|
||||
/* 3 */
|
||||
-o-tab-size: 4;
|
||||
tab-size: 4;
|
||||
/* 3 */
|
||||
font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
||||
/* 4 */
|
||||
}
|
||||
|
||||
/*
|
||||
1. Remove the margin in all browsers.
|
||||
2. Inherit line-height from `html` so users can set them as a class directly on the `html` element.
|
||||
*/
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
/* 1 */
|
||||
line-height: inherit;
|
||||
/* 2 */
|
||||
}
|
||||
|
||||
/*
|
||||
1. Add the correct height in Firefox.
|
||||
2. Correct the inheritance of border color in Firefox. (https://bugzilla.mozilla.org/show_bug.cgi?id=190655)
|
||||
3. Ensure horizontal rules are visible by default.
|
||||
*/
|
||||
|
||||
hr {
|
||||
height: 0;
|
||||
/* 1 */
|
||||
color: inherit;
|
||||
/* 2 */
|
||||
border-top-width: 1px;
|
||||
/* 3 */
|
||||
}
|
||||
|
||||
/*
|
||||
Add the correct text decoration in Chrome, Edge, and Safari.
|
||||
*/
|
||||
|
||||
abbr:where([title]) {
|
||||
-webkit-text-decoration: underline dotted;
|
||||
text-decoration: underline dotted;
|
||||
}
|
||||
|
||||
/*
|
||||
Remove the default font size and weight for headings.
|
||||
*/
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
font-size: inherit;
|
||||
font-weight: inherit;
|
||||
}
|
||||
|
||||
/*
|
||||
Reset links to optimize for opt-in styling instead of opt-out.
|
||||
*/
|
||||
|
||||
a {
|
||||
color: inherit;
|
||||
text-decoration: inherit;
|
||||
}
|
||||
|
||||
/*
|
||||
Add the correct font weight in Edge and Safari.
|
||||
*/
|
||||
|
||||
b,
|
||||
strong {
|
||||
font-weight: bolder;
|
||||
}
|
||||
|
||||
/*
|
||||
1. Use the user's configured `mono` font family by default.
|
||||
2. Correct the odd `em` font sizing in all browsers.
|
||||
*/
|
||||
|
||||
code,
|
||||
kbd,
|
||||
samp,
|
||||
pre {
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
||||
/* 1 */
|
||||
font-size: 1em;
|
||||
/* 2 */
|
||||
}
|
||||
|
||||
/*
|
||||
Add the correct font size in all browsers.
|
||||
*/
|
||||
|
||||
small {
|
||||
font-size: 80%;
|
||||
}
|
||||
|
||||
/*
|
||||
Prevent `sub` and `sup` elements from affecting the line height in all browsers.
|
||||
*/
|
||||
|
||||
sub,
|
||||
sup {
|
||||
font-size: 75%;
|
||||
line-height: 0;
|
||||
position: relative;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
sub {
|
||||
bottom: -0.25em;
|
||||
}
|
||||
|
||||
sup {
|
||||
top: -0.5em;
|
||||
}
|
||||
|
||||
/*
|
||||
1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297)
|
||||
2. Correct table border color inheritance in all Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016)
|
||||
3. Remove gaps between table borders by default.
|
||||
*/
|
||||
|
||||
table {
|
||||
text-indent: 0;
|
||||
/* 1 */
|
||||
border-color: inherit;
|
||||
/* 2 */
|
||||
border-collapse: collapse;
|
||||
/* 3 */
|
||||
}
|
||||
|
||||
/*
|
||||
1. Change the font styles in all browsers.
|
||||
2. Remove the margin in Firefox and Safari.
|
||||
3. Remove default padding in all browsers.
|
||||
*/
|
||||
|
||||
button,
|
||||
input,
|
||||
optgroup,
|
||||
select,
|
||||
textarea {
|
||||
font-family: inherit;
|
||||
/* 1 */
|
||||
font-size: 100%;
|
||||
/* 1 */
|
||||
font-weight: inherit;
|
||||
/* 1 */
|
||||
line-height: inherit;
|
||||
/* 1 */
|
||||
color: inherit;
|
||||
/* 1 */
|
||||
margin: 0;
|
||||
/* 2 */
|
||||
padding: 0;
|
||||
/* 3 */
|
||||
}
|
||||
|
||||
/*
|
||||
Remove the inheritance of text transform in Edge and Firefox.
|
||||
*/
|
||||
|
||||
button,
|
||||
select {
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
/*
|
||||
1. Correct the inability to style clickable types in iOS and Safari.
|
||||
2. Remove default button styles.
|
||||
*/
|
||||
|
||||
button,
|
||||
[type='button'],
|
||||
[type='reset'],
|
||||
[type='submit'] {
|
||||
-webkit-appearance: button;
|
||||
/* 1 */
|
||||
background-color: transparent;
|
||||
/* 2 */
|
||||
background-image: none;
|
||||
/* 2 */
|
||||
}
|
||||
|
||||
/*
|
||||
Use the modern Firefox focus style for all focusable elements.
|
||||
*/
|
||||
|
||||
:-moz-focusring {
|
||||
outline: auto;
|
||||
}
|
||||
|
||||
/*
|
||||
Remove the additional `:invalid` styles in Firefox. (https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d494c9be1/layout/style/res/forms.css#L728-L737)
|
||||
*/
|
||||
|
||||
:-moz-ui-invalid {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
/*
|
||||
Add the correct vertical alignment in Chrome and Firefox.
|
||||
*/
|
||||
|
||||
progress {
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
/*
|
||||
Correct the cursor style of increment and decrement buttons in Safari.
|
||||
*/
|
||||
|
||||
::-webkit-inner-spin-button,
|
||||
::-webkit-outer-spin-button {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
/*
|
||||
1. Correct the odd appearance in Chrome and Safari.
|
||||
2. Correct the outline style in Safari.
|
||||
*/
|
||||
|
||||
[type='search'] {
|
||||
-webkit-appearance: textfield;
|
||||
/* 1 */
|
||||
outline-offset: -2px;
|
||||
/* 2 */
|
||||
}
|
||||
|
||||
/*
|
||||
Remove the inner padding in Chrome and Safari on macOS.
|
||||
*/
|
||||
|
||||
::-webkit-search-decoration {
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
|
||||
/*
|
||||
1. Correct the inability to style clickable types in iOS and Safari.
|
||||
2. Change font properties to `inherit` in Safari.
|
||||
*/
|
||||
|
||||
::-webkit-file-upload-button {
|
||||
-webkit-appearance: button;
|
||||
/* 1 */
|
||||
font: inherit;
|
||||
/* 2 */
|
||||
}
|
||||
|
||||
/*
|
||||
Add the correct display in Chrome and Safari.
|
||||
*/
|
||||
|
||||
summary {
|
||||
display: list-item;
|
||||
}
|
||||
|
||||
/*
|
||||
Removes the default spacing and border for appropriate elements.
|
||||
*/
|
||||
|
||||
blockquote,
|
||||
dl,
|
||||
dd,
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6,
|
||||
hr,
|
||||
figure,
|
||||
p,
|
||||
pre {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
fieldset {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
legend {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
ol,
|
||||
ul,
|
||||
menu {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/*
|
||||
Prevent resizing textareas horizontally by default.
|
||||
*/
|
||||
|
||||
textarea {
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
/*
|
||||
1. Reset the default placeholder opacity in Firefox. (https://github.com/tailwindlabs/tailwindcss/issues/3300)
|
||||
2. Set the default placeholder color to the user's configured gray 400 color.
|
||||
*/
|
||||
|
||||
input::-moz-placeholder, textarea::-moz-placeholder {
|
||||
opacity: 1;
|
||||
/* 1 */
|
||||
color: #9ca3af;
|
||||
/* 2 */
|
||||
}
|
||||
|
||||
input::placeholder,
|
||||
textarea::placeholder {
|
||||
opacity: 1;
|
||||
/* 1 */
|
||||
color: #9ca3af;
|
||||
/* 2 */
|
||||
}
|
||||
|
||||
/*
|
||||
Set the default cursor for buttons.
|
||||
*/
|
||||
|
||||
button,
|
||||
[role="button"] {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/*
|
||||
Make sure disabled buttons don't get the pointer cursor.
|
||||
*/
|
||||
|
||||
:disabled {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
/*
|
||||
1. Make replaced elements `display: block` by default. (https://github.com/mozdevs/cssremedy/issues/14)
|
||||
2. Add `vertical-align: middle` to align replaced elements more sensibly by default. (https://github.com/jensimmons/cssremedy/issues/14#issuecomment-634934210)
|
||||
This can trigger a poorly considered lint error in some tools but is included by design.
|
||||
*/
|
||||
|
||||
img,
|
||||
svg,
|
||||
video,
|
||||
canvas,
|
||||
audio,
|
||||
iframe,
|
||||
embed,
|
||||
object {
|
||||
display: block;
|
||||
/* 1 */
|
||||
vertical-align: middle;
|
||||
/* 2 */
|
||||
}
|
||||
|
||||
/*
|
||||
Constrain images and videos to the parent width and preserve their intrinsic aspect ratio. (https://github.com/mozdevs/cssremedy/issues/14)
|
||||
*/
|
||||
|
||||
img,
|
||||
video {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
*, ::before, ::after {
|
||||
--tw-border-spacing-x: 0;
|
||||
--tw-border-spacing-y: 0;
|
||||
--tw-translate-x: 0;
|
||||
--tw-translate-y: 0;
|
||||
--tw-rotate: 0;
|
||||
--tw-skew-x: 0;
|
||||
--tw-skew-y: 0;
|
||||
--tw-scale-x: 1;
|
||||
--tw-scale-y: 1;
|
||||
--tw-pan-x: ;
|
||||
--tw-pan-y: ;
|
||||
--tw-pinch-zoom: ;
|
||||
--tw-scroll-snap-strictness: proximity;
|
||||
--tw-ordinal: ;
|
||||
--tw-slashed-zero: ;
|
||||
--tw-numeric-figure: ;
|
||||
--tw-numeric-spacing: ;
|
||||
--tw-numeric-fraction: ;
|
||||
--tw-ring-inset: ;
|
||||
--tw-ring-offset-width: 0px;
|
||||
--tw-ring-offset-color: #fff;
|
||||
--tw-ring-color: rgb(59 130 246 / 0.5);
|
||||
--tw-ring-offset-shadow: 0 0 #0000;
|
||||
--tw-ring-shadow: 0 0 #0000;
|
||||
--tw-shadow: 0 0 #0000;
|
||||
--tw-shadow-colored: 0 0 #0000;
|
||||
--tw-blur: ;
|
||||
--tw-brightness: ;
|
||||
--tw-contrast: ;
|
||||
--tw-grayscale: ;
|
||||
--tw-hue-rotate: ;
|
||||
--tw-invert: ;
|
||||
--tw-saturate: ;
|
||||
--tw-sepia: ;
|
||||
--tw-drop-shadow: ;
|
||||
--tw-backdrop-blur: ;
|
||||
--tw-backdrop-brightness: ;
|
||||
--tw-backdrop-contrast: ;
|
||||
--tw-backdrop-grayscale: ;
|
||||
--tw-backdrop-hue-rotate: ;
|
||||
--tw-backdrop-invert: ;
|
||||
--tw-backdrop-opacity: ;
|
||||
--tw-backdrop-saturate: ;
|
||||
--tw-backdrop-sepia: ;
|
||||
}
|
||||
|
||||
::-webkit-backdrop {
|
||||
--tw-border-spacing-x: 0;
|
||||
--tw-border-spacing-y: 0;
|
||||
--tw-translate-x: 0;
|
||||
--tw-translate-y: 0;
|
||||
--tw-rotate: 0;
|
||||
--tw-skew-x: 0;
|
||||
--tw-skew-y: 0;
|
||||
--tw-scale-x: 1;
|
||||
--tw-scale-y: 1;
|
||||
--tw-pan-x: ;
|
||||
--tw-pan-y: ;
|
||||
--tw-pinch-zoom: ;
|
||||
--tw-scroll-snap-strictness: proximity;
|
||||
--tw-ordinal: ;
|
||||
--tw-slashed-zero: ;
|
||||
--tw-numeric-figure: ;
|
||||
--tw-numeric-spacing: ;
|
||||
--tw-numeric-fraction: ;
|
||||
--tw-ring-inset: ;
|
||||
--tw-ring-offset-width: 0px;
|
||||
--tw-ring-offset-color: #fff;
|
||||
--tw-ring-color: rgb(59 130 246 / 0.5);
|
||||
--tw-ring-offset-shadow: 0 0 #0000;
|
||||
--tw-ring-shadow: 0 0 #0000;
|
||||
--tw-shadow: 0 0 #0000;
|
||||
--tw-shadow-colored: 0 0 #0000;
|
||||
--tw-blur: ;
|
||||
--tw-brightness: ;
|
||||
--tw-contrast: ;
|
||||
--tw-grayscale: ;
|
||||
--tw-hue-rotate: ;
|
||||
--tw-invert: ;
|
||||
--tw-saturate: ;
|
||||
--tw-sepia: ;
|
||||
--tw-drop-shadow: ;
|
||||
--tw-backdrop-blur: ;
|
||||
--tw-backdrop-brightness: ;
|
||||
--tw-backdrop-contrast: ;
|
||||
--tw-backdrop-grayscale: ;
|
||||
--tw-backdrop-hue-rotate: ;
|
||||
--tw-backdrop-invert: ;
|
||||
--tw-backdrop-opacity: ;
|
||||
--tw-backdrop-saturate: ;
|
||||
--tw-backdrop-sepia: ;
|
||||
}
|
||||
|
||||
::backdrop {
|
||||
--tw-border-spacing-x: 0;
|
||||
--tw-border-spacing-y: 0;
|
||||
--tw-translate-x: 0;
|
||||
--tw-translate-y: 0;
|
||||
--tw-rotate: 0;
|
||||
--tw-skew-x: 0;
|
||||
--tw-skew-y: 0;
|
||||
--tw-scale-x: 1;
|
||||
--tw-scale-y: 1;
|
||||
--tw-pan-x: ;
|
||||
--tw-pan-y: ;
|
||||
--tw-pinch-zoom: ;
|
||||
--tw-scroll-snap-strictness: proximity;
|
||||
--tw-ordinal: ;
|
||||
--tw-slashed-zero: ;
|
||||
--tw-numeric-figure: ;
|
||||
--tw-numeric-spacing: ;
|
||||
--tw-numeric-fraction: ;
|
||||
--tw-ring-inset: ;
|
||||
--tw-ring-offset-width: 0px;
|
||||
--tw-ring-offset-color: #fff;
|
||||
--tw-ring-color: rgb(59 130 246 / 0.5);
|
||||
--tw-ring-offset-shadow: 0 0 #0000;
|
||||
--tw-ring-shadow: 0 0 #0000;
|
||||
--tw-shadow: 0 0 #0000;
|
||||
--tw-shadow-colored: 0 0 #0000;
|
||||
--tw-blur: ;
|
||||
--tw-brightness: ;
|
||||
--tw-contrast: ;
|
||||
--tw-grayscale: ;
|
||||
--tw-hue-rotate: ;
|
||||
--tw-invert: ;
|
||||
--tw-saturate: ;
|
||||
--tw-sepia: ;
|
||||
--tw-drop-shadow: ;
|
||||
--tw-backdrop-blur: ;
|
||||
--tw-backdrop-brightness: ;
|
||||
--tw-backdrop-contrast: ;
|
||||
--tw-backdrop-grayscale: ;
|
||||
--tw-backdrop-hue-rotate: ;
|
||||
--tw-backdrop-invert: ;
|
||||
--tw-backdrop-opacity: ;
|
||||
--tw-backdrop-saturate: ;
|
||||
--tw-backdrop-sepia: ;
|
||||
}
|
||||
|
||||
.relative {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.bottom-6 {
|
||||
bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.m-0 {
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
.m-auto {
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.mx-5 {
|
||||
margin-left: 1.25rem;
|
||||
margin-right: 1.25rem;
|
||||
}
|
||||
|
||||
.my-4 {
|
||||
margin-top: 1rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.block {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.inline-block {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.inline {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.flex {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.grid {
|
||||
display: grid;
|
||||
}
|
||||
|
||||
.h-12 {
|
||||
height: 3rem;
|
||||
}
|
||||
|
||||
.max-h-80 {
|
||||
max-height: 20rem;
|
||||
}
|
||||
|
||||
.w-10\/12 {
|
||||
width: 83.333333%;
|
||||
}
|
||||
|
||||
.w-12 {
|
||||
width: 3rem;
|
||||
}
|
||||
|
||||
.grid-cols-1 {
|
||||
grid-template-columns: repeat(1, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.grid-rows-3 {
|
||||
grid-template-rows: repeat(3, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.flex-col {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.items-center {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.justify-start {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.gap-1 {
|
||||
gap: 0.25rem;
|
||||
}
|
||||
|
||||
.rounded-full {
|
||||
border-radius: 9999px;
|
||||
}
|
||||
|
||||
.rounded {
|
||||
border-radius: 0.25rem;
|
||||
}
|
||||
|
||||
.border-2 {
|
||||
border-width: 2px;
|
||||
}
|
||||
|
||||
.border-black {
|
||||
--tw-border-opacity: 1;
|
||||
border-color: rgb(0 0 0 / var(--tw-border-opacity));
|
||||
}
|
||||
|
||||
.bg-slate-800 {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(30 41 59 / var(--tw-bg-opacity));
|
||||
}
|
||||
|
||||
.bg-slate-900 {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(15 23 42 / var(--tw-bg-opacity));
|
||||
}
|
||||
|
||||
.object-cover {
|
||||
-o-object-fit: cover;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.p-2 {
|
||||
padding: 0.5rem;
|
||||
}
|
||||
|
||||
.p-4 {
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.text-center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.text-xl {
|
||||
font-size: 1.25rem;
|
||||
line-height: 1.75rem;
|
||||
}
|
||||
|
||||
.text-xs {
|
||||
font-size: 0.75rem;
|
||||
line-height: 1rem;
|
||||
}
|
||||
|
||||
.text-sm {
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.25rem;
|
||||
}
|
||||
|
||||
.font-light {
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
.font-medium {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.text-white {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(255 255 255 / var(--tw-text-opacity));
|
||||
}
|
||||
|
||||
.drop-shadow-lg {
|
||||
--tw-drop-shadow: drop-shadow(0 10px 8px rgb(0 0 0 / 0.04)) drop-shadow(0 4px 3px rgb(0 0 0 / 0.1));
|
||||
filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);
|
||||
}
|
||||
|
||||
.drop-shadow-md {
|
||||
--tw-drop-shadow: drop-shadow(0 4px 3px rgb(0 0 0 / 0.07)) drop-shadow(0 2px 2px rgb(0 0 0 / 0.06));
|
||||
filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);
|
||||
}
|
||||
|
||||
@media (min-width: 640px) {
|
||||
.sm\:h-20 {
|
||||
height: 5rem;
|
||||
}
|
||||
|
||||
.sm\:w-20 {
|
||||
width: 5rem;
|
||||
}
|
||||
|
||||
.sm\:grid-cols-4 {
|
||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||
}
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en" style="overflow-x:hidden;">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Cloudstream Extensions</title>
|
||||
<link rel="stylesheet" href="./css/index.css">
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
|
||||
<script src="./js/index.js" defer></script>
|
||||
</head>
|
||||
<body class="bg-slate-800 text-white m-0 mx-5">
|
||||
<div class="m-0 my-4">
|
||||
<div class="repoInfo p-4 h-20 bg-slate-900 rounded-full my-4 text-center border-black border-2 drop-shadow-lg">
|
||||
<h1 id="title" class="text-xl"></h1>
|
||||
</div>
|
||||
<div class="plugins">
|
||||
<div id="grid" class="grid gap-1 grid-cols-1 sm:grid-cols-4 grid-rows-3 w-10/12 m-auto">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -1,60 +0,0 @@
|
|||
var typeTemplate = `<span class="font-light inline-block" style="{{style}}">{{type}}</span>`
|
||||
var template = `
|
||||
<div class="plugin flex justify-start flex-col items-center p-4 bg-slate-900 max-h-80 border-black border-2 rounded drop-shadow-md">
|
||||
<div class="image">
|
||||
<img class="rounded-full h-12 w-12 sm:h-20 sm:w-20 object-cover" src="{{icon_url}}" onerror="this.onerror=null;this.src='https://cdn0.iconfinder.com/data/icons/file-management-system-flat/32/file_managemenr_system_icon_set_flat_style-14-512.png';">
|
||||
<svg class="inline relative bottom-6" height="25" width="25">
|
||||
<circle cx="12.5" cy="12.5" r="10" fill="{{status}}" />
|
||||
</svg>
|
||||
</div>
|
||||
<div class="font-medium text-center break-word">
|
||||
<span><a href="{{url}}">{{name}}</a></span>
|
||||
<span class="font-light text-sm block">Language: {{language}}</span>
|
||||
<span class="font-light text-xs block">Version: {{version}}</span>
|
||||
<span class="font-light text-xs block">Authors: {{authors}}</span>
|
||||
{{types}}
|
||||
<span class="font-light text-sm block">
|
||||
{{description}}
|
||||
</span>
|
||||
</div>
|
||||
</div>`
|
||||
var allList = []
|
||||
$.getJSON( "https://raw.githubusercontent.com/recloudstream/cs-repos/master/repos-db.json",
|
||||
function( data ) {
|
||||
data.forEach(repoUrl => {
|
||||
$.getJSON( repoUrl,
|
||||
function( data ) {
|
||||
data.pluginLists.forEach(pluginUrl => {
|
||||
$.getJSON( pluginUrl,
|
||||
function( data ) {
|
||||
data.forEach(element=> allList.push(element))
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
setTimeout(function(){
|
||||
$("#title").html(`<span style="display:block;"><b>( ${allList.length} Plugins )</b></span>`)
|
||||
allList.forEach(plugin => {
|
||||
var statusColor;
|
||||
var types = plugin.tvTypes?.map(tvType=> {
|
||||
var whatToReturn = typeTemplate.replace("{{type}}", tvType)
|
||||
if(tvType == "NSFW") whatToReturn = whatToReturn.replace("{{style}}", "color: red;font-size: 10px;font-weight: bold;")
|
||||
else whatToReturn = whatToReturn.replace("{{style}}", "font-size: 10px;")
|
||||
return whatToReturn
|
||||
})
|
||||
if(plugin?.status == 0) statusColor = "red"; else if(plugin?.status == 1) statusColor = "green"; else statusColor = "yellow"
|
||||
$(".plugins > #grid").append(
|
||||
template
|
||||
.replace("{{icon_url}}", plugin.iconUrl?.replace("%size%", "128") ?? "https://cdn0.iconfinder.com/data/icons/file-management-system-flat/32/file_managemenr_system_icon_set_flat_style-14-512.png")
|
||||
.replace("{{status}}", statusColor)
|
||||
.replace("{{url}}", plugin?.repositoryUrl)
|
||||
.replace("{{name}}", plugin?.name)
|
||||
.replace("{{language}}", plugin?.language ?? "Not defined")
|
||||
.replace("{{authors}}", plugin.authors?.join(", ") || "Not defined")
|
||||
.replace("{{version}}", plugin?.version)
|
||||
.replace("{{types}}", types?.join("\n") ?? "")
|
||||
.replace("{{description}}", plugin?.description ?? "")
|
||||
)
|
||||
})
|
||||
}, 1000)
|
|
@ -1,56 +0,0 @@
|
|||
var typeTemplate = `<span class="font-light inline-block" style="font-size:10px;">{{type}}</span>`
|
||||
var template = `
|
||||
<div class="plugin flex justify-start flex-col items-center p-4 bg-slate-900 max-h-80 border-black border-2 rounded drop-shadow-md">
|
||||
<div class="image">
|
||||
<img class="rounded-full h-12 w-12 sm:h-20 sm:w-20 object-cover" src="{{icon_url}}" onerror="this.onerror=null;this.src='https://cdn0.iconfinder.com/data/icons/file-management-system-flat/32/file_managemenr_system_icon_set_flat_style-14-512.png';">
|
||||
<svg class="inline relative bottom-6" height="25" width="25">
|
||||
<circle cx="12.5" cy="12.5" r="10" fill="{{status}}" />
|
||||
</svg>
|
||||
</div>
|
||||
<div class="font-medium text-center break-word">
|
||||
<span><a href="{{url}}">{{name}}</a></span>
|
||||
<span class="font-light text-sm block">Language: {{language}}</span>
|
||||
<span class="font-light text-xs block">Version: {{version}}</span>
|
||||
<span class="font-light text-xs block">Authors: {{authors}}</span>
|
||||
{{types}}
|
||||
<span class="font-light text-sm block">
|
||||
{{description}}
|
||||
</span>
|
||||
</div>
|
||||
</div>`
|
||||
|
||||
|
||||
|
||||
var rawRepoUrl = "https://raw.githubusercontent.com/ImZaw/cloudstream-extensions-arabic/builds/repo.json"
|
||||
const urlSearchParams = new URLSearchParams(window.location.search);
|
||||
if(urlSearchParams.get("url")) rawRepoUrl = urlSearchParams.get("url")
|
||||
$.getJSON( rawRepoUrl , function( data ) {
|
||||
var title = data.name
|
||||
data.pluginLists.forEach(url => {
|
||||
$.getJSON( url , function( data ) {
|
||||
$("#title").html(title + ` <span style="display:block;"><b>( ${data.length} Plugins )</b></span>`)
|
||||
data.forEach(plugin => {
|
||||
var statusColor;
|
||||
var types = plugin.tvTypes?.map(tvType=> {
|
||||
var whatToReturn = typeTemplate.replace("{{type}}", tvType)
|
||||
if(tvType == "NSFW") whatToReturn = whatToReturn.replace("{{style}}", "color: red;font-size: 10px;font-weight: bold;")
|
||||
else whatToReturn = whatToReturn.replace("{{style}}", "font-size: 10px;")
|
||||
return whatToReturn
|
||||
})
|
||||
if(plugin?.status == 0) statusColor = "red"; else if(plugin?.status == 1) statusColor = "green"; else statusColor = "yellow"
|
||||
$(".plugins > #grid").append(
|
||||
template
|
||||
.replace("{{icon_url}}", plugin.iconUrl?.replace("%size%", "128") ?? "https://cdn0.iconfinder.com/data/icons/file-management-system-flat/32/file_managemenr_system_icon_set_flat_style-14-512.png")
|
||||
.replace("{{status}}", statusColor)
|
||||
.replace("{{url}}", plugin?.url)
|
||||
.replace("{{name}}", plugin?.name)
|
||||
.replace("{{language}}", plugin?.language)
|
||||
.replace("{{authors}}", plugin.authors?.join(", ") || "Ghost")
|
||||
.replace("{{version}}", plugin?.version)
|
||||
.replace("{{types}}", types?.join("\n") ?? "")
|
||||
.replace("{{description}}", plugin?.description ?? "")
|
||||
)
|
||||
})
|
||||
})
|
||||
});
|
||||
});
|
|
@ -1,19 +0,0 @@
|
|||
# Project-wide Gradle settings.
|
||||
# IDE (e.g. Android Studio) users:
|
||||
# Gradle settings configured through the IDE *will override*
|
||||
# any settings specified in this file.
|
||||
# For more details on how to configure your build environment visit
|
||||
# http://www.gradle.org/docs/current/userguide/build_environment.html
|
||||
# Specifies the JVM arguments used for the daemon process.
|
||||
# The setting is particularly useful for tweaking memory settings.
|
||||
org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
|
||||
# When configured, Gradle will run in incubating parallel mode.
|
||||
# This option should only be used with decoupled projects. More details, visit
|
||||
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
|
||||
# org.gradle.parallel=true
|
||||
# AndroidX package structure to make it clearer which packages are bundled with the
|
||||
# Android operating system, and which are packaged with your app"s APK
|
||||
# https://developer.android.com/topic/libraries/support-library/androidx-rn
|
||||
android.useAndroidX=true
|
||||
# Automatically convert third-party libraries to use AndroidX
|
||||
android.enableJetifier=true
|
Binary file not shown.
|
@ -1,6 +0,0 @@
|
|||
#Sun Feb 20 16:26:11 CET 2022
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip
|
||||
distributionPath=wrapper/dists
|
||||
zipStorePath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
|
@ -1,172 +0,0 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
## Gradle start up script for UN*X
|
||||
##
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
# Resolve links: $0 may be a link
|
||||
PRG="$0"
|
||||
# Need this for relative symlinks.
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG=`dirname "$PRG"`"/$link"
|
||||
fi
|
||||
done
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >/dev/null
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS=""
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
}
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
NONSTOP* )
|
||||
nonstop=true
|
||||
;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD="java"
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
||||
MAX_FD_LIMIT=`ulimit -H -n`
|
||||
if [ $? -eq 0 ] ; then
|
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||
MAX_FD="$MAX_FD_LIMIT"
|
||||
fi
|
||||
ulimit -n $MAX_FD
|
||||
if [ $? -ne 0 ] ; then
|
||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||
fi
|
||||
else
|
||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||
fi
|
||||
fi
|
||||
|
||||
# For Darwin, add options to specify how the application appears in the dock
|
||||
if $darwin; then
|
||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||
fi
|
||||
|
||||
# For Cygwin, switch paths to Windows format before running java
|
||||
if $cygwin ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||
|
||||
# We build the pattern for arguments to be converted via cygpath
|
||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||
SEP=""
|
||||
for dir in $ROOTDIRSRAW ; do
|
||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||
SEP="|"
|
||||
done
|
||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||
# Add a user-defined pattern to the cygpath arguments
|
||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||
fi
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
i=0
|
||||
for arg in "$@" ; do
|
||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||
|
||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||
else
|
||||
eval `echo args$i`="\"$arg\""
|
||||
fi
|
||||
i=$((i+1))
|
||||
done
|
||||
case $i in
|
||||
(0) set -- ;;
|
||||
(1) set -- "$args0" ;;
|
||||
(2) set -- "$args0" "$args1" ;;
|
||||
(3) set -- "$args0" "$args1" "$args2" ;;
|
||||
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Escape application args
|
||||
save () {
|
||||
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||
echo " "
|
||||
}
|
||||
APP_ARGS=$(save "$@")
|
||||
|
||||
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
||||
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
||||
|
||||
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
|
||||
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
|
||||
cd "$(dirname "$0")"
|
||||
fi
|
||||
|
||||
exec "$JAVACMD" "$@"
|
|
@ -1,84 +0,0 @@
|
|||
@if "%DEBUG%" == "" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS=
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:init
|
||||
@rem Get command-line arguments, handling Windows variants
|
||||
|
||||
if not "%OS%" == "Windows_NT" goto win9xME_args
|
||||
|
||||
:win9xME_args
|
||||
@rem Slurp the command line arguments.
|
||||
set CMD_LINE_ARGS=
|
||||
set _SKIP=2
|
||||
|
||||
:win9xME_args_slurp
|
||||
if "x%~1" == "x" goto execute
|
||||
|
||||
set CMD_LINE_ARGS=%*
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
|
@ -0,0 +1,290 @@
|
|||
[
|
||||
{
|
||||
"iconUrl": "https://www.google.com/s2/favicons?domain=akwam.to&sz=%size%",
|
||||
"apiVersion": 1,
|
||||
"repositoryUrl": "https://github.com/ImZaw/cloudstream-extensions-arabic",
|
||||
"fileSize": 13780,
|
||||
"status": 1,
|
||||
"language": "ar",
|
||||
"authors": [
|
||||
"Blatzar"
|
||||
],
|
||||
"tvTypes": [
|
||||
"TvSeries",
|
||||
"Movie",
|
||||
"Anime",
|
||||
"Cartoon"
|
||||
],
|
||||
"version": 1,
|
||||
"internalName": "AkwamProvider",
|
||||
"description": "",
|
||||
"url": "https://raw.githubusercontent.com/ImZaw/cloudstream-extensions-arabic/builds/AkwamProvider.cs3",
|
||||
"name": "AkwamProvider"
|
||||
},
|
||||
{
|
||||
"iconUrl": "https://www.google.com/s2/favicons?domain=anime4up.tv&sz=%size%",
|
||||
"apiVersion": 1,
|
||||
"repositoryUrl": "https://github.com/ImZaw/cloudstream-extensions-arabic",
|
||||
"fileSize": 15389,
|
||||
"status": 1,
|
||||
"language": "ar",
|
||||
"authors": [
|
||||
"ImZaw"
|
||||
],
|
||||
"tvTypes": [
|
||||
"Anime",
|
||||
"AnimeMovie",
|
||||
"Others"
|
||||
],
|
||||
"version": 1,
|
||||
"internalName": "Anime4upPack",
|
||||
"description": "This pack contains Anime4up and Witanime",
|
||||
"url": "https://raw.githubusercontent.com/ImZaw/cloudstream-extensions-arabic/builds/Anime4upPack.cs3",
|
||||
"name": "Anime4upPack"
|
||||
},
|
||||
{
|
||||
"iconUrl": "https://www.google.com/s2/favicons?domain=animeblkom.net&sz=%size%",
|
||||
"apiVersion": 1,
|
||||
"repositoryUrl": "https://github.com/ImZaw/cloudstream-extensions-arabic",
|
||||
"fileSize": 13332,
|
||||
"status": 1,
|
||||
"language": "ar",
|
||||
"authors": [
|
||||
"ImZaw"
|
||||
],
|
||||
"tvTypes": [
|
||||
"Anime",
|
||||
"AnimeMovie",
|
||||
"OVA"
|
||||
],
|
||||
"version": 2,
|
||||
"internalName": "AnimeBlkomProvider",
|
||||
"description": "",
|
||||
"url": "https://raw.githubusercontent.com/ImZaw/cloudstream-extensions-arabic/builds/AnimeBlkomProvider.cs3",
|
||||
"name": "AnimeBlkomProvider"
|
||||
},
|
||||
{
|
||||
"iconUrl": "https://www.google.com/s2/favicons?domain=animeiat.tv&sz=%size%",
|
||||
"apiVersion": 1,
|
||||
"repositoryUrl": "https://github.com/ImZaw/cloudstream-extensions-arabic",
|
||||
"fileSize": 20625,
|
||||
"status": 1,
|
||||
"language": "ar",
|
||||
"authors": [
|
||||
"ImZaw"
|
||||
],
|
||||
"tvTypes": [
|
||||
"Anime"
|
||||
],
|
||||
"version": 2,
|
||||
"internalName": "AnimeiatProvider",
|
||||
"description": "",
|
||||
"url": "https://raw.githubusercontent.com/ImZaw/cloudstream-extensions-arabic/builds/AnimeiatProvider.cs3",
|
||||
"name": "AnimeiatProvider"
|
||||
},
|
||||
{
|
||||
"iconUrl": "https://www.google.com/s2/favicons?domain=arabseed.ink&sz=%size%",
|
||||
"apiVersion": 1,
|
||||
"repositoryUrl": "https://github.com/ImZaw/cloudstream-extensions-arabic",
|
||||
"fileSize": 17171,
|
||||
"status": 1,
|
||||
"language": "ar",
|
||||
"authors": [
|
||||
"ImZaw"
|
||||
],
|
||||
"tvTypes": [
|
||||
"TvSeries",
|
||||
"Movie"
|
||||
],
|
||||
"version": 2,
|
||||
"internalName": "ArabSeedProvider",
|
||||
"description": "",
|
||||
"url": "https://raw.githubusercontent.com/ImZaw/cloudstream-extensions-arabic/builds/ArabSeedProvider.cs3",
|
||||
"name": "ArabSeedProvider"
|
||||
},
|
||||
{
|
||||
"iconUrl": "https://www.google.com/s2/favicons?domain=cimanow.cc&sz=%size%",
|
||||
"apiVersion": 1,
|
||||
"repositoryUrl": "https://github.com/ImZaw/cloudstream-extensions-arabic",
|
||||
"fileSize": 14704,
|
||||
"status": 1,
|
||||
"language": "ar",
|
||||
"authors": [
|
||||
"ImZaw"
|
||||
],
|
||||
"tvTypes": [
|
||||
"TvSeries",
|
||||
"Movie"
|
||||
],
|
||||
"version": 1,
|
||||
"internalName": "CimaNowProvider",
|
||||
"description": "",
|
||||
"url": "https://raw.githubusercontent.com/ImZaw/cloudstream-extensions-arabic/builds/CimaNowProvider.cs3",
|
||||
"name": "CimaNowProvider"
|
||||
},
|
||||
{
|
||||
"iconUrl": "https://www.google.com/s2/favicons?domain=tv.egydead.live&sz=%size%",
|
||||
"apiVersion": 1,
|
||||
"repositoryUrl": "https://github.com/ImZaw/cloudstream-extensions-arabic",
|
||||
"fileSize": 17103,
|
||||
"status": 1,
|
||||
"language": "ar",
|
||||
"authors": [
|
||||
"ImZaw"
|
||||
],
|
||||
"tvTypes": [
|
||||
"TvSeries",
|
||||
"Movie",
|
||||
"Anime"
|
||||
],
|
||||
"version": 2,
|
||||
"internalName": "EgyDeadProvider",
|
||||
"description": "Some LinkBox links are broken idk why",
|
||||
"url": "https://raw.githubusercontent.com/ImZaw/cloudstream-extensions-arabic/builds/EgyDeadProvider.cs3",
|
||||
"name": "EgyDeadProvider"
|
||||
},
|
||||
{
|
||||
"iconUrl": "https://www.google.com/s2/favicons?domain=https://fajer.show&sz=%size%",
|
||||
"apiVersion": 1,
|
||||
"repositoryUrl": "https://github.com/ImZaw/cloudstream-extensions-arabic",
|
||||
"fileSize": 18252,
|
||||
"status": 1,
|
||||
"language": "ar",
|
||||
"authors": [
|
||||
"ImZaw"
|
||||
],
|
||||
"tvTypes": [
|
||||
"TvSeries",
|
||||
"Movie"
|
||||
],
|
||||
"version": 2,
|
||||
"internalName": "FajerShowProvider",
|
||||
"description": "",
|
||||
"url": "https://raw.githubusercontent.com/ImZaw/cloudstream-extensions-arabic/builds/FajerShowProvider.cs3",
|
||||
"name": "FajerShowProvider"
|
||||
},
|
||||
{
|
||||
"iconUrl": "https://www.google.com/s2/favicons?domain=faselhd.io&sz=%size%",
|
||||
"apiVersion": 1,
|
||||
"repositoryUrl": "https://github.com/ImZaw/cloudstream-extensions-arabic",
|
||||
"fileSize": 15953,
|
||||
"status": 1,
|
||||
"language": "ar",
|
||||
"authors": [
|
||||
"ImZaw"
|
||||
],
|
||||
"tvTypes": [
|
||||
"TvSeries",
|
||||
"Movie",
|
||||
"Anime",
|
||||
"AsianDrama"
|
||||
],
|
||||
"version": 6,
|
||||
"internalName": "FaselHDProvider",
|
||||
"description": "",
|
||||
"url": "https://raw.githubusercontent.com/ImZaw/cloudstream-extensions-arabic/builds/FaselHDProvider.cs3",
|
||||
"name": "FaselHDProvider"
|
||||
},
|
||||
{
|
||||
"iconUrl": "https://www.google.com/s2/favicons?domain=www.fushaar.com&sz=%size%",
|
||||
"apiVersion": 1,
|
||||
"repositoryUrl": "https://github.com/ImZaw/cloudstream-extensions-arabic",
|
||||
"fileSize": 11005,
|
||||
"status": 1,
|
||||
"language": "ar",
|
||||
"authors": [
|
||||
"Spoonge"
|
||||
],
|
||||
"tvTypes": [
|
||||
"Movie"
|
||||
],
|
||||
"version": 1,
|
||||
"internalName": "FushaarProvider",
|
||||
"description": "",
|
||||
"url": "https://raw.githubusercontent.com/ImZaw/cloudstream-extensions-arabic/builds/FushaarProvider.cs3",
|
||||
"name": "FushaarProvider"
|
||||
},
|
||||
{
|
||||
"iconUrl": "https://b.gateanime.cam/wp-content/uploads/2020/12/cropped-Favicon-192x192.png",
|
||||
"apiVersion": 1,
|
||||
"repositoryUrl": "https://github.com/ImZaw/cloudstream-extensions-arabic",
|
||||
"fileSize": 11621,
|
||||
"status": 1,
|
||||
"language": "ar",
|
||||
"authors": [
|
||||
"ImZaw"
|
||||
],
|
||||
"tvTypes": [
|
||||
"Anime",
|
||||
"AnimeMovie",
|
||||
"Cartoon"
|
||||
],
|
||||
"version": 3,
|
||||
"internalName": "GateAnimeProvider",
|
||||
"description": "",
|
||||
"url": "https://raw.githubusercontent.com/ImZaw/cloudstream-extensions-arabic/builds/GateAnimeProvider.cs3",
|
||||
"name": "GateAnimeProvider"
|
||||
},
|
||||
{
|
||||
"iconUrl": "https://www.google.com/s2/favicons?domain=movizland.cyou&sz=%size%",
|
||||
"apiVersion": 1,
|
||||
"repositoryUrl": "https://github.com/ImZaw/cloudstream-extensions-arabic",
|
||||
"fileSize": 14977,
|
||||
"status": 1,
|
||||
"language": "ar",
|
||||
"authors": [
|
||||
"Spoonge"
|
||||
],
|
||||
"tvTypes": [
|
||||
"Movie"
|
||||
],
|
||||
"version": 3,
|
||||
"internalName": "MovizlandProvider",
|
||||
"description": "Not recommended for series.",
|
||||
"url": "https://raw.githubusercontent.com/ImZaw/cloudstream-extensions-arabic/builds/MovizlandProvider.cs3",
|
||||
"name": "MovizlandProvider"
|
||||
},
|
||||
{
|
||||
"iconUrl": "https://www.google.com/s2/favicons?domain=mycima.tv&sz=%size%",
|
||||
"apiVersion": 1,
|
||||
"repositoryUrl": "https://github.com/ImZaw/cloudstream-extensions-arabic",
|
||||
"fileSize": 18744,
|
||||
"status": 1,
|
||||
"language": "ar",
|
||||
"authors": [
|
||||
"ImZaw"
|
||||
],
|
||||
"tvTypes": [
|
||||
"TvSeries",
|
||||
"Movie",
|
||||
"Anime"
|
||||
],
|
||||
"version": 3,
|
||||
"internalName": "MyCimaProvider",
|
||||
"description": "",
|
||||
"url": "https://raw.githubusercontent.com/ImZaw/cloudstream-extensions-arabic/builds/MyCimaProvider.cs3",
|
||||
"name": "MyCimaProvider"
|
||||
},
|
||||
{
|
||||
"iconUrl": "https://www.google.com/s2/favicons?domain=shahid4u.cc&sz=%size%",
|
||||
"apiVersion": 1,
|
||||
"repositoryUrl": "https://github.com/ImZaw/cloudstream-extensions-arabic",
|
||||
"fileSize": 19439,
|
||||
"status": 1,
|
||||
"language": "ar",
|
||||
"authors": [
|
||||
"ImZaw"
|
||||
],
|
||||
"tvTypes": [
|
||||
"TvSeries",
|
||||
"Movie",
|
||||
"Anime",
|
||||
"AsianDrama"
|
||||
],
|
||||
"version": 6,
|
||||
"internalName": "Shahid4uProvider",
|
||||
"description": "",
|
||||
"url": "https://raw.githubusercontent.com/ImZaw/cloudstream-extensions-arabic/builds/Shahid4uProvider.cs3",
|
||||
"name": "Shahid4uProvider"
|
||||
}
|
||||
]
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"name": "Arabic providers repository",
|
||||
"description": "Cloudstream Arabic Plugin Repository",
|
||||
"manifestVersion": 1,
|
||||
"pluginLists": [
|
||||
"https://raw.githubusercontent.com/ImZaw/cloudstream-extensions-arabic/builds/plugins.json"
|
||||
]
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
rootProject.name = "CloudstreamExtensionsArabic"
|
||||
|
||||
val disabled = listOf<String>("EgyBestProvider")
|
||||
|
||||
File(rootDir, ".").eachDir { dir ->
|
||||
if (!disabled.contains(dir.name) && File(dir, "build.gradle.kts").exists()) {
|
||||
include(dir.name)
|
||||
}
|
||||
}
|
||||
|
||||
fun File.eachDir(block: (File) -> Unit) {
|
||||
listFiles()?.filter { it.isDirectory }?.forEach { block(it) }
|
||||
}
|
Loading…
Reference in New Issue