mirror of
https://github.com/recloudstream/cloudstream.git
synced 2024-08-15 01:53:11 +00:00
mpv
This commit is contained in:
parent
071004f6c2
commit
c2d245e8b4
7 changed files with 158 additions and 89 deletions
|
@ -24,6 +24,7 @@
|
||||||
<queries>
|
<queries>
|
||||||
<package android:name="org.videolan.vlc" />
|
<package android:name="org.videolan.vlc" />
|
||||||
<package android:name="com.instantbits.cast.webvideo" />
|
<package android:name="com.instantbits.cast.webvideo" />
|
||||||
|
<package android:name="is.xyz.mpv" />
|
||||||
</queries>
|
</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-->
|
||||||
|
|
|
@ -10,16 +10,22 @@ import android.util.Log
|
||||||
import android.view.*
|
import android.view.*
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
|
import androidx.activity.ComponentActivity
|
||||||
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
import androidx.annotation.MainThread
|
import androidx.annotation.MainThread
|
||||||
import androidx.annotation.StringRes
|
import androidx.annotation.StringRes
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.appcompat.widget.SearchView
|
import androidx.appcompat.widget.SearchView
|
||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
import com.google.android.gms.cast.framework.CastSession
|
import com.google.android.gms.cast.framework.CastSession
|
||||||
|
import com.lagradost.cloudstream3.AcraApplication.Companion.getKey
|
||||||
|
import com.lagradost.cloudstream3.AcraApplication.Companion.removeKey
|
||||||
import com.lagradost.cloudstream3.mvvm.logError
|
import com.lagradost.cloudstream3.mvvm.logError
|
||||||
import com.lagradost.cloudstream3.ui.player.PlayerEventType
|
import com.lagradost.cloudstream3.ui.player.PlayerEventType
|
||||||
|
import com.lagradost.cloudstream3.ui.result.ResultFragment
|
||||||
import com.lagradost.cloudstream3.ui.result.UiText
|
import com.lagradost.cloudstream3.ui.result.UiText
|
||||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.updateTv
|
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.updateTv
|
||||||
|
import com.lagradost.cloudstream3.utils.DataStoreHelper
|
||||||
import com.lagradost.cloudstream3.utils.Event
|
import com.lagradost.cloudstream3.utils.Event
|
||||||
import com.lagradost.cloudstream3.utils.UIHelper
|
import com.lagradost.cloudstream3.utils.UIHelper
|
||||||
import com.lagradost.cloudstream3.utils.UIHelper.hasPIPPermission
|
import com.lagradost.cloudstream3.utils.UIHelper.hasPIPPermission
|
||||||
|
@ -34,6 +40,7 @@ object CommonActivity {
|
||||||
return (this as MainActivity?)?.mSessionManager?.currentCastSession
|
return (this as MainActivity?)?.mSessionManager?.currentCastSession
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
var canEnterPipMode: Boolean = false
|
var canEnterPipMode: Boolean = false
|
||||||
var canShowPipMode: Boolean = false
|
var canShowPipMode: Boolean = false
|
||||||
var isInPIPMode: Boolean = false
|
var isInPIPMode: Boolean = false
|
||||||
|
@ -117,7 +124,7 @@ object CommonActivity {
|
||||||
setLocale(this, localeCode)
|
setLocale(this, localeCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun init(act: Activity?) {
|
fun init(act: ComponentActivity?) {
|
||||||
if (act == null) return
|
if (act == null) return
|
||||||
//https://stackoverflow.com/questions/52594181/how-to-know-if-user-has-disabled-picture-in-picture-feature-permission
|
//https://stackoverflow.com/questions/52594181/how-to-know-if-user-has-disabled-picture-in-picture-feature-permission
|
||||||
//https://developer.android.com/guide/topics/ui/picture-in-picture
|
//https://developer.android.com/guide/topics/ui/picture-in-picture
|
||||||
|
@ -129,6 +136,22 @@ object CommonActivity {
|
||||||
act.updateLocale()
|
act.updateLocale()
|
||||||
act.updateTv()
|
act.updateTv()
|
||||||
NewPipe.init(DownloaderTestImpl.getInstance())
|
NewPipe.init(DownloaderTestImpl.getInstance())
|
||||||
|
|
||||||
|
for (resumeApp in resumeApps) {
|
||||||
|
resumeApp.launcher =
|
||||||
|
act.registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
|
||||||
|
val resultCode = result.resultCode
|
||||||
|
val data = result.data
|
||||||
|
if (resultCode == AppCompatActivity.RESULT_OK && data != null && resumeApp.position != null && resumeApp.duration != null) {
|
||||||
|
val pos = data.getLongExtra(resumeApp.position, -1L)
|
||||||
|
val dur = data.getLongExtra(resumeApp.duration, -1L)
|
||||||
|
if (dur > 0L && pos > 0L)
|
||||||
|
DataStoreHelper.setViewPos(getKey(resumeApp.lastId), pos, dur)
|
||||||
|
removeKey(resumeApp.lastId)
|
||||||
|
ResultFragment.updateUI()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun Activity.enterPIPMode() {
|
private fun Activity.enterPIPMode() {
|
||||||
|
|
|
@ -10,7 +10,7 @@ import android.view.KeyEvent
|
||||||
import android.view.Menu
|
import android.view.Menu
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.view.WindowManager
|
import android.view.WindowManager
|
||||||
import android.widget.Toast
|
import androidx.activity.result.ActivityResultLauncher
|
||||||
import androidx.annotation.IdRes
|
import androidx.annotation.IdRes
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
@ -35,6 +35,8 @@ import com.lagradost.cloudstream3.APIHolder.apis
|
||||||
import com.lagradost.cloudstream3.APIHolder.getApiDubstatusSettings
|
import com.lagradost.cloudstream3.APIHolder.getApiDubstatusSettings
|
||||||
import com.lagradost.cloudstream3.APIHolder.initAll
|
import com.lagradost.cloudstream3.APIHolder.initAll
|
||||||
import com.lagradost.cloudstream3.APIHolder.updateHasTrailers
|
import com.lagradost.cloudstream3.APIHolder.updateHasTrailers
|
||||||
|
import com.lagradost.cloudstream3.AcraApplication.Companion.removeKey
|
||||||
|
import com.lagradost.cloudstream3.AcraApplication.Companion.setKey
|
||||||
import com.lagradost.cloudstream3.CommonActivity.loadThemes
|
import com.lagradost.cloudstream3.CommonActivity.loadThemes
|
||||||
import com.lagradost.cloudstream3.CommonActivity.onColorSelectedEvent
|
import com.lagradost.cloudstream3.CommonActivity.onColorSelectedEvent
|
||||||
import com.lagradost.cloudstream3.CommonActivity.onDialogDismissedEvent
|
import com.lagradost.cloudstream3.CommonActivity.onDialogDismissedEvent
|
||||||
|
@ -53,7 +55,6 @@ import com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.appStri
|
||||||
import com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.inAppAuths
|
import com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.inAppAuths
|
||||||
import com.lagradost.cloudstream3.ui.APIRepository
|
import com.lagradost.cloudstream3.ui.APIRepository
|
||||||
import com.lagradost.cloudstream3.ui.download.DOWNLOAD_NAVIGATE_TO
|
import com.lagradost.cloudstream3.ui.download.DOWNLOAD_NAVIGATE_TO
|
||||||
import com.lagradost.cloudstream3.ui.result.ResultFragment
|
|
||||||
import com.lagradost.cloudstream3.ui.search.SearchResultBuilder
|
import com.lagradost.cloudstream3.ui.search.SearchResultBuilder
|
||||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isEmulatorSettings
|
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isEmulatorSettings
|
||||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSettings
|
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSettings
|
||||||
|
@ -67,10 +68,8 @@ import com.lagradost.cloudstream3.utils.AppUtils.loadResult
|
||||||
import com.lagradost.cloudstream3.utils.BackupUtils.setUpBackup
|
import com.lagradost.cloudstream3.utils.BackupUtils.setUpBackup
|
||||||
import com.lagradost.cloudstream3.utils.Coroutines.ioSafe
|
import com.lagradost.cloudstream3.utils.Coroutines.ioSafe
|
||||||
import com.lagradost.cloudstream3.utils.DataStore.getKey
|
import com.lagradost.cloudstream3.utils.DataStore.getKey
|
||||||
import com.lagradost.cloudstream3.utils.DataStore.removeKey
|
|
||||||
import com.lagradost.cloudstream3.utils.DataStore.setKey
|
import com.lagradost.cloudstream3.utils.DataStore.setKey
|
||||||
import com.lagradost.cloudstream3.utils.DataStoreHelper.migrateResumeWatching
|
import com.lagradost.cloudstream3.utils.DataStoreHelper.migrateResumeWatching
|
||||||
import com.lagradost.cloudstream3.utils.DataStoreHelper.setViewPos
|
|
||||||
import com.lagradost.cloudstream3.utils.Event
|
import com.lagradost.cloudstream3.utils.Event
|
||||||
import com.lagradost.cloudstream3.utils.IOnBackPressed
|
import com.lagradost.cloudstream3.utils.IOnBackPressed
|
||||||
import com.lagradost.cloudstream3.utils.InAppUpdater.Companion.runAutoUpdate
|
import com.lagradost.cloudstream3.utils.InAppUpdater.Companion.runAutoUpdate
|
||||||
|
@ -95,18 +94,65 @@ import java.nio.charset.Charset
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
|
|
||||||
|
//https://github.com/videolan/vlc-android/blob/3706c4be2da6800b3d26344fc04fab03ffa4b860/application/vlc-android/src/org/videolan/vlc/gui/video/VideoPlayerActivity.kt#L1898
|
||||||
|
//https://wiki.videolan.org/Android_Player_Intents/
|
||||||
|
|
||||||
|
//https://github.com/mpv-android/mpv-android/blob/0eb3cdc6f1632636b9c30d52ec50e4b017661980/app/src/main/java/is/xyz/mpv/MPVActivity.kt#L904
|
||||||
|
//https://mpv-android.github.io/mpv-android/intent.html
|
||||||
|
|
||||||
|
// https://www.webvideocaster.com/integrations
|
||||||
|
|
||||||
|
//https://github.com/jellyfin/jellyfin-android/blob/6cbf0edf84a3da82347c8d59b5d5590749da81a9/app/src/main/java/org/jellyfin/mobile/bridge/ExternalPlayer.kt#L225
|
||||||
|
|
||||||
const val VLC_PACKAGE = "org.videolan.vlc"
|
const val VLC_PACKAGE = "org.videolan.vlc"
|
||||||
const val VLC_INTENT_ACTION_RESULT = "org.videolan.vlc.player.result"
|
const val MPV_PACKAGE = "is.xyz.mpv"
|
||||||
val VLC_COMPONENT: ComponentName =
|
|
||||||
ComponentName(VLC_PACKAGE, "org.videolan.vlc.gui.video.VideoPlayerActivity")
|
|
||||||
const val VLC_REQUEST_CODE = 42
|
|
||||||
|
|
||||||
const val VLC_EXTRA_POSITION_OUT = "extra_position"
|
|
||||||
const val VLC_EXTRA_DURATION_OUT = "extra_duration"
|
|
||||||
const val VLC_LAST_ID_KEY = "vlc_last_open_id"
|
|
||||||
|
|
||||||
const val WEB_VIDEO_CAST_PACKAGE = "com.instantbits.cast.webvideo"
|
const val WEB_VIDEO_CAST_PACKAGE = "com.instantbits.cast.webvideo"
|
||||||
|
|
||||||
|
val VLC_COMPONENT = ComponentName(VLC_PACKAGE, "$VLC_PACKAGE.gui.video.VideoPlayerActivity")
|
||||||
|
val MPV_COMPONENT = ComponentName(MPV_PACKAGE, "$MPV_PACKAGE.MPVActivity")
|
||||||
|
|
||||||
|
//TODO REFACTOR AF
|
||||||
|
data class ResultResume(
|
||||||
|
val packageString: String,
|
||||||
|
val action: String = Intent.ACTION_VIEW,
|
||||||
|
val position: String? = null,
|
||||||
|
val duration: String? = null,
|
||||||
|
var launcher: ActivityResultLauncher<Intent>? = null,
|
||||||
|
) {
|
||||||
|
val lastId get() = "${packageString}_last_open_id"
|
||||||
|
suspend fun launch(id: Int?, callback: suspend Intent.() -> Unit) {
|
||||||
|
val intent = Intent(action)
|
||||||
|
|
||||||
|
if (id != null)
|
||||||
|
setKey(lastId, id)
|
||||||
|
else
|
||||||
|
removeKey(lastId)
|
||||||
|
|
||||||
|
intent.setPackage(packageString)
|
||||||
|
callback.invoke(intent)
|
||||||
|
launcher?.launch(intent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val VLC = ResultResume(
|
||||||
|
VLC_PACKAGE,
|
||||||
|
"org.videolan.vlc.player.result",
|
||||||
|
"extra_position",
|
||||||
|
"extra_duration",
|
||||||
|
)
|
||||||
|
|
||||||
|
val MPV = ResultResume(
|
||||||
|
MPV_PACKAGE,
|
||||||
|
//"is.xyz.mpv.MPVActivity.result", // resume not working :pensive:
|
||||||
|
position = "position",
|
||||||
|
duration = "duration",
|
||||||
|
)
|
||||||
|
|
||||||
|
val WEB_VIDEO = ResultResume(WEB_VIDEO_CAST_PACKAGE)
|
||||||
|
|
||||||
|
val resumeApps = arrayOf(
|
||||||
|
VLC, MPV, WEB_VIDEO
|
||||||
|
)
|
||||||
|
|
||||||
// Short name for requests client to make it nicer to use
|
// Short name for requests client to make it nicer to use
|
||||||
|
|
||||||
|
@ -373,31 +419,6 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
|
||||||
if (requestCode == VLC_REQUEST_CODE) {
|
|
||||||
if (resultCode == RESULT_OK && data != null) {
|
|
||||||
val pos: Long =
|
|
||||||
data.getLongExtra(
|
|
||||||
VLC_EXTRA_POSITION_OUT,
|
|
||||||
-1
|
|
||||||
) //Last position in media when player exited
|
|
||||||
val dur: Long =
|
|
||||||
data.getLongExtra(
|
|
||||||
VLC_EXTRA_DURATION_OUT,
|
|
||||||
-1
|
|
||||||
) //Last position in media when player exited
|
|
||||||
val id = getKey<Int>(VLC_LAST_ID_KEY)
|
|
||||||
println("SET KEY $id at $pos / $dur")
|
|
||||||
if (dur > 0 && pos > 0) {
|
|
||||||
setViewPos(id, pos, dur)
|
|
||||||
}
|
|
||||||
removeKey(VLC_LAST_ID_KEY)
|
|
||||||
ResultFragment.updateUI()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
super.onActivityResult(requestCode, resultCode, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
val broadcastIntent = Intent()
|
val broadcastIntent = Intent()
|
||||||
broadcastIntent.action = "restart_service"
|
broadcastIntent.action = "restart_service"
|
||||||
|
|
|
@ -56,6 +56,7 @@ const val ACTION_DOWNLOAD_EPISODE_SUBTITLE = 13
|
||||||
const val ACTION_DOWNLOAD_EPISODE_SUBTITLE_MIRROR = 14
|
const val ACTION_DOWNLOAD_EPISODE_SUBTITLE_MIRROR = 14
|
||||||
|
|
||||||
const val ACTION_PLAY_EPISODE_IN_WEB_VIDEO = 16
|
const val ACTION_PLAY_EPISODE_IN_WEB_VIDEO = 16
|
||||||
|
const val ACTION_PLAY_EPISODE_IN_MPV = 17
|
||||||
|
|
||||||
|
|
||||||
data class EpisodeClickEvent(val action: Int, val data: ResultEpisode)
|
data class EpisodeClickEvent(val action: Int, val data: ResultEpisode)
|
||||||
|
@ -71,12 +72,14 @@ class EpisodeAdapter(
|
||||||
* See array.xml/player_pref_values
|
* See array.xml/player_pref_values
|
||||||
**/
|
**/
|
||||||
fun getPlayerAction(context: Context): Int {
|
fun getPlayerAction(context: Context): Int {
|
||||||
|
|
||||||
val settingsManager = PreferenceManager.getDefaultSharedPreferences(context)
|
val settingsManager = PreferenceManager.getDefaultSharedPreferences(context)
|
||||||
return when (settingsManager.getInt(context.getString(R.string.player_pref_key), 1)) {
|
return when (settingsManager.getInt(context.getString(R.string.player_pref_key), 1)) {
|
||||||
1 -> ACTION_PLAY_EPISODE_IN_PLAYER
|
1 -> ACTION_PLAY_EPISODE_IN_PLAYER
|
||||||
2 -> ACTION_PLAY_EPISODE_IN_VLC_PLAYER
|
2 -> ACTION_PLAY_EPISODE_IN_VLC_PLAYER
|
||||||
3 -> ACTION_PLAY_EPISODE_IN_BROWSER
|
3 -> ACTION_PLAY_EPISODE_IN_BROWSER
|
||||||
4 -> ACTION_PLAY_EPISODE_IN_WEB_VIDEO
|
4 -> ACTION_PLAY_EPISODE_IN_WEB_VIDEO
|
||||||
|
5 -> ACTION_PLAY_EPISODE_IN_MPV
|
||||||
else -> ACTION_PLAY_EPISODE_IN_PLAYER
|
else -> ACTION_PLAY_EPISODE_IN_PLAYER
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@ import androidx.lifecycle.viewModelScope
|
||||||
import com.lagradost.cloudstream3.*
|
import com.lagradost.cloudstream3.*
|
||||||
import com.lagradost.cloudstream3.APIHolder.getId
|
import com.lagradost.cloudstream3.APIHolder.getId
|
||||||
import com.lagradost.cloudstream3.APIHolder.unixTime
|
import com.lagradost.cloudstream3.APIHolder.unixTime
|
||||||
|
import com.lagradost.cloudstream3.AcraApplication.Companion.setKey
|
||||||
import com.lagradost.cloudstream3.CommonActivity.getCastSession
|
import com.lagradost.cloudstream3.CommonActivity.getCastSession
|
||||||
import com.lagradost.cloudstream3.CommonActivity.showToast
|
import com.lagradost.cloudstream3.CommonActivity.showToast
|
||||||
import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer
|
import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer
|
||||||
|
@ -43,7 +44,6 @@ import com.lagradost.cloudstream3.utils.Coroutines.ioSafe
|
||||||
import com.lagradost.cloudstream3.utils.Coroutines.ioWork
|
import com.lagradost.cloudstream3.utils.Coroutines.ioWork
|
||||||
import com.lagradost.cloudstream3.utils.Coroutines.ioWorkSafe
|
import com.lagradost.cloudstream3.utils.Coroutines.ioWorkSafe
|
||||||
import com.lagradost.cloudstream3.utils.Coroutines.main
|
import com.lagradost.cloudstream3.utils.Coroutines.main
|
||||||
import com.lagradost.cloudstream3.utils.DataStore.setKey
|
|
||||||
import com.lagradost.cloudstream3.utils.DataStoreHelper.getDub
|
import com.lagradost.cloudstream3.utils.DataStoreHelper.getDub
|
||||||
import com.lagradost.cloudstream3.utils.DataStoreHelper.getResultEpisode
|
import com.lagradost.cloudstream3.utils.DataStoreHelper.getResultEpisode
|
||||||
import com.lagradost.cloudstream3.utils.DataStoreHelper.getResultSeason
|
import com.lagradost.cloudstream3.utils.DataStoreHelper.getResultSeason
|
||||||
|
@ -613,7 +613,7 @@ class ResultViewModel2 : ViewModel() {
|
||||||
val src = "$DOWNLOAD_NAVIGATE_TO/$parentId" // url ?: return@let
|
val src = "$DOWNLOAD_NAVIGATE_TO/$parentId" // url ?: return@let
|
||||||
|
|
||||||
// SET VISUAL KEYS
|
// SET VISUAL KEYS
|
||||||
AcraApplication.setKey(
|
setKey(
|
||||||
DOWNLOAD_HEADER_CACHE,
|
DOWNLOAD_HEADER_CACHE,
|
||||||
parentId.toString(),
|
parentId.toString(),
|
||||||
VideoDownloadHelper.DownloadHeaderCached(
|
VideoDownloadHelper.DownloadHeaderCached(
|
||||||
|
@ -627,7 +627,7 @@ class ResultViewModel2 : ViewModel() {
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
AcraApplication.setKey(
|
setKey(
|
||||||
DataStore.getFolderName(
|
DataStore.getFolderName(
|
||||||
DOWNLOAD_EPISODE_CACHE,
|
DOWNLOAD_EPISODE_CACHE,
|
||||||
parentId.toString()
|
parentId.toString()
|
||||||
|
@ -956,12 +956,16 @@ class ResultViewModel2 : ViewModel() {
|
||||||
|
|
||||||
private fun launchActivity(
|
private fun launchActivity(
|
||||||
activity: Activity?,
|
activity: Activity?,
|
||||||
work: suspend (CoroutineScope.(Activity) -> Unit)
|
resumeApp: ResultResume,
|
||||||
|
id: Int? = null,
|
||||||
|
work: suspend (Intent.(Activity) -> Unit)
|
||||||
): Job? {
|
): Job? {
|
||||||
val act = activity ?: return null
|
val act = activity ?: return null
|
||||||
return CoroutineScope(Dispatchers.IO).launch {
|
return CoroutineScope(Dispatchers.IO).launch {
|
||||||
try {
|
try {
|
||||||
|
resumeApp.launch(id) {
|
||||||
work(act)
|
work(act)
|
||||||
|
}
|
||||||
} catch (t: Throwable) {
|
} catch (t: Throwable) {
|
||||||
logError(t)
|
logError(t)
|
||||||
main {
|
main {
|
||||||
|
@ -981,14 +985,12 @@ class ResultViewModel2 : ViewModel() {
|
||||||
title: String?,
|
title: String?,
|
||||||
posterUrl: String?,
|
posterUrl: String?,
|
||||||
subtitles: List<SubtitleData>
|
subtitles: List<SubtitleData>
|
||||||
) = launchActivity(activity) { act ->
|
) = launchActivity(activity, WEB_VIDEO) {
|
||||||
val shareVideo = Intent(Intent.ACTION_VIEW)
|
setDataAndType(Uri.parse(link.url), "video/*")
|
||||||
|
|
||||||
shareVideo.setDataAndType(Uri.parse(link.url), "video/*")
|
putExtra("subs", subtitles.map { it.url.toUri() }.toTypedArray())
|
||||||
shareVideo.setPackage(WEB_VIDEO_CAST_PACKAGE)
|
title?.let { putExtra("title", title) }
|
||||||
shareVideo.putExtra("subs", subtitles.map { it.url.toUri() }.toTypedArray())
|
posterUrl?.let { putExtra("poster", posterUrl) }
|
||||||
title?.let { shareVideo.putExtra("title", title) }
|
|
||||||
posterUrl?.let { shareVideo.putExtra("poster", posterUrl) }
|
|
||||||
val headers = Bundle().apply {
|
val headers = Bundle().apply {
|
||||||
if (link.referer.isNotBlank())
|
if (link.referer.isNotBlank())
|
||||||
putString("Referer", link.referer)
|
putString("Referer", link.referer)
|
||||||
|
@ -997,10 +999,27 @@ class ResultViewModel2 : ViewModel() {
|
||||||
putString(key, value)
|
putString(key, value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
shareVideo.putExtra("android.media.intent.extra.HTTP_HEADERS", headers)
|
putExtra("android.media.intent.extra.HTTP_HEADERS", headers)
|
||||||
shareVideo.putExtra("secure_uri", true)
|
putExtra("secure_uri", true)
|
||||||
|
}
|
||||||
|
|
||||||
act.startActivity(shareVideo)
|
private fun playWithMpv(
|
||||||
|
activity: Activity?,
|
||||||
|
id: Int,
|
||||||
|
link: ExtractorLink,
|
||||||
|
subtitles: List<SubtitleData>,
|
||||||
|
resume: Boolean = true,
|
||||||
|
) = launchActivity(activity, MPV, id) {
|
||||||
|
putExtra("subs", subtitles.map { it.url.toUri() }.toTypedArray())
|
||||||
|
putExtra("subs.name", subtitles.map { it.name }.toTypedArray())
|
||||||
|
putExtra("subs.filename", subtitles.map { it.name }.toTypedArray())
|
||||||
|
setDataAndType(Uri.parse(link.url), "video/*")
|
||||||
|
component = MPV_COMPONENT
|
||||||
|
putExtra("secure_uri", true)
|
||||||
|
putExtra("return_result", true)
|
||||||
|
val position = getViewPos(id)?.position
|
||||||
|
if (resume && position != null)
|
||||||
|
putExtra("position", position.toInt())
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://wiki.videolan.org/Android_Player_Intents/
|
// https://wiki.videolan.org/Android_Player_Intents/
|
||||||
|
@ -1011,18 +1030,16 @@ class ResultViewModel2 : ViewModel() {
|
||||||
resume: Boolean = true,
|
resume: Boolean = true,
|
||||||
// if it is only a single link then resume works correctly
|
// if it is only a single link then resume works correctly
|
||||||
singleFile: Boolean? = null
|
singleFile: Boolean? = null
|
||||||
) = launchActivity(activity) { act ->
|
) = launchActivity(activity, VLC, id) { act ->
|
||||||
val vlcIntent = Intent(VLC_INTENT_ACTION_RESULT)
|
addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION)
|
||||||
|
addFlags(Intent.FLAG_GRANT_PREFIX_URI_PERMISSION)
|
||||||
|
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||||
|
addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
|
||||||
|
|
||||||
vlcIntent.setPackage(VLC_PACKAGE)
|
|
||||||
vlcIntent.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION)
|
|
||||||
vlcIntent.addFlags(Intent.FLAG_GRANT_PREFIX_URI_PERMISSION)
|
|
||||||
vlcIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
|
||||||
vlcIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
|
|
||||||
val outputDir = act.cacheDir
|
val outputDir = act.cacheDir
|
||||||
|
|
||||||
if (singleFile ?: (data.links.size == 1)) {
|
if (singleFile ?: (data.links.size == 1)) {
|
||||||
vlcIntent.setDataAndType(data.links.first().url.toUri(), "video/*")
|
setDataAndType(data.links.first().url.toUri(), "video/*")
|
||||||
} else {
|
} else {
|
||||||
val outputFile = File.createTempFile("mirrorlist", ".m3u8", outputDir)
|
val outputFile = File.createTempFile("mirrorlist", ".m3u8", outputDir)
|
||||||
|
|
||||||
|
@ -1037,7 +1054,7 @@ class ResultViewModel2 : ViewModel() {
|
||||||
}
|
}
|
||||||
outputFile.writeText(text)
|
outputFile.writeText(text)
|
||||||
|
|
||||||
vlcIntent.setDataAndType(
|
setDataAndType(
|
||||||
FileProvider.getUriForFile(
|
FileProvider.getUriForFile(
|
||||||
act,
|
act,
|
||||||
act.applicationContext.packageName + ".provider",
|
act.applicationContext.packageName + ".provider",
|
||||||
|
@ -1051,33 +1068,14 @@ class ResultViewModel2 : ViewModel() {
|
||||||
} else {
|
} else {
|
||||||
1L
|
1L
|
||||||
}
|
}
|
||||||
vlcIntent.putExtra("from_start", !resume)
|
|
||||||
vlcIntent.putExtra("position", position)
|
|
||||||
//vlcIntent.putExtra("subtitles_location", data.subs.first().url)
|
|
||||||
/*for (s in data.subs) {
|
|
||||||
if (s.origin == SubtitleOrigin.URL) {
|
|
||||||
try {
|
|
||||||
val txt = app.get(s.url, s.headers).text
|
|
||||||
val subtitleFile = File.createTempFile("subtitle1", ".srt", outputDir)
|
|
||||||
subtitleFile.writeText(txt)
|
|
||||||
println("Subtitles::::::${subtitleFile.path}")
|
|
||||||
vlcIntent.putExtra("subtitles_location", FileProvider.getUriForFile(
|
|
||||||
act,
|
|
||||||
act.applicationContext.packageName + ".provider",
|
|
||||||
subtitleFile
|
|
||||||
))
|
|
||||||
break
|
|
||||||
} catch (t : Throwable) {
|
|
||||||
logError(t)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
|
|
||||||
vlcIntent.component = VLC_COMPONENT
|
component = VLC_COMPONENT
|
||||||
act.setKey(VLC_LAST_ID_KEY, id)
|
|
||||||
act.startActivityForResult(vlcIntent, VLC_REQUEST_CODE)
|
putExtra("from_start", !resume)
|
||||||
|
putExtra("position", position)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fun handleAction(activity: Activity?, click: EpisodeClickEvent) =
|
fun handleAction(activity: Activity?, click: EpisodeClickEvent) =
|
||||||
viewModelScope.launchSafe {
|
viewModelScope.launchSafe {
|
||||||
handleEpisodeClickEvent(activity, click)
|
handleEpisodeClickEvent(activity, click)
|
||||||
|
@ -1098,6 +1096,11 @@ class ResultViewModel2 : ViewModel() {
|
||||||
WEB_VIDEO_CAST_PACKAGE,
|
WEB_VIDEO_CAST_PACKAGE,
|
||||||
R.string.player_settings_play_in_web,
|
R.string.player_settings_play_in_web,
|
||||||
ACTION_PLAY_EPISODE_IN_WEB_VIDEO
|
ACTION_PLAY_EPISODE_IN_WEB_VIDEO
|
||||||
|
),
|
||||||
|
ExternalApp(
|
||||||
|
MPV_PACKAGE,
|
||||||
|
R.string.player_settings_play_in_mpv,
|
||||||
|
ACTION_PLAY_EPISODE_IN_MPV
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1329,6 +1332,21 @@ class ResultViewModel2 : ViewModel() {
|
||||||
result.subs
|
result.subs
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
ACTION_PLAY_EPISODE_IN_MPV -> acquireSingleLink(
|
||||||
|
click.data,
|
||||||
|
isCasting = true,
|
||||||
|
txt(
|
||||||
|
R.string.episode_action_play_in_format,
|
||||||
|
txt(R.string.player_settings_play_in_mpv)
|
||||||
|
)
|
||||||
|
) { (result, index) ->
|
||||||
|
playWithMpv(
|
||||||
|
activity,
|
||||||
|
click.data.id,
|
||||||
|
result.links[index],
|
||||||
|
result.subs
|
||||||
|
)
|
||||||
|
}
|
||||||
ACTION_PLAY_EPISODE_IN_PLAYER -> {
|
ACTION_PLAY_EPISODE_IN_PLAYER -> {
|
||||||
val data = currentResponse?.syncData?.toList() ?: emptyList()
|
val data = currentResponse?.syncData?.toList() ?: emptyList()
|
||||||
val list =
|
val list =
|
||||||
|
@ -2107,7 +2125,7 @@ class ResultViewModel2 : ViewModel() {
|
||||||
preferStartEpisode = getResultEpisode(mainId)
|
preferStartEpisode = getResultEpisode(mainId)
|
||||||
preferStartSeason = getResultSeason(mainId)
|
preferStartSeason = getResultSeason(mainId)
|
||||||
|
|
||||||
AcraApplication.setKey(
|
setKey(
|
||||||
DOWNLOAD_HEADER_CACHE,
|
DOWNLOAD_HEADER_CACHE,
|
||||||
mainId.toString(),
|
mainId.toString(),
|
||||||
VideoDownloadHelper.DownloadHeaderCached(
|
VideoDownloadHelper.DownloadHeaderCached(
|
||||||
|
|
|
@ -36,6 +36,7 @@
|
||||||
<array name="player_pref_names">
|
<array name="player_pref_names">
|
||||||
<item>@string/player_settings_play_in_app</item>
|
<item>@string/player_settings_play_in_app</item>
|
||||||
<item>@string/player_settings_play_in_vlc</item>
|
<item>@string/player_settings_play_in_vlc</item>
|
||||||
|
<item>@string/player_settings_play_in_mpv</item>
|
||||||
<item>@string/player_settings_play_in_web</item>
|
<item>@string/player_settings_play_in_web</item>
|
||||||
<item>@string/player_settings_play_in_browser</item>
|
<item>@string/player_settings_play_in_browser</item>
|
||||||
</array>
|
</array>
|
||||||
|
@ -43,6 +44,7 @@
|
||||||
<array name="player_pref_values">
|
<array name="player_pref_values">
|
||||||
<item>1</item>
|
<item>1</item>
|
||||||
<item>2</item>
|
<item>2</item>
|
||||||
|
<item>5</item>
|
||||||
<item>4</item>
|
<item>4</item>
|
||||||
<item>3</item>
|
<item>3</item>
|
||||||
</array>
|
</array>
|
||||||
|
|
|
@ -633,6 +633,7 @@
|
||||||
<string name="player_pref">Preferred video player</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_app">Internal player</string>
|
||||||
<string name="player_settings_play_in_vlc">VLC</string>
|
<string name="player_settings_play_in_vlc">VLC</string>
|
||||||
|
<string name="player_settings_play_in_mpv">MPV</string>
|
||||||
<string name="player_settings_play_in_web">Web Video Cast</string>
|
<string name="player_settings_play_in_web">Web Video Cast</string>
|
||||||
<string name="player_settings_play_in_browser">Browser</string>
|
<string name="player_settings_play_in_browser">Browser</string>
|
||||||
<string name="app_not_found_error">App not found</string>
|
<string name="app_not_found_error">App not found</string>
|
||||||
|
|
Loading…
Reference in a new issue