diff --git a/SoraStream/src/main/kotlin/com/hexated/SoraStream.kt b/SoraStream/src/main/kotlin/com/hexated/SoraStream.kt index cca89431..b540f6f3 100644 --- a/SoraStream/src/main/kotlin/com/hexated/SoraStream.kt +++ b/SoraStream/src/main/kotlin/com/hexated/SoraStream.kt @@ -147,9 +147,9 @@ open class SoraStream : TmdbProvider() { page: Int, request: MainPageRequest ): HomePageResponse { - val adultQuery = if(settingsForProvider.enableAdult) "&page=" else "&without_keywords=190370|13059|226161|195669&page=" + val adultQuery = if (settingsForProvider.enableAdult) "" else "&without_keywords=190370|13059|226161|195669" val type = if (request.data.contains("/movie")) "movie" else "tv" - val home = app.get("${request.data}$adultQuery$page") + val home = app.get("${request.data}$adultQuery&page=$page") .parsedSafe()?.results ?.mapNotNull { media -> media.toSearchResponse(type) @@ -180,9 +180,9 @@ open class SoraStream : TmdbProvider() { val data = parseJson(url) val type = getType(data.type) val resUrl = if (type == TvType.Movie) { - "$tmdbAPI/movie/${data.id}?api_key=$apiKey&append_to_response=credits,external_ids,videos,recommendations" + "$tmdbAPI/movie/${data.id}?api_key=$apiKey&append_to_response=keywords,credits,external_ids,videos,recommendations" } else { - "$tmdbAPI/tv/${data.id}?api_key=$apiKey&append_to_response=credits,external_ids,videos,recommendations" + "$tmdbAPI/tv/${data.id}?api_key=$apiKey&append_to_response=keywords,credits,external_ids,videos,recommendations" } val res = app.get(resUrl).parsedSafe() ?: throw ErrorLoadingException("Invalid Json Response") @@ -195,6 +195,8 @@ open class SoraStream : TmdbProvider() { val rating = res.vote_average.toString().toRatingInt() val genres = res.genres?.mapNotNull { it.name } val isAnime = genres?.contains("Animation") == true && res.original_language == "ja" + val keywords = res.keywords?.results?.mapNotNull { it.name }.orEmpty() + .ifEmpty { res.keywords?.keywords?.mapNotNull { it.name } } val actors = res.credits?.cast?.mapNotNull { cast -> ActorData( @@ -252,7 +254,7 @@ open class SoraStream : TmdbProvider() { this.backgroundPosterUrl = bgPoster this.year = year this.plot = res.overview - this.tags = genres + this.tags = if (isAnime) keywords else genres this.rating = rating this.showStatus = getStatus(res.status) this.recommendations = recommendations @@ -278,7 +280,7 @@ open class SoraStream : TmdbProvider() { this.backgroundPosterUrl = bgPoster this.year = year this.plot = res.overview - this.tags = genres + this.tags = if (isAnime) keywords else genres this.rating = rating this.recommendations = recommendations this.actors = actors @@ -534,6 +536,16 @@ open class SoraStream : TmdbProvider() { @JsonProperty("name") val name: String? = null, ) + data class Keywords( + @JsonProperty("id") val id: Int? = null, + @JsonProperty("name") val name: String? = null, + ) + + data class KeywordResults( + @JsonProperty("results") val results: ArrayList? = arrayListOf(), + @JsonProperty("keywords") val keywords: ArrayList? = arrayListOf(), + ) + data class Seasons( @JsonProperty("id") val id: Int? = null, @JsonProperty("name") val name: String? = null, @@ -602,6 +614,7 @@ open class SoraStream : TmdbProvider() { @JsonProperty("original_language") val original_language: String? = null, @JsonProperty("status") val status: String? = null, @JsonProperty("genres") val genres: ArrayList? = arrayListOf(), + @JsonProperty("keywords") val keywords: KeywordResults? = null, @JsonProperty("seasons") val seasons: ArrayList? = arrayListOf(), @JsonProperty("videos") val videos: ResultsTrailer? = null, @JsonProperty("external_ids") val external_ids: ExternalIds? = null, @@ -609,14 +622,6 @@ open class SoraStream : TmdbProvider() { @JsonProperty("recommendations") val recommendations: ResultsRecommendations? = null, ) -// data class PageProps( -// @JsonProperty("id") val id: String? = null, -// @JsonProperty("imdb") val imdbId: String? = null, -// @JsonProperty("result") val result: MediaDetail? = null, -// @JsonProperty("recommandations") val recommandations: ArrayList? = arrayListOf(), -// @JsonProperty("cast") val cast: ArrayList? = arrayListOf(), -// ) - data class EmbedJson( @JsonProperty("type") val type: String? = null, @JsonProperty("link") val link: String? = null, diff --git a/TimefourTv/build.gradle.kts b/TimefourTv/build.gradle.kts index b8c5c646..6c49f54e 100644 --- a/TimefourTv/build.gradle.kts +++ b/TimefourTv/build.gradle.kts @@ -1,5 +1,5 @@ // use an integer for version numbers -version = 12 +version = 13 cloudstream { diff --git a/TimefourTv/src/main/kotlin/com/hexated/TimefourTv.kt b/TimefourTv/src/main/kotlin/com/hexated/TimefourTv.kt index c23ebfa4..4e873717 100644 --- a/TimefourTv/src/main/kotlin/com/hexated/TimefourTv.kt +++ b/TimefourTv/src/main/kotlin/com/hexated/TimefourTv.kt @@ -9,6 +9,7 @@ import org.jsoup.nodes.Element open class TimefourTv : MainAPI() { final override var mainUrl = "https://time4tv.stream" + val daddyUrl = "https://daddyhd.com" override var name = "Time4tv" override val hasDownloadSupport = false override val hasMainPage = true @@ -25,8 +26,14 @@ open class TimefourTv : MainAPI() { "$mainUrl/live-sports-streams" to "Live Sport Channels", "$mainUrl/news-channels" to "News Channels", "$mainUrl/schedule.php" to "Schedule", + "$daddyUrl/24-7-channels.php" to "DaddyHD Channels" ) + private fun fixDetailLink(link: String?): String? { + if (link == null) return null + return if (link.startsWith("/")) "$daddyUrl$link" else link + } + override suspend fun getMainPage( page: Int, request: MainPageRequest @@ -38,7 +45,7 @@ open class TimefourTv : MainAPI() { val home = res.select("div.tab-content ul li").mapNotNull { it.toSearchResult() } - if(home.isNotEmpty()) items.add(HomePageList(request.name, home, true)) + if (home.isNotEmpty()) items.add(HomePageList(request.name, home, true)) } if (request.name == "All Channels") { val res = if (page == 1) { @@ -49,7 +56,15 @@ open class TimefourTv : MainAPI() { val home = res.select("div.tab-content ul li").mapNotNull { it.toSearchResult() } - if(home.isNotEmpty()) items.add(HomePageList(request.name, home, true)) + if (home.isNotEmpty()) items.add(HomePageList(request.name, home, true)) + } + + if (nonPaged && request.name == "DaddyHD Channels") { + val res = app.get(request.data).document + val channelDaddy = res.select("div.grid-container div.grid-item").mapNotNull { + it.toSearchDaddy() + } + if (channelDaddy.isNotEmpty()) items.add(HomePageList(request.name, channelDaddy, true)) } if (nonPaged && request.name == "Schedule") { @@ -57,12 +72,22 @@ open class TimefourTv : MainAPI() { val schedule = res.select("div.search_p h1,div.search_p h2").mapNotNull { it.toSearchSchedule() } - items.add(HomePageList(request.name, schedule, true)) + if (schedule.isNotEmpty()) items.add(HomePageList(request.name, schedule, true)) } return newHomePageResponse(items) } + private fun Element.toSearchDaddy(): LiveSearchResponse? { + return LiveSearchResponse( + this.select("strong").text() ?: return null, + fixDetailLink(this.select("a").attr("href")) ?: return null, + this@TimefourTv.name, + TvType.Live, + posterUrl = time4tvPoster + ) + } + private fun Element.toSearchSchedule(): LiveSearchResponse? { return LiveSearchResponse( this.text() ?: return null, @@ -115,10 +140,13 @@ open class TimefourTv : MainAPI() { if (!res.isSuccessful) return loadSchedule(url) val document = res.document - val title = document.selectFirst("div.channelHeading h1")?.text() ?: return null + val title = + document.selectFirst("div.channelHeading h1")?.text() ?: document.selectFirst("title") + ?.text()?.substringBefore("HD")?.trim() ?: return null val poster = - fixUrlNull(document.selectFirst("meta[property=\"og:image\"]")?.attr("content")) - val description = document.selectFirst("div.tvText")?.text() ?: return null + fixUrlNull(document.selectFirst("meta[property=\"og:image\"]")?.attr("content")) ?: time4tvPoster + val description = document.selectFirst("div.tvText")?.text() + ?: document.selectFirst("meta[name=description]")?.attr("content") ?: return null val episodes = document.selectFirst("div.playit")?.attr("onclick")?.substringAfter("open('") ?.substringBefore("',")?.let { link -> val doc = app.get(link).document.selectFirst("div.tv_palyer iframe")?.attr("src") @@ -140,7 +168,11 @@ open class TimefourTv : MainAPI() { ) } } - } ?: throw ErrorLoadingException("Refresh page") + } ?: listOf( + Episode( + document.selectFirst("div#content iframe")?.attr("src") ?: return null, title + ) + ) ?: throw ErrorLoadingException("Refresh page") return newTvSeriesLoadResponse(title, url, TvType.TvSeries, episodes) { this.posterUrl = poster this.plot = description @@ -155,13 +187,13 @@ open class TimefourTv : MainAPI() { ): Boolean { val link = when { - data.contains("/channel") -> app.get(data).document.selectFirst("div.tv_palyer iframe")?.attr("src") - data.startsWith(mainUrl) -> { - app.get(data, allowRedirects = false).document.selectFirst("iframe")?.attr("src") - } - else -> { - data - } + data.contains("/channel") -> app.get(data).document.selectFirst("div.tv_palyer iframe") + ?.attr("src") + data.startsWith(mainUrl) -> app.get( + data, + allowRedirects = false + ).document.selectFirst("iframe")?.attr("src") + else -> data } ?: throw ErrorLoadingException() getLink(fixUrl(link))?.let { m3uLink -> val url = app.get(m3uLink, referer = "$mainServer/") diff --git a/TimefourTv/src/main/kotlin/com/hexated/TimefourTvExtractor.kt b/TimefourTv/src/main/kotlin/com/hexated/TimefourTvExtractor.kt index 18973922..5b6a4cfe 100644 --- a/TimefourTv/src/main/kotlin/com/hexated/TimefourTvExtractor.kt +++ b/TimefourTv/src/main/kotlin/com/hexated/TimefourTvExtractor.kt @@ -3,6 +3,7 @@ package com.hexated import com.lagradost.cloudstream3.app import com.lagradost.cloudstream3.fixUrl import com.lagradost.cloudstream3.utils.getAndUnpack +import com.lagradost.nicehttp.NiceResponse import java.net.URI var mainServer: String? = null @@ -71,6 +72,11 @@ object TimefourTvExtractor : TimefourTv() { return getSportLink(url) } + if(url.contains("daddyhd")) { + mainServer = getBaseUrl(url) + return getFinalLink(app.get(url, referer = daddyUrl)) + } + val (channel, iframe) = if (url.contains("width=") || url.contains("/link")) { val doc = app.get(url, referer = "$mainUrl/").document val tempIframe = doc.selectFirst("iframe")?.attr("src") ?: return null @@ -105,15 +111,19 @@ object TimefourTvExtractor : TimefourTv() { val docThird = app.get(fixUrl(iframeSecond), referer = "$refSecond/") mainServer = getBaseUrl(iframeSecond) - return Regex("""source:['|"](\S+.m3u8)['|"],""").find(docThird.text)?.groupValues?.getOrNull( + return getFinalLink(docThird) + + } + + private fun getFinalLink(res: NiceResponse): String? { + return Regex("""source:['|"](\S+.m3u8)['|"],""").find(res.text)?.groupValues?.getOrNull( 1 ) ?: run { val scriptData = - docThird.document.selectFirst("div#player")?.nextElementSibling()?.data() + res.document.selectFirst("div#player")?.nextElementSibling()?.data() ?.substringAfterLast("return(")?.substringBefore(".join") scriptData?.removeSurrounding("[", "]")?.replace("\"", "")?.split(",") ?.joinToString("") } - } } \ No newline at end of file