diff --git a/CanliTV/build.gradle.kts b/CanliTV/build.gradle.kts
new file mode 100644
index 00000000..4782f0df
--- /dev/null
+++ b/CanliTV/build.gradle.kts
@@ -0,0 +1,18 @@
+version = 1
+
+cloudstream {
+ authors = listOf("keyiflerolsun")
+ language = "tr"
+ description = "Canlı TV"
+
+ /**
+ * Status int as the following:
+ * 0: Down
+ * 1: Ok
+ * 2: Slow
+ * 3: Beta only
+ **/
+ status = 1 // will be 3 if unspecified
+ tvTypes = listOf("Live")
+ iconUrl = "https://www.google.com/s2/favicons?domain=tr.canlitv.team&sz=%size%"
+}
\ No newline at end of file
diff --git a/CanliTV/src/main/AndroidManifest.xml b/CanliTV/src/main/AndroidManifest.xml
new file mode 100644
index 00000000..1ffaf63d
--- /dev/null
+++ b/CanliTV/src/main/AndroidManifest.xml
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/CanliTV/src/main/kotlin/com/keyiflerolsun/CanliTV.kt b/CanliTV/src/main/kotlin/com/keyiflerolsun/CanliTV.kt
new file mode 100644
index 00000000..d2755ff3
--- /dev/null
+++ b/CanliTV/src/main/kotlin/com/keyiflerolsun/CanliTV.kt
@@ -0,0 +1,339 @@
+package com.keyiflerolsun
+
+import com.lagradost.cloudstream3.*
+import com.lagradost.cloudstream3.utils.AppUtils.parseJson
+import com.lagradost.cloudstream3.utils.AppUtils.toJson
+import com.lagradost.cloudstream3.utils.ExtractorLink
+import com.lagradost.cloudstream3.utils.Qualities
+import java.io.InputStream
+
+class CanliTV : MainAPI() {
+ override var mainUrl = "https://raw.githubusercontent.com/keyiflerolsun/IPTV_YenirMi/main/Kanallar/KekikAkademi.m3u"
+ override var name = "CanliTV"
+ override val hasMainPage = true
+ override var lang = "tr"
+ override val hasChromecastSupport = true
+ override val supportedTypes = setOf(TvType.Live)
+
+ override suspend fun getMainPage(page: Int, request: MainPageRequest): HomePageResponse {
+ val data = IptvPlaylistParser().parseM3U(app.get(mainUrl).text)
+ return HomePageResponse(
+ data.items
+ .groupBy { it.attributes["group-title"] }
+ .map { group ->
+ val title = group.key ?: ""
+ val show =
+ group.value.map { channel ->
+ val streamurl = channel.url.toString()
+ val channelname = channel.title.toString()
+ val posterurl = channel.attributes["tvg-logo"].toString()
+ // val nation = channel.attributes["group-title"].toString()
+ val nation = "TR"
+ LiveSearchResponse(
+ channelname,
+ LoadData(streamurl, channelname, posterurl, nation).toJson(),
+ this@CanliTV.name,
+ TvType.Live,
+ posterurl,
+ // lang = channel.attributes["group-title"]
+ lang = "TR"
+ )
+ }
+ HomePageList(title, show, isHorizontalImages = true)
+ }
+ )
+ }
+
+ override suspend fun search(query: String): List {
+ val data = IptvPlaylistParser().parseM3U(app.get(mainUrl).text)
+
+ return data.items
+ .filter { it.attributes["tvg-id"]?.contains(query) ?: false }
+ .map { channel ->
+ val streamurl = channel.url.toString()
+ val channelname = channel.attributes["tvg-id"].toString()
+ val posterurl = channel.attributes["tvg-logo"].toString()
+ val nation = channel.attributes["group-title"].toString()
+ LiveSearchResponse(
+ channelname,
+ LoadData(streamurl, channelname, posterurl, nation).toJson(),
+ this@CanliTV.name,
+ TvType.Live,
+ posterurl,
+ )
+ }
+ }
+
+ override suspend fun load(url: String): LoadResponse {
+ val data = parseJson(url)
+ return LiveStreamLoadResponse(
+ data.title,
+ data.url,
+ this.name,
+ url,
+ data.poster,
+ plot = data.nation
+ )
+ }
+
+ data class LoadData(val url: String, val title: String, val poster: String, val nation: String)
+
+ override suspend fun loadLinks(
+ data: String,
+ isCasting: Boolean,
+ subtitleCallback: (SubtitleFile) -> Unit,
+ callback: (ExtractorLink) -> Unit
+ ): Boolean {
+ val loadData = parseJson(data)
+ callback.invoke(
+ ExtractorLink(
+ this.name,
+ loadData.title,
+ loadData.url,
+ "",
+ Qualities.Unknown.value,
+ isM3u8 = true
+ )
+ )
+ return true
+ }
+}
+
+data class Playlist(
+ val items: List = emptyList(),
+)
+
+data class PlaylistItem(
+ val title: String? = null,
+ val attributes: Map = emptyMap(),
+ val headers: Map = emptyMap(),
+ val url: String? = null,
+ val userAgent: String? = null,
+)
+
+class IptvPlaylistParser {
+
+ /**
+ * Parse M3U8 string into [Playlist]
+ *
+ * @param content M3U8 content string.
+ * @throws PlaylistParserException if an error occurs.
+ */
+ fun parseM3U(content: String): Playlist {
+ return parseM3U(content.byteInputStream())
+ }
+
+ /**
+ * Parse M3U8 content [InputStream] into [Playlist]
+ *
+ * @param input Stream of input data.
+ * @throws PlaylistParserException if an error occurs.
+ */
+ @Throws(PlaylistParserException::class)
+ fun parseM3U(input: InputStream): Playlist {
+ val reader = input.bufferedReader()
+
+ if (!reader.readLine().isExtendedM3u()) {
+ throw PlaylistParserException.InvalidHeader()
+ }
+
+ val playlistItems: MutableList = mutableListOf()
+ var currentIndex = 0
+
+ var line: String? = reader.readLine()
+
+ while (line != null) {
+ if (line.isNotEmpty()) {
+ if (line.startsWith(EXT_INF)) {
+ val title = line.getTitle()
+ val attributes = line.getAttributes()
+ playlistItems.add(PlaylistItem(title, attributes))
+ } else if (line.startsWith(EXT_VLC_OPT)) {
+ val item = playlistItems[currentIndex]
+ val userAgent = line.getTagValue("http-user-agent")
+ val referrer = line.getTagValue("http-referrer")
+ val headers =
+ if (referrer != null) {
+ item.headers + mapOf("referrer" to referrer)
+ } else item.headers
+ playlistItems[currentIndex] =
+ item.copy(userAgent = userAgent, headers = headers)
+ } else {
+ if (!line.startsWith("#")) {
+ val item = playlistItems[currentIndex]
+ val url = line.getUrl()
+ val userAgent = line.getUrlParameter("user-agent")
+ val referrer = line.getUrlParameter("referer")
+ val urlHeaders =
+ if (referrer != null) {
+ item.headers + mapOf("referrer" to referrer)
+ } else item.headers
+ playlistItems[currentIndex] =
+ item.copy(
+ url = url,
+ headers = item.headers + urlHeaders,
+ userAgent = userAgent
+ )
+ currentIndex++
+ }
+ }
+ }
+
+ line = reader.readLine()
+ }
+ return Playlist(playlistItems)
+ }
+
+ /** Replace "" (quotes) from given string. */
+ private fun String.replaceQuotesAndTrim(): String {
+ return replace("\"", "").trim()
+ }
+
+ /** Check if given content is valid M3U8 playlist. */
+ private fun String.isExtendedM3u(): Boolean = startsWith(EXT_M3U)
+
+ /**
+ * Get title of media.
+ *
+ * Example:-
+ *
+ * Input:
+ * ```
+ * #EXTINF:-1 tvg-id="1234" group-title="Kids" tvg-logo="url/to/logo", Title
+ * ```
+ *
+ * Result: Title
+ */
+ private fun String.getTitle(): String? {
+ return split(",").lastOrNull()?.replaceQuotesAndTrim()
+ }
+
+ /**
+ * Get media url.
+ *
+ * Example:-
+ *
+ * Input:
+ * ```
+ * https://example.com/sample.m3u8|user-agent="Custom"
+ * ```
+ *
+ * Result: https://example.com/sample.m3u8
+ */
+ private fun String.getUrl(): String? {
+ return split("|").firstOrNull()?.replaceQuotesAndTrim()
+ }
+
+ /**
+ * Get url parameters.
+ *
+ * Example:-
+ *
+ * Input:
+ * ```
+ * http://192.54.104.122:8080/d/abcdef/video.mp4|User-Agent=Mozilla&Referer=CustomReferrer
+ * ```
+ *
+ * Result will be equivalent to kotlin map:
+ * ```Kotlin
+ * mapOf(
+ * "User-Agent" to "Mozilla",
+ * "Referer" to "CustomReferrer"
+ * )
+ * ```
+ */
+ private fun String.getUrlParameters(): Map {
+ val urlRegex = Regex("^(.*)\\|", RegexOption.IGNORE_CASE)
+ val headersString = replace(urlRegex, "").replaceQuotesAndTrim()
+ return headersString
+ .split("&")
+ .mapNotNull {
+ val pair = it.split("=")
+ if (pair.size == 2) pair.first() to pair.last() else null
+ }
+ .toMap()
+ }
+
+ /**
+ * Get url parameter with key.
+ *
+ * Example:-
+ *
+ * Input:
+ * ```
+ * http://192.54.104.122:8080/d/abcdef/video.mp4|User-Agent=Mozilla&Referer=CustomReferrer
+ * ```
+ *
+ * If given key is `user-agent`, then
+ *
+ * Result: Mozilla
+ */
+ private fun String.getUrlParameter(key: String): String? {
+ val urlRegex = Regex("^(.*)\\|", RegexOption.IGNORE_CASE)
+ val keyRegex = Regex("$key=(\\w[^&]*)", RegexOption.IGNORE_CASE)
+ val paramsString = replace(urlRegex, "").replaceQuotesAndTrim()
+ return keyRegex.find(paramsString)?.groups?.get(1)?.value
+ }
+
+ /**
+ * Get attributes from `#EXTINF` tag as Map.
+ *
+ * Example:-
+ *
+ * Input:
+ * ```
+ * #EXTINF:-1 tvg-id="1234" group-title="Kids" tvg-logo="url/to/logo", Title
+ * ```
+ *
+ * Result will be equivalent to kotlin map:
+ * ```Kotlin
+ * mapOf(
+ * "tvg-id" to "1234",
+ * "group-title" to "Kids",
+ * "tvg-logo" to "url/to/logo"
+ * )
+ * ```
+ */
+ private fun String.getAttributes(): Map {
+ val extInfRegex = Regex("(#EXTINF:.?[0-9]+)", RegexOption.IGNORE_CASE)
+ val attributesString = replace(extInfRegex, "").replaceQuotesAndTrim().split(",").first()
+ return attributesString
+ .split(Regex("\\s"))
+ .mapNotNull {
+ val pair = it.split("=")
+ if (pair.size == 2) pair.first() to pair.last().replaceQuotesAndTrim() else null
+ }
+ .toMap()
+ }
+
+ /**
+ * Get value from a tag.
+ *
+ * Example:-
+ *
+ * Input:
+ * ```
+ * #EXTVLCOPT:http-referrer=http://example.com/
+ * ```
+ *
+ * Result: http://example.com/
+ */
+ private fun String.getTagValue(key: String): String? {
+ val keyRegex = Regex("$key=(.*)", RegexOption.IGNORE_CASE)
+ return keyRegex.find(this)?.groups?.get(1)?.value?.replaceQuotesAndTrim()
+ }
+
+ companion object {
+ const val EXT_M3U = "#EXTM3U"
+ const val EXT_INF = "#EXTINF"
+ const val EXT_VLC_OPT = "#EXTVLCOPT"
+ }
+}
+
+/** Exception thrown when an error occurs while parsing playlist. */
+sealed class PlaylistParserException(message: String) : Exception(message) {
+
+ /** Exception thrown if given file content is not valid. */
+ class InvalidHeader :
+ PlaylistParserException("Invalid file header. Header doesn't start with #EXTM3U")
+}
diff --git a/CanliTV/src/main/kotlin/com/keyiflerolsun/CanliTVPlugin.kt b/CanliTV/src/main/kotlin/com/keyiflerolsun/CanliTVPlugin.kt
new file mode 100644
index 00000000..4ecbcc01
--- /dev/null
+++ b/CanliTV/src/main/kotlin/com/keyiflerolsun/CanliTVPlugin.kt
@@ -0,0 +1,12 @@
+package com.keyiflerolsun
+
+import com.lagradost.cloudstream3.plugins.CloudstreamPlugin
+import com.lagradost.cloudstream3.plugins.Plugin
+import android.content.Context
+
+@CloudstreamPlugin
+class CanliTVPlugin: Plugin() {
+ override fun load(context: Context) {
+ registerMainAPI(CanliTV())
+ }
+}
\ No newline at end of file
diff --git a/FullHDFilmizlesene/build.gradle.kts b/FullHDFilmizlesene/build.gradle.kts
new file mode 100644
index 00000000..f53b71ac
--- /dev/null
+++ b/FullHDFilmizlesene/build.gradle.kts
@@ -0,0 +1,18 @@
+version = 1
+
+cloudstream {
+ authors = listOf("keyiflerolsun")
+ language = "tr"
+ description = "Sinema zevkini evinize kadar getirdik. Türkiye'nin lider Film sitesinde, en yeni filmleri Full HD izleyin."
+
+ /**
+ * Status int as the following:
+ * 0: Down
+ * 1: Ok
+ * 2: Slow
+ * 3: Beta only
+ **/
+ status = 1 // will be 3 if unspecified
+ tvTypes = listOf("Movie")
+ iconUrl = "https://www.google.com/s2/favicons?domain=www.fullhdfilmizlesene.pw&sz=%size%"
+}
\ No newline at end of file
diff --git a/FullHDFilmizlesene/src/main/AndroidManifest.xml b/FullHDFilmizlesene/src/main/AndroidManifest.xml
new file mode 100644
index 00000000..1ffaf63d
--- /dev/null
+++ b/FullHDFilmizlesene/src/main/AndroidManifest.xml
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/FullHDFilmizlesene/src/main/kotlin/com/keyiflerolsun/FullHDFilmizlesene.kt b/FullHDFilmizlesene/src/main/kotlin/com/keyiflerolsun/FullHDFilmizlesene.kt
new file mode 100644
index 00000000..ee724239
--- /dev/null
+++ b/FullHDFilmizlesene/src/main/kotlin/com/keyiflerolsun/FullHDFilmizlesene.kt
@@ -0,0 +1,105 @@
+package com.keyiflerolsun
+
+import com.lagradost.cloudstream3.*
+import com.lagradost.cloudstream3.LoadResponse.Companion.addActors
+import com.lagradost.cloudstream3.utils.ExtractorLink
+import com.lagradost.cloudstream3.utils.M3u8Helper
+import com.lagradost.cloudstream3.utils.loadExtractor
+import org.jsoup.nodes.Element
+import android.util.Log
+
+class FullHDFilmizlesene : MainAPI() {
+ override var mainUrl = "https://www.fullhdfilmizlesene.pw"
+ override var name = "FullHDFilmizlesene"
+ override val hasMainPage = true
+ override var lang = "tr"
+ override val hasQuickSearch = true
+ override val hasDownloadSupport = true
+ override val supportedTypes = setOf(TvType.Movie)
+
+ override val mainPage =
+ mainPageOf(
+ "$mainUrl/en-cok-izlenen-filmler-izle-hd/" to "En Çok izlenen Filmler",
+ "$mainUrl/filmizle/imdb-puani-yuksek-filmler-izle-1/" to "IMDB Puanı Yüksek Filmler",
+ "$mainUrl/filmizle/bilim-kurgu-filmleri-izle-1/" to "Bilim Kurgu Filmleri",
+ "$mainUrl/filmizle/komedi-filmleri-izle-2/" to "Komedi Filmleri",
+ )
+
+ override suspend fun getMainPage(page: Int, request: MainPageRequest): HomePageResponse {
+ val document = app.get(request.data + page).document
+ val home = document.select("li.film").mapNotNull { it.toSearchResult() }
+ return newHomePageResponse(request.name, home)
+ }
+
+ private fun Element.toSearchResult(): SearchResponse? {
+ val title = this.selectFirst("span.film-title")?.text() ?: return null
+ val href = fixUrlNull(this.selectFirst("a")?.attr("href")) ?: return null
+ val posterUrl = fixUrlNull(this.selectFirst("img")?.attr("data-src"))
+ return newMovieSearchResponse(title, href, TvType.Movie) { this.posterUrl = posterUrl }
+ }
+
+ override suspend fun search(query: String): List {
+ val document = app.get("$mainUrl/arama/$query").document
+ return document.select("li.film").mapNotNull { it.toSearchResult() }
+ }
+
+ override suspend fun load(url: String): LoadResponse? {
+ val document = app.get(url).document
+
+ val title = document.selectFirst("div[class=izle-titles]")?.text()?.trim() ?: return null
+ val poster = fixUrlNull(document.selectFirst("div img")?.attr("data-src"))
+ val year = document.selectFirst("div.dd a.category")?.text()?.split(" ")?.get(0)?.trim()?.toIntOrNull()
+ val description = document.selectFirst("div.ozet-ic > p")?.text()?.trim()
+ val tags = document.select("a[rel='category tag']").map { it.text() }
+ val rating = document.selectFirst("div.puanx-puan")?.text()?.trim()?.split(".")?.get(0)?.toRatingInt()
+ val duration = document.selectFirst("span.sure")?.text()?.split(" ")?.get(0)?.trim()?.toRatingInt()
+ val recommendations = document.select("div.izle-alt-content:nth-of-type(3) ul li").mapNotNull {
+ val recName = it.selectFirst("h2.film-title")?.text() ?: return@mapNotNull null
+ val recHref = fixUrlNull(it.selectFirst("a")?.attr("href")) ?: return@mapNotNull null
+ val recPosterUrl = fixUrlNull(it.selectFirst("img")?.attr("src"))
+ newTvSeriesSearchResponse(recName, recHref, TvType.TvSeries) {
+ this.posterUrl = recPosterUrl
+ }
+ }
+ val actors = document.select("div.film-info ul li:nth-child(2) a > span").map {
+ Actor(it.text())
+ }
+
+ return newMovieLoadResponse(title, url, TvType.Movie, url) {
+ this.posterUrl = poster
+ this.year = year
+ this.plot = description
+ this.tags = tags
+ this.rating = rating
+ this.duration = duration
+ this.recommendations = recommendations
+ addActors(actors)
+ }
+ }
+
+ override suspend fun loadLinks(
+ data: String,
+ isCasting: Boolean,
+ subtitleCallback: (SubtitleFile) -> Unit,
+ callback: (ExtractorLink) -> Unit
+ ): Boolean {
+
+ val document = app.get(data).document
+ val iframe = document.selectFirst("div#plx iframe")?.attr("src") ?: return false
+
+ val rapid = app.get(iframe, referer = "$mainUrl/").text
+ val pattern = """file": "(.*)",""".toRegex()
+ val matchResult = pattern.find(rapid)
+ val extractedValue = matchResult?.groups?.get(1)?.value ?: return false
+
+ // val encoded = extractedValue.toByteArray(Charsets.UTF_8)
+ // val decoded = String(encoded, Charsets.UTF_8)
+
+ val bytes = extractedValue.split("""\\x""").filter { it.isNotEmpty() }.map { it.toInt(16).toByte() }.toByteArray()
+ val decoded = String(bytes, Charsets.UTF_8)
+
+ loadExtractor(decoded, "$mainUrl/", subtitleCallback, callback)
+
+ return true
+ }
+}
diff --git a/FullHDFilmizlesene/src/main/kotlin/com/keyiflerolsun/FullHDFilmizlesenePlugin.kt b/FullHDFilmizlesene/src/main/kotlin/com/keyiflerolsun/FullHDFilmizlesenePlugin.kt
new file mode 100644
index 00000000..e44f73fa
--- /dev/null
+++ b/FullHDFilmizlesene/src/main/kotlin/com/keyiflerolsun/FullHDFilmizlesenePlugin.kt
@@ -0,0 +1,12 @@
+package com.keyiflerolsun
+
+import com.lagradost.cloudstream3.plugins.CloudstreamPlugin
+import com.lagradost.cloudstream3.plugins.Plugin
+import android.content.Context
+
+@CloudstreamPlugin
+class FullHDFilmizlesenePlugin: Plugin() {
+ override fun load(context: Context) {
+ registerMainAPI(FullHDFilmizlesene())
+ }
+}
\ No newline at end of file
diff --git a/HDFilmCehennemi/build.gradle.kts b/HDFilmCehennemi/build.gradle.kts
new file mode 100644
index 00000000..c9250f74
--- /dev/null
+++ b/HDFilmCehennemi/build.gradle.kts
@@ -0,0 +1,18 @@
+version = 11
+
+cloudstream {
+ authors = listOf("Hexated")
+ language = "tr"
+ description = "Türkiye'nin en hızlı hd film izleme sitesi"
+
+ /**
+ * Status int as the following:
+ * 0: Down
+ * 1: Ok
+ * 2: Slow
+ * 3: Beta only
+ **/
+ status = 1 // will be 3 if unspecified
+ tvTypes = listOf("Movie")
+ iconUrl = "https://www.google.com/s2/favicons?domain=hdfilmcehennemi.live&sz=%size%"
+}
\ No newline at end of file
diff --git a/Hdfilmcehennemi/src/main/AndroidManifest.xml b/HDFilmCehennemi/src/main/AndroidManifest.xml
similarity index 100%
rename from Hdfilmcehennemi/src/main/AndroidManifest.xml
rename to HDFilmCehennemi/src/main/AndroidManifest.xml
diff --git a/Hdfilmcehennemi/src/main/kotlin/com/hexated/Hdfilmcehennemi.kt b/HDFilmCehennemi/src/main/kotlin/com/keyiflerolsun/HDFilmCehennemi.kt
similarity index 59%
rename from Hdfilmcehennemi/src/main/kotlin/com/hexated/Hdfilmcehennemi.kt
rename to HDFilmCehennemi/src/main/kotlin/com/keyiflerolsun/HDFilmCehennemi.kt
index cce3f58e..d08f43f8 100644
--- a/Hdfilmcehennemi/src/main/kotlin/com/hexated/Hdfilmcehennemi.kt
+++ b/HDFilmCehennemi/src/main/kotlin/com/keyiflerolsun/HDFilmCehennemi.kt
@@ -9,35 +9,30 @@ import com.lagradost.cloudstream3.utils.*
import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
import org.jsoup.nodes.Element
-class Hdfilmcehennemi : MainAPI() {
- override var mainUrl = "https://www.hdfilmcehennemi.life"
- override var name = "hdfilmcehennemi"
- override val hasMainPage = true
- override var lang = "tr"
- override val hasQuickSearch = true
+class HDFilmCehennemi : MainAPI() {
+ override var mainUrl = "https://www.hdfilmcehennemi.life"
+ override var name = "HDFilmCehennemi"
+ override val hasMainPage = true
+ override var lang = "tr"
+ override val hasQuickSearch = true
override val hasDownloadSupport = true
- override val supportedTypes = setOf(
- TvType.Movie,
- TvType.TvSeries,
- )
+ override val supportedTypes = setOf(TvType.Movie)
- override val mainPage = mainPageOf(
- "$mainUrl/category/tavsiye-filmler-izle2/page/" to "Tavsiye Filmler Kategorisi",
- "$mainUrl/yabancidiziizle-1/page/" to "Son Eklenen Yabancı Diziler",
- "$mainUrl/imdb-7-puan-uzeri-filmler/page/" to "Imdb 7+ Filmler",
- "$mainUrl/en-cok-yorumlananlar/page/" to "En Çok Yorumlananlar",
- "$mainUrl/en-cok-begenilen-filmleri-izle/page/" to "En Çok Beğenilenler",
- )
+ override val mainPage =
+ mainPageOf(
+ "$mainUrl/category/tavsiye-filmler-izle2/page/" to "Tavsiye Filmler Kategorisi",
+ "$mainUrl/yabancidiziizle-1/page/" to "Son Eklenen Yabancı Diziler",
+ "$mainUrl/imdb-7-puan-uzeri-filmler/page/" to "IMDB 7+ Filmler",
+ "$mainUrl/en-cok-yorumlananlar/page/" to "En Çok Yorumlananlar",
+ "$mainUrl/en-cok-begenilen-filmleri-izle/page/" to "En Çok Beğenilenler",
+ )
- override suspend fun getMainPage(
- page: Int,
- request: MainPageRequest
- ): HomePageResponse {
+ override suspend fun getMainPage(page: Int, request: MainPageRequest): HomePageResponse {
val document = app.get(request.data + page).document
- val home = document.select("div.card-body div.row div.col-6.col-sm-3.poster-container")
- .mapNotNull {
- it.toSearchResult()
- }
+ val home =
+ document
+ .select("div.card-body div.row div.col-6.col-sm-3.poster-container")
+ .mapNotNull { it.toSearchResult() }
return newHomePageResponse(request.name, home)
}
@@ -45,10 +40,7 @@ class Hdfilmcehennemi : MainAPI() {
val title = this.selectFirst("h2.title")?.text() ?: return null
val href = fixUrlNull(this.selectFirst("a")?.attr("href")) ?: return null
val posterUrl = fixUrlNull(this.selectFirst("img")?.attr("data-src"))
- return newMovieSearchResponse(title, href, TvType.Movie) {
- this.posterUrl = posterUrl
- }
-
+ return newMovieSearchResponse(title, href, TvType.Movie) { this.posterUrl = posterUrl }
}
private fun Media.toSearchResponse(): SearchResponse? {
@@ -65,35 +57,43 @@ class Hdfilmcehennemi : MainAPI() {
override suspend fun search(query: String): List {
return app.post(
- "$mainUrl/search/",
- data = mapOf("query" to query),
- referer = "$mainUrl/",
- headers = mapOf(
- "Accept" to "application/json, text/javascript, */*; q=0.01",
- "X-Requested-With" to "XMLHttpRequest"
+ "$mainUrl/search/",
+ data = mapOf("query" to query),
+ referer = "$mainUrl/",
+ headers =
+ mapOf(
+ "Accept" to "application/json, text/javascript, */*; q=0.01",
+ "X-Requested-With" to "XMLHttpRequest"
+ )
)
- ).parsedSafe()?.result?.mapNotNull { media ->
- media.toSearchResponse()
- } ?: throw ErrorLoadingException("Invalid Json reponse")
+ .parsedSafe()
+ ?.result
+ ?.mapNotNull { media -> media.toSearchResponse() }
+ ?: throw ErrorLoadingException("Invalid Json reponse")
}
override suspend fun load(url: String): LoadResponse? {
val document = app.get(url).document
- val title = document.selectFirst("div.card-header > h1, div.card-header > h2")?.text()
- ?.removeSuffix("Filminin Bilgileri")?.trim()
- ?: return null
+ val title =
+ document
+ .selectFirst("div.card-header > h1, div.card-header > h2")
+ ?.text()
+ ?.removeSuffix("Filminin Bilgileri")
+ ?.trim() ?: return null
val poster = fixUrlNull(document.select("img.img-fluid").lastOrNull()?.attr("src"))
val tags = document.select("div.mb-0.lh-lg div:nth-child(5) a").map { it.text() }
val year =
document.selectFirst("div.mb-0.lh-lg div:nth-child(4) a")?.text()?.trim()?.toIntOrNull()
- val tvType = if (document.select("nav#seasonsTabs").isNullOrEmpty()
- ) TvType.Movie else TvType.TvSeries
+ val tvType =
+ if (document.select("nav#seasonsTabs").isNullOrEmpty()) TvType.Movie
+ else TvType.TvSeries
val description = document.selectFirst("article.text-white > p")?.text()?.trim()
val rating = document.selectFirst("div.rating-votes div.rate span")?.text()?.toRatingInt()
- val actors = document.select("div.mb-0.lh-lg div:last-child a.chip").map {
- Actor(it.text(), it.select("img").attr("src"))
- }
+ val actors =
+ document.select("div.mb-0.lh-lg div:last-child a.chip").map {
+ Actor(it.text(), it.select("img").attr("src"))
+ }
val recommendations =
document.select("div.swiper-wrapper div.poster.poster-pop").mapNotNull {
val recName = it.selectFirst("h2.title")?.text() ?: return@mapNotNull null
@@ -107,24 +107,30 @@ class Hdfilmcehennemi : MainAPI() {
return if (tvType == TvType.TvSeries) {
val trailer =
- document.selectFirst("button.btn.btn-fragman.btn-danger")?.attr("data-trailer")
- ?.let {
- "https://www.youtube.com/embed/$it"
- }
- val episodes = document.select("div#seasonsTabs-tabContent div.card-list-item").map {
- val href = it.select("a").attr("href")
- val name = it.select("h3").text().trim()
- val episode = it.select("h3").text().let { num ->
- Regex("Sezon\\s?([0-9]+).").find(num)?.groupValues?.getOrNull(1)?.toIntOrNull()
+ document
+ .selectFirst("button.btn.btn-fragman.btn-danger")
+ ?.attr("data-trailer")
+ ?.let { "https://www.youtube.com/embed/$it" }
+ val episodes =
+ document.select("div#seasonsTabs-tabContent div.card-list-item").map {
+ val href = it.select("a").attr("href")
+ val name = it.select("h3").text().trim()
+ val episode =
+ it.select("h3").text().let { num ->
+ Regex("Sezon\\s?([0-9]+).")
+ .find(num)
+ ?.groupValues
+ ?.getOrNull(1)
+ ?.toIntOrNull()
+ }
+ val season = it.parents()[1].attr("id").substringAfter("-").toIntOrNull()
+ Episode(
+ href,
+ name,
+ season,
+ episode,
+ )
}
- val season = it.parents()[1].attr("id").substringAfter("-").toIntOrNull()
- Episode(
- href,
- name,
- season,
- episode,
- )
- }
newTvSeriesLoadResponse(title, url, TvType.TvSeries, episodes) {
this.posterUrl = poster
this.year = year
@@ -137,10 +143,10 @@ class Hdfilmcehennemi : MainAPI() {
}
} else {
val trailer =
- document.selectFirst("nav.nav.card-nav.nav-slider a[data-bs-toggle=\"modal\"]")
- ?.attr("data-trailer")?.let {
- "https://www.youtube.com/embed/$it"
- }
+ document
+ .selectFirst("nav.nav.card-nav.nav-slider a[data-bs-toggle=\"modal\"]")
+ ?.attr("data-trailer")
+ ?.let { "https://www.youtube.com/embed/$it" }
newMovieLoadResponse(title, url, TvType.Movie, url) {
this.posterUrl = poster
this.year = year
@@ -160,11 +166,12 @@ class Hdfilmcehennemi : MainAPI() {
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
) {
- val script = app.get(
- url,
- referer = "${mainUrl}/"
- ).document.select("script")
- .find { it.data().contains("sources:") }?.data() ?: return
+ val script =
+ app.get(url, referer = "${mainUrl}/")
+ .document
+ .select("script")
+ .find { it.data().contains("sources:") }
+ ?.data() ?: return
val videoData = getAndUnpack(script).substringAfter("file_link=\"").substringBefore("\";")
val subData = script.substringAfter("tracks: [").substringBefore("]")
@@ -180,12 +187,10 @@ class Hdfilmcehennemi : MainAPI() {
)
tryParseJson>("[${subData}]")
- ?.filter { it.kind == "captions" }?.map {
+ ?.filter { it.kind == "captions" }
+ ?.map {
subtitleCallback.invoke(
- SubtitleFile(
- it.label.toString(),
- fixUrl(it.file.toString())
- )
+ SubtitleFile(it.label.toString(), fixUrl(it.file.toString()))
)
}
}
@@ -196,12 +201,14 @@ class Hdfilmcehennemi : MainAPI() {
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
): Boolean {
- app.get(data).document.select("nav.nav.card-nav.nav-slider a.nav-link").map {
- Pair(it.attr("href"), it.text())
- }.apmap { (url, source) ->
- safeApiCall {
- app.get(url).document.select("div.card-video > iframe").attr("data-src")
- .let { url ->
+ app.get(data)
+ .document
+ .select("nav.nav.card-nav.nav-slider a.nav-link")
+ .map { Pair(it.attr("href"), it.text()) }
+ .apmap { (url, source) ->
+ safeApiCall {
+ app.get(url).document.select("div.card-video > iframe").attr("data-src").let {
+ url ->
if (url.startsWith(mainUrl)) {
invokeLocalSource(source, url, subtitleCallback, callback)
} else {
@@ -221,8 +228,8 @@ class Hdfilmcehennemi : MainAPI() {
}
}
}
+ }
}
- }
return true
}
@@ -242,4 +249,4 @@ class Hdfilmcehennemi : MainAPI() {
@JsonProperty("slug") val slug: String? = null,
@JsonProperty("slug_prefix") val slugPrefix: String? = null,
)
-}
\ No newline at end of file
+}
diff --git a/Hdfilmcehennemi/src/main/kotlin/com/hexated/HdfilmcehennemiPlugin.kt b/HDFilmCehennemi/src/main/kotlin/com/keyiflerolsun/HDFilmCehennemiPlugin.kt
similarity index 54%
rename from Hdfilmcehennemi/src/main/kotlin/com/hexated/HdfilmcehennemiPlugin.kt
rename to HDFilmCehennemi/src/main/kotlin/com/keyiflerolsun/HDFilmCehennemiPlugin.kt
index 257679b0..88bccafd 100644
--- a/Hdfilmcehennemi/src/main/kotlin/com/hexated/HdfilmcehennemiPlugin.kt
+++ b/HDFilmCehennemi/src/main/kotlin/com/keyiflerolsun/HDFilmCehennemiPlugin.kt
@@ -1,4 +1,3 @@
-
package com.hexated
import com.lagradost.cloudstream3.plugins.CloudstreamPlugin
@@ -6,9 +5,8 @@ import com.lagradost.cloudstream3.plugins.Plugin
import android.content.Context
@CloudstreamPlugin
-class HdfilmcehennemiPlugin: Plugin() {
+class HDFilmCehennemiPlugin: Plugin() {
override fun load(context: Context) {
- // All providers should be added in this manner. Please don't edit the providers list directly.
- registerMainAPI(Hdfilmcehennemi())
+ registerMainAPI(HDFilmCehennemi())
}
}
\ No newline at end of file
diff --git a/Hdfilmcehennemi/build.gradle.kts b/Hdfilmcehennemi/build.gradle.kts
deleted file mode 100644
index 3b75abc6..00000000
--- a/Hdfilmcehennemi/build.gradle.kts
+++ /dev/null
@@ -1,26 +0,0 @@
-// use an integer for version numbers
-version = 11
-
-
-cloudstream {
- language = "tr"
- // All of these properties are optional, you can safely remove them
-
- // description = "Lorem Ipsum"
- authors = listOf("Hexated")
-
- /**
- * Status int as the following:
- * 0: Down
- * 1: Ok
- * 2: Slow
- * 3: Beta only
- * */
- status = 1 // will be 3 if unspecified
- tvTypes = listOf(
- "TvSeries",
- "Movie",
- )
-
- iconUrl = "https://www.google.com/s2/favicons?domain=hdfilmcehennemi.live&sz=%size%"
-}
\ No newline at end of file
diff --git a/Turkish/build.gradle.kts b/Turkish/build.gradle.kts
deleted file mode 100644
index bb0853d9..00000000
--- a/Turkish/build.gradle.kts
+++ /dev/null
@@ -1,26 +0,0 @@
-// use an integer for version numbers
-version = 1
-
-
-cloudstream {
- language = "tr"
- // All of these properties are optional, you can safely remove them
-
- // description = "Lorem Ipsum"
- authors = listOf("Hexated")
-
- /**
- * Status int as the following:
- * 0: Down
- * 1: Ok
- * 2: Slow
- * 3: Beta only
- * */
- status = 1 // will be 3 if unspecified
- tvTypes = listOf(
- "TvSeries",
- "Movie",
- )
-
- iconUrl = "https://www.google.com/s2/favicons?domain=turkish123.com&sz=%size%"
-}
\ No newline at end of file
diff --git a/Turkish/src/main/kotlin/com/hexated/Lajkema.kt b/Turkish/src/main/kotlin/com/hexated/Lajkema.kt
deleted file mode 100644
index b2b6f570..00000000
--- a/Turkish/src/main/kotlin/com/hexated/Lajkema.kt
+++ /dev/null
@@ -1,8 +0,0 @@
-package com.hexated
-
-import com.lagradost.cloudstream3.extractors.XStreamCdn
-
-class Lajkema : XStreamCdn() {
- override val name: String = "Lajkema"
- override val mainUrl: String = "https://lajkema.com"
-}
\ No newline at end of file
diff --git a/Turkish123/build.gradle.kts b/Turkish123/build.gradle.kts
new file mode 100644
index 00000000..ae9e274e
--- /dev/null
+++ b/Turkish123/build.gradle.kts
@@ -0,0 +1,18 @@
+version = 1
+
+cloudstream {
+ authors = listOf("Hexated")
+ language = "tr"
+ description = "Watch Turkish Series with English Subtitles"
+
+ /**
+ * Status int as the following:
+ * 0: Down
+ * 1: Ok
+ * 2: Slow
+ * 3: Beta only
+ **/
+ status = 1 // will be 3 if unspecified
+ tvTypes = listOf("TvSeries")
+ iconUrl = "https://www.google.com/s2/favicons?domain=turkish123.com&sz=%size%"
+}
\ No newline at end of file
diff --git a/Turkish/src/main/AndroidManifest.xml b/Turkish123/src/main/AndroidManifest.xml
similarity index 100%
rename from Turkish/src/main/AndroidManifest.xml
rename to Turkish123/src/main/AndroidManifest.xml
diff --git a/Turkish/src/main/kotlin/com/hexated/Turkish.kt b/Turkish123/src/main/kotlin/com/keyiflerolsun/Turkish123.kt
similarity index 67%
rename from Turkish/src/main/kotlin/com/hexated/Turkish.kt
rename to Turkish123/src/main/kotlin/com/keyiflerolsun/Turkish123.kt
index 7bb68e2f..a5be02a7 100644
--- a/Turkish/src/main/kotlin/com/hexated/Turkish.kt
+++ b/Turkish123/src/main/kotlin/com/keyiflerolsun/Turkish123.kt
@@ -7,28 +7,27 @@ import com.lagradost.cloudstream3.utils.M3u8Helper
import com.lagradost.cloudstream3.utils.loadExtractor
import org.jsoup.nodes.Element
-class Turkish : MainAPI() {
- override var mainUrl = "https://turkish123.com"
- override var name = "Turkish123"
- override val hasMainPage = true
- override var lang = "tr"
+class Turkish123 : MainAPI() {
+ override var mainUrl = "https://turkish123.com"
+ override var name = "Turkish123"
+ override val hasMainPage = true
+ override var lang = "tr"
override val hasDownloadSupport = true
- override val supportedTypes = setOf(TvType.TvSeries, TvType.Movie)
+ override val supportedTypes = setOf(TvType.TvSeries)
companion object {
private const val mainServer = "https://tukipasti.com"
}
- override val mainPage = mainPageOf(
- "$mainUrl/series-list/page/" to "Series List",
- "$mainUrl/episodes-list/page/" to "Episodes List",
- )
+ override val mainPage =
+ mainPageOf(
+ "$mainUrl/series-list/page/" to "Diziler",
+ "$mainUrl/episodes-list/page/" to "Bölümler",
+ )
override suspend fun getMainPage(page: Int, request: MainPageRequest): HomePageResponse {
val document = app.get(request.data + page).document
- val home = document.select("div.movies-list div.ml-item").mapNotNull {
- it.toSearchResult()
- }
+ val home = document.select("div.movies-list div.ml-item").mapNotNull { it.toSearchResult() }
return newHomePageResponse(request.name, home)
}
@@ -55,9 +54,7 @@ class Turkish : MainAPI() {
override suspend fun search(query: String): List {
val document = app.get("$mainUrl/?s=$query").document
- return document.select("div.movies-list div.ml-item").mapNotNull {
- it.toSearchResult()
- }
+ return document.select("div.movies-list div.ml-item").mapNotNull { it.toSearchResult() }
}
override suspend fun load(url: String): LoadResponse? {
@@ -67,24 +64,32 @@ class Turkish : MainAPI() {
val poster = fixUrlNull(document.selectFirst("div.thumb.mvic-thumb img")?.attr("src"))
val tags = document.select("div.mvici-left p:contains(Genre:) a").map { it.text() }
- val year = document.selectFirst("div.mvici-right p:contains(Year:) a")?.text()?.trim()
- ?.toIntOrNull()
+ val year =
+ document
+ .selectFirst("div.mvici-right p:contains(Year:) a")
+ ?.text()
+ ?.trim()
+ ?.toIntOrNull()
val description = document.select("p.f-desc").text().trim()
- val duration = document.selectFirst("div.mvici-right span[itemprop=duration]")?.text()
- ?.filter { it.isDigit() }?.toIntOrNull()
+ val duration =
+ document
+ .selectFirst("div.mvici-right span[itemprop=duration]")
+ ?.text()
+ ?.filter { it.isDigit() }
+ ?.toIntOrNull()
val rating = document.select("span.imdb-r").text().trim().toRatingInt()
val actors = document.select("div.mvici-left p:contains(Actors:) a").map { it.text() }
- val recommendations = document.select("div.movies-list div.ml-item").mapNotNull {
- it.toSearchResult()
- }
+ val recommendations =
+ document.select("div.movies-list div.ml-item").mapNotNull { it.toSearchResult() }
- val episodes = document.select("div.les-content a").map {
- Episode(
- it.attr("href"),
- it.text(),
- )
- }
+ val episodes =
+ document.select("div.les-content a").map {
+ Episode(
+ it.attr("href"),
+ it.text(),
+ )
+ }
return newTvSeriesLoadResponse(title, url, TvType.TvSeries, episodes) {
this.posterUrl = poster
this.year = year
@@ -97,21 +102,13 @@ class Turkish : MainAPI() {
}
}
- private suspend fun invokeLocalSource(
- url: String,
- callback: (ExtractorLink) -> Unit
- ) {
+ private suspend fun invokeLocalSource(url: String, callback: (ExtractorLink) -> Unit) {
val document = app.get(url, referer = "$mainUrl/").text
- Regex("var\\surlPlay\\s=\\s[\"|'](\\S+)[\"|'];").find(document)?.groupValues?.get(1)
- ?.let { link ->
- M3u8Helper.generateM3u8(
- this.name,
- link,
- referer = "$mainServer/"
- ).forEach(callback)
- }
-
+ Regex("var\\surlPlay\\s=\\s[\"|'](\\S+)[\"|'];").find(document)?.groupValues?.get(1)?.let {
+ link ->
+ M3u8Helper.generateM3u8(this.name, link, referer = "$mainServer/").forEach(callback)
+ }
}
override suspend fun loadLinks(
@@ -123,8 +120,11 @@ class Turkish : MainAPI() {
val document = app.get(data).text
- Regex("
+ Regex("
if (link.startsWith(mainServer)) {
invokeLocalSource(link, callback)
} else {
@@ -133,7 +133,5 @@ class Turkish : MainAPI() {
}
return true
-
}
-
-}
\ No newline at end of file
+}
diff --git a/Turkish/src/main/kotlin/com/hexated/TurkishPlugin.kt b/Turkish123/src/main/kotlin/com/keyiflerolsun/Turkish123Plugin.kt
similarity index 51%
rename from Turkish/src/main/kotlin/com/hexated/TurkishPlugin.kt
rename to Turkish123/src/main/kotlin/com/keyiflerolsun/Turkish123Plugin.kt
index 10f6b0bb..5773e37b 100644
--- a/Turkish/src/main/kotlin/com/hexated/TurkishPlugin.kt
+++ b/Turkish123/src/main/kotlin/com/keyiflerolsun/Turkish123Plugin.kt
@@ -1,4 +1,3 @@
-
package com.hexated
import com.lagradost.cloudstream3.plugins.CloudstreamPlugin
@@ -6,10 +5,8 @@ import com.lagradost.cloudstream3.plugins.Plugin
import android.content.Context
@CloudstreamPlugin
-class TurkishPlugin: Plugin() {
+class Turkish123Plugin: Plugin() {
override fun load(context: Context) {
- // All providers should be added in this manner. Please don't edit the providers list directly.
- registerMainAPI(Turkish())
- registerExtractorAPI(Lajkema())
+ registerMainAPI(Turkish123())
}
}
\ No newline at end of file