diff --git a/TeleportalProvider/build.gradle.kts b/TeleportalProvider/build.gradle.kts new file mode 100644 index 0000000..d43ab6e --- /dev/null +++ b/TeleportalProvider/build.gradle.kts @@ -0,0 +1,29 @@ +// use an integer for version numbers +version = 1 + +dependencies{ + implementation("com.google.code.gson:gson:2.9.0") +} + +cloudstream { + language = "uk" + // All of these properties are optional, you can safely remove them + + description = "Telepotral - Серіали. шоу, Док. фільми" + authors = listOf("CakesTwix") + + /** + * Status int as the following: + * 0: Down + * 1: Ok + * 2: Slow + * 3: Beta only + * */ + status = 1 // will be 3 if unspecified + tvTypes = listOf( + "Series", + "Movie", + ) + + iconUrl = "https://www.google.com/s2/favicons?domain=teleportal.ua&sz=%size%" +} \ No newline at end of file diff --git a/TeleportalProvider/src/main/AndroidManifest.xml b/TeleportalProvider/src/main/AndroidManifest.xml new file mode 100644 index 0000000..29aec9d --- /dev/null +++ b/TeleportalProvider/src/main/AndroidManifest.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/TeleportalProvider/src/main/kotlin/com/lagradost/TeleportalProvider.kt b/TeleportalProvider/src/main/kotlin/com/lagradost/TeleportalProvider.kt new file mode 100644 index 0000000..0cd9182 --- /dev/null +++ b/TeleportalProvider/src/main/kotlin/com/lagradost/TeleportalProvider.kt @@ -0,0 +1,166 @@ +package com.lagradost + +import com.google.gson.Gson +import com.lagradost.cloudstream3.DubStatus +import com.lagradost.cloudstream3.Episode +import com.lagradost.cloudstream3.HomePageResponse +import com.lagradost.cloudstream3.LoadResponse +import com.lagradost.cloudstream3.MainAPI +import com.lagradost.cloudstream3.MainPageRequest +import com.lagradost.cloudstream3.SearchResponse +import com.lagradost.cloudstream3.SubtitleFile +import com.lagradost.cloudstream3.TvType +import com.lagradost.cloudstream3.addEpisodes +import com.lagradost.cloudstream3.app +import com.lagradost.cloudstream3.mainPageOf +import com.lagradost.cloudstream3.newAnimeLoadResponse +import com.lagradost.cloudstream3.newAnimeSearchResponse +import com.lagradost.cloudstream3.newHomePageResponse +import com.lagradost.cloudstream3.newMovieLoadResponse +import com.lagradost.cloudstream3.utils.ExtractorLink +import com.lagradost.cloudstream3.utils.M3u8Helper +import com.lagradost.models.Media +import com.lagradost.models.MediaShows +import com.lagradost.models.SeasonModel +import com.lagradost.models.TitleShows +import com.lagradost.models.VideoPlayer + +class TeleportalProvider : MainAPI() { + + // Basic Info + override var mainUrl = "https://teleportal.ua" + override var name = "Teleportal" + override val hasMainPage = true + override var lang = "uk" + override val hasDownloadSupport = true + override val supportedTypes = setOf( + TvType.TvSeries, + TvType.Movie, + ) + + private val apiUrl = "https://tp-back.starlight.digital" + private val findUrl = "$apiUrl/ua/live-search?q=" + private val playerUrl = "https://vcms-api2.starlight.digital/player-api/" + + // Sections + override val mainPage = mainPageOf( + "$apiUrl/ua/serials" to "Серіали", + "$apiUrl/ua/show" to "Шоу", + "$apiUrl/ua/documentaries" to "Документальні фільми", + ) + + override suspend fun getMainPage( + page: Int, + request: MainPageRequest + ): HomePageResponse { + // Movies + if(request.data.substringAfterLast("/") == "documentaries"){ + val homeList = Gson().fromJson(app.get(request.data).text, Media::class.java).items.map{ + newAnimeSearchResponse(it.title, "$apiUrl/ua${it.videoSlug}", TvType.TvSeries) { + this.posterUrl = "$mainUrl${it.image}" + } + } + return newHomePageResponse(request.name, homeList) + } + // Shows + else { + val homeList = Gson().fromJson(app.get(request.data).text, MediaShows::class.java).items.map{ + newAnimeSearchResponse(it.name, "$apiUrl/ua/${request.data.substringAfterLast("/")}/${it.channelSlug}/${it.projectSlug}", TvType.TvSeries) { + this.posterUrl = "$mainUrl${it.image}" + } + } + return newHomePageResponse(request.name, homeList) + } + + + } + + override suspend fun search(query: String): List { + return app.get("$findUrl$query&page=1").parsedSafe()!!.items.map{ + newAnimeSearchResponse(it.title, "$apiUrl${it.videoSlug}", TvType.TvSeries) { + this.posterUrl = "$mainUrl${it.image}" + } + } + } + + // Detailed information + override suspend fun load(url: String): LoadResponse { + //val title = app.get(url).parsedSafe()!! + val title = Gson().fromJson(app.get(url).text, TitleShows::class.java) + val tvType = when(title.typeSlug){ + "show" -> TvType.TvSeries + "series" -> TvType.TvSeries + "serials" -> TvType.TvSeries + else -> TvType.Movie + } + + + val episodes = mutableListOf() + if (tvType == TvType.TvSeries){ + title.seasons.map{ + val season = Gson().fromJson(app.get("$url/${it.seasonSlug}").text, SeasonModel::class.java) + if(season.seasonGallery.items.isNullOrEmpty()) return@map + season.seasonGallery.items.forEach { episode -> + episodes.add( + Episode( + "$url/${it.seasonSlug}/${episode.videoSlug}", + episode.title, + extractIntFromString(season.seasonTitle), + extractIntFromString(episode.seriesTitle), + "$mainUrl${episode.image}", + description = episode.tizer, + ) + ) + } + } + return newAnimeLoadResponse( + title.title, + "$mainUrl${title.projectSlug}", + tvType, + ) { + this.posterUrl = "$mainUrl${title.image}" + this.plot = title.description + addEpisodes(DubStatus.Dubbed, episodes) + } + } + + return newMovieLoadResponse(title.title, url, TvType.Movie, "$apiUrl/ua/${title.typeSlug}/${title.channelSlug}/${title.videoSlug}") { + this.posterUrl = "$mainUrl${title.image}" + this.plot = title.description + } + } + + // It works when I click to view the series + override suspend fun loadLinks( + data: String, + isCasting: Boolean, + subtitleCallback: (SubtitleFile) -> Unit, + callback: (ExtractorLink) -> Unit + ): Boolean { + // Log.d("CakesTwix-Debug", data) + val videoHash = Gson().fromJson(app.get(data).text, TitleShows::class.java).hash + // Log.d("CakesTwix-Debug", "$playerUrl$videoHash?referer=https://teleportal.ua/") + val video = Gson().fromJson(app.get("$playerUrl$videoHash?referer=https://teleportal.ua/").text, VideoPlayer::class.java).video[0] + // Log.d("CakesTwix-Debug", video.toString()) + + if(video.mediaHlsNoAdv.isNullOrEmpty()) return false + + // Log.d("CakesTwix-Debug", video.mediaHlsNoAdv) + M3u8Helper.generateM3u8( + source = video.projectName, + streamUrl = video.mediaHlsNoAdv, + referer = mainUrl + ).forEach(callback) + return true + } + + private fun extractIntFromString(string: String): Int? { + val value = Regex("(\\d+)").findAll(string).lastOrNull() ?: return null + if(value.value[0].toString() == "0"){ + return value.value.drop(1).toIntOrNull() + } + + return value.value.toIntOrNull() + + } +} diff --git a/TeleportalProvider/src/main/kotlin/com/lagradost/TeleportalProviderPlugin.kt b/TeleportalProvider/src/main/kotlin/com/lagradost/TeleportalProviderPlugin.kt new file mode 100644 index 0000000..b46dc2f --- /dev/null +++ b/TeleportalProvider/src/main/kotlin/com/lagradost/TeleportalProviderPlugin.kt @@ -0,0 +1,13 @@ +package com.lagradost + +import com.lagradost.cloudstream3.plugins.CloudstreamPlugin +import com.lagradost.cloudstream3.plugins.Plugin +import android.content.Context + +@CloudstreamPlugin +class TeleportalProviderPlugin: Plugin() { + override fun load(context: Context) { + // All providers should be added in this manner. Please don't edit the providers list directly. + registerMainAPI(TeleportalProvider()) + } +} \ No newline at end of file diff --git a/TeleportalProvider/src/main/kotlin/com/lagradost/models/Media.kt b/TeleportalProvider/src/main/kotlin/com/lagradost/models/Media.kt new file mode 100644 index 0000000..2cb0967 --- /dev/null +++ b/TeleportalProvider/src/main/kotlin/com/lagradost/models/Media.kt @@ -0,0 +1,23 @@ +package com.lagradost.models + +data class Media( + + val galleryName : String, + val typeSlug : String, + val seoTitle : String, + val seoDescription : String, + val seoKeywords : String, + val channels : List, + val items : List +) + +data class Items ( + + val title : String, + val tizer : String, + val image : String, + val imageMob : String, + val videoSlug : String, + val seriesTitle : String, +) + diff --git a/TeleportalProvider/src/main/kotlin/com/lagradost/models/MediaShows.kt b/TeleportalProvider/src/main/kotlin/com/lagradost/models/MediaShows.kt new file mode 100644 index 0000000..f92ed06 --- /dev/null +++ b/TeleportalProvider/src/main/kotlin/com/lagradost/models/MediaShows.kt @@ -0,0 +1,30 @@ +package com.lagradost.models + +data class MediaShows ( + + val galleryName : String, + val typeSlug : String, + val seoTitle : String, + val seoDescription : String, + val seoKeywords : String, + val channels : List, + val items : List +) + +data class Channels ( + + val title : String, + val channelSlug : String, + val seoTitle : String, + val seoDescription : String, + val seoKeywords : String +) + +data class ItemsShows ( + + val name : String, + val image : String, + val imageMob : String, + val channelSlug : String, + val projectSlug : String +) \ No newline at end of file diff --git a/TeleportalProvider/src/main/kotlin/com/lagradost/models/Season.kt b/TeleportalProvider/src/main/kotlin/com/lagradost/models/Season.kt new file mode 100644 index 0000000..fa6767d --- /dev/null +++ b/TeleportalProvider/src/main/kotlin/com/lagradost/models/Season.kt @@ -0,0 +1,36 @@ +package com.lagradost.models + +data class SeasonModel ( + +val id : Int, +val seoTitle : String, +val seoDescription : String, +val seoKeywords : String, +val typeTitle : String, +val channelTitle : String, +val channelImage : String, +val sortableCompilations : String, +val projectTitle : String, +val seasonTitle : String, +val age : String, +val image : String, +val imageTab : String, +val imageMob : String, +val logoImage : String, +val description : String, +val typeSlug : String, +val channelSlug : String, +val projectSlug : String, +val seasonSlug : String, +val personPage : Boolean, +// val persons : List, +val seasons : List, +val seasonGallery : SeasonGallery, +) + +data class SeasonGallery ( + + val title : String, + val seasonSlug : String, + val items : List +) \ No newline at end of file diff --git a/TeleportalProvider/src/main/kotlin/com/lagradost/models/TitleShows.kt b/TeleportalProvider/src/main/kotlin/com/lagradost/models/TitleShows.kt new file mode 100644 index 0000000..eb89809 --- /dev/null +++ b/TeleportalProvider/src/main/kotlin/com/lagradost/models/TitleShows.kt @@ -0,0 +1,27 @@ +package com.lagradost.models + +data class TitleShows ( + + val id : Int, + val typeTitle : String, + val title : String, + val image : String, + val imageTab : String, + val imageMob : String, + val logoImage : String, + val description : String, + val typeSlug : String, + val channelSlug : String, + val projectSlug : String, + val videoSlug : String, + val seasons : List, + val video : String, + val hash : String, +) + +data class Seasons ( + + val id : Int, + val title : String, + val seasonSlug : String +) \ No newline at end of file diff --git a/TeleportalProvider/src/main/kotlin/com/lagradost/models/Video.kt b/TeleportalProvider/src/main/kotlin/com/lagradost/models/Video.kt new file mode 100644 index 0000000..d09ef39 --- /dev/null +++ b/TeleportalProvider/src/main/kotlin/com/lagradost/models/Video.kt @@ -0,0 +1,49 @@ +package com.lagradost.models + +data class VideoPlayer ( + + val version : String, + val type : String, + val poster : String, + val posterMob : String, + val name : String, + val video : List