Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added quality profiles #414

Merged
merged 4 commits into from
Jun 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ open class DoodLaExtractor : ExtractorApi() {
val quality = Regex("\\d{3,4}p").find(response0.substringAfter("<title>").substringBefore("</title>"))?.groupValues?.get(0)
return listOf(
ExtractorLink(
trueUrl,
this.name,
this.name,
trueUrl,
mainUrl,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ open class GuardareStream : ExtractorApi() {
jsonVideoData.data.forEach {
callback.invoke(
ExtractorLink(
it.file + ".${it.type}",
this.name,
this.name,
it.file + ".${it.type}",
mainUrl,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ open class Tantifilm : ExtractorApi() {
val jsonvideodata = parseJson<TantifilmJsonData>(response)
return jsonvideodata.data.map {
ExtractorLink(
it.file+".${it.type}",
this.name,
this.name,
it.file+".${it.type}",
mainUrl,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import com.lagradost.cloudstream3.CommonActivity.playerEventListener
import com.lagradost.cloudstream3.R
import com.lagradost.cloudstream3.mvvm.logError
import com.lagradost.cloudstream3.ui.player.GeneratorPlayer.Companion.subsProvidersIsActive
import com.lagradost.cloudstream3.ui.player.source_priority.QualityDataHelper
import com.lagradost.cloudstream3.utils.Qualities
import com.lagradost.cloudstream3.utils.AppUtils.isUsingMobileData
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showDialog
Expand Down Expand Up @@ -108,8 +109,15 @@ open class FullScreenPlayer : AbstractPlayerFragment() {
// get() = episodes.isNotEmpty()

// options for player
protected var currentPrefQuality =
Qualities.P2160.value // preferred maximum quality, used for ppl w bad internet or on cell

/**
* Default profile 1
* Decides how links should be sorted based on a priority system.
* This will be set in runtime based on settings.
**/
protected var currentQualityProfile = 1
// protected var currentPrefQuality =
// Qualities.P2160.value // preferred maximum quality, used for ppl w bad internet or on cell
protected var fastForwardTime = 10000L
protected var androidTVInterfaceOffSeekTime = 10000L;
protected var androidTVInterfaceOnSeekTime = 30000L;
Expand Down Expand Up @@ -1221,10 +1229,16 @@ open class FullScreenPlayer : AbstractPlayerFragment() {
.toLong() * 1000L

androidTVInterfaceOffSeekTime =
settingsManager.getInt(ctx.getString(R.string.android_tv_interface_off_seek_key), 10)
settingsManager.getInt(
ctx.getString(R.string.android_tv_interface_off_seek_key),
10
)
.toLong() * 1000L
androidTVInterfaceOnSeekTime =
settingsManager.getInt(ctx.getString(R.string.android_tv_interface_on_seek_key), 10)
settingsManager.getInt(
ctx.getString(R.string.android_tv_interface_on_seek_key),
10
)
.toLong() * 1000L

navigationBarHeight = ctx.getNavigationBarHeight()
Expand Down Expand Up @@ -1257,10 +1271,20 @@ open class FullScreenPlayer : AbstractPlayerFragment() {
ctx.getString(R.string.double_tap_pause_enabled_key),
false
)
currentPrefQuality = settingsManager.getInt(
ctx.getString(if (ctx.isUsingMobileData()) R.string.quality_pref_mobile_data_key else R.string.quality_pref_key),
currentPrefQuality
)

val profiles = QualityDataHelper.getProfiles()
val type = if (ctx.isUsingMobileData())
QualityDataHelper.QualityProfileType.Data
else QualityDataHelper.QualityProfileType.WiFi

currentQualityProfile =
profiles.firstOrNull { it.type == type }?.id ?: profiles.firstOrNull()?.id
?: currentQualityProfile

// currentPrefQuality = settingsManager.getInt(
// ctx.getString(if (ctx.isUsingMobileData()) R.string.quality_pref_mobile_data_key else R.string.quality_pref_key),
// currentPrefQuality
// )
// useSystemBrightness =
// settingsManager.getBoolean(ctx.getString(R.string.use_system_brightness_key), false)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ import com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.subtitl
import com.lagradost.cloudstream3.ui.player.CS3IPlayer.Companion.preferredAudioTrackLanguage
import com.lagradost.cloudstream3.ui.player.CustomDecoder.Companion.updateForcedEncoding
import com.lagradost.cloudstream3.ui.player.PlayerSubtitleHelper.Companion.toSubtitleMimeType
import com.lagradost.cloudstream3.ui.player.source_priority.QualityDataHelper
import com.lagradost.cloudstream3.ui.player.source_priority.QualityProfileDialog
import com.lagradost.cloudstream3.ui.player.source_priority.SourcePriority
import com.lagradost.cloudstream3.ui.player.source_priority.SourcePriorityDialog
import com.lagradost.cloudstream3.ui.result.*
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSettings
import com.lagradost.cloudstream3.ui.subtitles.SubtitlesFragment.Companion.getAutoSelectLanguageISO639_1
Expand All @@ -57,6 +61,7 @@ import kotlinx.coroutines.Job
import java.util.*
import kotlin.collections.ArrayList
import kotlin.collections.HashMap
import kotlin.math.abs

class GeneratorPlayer : FullScreenPlayer() {
companion object {
Expand Down Expand Up @@ -188,17 +193,31 @@ class GeneratorPlayer : FullScreenPlayer() {
player.addTimeStamps(listOf()) // clear stamps
}

private fun sortLinks(useQualitySettings: Boolean = true): List<Pair<ExtractorLink?, ExtractorUri?>> {
return currentLinks.sortedBy {
val (linkData, _) = it
var quality = linkData?.quality ?: Qualities.Unknown.value
private fun closestQuality(target: Int?): Qualities {
if (target == null) return Qualities.Unknown
return Qualities.values().minBy { abs(it.value - target) }
}

// we set all qualities above current max as reverse
if (useQualitySettings && quality > currentPrefQuality) {
quality = currentPrefQuality - quality - 1
}
// negative because we want to sort highest quality first
-(quality)
private fun getLinkPriority(
qualityProfile: Int,
link: Pair<ExtractorLink?, ExtractorUri?>
): Int {
val (linkData, _) = link

val qualityPriority = QualityDataHelper.getQualityPriority(
qualityProfile,
closestQuality(linkData?.quality)
)
val sourcePriority =
QualityDataHelper.getSourcePriority(qualityProfile, linkData?.name)

// negative because we want to sort highest quality first
return qualityPriority + sourcePriority
}

private fun sortLinks(qualityProfile: Int): List<Pair<ExtractorLink?, ExtractorUri?>> {
return currentLinks.sortedBy {
-getLinkPriority(qualityProfile, it)
}
}

Expand Down Expand Up @@ -584,33 +603,39 @@ class GeneratorPlayer : FullScreenPlayer() {

var sourceIndex = 0
var startSource = 0
var sortedUrls = emptyList<Pair<ExtractorLink?, ExtractorUri?>>()

fun refreshLinks(qualityProfile: Int) {
sortedUrls = sortLinks(qualityProfile)
if (sortedUrls.isEmpty()) {
sourceDialog.findViewById<LinearLayout>(R.id.sort_sources_holder)?.isGone =
true
} else {
startSource = sortedUrls.indexOf(currentSelectedLink)
sourceIndex = startSource

val sourcesArrayAdapter =
ArrayAdapter<String>(ctx, R.layout.sort_bottom_single_choice)

sourcesArrayAdapter.addAll(sortedUrls.map { (link, uri) ->
val name = link?.name ?: uri?.name ?: "NULL"
"$name ${Qualities.getStringByInt(link?.quality)}"
})

providerList.choiceMode = AbsListView.CHOICE_MODE_SINGLE
providerList.adapter = sourcesArrayAdapter
providerList.setSelection(sourceIndex)
providerList.setItemChecked(sourceIndex, true)

val sortedUrls = sortLinks(useQualitySettings = false)
if (sortedUrls.isEmpty()) {
sourceDialog.findViewById<LinearLayout>(R.id.sort_sources_holder)?.isGone = true
} else {
startSource = sortedUrls.indexOf(currentSelectedLink)
sourceIndex = startSource

val sourcesArrayAdapter =
ArrayAdapter<String>(ctx, R.layout.sort_bottom_single_choice)

sourcesArrayAdapter.addAll(sortedUrls.map { (link, uri) ->
val name = link?.name ?: uri?.name ?: "NULL"
"$name ${Qualities.getStringByInt(link?.quality)}"
})

providerList.choiceMode = AbsListView.CHOICE_MODE_SINGLE
providerList.adapter = sourcesArrayAdapter
providerList.setSelection(sourceIndex)
providerList.setItemChecked(sourceIndex, true)

providerList.setOnItemClickListener { _, _, which, _ ->
sourceIndex = which
providerList.setItemChecked(which, true)
providerList.setOnItemClickListener { _, _, which, _ ->
sourceIndex = which
providerList.setItemChecked(which, true)
}
}
}

refreshLinks(currentQualityProfile)

sourceDialog.setOnDismissListener {
if (shouldDismiss) dismiss()
selectSourceDialog = null
Expand Down Expand Up @@ -650,6 +675,29 @@ class GeneratorPlayer : FullScreenPlayer() {
sourceDialog.dismissSafe(activity)
}

fun setProfileName(profile: Int) {
sourceDialog.source_settings_btt.setText(
QualityDataHelper.getProfileName(
profile
)
)
}
setProfileName(currentQualityProfile)

sourceDialog.profiles_click_settings.setOnClickListener {
val activity = activity ?: return@setOnClickListener
QualityProfileDialog(
activity,
R.style.AlertDialogCustomBlack,
currentLinks.mapNotNull { it.first },
currentQualityProfile
) { profile ->
currentQualityProfile = profile.id
setProfileName(profile.id)
refreshLinks(profile.id)
}.show()
}

sourceDialog.subtitles_encoding_format?.apply {
val settingsManager = PreferenceManager.getDefaultSharedPreferences(ctx)

Expand Down Expand Up @@ -847,7 +895,7 @@ class GeneratorPlayer : FullScreenPlayer() {
private fun startPlayer() {
if (isActive) return // we don't want double load when you skip loading

val links = sortLinks()
val links = sortLinks(currentQualityProfile)
if (links.isEmpty()) {
noLinksFound()
return
Expand All @@ -868,12 +916,12 @@ class GeneratorPlayer : FullScreenPlayer() {
}

override fun hasNextMirror(): Boolean {
val links = sortLinks()
val links = sortLinks(currentQualityProfile)
return links.isNotEmpty() && links.indexOf(currentSelectedLink) + 1 < links.size
}

override fun nextMirror() {
val links = sortLinks()
val links = sortLinks(currentQualityProfile)
if (links.isEmpty()) {
noLinksFound()
return
Expand Down Expand Up @@ -1314,6 +1362,15 @@ class GeneratorPlayer : FullScreenPlayer() {
val turnVisible = it.isNotEmpty()
val wasGone = overlay_loading_skip_button?.isGone == true
overlay_loading_skip_button?.isVisible = turnVisible

normalSafeApiCall {
currentLinks.lastOrNull()?.let { last ->
if (getLinkPriority(currentQualityProfile, last) >= QualityDataHelper.AUTO_SKIP_PRIORITY) {
startPlayer()
}
}
}

if (turnVisible && wasGone) {
overlay_loading_skip_button?.requestFocus()
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package com.lagradost.cloudstream3.ui.player.source_priority

import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.lagradost.cloudstream3.R
import com.lagradost.cloudstream3.utils.AppUtils
import kotlinx.android.synthetic.main.player_prioritize_item.view.*

data class SourcePriority<T>(
val data: T,
val name: String,
var priority: Int
)

class PriorityAdapter<T>(override val items: MutableList<SourcePriority<T>>) :
AppUtils.DiffAdapter<SourcePriority<T>>(items) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return PriorityViewHolder(
LayoutInflater.from(parent.context).inflate(R.layout.player_prioritize_item, parent, false)
)
}

override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when (holder) {
is PriorityViewHolder -> holder.bind(items[position])
}
}

class PriorityViewHolder(
itemView: View,
) : RecyclerView.ViewHolder(itemView) {
fun <T> bind(item: SourcePriority<T>) {
val plusButton: ImageView = itemView.add_button
val subtractButton: ImageView = itemView.subtract_button
val priorityText: TextView = itemView.priority_text
val priorityNumber: TextView = itemView.priority_number
priorityText.text = item.name

fun updatePriority() {
priorityNumber.text = item.priority.toString()
}

updatePriority()
plusButton.setOnClickListener {
// If someone clicks til the integer limit then they deserve to crash.
item.priority++
updatePriority()
}

subtractButton.setOnClickListener {
item.priority--
updatePriority()
}
}
}
}
Loading
Loading