diff --git a/MaciptvProvider/src/main/kotlin/com/lagradost/MacIPTVProvider.kt b/MaciptvProvider/src/main/kotlin/com/lagradost/MacIPTVProvider.kt index d5b54ad..9f98b72 100644 --- a/MaciptvProvider/src/main/kotlin/com/lagradost/MacIPTVProvider.kt +++ b/MaciptvProvider/src/main/kotlin/com/lagradost/MacIPTVProvider.kt @@ -4,6 +4,8 @@ import com.fasterxml.jackson.annotation.JsonProperty import com.lagradost.cloudstream3.* import okhttp3.Interceptor import com.lagradost.cloudstream3.utils.* +import com.lagradost.cloudstream3.utils.AppUtils.parseJson +import com.lagradost.cloudstream3.utils.AppUtils.toJson import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson import com.lagradost.nicehttp.NiceResponse import kotlinx.coroutines.runBlocking @@ -15,18 +17,16 @@ class MacIPTVProvider(override var lang: String) : MainAPI() { private val defaultmainUrl = "http://ky-iptv.com:25461/portalstb" var defaultname = "ky-iptv |${lang.uppercase()}|" - override var name = "Box Iptv" + var Basename = "Box Iptv" override val hasQuickSearch = false override val hasMainPage = true override val supportedTypes = setOf(TvType.Live) // live - private var firstInitDone = false private var key: String? = "" - - private fun detectNewAccount(): Boolean { - return oldAthMac != loginMac || oldAthUrl != overrideUrl + init { + name = Basename + " |${lang.uppercase()}|" } private fun accountInfoNotGood(url: String, mac: String?): Boolean { @@ -34,6 +34,9 @@ class MacIPTVProvider(override var lang: String) : MainAPI() { ?.trim() == "NONE" || mac.isNullOrBlank() } + /** + Sometimes providers ask a key (token) in the headers + **/ private suspend fun getkey(mac: String) { val adresseMac = if (!mac.contains("mac=")) { "mac=$mac" @@ -53,26 +56,16 @@ class MacIPTVProvider(override var lang: String) : MainAPI() { } - init { - name = (companionName ?: name) + " |${lang.uppercase()}|" - } - private suspend fun getAuthHeader() { - tags = tags ?: "" + tags = tags ?: "" // tags will allow to select more contains if (tags?.uppercase()?.trim() == "NONE" || tags?.isBlank() == true) tags = lang tags = tags?.uppercase() - oldAthMac = loginMac - oldAthUrl = overrideUrl mainUrl = overrideUrl.toString() - headerMac = when (true) { - accountInfoNotGood(mainUrl, loginMac) -> { + headerMac = when { + accountInfoNotGood(mainUrl, loginMac) -> { // do this if mainUrl or mac adresse is blank mainUrl = defaultmainUrl name = defaultname - if (!firstInitDone) { - getkey(defaulmac_adresse) - firstInitDone = true - } - + getkey(defaulmac_adresse) mutableMapOf( "Cookie" to defaulmac_adresse, "User-Agent" to "Mozilla/5.0 (QtEmbedded; U; Linux; C) AppleWebKit/533.3 (KHTML, like Gecko) MAG200 stbapp ver: 2 rev: 250 Safari/533.3", @@ -80,12 +73,8 @@ class MacIPTVProvider(override var lang: String) : MainAPI() { ) } else -> { - name = (companionName ?: name) + " |${lang.uppercase()}|" - if (!firstInitDone) { - getkey(loginMac.toString()) - firstInitDone = true - } - + name = (companionName ?: Basename) + " |${lang.uppercase()}|" + getkey(loginMac.toString()) mutableMapOf( "Cookie" to "mac=$loginMac", "User-Agent" to "Mozilla/5.0 (QtEmbedded; U; Linux; C) AppleWebKit/533.3 (KHTML, like Gecko) MAG200 stbapp ver: 2 rev: 250 Safari/533.3", @@ -93,7 +82,7 @@ class MacIPTVProvider(override var lang: String) : MainAPI() { ) } } - + isNotInit = false } @@ -105,11 +94,7 @@ class MacIPTVProvider(override var lang: String) : MainAPI() { var id: String?, var tv_genre_id: String?, var ch_id: String?, - ) { - fun toStringCode(): String { - return "${this.title}*${this.url}*${this.url_image}*${this.lang}*${this.id}*${this.tv_genre_id}*${this.ch_id}" - } - } + ) private fun List.sortByname(query: String?): List { @@ -126,27 +111,17 @@ class MacIPTVProvider(override var lang: String) : MainAPI() { } - /** - Cherche le site pour un titre spécifique - - La recherche retourne une SearchResponse, qui peut être des classes suivants: AnimeSearchResponse, MovieSearchResponse, TorrentSearchResponse, TvSeriesSearchResponse - Chaque classes nécessite des données différentes, mais a en commun le nom, le poster et l'url - **/ - private val resultsSearchNbr = 50 + private val resultsSearchNbr = 50 // show only the 50 results override suspend fun search(query: String): List { - val searchResutls = ArrayList() - arraymediaPlaylist.sortByname(query).take(resultsSearchNbr).forEach { media -> - searchResutls.add( - LiveSearchResponse( - media.title, - media.toStringCode(), - name, - TvType.Live, - media.url_image, - ) + return arraymediaPlaylist.sortByname(query).take(resultsSearchNbr).map { media -> + LiveSearchResponse( + media.title, + media.toJson(), + name, + TvType.Live, + media.url_image, ) } - return searchResutls } data class Root_epg( @@ -160,7 +135,7 @@ class MacIPTVProvider(override var lang: String) : MainAPI() { @JsonProperty("t_time_to") var tTimeTo: String? = null, ) - private fun getEpg(response: String): String { + private fun getEpg(response: String): String { // get the EPG to have get the schedual val reponseJSON_0 = tryParseJson(response) var description = "" reponseJSON_0?.js?.forEach { epg_i -> @@ -177,16 +152,9 @@ class MacIPTVProvider(override var lang: String) : MainAPI() { return description } - fun String.getDataChannelFromString(): Channel { - val res = this.split("*") - - return Channel(res[0], res[1], res[2], res[3], res[4], res[5], res[6]) - } - override suspend fun load(url: String): LoadResponse { - val allresultshome: MutableList = mutableListOf() - val media = url.replace(mainUrl, "").getDataChannelFromString() + val media = parseJson(url.replace(mainUrl, "")) val epg_url = "$mainUrl/portal.php?type=itv&action=get_short_epg&ch_id=${media.ch_id}&size=10&JsHttpRequest=1-xml" // plot val response = app.get(epg_url, headers = headerMac) @@ -196,41 +164,47 @@ class MacIPTVProvider(override var lang: String) : MainAPI() { val a = cleanTitle(title).replace(rgxcodeCountry, "").trim() val posterUrl = media.url_image.toString() var b_new: String - arraymediaPlaylist.forEach { channel -> - 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 - ) { - val streamurl = channel.toStringCode() - val channelname = channel.title - val posterurl = channel.url_image.toString() - val uppername = channelname.uppercase() - val quality = getQualityFromString( - when (!channelname.isNullOrBlank()) { - uppername.contains(findKeyWord("UHD")) -> { - "UHD" - } - uppername.contains(findKeyWord("HD")) -> { - "HD" - } - uppername.contains(findKeyWord("SD")) -> { - "SD" - } - uppername.contains(findKeyWord("FHD")) -> { - "HD" - } - uppername.contains(findKeyWord("4K")) -> { - "FourK" - } + return LiveStreamLoadResponse( + name = title, + url = link, + apiName = this.name, + dataUrl = link, + posterUrl = posterUrl, + plot = description, + recommendations = arraymediaPlaylist.mapNotNull { channel -> + 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 + ) { + val streamurl = channel.toJson() + val channelname = channel.title + val posterurl = channel.url_image.toString() + val uppername = channelname.uppercase() + val quality = getQualityFromString( + when (!channelname.isBlank()) { + uppername.contains(findKeyWord("UHD")) -> { + "UHD" + } + uppername.contains(findKeyWord("HD")) -> { + "HD" + } + uppername.contains(findKeyWord("SD")) -> { + "SD" + } + uppername.contains(findKeyWord("FHD")) -> { + "HD" + } + uppername.contains(findKeyWord("4K")) -> { + "FourK" + } - else -> { - null + else -> { + null + } } - } - ) - allresultshome.add( + ) LiveSearchResponse( name = cleanTitleButKeepNumber(channelname).replace( rgxcodeCountry, @@ -242,37 +216,12 @@ class MacIPTVProvider(override var lang: String) : MainAPI() { posterUrl = posterurl, quality = quality, ) - ) - - + } else { + null + } } + ) - } - - - - - if (allresultshome.size >= 1) { - val recommendation = allresultshome - return LiveStreamLoadResponse( - name = title, - url = link, - apiName = this.name, - dataUrl = link, - posterUrl = posterUrl, - plot = description, - recommendations = recommendation - ) - } else { - return LiveStreamLoadResponse( - name = title, - url = link, - apiName = this.name, - dataUrl = link, - posterUrl = posterUrl, - plot = description, - ) - } } /** get the channel id */ @@ -350,18 +299,21 @@ class MacIPTVProvider(override var lang: String) : MainAPI() { ) - var lien = link - if (link.contains("extension")) { - val headerlocation = app.get( - link, - allowRedirects = false - ).headers - val redirectlink = headerlocation.get("location") - .toString() - - if (redirectlink != "null") { - lien = redirectlink + val lien = when { + link.contains("extension") -> { + val headerlocation = app.get( + link, + allowRedirects = false + ).headers + val redirectlink = headerlocation.get("location") + .toString() + if (redirectlink != "null") { + redirectlink + } else { + link + } } + else -> link } val isM3u8 = false callback.invoke( @@ -375,7 +327,6 @@ class MacIPTVProvider(override var lang: String) : MainAPI() { headers = head ) ) - return true } @@ -435,26 +386,26 @@ class MacIPTVProvider(override var lang: String) : MainAPI() { private var codeCountry = lang val rgxcodeCountry = findKeyWord(codeCountry) + var isNotInit = true override suspend fun getMainPage(page: Int, request: MainPageRequest): HomePageResponse { - if (!firstInitDone || arraymediaPlaylist.isEmpty() || detectNewAccount()) { - if (detectNewAccount()) firstInitDone = false - getAuthHeader() + if (isNotInit || arraymediaPlaylist.isEmpty()) { + if (isNotInit) getAuthHeader() - var reponseGetInfo: NiceResponse? = null - var responseGetgenre: NiceResponse? = null var responseAllchannels: NiceResponse? = null listOf( "$mainUrl/portal.php?type=account_info&action=get_main_info&JsHttpRequest=1-xml", "$mainUrl/portal.php?type=itv&action=get_genres&JsHttpRequest=1-xml", "$mainUrl/portal.php?type=itv&action=get_all_channels&JsHttpRequest=1-xml", ).apmap { url -> - when (true) { + when { url.contains("action=get_main_info") -> { - reponseGetInfo = app.get(url, headers = headerMac) + expiration = app.get(url, headers = headerMac) + .parsed().js?.phone.toString() // GET EXPIRATION } url.contains("action=get_genre") -> { - responseGetgenre = app.get(url, headers = headerMac) + responseGetGenretoJSON = app.get(url, headers = headerMac) + .parsed().js // GET ALL GENRES } url.contains("action=get_all_channels") -> { responseAllchannels = app.get(url, headers = headerMac) @@ -465,18 +416,9 @@ class MacIPTVProvider(override var lang: String) : MainAPI() { } } - ///////////// GET EXPIRATION - val infoExpirationJson = reponseGetInfo!!.parsed() - expiration = infoExpirationJson.js?.phone.toString() - ////////////////////////// GET ALL GENRES - responseGetGenretoJSON = responseGetgenre!!.parsed().js - ////////////////////////// GET ALL CHANNELS - val responseAllchannelstoJSON = responseAllchannels!!.parsed() //parsedSafe - val AllchannelstoJSON = responseAllchannelstoJSON.js!!.data.sortByTitleNumber() - return HomePageResponse( HomeResponse( - AllchannelstoJSON, + responseAllchannels!!.parsed().js!!.data.sortByTitleNumber(),// GET ALL CHANNELS and Sort byTitle ).getHomePageListsInit(this), false ) } else { @@ -497,154 +439,122 @@ class MacIPTVProvider(override var lang: String) : MainAPI() { private data class HomeResponse( - val channels: ArrayList = ArrayList(), + val channels: MutableList = ArrayList(), ) { 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 + val langs = hashMapOf( + "FR" to arrayListOf("FRENCH", "FRANCE"), + "EN" to arrayListOf("ENGLISH", "USA"), + "AR" to arrayListOf("ARABIC", "ARAB", "ARABIA") + ) + return langs[getLang]?.any { this.uppercase().contains(findKeyWord(it)) } ?: false } fun getHomePageListsInit(provider: MacIPTVProvider): List { - val arrayHomepage = mutableListOf() val rgxcodeCountry = provider.rgxcodeCountry var firstCat = true - if (responseGetGenretoJSON.isNotEmpty() && channels.isNotEmpty()) { - responseGetGenretoJSON.forEach { js -> - val idGenre = js.id - val categoryTitle = js.title.toString() - val arraychannel = ArrayList() - if (idGenre!!.contains("""\d""".toRegex()) && (categoryTitle.uppercase() - .contains(rgxcodeCountry) || - categoryTitle.isContainsTargetCountry(provider) - ) || categoryTitle.uppercase() - .contains(findKeyWord(tags.toString())) - ) { - val itr = channels.iterator() - while (itr.hasNext()) { - val data = itr.next() - val genre = data.tvGenreId - if (genre != null) { - if (genre == idGenre) { - itr.remove() - val name = data.name.toString() - val tv_genre_id = data.tvGenreId - val idCH = data.id - val link = "http://localhost/ch/$idCH" + "_" - val logo = data.logo?.replace("""\""", "") - val ch_id = data.cmds[0].chId - arraychannel.add( - Channel( - name, - link, - logo, - "", - idCH, - tv_genre_id, - ch_id - ) + return responseGetGenretoJSON.mapNotNull { js -> + val idGenre = js.id.toString() + val categoryTitle = js.title.toString() + val arraychannel = mutableListOf() + if (channels.isNotEmpty() && idGenre.contains("""\d""".toRegex()) && (categoryTitle.uppercase() + .contains(rgxcodeCountry) || + categoryTitle.isContainsTargetCountry(provider) + ) || categoryTitle.uppercase() + .contains(findKeyWord(tags.toString())) + ) { + val itr = channels.iterator() + while (itr.hasNext()) { + val data = itr.next() + val genre = data.tvGenreId + if (genre != null) { + if (genre == idGenre) { + itr.remove() + val name = data.name.toString() + val tv_genre_id = data.tvGenreId + val idCH = data.id + val link = "http://localhost/ch/$idCH" + "_" + val logo = data.logo?.replace("""\""", "") + val ch_id = data.cmds[0].chId + arraychannel.add( + Channel( + name, + link, + logo, + "", + idCH, + tv_genre_id, + ch_id ) - provider.arraymediaPlaylist.add( - Channel( - name, - link, - logo, - "", - idCH, - tv_genre_id, - ch_id - ) + ) + provider.arraymediaPlaylist.add( + Channel( + name, + link, + logo, + "", + idCH, + tv_genre_id, + ch_id ) - } + ) } } } - /***************************************** */ - val flag: String - if (categoryTitle.uppercase() - .contains(rgxcodeCountry) || categoryTitle.isContainsTargetCountry( - provider - ) || categoryTitle.uppercase() - .contains(findKeyWord(tags.toString())) - ) { - flag = getFlag(categoryTitle) - val nameGenre = if (firstCat) { - firstCat = false - "$flag ${ - cleanTitle(categoryTitle).replace(rgxcodeCountry, "").trim() - } \uD83D\uDCFA ${provider.name} \uD83D\uDCFA (⏳ $expiration)" - } else { - "$flag ${cleanTitle(categoryTitle).replace(rgxcodeCountry, "").trim()}" - } - arrayHomepage.add( - arraychannel.toHomePageList(nameGenre, provider, idGenre) - ) + + val flag = getFlag(categoryTitle) + val nameGenre = if (firstCat) { + firstCat = false + "$flag ${ + cleanTitle(categoryTitle).replace(rgxcodeCountry, "").trim() + } \uD83D\uDCFA ${provider.name} \uD83D\uDCFA (⏳ $expiration)" + } else { + "$flag ${cleanTitle(categoryTitle).replace(rgxcodeCountry, "").trim()}" } + + arraychannel.toHomePageList(nameGenre, provider, idGenre) + + } else { + null } } - - return arrayHomepage } fun getHomePageListsFromArrayChannel(provider: MacIPTVProvider): List { - val arrayHomepage = mutableListOf() val rgxcodeCountry = provider.rgxcodeCountry var firstCat = true - val mychannels = ArrayList(provider.arraymediaPlaylist) - if (responseGetGenretoJSON.isNotEmpty() && provider.arraymediaPlaylist.isNotEmpty()) { - responseGetGenretoJSON.forEach { js -> - val idGenre = js.id.toString() - val categoryTitle = js.title.toString() - - /***************************************** */ - val flag: String - if (categoryTitle.uppercase() - .contains(rgxcodeCountry) || categoryTitle.isContainsTargetCountry( - provider - ) - ) { - flag = getFlag(categoryTitle) - val nameGenre = if (firstCat) { - firstCat = false - "$flag ${ - cleanTitle(categoryTitle).replace(rgxcodeCountry, "").trim() - } \uD83D\uDCFA ${provider.name} \uD83D\uDCFA (⏳ $expiration)" - } else { - "$flag ${cleanTitle(categoryTitle).replace(rgxcodeCountry, "").trim()}" - } - arrayHomepage.add( - mychannels.toHomePageList(nameGenre, provider, idGenre) - ) + val arrayChannel = provider.arraymediaPlaylist.toMutableList() + return responseGetGenretoJSON.mapNotNull { js -> + val idGenre = js.id.toString() + val categoryTitle = js.title.toString() + val flag: String + if (categoryTitle.uppercase() + .contains(rgxcodeCountry) || categoryTitle.isContainsTargetCountry( + provider + ) + ) { + flag = getFlag(categoryTitle) + val nameGenre = if (firstCat) { + firstCat = false + "$flag ${ + cleanTitle(categoryTitle).replace(rgxcodeCountry, "").trim() + } \uD83D\uDCFA ${provider.name} \uD83D\uDCFA (⏳ $expiration)" + } else { + "$flag ${ + cleanTitle(categoryTitle).replace(rgxcodeCountry, "").trim() + }" } + arrayChannel.toHomePageList( + nameGenre, + provider, + idGenre + ) + } else { + null } } - - return arrayHomepage } } @@ -654,8 +564,6 @@ class MacIPTVProvider(override var lang: String) : MainAPI() { var loginMac: String? = null var overrideUrl: String? = null var tags: String? = null - private var oldAthMac: String? = null - private var oldAthUrl: String? = null private var headerMac = mutableMapOf() var expiration: String? = null var responseGetGenretoJSON = ArrayList() // all genres from the provider @@ -683,8 +591,7 @@ class MacIPTVProvider(override var lang: String) : MainAPI() { val US = findKeyWord("US|USA") val AR = findKeyWord("AR|ARAB|ARABIC|ARABIA") val UK = findKeyWord("UK") - val flag: String - flag = when (true) { + return when { sequence.uppercase() .contains(FR) -> "\uD83C\uDDE8\uD83C\uDDF5" sequence.uppercase() @@ -695,7 +602,7 @@ class MacIPTVProvider(override var lang: String) : MainAPI() { .contains(AR) -> " نظرة" else -> "" } - return flag + } fun cleanTitle(title: String): String { @@ -705,7 +612,7 @@ class MacIPTVProvider(override var lang: String) : MainAPI() { ) } - fun ArrayList.toSearchResponseHomePage( + fun MutableList.toSearchResponseHomePage( provider: MacIPTVProvider, GenreId: String ): List { val groupChannel = ArrayList() @@ -732,7 +639,7 @@ class MacIPTVProvider(override var lang: String) : MainAPI() { home.add( LiveSearchResponse( groupName, - "${provider.mainUrl}${media.toStringCode()}", + "${provider.mainUrl}${media.toJson()}", provider.name, TvType.Live, media.url_image, @@ -746,7 +653,7 @@ class MacIPTVProvider(override var lang: String) : MainAPI() { return home } - fun ArrayList.toHomePageList( + fun MutableList.toHomePageList( name: String, provider: MacIPTVProvider, GenreId: String diff --git a/MaciptvProvider/src/main/kotlin/com/lagradost/MacIptvAPI.kt b/MaciptvProvider/src/main/kotlin/com/lagradost/MacIptvAPI.kt index fc0f897..b3af442 100644 --- a/MaciptvProvider/src/main/kotlin/com/lagradost/MacIptvAPI.kt +++ b/MaciptvProvider/src/main/kotlin/com/lagradost/MacIptvAPI.kt @@ -30,7 +30,7 @@ class MacIptvAPI(index: Int) : InAppAuthAPIManager(index) { } override suspend fun login(data: InAppAuthAPI.LoginData): Boolean { - if (data.server.isNullOrBlank()) return false // we require a server + if (data.server.isNullOrBlank() || !data.password?.contains("""(([0-9A-Za-z]{2}[:-]){5}[0-9A-Za-z]{2})""".toRegex())!!) return false // we require a server and a mac address switchToNewAccount() setKey(accountId, IPTVBOX_USER_KEY, data) registerAccount()