forked from recloudstream/cloudstream
		
	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…
	
	Add table
		Add a link
		
	
		Reference in a new issue