diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultFragmentPhone.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultFragmentPhone.kt index 3bac24dd74e..a5f5b4288e7 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultFragmentPhone.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultFragmentPhone.kt @@ -800,6 +800,17 @@ open class ResultFragmentPhone : FullScreenPlayer() { } } + if (!d.logourl.isNullOrBlank()) { + backgroundPosterWatermarkBadge.isVisible = true + resultTitle.isVisible = false + + backgroundPosterWatermarkBadge.loadImage(d.logourl) + } else { + // No logo URL → show title + backgroundPosterWatermarkBadge.isVisible = false + resultTitle.isVisible = true + } + var isExpanded = false resultDescription.apply { setTextHtml(d.plotText) diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultFragmentTv.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultFragmentTv.kt index af2fe254dd0..150162b7bbe 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultFragmentTv.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultFragmentTv.kt @@ -909,6 +909,17 @@ class ResultFragmentTv : BaseFragment( backgroundPoster.loadImage(d.posterBackgroundImage) { error { getImageFromDrawable(context ?: return@error null, error) } } + + if (!d.logourl.isNullOrBlank()) { + backgroundPosterWatermarkBadgeHolder.isVisible = true + resultTitle.isVisible = false + + backgroundPosterWatermarkBadgeHolder.loadImage(d.logourl) + } else { + // No logo URL → show title + backgroundPosterWatermarkBadgeHolder.isVisible = false + resultTitle.isVisible = true + } comingSoon = d.comingSoon resultTvComingSoon.isVisible = d.comingSoon diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultViewModel2.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultViewModel2.kt index 27ae0eacc24..aa81003981d 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultViewModel2.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultViewModel2.kt @@ -120,6 +120,7 @@ data class ResultData( val posterImage: String?, val posterBackgroundImage: String?, + val logourl: String?, val plotText: UiText, val apiName: UiText, val ratingText: UiText?, @@ -245,6 +246,7 @@ fun LoadResponse.toResultData(repo: APIRepository): ResultData { plot!! ), backgroundPosterUrl = backgroundPosterUrl, + logourl = logourl, title = name, typeText = txt( when (type) { @@ -1895,6 +1897,7 @@ class ResultViewModel2 : ViewModel() { // set posters, might fuck up due to headers idk posterUrl = posterUrl ?: res?.image backgroundPosterUrl = backgroundPosterUrl ?: res?.cover + logourl = logourl }, { if (meta == null) return@runAllAsync @@ -2695,6 +2698,7 @@ class ResultViewModel2 : ViewModel() { override var syncData: MutableMap = mutableMapOf(), override var posterHeaders: Map? = null, override var backgroundPosterUrl: String? = null, + override var logourl: String? = null, override var contentRating: String? = null, override var uniqueUrl: String = url, val id: Int?, diff --git a/app/src/main/res/layout/fragment_result.xml b/app/src/main/res/layout/fragment_result.xml index e025e72bd27..2a44c327f63 100644 --- a/app/src/main/res/layout/fragment_result.xml +++ b/app/src/main/res/layout/fragment_result.xml @@ -293,6 +293,16 @@ android:layout_height="match_parent" android:scaleType="centerCrop" /> + + + + + + var posterHeaders: Map? var backgroundPosterUrl: String? + var logourl: String? var contentRating: String? var uniqueUrl: String @@ -2217,6 +2218,7 @@ constructor( override var syncData: MutableMap = mutableMapOf(), override var posterHeaders: Map? = null, override var backgroundPosterUrl: String? = null, + override var logourl: String? = null, override var contentRating: String? = null, override var uniqueUrl: String = url ) : LoadResponse @@ -2277,6 +2279,7 @@ constructor( override var nextAiring: NextAiring? = null, override var seasonNames: List? = null, override var backgroundPosterUrl: String? = null, + override var logourl: String? = null, override var contentRating: String? = null, override var uniqueUrl: String = url ) : LoadResponse, EpisodeResponse { @@ -2362,6 +2365,7 @@ constructor( override var syncData: MutableMap = mutableMapOf(), override var posterHeaders: Map? = null, override var backgroundPosterUrl: String? = null, + override var logourl: String? = null, override var contentRating: String? = null, override var uniqueUrl: String = url ) : LoadResponse @@ -2410,6 +2414,7 @@ constructor( override var syncData: MutableMap = mutableMapOf(), override var posterHeaders: Map? = null, override var backgroundPosterUrl: String? = null, + override var logourl: String? = null, override var contentRating: String? = null, override var uniqueUrl: String = url ) : LoadResponse @@ -2589,6 +2594,7 @@ constructor( override var nextAiring: NextAiring? = null, override var seasonNames: List? = null, override var backgroundPosterUrl: String? = null, + override var logourl: String? = null, override var contentRating: String? = null, override var uniqueUrl: String = url ) : LoadResponse, EpisodeResponse { diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/BuzzServer.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/BuzzServer.kt new file mode 100644 index 00000000000..9e0eb7f6098 --- /dev/null +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/BuzzServer.kt @@ -0,0 +1,47 @@ +package com.lagradost.cloudstream3.extractors + +import com.lagradost.api.Log +import com.lagradost.cloudstream3.Prerelease +import com.lagradost.cloudstream3.SubtitleFile +import com.lagradost.cloudstream3.app +import com.lagradost.cloudstream3.utils.ExtractorApi +import com.lagradost.cloudstream3.utils.ExtractorLink +import com.lagradost.cloudstream3.utils.getQualityFromName +import com.lagradost.cloudstream3.utils.newExtractorLink + +@Prerelease +class BuzzServer : ExtractorApi() { + override val name = "BuzzServer" + override val mainUrl = "https://buzzheavier.com" + override val requiresReferer = true + + override suspend fun getUrl( + url: String, + referer: String?, + subtitleCallback: (SubtitleFile) -> Unit, + callback: (ExtractorLink) -> Unit + ) { + try { + val qualityText = app.get(url).documentLarge.selectFirst("div.max-w-2xl > span")?.text() + val quality = getQualityFromName(qualityText) + val response = app.get("$url/download", referer = url, allowRedirects = false) + val redirectUrl = response.headers["hx-redirect"] ?: "" + + if (redirectUrl.isNotEmpty()) { + callback.invoke( + newExtractorLink( + "BuzzServer", + "BuzzServer", + redirectUrl, + ) { + this.quality = quality + } + ) + } else { + Log.w("BuzzServer", "No redirect URL found in headers.") + } + } catch (e: Exception) { + Log.e("BuzzServer", "Exception occurred: ${e.message}") + } + } +} \ No newline at end of file diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Krakenfiles.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Krakenfiles.kt index b605a39c6b4..ea59825f91f 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Krakenfiles.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Krakenfiles.kt @@ -5,6 +5,7 @@ import com.lagradost.cloudstream3.app import com.lagradost.cloudstream3.utils.ExtractorApi import com.lagradost.cloudstream3.utils.ExtractorLink import com.lagradost.cloudstream3.utils.Qualities +import com.lagradost.cloudstream3.utils.getQualityFromName import com.lagradost.cloudstream3.utils.httpsify import com.lagradost.cloudstream3.utils.newExtractorLink @@ -19,18 +20,28 @@ open class Krakenfiles : ExtractorApi() { subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit ) { - val id = Regex("/(?:view|embed-video)/([\\da-zA-Z]+)").find(url)?.groupValues?.get(1) + val id = Regex("/(?:view|embed-video)/([\\da-zA-Z]+)") + .find(url) + ?.groupValues + ?.get(1) + ?: return + val doc = app.get("$mainUrl/embed-video/$id").document - val link = doc.selectFirst("source")?.attr("src") + val title = doc.select("span.coin-name").text() + val link = doc.selectFirst("source")?.attr("src") ?: return + val quality = getQualityFromName(title) + - callback.invoke( + callback( newExtractorLink( - this.name, - this.name, - httpsify(link ?: return), - ) + name, + name, + httpsify(link) + ) { + this.quality = quality + } ) - } -} \ No newline at end of file +} + diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/ExtractorApi.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/ExtractorApi.kt index 641c913195e..f3ddb6694b1 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/ExtractorApi.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/ExtractorApi.kt @@ -18,6 +18,7 @@ import com.lagradost.cloudstream3.extractors.BigwarpArt import com.lagradost.cloudstream3.extractors.BigwarpIO import com.lagradost.cloudstream3.extractors.Blogger import com.lagradost.cloudstream3.extractors.BullStream +import com.lagradost.cloudstream3.extractors.BuzzServer import com.lagradost.cloudstream3.extractors.ByseSX import com.lagradost.cloudstream3.extractors.Bysezejataos import com.lagradost.cloudstream3.extractors.ByteShare @@ -791,15 +792,26 @@ enum class Qualities(var value: Int, val defaultPriority: Int) { } } +private val QUALITY_REGEX_MAP = listOf( + Regex("""\b(4k|2160p?|2160)\b""", RegexOption.IGNORE_CASE) to Qualities.P2160.value, + Regex("""\b1440p?|1440\b""", RegexOption.IGNORE_CASE) to Qualities.P1440.value, + Regex("""\b1080p?|1080\b""", RegexOption.IGNORE_CASE) to Qualities.P1080.value, + Regex("""\b720p?|720\b""", RegexOption.IGNORE_CASE) to Qualities.P720.value, + Regex("""\b480p?|480\b""", RegexOption.IGNORE_CASE) to Qualities.P480.value +) +private var lastResolvedQuality: Int = Qualities.Unknown.value + fun getQualityFromName(qualityName: String?): Int { - if (qualityName == null) - return Qualities.Unknown.value - - val match = qualityName.lowercase().replace("p", "").trim() - return when (match) { - "4k" -> Qualities.P2160 - else -> null - }?.value ?: match.toIntOrNull() ?: Qualities.Unknown.value + if (qualityName.isNullOrBlank()) + return lastResolvedQuality + + for ((regex, quality) in QUALITY_REGEX_MAP) { + if (regex.containsMatchIn(qualityName)) { + lastResolvedQuality = maxOf(lastResolvedQuality, quality) + return lastResolvedQuality + } + } + return lastResolvedQuality } private val packedRegex = Regex("""eval\(function\(p,a,c,k,e,.*\)\)""") @@ -1077,6 +1089,7 @@ val extractorApis: MutableList = arrayListOf( Fembed9hd(), StreamM4u(), Krakenfiles(), + BuzzServer(), Gofile(), Vicloud(), Uservideo(),