diff --git a/MaciptvProvider/src/main/kotlin/com/lagradost/MacIPTVProvider.kt b/MaciptvProvider/src/main/kotlin/com/lagradost/MacIPTVProvider.kt index 3eebcf4..ea5ba81 100644 --- a/MaciptvProvider/src/main/kotlin/com/lagradost/MacIPTVProvider.kt +++ b/MaciptvProvider/src/main/kotlin/com/lagradost/MacIPTVProvider.kt @@ -8,6 +8,78 @@ import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson import com.lagradost.nicehttp.NiceResponse import kotlinx.coroutines.runBlocking import me.xdrop.fuzzywuzzy.FuzzySearch +import com.lagradost.MacIPTVProvider.Companion.toHomePageList + + +fun findKeyWord(str: String): Regex { + val upperSTR = str.uppercase() + val sequence = when (true) { + upperSTR == "EN" -> { + "US|UK" + } + else -> upperSTR + } + return """(?:^|\W+|\s)+($sequence)(?:\s|\W+|${'$'}|\|)+""".toRegex() +} + +fun cleanTitleButKeepNumber(title: String): String { + return title.uppercase().replace("""FHD""", "") + .replace(findKeyWord("VIP"), "") + .replace("""UHD""", "").replace("""HEVC""", "") + .replace("""HDR""", "").replace("""SD""", "").replace("""4K""", "") + .replace("""HD""", "") +} + +fun cleanTitle(title: String): String { + return cleanTitleButKeepNumber(title).replace( + """(\s\d{1,}${'$'}|\s\d{1,}\s)""".toRegex(), + " " + ) +} + +fun getFlag(sequence: String): String { + val FR = findKeyWord("FR|FRANCE|FRENCH") + val US = findKeyWord("US|USA") + val AR = findKeyWord("AR|ARAB|ARABIC|ARABIA") + val UK = findKeyWord("UK") + val flag: String + flag = when (true) { + sequence.uppercase() + .contains(FR) -> "\uD83C\uDDE8\uD83C\uDDF5" + sequence.uppercase() + .contains(US) -> "\uD83C\uDDFA\uD83C\uDDF8" + sequence.uppercase() + .contains(UK) -> "\uD83C\uDDEC\uD83C\uDDE7" + sequence.uppercase() + .contains(AR) -> " نظرة" + else -> "" + } + return flag +} + +data class Channel( + var title: String, + var url: String, + val url_image: String?, + val lang: String?, + var id: String?, + var tv_genre_id: String?, + var ch_id: String?, +) { + fun toSearchResponseHomePage( + provider: MacIPTVProvider, + ): SearchResponse { + val media = this + val groupName = cleanTitle(media.title).replace(provider.rgxcodeCountry, "").trim() + return LiveSearchResponse( + groupName, + "$provider.mainUrl/-${media.id}-", + provider.name, + TvType.Live, + media.url_image, + ) + } +} class MacIPTVProvider(override var lang: String) : MainAPI() { @@ -25,12 +97,6 @@ class MacIPTVProvider(override var lang: String) : MainAPI() { private var firstInitDone = false private var key: String? = "" - companion object { - var companionName: String? = null - var loginMac: String? = null - var overrideUrl: String? = null - } - private fun accountInfoNotGood(url: String, mac: String?): Boolean { return url.uppercase().trim() == "NONE" || url.isBlank() || mac?.uppercase() ?.trim() == "NONE" || mac.isNullOrBlank() @@ -88,7 +154,6 @@ class MacIPTVProvider(override var lang: String) : MainAPI() { } - private fun List.sortByname(query: String?): List { return if (query == null) { // Return list to base state if no query @@ -96,7 +161,7 @@ class MacIPTVProvider(override var lang: String) : MainAPI() { } else { this.sortedBy { - val name = cleanTitle(it.title) + val name = cleanTitle(it.title).replace(rgxcodeCountry, "").trim() -FuzzySearch.ratio(name.lowercase(), query.lowercase()) } } @@ -123,38 +188,18 @@ class MacIPTVProvider(override var lang: String) : MainAPI() { ) ) } - return searchResutls - } data class Root_epg( - @JsonProperty("js") var js: ArrayList = arrayListOf() - ) data class Js_epg( - - /* @JsonProperty("id") var id: String? = null, - @JsonProperty("ch_id") var chId: String? = null, - @JsonProperty("correct") var correct: String? = null, - @JsonProperty("time") var time: String? = null, - @JsonProperty("time_to") var timeTo: String? = null, - @JsonProperty("duration") var duration: Int? = null,*/ @JsonProperty("name") var name: String? = null, @JsonProperty("descr") var descr: String? = null, -/* @JsonProperty("real_id") var realId: String? = null, - @JsonProperty("category") var category: String? = null, - @JsonProperty("director") var director: String? = null, - @JsonProperty("actor") var actor: String? = null, - @JsonProperty("start_timestamp") var startTimestamp: Int? = null, - @JsonProperty("stop_timestamp") var stopTimestamp: Int? = null,*/ @JsonProperty("t_time") var tTime: String? = null, @JsonProperty("t_time_to") var tTimeTo: String? = null, - /* @JsonProperty("mark_memo") var markMemo: Int? = null, - @JsonProperty("mark_archive") var markArchive: Int? = null*/ - ) private fun getEpg(response: String): String { @@ -192,11 +237,11 @@ class MacIPTVProvider(override var lang: String) : MainAPI() { description = getEpg(response.text) link = media.url title = media.title - val a = cleanTitle(title) + val a = cleanTitle(title).replace(rgxcodeCountry, "").trim() posterUrl = media.url_image.toString() var b_new: String arraymediaPlaylist.forEach { channel -> - val b = cleanTitle(channel.title) + val b = cleanTitle(channel.title).replace(rgxcodeCountry, "").trim() b_new = b.take(6) if (channel.id != media.id && a.take(6) .contains(b_new) && media.tv_genre_id == channel.tv_genre_id @@ -230,7 +275,10 @@ class MacIPTVProvider(override var lang: String) : MainAPI() { ) allresultshome.add( LiveSearchResponse( - name = cleanTitleButKeepNumber(channelname), + name = cleanTitleButKeepNumber(channelname).replace( + rgxcodeCountry, + "" + ).trim(), url = streamurl, name, TvType.Live, @@ -380,275 +428,174 @@ class MacIPTVProvider(override var lang: String) : MainAPI() { private val arraymediaPlaylist = ArrayList() - data class Channel( - var title: String, - var url: String, - val url_image: String?, - val lang: String?, - var id: String?, - var tv_genre_id: String?, - var ch_id: String?, - ) data class Cmds( - - // @JsonProperty("id") var id: String? = null, @JsonProperty("ch_id") var chId: String? = null, - /* @JsonProperty("priority") var priority: String? = null, - @JsonProperty("url") var url: String? = null, - @JsonProperty("status") var status: String? = null, - @JsonProperty("use_http_tmp_link") var useHttpTmpLink: String? = null, - @JsonProperty("wowza_tmp_link") var wowzaTmpLink: String? = null, - @JsonProperty("user_agent_filter") var userAgentFilter: String? = null, - @JsonProperty("use_load_balancing") var useLoadBalancing: String? = null, - @JsonProperty("changed") var changed: String? = null, - @JsonProperty("enable_monitoring") var enableMonitoring: String? = null, - @JsonProperty("enable_balancer_monitoring") var enableBalancerMonitoring: String? = null, - @JsonProperty("nginx_secure_link") var nginxSecureLink: String? = null, - @JsonProperty("flussonic_tmp_link") var flussonicTmpLink: String? = null*/ - ) data class Data( - @JsonProperty("id") var id: String? = null, @JsonProperty("name") var name: String? = null, @JsonProperty("number") var number: String? = null, -/* @JsonProperty("censored") var censored: Int? = null, - @JsonProperty("cmd") var cmd: String? = null, - @JsonProperty("cost") var cost: String? = null, - @JsonProperty("count") var count: String? = null, - @JsonProperty("status") var status: Int? = null, - @JsonProperty("hd") var hd: String? = null,*/ @JsonProperty("tv_genre_id") var tvGenreId: String? = null, -/* @JsonProperty("base_ch") var baseCh: String? = null, - @JsonProperty("xmltv_id") var xmltvId: String? = null, - @JsonProperty("service_id") var serviceId: String? = null, - @JsonProperty("bonus_ch") var bonusCh: String? = null, - @JsonProperty("volume_correction") var volumeCorrection: String? = null, - @JsonProperty("mc_cmd") var mcCmd: String? = null, - @JsonProperty("enable_tv_archive") var enableTvArchive: Int? = null, - @JsonProperty("wowza_tmp_link") var wowzaTmpLink: String? = null, - @JsonProperty("wowza_dvr") var wowzaDvr: String? = null, - @JsonProperty("use_http_tmp_link") var useHttpTmpLink: String? = null, - @JsonProperty("monitoring_status") var monitoringStatus: String? = null, - @JsonProperty("enable_monitoring") var enableMonitoring: String? = null, - @JsonProperty("enable_wowza_load_balancing") var enableWowzaLoadBalancing: String? = null, - @JsonProperty("cmd_1") var cmd1: String? = null, - @JsonProperty("cmd_2") var cmd2: String? = null, - @JsonProperty("cmd_3") var cmd3: String? = null,*/ @JsonProperty("logo") var logo: String? = null, - /* @JsonProperty("correct_time") var correctTime: String? = null, - @JsonProperty("nimble_dvr") var nimbleDvr: String? = null, - @JsonProperty("allow_pvr") var allowPvr: Int? = null, - @JsonProperty("allow_local_pvr") var allowLocalPvr: Int? = null, - @JsonProperty("allow_remote_pvr") var allowRemotePvr: Int? = null, - @JsonProperty("modified") var modified: String? = null, - @JsonProperty("allow_local_timeshift") var allowLocalTimeshift: String? = null, - @JsonProperty("nginx_secure_link") var nginxSecureLink: String? = null, - @JsonProperty("tv_archive_duration") var tvArchiveDuration: Int? = null, - @JsonProperty("locked") var locked: Int? = null, - @JsonProperty("lock") var lock: Int? = null, - @JsonProperty("fav") var fav: Int? = null, - @JsonProperty("archive") var archive: Int? = null, - @JsonProperty("genres_str") var genresStr: String? = null, - @JsonProperty("cur_playing") var curPlaying: String? = null, - @JsonProperty("epg") var epg: ArrayList = arrayListOf(), - @JsonProperty("open") var open: Int? = null,*/ @JsonProperty("cmds") var cmds: ArrayList = arrayListOf(), - /* @JsonProperty("use_load_balancing") var useLoadBalancing: Int? = null, - @JsonProperty("pvr") var pvr: Int? = null*/ - ) data class JsKey( - @JsonProperty("token") var token: String? = null - ) data class Getkey( - @JsonProperty("js") var js: JsKey? = JsKey() - ) data class JsInfo( - @JsonProperty("mac") var mac: String? = null, @JsonProperty("phone") var phone: String? = null - ) data class GetExpiration( - @JsonProperty("js") var js: JsInfo? = JsInfo() - ) data class Js( - @JsonProperty("total_items") var totalItems: Int? = null, @JsonProperty("max_page_items") var maxPageItems: Int? = null, - /* @JsonProperty("selected_item") var selectedItem: Int? = null, - @JsonProperty("cur_page") var curPage: Int? = null,*/ @JsonProperty("data") var data: ArrayList = arrayListOf() - ) data class JsonGetGenre( - @JsonProperty("js") var js: ArrayList = arrayListOf() - ) data class Js_category( - @JsonProperty("id") var id: String? = null, @JsonProperty("title") var title: String? = null, - /* @JsonProperty("alias") var alias: String? = null, - @JsonProperty("active_sub") var activeSub: Boolean? = null, - @JsonProperty("censored") var censored: Int? = null*/ - ) data class Root( - @JsonProperty("js") var js: Js? = Js() - ) private var codeCountry = lang - private fun findKeyWord(str: String): Regex { - val upperSTR = str.uppercase() - val sequence = when (true) { - upperSTR == "EN" -> { - "US|UK" - } - else -> upperSTR - } - return """(?:^|\W+|\s)+($sequence)(?:\s|\W+|${'$'}|\|)+""".toRegex() - } - - private fun String.isContainsTargetCountry(): Boolean { - val getLang = lang.uppercase() - var resp = false - when (true) { - getLang == "FR" -> { - arrayListOf("FRENCH", "FRANCE").forEach { - if (this.uppercase().contains(findKeyWord(it))) { - resp = true - } - } - } - getLang == "EN" -> { - arrayListOf("ENGLISH", "USA").forEach { - if (this.uppercase().contains(findKeyWord(it))) { - resp = true - } - } - } - getLang == "AR" -> { - arrayListOf("ARABIC", "ARAB", "ARABIA").forEach { - if (this.uppercase().contains(findKeyWord(it))) { - resp = true - } - } - } - else -> resp = false - } - - - - return resp - } - - private fun cleanTitle(title: String): String { - return title.uppercase().replace("""(\s\d{1,}${'$'}|\s\d{1,}\s)""".toRegex(), " ") - .replace("""FHD""", "") - .replace(findKeyWord("VIP"), "") - .replace("""UHD""", "").replace(rgxcodeCountry, "").replace("""HEVC""", "") - .replace("""HDR""", "").replace("""SD""", "").replace("""4K""", "") - .replace("""HD""", "").replace(rgxcodeCountry, "").trim() - } - - - private fun getFlag(sequence: String): String { - val FR = findKeyWord("FR|FRANCE|FRENCH") - val US = findKeyWord("US|USA") - val AR = findKeyWord("AR|ARAB|ARABIC|ARABIA") - val UK = findKeyWord("UK") - val flag: String - flag = when (true) { - sequence.uppercase() - .contains(FR) -> "\uD83C\uDDE8\uD83C\uDDF5" - sequence.uppercase() - .contains(US) -> "\uD83C\uDDFA\uD83C\uDDF8" - sequence.uppercase() - .contains(UK) -> "\uD83C\uDDEC\uD83C\uDDE7" - sequence.uppercase() - .contains(AR) -> " نظرة" - else -> "" - } - return flag - } val rgxcodeCountry = findKeyWord(codeCountry) override suspend fun getMainPage(page: Int, request: MainPageRequest): HomePageResponse { - val arrayHomepage = arrayListOf() - if (!firstInitDone) { - val headerIPTV = getAuthHeader() - val url_info = - "$mainUrl/portal.php?type=account_info&action=get_main_info&JsHttpRequest=1-xml" - val urlGetGenre = - "$mainUrl/portal.php?type=itv&action=get_genres&JsHttpRequest=1-xml" - val urlGetallchannels = - "$mainUrl/portal.php?type=itv&action=get_all_channels&JsHttpRequest=1-xml" + val headerIPTV = getAuthHeader() + val url_info = + "$mainUrl/portal.php?type=account_info&action=get_main_info&JsHttpRequest=1-xml" + val urlGetGenre = + "$mainUrl/portal.php?type=itv&action=get_genres&JsHttpRequest=1-xml" + val urlGetallchannels = + "$mainUrl/portal.php?type=itv&action=get_all_channels&JsHttpRequest=1-xml" - var reponseGetInfo: NiceResponse? = null - var responseGetgenre: NiceResponse? = null - var responseAllchannels: NiceResponse? = null - listOf( - url_info, - urlGetGenre, - urlGetallchannels - ).apmap { url -> - val response = app.get(url, headers = headerIPTV) - when (true) { - url.contains("action=get_main_info") -> { - reponseGetInfo = response - } - url.contains("action=get_genre") -> { - responseGetgenre = response - } - url.contains("action=get_all_channels") -> { - responseAllchannels = response - } - else -> { - "" - } + var reponseGetInfo: NiceResponse? = null + var responseGetgenre: NiceResponse? = null + var responseAllchannels: NiceResponse? = null + listOf( + url_info, + urlGetGenre, + urlGetallchannels + ).apmap { url -> + val response = app.get(url, headers = headerIPTV) + when (true) { + url.contains("action=get_main_info") -> { + reponseGetInfo = response + } + url.contains("action=get_genre") -> { + responseGetgenre = response + } + url.contains("action=get_all_channels") -> { + responseAllchannels = response + } + else -> { + "" } } - ///////////// GET EXPIRATION - val infoExpirationJson = reponseGetInfo!!.parsed() - val expiration = infoExpirationJson.js?.phone - ////////////////////////// GET ALL GENRES - val responseGetGenretoJSON = responseGetgenre!!.parsed() - ////////////////////////// GET ALL CHANNELS - val responseAllchannelstoJSON = responseAllchannels!!.parsed() - val AllchannelstoJSON = responseAllchannelstoJSON.js!!.data.sortByTitleNumber() + } + ///////////// GET EXPIRATION + val infoExpirationJson = reponseGetInfo!!.parsed() + val expiration = infoExpirationJson.js?.phone.toString() + ////////////////////////// GET ALL GENRES + val responseGetGenretoJSON = responseGetgenre!!.parsed() + ////////////////////////// GET ALL CHANNELS + val responseAllchannelstoJSON = responseAllchannels!!.parsed() + val AllchannelstoJSON = responseAllchannelstoJSON.js!!.data.sortByTitleNumber() + + return HomePageResponse( + HomeResponse( + responseGetGenretoJSON, + AllchannelstoJSON, + expiration, + ).getHomePageLists(this), false + ) + } + + + fun ArrayList.sortByTitleNumber(): ArrayList { + val regxNbr = Regex("""(\s\d{1,}${'$'}|\s\d{1,}\s)""") + return ArrayList(this.sortedBy { + val str = it.name.toString() + regxNbr.find(str)?.groupValues?.get(0)?.trim()?.toInt() ?: 1000 + }) + } + + + private data class HomeResponse( + val genres: JsonGetGenre, + val channels: ArrayList, + val expiration: String, + ) { + fun String.isContainsTargetCountry(provider: MacIPTVProvider): Boolean { + val getLang = provider.lang.uppercase() + var resp = false + when (true) { + getLang == "FR" -> { + arrayListOf("FRENCH", "FRANCE").forEach { + if (this.uppercase().contains(findKeyWord(it))) { + resp = true + } + } + } + getLang == "EN" -> { + arrayListOf("ENGLISH", "USA").forEach { + if (this.uppercase().contains(findKeyWord(it))) { + resp = true + } + } + } + getLang == "AR" -> { + arrayListOf("ARABIC", "ARAB", "ARABIA").forEach { + if (this.uppercase().contains(findKeyWord(it))) { + resp = true + } + } + } + else -> resp = false + } + + + + return resp + } + + + fun getHomePageLists(provider: MacIPTVProvider): ArrayList { + val arrayHomepage = ArrayList() + val rgxcodeCountry = provider.rgxcodeCountry var firstCat = true - responseGetGenretoJSON.js.forEach { js -> + genres.js.forEach { js -> val idGenre = js.id val categoryTitle = js.title.toString() - val arraymedia = ArrayList() + val arraychannel = ArrayList() if (idGenre!!.contains("""\d""".toRegex()) && (categoryTitle.uppercase() .contains(rgxcodeCountry) || - categoryTitle.isContainsTargetCountry() + categoryTitle.isContainsTargetCountry(provider) ) ) { - val itr = AllchannelstoJSON.iterator() + val itr = channels.iterator() while (itr.hasNext()) { val data = itr.next() val genre = data.tvGenreId @@ -661,7 +608,7 @@ class MacIPTVProvider(override var lang: String) : MainAPI() { val link = "http://localhost/ch/$idCH" + "_" val logo = data.logo?.replace("""\""", "") val ch_id = data.cmds[0].chId - arraymedia.add( + arraychannel.add( Channel( name, link, @@ -672,7 +619,7 @@ class MacIPTVProvider(override var lang: String) : MainAPI() { ch_id ) ) - arraymediaPlaylist.add( + provider.arraymediaPlaylist.add( Channel( name, link, @@ -689,75 +636,68 @@ class MacIPTVProvider(override var lang: String) : MainAPI() { } } /***************************************** */ - - val groupMedia = ArrayList() - var b_new: String - var newgroupMedia: Boolean - val home = arraymedia.mapNotNull { media -> - val b = cleanTitle(media.title) - b_new = b.take(6) - newgroupMedia = true - for (nameMedia in groupMedia) { - if (nameMedia.contains(b_new) && media.tv_genre_id == idGenre) { - newgroupMedia = false - break - } - } - groupMedia.contains(b_new) - if (page == 1 && media.tv_genre_id == idGenre && newgroupMedia - ) { - groupMedia.add(b_new) - val groupName = cleanTitle(media.title) - - LiveSearchResponse( - groupName, - "$mainUrl/-${media.id}-", - name, - TvType.Live, - media.url_image, - ) - } else { - null - } - } val flag: String if (categoryTitle.uppercase() - .contains(rgxcodeCountry) || categoryTitle.isContainsTargetCountry() + .contains(rgxcodeCountry) || categoryTitle.isContainsTargetCountry( + provider + ) ) { flag = getFlag(categoryTitle) val nameGenre = if (firstCat) { firstCat = false - "$flag ${cleanTitle(categoryTitle)} \uD83D\uDCFA $name \uD83D\uDCFA (⏳ $expiration)" + "$flag ${ + cleanTitle(categoryTitle).replace(rgxcodeCountry, "").trim() + } \uD83D\uDCFA ${provider.name} \uD83D\uDCFA (⏳ $expiration)" } else { - "$flag ${cleanTitle(categoryTitle)}" + "$flag ${cleanTitle(categoryTitle).replace(rgxcodeCountry, "").trim()}" + } + arrayHomepage.add( + arraychannel.toHomePageList(nameGenre, provider, idGenre) + ) + if (provider.groupMedia.isNotEmpty()) { + provider.groupMedia.clear() } - arrayHomepage.add(HomePageList(nameGenre, home, isHorizontalImages = true)) } } - + return arrayHomepage } - - return HomePageResponse( - arrayHomepage - ) } - private fun cleanTitleButKeepNumber(title: String): String { - return title.uppercase().replace("""FHD""", "") - .replace(findKeyWord("VIP"), "") - .replace("""UHD""", "").replace("""HEVC""", "") - .replace("""HDR""", "").replace("""SD""", "").replace("""4K""", "") - .replace("""HD""", "").replace(rgxcodeCountry, "").trim() - } + var groupMedia = mutableListOf() + + companion object { + var companionName: String? = null + var loginMac: String? = null + var overrideUrl: String? = null + fun List.toHomePageList(name: String, provider: MacIPTVProvider, GenreId: String) = + HomePageList( + name, this.mapNotNull { + + var b_new: String + var newgroupMedia: Boolean + val rgxcodeCountry = provider.rgxcodeCountry + val media = it + val b = cleanTitle(media.title).replace(rgxcodeCountry, "").trim() + b_new = b.take(6) + newgroupMedia = true + for (nameMedia in provider.groupMedia) { + if (nameMedia.contains(b_new) && media.tv_genre_id == GenreId) { + newgroupMedia = false + break + } + } + if (newgroupMedia && media.tv_genre_id == GenreId) { // + provider.groupMedia.add(b_new) + it.toSearchResponseHomePage(provider) + } else { + null + } + }, + isHorizontalImages = true + ) - private fun ArrayList.sortByTitleNumber(): ArrayList { - val regxNbr = Regex("""(\s\d{1,}${'$'}|\s\d{1,}\s)""") - return ArrayList(this.sortedBy { - val str = it.name.toString() - regxNbr.find(str)?.groupValues?.get(0)?.trim()?.toInt() ?: 1000 - }) } } \ No newline at end of file