From a5582a7a67b0e331e1fb406f4cd267ab05128c42 Mon Sep 17 00:00:00 2001
From: IndusAryan <125901294+IndusAryan@users.noreply.github.com>
Date: Tue, 2 Jul 2024 03:04:36 +0530
Subject: [PATCH] feat(ui): ability to play any local video from files using
file chooser (#1158)
---
.../ui/download/DownloadFragment.kt | 44 +++++++++++--
.../ui/player/DownloadedPlayerActivity.kt | 63 ++++---------------
.../cloudstream3/ui/player/LinkGenerator.kt | 9 ++-
.../ui/player/OfflinePlaybackHelper.kt | 43 +++++++++++++
.../main/res/drawable/ic_network_stream.xml | 11 ++++
.../main/res/layout/fragment_downloads.xml | 23 ++++++-
app/src/main/res/values/strings.xml | 1 +
7 files changed, 135 insertions(+), 59 deletions(-)
create mode 100644 app/src/main/java/com/lagradost/cloudstream3/ui/player/OfflinePlaybackHelper.kt
create mode 100644 app/src/main/res/drawable/ic_network_stream.xml
diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/download/DownloadFragment.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/download/DownloadFragment.kt
index de2d4f3c..0186a651 100644
--- a/app/src/main/java/com/lagradost/cloudstream3/ui/download/DownloadFragment.kt
+++ b/app/src/main/java/com/lagradost/cloudstream3/ui/download/DownloadFragment.kt
@@ -1,8 +1,11 @@
package com.lagradost.cloudstream3.ui.download
+import android.app.Activity
import android.app.Dialog
import android.content.ClipboardManager
import android.content.Context
+import android.content.Intent
+import android.content.Intent.FLAG_GRANT_READ_URI_PERMISSION
import android.os.Build
import android.os.Bundle
import android.text.format.Formatter.formatShortFileSize
@@ -12,6 +15,7 @@ import android.view.ViewGroup
import android.widget.LinearLayout
import android.widget.TextView
import android.widget.Toast
+import androidx.activity.result.contract.ActivityResultContracts
import androidx.annotation.StringRes
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.isGone
@@ -30,6 +34,7 @@ import com.lagradost.cloudstream3.ui.download.DownloadButtonSetup.handleDownload
import com.lagradost.cloudstream3.ui.player.BasicLink
import com.lagradost.cloudstream3.ui.player.GeneratorPlayer
import com.lagradost.cloudstream3.ui.player.LinkGenerator
+import com.lagradost.cloudstream3.ui.player.OfflinePlaybackHelper.playUri
import com.lagradost.cloudstream3.ui.result.FOCUS_SELF
import com.lagradost.cloudstream3.ui.result.setLinearListLayout
import com.lagradost.cloudstream3.ui.settings.Globals.TV
@@ -137,9 +142,15 @@ class DownloadFragment : Fragment() {
)
}
- binding?.downloadStreamButton?.apply {
- isGone = isLayout(TV)
- setOnClickListener { showStreamInputDialog(it.context) }
+ binding?.apply {
+ openLocalVideoButton.apply {
+ isGone = isLayout(TV)
+ setOnClickListener { openLocalVideo() }
+ }
+ downloadStreamButton.apply {
+ isGone = isLayout(TV)
+ setOnClickListener { showStreamInputDialog(it.context) }
+ }
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
@@ -189,6 +200,22 @@ class DownloadFragment : Fragment() {
view?.setLayoutWidth(bytes)
}
+ private fun openLocalVideo() {
+ val intent = Intent()
+ .setAction(Intent.ACTION_GET_CONTENT)
+ .setType("video/*")
+ .addCategory(Intent.CATEGORY_OPENABLE)
+ .addFlags(FLAG_GRANT_READ_URI_PERMISSION) // Request temporary access
+ normalSafeApiCall {
+ videoResultLauncher.launch(
+ Intent.createChooser(
+ intent,
+ getString(R.string.open_local_video)
+ )
+ )
+ }
+ }
+
private fun showStreamInputDialog(context: Context) {
val dialog = Dialog(context, R.style.AlertDialogCustom)
val binding = StreamInputBinding.inflate(dialog.layoutInflater)
@@ -247,4 +274,13 @@ class DownloadFragment : Fragment() {
binding?.downloadStreamButton?.extend()
}
}
-}
\ No newline at end of file
+
+ // Open local video from files using content provider x safeFile
+ private val videoResultLauncher = registerForActivityResult(
+ ActivityResultContracts.StartActivityForResult()
+ ) { result ->
+ if (result.resultCode != Activity.RESULT_OK) return@registerForActivityResult
+ val selectedVideoUri = result?.data?.data ?: return@registerForActivityResult
+ playUri(activity ?: return@registerForActivityResult, selectedVideoUri)
+ }
+}
diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/player/DownloadedPlayerActivity.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/player/DownloadedPlayerActivity.kt
index 4d8860f8..4279b542 100644
--- a/app/src/main/java/com/lagradost/cloudstream3/ui/player/DownloadedPlayerActivity.kt
+++ b/app/src/main/java/com/lagradost/cloudstream3/ui/player/DownloadedPlayerActivity.kt
@@ -1,8 +1,6 @@
package com.lagradost.cloudstream3.ui.player
-import android.content.ContentUris
import android.content.Intent
-import android.net.Uri
import android.os.Bundle
import android.util.Log
import android.view.KeyEvent
@@ -10,13 +8,13 @@ import androidx.activity.OnBackPressedCallback
import androidx.appcompat.app.AppCompatActivity
import com.lagradost.cloudstream3.CommonActivity
import com.lagradost.cloudstream3.R
-import com.lagradost.cloudstream3.utils.ExtractorUri
-import com.lagradost.cloudstream3.utils.UIHelper.navigate
-import com.lagradost.safefile.SafeFile
-
-const val DTAG = "PlayerActivity"
+import com.lagradost.cloudstream3.mvvm.normalSafeApiCall
+import com.lagradost.cloudstream3.ui.player.OfflinePlaybackHelper.playLink
+import com.lagradost.cloudstream3.ui.player.OfflinePlaybackHelper.playUri
class DownloadedPlayerActivity : AppCompatActivity() {
+ private val dTAG = "DownloadedPlayerAct"
+
override fun dispatchKeyEvent(event: KeyEvent): Boolean {
CommonActivity.dispatchKeyEvent(this, event)?.let {
return it
@@ -35,53 +33,18 @@ class DownloadedPlayerActivity : AppCompatActivity() {
CommonActivity.onUserLeaveHint(this)
}
- private fun playLink(url: String) {
- this.navigate(
- R.id.global_to_navigation_player, GeneratorPlayer.newInstance(
- LinkGenerator(
- listOf(
- BasicLink(url)
- )
- )
- )
- )
- }
-
- private fun playUri(uri: Uri) {
- val name = SafeFile.fromUri(this, uri)?.name()
- this.navigate(
- R.id.global_to_navigation_player, GeneratorPlayer.newInstance(
- DownloadFileGenerator(
- listOf(
- ExtractorUri(
- uri = uri,
- name = name ?: getString(R.string.downloaded_file),
- // well not the same as a normal id, but we take it as users may want to
- // play downloaded files and save the location
- id = kotlin.runCatching { ContentUris.parseId(uri) }.getOrNull()?.hashCode()
- )
- )
- )
- )
- )
- }
-
override fun onCreate(savedInstanceState: Bundle?) {
- Log.i(DTAG, "onCreate")
-
- CommonActivity.loadThemes(this)
super.onCreate(savedInstanceState)
+ CommonActivity.loadThemes(this)
CommonActivity.init(this)
-
setContentView(R.layout.empty_layout)
+ Log.i(dTAG, "onCreate")
val data = intent.data
if (intent?.action == Intent.ACTION_SEND) {
- val extraText = try { // I dont trust android
+ val extraText = normalSafeApiCall { // I dont trust android
intent.getStringExtra(Intent.EXTRA_TEXT)
- } catch (e: Exception) {
- null
}
val cd = intent.clipData
val item = if (cd != null && cd.itemCount > 0) cd.getItemAt(0) else null
@@ -89,19 +52,19 @@ class DownloadedPlayerActivity : AppCompatActivity() {
// idk what I am doing, just hope any of these work
if (item?.uri != null)
- playUri(item.uri)
+ playUri(this, item.uri)
else if (url != null)
- playLink(url)
+ playLink(this, url)
else if (data != null)
- playUri(data)
+ playUri(this, data)
else if (extraText != null)
- playLink(extraText)
+ playLink(this, extraText)
else {
finish()
return
}
} else if (data?.scheme == "content") {
- playUri(data)
+ playUri(this, data)
} else {
finish()
return
diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/player/LinkGenerator.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/player/LinkGenerator.kt
index ca2d9c81..02f44eb9 100644
--- a/app/src/main/java/com/lagradost/cloudstream3/ui/player/LinkGenerator.kt
+++ b/app/src/main/java/com/lagradost/cloudstream3/ui/player/LinkGenerator.kt
@@ -1,9 +1,12 @@
package com.lagradost.cloudstream3.ui.player
import com.lagradost.cloudstream3.amap
-import com.lagradost.cloudstream3.mvvm.normalSafeApiCall
-import com.lagradost.cloudstream3.utils.*
-import java.net.URI
+import com.lagradost.cloudstream3.utils.ExtractorLink
+import com.lagradost.cloudstream3.utils.ExtractorUri
+import com.lagradost.cloudstream3.utils.INFER_TYPE
+import com.lagradost.cloudstream3.utils.Qualities
+import com.lagradost.cloudstream3.utils.loadExtractor
+import com.lagradost.cloudstream3.utils.unshortenLinkSafe
/**
* Used to open the player more easily with the LinkGenerator
diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/player/OfflinePlaybackHelper.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/player/OfflinePlaybackHelper.kt
new file mode 100644
index 00000000..a52ce160
--- /dev/null
+++ b/app/src/main/java/com/lagradost/cloudstream3/ui/player/OfflinePlaybackHelper.kt
@@ -0,0 +1,43 @@
+package com.lagradost.cloudstream3.ui.player
+
+import android.app.Activity
+import android.content.ContentUris
+import android.net.Uri
+import androidx.core.content.ContextCompat.getString
+import com.lagradost.cloudstream3.R
+import com.lagradost.cloudstream3.utils.ExtractorUri
+import com.lagradost.cloudstream3.utils.UIHelper.navigate
+import com.lagradost.safefile.SafeFile
+
+object OfflinePlaybackHelper {
+ fun playLink(activity: Activity, url: String) {
+ activity.navigate(
+ R.id.global_to_navigation_player, GeneratorPlayer.newInstance(
+ LinkGenerator(
+ listOf(
+ BasicLink(url)
+ )
+ )
+ )
+ )
+ }
+
+ fun playUri(activity: Activity, uri: Uri) {
+ val name = SafeFile.fromUri(activity, uri)?.name()
+ activity.navigate(
+ R.id.global_to_navigation_player, GeneratorPlayer.newInstance(
+ DownloadFileGenerator(
+ listOf(
+ ExtractorUri(
+ uri = uri,
+ name = name ?: getString(activity, R.string.downloaded_file),
+ // well not the same as a normal id, but we take it as users may want to
+ // play downloaded files and save the location
+ id = kotlin.runCatching { ContentUris.parseId(uri) }.getOrNull()?.hashCode()
+ )
+ )
+ )
+ )
+ )
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ic_network_stream.xml b/app/src/main/res/drawable/ic_network_stream.xml
new file mode 100644
index 00000000..8e21fd25
--- /dev/null
+++ b/app/src/main/res/drawable/ic_network_stream.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
diff --git a/app/src/main/res/layout/fragment_downloads.xml b/app/src/main/res/layout/fragment_downloads.xml
index 5623bc7e..9dd07cfd 100644
--- a/app/src/main/res/layout/fragment_downloads.xml
+++ b/app/src/main/res/layout/fragment_downloads.xml
@@ -198,11 +198,30 @@
+
+
+
+
+ app:icon="@drawable/ic_network_stream"
+ android:contentDescription="@string/stream" />
+
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index f577d6e1..b4a2e751 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -151,6 +151,7 @@
%s - %s
Update Started
Network stream
+ Open local video
Error Loading Links
Links Reloaded
Internal Storage