@ -2,10 +2,8 @@ package eu.kanade.tachiyomi.animeextension.ar.mycima
import android.app.Application
import android.app.Application
import android.content.SharedPreferences
import android.content.SharedPreferences
import android.widget.Toast
import androidx.preference.ListPreference
import androidx.preference.ListPreference
import androidx.preference.PreferenceScreen
import androidx.preference.PreferenceScreen
import eu.kanade.tachiyomi.animeextension.ar.mycima.extractors.GoVadExtractor
import eu.kanade.tachiyomi.animesource.ConfigurableAnimeSource
import eu.kanade.tachiyomi.animesource.ConfigurableAnimeSource
import eu.kanade.tachiyomi.animesource.model.AnimeFilter
import eu.kanade.tachiyomi.animesource.model.AnimeFilter
import eu.kanade.tachiyomi.animesource.model.AnimeFilterList
import eu.kanade.tachiyomi.animesource.model.AnimeFilterList
@ -13,7 +11,10 @@ import eu.kanade.tachiyomi.animesource.model.SAnime
import eu.kanade.tachiyomi.animesource.model.SEpisode
import eu.kanade.tachiyomi.animesource.model.SEpisode
import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.animesource.online.ParsedAnimeHttpSource
import eu.kanade.tachiyomi.animesource.online.ParsedAnimeHttpSource
import eu.kanade.tachiyomi.lib.doodextractor.DoodExtractor
import eu.kanade.tachiyomi.lib.okruextractor.OkruExtractor
import eu.kanade.tachiyomi.lib.uqloadextractor.UqloadExtractor
import eu.kanade.tachiyomi.lib.uqloadextractor.UqloadExtractor
import eu.kanade.tachiyomi.lib.vidbomextractor.VidBomExtractor
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.util.asJsoup
import eu.kanade.tachiyomi.util.asJsoup
import eu.kanade.tachiyomi.util.parallelCatchingFlatMapBlocking
import eu.kanade.tachiyomi.util.parallelCatchingFlatMapBlocking
@ -23,13 +24,14 @@ import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import org.jsoup.nodes.Element
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
import uy.kohesive.injekt.api.get
import java.lang.Exception
class MyCima : ConfigurableAnimeSource , ParsedAnimeHttpSource ( ) {
class MyCima : ConfigurableAnimeSource , ParsedAnimeHttpSource ( ) {
override val name = " MY Cima "
override val name = " MY Cima "
override val baseUrl by lazy { getPrefBaseUrl ( ) }
// TODO: Check frequency of url changes to potentially
// add back overridable baseurl preference
override val baseUrl = " https://wecima.show "
override val lang = " ar "
override val lang = " ar "
@ -39,13 +41,14 @@ class MyCima : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
Injekt . get < Application > ( ) . getSharedPreferences ( " source_ $id " , 0x0000 )
Injekt . get < Application > ( ) . getSharedPreferences ( " source_ $id " , 0x0000 )
}
}
// ============================== p opular ==============================
// ============================== P opular ==============================
override fun popularAnimeSelector ( ) : String =
override fun popularAnimeSelector ( ) : String = " div.Grid--WecimaPosts div.GridItem div.Thumb--GridItem "
" div.Grid--WecimaPosts div.GridItem div.Thumb--GridItem "
override fun popularAnimeNextPageSelector ( ) : String = " ul.page-numbers li a.next "
override fun popularAnimeNextPageSelector ( ) : String = " ul.page-numbers li a.next "
override fun popularAnimeRequest ( page : Int ) : Request = GET ( " $baseUrl /seriestv/top/?page_number= $page " )
override fun popularAnimeRequest ( page : Int ) : Request =
GET ( " $baseUrl /seriestv/top/?page_number= $page " , headers )
override fun popularAnimeFromElement ( element : Element ) : SAnime {
override fun popularAnimeFromElement ( element : Element ) : SAnime {
val anime = SAnime . create ( )
val anime = SAnime . create ( )
@ -59,116 +62,125 @@ class MyCima : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
return anime
return anime
}
}
// ============================== e pisodes ==============================
// ============================== E pisodes ==============================
override fun episodeListSelector ( ) = " div.Episodes--Seasons--Episodes a "
override fun episodeListSelector ( ) = " div.Episodes--Seasons--Episodes a "
private fun seasonsNextPage Selector ( seasonNumber : Int ) = " div.List--Seasons--Episodes > a:nth-child( $seasonNumber ) "
private fun seasonsList Selector ( ) = " div.List--Seasons--Episodes a "
override fun episodeListParse ( response : Response ) : List < SEpisode > {
override fun episodeListParse ( response : Response ) : List < SEpisode > {
val episodes = mutableListOf < SEpisode > ( )
val document = response . asJsoup ( )
return if ( document . select ( episodeListSelector ( ) ) . isNullOrEmpty ( ) ) {
var seasonNumber = 1
val movieSeries =
fun addEpisodes ( document : Document ) {
document . select ( " singlerelated.hasdivider:contains(سلسلة) div.Thumb--GridItem a " )
if ( document . select ( episodeListSelector ( ) ) . isNullOr Empty ( ) ) {
if ( movieSeries . isNot Empty ( ) ) {
if ( ! document . select ( " mycima singlerelated.hasdivider ${popularAnimeSelector()} " ) . isNullOrEmpty ( ) ) {
movieSeries . sortedByDescending {
documen t. select ( " mycima singlerelated.hasdivider ${popularAnimeSelector()} " ) . map { episodes . add ( newEpisodeFromElement ( it , " mSeries " ) ) }
i t. selectFirst ( " .year " ) !! . text ( ) . let ( :: getNumberFromEpsString )
} . map ( :: mSeriesEpisode )
} else {
} else {
episodes . add ( newEpisodeFromElement ( document . selectFirst ( " div.Poster--Single-begin > a " ) !! , " movie " ) )
document . selectFirst ( " div.Poster--Single-begin > a " ) !! . let ( :: movieEpisode )
}
}
} else {
} else {
document . select ( episode ListSelector( ) ) . map { episodes . add ( newEpisodeFromElement ( it ) ) }
val seasonsList = document . select ( seasons ListSelector( ) )
document . selectFirst ( seasonsNextPageSelector ( seasonNumber ) ) ?. let {
if ( seasonsList . isNullOrEmpty ( ) ) {
seasonNumber ++
document . select ( episodeListSelector ( ) ) . map ( :: newEpisodeFromElement )
addEpisodes (
} else {
client . newCall ( GET ( it . attr ( " abs:href " ) , head ers ) ) . execute ( ) . asJsoup ( ) ,
seasonsList . rev ersed ( ) . flatMap { season ->
)
val seNum = season . text ( ) . let ( :: getNumberFromEpsString )
if ( season . hasClass ( " selected " ) ) {
document . select ( episodeListSelector ( ) )
. map { newEpisodeFromElement ( it , seNum ) }
} else {
val seasonDoc =
client . newCall ( GET ( season . absUrl ( " href " ) , headers ) ) . execute ( ) . asJsoup ( )
seasonDoc . select ( episodeListSelector ( ) )
. map { newEpisodeFromElement ( it , seNum ) }
}
}
}
}
}
}
}
addEpisodes ( response . asJsoup ( ) )
return episodes
}
}
private fun new EpisodeFromElement ( element : Element , type : String = " series " ): SEpisode {
private fun movie Episode( element : Element ) : List < SEpisode > =
newEpisodeFromElement ( element , type = " movie " ) . let ( :: listOf )
private fun mSeriesEpisode ( element : Element ) : SEpisode =
newEpisodeFromElement ( element , type = " mSeries " )
private fun newEpisodeFromElement (
element : Element ,
seNum : String = " 1 " ,
type : String = " series " ,
) : SEpisode {
val episode = SEpisode . create ( )
val episode = SEpisode . create ( )
val epNum = getNumberFromEpsStr ing ( element . text ( ) )
episode . setUrlWithoutDoma in(
episode . setUrlWithoutDomain ( if ( type == " mSeries " ) element . select ( " a " ) . attr ( " href " ) else element . attr ( " abs:href " ) )
when ( type ) {
if ( type == " series " ) {
" series " -> element . select ( " a " ) . attr ( " href " )
episode . episode _number = when {
else -> element . absUrl ( " href " )
epNum . isNotEmpty ( ) -> epNum . toFloatOrNull ( ) ?: 1F
} ,
else -> 1F
)
}
}
episode . name = when ( type ) {
episode . name = when ( type ) {
" mov ie" -> " مشاهدة "
" ser ies " -> " الموسم $seNum : ${element.text()} "
" mSeries " -> element . select ( " a " ) . attr ( " title " )
" mSeries " -> element . text ( ) . replace ( " مشاهدة فيلم " , " " ) . substringBefore ( " مترجم " )
else -> element . ownerDocument ( ) !! . select ( " div.List--Seasons--Episodes a.selected " ) . text ( ) + element . text ( )
else -> " مشاهدة "
}
episode . episode _number = when ( type ) {
" series " -> " $seNum . ${element.text().let(::getNumberFromEpsString)} " . toFloat ( )
else -> 1F
}
}
return episode
return episode
}
}
override fun episodeFromElement ( element : Element ) : SEpisode = throw UnsupportedOperationException ( )
override fun episodeFromElement ( element : Element ) : SEpisode =
throw UnsupportedOperationException ( )
private fun getNumberFromEpsString ( epsStr : String ) : String {
private fun getNumberFromEpsString ( epsStr : String ) : String = epsStr . filter { it . isDigit ( ) }
return epsStr . filter { it . isDigit ( ) }
}
// ============================== video urls ==============================
// ============================== Video Links ==============================
override fun videoListParse ( response : Response ) : List < Video > {
override fun videoListParse ( response : Response ) : List < Video > {
val document = response . asJsoup ( )
val document = response . asJsoup ( )
return document . select ( " ul.WatchServersList li btn " ) . parallelCatchingFlatMapBlocking {
return document . select ( videoListSelector ( ) )
val frameURL = it . attr ( " data-url " )
. parallelCatchingFlatMapBlocking ( :: extractVideos )
if ( it . parent ( ) ?. hasClass ( " MyCimaServer " ) == true ) {
val referer = response . request . url . encodedPath
val newHeader = headers . newBuilder ( ) . add ( " referer " , baseUrl + referer ) . build ( )
val iframeResponse = client . newCall ( GET ( frameURL , newHeader ) ) . execute ( ) . asJsoup ( )
videosFromElement ( iframeResponse . selectFirst ( videoListSelector ( ) ) !! )
} else {
extractVideos ( frameURL )
}
}
}
}
private fun extractVideos ( url : String ) : List < Video > {
private val vidBomExtractor by lazy { VidBomExtractor ( client ) }
private val uqloadExtractor by lazy { UqloadExtractor ( client ) }
private val doodExtractor by lazy { DoodExtractor ( client ) }
private val okruExtractor by lazy { OkruExtractor ( client ) }
private fun extractVideos ( element : Element ) : List < Video > {
val iframeUrl = element . selectFirst ( " btn " ) !! . absUrl ( " data-url " )
val newHeader = headers . newBuilder ( ) . add ( " referer " , " $baseUrl / " ) . build ( )
val iframeTxt = element . text ( ) . lowercase ( )
return when {
return when {
GOVAD_REGEX . containsMatchIn ( url ) -> {
element . hasClass ( " MyCimaServer " ) && " /run/ " in iframeUrl -> {
val final Url = GOVAD_REGEX . find ( url ) !! . groupValues [ 0 ]
val mp4 Url = iframeUrl . replace ( " ?Key " , " /?Key " ) + " &auto=true "
val urlHost = GOVAD_REGEX . find ( url ) !! . groupValues [ 1 ]
Video ( mp4Url , " Default (may take a while) " , mp4Url , newHeader ) . let ( :: listOf )
GoVadExtractor ( client ) . videosFromUrl ( " https://www. $finalUrl .html " , urlHost )
}
}
UQLOAD_REGEX . containsMatchIn ( url ) -> {
val finalUrl = UQLOAD_REGEX . find ( url ) !! . groupValues [ 0 ]
" govid " in iframeTxt || " vidbom " in iframeTxt || " vidshare " in iframeTxt -> {
Uqload Extractor( client ) .videosFromUrl ( " https://www. $finalUrl .html " )
vidBom Extractor. videosFromUrl ( iframeUrl , newHeader )
}
}
" dood " in iframeTxt -> {
doodExtractor . videosFromUrl ( iframeUrl )
}
" ok.ru " in iframeTxt -> {
okruExtractor . videosFromUrl ( iframeUrl )
}
" uqload " in iframeTxt -> {
uqloadExtractor . videosFromUrl ( iframeUrl )
}
else -> null
else -> null
} ?: emptyList ( )
} ?: emptyList ( )
}
}
override fun videoListSelector ( ) = " body "
override fun videoListSelector ( ) = " ul.WatchServersList li "
private fun videosFromElement ( element : Element ) : List < Video > {
val videoList = mutableListOf < Video > ( )
val script = element . select ( " script " )
. firstOrNull { it . data ( ) . contains ( " player.qualityselector({ " ) }
if ( script != null ) {
val data = element . data ( ) . substringAfter ( " sources: [ " ) . substringBefore ( " ], " )
val sources = data . split ( " format: ' " ) . drop ( 1 )
for ( source in sources ) {
val src = source . substringAfter ( " src: \" " ) . substringBefore ( " \" " )
val quality = source . substringBefore ( " ' " ) // .substringAfter("format: '")
val video = Video ( src , quality , src )
videoList . add ( video )
}
return videoList
}
val sourceTag = element . ownerDocument ( ) !! . select ( " source " ) . firstOrNull ( ) !!
return listOf ( Video ( sourceTag . attr ( " src " ) , " Default " , sourceTag . attr ( " src " ) ) )
}
override fun List < Video > . sort ( ) : List < Video > {
override fun List < Video > . sort ( ) : List < Video > {
val quality = preferences . getString ( PREF _QUALITY _KEY , PREF _QUALITY _DEFAULT ) !!
val quality = preferences . getString ( " preferred_quality " , " 1080 " ) !!
return sortedWith (
return sortedWith (
compareBy { it . quality . contains ( quality ) } ,
compareBy { it . quality . contains ( quality ) } ,
) . reversed ( )
) . reversed ( )
@ -178,65 +190,50 @@ class MyCima : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
override fun videoUrlParse ( document : Document ) = throw UnsupportedOperationException ( )
override fun videoUrlParse ( document : Document ) = throw UnsupportedOperationException ( )
// ============================== s earch ==============================
// ============================== S earch ==============================
override fun searchAnimeFromElement ( element : Element ) : SAnime = popularAnimeFromElement ( element )
override fun searchAnimeFromElement ( element : Element ) : SAnime {
override fun searchAnimeNextPageSelector ( ) : String = popularAnimeNextPageSelector ( )
val anime = SAnime . create ( )
anime . setUrlWithoutDomain ( element . select ( " a " ) . attr ( " href " ) )
anime . title = element . select ( " a > strong " ) . text ( )
anime . thumbnail _url = element . select ( " a > span.BG--GridItem " ) . attr ( " data-lazy-style " ) . substringAfter ( " -image:url( " ) . substringBefore ( " ); " )
return anime
}
override fun searchAnimeNextPage Selector ( ) : String = " ul.page-numbers li a.next "
override fun searchAnimeSelector ( ) : String = popularAnimeSelector ( )
override fun searchAnimeSelector ( ) : String = " div.Grid--WecimaPosts div.GridItem div.Thumb--GridItem "
override fun searchAnimeRequest ( page : Int , query : String , filters : AnimeFilterList ) : Request {
override fun searchAnimeRequest ( page : Int , query : String , filters : AnimeFilterList ) : Request {
if ( qu ery . isNotBlank ( ) ) {
val filterList = if ( filt ers . isEmpty ( ) ) getFilterList ( ) else filters
( if ( filters . isEmpty ( ) ) getFilterList ( ) else filters ) . forEach { f ilter ->
val sectionFilter = filterList . find { it is SectionFilter } as SectionF ilter
when ( filter ) {
val categoryFilter = filterList . find { it is CategoryFilter } as CategoryFilter
is SearchCategoryList -> {
val genreFilter = filterList . find { it is GenreFilter } as GenreFilter
val catQ = getSearchCategoryList ( ) [ filt er. state ] . query
val url = baseUrl + if ( qu ery . isNotBlank ( ) ) {
val catUrl = " $baseUrl /search/ $query / " + if ( catQ == " page/ " && page == 1 ) " " else " $catQ $page "
" /search/ $query / ${categoryFilter.toUriPart()} $page / "
return GET ( catUrl , headers )
} else if ( sectionFilter . state != 0 ) {
}
" / ${sectionFilter.toUriPart()} /page/ $page / "
else -> { }
}
}
} else {
} else {
( if ( filters . isEmpty ( ) ) getFilterList ( ) else filters ) . forEach { filter ->
" /genre/ ${genreFilter.toUriPart()} / ${categoryFilter.toUriPart()} $page / "
when ( filter ) {
is CategoryList -> {
if ( filter . state > 0 ) {
val catQ = getCategoryList ( ) [ filter . state ] . query
val catUrl = " $baseUrl / $catQ /page/ $page / "
return GET ( catUrl , headers )
}
}
}
return GET ( url , headers )
else -> { }
}
}
throw Exception ( " Choose a Filters " )
}
return GET ( baseUrl , headers )
}
}
// ============================== d etails ==============================
// ============================== D etails ==============================
override fun animeDetailsParse ( document : Document ) : SAnime {
override fun animeDetailsParse ( document : Document ) : SAnime {
val anime = SAnime . create ( )
val anime = SAnime . create ( )
anime . title = when {
anime . title = when {
document . selectFirst ( " li:contains(المسلسل) p " ) != null -> {
document . selectFirst ( " li:contains(المسلسل) p " ) != null -> {
document . select ( " li:contains(المسلسل) p " ) . text ( )
document . select ( " li:contains(المسلسل) p " ) . text ( )
}
}
document . selectFirst ( " singlerelated.hasdivider:contains(سلسلة) a " ) != null -> {
document . selectFirst ( " singlerelated.hasdivider:contains(سلسلة) a " ) !! . text ( )
}
else -> {
else -> {
document . select ( " div.Title--Content--Single-begin > h1 " ) . text ( ) . substringBefore ( " ( " )
document . select ( " div.Title--Content--Single-begin > h1 " ) . text ( )
. substringBefore ( " ( " ) . replace ( " مشاهدة فيلم " , " " ) . substringBefore ( " مترجم " )
}
}
}
}
anime . genre = document . select ( " li:contains(التصنيف) > p > a, li:contains(النوع) > p > a " ) . joinToString ( " , " ) { it . text ( ) }
anime . genre = document . select ( " li:contains(التصنيف) > p > a, li:contains(النوع) > p > a " )
. joinToString ( " , " ) { it . text ( ) }
anime . description = document . select ( " div.AsideContext > div.StoryMovieContent " ) . text ( )
anime . description = document . select ( " div.AsideContext > div.StoryMovieContent " ) . text ( )
anime . author = document . select ( " li:contains(شركات الإنتاج) > p > a " ) . joinToString ( " , " ) { it . text ( ) }
anime . author =
document . select ( " li:contains(شركات الإنتاج) > p > a " ) . joinToString ( " , " ) { it . text ( ) }
// add alternative name to anime description
// add alternative name to anime description
document . select ( " li:contains( بالعربي) > p, li:contains(معروف) > p " ) . text ( ) . let {
document . select ( " li:contains( بالعربي) > p, li:contains(معروف) > p " ) . text ( ) . let {
if ( it . isEmpty ( ) . not ( ) ) {
if ( it . isEmpty ( ) . not ( ) ) {
@ -249,101 +246,111 @@ class MyCima : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
return anime
return anime
}
}
// ============================== l atest ==============================
// ============================== L atest ==============================
override fun latestUpdatesSelector ( ) : String = popularAnimeSelector ( )
override fun latestUpdatesSelector ( ) : String = " div.Grid--WecimaPosts div.GridItem div.Thumb--GridItem "
override fun latestUpdatesNextPage Selector ( ) : String = popularAnimeNextPageSelector ( )
override fun latestUpdatesNextPageSelector ( ) : String = " ul.page-numbers li a.next "
override fun latestUpdatesFromElement ( element : Element ) : SAnime =
popularAnimeFromElement ( element )
override fun latestUpdatesFromElement ( element : Eleme nt) : SAnime {
override fun latestUpdatesRequest ( page : I nt) : Request = GET ( " $baseUrl /page/ $page " , headers )
val anime = SAnime . create ( )
anime . setUrlWithoutDomain ( element . select ( " a " ) . attr ( " href " ) )
anime . title = element . select ( " a > strong " ) . text ( )
anime . thumbnail _url = element . select ( " a > span " ) . attr ( " data-lazy-style " ) . substringAfter ( " -image:url( " ) . substringBefore ( " ); " )
return anime
}
override fun latestUpdatesRequest ( page : Int ) : Request = GET ( " $baseUrl /page/ $page " )
// ============================== filters ==============================
// ============================== Filters ==============================
override fun getFilterList ( ) = AnimeFilterList (
override fun getFilterList ( ) = AnimeFilterList (
AnimeFilter . Header ( " فلترات البحث" ) ,
AnimeFilter . Header ( " هذا القسم يعمل لو كان البحث فارع " ) ,
SearchCategoryList ( searchCategoryNames ) ,
SectionFilter ( ) ,
AnimeFilter . Separator ( ) ,
AnimeFilter . Separator ( ) ,
AnimeFilter . Header ( " ا قسام الموقع (تعمل فقط اذا كان البحث فارغ) " ) ,
AnimeFilter . Header ( " ا لنوع يستخدم فى البحث و التصنيف " ) ,
CategoryList ( categoryNames ) ,
CategoryFilter ( ) ,
AnimeFilter . Separator ( ) ,
AnimeFilter . Header ( " التصنيف يعمل لو كان اقسام الموقع على 'اختر' فقط " ) ,
GenreFilter ( ) ,
)
)
private class Search CategoryList ( categories : Array < String > ) : AnimeFilter . Select < String > ( " بحث عن " , categories )
private class CategoryFilter : PairFilter (
private class CategoryList ( categories : Array < String > ) : AnimeFilter . Select < String > ( " اختر قسم " , categories )
" النوع " ,
private data class CatUnit ( val name : String , val query : String )
arrayOf (
private val searchCategoryNames = getSearchCategoryList ( ) . map {
Pair ( " فيلم " , " page/ " ) ,
it . name
Pair ( " مسلسل " , " list/series/?page_number= " ) ,
} . toTypedArray ( )
Pair ( " انمى " , " list/anime/?page_number= " ) ,
private val categoryNames = getCategoryList ( ) . map {
Pair ( " برنامج " , " list/tv/?page_number= " ) ,
it . name
) ,
} . toTypedArray ( )
private fun getSearchCategoryList ( ) = listOf (
CatUnit ( " فيلم " , " page/ " ) ,
CatUnit ( " مسلسل " , " list/series/?page_number= " ) ,
CatUnit ( " انمى " , " list/anime/?page_number= " ) ,
CatUnit ( " برنامج " , " list/tv/?page_number= " ) ,
)
private fun getCategoryList ( ) = listOf (
CatUnit ( " اختر " , " " ) ,
CatUnit ( " جميع الافلام " , " category/أفلام/ " ) ,
CatUnit ( " افلام اجنبى " , " category/أفلام/10-movies-english-افلام-اجنبي " ) ,
CatUnit ( " افلام عربى " , " category/أفلام/افلام-عربي-arabic-movies " ) ,
CatUnit ( " افلام هندى " , " category/أفلام/افلام-هندي-indian-movies " ) ,
CatUnit ( " افلام تركى " , " category/أفلام/افلام-تركى-turkish-films " ) ,
CatUnit ( " افلام وثائقية " , " category/أفلام/افلام-وثائقية-documentary-films " ) ,
CatUnit ( " افلام انمي " , " category/افلام-كرتون " ) ,
CatUnit ( " سلاسل افلام " , " category/أفلام/10-movies-english-افلام-اجنبي/سلاسل-الافلام-الكاملة-full-pack " ) ,
CatUnit ( " مسلسلات " , " category/مسلسلات " ) ,
CatUnit ( " مسلسلات اجنبى " , " category/مسلسلات/5-series-english-مسلسلات-اجنبي " ) ,
CatUnit ( " مسلسلات عربى " , " category/مسلسلات/5-series-english-مسلسلات-اجنبي " ) ,
CatUnit ( " مسلسلات هندى " , " category/مسلسلات/9-series-indian-مسلسلات-هندية " ) ,
CatUnit ( " مسلسلات اسيوى " , " category/مسلسلات/مسلسلات-اسيوية " ) ,
CatUnit ( " مسلسلات تركى " , " category/مسلسلات/8-مسلسلات-تركية-turkish-series " ) ,
CatUnit ( " مسلسلات وثائقية " , " category/مسلسلات/مسلسلات-وثائقية-documentary-series " ) ,
CatUnit ( " مسلسلات انمي " , " category/مسلسلات-كرتون " ) ,
CatUnit ( " NETFLIX " , " production/netflix " ) ,
CatUnit ( " WARNER BROS " , " production/warner-bros " ) ,
CatUnit ( " LIONSGATE " , " production/lionsgate " ) ,
CatUnit ( " DISNEY " , " production/walt-disney-pictures " ) ,
CatUnit ( " COLUMBIA " , " production/columbia-pictures " ) ,
)
)
// preferred quality settings
private class SectionFilter : PairFilter (
" اقسام الموقع " ,
arrayOf (
Pair ( " اختر " , " " ) ,
Pair ( " جميع الافلام " , " movies " ) ,
Pair ( " افلام اجنبى " , " category/أفلام/10-movies-english-افلام-اجنبي " ) ,
Pair ( " افلام عربى " , " category/أفلام/افلام-عربي-arabic-movies " ) ,
Pair ( " افلام هندى " , " category/أفلام/افلام-هندي-indian-movies " ) ,
Pair ( " افلام تركى " , " category/أفلام/افلام-تركى-turkish-films " ) ,
Pair ( " افلام وثائقية " , " category/أفلام/افلام-وثائقية-documentary-films " ) ,
Pair ( " افلام انمي " , " category/افلام-كرتون " ) ,
Pair (
" سلاسل افلام " ,
" category/أفلام/10-movies-english-افلام-اجنبي/سلاسل-الافلام-الكاملة-full-pack " ,
) ,
Pair ( " مسلسلات " , " seriestv " ) ,
Pair ( " مسلسلات اجنبى " , " category/مسلسلات/5-series-english-مسلسلات-اجنبي " ) ,
Pair ( " مسلسلات عربى " , " category/مسلسلات/5-series-english-مسلسلات-اجنبي " ) ,
Pair ( " مسلسلات هندى " , " category/مسلسلات/9-series-indian-مسلسلات-هندية " ) ,
Pair ( " مسلسلات اسيوى " , " category/مسلسلات/مسلسلات-اسيوية " ) ,
Pair ( " مسلسلات تركى " , " category/مسلسلات/8-مسلسلات-تركية-turkish-series " ) ,
Pair ( " مسلسلات وثائقية " , " category/مسلسلات/مسلسلات-وثائقية-documentary-series " ) ,
Pair ( " مسلسلات انمي " , " category/مسلسلات-كرتون " ) ,
Pair ( " NETFLIX " , " production/netflix " ) ,
Pair ( " WARNER BROS " , " production/warner-bros " ) ,
Pair ( " LIONSGATE " , " production/lionsgate " ) ,
Pair ( " DISNEY " , " production/walt-disney-pictures " ) ,
Pair ( " COLUMBIA " , " production/columbia-pictures " ) ,
) ,
)
private class GenreFilter : PairFilter (
" التصنيف " ,
arrayOf (
Pair ( " اكشن " , " اكشن-action " ) ,
Pair ( " مغامرات " , " مغامرات-adventure " ) ,
Pair ( " خيال علمى " , " خيال-علمى-science-fiction " ) ,
Pair ( " فانتازيا " , " فانتازيا-fantasy " ) ,
Pair ( " كوميديا " , " كوميديا-comedy " ) ,
Pair ( " دراما " , " دراما-drama " ) ,
Pair ( " جريمة " , " جريمة-crime " ) ,
Pair ( " اثارة " , " اثارة-thriller " ) ,
Pair ( " رعب " , " رعب-horror " ) ,
Pair ( " سيرة ذاتية " , " سيرة-ذاتية-biography " ) ,
Pair ( " كرتون " , " كرتون " ) ,
Pair ( " انيميشين " , " انيميشين-anime " ) ,
) ,
)
open class PairFilter ( displayName : String , private val vals : Array < Pair < String , String > > ) :
AnimeFilter . Select < String > ( displayName , vals . map { it . first } . toTypedArray ( ) ) {
fun toUriPart ( ) = vals [ state ] . second
}
// ============================== Settings ==============================
override fun setupPreferenceScreen ( screen : PreferenceScreen ) {
override fun setupPreferenceScreen ( screen : PreferenceScreen ) {
val baseUrlPref = androidx . preference . EditTextPreference ( screen . context ) . apply {
key = PREF _BASE _URL _KEY
title = PREF _BASE _URL _TITLE
summary = getPrefBaseUrl ( )
this . setDefaultValue ( PREF _BASE _URL _DEFAULT )
dialogTitle = PREF _BASE _URL _DIALOG _TITLE
dialogMessage = PREF _BASE _URL _DIALOG _MESSAGE
setOnPreferenceChangeListener { _ , newValue ->
try {
val res = preferences . edit ( ) . putString ( PREF _BASE _URL _KEY , newValue as String ) . commit ( )
Toast . makeText ( screen . context , " Restart Aniyomi to apply changes " , Toast . LENGTH _LONG ) . show ( )
res
} catch ( e : Exception ) {
e . printStackTrace ( )
false
}
}
}
val videoQualityPref = ListPreference ( screen . context ) . apply {
val videoQualityPref = ListPreference ( screen . context ) . apply {
key = PREF _QUALITY _KEY
key = " preferred_quality "
title = PREF _QUALITY _TITLE
title = " Preferred quality "
entries = PREF _QUALITY _ENTRIES
entries = arrayOf (
entryValues = PREF_QUALITY_ENTRIES . map { it . replace ( " p " , " " ) } . toTypedArray ( )
" 1080p " ,
setDefaultValue ( PREF _QUALITY _DEFAULT )
" 720p " ,
" 480p " ,
" 360p " ,
" 240p " ,
" Vidbom " ,
" Vidshare " ,
" Dood " ,
" Default " ,
)
entryValues =
arrayOf ( " 1080 " , " 720 " , " 480 " , " 360 " , " 240 " , " Vidbom " , " Vidshare " , " Dood " , " Default " )
setDefaultValue ( " 1080 " )
summary = " %s "
summary = " %s "
setOnPreferenceChangeListener { _ , newValue ->
setOnPreferenceChangeListener { _ , newValue ->
val selected = newValue as String
val selected = newValue as String
@ -352,26 +359,6 @@ class MyCima : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
preferences . edit ( ) . putString ( key , entry ) . commit ( )
preferences . edit ( ) . putString ( key , entry ) . commit ( )
}
}
}
}
screen . addPreference ( baseUrlPref )
screen . addPreference ( videoQualityPref )
screen . addPreference ( videoQualityPref )
}
}
private fun getPrefBaseUrl ( ) : String = preferences . getString ( PREF _BASE _URL _KEY , PREF _BASE _URL _DEFAULT ) !!
// ============================= Utilities ===================================
companion object {
private const val PREF _QUALITY _KEY = " preferred_quality "
private const val PREF _QUALITY _TITLE = " Preferred quality "
private const val PREF _QUALITY _DEFAULT = " 1080 "
private val PREF _QUALITY _ENTRIES = arrayOf ( " 1080p " , " 720p " , " 480p " , " 360p " , " 240p " )
private const val PREF _BASE _URL _DEFAULT = " https://cdn3.wecima.watch "
private const val PREF _BASE _URL _KEY = " default_domain "
private const val PREF _BASE _URL _TITLE = " Enter default domain "
private const val PREF _BASE _URL _DIALOG _TITLE = " Default domain "
private const val PREF _BASE _URL _DIALOG _MESSAGE = " You can change the site domain from here "
private val GOVAD _REGEX = Regex ( " (v[aie]d[bp][aoe]?m|myvii?d|govad|segavid|v[aei]{1,2}dshar[er]?) \\ .(?:com|net|org|xyz)(?:: \\ d+)?/(?:embed[/-])?([A-Za-z0-9]+) " )
private val UQLOAD _REGEX = Regex ( " (uqload \\ .[ic]om?)/(?:embed-)?([0-9a-zA-Z]+) " )
}
}
}