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,9 +1012,15 @@ 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) | ||||||
|  |             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) |                     showToast(act, e.toString(), Toast.LENGTH_LONG) | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|     fun handleAction(activity: Activity?, click: EpisodeClickEvent) = viewModelScope.launchSafe { |     fun handleAction(activity: Activity?, click: EpisodeClickEvent) = viewModelScope.launchSafe { | ||||||
|         handleEpisodeClickEvent(activity, click) |         handleEpisodeClickEvent(activity, click) | ||||||
|  | @ -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…
	
	Add table
		Add a link
		
	
		Reference in a new issue