forked from recloudstream/cloudstream
Add option for default media player (Internal, VLC and browser) & fixed VLC detection
This commit is contained in:
parent
03eb17149f
commit
fbbcdb4889
8 changed files with 102 additions and 22 deletions
|
@ -21,6 +21,10 @@
|
||||||
android:name="android.software.leanback"
|
android:name="android.software.leanback"
|
||||||
android:required="false" />
|
android:required="false" />
|
||||||
|
|
||||||
|
<queries>
|
||||||
|
<package android:name="org.videolan.vlc" />
|
||||||
|
</queries>
|
||||||
|
|
||||||
<!--TODO https://stackoverflow.com/questions/41799732/chromecast-button-not-visible-in-android-->
|
<!--TODO https://stackoverflow.com/questions/41799732/chromecast-button-not-visible-in-android-->
|
||||||
<application
|
<application
|
||||||
android:name=".AcraApplication"
|
android:name=".AcraApplication"
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package com.lagradost.cloudstream3.ui.result
|
package com.lagradost.cloudstream3.ui.result
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
|
import android.content.Context
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
@ -9,6 +10,7 @@ import android.widget.TextView
|
||||||
import androidx.core.view.isGone
|
import androidx.core.view.isGone
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import androidx.core.widget.ContentLoadingProgressBar
|
import androidx.core.widget.ContentLoadingProgressBar
|
||||||
|
import androidx.preference.PreferenceManager
|
||||||
import androidx.recyclerview.widget.DiffUtil
|
import androidx.recyclerview.widget.DiffUtil
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.google.android.material.button.MaterialButton
|
import com.google.android.material.button.MaterialButton
|
||||||
|
@ -60,6 +62,22 @@ class EpisodeAdapter(
|
||||||
private val clickCallback: (EpisodeClickEvent) -> Unit,
|
private val clickCallback: (EpisodeClickEvent) -> Unit,
|
||||||
private val downloadClickCallback: (DownloadClickEvent) -> Unit,
|
private val downloadClickCallback: (DownloadClickEvent) -> Unit,
|
||||||
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||||
|
companion object {
|
||||||
|
/**
|
||||||
|
* @return ACTION_PLAY_EPISODE_IN_PLAYER, ACTION_PLAY_EPISODE_IN_BROWSER or ACTION_PLAY_EPISODE_IN_VLC_PLAYER depending on player settings.
|
||||||
|
* See array.xml/player_pref_values
|
||||||
|
**/
|
||||||
|
fun getPlayerAction(context: Context): Int {
|
||||||
|
val settingsManager = PreferenceManager.getDefaultSharedPreferences(context)
|
||||||
|
return when (settingsManager.getInt(context.getString(R.string.player_pref_key), 1)) {
|
||||||
|
1 -> ACTION_PLAY_EPISODE_IN_PLAYER
|
||||||
|
2 -> ACTION_PLAY_EPISODE_IN_VLC_PLAYER
|
||||||
|
3 -> ACTION_PLAY_EPISODE_IN_BROWSER
|
||||||
|
else -> ACTION_PLAY_EPISODE_IN_PLAYER
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var cardList: MutableList<ResultEpisode> = mutableListOf()
|
var cardList: MutableList<ResultEpisode> = mutableListOf()
|
||||||
|
|
||||||
private val mBoundViewHolders: HashSet<DownloadButtonViewHolder> = HashSet()
|
private val mBoundViewHolders: HashSet<DownloadButtonViewHolder> = HashSet()
|
||||||
|
|
|
@ -38,6 +38,7 @@ import com.lagradost.cloudstream3.ui.download.DOWNLOAD_ACTION_DOWNLOAD
|
||||||
import com.lagradost.cloudstream3.ui.download.DownloadButtonSetup.handleDownloadClick
|
import com.lagradost.cloudstream3.ui.download.DownloadButtonSetup.handleDownloadClick
|
||||||
import com.lagradost.cloudstream3.ui.download.EasyDownloadButton
|
import com.lagradost.cloudstream3.ui.download.EasyDownloadButton
|
||||||
import com.lagradost.cloudstream3.ui.quicksearch.QuickSearchFragment
|
import com.lagradost.cloudstream3.ui.quicksearch.QuickSearchFragment
|
||||||
|
import com.lagradost.cloudstream3.ui.result.EpisodeAdapter.Companion.getPlayerAction
|
||||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTrueTvSettings
|
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTrueTvSettings
|
||||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSettings
|
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSettings
|
||||||
import com.lagradost.cloudstream3.utils.*
|
import com.lagradost.cloudstream3.utils.*
|
||||||
|
@ -455,7 +456,8 @@ open class ResultFragment : ResultTrailerPlayer() {
|
||||||
val apiName: String,
|
val apiName: String,
|
||||||
val showFillers: Boolean,
|
val showFillers: Boolean,
|
||||||
val dubStatus: DubStatus,
|
val dubStatus: DubStatus,
|
||||||
val start: AutoResume?
|
val start: AutoResume?,
|
||||||
|
val playerAction: Int
|
||||||
)
|
)
|
||||||
|
|
||||||
private fun getStoredData(context: Context): StoredData? {
|
private fun getStoredData(context: Context): StoredData? {
|
||||||
|
@ -469,6 +471,8 @@ open class ResultFragment : ResultTrailerPlayer() {
|
||||||
) DubStatus.Dubbed else DubStatus.Subbed
|
) DubStatus.Dubbed else DubStatus.Subbed
|
||||||
val startAction = arguments?.getInt(START_ACTION_BUNDLE)
|
val startAction = arguments?.getInt(START_ACTION_BUNDLE)
|
||||||
|
|
||||||
|
val playerAction = getPlayerAction(context)
|
||||||
|
|
||||||
val start = startAction?.let { action ->
|
val start = startAction?.let { action ->
|
||||||
val startValue = arguments?.getInt(START_VALUE_BUNDLE)
|
val startValue = arguments?.getInt(START_VALUE_BUNDLE)
|
||||||
val resumeEpisode = arguments?.getInt(EPISODE_BUNDLE)
|
val resumeEpisode = arguments?.getInt(EPISODE_BUNDLE)
|
||||||
|
@ -483,7 +487,7 @@ open class ResultFragment : ResultTrailerPlayer() {
|
||||||
season = resumeSeason
|
season = resumeSeason
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
return StoredData(url, apiName, showFillers, dubStatus, start)
|
return StoredData(url, apiName, showFillers, dubStatus, start, playerAction)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun reloadViewModel(success: Boolean = false) {
|
private fun reloadViewModel(success: Boolean = false) {
|
||||||
|
@ -774,7 +778,8 @@ open class ResultFragment : ResultTrailerPlayer() {
|
||||||
viewModel.handleAction(
|
viewModel.handleAction(
|
||||||
activity,
|
activity,
|
||||||
EpisodeClickEvent(
|
EpisodeClickEvent(
|
||||||
ACTION_PLAY_EPISODE_IN_PLAYER, value.result
|
storedData?.playerAction ?: ACTION_PLAY_EPISODE_IN_PLAYER,
|
||||||
|
value.result
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,7 @@
|
||||||
package com.lagradost.cloudstream3.ui.result
|
package com.lagradost.cloudstream3.ui.result
|
||||||
|
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.content.ClipData
|
import android.content.*
|
||||||
import android.content.ClipboardManager
|
|
||||||
import android.content.Context
|
|
||||||
import android.content.Intent
|
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
|
@ -33,6 +30,7 @@ import com.lagradost.cloudstream3.ui.player.GeneratorPlayer
|
||||||
import com.lagradost.cloudstream3.ui.player.IGenerator
|
import com.lagradost.cloudstream3.ui.player.IGenerator
|
||||||
import com.lagradost.cloudstream3.ui.player.RepoLinkGenerator
|
import com.lagradost.cloudstream3.ui.player.RepoLinkGenerator
|
||||||
import com.lagradost.cloudstream3.ui.player.SubtitleData
|
import com.lagradost.cloudstream3.ui.player.SubtitleData
|
||||||
|
import com.lagradost.cloudstream3.ui.result.EpisodeAdapter.Companion.getPlayerAction
|
||||||
import com.lagradost.cloudstream3.ui.subtitles.SubtitlesFragment
|
import com.lagradost.cloudstream3.ui.subtitles.SubtitlesFragment
|
||||||
import com.lagradost.cloudstream3.utils.*
|
import com.lagradost.cloudstream3.utils.*
|
||||||
import com.lagradost.cloudstream3.utils.AppUtils.getNameFull
|
import com.lagradost.cloudstream3.utils.AppUtils.getNameFull
|
||||||
|
@ -973,9 +971,11 @@ class ResultViewModel2 : ViewModel() {
|
||||||
File.createTempFile("mirrorlist", ".m3u8", outputDir)
|
File.createTempFile("mirrorlist", ".m3u8", outputDir)
|
||||||
}
|
}
|
||||||
var text = "#EXTM3U"
|
var text = "#EXTM3U"
|
||||||
for (sub in data.subs) {
|
|
||||||
text += "\n#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID=\"subs\",NAME=\"${sub.name}\",DEFAULT=NO,AUTOSELECT=NO,FORCED=NO,LANGUAGE=\"${sub.name}\",URI=\"${sub.url}\""
|
// With subtitles it doesn't work for no reason :(
|
||||||
}
|
// for (sub in data.subs) {
|
||||||
|
// text += "\n#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID=\"subs\",NAME=\"${sub.name}\",DEFAULT=NO,AUTOSELECT=NO,FORCED=NO,LANGUAGE=\"${sub.name}\",URI=\"${sub.url}\""
|
||||||
|
// }
|
||||||
for (link in data.links) {
|
for (link in data.links) {
|
||||||
text += "\n#EXTINF:, ${link.name}\n${link.url}"
|
text += "\n#EXTINF:, ${link.name}\n${link.url}"
|
||||||
}
|
}
|
||||||
|
@ -999,11 +999,10 @@ class ResultViewModel2 : ViewModel() {
|
||||||
|
|
||||||
val startId = VLC_FROM_PROGRESS
|
val startId = VLC_FROM_PROGRESS
|
||||||
|
|
||||||
var position = startId
|
val position = when (startId) {
|
||||||
if (startId == VLC_FROM_START) {
|
VLC_FROM_START -> 1
|
||||||
position = 1
|
VLC_FROM_PROGRESS -> 0
|
||||||
} else if (startId == VLC_FROM_PROGRESS) {
|
else -> 0
|
||||||
position = 0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
vlcIntent.putExtra("position", position)
|
vlcIntent.putExtra("position", position)
|
||||||
|
@ -1013,7 +1012,13 @@ class ResultViewModel2 : ViewModel() {
|
||||||
act.startActivityForResult(vlcIntent, VLC_REQUEST_CODE)
|
act.startActivityForResult(vlcIntent, VLC_REQUEST_CODE)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
logError(e)
|
logError(e)
|
||||||
showToast(act, e.toString(), Toast.LENGTH_LONG)
|
main {
|
||||||
|
if (e is ActivityNotFoundException) {
|
||||||
|
showToast(act, txt(R.string.vlc_not_found_error), Toast.LENGTH_LONG)
|
||||||
|
} else {
|
||||||
|
showToast(act, e.toString(), Toast.LENGTH_LONG)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1073,9 +1078,10 @@ class ResultViewModel2 : ViewModel() {
|
||||||
click.copy(action = ACTION_CHROME_CAST_EPISODE)
|
click.copy(action = ACTION_CHROME_CAST_EPISODE)
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
|
val action = getPlayerAction(ctx)
|
||||||
handleEpisodeClickEvent(
|
handleEpisodeClickEvent(
|
||||||
activity,
|
activity,
|
||||||
click.copy(action = ACTION_PLAY_EPISODE_IN_PLAYER)
|
click.copy(action = action)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1592,7 +1598,8 @@ class ResultViewModel2 : ViewModel() {
|
||||||
val idIndex = ep.key.id
|
val idIndex = ep.key.id
|
||||||
for ((index, i) in ep.value.withIndex()) {
|
for ((index, i) in ep.value.withIndex()) {
|
||||||
val episode = i.episode ?: (index + 1)
|
val episode = i.episode ?: (index + 1)
|
||||||
val id = mainId + episode + idIndex * 1_000_000 + (i.season?.times(10_000) ?: 0)
|
val id =
|
||||||
|
mainId + episode + idIndex * 1_000_000 + (i.season?.times(10_000) ?: 0)
|
||||||
if (!existingEpisodes.contains(id)) {
|
if (!existingEpisodes.contains(id)) {
|
||||||
existingEpisodes.add(id)
|
existingEpisodes.add(id)
|
||||||
val seasonData = loadResponse.seasonNames.getSeason(i.season)
|
val seasonData = loadResponse.seasonNames.getSeason(i.season)
|
||||||
|
@ -1888,7 +1895,10 @@ class ResultViewModel2 : ViewModel() {
|
||||||
if (ep.getWatchProgress() > 0.9) continue
|
if (ep.getWatchProgress() > 0.9) continue
|
||||||
handleAction(
|
handleAction(
|
||||||
activity,
|
activity,
|
||||||
EpisodeClickEvent(ACTION_PLAY_EPISODE_IN_PLAYER, ep)
|
EpisodeClickEvent(
|
||||||
|
getPlayerAction(activity),
|
||||||
|
ep
|
||||||
|
)
|
||||||
)
|
)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -1905,7 +1915,10 @@ class ResultViewModel2 : ViewModel() {
|
||||||
?: return@launchSafe
|
?: return@launchSafe
|
||||||
handleAction(
|
handleAction(
|
||||||
activity,
|
activity,
|
||||||
EpisodeClickEvent(ACTION_PLAY_EPISODE_IN_PLAYER, episode)
|
EpisodeClickEvent(
|
||||||
|
getPlayerAction(activity),
|
||||||
|
episode
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -113,6 +113,22 @@ class SettingsPlayer : PreferenceFragmentCompat() {
|
||||||
return@setOnPreferenceClickListener true
|
return@setOnPreferenceClickListener true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getPref(R.string.player_pref_key)?.setOnPreferenceClickListener {
|
||||||
|
val prefNames = resources.getStringArray(R.array.player_pref_names)
|
||||||
|
val prefValues = resources.getIntArray(R.array.player_pref_values)
|
||||||
|
val current = settingsManager.getInt(getString(R.string.player_pref_key), 1)
|
||||||
|
|
||||||
|
activity?.showBottomDialog(
|
||||||
|
prefNames.toList(),
|
||||||
|
prefValues.indexOf(current),
|
||||||
|
getString(R.string.player_pref),
|
||||||
|
true,
|
||||||
|
{}) {
|
||||||
|
settingsManager.edit().putInt(getString(R.string.player_pref_key), prefValues[it]).apply()
|
||||||
|
}
|
||||||
|
return@setOnPreferenceClickListener true
|
||||||
|
}
|
||||||
|
|
||||||
getPref(R.string.subtitle_settings_key)?.setOnPreferenceClickListener {
|
getPref(R.string.subtitle_settings_key)?.setOnPreferenceClickListener {
|
||||||
SubtitlesFragment.push(activity, false)
|
SubtitlesFragment.push(activity, false)
|
||||||
return@setOnPreferenceClickListener true
|
return@setOnPreferenceClickListener true
|
||||||
|
|
|
@ -33,6 +33,18 @@
|
||||||
<item>6</item>
|
<item>6</item>
|
||||||
</array>
|
</array>
|
||||||
|
|
||||||
|
<array name="player_pref_names">
|
||||||
|
<item>@string/player_settings_play_in_app</item>
|
||||||
|
<item>@string/player_settings_play_in_vlc</item>
|
||||||
|
<item>@string/player_settings_play_in_browser</item>
|
||||||
|
</array>
|
||||||
|
|
||||||
|
<array name="player_pref_values">
|
||||||
|
<item>1</item>
|
||||||
|
<item>2</item>
|
||||||
|
<item>3</item>
|
||||||
|
</array>
|
||||||
|
|
||||||
<array name="limit_title_rez_pref_names">
|
<array name="limit_title_rez_pref_names">
|
||||||
<item>@string/resolution_and_title</item>
|
<item>@string/resolution_and_title</item>
|
||||||
<item>@string/title</item>
|
<item>@string/title</item>
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
<string name="subtitle_settings_key" translatable="false">subtitle_settings_key</string>
|
<string name="subtitle_settings_key" translatable="false">subtitle_settings_key</string>
|
||||||
<string name="subtitle_settings_chromecast_key" translatable="false">subtitle_settings_chromecast_key</string>
|
<string name="subtitle_settings_chromecast_key" translatable="false">subtitle_settings_chromecast_key</string>
|
||||||
<string name="quality_pref_key" translatable="false">quality_pref_key</string>
|
<string name="quality_pref_key" translatable="false">quality_pref_key</string>
|
||||||
|
<string name="player_pref_key" translatable="false">player_pref_key</string>
|
||||||
<string name="prefer_limit_title_key" translatable="false">prefer_limit_title_key</string>
|
<string name="prefer_limit_title_key" translatable="false">prefer_limit_title_key</string>
|
||||||
<string name="prefer_limit_title_rez_key" translatable="false">prefer_limit_title_rez_key</string>
|
<string name="prefer_limit_title_rez_key" translatable="false">prefer_limit_title_rez_key</string>
|
||||||
<string name="video_buffer_size_key" translatable="false">video_buffer_size_key</string>
|
<string name="video_buffer_size_key" translatable="false">video_buffer_size_key</string>
|
||||||
|
@ -628,4 +629,10 @@
|
||||||
<string name="extension_install_first">Install the extension first</string>
|
<string name="extension_install_first">Install the extension first</string>
|
||||||
|
|
||||||
<string name="hls_playlist">HLS Playlist</string>
|
<string name="hls_playlist">HLS Playlist</string>
|
||||||
|
|
||||||
|
<string name="player_pref">Preferred video player</string>
|
||||||
|
<string name="player_settings_play_in_app">Internal player</string>
|
||||||
|
<string name="player_settings_play_in_vlc">VLC</string>
|
||||||
|
<string name="player_settings_play_in_browser">Browser</string>
|
||||||
|
<string name="vlc_not_found_error">VLC not found</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -18,6 +18,11 @@
|
||||||
android:title="@string/watch_quality_pref"
|
android:title="@string/watch_quality_pref"
|
||||||
android:icon="@drawable/ic_baseline_hd_24" />
|
android:icon="@drawable/ic_baseline_hd_24" />
|
||||||
|
|
||||||
|
<Preference
|
||||||
|
android:key="@string/player_pref_key"
|
||||||
|
android:title="@string/player_pref"
|
||||||
|
android:icon="@drawable/netflix_play" />
|
||||||
|
|
||||||
<Preference
|
<Preference
|
||||||
android:key="@string/prefer_limit_title_key"
|
android:key="@string/prefer_limit_title_key"
|
||||||
android:title="@string/limit_title"
|
android:title="@string/limit_title"
|
||||||
|
|
Loading…
Reference in a new issue