[Time4tv] added DaddyHD Channels

This commit is contained in:
hexated 2023-01-01 21:03:35 +07:00
parent 99422ff76b
commit 771643a9d7
4 changed files with 79 additions and 32 deletions

View file

@ -147,9 +147,9 @@ open class SoraStream : TmdbProvider() {
page: Int, page: Int,
request: MainPageRequest request: MainPageRequest
): HomePageResponse { ): 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 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>()?.results .parsedSafe<Results>()?.results
?.mapNotNull { media -> ?.mapNotNull { media ->
media.toSearchResponse(type) media.toSearchResponse(type)
@ -180,9 +180,9 @@ open class SoraStream : TmdbProvider() {
val data = parseJson<Data>(url) val data = parseJson<Data>(url)
val type = getType(data.type) val type = getType(data.type)
val resUrl = if (type == TvType.Movie) { 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 { } 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<MediaDetail>() val res = app.get(resUrl).parsedSafe<MediaDetail>()
?: throw ErrorLoadingException("Invalid Json Response") ?: throw ErrorLoadingException("Invalid Json Response")
@ -195,6 +195,8 @@ open class SoraStream : TmdbProvider() {
val rating = res.vote_average.toString().toRatingInt() val rating = res.vote_average.toString().toRatingInt()
val genres = res.genres?.mapNotNull { it.name } val genres = res.genres?.mapNotNull { it.name }
val isAnime = genres?.contains("Animation") == true && res.original_language == "ja" 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 -> val actors = res.credits?.cast?.mapNotNull { cast ->
ActorData( ActorData(
@ -252,7 +254,7 @@ open class SoraStream : TmdbProvider() {
this.backgroundPosterUrl = bgPoster this.backgroundPosterUrl = bgPoster
this.year = year this.year = year
this.plot = res.overview this.plot = res.overview
this.tags = genres this.tags = if (isAnime) keywords else genres
this.rating = rating this.rating = rating
this.showStatus = getStatus(res.status) this.showStatus = getStatus(res.status)
this.recommendations = recommendations this.recommendations = recommendations
@ -278,7 +280,7 @@ open class SoraStream : TmdbProvider() {
this.backgroundPosterUrl = bgPoster this.backgroundPosterUrl = bgPoster
this.year = year this.year = year
this.plot = res.overview this.plot = res.overview
this.tags = genres this.tags = if (isAnime) keywords else genres
this.rating = rating this.rating = rating
this.recommendations = recommendations this.recommendations = recommendations
this.actors = actors this.actors = actors
@ -534,6 +536,16 @@ open class SoraStream : TmdbProvider() {
@JsonProperty("name") val name: String? = null, @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<Keywords>? = arrayListOf(),
@JsonProperty("keywords") val keywords: ArrayList<Keywords>? = arrayListOf(),
)
data class Seasons( data class Seasons(
@JsonProperty("id") val id: Int? = null, @JsonProperty("id") val id: Int? = null,
@JsonProperty("name") val name: String? = null, @JsonProperty("name") val name: String? = null,
@ -602,6 +614,7 @@ open class SoraStream : TmdbProvider() {
@JsonProperty("original_language") val original_language: String? = null, @JsonProperty("original_language") val original_language: String? = null,
@JsonProperty("status") val status: String? = null, @JsonProperty("status") val status: String? = null,
@JsonProperty("genres") val genres: ArrayList<Genres>? = arrayListOf(), @JsonProperty("genres") val genres: ArrayList<Genres>? = arrayListOf(),
@JsonProperty("keywords") val keywords: KeywordResults? = null,
@JsonProperty("seasons") val seasons: ArrayList<Seasons>? = arrayListOf(), @JsonProperty("seasons") val seasons: ArrayList<Seasons>? = arrayListOf(),
@JsonProperty("videos") val videos: ResultsTrailer? = null, @JsonProperty("videos") val videos: ResultsTrailer? = null,
@JsonProperty("external_ids") val external_ids: ExternalIds? = null, @JsonProperty("external_ids") val external_ids: ExternalIds? = null,
@ -609,14 +622,6 @@ open class SoraStream : TmdbProvider() {
@JsonProperty("recommendations") val recommendations: ResultsRecommendations? = null, @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<Media>? = arrayListOf(),
// @JsonProperty("cast") val cast: ArrayList<Cast>? = arrayListOf(),
// )
data class EmbedJson( data class EmbedJson(
@JsonProperty("type") val type: String? = null, @JsonProperty("type") val type: String? = null,
@JsonProperty("link") val link: String? = null, @JsonProperty("link") val link: String? = null,

View file

@ -1,5 +1,5 @@
// use an integer for version numbers // use an integer for version numbers
version = 12 version = 13
cloudstream { cloudstream {

View file

@ -9,6 +9,7 @@ import org.jsoup.nodes.Element
open class TimefourTv : MainAPI() { open class TimefourTv : MainAPI() {
final override var mainUrl = "https://time4tv.stream" final override var mainUrl = "https://time4tv.stream"
val daddyUrl = "https://daddyhd.com"
override var name = "Time4tv" override var name = "Time4tv"
override val hasDownloadSupport = false override val hasDownloadSupport = false
override val hasMainPage = true override val hasMainPage = true
@ -25,8 +26,14 @@ open class TimefourTv : MainAPI() {
"$mainUrl/live-sports-streams" to "Live Sport Channels", "$mainUrl/live-sports-streams" to "Live Sport Channels",
"$mainUrl/news-channels" to "News Channels", "$mainUrl/news-channels" to "News Channels",
"$mainUrl/schedule.php" to "Schedule", "$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( override suspend fun getMainPage(
page: Int, page: Int,
request: MainPageRequest request: MainPageRequest
@ -38,7 +45,7 @@ open class TimefourTv : MainAPI() {
val home = res.select("div.tab-content ul li").mapNotNull { val home = res.select("div.tab-content ul li").mapNotNull {
it.toSearchResult() 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") { if (request.name == "All Channels") {
val res = if (page == 1) { val res = if (page == 1) {
@ -49,7 +56,15 @@ open class TimefourTv : MainAPI() {
val home = res.select("div.tab-content ul li").mapNotNull { val home = res.select("div.tab-content ul li").mapNotNull {
it.toSearchResult() 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") { 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 { val schedule = res.select("div.search_p h1,div.search_p h2").mapNotNull {
it.toSearchSchedule() it.toSearchSchedule()
} }
items.add(HomePageList(request.name, schedule, true)) if (schedule.isNotEmpty()) items.add(HomePageList(request.name, schedule, true))
} }
return newHomePageResponse(items) 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? { private fun Element.toSearchSchedule(): LiveSearchResponse? {
return LiveSearchResponse( return LiveSearchResponse(
this.text() ?: return null, this.text() ?: return null,
@ -115,10 +140,13 @@ open class TimefourTv : MainAPI() {
if (!res.isSuccessful) return loadSchedule(url) if (!res.isSuccessful) return loadSchedule(url)
val document = res.document 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 = val poster =
fixUrlNull(document.selectFirst("meta[property=\"og:image\"]")?.attr("content")) fixUrlNull(document.selectFirst("meta[property=\"og:image\"]")?.attr("content")) ?: time4tvPoster
val description = document.selectFirst("div.tvText")?.text() ?: return null 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('") val episodes = document.selectFirst("div.playit")?.attr("onclick")?.substringAfter("open('")
?.substringBefore("',")?.let { link -> ?.substringBefore("',")?.let { link ->
val doc = app.get(link).document.selectFirst("div.tv_palyer iframe")?.attr("src") 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) { return newTvSeriesLoadResponse(title, url, TvType.TvSeries, episodes) {
this.posterUrl = poster this.posterUrl = poster
this.plot = description this.plot = description
@ -155,13 +187,13 @@ open class TimefourTv : MainAPI() {
): Boolean { ): Boolean {
val link = when { val link = when {
data.contains("/channel") -> app.get(data).document.selectFirst("div.tv_palyer iframe")?.attr("src") data.contains("/channel") -> app.get(data).document.selectFirst("div.tv_palyer iframe")
data.startsWith(mainUrl) -> { ?.attr("src")
app.get(data, allowRedirects = false).document.selectFirst("iframe")?.attr("src") data.startsWith(mainUrl) -> app.get(
} data,
else -> { allowRedirects = false
data ).document.selectFirst("iframe")?.attr("src")
} else -> data
} ?: throw ErrorLoadingException() } ?: throw ErrorLoadingException()
getLink(fixUrl(link))?.let { m3uLink -> getLink(fixUrl(link))?.let { m3uLink ->
val url = app.get(m3uLink, referer = "$mainServer/") val url = app.get(m3uLink, referer = "$mainServer/")

View file

@ -3,6 +3,7 @@ package com.hexated
import com.lagradost.cloudstream3.app import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.fixUrl import com.lagradost.cloudstream3.fixUrl
import com.lagradost.cloudstream3.utils.getAndUnpack import com.lagradost.cloudstream3.utils.getAndUnpack
import com.lagradost.nicehttp.NiceResponse
import java.net.URI import java.net.URI
var mainServer: String? = null var mainServer: String? = null
@ -71,6 +72,11 @@ object TimefourTvExtractor : TimefourTv() {
return getSportLink(url) 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 (channel, iframe) = if (url.contains("width=") || url.contains("/link")) {
val doc = app.get(url, referer = "$mainUrl/").document val doc = app.get(url, referer = "$mainUrl/").document
val tempIframe = doc.selectFirst("iframe")?.attr("src") ?: return null val tempIframe = doc.selectFirst("iframe")?.attr("src") ?: return null
@ -105,15 +111,19 @@ object TimefourTvExtractor : TimefourTv() {
val docThird = app.get(fixUrl(iframeSecond), referer = "$refSecond/") val docThird = app.get(fixUrl(iframeSecond), referer = "$refSecond/")
mainServer = getBaseUrl(iframeSecond) 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 1
) ?: run { ) ?: run {
val scriptData = val scriptData =
docThird.document.selectFirst("div#player")?.nextElementSibling()?.data() res.document.selectFirst("div#player")?.nextElementSibling()?.data()
?.substringAfterLast("return(")?.substringBefore(".join") ?.substringAfterLast("return(")?.substringBefore(".join")
scriptData?.removeSurrounding("[", "]")?.replace("\"", "")?.split(",") scriptData?.removeSurrounding("[", "]")?.replace("\"", "")?.split(",")
?.joinToString("") ?.joinToString("")
} }
} }
} }