diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 1aeef5550..a04504acd 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -17,7 +17,7 @@ - + @@ -30,13 +30,6 @@ android:name="android.software.leanback" android:required="false" /> - - - - - - - - val resultCode = result.resultCode - val data = result.data - if (resultCode == AppCompatActivity.RESULT_OK && data != null && resumeApp.position != null && resumeApp.duration != null) { - val pos = resumeApp.getPosition(data) - val dur = resumeApp.getDuration(data) - if (dur > 0L && pos > 0L) - DataStoreHelper.setViewPos(getKey(resumeApp.lastId), pos, dur) - removeKey(resumeApp.lastId) - ResultFragment.updateUI() - } - } + MainActivity.activityResultLauncher = componentActivity.registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> + if (result.resultCode == AppCompatActivity.RESULT_OK) { + val actionUid = getKey("last_click_action") ?: return@registerForActivityResult + Log.d(TAG, "Loading action $actionUid result handler") + val action = VideoClickActionHolder.getByUniqueId(actionUid) as? OpenInAppAction ?: return@registerForActivityResult + action.onResult(act, result.data) + removeKey("last_click_action") + removeKey("last_opened_id") + } } // Ask for notification permissions on Android 13 diff --git a/app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt b/app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt index 3581a3d29..fa54545cf 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt @@ -173,7 +173,7 @@ import com.lagradost.cloudstream3.utils.UIHelper.setImage import com.lagradost.cloudstream3.utils.UIHelper.toPx import com.lagradost.cloudstream3.utils.USER_PROVIDER_API import com.lagradost.cloudstream3.utils.USER_SELECTED_HOMEPAGE_API -import com.lagradost.cloudstream3.utils.fcast.FcastManager +import com.lagradost.cloudstream3.actions.temp.fcast.FcastManager import com.lagradost.safefile.SafeFile import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock @@ -186,120 +186,9 @@ import kotlin.math.abs import kotlin.math.absoluteValue import kotlin.system.exitProcess -//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 - class MainActivity : AppCompatActivity(), ColorPickerDialogListener, BiometricCallback { companion object { - const val VLC_PACKAGE = "org.videolan.vlc" - const val MPV_PACKAGE = "is.xyz.mpv" - const val MPV_YTDL_PACKAGE = "is.xyz.mpv.ytdl" - 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") - val MPV_YTDL_COMPONENT = ComponentName(MPV_YTDL_PACKAGE, "$MPV_PACKAGE.MPVActivity") - - //TODO REFACTOR AF - open class ResultResume( - val packageString: String, - val action: String = Intent.ACTION_VIEW, - val position: String? = null, - val duration: String? = null, - var launcher: ActivityResultLauncher? = null, - ) { - val defaultTime = -1L - - 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) - } - - open fun getPosition(intent: Intent?): Long { - return defaultTime - } - - open fun getDuration(intent: Intent?): Long { - return defaultTime - } - } - - val VLC = object : ResultResume( - VLC_PACKAGE, - // Android 13 intent restrictions fucks up specifically launching the VLC player - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) { - "org.videolan.vlc.player.result" - } else { - Intent.ACTION_VIEW - }, - "extra_position", - "extra_duration", - ) { - override fun getPosition(intent: Intent?): Long { - return intent?.getLongExtra(this.position, defaultTime) ?: defaultTime - } - - override fun getDuration(intent: Intent?): Long { - return intent?.getLongExtra(this.duration, defaultTime) ?: defaultTime - } - } - - val MPV = object : ResultResume( - MPV_PACKAGE, - //"is.xyz.mpv.MPVActivity.result", // resume not working :pensive: - position = "position", - duration = "duration", - ) { - override fun getPosition(intent: Intent?): Long { - return intent?.getIntExtra(this.position, defaultTime.toInt())?.toLong() - ?: defaultTime - } - - override fun getDuration(intent: Intent?): Long { - return intent?.getIntExtra(this.duration, defaultTime.toInt())?.toLong() - ?: defaultTime - } - } - - val MPV_YTDL = object : ResultResume( - MPV_YTDL_PACKAGE, - //"is.xyz.mpv.ytdl/is.xyz.mpv.MPVActivity.result", // resume not working :pensive: - position = "position", - duration = "duration", - ) { - override fun getPosition(intent: Intent?): Long { - return intent?.getIntExtra(this.position, defaultTime.toInt())?.toLong() - ?: defaultTime - } - - override fun getDuration(intent: Intent?): Long { - return intent?.getIntExtra(this.duration, defaultTime.toInt())?.toLong() - ?: defaultTime - } - } - - val WEB_VIDEO = ResultResume(WEB_VIDEO_CAST_PACKAGE) - - val resumeApps = arrayOf( - VLC, MPV, MPV_YTDL, WEB_VIDEO - ) - + var activityResultLauncher: ActivityResultLauncher? = null const val TAG = "MAINACT" const val ANIMATED_OUTLINE: Boolean = false diff --git a/app/src/main/java/com/lagradost/cloudstream3/actions/OpenInAppAction.kt b/app/src/main/java/com/lagradost/cloudstream3/actions/OpenInAppAction.kt new file mode 100644 index 000000000..99c1ac38b --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/actions/OpenInAppAction.kt @@ -0,0 +1,134 @@ +package com.lagradost.cloudstream3.actions + +import android.app.Activity +import android.content.ActivityNotFoundException +import android.content.ComponentName +import android.content.Context +import android.content.Intent +import android.widget.Toast +import androidx.core.content.FileProvider +import androidx.core.net.toUri +import com.lagradost.cloudstream3.AcraApplication.Companion.getKey +import com.lagradost.cloudstream3.AcraApplication.Companion.setKey +import com.lagradost.cloudstream3.CommonActivity.showToast +import com.lagradost.cloudstream3.MainActivity.Companion.activityResultLauncher +import com.lagradost.cloudstream3.R +import com.lagradost.cloudstream3.mvvm.logError +import com.lagradost.cloudstream3.ui.result.LinkLoadingResult +import com.lagradost.cloudstream3.ui.result.ResultEpisode +import com.lagradost.cloudstream3.ui.result.ResultFragment +import com.lagradost.cloudstream3.ui.result.UiText +import com.lagradost.cloudstream3.ui.result.txt +import com.lagradost.cloudstream3.utils.AppContextUtils.isAppInstalled +import com.lagradost.cloudstream3.utils.DataStoreHelper +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import java.io.File + +fun updateDurationAndPosition(position: Long, duration: Long) { + if (position <= 0 || duration <= 0) return + DataStoreHelper.setViewPos(getKey("last_opened_id"), position, duration) + ResultFragment.updateUI() +} + +/** + * Util method that may be helpful for creating intents for apps that support m3u8 files. + * All sources are written to a temporary m3u8 file, which is then sent to the app. + */ +fun makeTempM3U8Intent( + context: Context, + intent: Intent, + result: LinkLoadingResult) { + intent.apply { + 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) + } + + val outputDir = context.cacheDir + + if (result.links.size == 1) { + intent.setDataAndType(result.links.first().url.toUri(), "video/*") + } else { + val outputFile = File.createTempFile("mirrorlist", ".m3u8", outputDir) + + var text = "#EXTM3U\n#EXT-X-VERSION:3" + + result.links.forEachIndexed { index, link -> + text += "\n#EXTINF:$index,${link.name}\n${link.url}" + } + + //With subtitles it doesn't work for no reason :( + /*for (sub in result.subs) { + val normalizedName = sub.name.replace("[^a-zA-Z0-9 ]".toRegex(), "") + text += "\n#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID=\"subs\",NAME=\"${normalizedName}\",DEFAULT=NO,AUTOSELECT=NO,FORCED=NO,LANGUAGE=\"${sub.languageCode}\",URI=\"${sub.url}\"" + }*/ + + text += "\n#EXT-X-ENDLIST" + + outputFile.writeText(text) + + intent.setDataAndType( + FileProvider.getUriForFile( + context, + context.applicationContext.packageName + ".provider", + outputFile + ), "application/x-mpegURL" + ) + } +} + +abstract class OpenInAppAction( + open val appName: UiText, + open val packageName: String, + private val intentClass: String? = null, + private val action: String = Intent.ACTION_VIEW +): VideoClickAction() { + override val name: UiText + get() = txt(R.string.episode_action_play_in_format, appName) + + override val isPlayer = true + + override fun shouldShow(context: Context?, video: ResultEpisode?) = context?.isAppInstalled(packageName) == true + + override fun runAction( + context: Context?, + video: ResultEpisode, + result: LinkLoadingResult, + index: Int? + ) { + if (context == null) return + val intent = Intent(action) + intent.setPackage(packageName) + if (intentClass != null) { + intent.component = ComponentName(packageName, intentClass) + } + putExtra(context, intent, video, result, index) + setKey("last_opened_id", video.id) + try { + CoroutineScope(Dispatchers.IO).launch { + activityResultLauncher?.launch(intent) + } + } catch (_: ActivityNotFoundException) { + showToast(R.string.app_not_found_error, Toast.LENGTH_LONG) + } catch (t: Throwable) { + logError(t) + showToast(t.toString(), Toast.LENGTH_LONG) + } + } + + /** + * Before intent is sent, this function is called to put extra data into the intent. + * @see VideoClickAction.runAction + * */ + abstract fun putExtra(context: Context, intent: Intent, video: ResultEpisode, result: LinkLoadingResult, index: Int?) + + /** + * This function is called when the app is opened again after the intent was sent. + * You can use it to for example update duration and position. + * @see updateDurationAndPosition + */ + abstract fun onResult(activity: Activity, intent: Intent?) +} \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/actions/VideoClickAction.kt b/app/src/main/java/com/lagradost/cloudstream3/actions/VideoClickAction.kt new file mode 100644 index 000000000..f66ed74d9 --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/actions/VideoClickAction.kt @@ -0,0 +1,87 @@ +package com.lagradost.cloudstream3.actions + +import android.app.Activity +import android.content.Context +import com.lagradost.api.Log +import com.lagradost.cloudstream3.actions.temp.CopyClipboardAction +import com.lagradost.cloudstream3.actions.temp.MpvKtPackage +import com.lagradost.cloudstream3.actions.temp.MpvKtPreviewPackage +import com.lagradost.cloudstream3.actions.temp.MpvPackage +import com.lagradost.cloudstream3.actions.temp.MpvYTDLPackage +import com.lagradost.cloudstream3.actions.temp.PlayInBrowserAction +import com.lagradost.cloudstream3.actions.temp.ViewM3U8Action +import com.lagradost.cloudstream3.actions.temp.VlcPackage +import com.lagradost.cloudstream3.actions.temp.WebVideoCastPackage +import com.lagradost.cloudstream3.actions.temp.fcast.FcastAction +import com.lagradost.cloudstream3.ui.result.LinkLoadingResult +import com.lagradost.cloudstream3.ui.result.ResultEpisode +import com.lagradost.cloudstream3.ui.result.UiText +import com.lagradost.cloudstream3.utils.Coroutines.threadSafeListOf +import com.lagradost.cloudstream3.utils.ExtractorLinkType +import kotlin.reflect.jvm.jvmName + +object VideoClickActionHolder { + val allVideoClickActions = threadSafeListOf( + PlayInBrowserAction(), CopyClipboardAction(), + VlcPackage(), ViewM3U8Action(), + MpvPackage(), MpvYTDLPackage(), + WebVideoCastPackage(), MpvKtPackage(), MpvKtPreviewPackage(), + FcastAction() + ) + + init { + Log.d("VideoClickActionHolder", "allVideoClickActions: ${allVideoClickActions.map { it.uniqueId() }}") + } + + private const val ACTION_ID_OFFSET = 1000 + + fun makeOptionMap(activity: Activity?, video: ResultEpisode) = allVideoClickActions + // We need to have index before filtering + .mapIndexed { id, it -> it to id + ACTION_ID_OFFSET } + .filter { it.first.shouldShow(activity, video) } + .map { it.first.name to it.second } + + + fun getActionById(id: Int): VideoClickAction? = allVideoClickActions.getOrNull(id - ACTION_ID_OFFSET) + + fun getByUniqueId(uniqueId: String): VideoClickAction? = allVideoClickActions.firstOrNull { it.uniqueId() == uniqueId } + + fun uniqueIdToId(uniqueId: String?): Int? { + if (uniqueId == null) return null + return allVideoClickActions + .mapIndexed { id, it -> it to id + ACTION_ID_OFFSET } + .firstOrNull { it.first.uniqueId() == uniqueId } + ?.second + } + + fun getPlayers(activity: Activity? = null) = allVideoClickActions.filter { it.isPlayer && it.shouldShow(activity, null) } +} + +abstract class VideoClickAction { + abstract val name: UiText + + /** if true, the app will show dialog to select source - result.links[index] */ + open val oneSource : Boolean = false + + /** if true, this action could be selected as default player (one press action) in settings */ + open val isPlayer: Boolean = false + + /** Which type of sources this action can handle. */ + open val sourceTypes: Set = ExtractorLinkType.entries.toSet() + + /** Determines which plugin a given provider is from. This is the full path to the plugin. */ + var sourcePlugin: String? = null + + fun uniqueId() = "$sourcePlugin:${this::class.jvmName}" + + abstract fun shouldShow(context: Context?, video: ResultEpisode?): Boolean + + /** + * This function is called when the action is clicked. + * @param context The current activity + * @param video The episode/movie that was clicked + * @param result The result of the link loading, contains video & subtitle links + * @param index if oneSource is true, this is the index of the selected source + */ + abstract fun runAction(context: Context?, video: ResultEpisode, result: LinkLoadingResult, index: Int?) +} \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/actions/temp/CopyClipboardAction.kt b/app/src/main/java/com/lagradost/cloudstream3/actions/temp/CopyClipboardAction.kt new file mode 100644 index 000000000..e054b5ce2 --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/actions/temp/CopyClipboardAction.kt @@ -0,0 +1,27 @@ +package com.lagradost.cloudstream3.actions.temp + +import android.content.Context +import com.lagradost.cloudstream3.actions.VideoClickAction +import com.lagradost.cloudstream3.ui.result.LinkLoadingResult +import com.lagradost.cloudstream3.ui.result.ResultEpisode +import com.lagradost.cloudstream3.ui.result.txt +import com.lagradost.cloudstream3.utils.UIHelper.clipboardHelper + +class CopyClipboardAction: VideoClickAction() { + override val name = txt("Copy to clipboard") + + override val oneSource = true + + override fun shouldShow(context: Context?, video: ResultEpisode?) = true + + override fun runAction( + context: Context?, + video: ResultEpisode, + result: LinkLoadingResult, + index: Int? + ) { + if (index == null) return + val link = result.links.getOrNull(index) ?: return + clipboardHelper(txt(link.name), link.url) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/actions/temp/MpvKtPackage.kt b/app/src/main/java/com/lagradost/cloudstream3/actions/temp/MpvKtPackage.kt new file mode 100644 index 000000000..f5ded49b8 --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/actions/temp/MpvKtPackage.kt @@ -0,0 +1,69 @@ +package com.lagradost.cloudstream3.actions.temp + +import android.app.Activity +import android.content.Context +import android.content.Intent +import android.net.Uri +import androidx.core.net.toUri +import com.lagradost.cloudstream3.actions.OpenInAppAction +import com.lagradost.cloudstream3.actions.updateDurationAndPosition +import com.lagradost.cloudstream3.ui.result.LinkLoadingResult +import com.lagradost.cloudstream3.ui.result.ResultEpisode +import com.lagradost.cloudstream3.ui.result.txt +import com.lagradost.cloudstream3.utils.DataStoreHelper.getViewPos +import com.lagradost.cloudstream3.utils.ExtractorLinkType + +class MpvKtPreviewPackage: MpvKtPackage( + appName = "mpvKt Preview", + packageName = "live.mehiz.mpvkt.preview", +) + +open class MpvKtPackage( + appName: String = "mpvKt", + packageName: String = "live.mehiz.mpvkt", +): OpenInAppAction( + appName = txt(appName), + packageName = packageName, + intentClass = "live.mehiz.mpvkt.ui.player.PlayerActivity" +) { + override val oneSource = true + + override val sourceTypes = setOf( + ExtractorLinkType.VIDEO, + ExtractorLinkType.DASH, + ExtractorLinkType.M3U8 + ) + + override fun putExtra( + context: Context, + intent: Intent, + video: ResultEpisode, + result: LinkLoadingResult, + index: Int? + ) { + val link = result.links.getOrNull(index ?: 0) ?: return + + intent.apply { + putExtra("subs", result.subs.map { it.url.toUri() }.toTypedArray()) + setDataAndType(Uri.parse(link.url), "video/*") + + // m3u8 plays, but changing sources feature is not available + // makeTempM3U8Intent(activity, this, result) + + //putExtra("headers", link.headers.flatMap { listOf(it.key, it.value) }.toTypedArray()) + + val position = getViewPos(video.id)?.position + if (position != null) + putExtra("position", position.toInt()) + + putExtra("secure_uri", true) + } + } + + override fun onResult(activity: Activity, intent: Intent?) { + val position = intent?.getIntExtra("position", -1)?.toLong() ?: -1 + val duration = intent?.getIntExtra("duration", -1)?.toLong() ?: -1 + updateDurationAndPosition(position, duration) + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/actions/temp/MpvPackage.kt b/app/src/main/java/com/lagradost/cloudstream3/actions/temp/MpvPackage.kt new file mode 100644 index 000000000..4c66d0450 --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/actions/temp/MpvPackage.kt @@ -0,0 +1,61 @@ +package com.lagradost.cloudstream3.actions.temp + +import android.app.Activity +import android.content.Context +import android.content.Intent +import androidx.core.net.toUri +import com.lagradost.api.Log +import com.lagradost.cloudstream3.actions.OpenInAppAction +import com.lagradost.cloudstream3.actions.makeTempM3U8Intent +import com.lagradost.cloudstream3.actions.updateDurationAndPosition +import com.lagradost.cloudstream3.ui.result.LinkLoadingResult +import com.lagradost.cloudstream3.ui.result.ResultEpisode +import com.lagradost.cloudstream3.ui.result.txt +import com.lagradost.cloudstream3.utils.DataStoreHelper.getViewPos +import com.lagradost.cloudstream3.utils.ExtractorLinkType + +// 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 + +class MpvYTDLPackage : MpvPackage("MPV YTDL", "is.xyz.mpv.ytdl") { + override val sourceTypes = setOf( + ExtractorLinkType.VIDEO, + ExtractorLinkType.DASH, + ExtractorLinkType.M3U8 + ) +} + +open class MpvPackage(appName: String = "MPV", packageName: String = "is.xyz.mpv"): OpenInAppAction( + txt(appName), + packageName, + "is.xyz.mpv.MPVActivity" +) { + + override fun putExtra( + context: Context, + intent: Intent, + video: ResultEpisode, + result: LinkLoadingResult, + index: Int? + ) { + intent.apply { + putExtra("subs", result.subs.map { it.url.toUri() }.toTypedArray()) + putExtra("title", video.name) + + makeTempM3U8Intent(context, this, result) + + val position = getViewPos(video.id)?.position + if (position != null) + putExtra("position", position.toInt()) + + putExtra("secure_uri", true) + } + } + + override fun onResult(activity: Activity, intent: Intent?) { + val position = intent?.getIntExtra("position", -1) ?: -1 + val duration = intent?.getIntExtra("duration", -1) ?: -1 + Log.d("MPV", "Position: $position, Duration: $duration") + updateDurationAndPosition(position.toLong(), duration.toLong()) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/actions/temp/PlayInBrowserAction.kt b/app/src/main/java/com/lagradost/cloudstream3/actions/temp/PlayInBrowserAction.kt new file mode 100644 index 000000000..de32bb4b3 --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/actions/temp/PlayInBrowserAction.kt @@ -0,0 +1,44 @@ +package com.lagradost.cloudstream3.actions.temp + +import android.content.Context +import android.content.Intent +import android.net.Uri +import com.lagradost.cloudstream3.R +import com.lagradost.cloudstream3.actions.VideoClickAction +import com.lagradost.cloudstream3.mvvm.logError +import com.lagradost.cloudstream3.ui.result.LinkLoadingResult +import com.lagradost.cloudstream3.ui.result.ResultEpisode +import com.lagradost.cloudstream3.ui.result.txt +import com.lagradost.cloudstream3.utils.ExtractorLinkType + +class PlayInBrowserAction: VideoClickAction() { + override val name = txt(R.string.episode_action_play_in_format, "Browser") + + override val oneSource = true + + override val isPlayer = true + + override val sourceTypes: Set = setOf( + ExtractorLinkType.VIDEO, + ExtractorLinkType.DASH, + ExtractorLinkType.M3U8 + ) + + override fun shouldShow(context: Context?, video: ResultEpisode?) = true + + override fun runAction( + context: Context?, + video: ResultEpisode, + result: LinkLoadingResult, + index: Int? + ) { + val link = result.links.getOrNull(index ?: 0) ?: return + try { + val i = Intent(Intent.ACTION_VIEW) + i.data = Uri.parse(link.url) + context?.startActivity(i) + } catch (e: Exception) { + logError(e) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/actions/temp/ViewM3U8Action.kt b/app/src/main/java/com/lagradost/cloudstream3/actions/temp/ViewM3U8Action.kt new file mode 100644 index 000000000..c14168e96 --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/actions/temp/ViewM3U8Action.kt @@ -0,0 +1,30 @@ +package com.lagradost.cloudstream3.actions.temp + +import android.content.Context +import android.content.Intent +import com.lagradost.cloudstream3.R +import com.lagradost.cloudstream3.actions.VideoClickAction +import com.lagradost.cloudstream3.actions.makeTempM3U8Intent +import com.lagradost.cloudstream3.ui.result.LinkLoadingResult +import com.lagradost.cloudstream3.ui.result.ResultEpisode +import com.lagradost.cloudstream3.ui.result.txt + +class ViewM3U8Action: VideoClickAction() { + override val name = txt(R.string.episode_action_play_in_format, "m3u8 player") + + override val isPlayer = true + + override fun shouldShow(context: Context?, video: ResultEpisode?) = true + + override fun runAction( + context: Context?, + video: ResultEpisode, + result: LinkLoadingResult, + index: Int? + ) { + if (context == null) return + val i = Intent(Intent.ACTION_VIEW) + makeTempM3U8Intent(context, i, result) + context.startActivity(i) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/actions/temp/VlcPackage.kt b/app/src/main/java/com/lagradost/cloudstream3/actions/temp/VlcPackage.kt new file mode 100644 index 000000000..ecb37fdc6 --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/actions/temp/VlcPackage.kt @@ -0,0 +1,68 @@ +package com.lagradost.cloudstream3.actions.temp + +import android.app.Activity +import android.content.Context +import android.content.Intent +import android.os.Build +import com.lagradost.api.Log +import com.lagradost.cloudstream3.AcraApplication.Companion.getKey +import com.lagradost.cloudstream3.actions.OpenInAppAction +import com.lagradost.cloudstream3.actions.makeTempM3U8Intent +import com.lagradost.cloudstream3.actions.updateDurationAndPosition +import com.lagradost.cloudstream3.ui.result.LinkLoadingResult +import com.lagradost.cloudstream3.ui.result.ResultEpisode +import com.lagradost.cloudstream3.ui.result.txt +import com.lagradost.cloudstream3.ui.subtitles.SUBTITLE_AUTO_SELECT_KEY +import com.lagradost.cloudstream3.utils.DataStoreHelper.getViewPos + +// 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/ + +class VlcPackage: OpenInAppAction( + appName = txt("VLC"), + packageName = "org.videolan.vlc", + intentClass = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) { + "org.videolan.vlc.gui.video.VideoPlayerActivity" + } else { + null + }, + action = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) { + "org.videolan.vlc.player.result" + } else { + Intent.ACTION_VIEW + } +) { + override val oneSource = false + + override fun putExtra( + context: Context, + intent: Intent, + video: ResultEpisode, + result: LinkLoadingResult, + index: Int? + ) { + + makeTempM3U8Intent(context, intent, result) + + val position = getViewPos(video.id)?.position ?: 0L + + intent.putExtra("from_start", false) + intent.putExtra("position", position) + intent.putExtra("secure_uri", true) + intent.putExtra("title", video.name) + + val subsLang = getKey(SUBTITLE_AUTO_SELECT_KEY) ?: "en" + result.subs.firstOrNull { + subsLang == it.languageCode + }?.let { + intent.putExtra("subtitles_location", it.url) + } + } + + override fun onResult(activity: Activity, intent: Intent?) { + val position = intent?.getLongExtra("extra_position", -1) ?: -1 + val duration = intent?.getLongExtra("extra_duration", -1) ?: -1 + Log.d("VLC", "Position: $position, Duration: $duration") + updateDurationAndPosition(position, duration) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/actions/temp/WebVideoCastPackage.kt b/app/src/main/java/com/lagradost/cloudstream3/actions/temp/WebVideoCastPackage.kt new file mode 100644 index 000000000..f8419f63c --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/actions/temp/WebVideoCastPackage.kt @@ -0,0 +1,62 @@ +package com.lagradost.cloudstream3.actions.temp + +import android.app.Activity +import android.content.Context +import android.content.Intent +import android.net.Uri +import android.os.Bundle +import androidx.core.net.toUri +import com.lagradost.cloudstream3.USER_AGENT +import com.lagradost.cloudstream3.actions.OpenInAppAction +import com.lagradost.cloudstream3.ui.result.LinkLoadingResult +import com.lagradost.cloudstream3.ui.result.ResultEpisode +import com.lagradost.cloudstream3.ui.result.txt +import com.lagradost.cloudstream3.utils.ExtractorLinkType + +// https://www.webvideocaster.com/integrations + +class WebVideoCastPackage: OpenInAppAction( + txt("Web Video Cast"), + "com.instantbits.cast.webvideo" +) { + + override val oneSource = true + + override val sourceTypes = setOf( + ExtractorLinkType.VIDEO, + ExtractorLinkType.DASH, + ExtractorLinkType.M3U8 + ) + + override fun putExtra( + context: Context, + intent: Intent, + video: ResultEpisode, + result: LinkLoadingResult, + index: Int? + ) { + val link = result.links[index ?: 0] + + intent.apply { + setDataAndType(Uri.parse(link.url), "video/*") + + val title = video.name ?: video.headerName + + putExtra("subs", result.subs.map { it.url.toUri() }.toTypedArray()) + putExtra("title", title) + video.poster?.let { putExtra("poster", it) } + val headers = Bundle().apply { + if (link.referer.isNotBlank()) + putString("Referer", link.referer) + putString("User-Agent", USER_AGENT) + for ((key, value) in link.headers) { + putString(key, value) + } + } + putExtra("android.media.intent.extra.HTTP_HEADERS", headers) + putExtra("secure_uri", true) + } + } + + override fun onResult(activity: Activity, intent: Intent?) = Unit +} \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/actions/temp/fcast/FcastAction.kt b/app/src/main/java/com/lagradost/cloudstream3/actions/temp/fcast/FcastAction.kt new file mode 100644 index 000000000..c0f92e4df --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/actions/temp/fcast/FcastAction.kt @@ -0,0 +1,67 @@ +package com.lagradost.cloudstream3.actions.temp.fcast + +import android.content.Context +import com.lagradost.cloudstream3.AcraApplication.Companion.getActivity +import com.lagradost.cloudstream3.R +import com.lagradost.cloudstream3.USER_AGENT +import com.lagradost.cloudstream3.actions.VideoClickAction +import com.lagradost.cloudstream3.ui.result.LinkLoadingResult +import com.lagradost.cloudstream3.ui.result.ResultEpisode +import com.lagradost.cloudstream3.ui.result.txt +import com.lagradost.cloudstream3.utils.DataStoreHelper.getViewPos +import com.lagradost.cloudstream3.utils.ExtractorLink +import com.lagradost.cloudstream3.utils.ExtractorLinkType +import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showBottomDialog + +class FcastAction: VideoClickAction() { + override val name = txt("Fcast to device") + + override val oneSource = true + + override val sourceTypes = setOf( + ExtractorLinkType.VIDEO, + ExtractorLinkType.DASH, + ExtractorLinkType.M3U8 + ) + + override fun shouldShow(context: Context?, video: ResultEpisode?) = FcastManager.currentDevices.isNotEmpty() + + override fun runAction( + context: Context?, + video: ResultEpisode, + result: LinkLoadingResult, + index: Int? + ) { + val link = result.links.getOrNull(index ?: 0) ?: return + val devices = FcastManager.currentDevices.toList() + context?.getActivity()?.showBottomDialog( + devices.map { it.name }, + -1, + txt(R.string.player_settings_select_cast_device).asString(context), + false, + {}) { + val position = getViewPos(video.id)?.position + castTo(devices.getOrNull(it), link, position) + } + } + + + private fun castTo(device: PublicDeviceInfo?, link: ExtractorLink, position: Long?) { + val host = device?.host ?: return + + FcastSession(host).use { session -> + session.sendMessage( + Opcode.Play, + PlayMessage( + "video/*", + link.url, + time = position?.let { it / 1000.0 }, + headers = mapOf( + "referer" to link.referer, + "user-agent" to USER_AGENT + ) + link.headers + ) + ) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/fcast/FcastManager.kt b/app/src/main/java/com/lagradost/cloudstream3/actions/temp/fcast/FcastManager.kt similarity index 98% rename from app/src/main/java/com/lagradost/cloudstream3/utils/fcast/FcastManager.kt rename to app/src/main/java/com/lagradost/cloudstream3/actions/temp/fcast/FcastManager.kt index e7c36a872..78682ca1c 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/fcast/FcastManager.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/actions/temp/fcast/FcastManager.kt @@ -1,4 +1,4 @@ -package com.lagradost.cloudstream3.utils.fcast +package com.lagradost.cloudstream3.actions.temp.fcast import android.content.Context import android.net.nsd.NsdManager diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/fcast/FcastSession.kt b/app/src/main/java/com/lagradost/cloudstream3/actions/temp/fcast/FcastSession.kt similarity index 96% rename from app/src/main/java/com/lagradost/cloudstream3/utils/fcast/FcastSession.kt rename to app/src/main/java/com/lagradost/cloudstream3/actions/temp/fcast/FcastSession.kt index 1f33bca43..326d11191 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/fcast/FcastSession.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/actions/temp/fcast/FcastSession.kt @@ -1,4 +1,4 @@ -package com.lagradost.cloudstream3.utils.fcast +package com.lagradost.cloudstream3.actions.temp.fcast import android.util.Log import androidx.annotation.WorkerThread diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/fcast/Packets.kt b/app/src/main/java/com/lagradost/cloudstream3/actions/temp/fcast/Packets.kt similarity index 95% rename from app/src/main/java/com/lagradost/cloudstream3/utils/fcast/Packets.kt rename to app/src/main/java/com/lagradost/cloudstream3/actions/temp/fcast/Packets.kt index 61c00d6ed..26f5cec53 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/fcast/Packets.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/actions/temp/fcast/Packets.kt @@ -1,4 +1,4 @@ -package com.lagradost.cloudstream3.utils.fcast +package com.lagradost.cloudstream3.actions.temp.fcast // See https://gitlab.com/futo-org/fcast/-/wikis/Protocol-version-1 enum class Opcode(val value: Byte) { diff --git a/app/src/main/java/com/lagradost/cloudstream3/plugins/Plugin.kt b/app/src/main/java/com/lagradost/cloudstream3/plugins/Plugin.kt index fc8365876..e35ae24b9 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/plugins/Plugin.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/plugins/Plugin.kt @@ -9,6 +9,8 @@ import com.lagradost.cloudstream3.utils.ExtractorApi import com.lagradost.cloudstream3.utils.extractorApis import android.util.Log import com.fasterxml.jackson.annotation.JsonProperty +import com.lagradost.cloudstream3.actions.VideoClickAction +import com.lagradost.cloudstream3.actions.VideoClickActionHolder const val PLUGIN_TAG = "PluginInstance" @@ -52,6 +54,18 @@ abstract class Plugin { extractorApis.add(element) } + /** + * Used to register VideoClickAction instances + * @param element VideoClickAction you want to register + */ + fun registerVideoClickAction(element: VideoClickAction) { + Log.i(PLUGIN_TAG, "Adding ${element.name} VideoClickAction") + element.sourcePlugin = this.filename + synchronized(VideoClickActionHolder.allVideoClickActions) { + VideoClickActionHolder.allVideoClickActions.add(element) + } + } + class Manifest { @JsonProperty("name") var name: String? = null diff --git a/app/src/main/java/com/lagradost/cloudstream3/plugins/PluginManager.kt b/app/src/main/java/com/lagradost/cloudstream3/plugins/PluginManager.kt index c7f416883..8535592d4 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/plugins/PluginManager.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/plugins/PluginManager.kt @@ -24,6 +24,8 @@ import com.lagradost.cloudstream3.AcraApplication.Companion.setKey import com.lagradost.cloudstream3.CommonActivity.showToast import com.lagradost.cloudstream3.MainAPI.Companion.settingsForProvider import com.lagradost.cloudstream3.MainActivity.Companion.afterPluginsLoadedEvent +import com.lagradost.cloudstream3.actions.VideoClickAction +import com.lagradost.cloudstream3.actions.VideoClickActionHolder import com.lagradost.cloudstream3.mvvm.debugPrint import com.lagradost.cloudstream3.mvvm.logError import com.lagradost.cloudstream3.mvvm.normalSafeApiCall @@ -583,8 +585,13 @@ object PluginManager { synchronized(APIHolder.allProviders) { APIHolder.allProviders.removeIf { provider: MainAPI -> provider.sourcePlugin == plugin.filename } } + extractorApis.removeIf { provider: ExtractorApi -> provider.sourcePlugin == plugin.filename } + synchronized(VideoClickActionHolder.allVideoClickActions) { + VideoClickActionHolder.allVideoClickActions.removeIf { action: VideoClickAction -> action.sourcePlugin == plugin.filename } + } + classLoaders.values.removeIf { v -> v == plugin } plugins.remove(absolutePath) diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/ControllerActivity.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/ControllerActivity.kt index 1eaac5056..4b5d680c3 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/ControllerActivity.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/ControllerActivity.kt @@ -3,10 +3,15 @@ package com.lagradost.cloudstream3.ui import android.os.Bundle import android.util.Log import android.view.Menu -import android.view.View.* -import android.widget.* +import android.view.View.GONE +import android.view.View.INVISIBLE +import android.view.View.VISIBLE +import android.widget.AbsListView +import android.widget.ArrayAdapter +import android.widget.ImageView +import android.widget.LinearLayout +import android.widget.ListView import androidx.appcompat.app.AlertDialog -import androidx.media3.common.util.UnstableApi import com.fasterxml.jackson.databind.DeserializationFeature import com.fasterxml.jackson.databind.json.JsonMapper import com.fasterxml.jackson.module.kotlin.kotlinModule @@ -25,7 +30,7 @@ import com.lagradost.cloudstream3.mvvm.Resource import com.lagradost.cloudstream3.mvvm.logError import com.lagradost.cloudstream3.mvvm.safeApiCall import com.lagradost.cloudstream3.sortUrls -import com.lagradost.cloudstream3.ui.player.LoadType +import com.lagradost.cloudstream3.ui.player.LOADTYPE_CHROMECAST import com.lagradost.cloudstream3.ui.player.RepoLinkGenerator import com.lagradost.cloudstream3.ui.player.SubtitleData import com.lagradost.cloudstream3.ui.result.ResultEpisode @@ -298,14 +303,16 @@ class SelectSourceController(val view: ImageView, val activity: ControllerActivi val isSuccessful = safeApiCall { generator.generateLinks( - clearCache = false, type = LoadType.Chromecast, + clearCache = false, + allowedTypes = LOADTYPE_CHROMECAST, callback = { it.first?.let { link -> currentLinks.add(link) } }, subtitleCallback = { currentSubs.add(it) - }) + }, + isCasting = true) } val sortedLinks = sortUrls(currentLinks) diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/player/DownloadFileGenerator.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/player/DownloadFileGenerator.kt index c7db7d045..7d3d18ca9 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/player/DownloadFileGenerator.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/player/DownloadFileGenerator.kt @@ -6,6 +6,7 @@ import com.lagradost.cloudstream3.CommonActivity.activity import com.lagradost.cloudstream3.R import com.lagradost.cloudstream3.ui.player.PlayerSubtitleHelper.Companion.toSubtitleMimeType import com.lagradost.cloudstream3.utils.ExtractorLink +import com.lagradost.cloudstream3.utils.ExtractorLinkType import com.lagradost.cloudstream3.utils.SubtitleUtils.cleanDisplayName import com.lagradost.cloudstream3.utils.SubtitleUtils.isMatchingSubtitle import com.lagradost.cloudstream3.utils.VideoDownloadManager.getDownloadFileInfoAndUpdateSettings @@ -57,10 +58,11 @@ class DownloadFileGenerator( override suspend fun generateLinks( clearCache: Boolean, - type: LoadType, + sourceTypes: Set, callback: (Pair) -> Unit, subtitleCallback: (SubtitleData) -> Unit, - offset: Int + offset: Int, + isCasting: Boolean ): Boolean { val meta = episodes[currentIndex + offset] diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/player/ExtractorLinkGenerator.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/player/ExtractorLinkGenerator.kt index ec485f1c8..794dd762d 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/player/ExtractorLinkGenerator.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/player/ExtractorLinkGenerator.kt @@ -1,6 +1,7 @@ package com.lagradost.cloudstream3.ui.player import com.lagradost.cloudstream3.utils.ExtractorLink +import com.lagradost.cloudstream3.utils.ExtractorLinkType class ExtractorLinkGenerator( private val links: List, @@ -37,15 +38,15 @@ class ExtractorLinkGenerator( override suspend fun generateLinks( clearCache: Boolean, - type: LoadType, + sourceTypes: Set, callback: (Pair) -> Unit, subtitleCallback: (SubtitleData) -> Unit, - offset: Int + offset: Int, + isCasting: Boolean ): Boolean { subtitles.forEach(subtitleCallback) - val allowedTypes = type.toSet() links.forEach { - if(allowedTypes.contains(it.type)) { + if(sourceTypes.contains(it.type)) { callback.invoke(it to null) } } diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/player/IGenerator.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/player/IGenerator.kt index 6b8e6ea88..31cf0c70f 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/player/IGenerator.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/player/IGenerator.kt @@ -3,45 +3,25 @@ package com.lagradost.cloudstream3.ui.player import com.lagradost.cloudstream3.utils.ExtractorLink import com.lagradost.cloudstream3.utils.ExtractorLinkType -enum class LoadType { - Unknown, - InApp, - InAppDownload, - ExternalApp, - Browser, - Chromecast, - Fcast -} +val LOADTYPE_INAPP = setOf( + ExtractorLinkType.VIDEO, + ExtractorLinkType.DASH, + ExtractorLinkType.M3U8 +) + +val LOADTYPE_INAPP_DOWNLOAD = setOf( + ExtractorLinkType.VIDEO, + ExtractorLinkType.M3U8 +) + +val LOADTYPE_CHROMECAST = setOf( + ExtractorLinkType.VIDEO, + ExtractorLinkType.DASH, + ExtractorLinkType.M3U8 +) + +val LOADTYPE_ALL = ExtractorLinkType.entries.toSet() -fun LoadType.toSet() : Set { - return when(this) { - LoadType.InApp -> setOf( - ExtractorLinkType.VIDEO, - ExtractorLinkType.DASH, - ExtractorLinkType.M3U8 - ) - LoadType.Browser -> setOf( - ExtractorLinkType.VIDEO, - ExtractorLinkType.DASH, - ExtractorLinkType.M3U8 - ) - LoadType.InAppDownload -> setOf( - ExtractorLinkType.VIDEO, - ExtractorLinkType.M3U8 - ) - LoadType.ExternalApp, LoadType.Unknown -> ExtractorLinkType.entries.toSet() - LoadType.Chromecast -> setOf( - ExtractorLinkType.VIDEO, - ExtractorLinkType.DASH, - ExtractorLinkType.M3U8 - ) - LoadType.Fcast -> setOf( - ExtractorLinkType.VIDEO, - ExtractorLinkType.DASH, - ExtractorLinkType.M3U8 - ) - } -} interface IGenerator { val hasCache: Boolean @@ -60,9 +40,10 @@ interface IGenerator { /* not safe, must use try catch */ suspend fun generateLinks( clearCache: Boolean, - type: LoadType, + sourceTypes: Set, callback: (Pair) -> Unit, subtitleCallback: (SubtitleData) -> Unit, offset: Int = 0, + isCasting: Boolean = false ): Boolean } \ No newline at end of file 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 20feae413..109e3137b 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 @@ -4,6 +4,7 @@ import android.net.Uri import com.lagradost.cloudstream3.TvType import com.lagradost.cloudstream3.amap import com.lagradost.cloudstream3.utils.ExtractorLink +import com.lagradost.cloudstream3.utils.ExtractorLinkType import com.lagradost.cloudstream3.utils.INFER_TYPE import com.lagradost.cloudstream3.utils.Qualities import com.lagradost.cloudstream3.utils.loadExtractor @@ -69,10 +70,11 @@ class LinkGenerator( override suspend fun generateLinks( clearCache: Boolean, - type: LoadType, + sourceTypes: Set, callback: (Pair) -> Unit, subtitleCallback: (SubtitleData) -> Unit, - offset: Int + offset: Int, + isCasting: Boolean ): Boolean { links.amap { link -> if (!extract || !loadExtractor(link.url, referer, { diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/player/PlayerGeneratorViewModel.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/player/PlayerGeneratorViewModel.kt index 122eaa975..67cd9de6d 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/player/PlayerGeneratorViewModel.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/player/PlayerGeneratorViewModel.kt @@ -15,6 +15,7 @@ import com.lagradost.cloudstream3.ui.result.ResultEpisode import com.lagradost.cloudstream3.utils.Coroutines.ioSafe import com.lagradost.cloudstream3.utils.EpisodeSkip import com.lagradost.cloudstream3.utils.ExtractorLink +import com.lagradost.cloudstream3.utils.ExtractorLinkType import kotlinx.coroutines.Job import kotlinx.coroutines.launch @@ -94,7 +95,7 @@ class PlayerGeneratorViewModel : ViewModel() { if (generator?.hasCache == true && generator?.hasNext() == true) { safeApiCall { generator?.generateLinks( - type = LoadType.InApp, + sourceTypes = LOADTYPE_INAPP, clearCache = false, callback = {}, subtitleCallback = {}, @@ -173,7 +174,7 @@ class PlayerGeneratorViewModel : ViewModel() { } } - fun loadLinks(type: LoadType = LoadType.InApp) { + fun loadLinks(sourceTypes: Set = LOADTYPE_INAPP) { Log.i(TAG, "loadLinks") currentJob?.cancel() @@ -188,7 +189,7 @@ class PlayerGeneratorViewModel : ViewModel() { // load more data _loadingLinks.postValue(Resource.Loading()) val loadingState = safeApiCall { - generator?.generateLinks(type = type, clearCache = forceClearCache, callback = { + generator?.generateLinks(sourceTypes = sourceTypes, clearCache = forceClearCache, callback = { currentLinks.add(it) // Clone to prevent ConcurrentModificationException normalSafeApiCall { diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/player/RepoLinkGenerator.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/player/RepoLinkGenerator.kt index 588afbb50..b97ca155b 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/player/RepoLinkGenerator.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/player/RepoLinkGenerator.kt @@ -1,13 +1,13 @@ package com.lagradost.cloudstream3.ui.player import android.util.Log -import androidx.media3.common.util.UnstableApi import com.lagradost.cloudstream3.APIHolder.getApiFromNameNull import com.lagradost.cloudstream3.APIHolder.unixTime import com.lagradost.cloudstream3.LoadResponse import com.lagradost.cloudstream3.ui.APIRepository import com.lagradost.cloudstream3.ui.result.ResultEpisode import com.lagradost.cloudstream3.utils.ExtractorLink +import com.lagradost.cloudstream3.utils.ExtractorLinkType import kotlin.math.max import kotlin.math.min @@ -75,12 +75,12 @@ class RepoLinkGenerator( override suspend fun generateLinks( clearCache: Boolean, - type: LoadType, + allowedTypes: Set, callback: (Pair) -> Unit, subtitleCallback: (SubtitleData) -> Unit, - offset: Int + offset: Int, + isCasting: Boolean, ): Boolean { - val allowedTypes = type.toSet() val index = currentIndex val current = episodes.getOrNull(index + offset) ?: return false @@ -123,7 +123,7 @@ class RepoLinkGenerator( val result = APIRepository( getApiFromNameNull(current.apiName) ?: throw Exception("This provider does not exist") ).loadLinks(current.data, - isCasting = LoadType.Chromecast == type, + isCasting = isCasting, subtitleCallback = { file -> val correctFile = PlayerSubtitleHelper.getSubtitleData(file) if (correctFile.url.isNotEmpty() && !currentSubsUrls.contains(correctFile.url)) { diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/result/EpisodeAdapter.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/result/EpisodeAdapter.kt index 4cd9cc9ea..2dd8e2ab4 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/result/EpisodeAdapter.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/result/EpisodeAdapter.kt @@ -11,6 +11,7 @@ import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.RecyclerView import com.lagradost.cloudstream3.APIHolder.unixTimeMS import com.lagradost.cloudstream3.R +import com.lagradost.cloudstream3.actions.VideoClickActionHolder import com.lagradost.cloudstream3.databinding.ResultEpisodeBinding import com.lagradost.cloudstream3.databinding.ResultEpisodeLargeBinding import com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.secondsToReadable @@ -30,9 +31,11 @@ import java.text.SimpleDateFormat import java.util.Date import java.util.Locale +/** + * Ids >= 1000 are reserved for VideoClickActions + * @see VideoClickActionHolder + */ const val ACTION_PLAY_EPISODE_IN_PLAYER = 1 -const val ACTION_PLAY_EPISODE_IN_VLC_PLAYER = 2 -const val ACTION_PLAY_EPISODE_IN_BROWSER = 3 const val ACTION_CHROME_CAST_EPISODE = 4 const val ACTION_CHROME_CAST_MIRROR = 5 @@ -41,7 +44,6 @@ const val ACTION_DOWNLOAD_EPISODE = 6 const val ACTION_DOWNLOAD_MIRROR = 7 const val ACTION_RELOAD_EPISODE = 8 -const val ACTION_COPY_LINK = 9 const val ACTION_SHOW_OPTIONS = 10 @@ -52,12 +54,7 @@ const val ACTION_SHOW_DESCRIPTION = 15 const val ACTION_DOWNLOAD_EPISODE_SUBTITLE = 13 const val ACTION_DOWNLOAD_EPISODE_SUBTITLE_MIRROR = 14 -const val ACTION_PLAY_EPISODE_IN_WEB_VIDEO = 16 -const val ACTION_PLAY_EPISODE_IN_MPV = 17 -const val ACTION_PLAY_EPISODE_IN_MPV_YTDL = 20 - const val ACTION_MARK_AS_WATCHED = 18 -const val ACTION_FCAST = 19 const val TV_EP_SIZE = 400 @@ -69,22 +66,10 @@ class EpisodeAdapter( private val downloadClickCallback: (DownloadClickEvent) -> Unit, ) : RecyclerView.Adapter() { 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 - 4 -> ACTION_PLAY_EPISODE_IN_WEB_VIDEO - 5 -> ACTION_PLAY_EPISODE_IN_MPV - 6 -> ACTION_PLAY_EPISODE_IN_MPV_YTDL - else -> ACTION_PLAY_EPISODE_IN_PLAYER - } + val playerPref = settingsManager.getString(context.getString(R.string.player_default_key), "") + return VideoClickActionHolder.uniqueIdToId(playerPref) ?: ACTION_PLAY_EPISODE_IN_PLAYER } } diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultViewModel2.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultViewModel2.kt index a29941d11..b5f83201e 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultViewModel2.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultViewModel2.kt @@ -2,16 +2,11 @@ package com.lagradost.cloudstream3.ui.result import android.app.Activity import android.content.* -import android.net.Uri -import android.os.Build -import android.os.Bundle import android.text.format.Formatter.formatFileSize import android.util.Log import android.widget.Toast import androidx.annotation.MainThread import androidx.appcompat.app.AlertDialog -import androidx.core.content.FileProvider -import androidx.core.net.toUri import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel @@ -30,37 +25,28 @@ import com.lagradost.cloudstream3.LoadResponse.Companion.getAniListId import com.lagradost.cloudstream3.LoadResponse.Companion.getMalId import com.lagradost.cloudstream3.LoadResponse.Companion.isMovie import com.lagradost.cloudstream3.LoadResponse.Companion.readIdFromString -import com.lagradost.cloudstream3.MainActivity.Companion.MPV -import com.lagradost.cloudstream3.MainActivity.Companion.MPV_COMPONENT -import com.lagradost.cloudstream3.MainActivity.Companion.MPV_PACKAGE -import com.lagradost.cloudstream3.MainActivity.Companion.MPV_YTDL -import com.lagradost.cloudstream3.MainActivity.Companion.MPV_YTDL_COMPONENT -import com.lagradost.cloudstream3.MainActivity.Companion.MPV_YTDL_PACKAGE -import com.lagradost.cloudstream3.MainActivity.Companion.VLC -import com.lagradost.cloudstream3.MainActivity.Companion.VLC_COMPONENT -import com.lagradost.cloudstream3.MainActivity.Companion.VLC_PACKAGE -import com.lagradost.cloudstream3.MainActivity.Companion.WEB_VIDEO -import com.lagradost.cloudstream3.MainActivity.Companion.WEB_VIDEO_CAST_PACKAGE +import com.lagradost.cloudstream3.actions.VideoClickActionHolder import com.lagradost.cloudstream3.metaproviders.SyncRedirector import com.lagradost.cloudstream3.mvvm.* import com.lagradost.cloudstream3.syncproviders.AccountManager import com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.secondsToReadable import com.lagradost.cloudstream3.syncproviders.SyncAPI import com.lagradost.cloudstream3.syncproviders.providers.Kitsu -import com.lagradost.cloudstream3.syncproviders.providers.SimklApi import com.lagradost.cloudstream3.ui.APIRepository import com.lagradost.cloudstream3.ui.WatchType import com.lagradost.cloudstream3.ui.download.DOWNLOAD_NAVIGATE_TO import com.lagradost.cloudstream3.ui.player.GeneratorPlayer import com.lagradost.cloudstream3.ui.player.IGenerator -import com.lagradost.cloudstream3.ui.player.LoadType +import com.lagradost.cloudstream3.ui.player.LOADTYPE_ALL +import com.lagradost.cloudstream3.ui.player.LOADTYPE_CHROMECAST +import com.lagradost.cloudstream3.ui.player.LOADTYPE_INAPP +import com.lagradost.cloudstream3.ui.player.LOADTYPE_INAPP_DOWNLOAD import com.lagradost.cloudstream3.ui.player.RepoLinkGenerator 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.utils.* import com.lagradost.cloudstream3.utils.AppContextUtils.getNameFull -import com.lagradost.cloudstream3.utils.AppContextUtils.isAppInstalled import com.lagradost.cloudstream3.utils.AppContextUtils.isConnectedToChromecast import com.lagradost.cloudstream3.utils.AppContextUtils.setDefaultFocus import com.lagradost.cloudstream3.utils.AppContextUtils.sortSubs @@ -69,6 +55,7 @@ import com.lagradost.cloudstream3.utils.Coroutines.ioSafe import com.lagradost.cloudstream3.utils.Coroutines.ioWork import com.lagradost.cloudstream3.utils.Coroutines.ioWorkSafe import com.lagradost.cloudstream3.utils.Coroutines.main +import com.lagradost.cloudstream3.utils.DataStore.setKey import com.lagradost.cloudstream3.utils.DataStoreHelper.deleteBookmarkedData import com.lagradost.cloudstream3.utils.DataStoreHelper.getAllBookmarkedData import com.lagradost.cloudstream3.utils.DataStoreHelper.getAllFavorites @@ -96,12 +83,7 @@ import com.lagradost.cloudstream3.utils.DataStoreHelper.setVideoWatchState import com.lagradost.cloudstream3.utils.DataStoreHelper.updateSubscribedData import com.lagradost.cloudstream3.utils.UIHelper.clipboardHelper import com.lagradost.cloudstream3.utils.UIHelper.navigate -import com.lagradost.cloudstream3.utils.fcast.FcastManager -import com.lagradost.cloudstream3.utils.fcast.FcastSession -import com.lagradost.cloudstream3.utils.fcast.Opcode -import com.lagradost.cloudstream3.utils.fcast.PlayMessage import kotlinx.coroutines.* -import java.io.File import java.util.concurrent.TimeUnit /** This starts at 1 */ @@ -803,7 +785,7 @@ class ResultViewModel2 : ViewModel() { val generator = RepoLinkGenerator(listOf(episode)) val currentLinks = mutableSetOf() val currentSubs = mutableSetOf() - generator.generateLinks(clearCache = false, LoadType.Chromecast, callback = { + generator.generateLinks(clearCache = false, allowedTypes = LOADTYPE_INAPP_DOWNLOAD, callback = { it.first?.let { link -> currentLinks.add(link) } @@ -954,7 +936,7 @@ class ResultViewModel2 : ViewModel() { isVisible: Boolean = true ) { if (activity == null) return - loadLinks(result, isVisible = isVisible, LoadType.Chromecast) { data -> + loadLinks(result, isVisible = isVisible, sourceTypes = LOADTYPE_CHROMECAST, isCasting = true) { data -> startChromecast(activity, result, data.links, data.subs, 0) } } @@ -1264,7 +1246,7 @@ class ResultViewModel2 : ViewModel() { _loadedLinks.postValue(null) } - private fun postPopup(text: UiText, options: List, callback: suspend (Int?) -> Unit) { + fun postPopup(text: UiText, options: List, callback: suspend (Int?) -> Unit) { _selectPopup.postValue( SelectPopup.SelectText( text, @@ -1300,8 +1282,9 @@ class ResultViewModel2 : ViewModel() { private fun loadLinks( result: ResultEpisode, isVisible: Boolean, - type: LoadType, + sourceTypes: Set = LOADTYPE_ALL, clearCache: Boolean = false, + isCasting: Boolean = false, work: suspend (CoroutineScope.(LinkLoadingResult) -> Unit) ) { currentLoadLinkJob?.cancel() @@ -1309,8 +1292,9 @@ class ResultViewModel2 : ViewModel() { val links = loadLinks( result, isVisible = isVisible, - type = type, - clearCache = clearCache + sourceTypes = sourceTypes, + clearCache = clearCache, + isCasting = isCasting ) if (!this.isActive) return@ioSafe work(links) @@ -1320,11 +1304,12 @@ class ResultViewModel2 : ViewModel() { private var currentLoadLinkJob: Job? = null private fun acquireSingleLink( result: ResultEpisode, - type: LoadType, + sourceTypes: Set, text: UiText, - callback: (Pair) -> Unit, + isCasting: Boolean = false, + callback: (Pair) -> Unit ) { - loadLinks(result, isVisible = true, type) { links -> + loadLinks(result, isVisible = true, sourceTypes, isCasting = isCasting) { links -> // Could not find a better way to do this val context = AcraApplication.context postPopup( @@ -1344,7 +1329,7 @@ class ResultViewModel2 : ViewModel() { text: UiText, callback: (Pair) -> Unit, ) { - loadLinks(result, isVisible = true, type = LoadType.Unknown) { links -> + loadLinks(result, isVisible = true) { links -> postPopup( text, links.subs.map { txt(it.name) }) @@ -1357,8 +1342,9 @@ class ResultViewModel2 : ViewModel() { private suspend fun CoroutineScope.loadLinks( result: ResultEpisode, isVisible: Boolean, - type: LoadType, + sourceTypes: Set = LOADTYPE_ALL, clearCache: Boolean = false, + isCasting: Boolean = false ): LinkLoadingResult { val tempGenerator = RepoLinkGenerator(listOf(result)) @@ -1371,15 +1357,19 @@ class ResultViewModel2 : ViewModel() { } try { updatePage() - tempGenerator.generateLinks(clearCache, type, { (link, _) -> - if (link != null) { - links += link - updatePage() - } - }, { sub -> + tempGenerator.generateLinks(clearCache, + allowedTypes = sourceTypes, + callback = { (link, _) -> + if (link != null) { + links += link + updatePage() + } + }, + subtitleCallback = { sub -> subs += sub updatePage() - }) + }, + isCasting = isCasting) } catch (e: Exception) { logError(e) } finally { @@ -1389,185 +1379,11 @@ class ResultViewModel2 : ViewModel() { return LinkLoadingResult(sortUrls(links), sortSubs(subs)) } - private fun launchActivity( - activity: Activity?, - resumeApp: MainActivity.Companion.ResultResume, - id: Int? = null, - work: suspend (Intent.(Activity) -> Unit) - ): Job? { - val act = activity ?: return null - return CoroutineScope(Dispatchers.IO).launch { - try { - resumeApp.launch(id) { - work(act) - } - } catch (t: Throwable) { - logError(t) - main { - if (t is ActivityNotFoundException) { - showToast(txt(R.string.app_not_found_error), Toast.LENGTH_LONG) - } else { - showToast(t.toString(), Toast.LENGTH_LONG) - } - } - } - } - } - - private fun playInWebVideo( - activity: Activity?, - link: ExtractorLink, - title: String?, - posterUrl: String?, - subtitles: List - ) = launchActivity(activity, WEB_VIDEO) { - setDataAndType(Uri.parse(link.url), "video/*") - - putExtra("subs", subtitles.map { it.url.toUri() }.toTypedArray()) - title?.let { putExtra("title", title) } - posterUrl?.let { putExtra("poster", posterUrl) } - val headers = Bundle().apply { - if (link.referer.isNotBlank()) - putString("Referer", link.referer) - putString("User-Agent", USER_AGENT) - for ((key, value) in link.headers) { - putString(key, value) - } - } - putExtra("android.media.intent.extra.HTTP_HEADERS", headers) - putExtra("secure_uri", true) - } - - private fun playWithMpv( - activity: Activity?, - id: Int, - link: ExtractorLink, - subtitles: List, - 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()) - } - - private fun playWithMpvYtdl( - activity: Activity?, - id: Int, - link: ExtractorLink, - subtitles: List, - resume: Boolean = true, - ) = launchActivity(activity, MPV_YTDL, 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_YTDL_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/ - private fun playWithVlc( - activity: Activity?, - data: LinkLoadingResult, - id: Int, - resume: Boolean = true, - // if it is only a single link then resume works correctly - singleFile: Boolean? = null - ) = launchActivity(activity, VLC, id) { act -> - 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) - - val outputDir = act.cacheDir - - if (singleFile ?: (data.links.size == 1)) { - setDataAndType(data.links.first().url.toUri(), "video/*") - } else { - val outputFile = File.createTempFile("mirrorlist", ".m3u8", outputDir) - - var text = "#EXTM3U" - - // 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) { - text += "\n#EXTINF:, ${link.name}\n${link.url}" - } - outputFile.writeText(text) - - setDataAndType( - FileProvider.getUriForFile( - act, - act.applicationContext.packageName + ".provider", - outputFile - ), "video/*" - ) - } - - val position = if (resume) { - getViewPos(id)?.position ?: 0L - } else { - 1L - } - - // Component no longer safe to use in A13 for VLC - // https://code.videolan.org/videolan/vlc-android/-/issues/2776 - // This will likely need to be updated once VLC fixes their documentation. - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) { - component = VLC_COMPONENT - } - - putExtra("from_start", !resume) - putExtra("position", position) - } - - fun handleAction(click: EpisodeClickEvent) = viewModelScope.launchSafe { handleEpisodeClickEvent(click) } - data class ExternalApp( - val packageString: String, - val name: Int, - val action: Int, - ) - - private val apps = listOf( - ExternalApp( - VLC_PACKAGE, - R.string.player_settings_play_in_vlc, - ACTION_PLAY_EPISODE_IN_VLC_PLAYER - ), ExternalApp( - WEB_VIDEO_CAST_PACKAGE, - R.string.player_settings_play_in_web, - ACTION_PLAY_EPISODE_IN_WEB_VIDEO - ), - ExternalApp( - MPV_PACKAGE, - R.string.player_settings_play_in_mpv, - ACTION_PLAY_EPISODE_IN_MPV - ), - ExternalApp( - MPV_YTDL_PACKAGE, - R.string.player_settings_play_in_mpvytdl, - ACTION_PLAY_EPISODE_IN_MPV_YTDL - ) - ) - fun releaseEpisodeSynopsis() { _episodeSynopsis.postValue(null) } @@ -1576,6 +1392,7 @@ class ResultViewModel2 : ViewModel() { when (click.action) { ACTION_SHOW_OPTIONS -> { val options = mutableListOf>() + if (activity?.isConnectedToChromecast() == true) { options.addAll( listOf( @@ -1585,29 +1402,10 @@ class ResultViewModel2 : ViewModel() { ) } - if (FcastManager.currentDevices.isNotEmpty()) { - options.add( - txt(R.string.player_settings_play_in_fcast) to ACTION_FCAST - ) - } - options.add(txt(R.string.episode_action_play_in_app) to ACTION_PLAY_EPISODE_IN_PLAYER) - for (app in apps) { - if (activity?.isAppInstalled(app.packageString) == true) { - options.add( - txt( - R.string.episode_action_play_in_format, - txt(app.name) - ) to app.action - ) - } - } - options.addAll( listOf( - txt(R.string.episode_action_play_in_browser) to ACTION_PLAY_EPISODE_IN_BROWSER, - txt(R.string.episode_action_copy_link) to ACTION_COPY_LINK, txt(R.string.episode_action_auto_download) to ACTION_DOWNLOAD_EPISODE, txt(R.string.episode_action_download_mirror) to ACTION_DOWNLOAD_MIRROR, txt(R.string.episode_action_download_subtitle) to ACTION_DOWNLOAD_EPISODE_SUBTITLE_MIRROR, @@ -1615,6 +1413,10 @@ class ResultViewModel2 : ViewModel() { ) ) + options.addAll( + VideoClickActionHolder.makeOptionMap(activity, click.data) + ) + // Do not add mark as watched on movies if (!listOf(TvType.Movie, TvType.AnimeMovie).contains(click.data.tvType)) { val isWatched = @@ -1716,7 +1518,7 @@ class ResultViewModel2 : ViewModel() { val response = currentResponse ?: return acquireSingleLink( click.data, - LoadType.InAppDownload, + LOADTYPE_INAPP_DOWNLOAD, txt(R.string.episode_action_download_mirror) ) { (result, index) -> ioSafe { @@ -1746,7 +1548,7 @@ class ResultViewModel2 : ViewModel() { loadLinks( click.data, isVisible = false, - type = LoadType.InApp, + LOADTYPE_INAPP, clearCache = true ) } @@ -1759,139 +1561,18 @@ class ResultViewModel2 : ViewModel() { ACTION_CHROME_CAST_MIRROR -> { acquireSingleLink( click.data, - LoadType.Chromecast, - txt(R.string.episode_action_chromecast_mirror) + LOADTYPE_CHROMECAST, + txt(R.string.episode_action_chromecast_mirror), + isCasting = true ) { (result, index) -> startChromecast(activity, click.data, result.links, result.subs, index) } } - ACTION_FCAST -> { - val devices = FcastManager.currentDevices.toList() - postPopup( - txt(R.string.player_settings_select_cast_device), - devices.map { txt(it.name) }) { index -> - if (index == null) return@postPopup - val device = devices.getOrNull(index) - - acquireSingleLink( - click.data, - LoadType.Fcast, - txt(R.string.episode_action_cast_mirror) - ) { (result, index) -> - val host = device?.host ?: return@acquireSingleLink - val link = result.links.getOrNull(index) ?: return@acquireSingleLink - - FcastSession(host).use { session -> - session.sendMessage( - Opcode.Play, - PlayMessage( - link.type.getMimeType(), - link.url, - headers = mapOf( - "referer" to link.referer, - "user-agent" to USER_AGENT - ) + link.headers - ) - ) - } - } - } - } - - ACTION_PLAY_EPISODE_IN_BROWSER -> acquireSingleLink( - click.data, - LoadType.Browser, - txt(R.string.episode_action_play_in_browser) - ) { (result, index) -> - try { - val i = Intent(Intent.ACTION_VIEW) - i.data = Uri.parse(result.links[index].url) - activity?.startActivity(i) - } catch (e: Exception) { - logError(e) - } - } - - ACTION_COPY_LINK -> { - acquireSingleLink( - click.data, - LoadType.ExternalApp, - txt(R.string.episode_action_copy_link) - ) { (result, index) -> - val link = result.links[index] - clipboardHelper(txt(link.name), link.url) - } - } - ACTION_CHROME_CAST_EPISODE -> { startChromecast(activity, click.data) } - ACTION_PLAY_EPISODE_IN_VLC_PLAYER -> { - loadLinks(click.data, isVisible = true, LoadType.ExternalApp) { links -> - if (links.links.isEmpty()) { - showToast(R.string.no_links_found_toast, Toast.LENGTH_SHORT) - return@loadLinks - } - - playWithVlc( - activity, - links, - click.data.id - ) - } - } - - ACTION_PLAY_EPISODE_IN_WEB_VIDEO -> acquireSingleLink( - click.data, - LoadType.Chromecast, - txt( - R.string.episode_action_play_in_format, - txt(R.string.player_settings_play_in_web) - ) - ) { (result, index) -> - playInWebVideo( - activity, - result.links[index], - click.data.name ?: click.data.headerName, - click.data.poster, - result.subs - ) - } - - ACTION_PLAY_EPISODE_IN_MPV -> acquireSingleLink( - click.data, - LoadType.Chromecast, - 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_MPV_YTDL -> acquireSingleLink( - click.data, - LoadType.Chromecast, - txt( - R.string.episode_action_play_in_format, - txt(R.string.player_settings_play_in_mpvytdl) - ) - ) { (result, index) -> - playWithMpvYtdl( - activity, - click.data.id, - result.links[index], - result.subs - ) - } - ACTION_PLAY_EPISODE_IN_PLAYER -> { val data = currentResponse?.syncData?.toList() ?: emptyList() val list = @@ -1907,7 +1588,7 @@ class ResultViewModel2 : ViewModel() { if (currentResponse?.type == TvType.CustomMedia) { generator?.generateLinks( clearCache = true, - LoadType.Unknown, + LOADTYPE_ALL, callback = {}, subtitleCallback = {}) } else { @@ -1933,6 +1614,35 @@ class ResultViewModel2 : ViewModel() { // Kinda dirty to reload all episodes :( reloadEpisodes() } + + else -> { + val action = VideoClickActionHolder.getActionById(click.action) ?: return + + activity?.setKey("last_click_action", action.uniqueId()) + if (action.oneSource) { + acquireSingleLink( + click.data, + action.sourceTypes, + action.name + ) { (result, index) -> + action.runAction( + activity, + click.data, + result, + index + ) + } + } else { + loadLinks(click.data, isVisible = true, action.sourceTypes) { links -> + action.runAction( + activity, + click.data, + links, + null + ) + } + } + } } } @@ -2040,7 +1750,7 @@ class ResultViewModel2 : ViewModel() { isResponseRequired = false ) if (map.isNullOrEmpty()) return@argamap - updateEpisodes = DubStatus.values().map { dubStatus -> + updateEpisodes = DubStatus.entries.map { dubStatus -> val current = this.episodes[dubStatus]?.mapIndexed { index, episode -> episode.apply { diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsPlayer.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsPlayer.kt index 1753032ac..17580236f 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsPlayer.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsPlayer.kt @@ -6,6 +6,7 @@ import android.view.View import androidx.preference.PreferenceFragmentCompat import androidx.preference.PreferenceManager import com.lagradost.cloudstream3.R +import com.lagradost.cloudstream3.actions.VideoClickActionHolder import com.lagradost.cloudstream3.mvvm.logError import com.lagradost.cloudstream3.ui.settings.Globals.EMULATOR import com.lagradost.cloudstream3.ui.settings.Globals.PHONE @@ -155,10 +156,17 @@ class SettingsPlayer : PreferenceFragmentCompat() { 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) + getPref(R.string.player_default_key)?.setOnPreferenceClickListener { + val players = VideoClickActionHolder.getPlayers(activity) + val prefNames = buildList { + add(getString(R.string.player_settings_play_in_app)) + addAll(players.map { it.name.asStringNull(activity) ?: it.javaClass.simpleName }) + } + val prefValues = buildList { + add("") + addAll(players.map { it.uniqueId() }) + } + val current = settingsManager.getString(getString(R.string.player_default_key), "") ?: "" activity?.showBottomDialog( prefNames.toList(), @@ -166,7 +174,7 @@ class SettingsPlayer : PreferenceFragmentCompat() { getString(R.string.player_pref), true, {}) { - settingsManager.edit().putInt(getString(R.string.player_pref_key), prefValues[it]).apply() + settingsManager.edit().putString(getString(R.string.player_default_key), prefValues[it]).apply() } return@setOnPreferenceClickListener true } diff --git a/app/src/main/res/values-ajp/strings.xml b/app/src/main/res/values-ajp/strings.xml index 6896cf2af..0b30cebac 100644 --- a/app/src/main/res/values-ajp/strings.xml +++ b/app/src/main/res/values-ajp/strings.xml @@ -221,9 +221,7 @@ بسبِب أعطال إزا نحط على مستوى عالي كتير على الأجهزة يللي م بتساع كتير، متل تلفزيون \"أندرويد\". شي غير أفي هيدا التجديد - نسوخ الرابط مَشي بال آپ - مشي بمتصفح الويب مفيد لتجاوز المنع من مزود خدمة الإنترنت مسلسل غير الحجم @@ -390,10 +388,8 @@ م قدرنا ننزل الإصدار الجديد تبع الآپ المؤلفين إضافة - كاست ڤيديو ع الوَب معقول يكون موجود أصلًا مشتركينلو - متصفح الوَب كل اللغات دايمًا كتوب ب أحرف كاپيتال، A بدل a مشغل الڤيديو المفضل @@ -422,7 +418,6 @@ خلصت محي السجل تجَدَد (من قديم للجديد) - \"ڤي أل سي ميديا پلاير\" كاميرا وَب أبجديًا (من الياء للألف) @@ -504,7 +499,6 @@ مزامنة شوفو معلومات عن المشكلة مدعوم - \"أم پي ڤي\" ظبّط وقت الترجمة افتتاح مختلط مقطع دعائي @@ -627,7 +621,6 @@ رح ينزل ب %s الحلقة ال %2$d من الجزء ال%1$d رح تنزل ب كاست مراية - إف كاست نقي جهاز الكاست ويكي \"كلود ستريم\" أكونتات @@ -669,6 +662,5 @@ \n%s صورة زغيرة مع التقريب وال تبعيد بت حط صورة زغير من الڤيديو إنت و عم بت قرب أو ترجع بال ڤيديو - MPV YTDL بعد مش معمول لود لولا ترجمة \ No newline at end of file diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml index 25118d963..56bb4b4a0 100644 --- a/app/src/main/res/values-ar/strings.xml +++ b/app/src/main/res/values-ar/strings.xml @@ -233,8 +233,6 @@ مرآة كروم كاست تشغيل في التطبيق %s تشغيل في - تشغيل في الويب - نسخ الرابط التحميل التلقائي تحميل بجودات مختلفة إعادة تحميل الروابط @@ -464,10 +462,6 @@ فتح(تشغيل) %1$s %2$d%3$s المكونات الإضافية المحدثة %d - VLC - MPV - اسقاط فيديو الويب - متصفح الإنترنت تخطي %s الافتتاح النهاية @@ -653,7 +647,6 @@ قادم خلال %s سيتم إصدار الحلقة %1$d من الموسم %2$d في مرآة البث - بث ف حدد جهاز البث CloudStream ويكي إعدادات الأمان @@ -695,6 +688,5 @@ \n%s معاينة شريط البحث تمكين معاينة الصورة المصغرة على شريط البحث - MPV YTDL لم يتم تحميل أي ترجمات بعد \ No newline at end of file diff --git a/app/src/main/res/values-ars/strings.xml b/app/src/main/res/values-ars/strings.xml index 873c55bf3..d1efdbbc5 100644 --- a/app/src/main/res/values-ars/strings.xml +++ b/app/src/main/res/values-ars/strings.xml @@ -311,11 +311,9 @@ اخرون تخطي هذا التحديث .قد يتسبب في تأخير التحديثات لبضعة أيام .jsDelivr باستخدام GitHubيتجاوز حظر - انسخ الرابط الدرامات الآسيوية في قائمة الانتظار افتح في التطبيق - افتح في المتصفح مفيد لتجاوز حجب مزودي خدمة الإنترنت مسلسل تقييم diff --git a/app/src/main/res/values-as/strings.xml b/app/src/main/res/values-as/strings.xml index fc50d2d02..2fdd469b4 100644 --- a/app/src/main/res/values-as/strings.xml +++ b/app/src/main/res/values-as/strings.xml @@ -89,7 +89,6 @@ সম্পূৰ্ণ সৰ্বজনীন তালিকা বন্ধ কৰক - VLC বেটাৰী অপ্টিমাইজেচন নিষ্ক্ৰিয় কৰক সদস্যতা গ্ৰহণ কৰা গুণসমূহ @@ -302,8 +301,6 @@ কাষ্ট মিৰৰ ডাব ছপা প্লে %s ত - ব্ৰাউজাৰত প্লে কৰক - লিংক কপি কৰক স্বয়ংক্ৰিয় ডাউনলোড ডাউনলোড মিৰৰ সাব ছপা @@ -498,10 +495,6 @@ HLS প্লেলিস্ট পছন্দৰ ভিডিঅ\' প্লেয়াৰ আভ্যন্তৰীণ প্লেয়াৰ - MPV - ৱেব ভিডিঅ\' কাষ্ট - Fcast - ৱেব ব্ৰাউজাৰ কাষ্ট ডিভাইচ চয়ন কৰক মিশ্ৰিত সমাপ্তি মিশ্ৰিত উদ্‌ঘাটনী @@ -650,7 +643,6 @@ ডিভাইচ পিন ক\'ড পোৱা নাই, স্থানীয় প্ৰমাণীকৰণ চেষ্টা কৰক পিন ক\'ডৰ মেয়াদ শেষ হৈছে! ক\'ড মেয়াদ শেষ হব %1$dm %2$ds - MPV YTDL সীকবৰ প্ৰিভিউ সীকবৰত প্ৰিভিউ থাম্বনেইল সক্ৰিয় কৰক আৰম্ভৰ পৰা প্লে কৰক diff --git a/app/src/main/res/values-bg/strings.xml b/app/src/main/res/values-bg/strings.xml index 3579c8353..218fa5e57 100644 --- a/app/src/main/res/values-bg/strings.xml +++ b/app/src/main/res/values-bg/strings.xml @@ -238,8 +238,6 @@ Chromecast огледало Пусни в приложението Пусни в %s - Пусни в браузър - Копирай връзка Автоматично изтегляне Изтегляне на огледало Презареждане на връзки @@ -443,10 +441,6 @@ HLS плейлист Предпочитан видео плеър Вътрешен плеър - VLC - MPV - Уеб видео предаване - Уеб браузър Приложението не е намерено Автоматично изтегли добавки Всички езици diff --git a/app/src/main/res/values-bn/strings.xml b/app/src/main/res/values-bn/strings.xml index c5ed86514..f1bc8f82a 100644 --- a/app/src/main/res/values-bn/strings.xml +++ b/app/src/main/res/values-bn/strings.xml @@ -230,7 +230,6 @@ প্লাগইন ডাউনলোড ফিল্টার করতে মোড নির্বাচন করুন লিঙ্ক পুনরায় লোড হয়েছে সুইচ অ্যাকাউন্ট - ব্রাউজারে প্লে করুন দাবিত্যাগ এশিয়ান ড্রামা সোর্স @@ -274,7 +273,6 @@ টরেন্ট এপিসোড ক্রোমকাস্ট করুন প্লে হচ্ছে %s সময়ের মধ্যে - লিঙ্ক কপি করুন স্বয়ংক্রিয় ডাউনলোড টাইটেল প্লেয়ার দেখা যাচ্ছে - সিকের পরিমাণ diff --git a/app/src/main/res/values-bp/strings.xml b/app/src/main/res/values-bp/strings.xml index 4c29a99e7..55e1ce180 100644 --- a/app/src/main/res/values-bp/strings.xml +++ b/app/src/main/res/values-bp/strings.xml @@ -235,8 +235,6 @@ Alternativa pelo Chromecast Assistir no App Assistir no %s - Assistir no navegador - Copiar link Auto download Baixar por servidor alternativo Recarregar links @@ -538,16 +536,13 @@ Começar Suportado Status - MPV Abrindo mistura - VLC Reinicie o aplicativo para ver as alterações. Visualização info de crash Faixas de áudio Adicionado em (novo para antigo) Faixas de video Legendas - Navegador 18+ Links Funcionalidades do Player @@ -563,7 +558,6 @@ Vídeo Android TV Wi-Fi - Lista de videos da web A interface de usuário não foi gerada corretamente. Isto se trata de um bug importante e deve ser reportado imediatamente %s Características da interface de usuário Provedor de teste @@ -642,7 +636,6 @@ Redefinir Próximos em %s Temporada %1$d Episódio %2$d será lançado em - Fcast Selecione o dispositivo de transmissão Espelhar transmissão CloudStream Wiki @@ -685,6 +678,5 @@ Desmarcar todos Ativar visualização de miniatura na barra de busca Visualização da barra de busca - MPV + YTDL Ainda não há legendas carregadas \ No newline at end of file diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml index 04b4b213b..ba03b05fb 100644 --- a/app/src/main/res/values-cs/strings.xml +++ b/app/src/main/res/values-cs/strings.xml @@ -223,8 +223,6 @@ Chromecast jako zrcadlo Přehrát v aplikace Přehrát ve %s - Přehrát v prohlížeči - Zkopírovat odkaz Automaticky stáhnout Zrcadlo stahování Obnovit odkazy @@ -400,8 +398,6 @@ Veřejný seznam Velká písmena u všech titulků Playlist HLS - MPV - Webové vysílání videa Aplikace nenalezena Přeskočit %s Úvod @@ -451,13 +447,11 @@ Popis Stav Nejprve nainstalujte rozšíření - VLC Smíšený konec Jazyk Interní přehrávač Rekapitulace Vymazat historii - Webový prohlížeč Všechny jazyky Smíšený úvod Poděkování @@ -645,7 +639,6 @@ Vychází %s Epizoda %2$d ze série %1$d bude vydána za Vysílat zrcadlení - Fcast Vyberte zařízení k vysílání CloudStream Wiki Zabezpečení @@ -687,6 +680,5 @@ Odstranit (%1$d | %2$s) Náhled v liště přehrávače Povolit náhled miniatur na liště přehrávače - MPV YTDL Zatím nenačteny žádné titulky \ No newline at end of file diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index c9656d9de..6cf8ff3bd 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -241,8 +241,6 @@ Downloadfehler, bitte überprüfen sie die Speicherberechtigungen Chromecast-Episode In %s wiedergeben - In Browser wiedergeben - Link kopieren Auto-Download Alternativer Download Links neu laden @@ -437,10 +435,6 @@ HLS-Playlist Bevorzugter Videoplayer Interner Player - VLC - MPV - Web Video Cast - Browser App nicht gefunden Alle Sprachen Überspringen %s @@ -618,7 +612,6 @@ hide_player_control_names_key Staffel %1$d Episode %2$d wird veröffentlicht in Wird veröffentlicht in %s - Fcast Sicherheit Konten Repository öffnen diff --git a/app/src/main/res/values-el/strings.xml b/app/src/main/res/values-el/strings.xml index e22182d23..268ea7bd1 100644 --- a/app/src/main/res/values-el/strings.xml +++ b/app/src/main/res/values-el/strings.xml @@ -194,8 +194,6 @@ Chromecast επεισόδιο Αναπαραγωγή εντός της εφαρμογής Αναπαραγωγή σε %s - Αναπαραγωγή στον περιηγητή - Αντιγραφή συνδέσμου Αυτόματη λήψη Λήψη mirror Επαναφόρτωση συνδέσμων @@ -359,10 +357,6 @@ HLS Playlist Προτεινόμενο πρόγραμμα αναπαραγωγής Ενσωματωμένο πρόγραμμα αναπαραγωγής - VLC - MPV - Web Video Cast - Περιηγητής Η εφαρμογή δεν βρέθηκε %1$s Επ %2$d Το επεισόδιο %d θα κυκλοφορήσει σε @@ -580,7 +574,6 @@ Δευτερόλεπτα Σκιπ όταν φαίνεται ο αναπαραγωγέας (πλειερ) Δοκιμή όλων των παροχών Αυτό το τεστ προορίζεται μόνο για τους προγραμματιστές και δε επαληθείει ούτε απορρίπτει την λειτουργία οποιουδήποτε παρόχου. - Fcast Επιλογή συσκευής για αναμετάδοση Πρόβλημα στην πρόσβαση στο Clipboard, Παρακαλώ προσπαθήστε ξανά. Πρόβλημα στην αντιγραφή , Παρακαλούμε αντιγράψτε το logcat και επικοινωνήστε με την υποστήριξη. diff --git a/app/src/main/res/values-es/array.xml b/app/src/main/res/values-es/array.xml index eb197f43e..fddd832a5 100644 --- a/app/src/main/res/values-es/array.xml +++ b/app/src/main/res/values-es/array.xml @@ -152,32 +152,6 @@ @string/show_title_key - - @string/episode_action_chromecast_episode - @string/episode_action_chromecast_mirror - @string/episode_action_play_in_app - @string/episode_action_play_in_format - @string/episode_action_play_in_browser - @string/episode_action_copy_link - @string/episode_action_auto_download - @string/episode_action_download_mirror - @string/episode_action_download_subtitle - @string/episode_action_reload_links - - - - 4 - 5 - 1 - 2 - 3 - 9 - 6 - 7 - 13 - 8 - - @string/automatic @string/phone_layout diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 155c5f746..a0c4587f5 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -57,11 +57,7 @@ Cantidad de búsquedas del reproductor (segundos) Use el brillo del sistema en el reproductor de la app en lugar de una superposición oscura Resolución del reproductor de video - MPV Reproductor - VLC - Web Video Cast - Navegador Web Iniciar el siguiente episodio cuando el actual termine Omitir Intro Apertura @@ -78,9 +74,7 @@ Actualizar progreso de lo visto Duplicar en Chromecast No se encontraron Episodios - Reproducir en Navegador Reproducir en %s - Copiar enlace Descarga automática Descargar desde servidor alternativo Recargar enlaces @@ -621,7 +615,6 @@ Próximamente en %s La temporada %1$d y el episodio %2$d se estrenarán en Seleccionar el dispositivo para transmitir - Fcast Espejo de transmisión Wiki de CloudStream Seguridad @@ -663,6 +656,5 @@ \n%s Activar la previsualización para las miniaturas en la barra de búsqueda Previsualización de Seekbar - MPV YTDL Aún no hay subtítulos cargados \ No newline at end of file diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 0483cb2ea..5b3f09120 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -111,8 +111,6 @@ Miroir Chromecast Lecture dans l\'application Lecture dans %s - Lecture dans le navigateur - Copier le lien Téléchargement automatique Télécharger depuis le miroir Recharger les liens @@ -140,7 +138,7 @@ DNS avec HTTPS Afficher les animés en Anglais (Dub) / sous-titrés Disposition en mode téléphone - %1$s Episode %2$d + episode_action_copy_link Note : %.1f Zoom Adapter à l\'écran @@ -430,12 +428,10 @@ Installer l\'extension d\'abord Playlist HLS Lecteur vidéo préféré - VLC Fin mitigée Introduction mitigée Installation de la mise a jour de l\'application… Impossible d\'installer la nouvelle version de l\'application - Navigateur Web Certains téléphones ne supporte pas le nouvel installateur d\'application. Essayez l\'option de l\'ancien installateur si les mises-à-jour ne s\'installe pas. Précédent Ignorer la configuration @@ -456,7 +452,6 @@ Lecteur interne Application introuvable Trop de texte. Impossible de sauvegarder dans le presse papier. - MPV Installateur de paquet plugins Cela supprimera également tous les plugins du repository @@ -466,7 +461,6 @@ Langage Afficher les popups skip pour les intro / fins Ancienne méthode d\'installation - Web Video Cast Liens Gestes Fonctionnalités du lecteur diff --git a/app/src/main/res/values-hi/strings.xml b/app/src/main/res/values-hi/strings.xml index eed5e44aa..4457b0ec4 100644 --- a/app/src/main/res/values-hi/strings.xml +++ b/app/src/main/res/values-hi/strings.xml @@ -114,8 +114,6 @@ क्रोमकास्ट मिरर एप्प में चलाएं %s में चलाएं - Browser में चलाएं - लिंक कॉपी करें डाउनलोड करें मिरर डाउनलोड लिंक दोबारा लोड करें diff --git a/app/src/main/res/values-hr/strings.xml b/app/src/main/res/values-hr/strings.xml index 44f1bd5b9..dcacbeee3 100644 --- a/app/src/main/res/values-hr/strings.xml +++ b/app/src/main/res/values-hr/strings.xml @@ -253,8 +253,6 @@ Chromecast mirror Pokreni u aplikaciji Pokreni u %s - Pokreni u pregledniku - Kopiraj poveznicu Automatsko preuzimanje Preuzmi zrcalo Ponovo učitaj poveznice @@ -461,9 +459,6 @@ Preferirani video player Interni player Najprije instaliraj proširenje - VLC - MPV - Emitiranje na webu Aplikacija nije pronađena Svi jezici Previše teksta. Nije moguće spremiti u međuspremnik. @@ -495,7 +490,6 @@ Zadane postavke Izgledi Značajke - Web preglednik Preskoči %s Kraj Sažetak @@ -646,7 +640,6 @@ Vaši CloudStream podaci su sada spremljeni u sigurnosnu kopiju. Iako je vjerojatnost mala, neki se uređaji mogu ponašati drugačije. Ako izgubite pristup aplikaciji, potpuno izbrišite podatke aplikacije i obnovite ih pomoću sigurnosne kopije. Ispričavamo se zbog mogućih neugodnosti. Sezona %1$d epizoda %2$d izlazi Cast mirror - Fcast Odaberi uređaj za emitiranje CloudStream Wiki Računi @@ -686,6 +679,5 @@ Stvarno želite trajno izbrisati sve epizode u sljedećoj seriji? \n \n%s - MPV YTDL Još nije učitan nijedan titl \ No newline at end of file diff --git a/app/src/main/res/values-hu/strings.xml b/app/src/main/res/values-hu/strings.xml index 1426e8a38..f124ad062 100644 --- a/app/src/main/res/values-hu/strings.xml +++ b/app/src/main/res/values-hu/strings.xml @@ -182,7 +182,6 @@ Dokumentumfilm Ázsiai dráma Linkek újratöltése - Link másolás Letöltés mirror Automatikus letöltés Adatok eltárolva @@ -227,7 +226,6 @@ Chromecast mirror Lejátszás az alkalmazásban Lejátszás %s - Lejátszás böngészőben Feliratok letöltése Újracsatlakozás… Húzd balra vagy jobbra a videólejátszóban az idő vezérléséhez @@ -352,7 +350,6 @@ Mit szeretnél látni Minden %s már letöltött Először telepítse a bővítményt - Webböngésző Kinézet Alkalmazás elrendezés Szinkronizálás @@ -368,7 +365,6 @@ Töltse le az összes bővítményt ebből a tárolóból? Biztonságos mód bekapcsolva Méret - MPV Alkalmazás nem található PackageInstaller Rendezés e szerint @@ -403,7 +399,6 @@ Emelt HD HLS lejátszási lista - VLC Nem sikerült telepíteni az alkalmazás új verzióját %s hitelesítve Körvonal @@ -528,7 +523,6 @@ Hivatkozó (opcionális) Nem találhatóak pluginek a repóban Repó nem található, ellenőrizze a címet vagy próbálja VPN-el - Web Videó Cast %s kihagyása A kihagyási felugró ablakok mutatása nyitás/zárás esetén Alapbeállítás diff --git a/app/src/main/res/values-in/strings.xml b/app/src/main/res/values-in/strings.xml index 09dfb5322..efd0ed0cf 100644 --- a/app/src/main/res/values-in/strings.xml +++ b/app/src/main/res/values-in/strings.xml @@ -221,8 +221,6 @@ Mirror Chromecast Putar di aplikasi Putar di %s - Putar di browser - Salin tautan Download otomatis Download mirror Muat ulang tautan @@ -442,8 +440,6 @@ Bahasa Pemutar video utama Pemutar Bawaan - VLC - MPV Terunduh %1$d %2$s Memulai mengunduh %1$d %2$s… Semua fitur tambahkan dimatikan karena crash, untuk memudahkanmu mencari penyebab crash. @@ -495,9 +491,7 @@ Tidak Memasang pembaruan… Tidak dapat memasang versi terbaru - Web browser Aplikasi tidak ditemukan - Web Video Cast Hapus Riwayat Tampilkan popup untuk skip sesi pembuka/akhir Mengunduh pembaruan… @@ -643,7 +637,6 @@ Akan datang di %s Cermin Cast Pilih perangkat cast - Fcast CloudStream Wiki Keamanan Akun diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index f498ccae1..590c167d9 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -243,8 +243,6 @@ Mirror Chromecast Riproduci in app Riproduci in %s - Riproduci nel browser - Copia link Download Mirror download Aggiorna link @@ -448,10 +446,6 @@ Playlist HLS Video player preferito Player interno - VLC - MPV - Cast Web Video - Web browser App non trovata Tutte le lingue Salta %s @@ -642,7 +636,6 @@ L\'episodio %2$d della stagione %1$d uscirà tra Mirror cast Seleziona dispositivo per cast - Fcast Wiki di CloudStream Conti Sicurezza @@ -683,6 +676,5 @@ \n%s Anteprima barra di ricerca Abilita miniatura di anteprima sulla barra di ricerca - MPV YTDL Nessun sottotitolo caricato \ No newline at end of file diff --git a/app/src/main/res/values-iw/strings.xml b/app/src/main/res/values-iw/strings.xml index 6316d7f79..6ebe405bc 100644 --- a/app/src/main/res/values-iw/strings.xml +++ b/app/src/main/res/values-iw/strings.xml @@ -168,7 +168,6 @@ דרמה אסייתית כרומקאסט את הפרק כרומקאסט את המראה - נגן בדפדפן תווית כתוביות החלף רכיבי ממשק משתמש בפוסטר דלג על הפתיח @@ -326,7 +325,6 @@ שגיאת הורדה, בדוק הרשאות אחסון נגן באפליקציה נגן ב %s - העתק קישור הורדה אוטומטית טען מחדש קישורים תווית איכות @@ -431,7 +429,6 @@ כל %s כבר הורד מחברים שפה - MPV קרדיטים מיין בחר ספרייה @@ -445,8 +442,6 @@ הורד את כל התוספים ממאגר זה? רצועות שמע מסלולים - Web Video Cast - דפדפן אינטרנט כל התוספים נכבו עקב התרסקות כדי לעזור לך למצוא את האחד הגורם לצרות. מוריד החבילות עודכן %d תוספים @@ -479,7 +474,6 @@ פלייליסט HLS נגן וידאו מועדף נגן פנימי - VLC האפליקציה לא נמצאה כל השפות דלג %s diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index ed9850e8e..3ca79b3d5 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -144,9 +144,6 @@ 完成 進行中 デフォルト - ウェブブラウザ - VLC - MPV 言語 作成者 サイズ diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml index 6993ec1c9..d62ecb69b 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -186,8 +186,6 @@ Chromecast 미러링 앱에서 재생 %s에서 재생 - 브라우저에서 재생 - 링크 복사 자동 다운로드 다운로드 미러 링크 새로고침 @@ -445,7 +443,6 @@ 소개 유형 먼저 확장 프로그램을 설치하세요 - 웹 브라우저 앱을 찾을 수 없음 모든 언어 건너뛰기 %s @@ -482,11 +479,8 @@ \n파일이 제거될 때까지 시작 시 확장 프로그램을 로드하지 않습니다. HLS 재생목록 내부 플레이어 - MPV 선호하는 동영상 플레이어 - VLC 라이브러리 선택 - 웹 동영상 캐스트 이 목록이 비어 있습니다. 다른 목록으로 전환해 보세요. 필러 라이브 스트리밍 재생 @@ -579,7 +573,6 @@ 자동 회전 모바일 데이터 사용 불가능 - fcast 캐스트 장치 선택 복사하는 중 오류가 발생했습니다. 로그캣을 복사하고 문의하십시오. 구독 취소 diff --git a/app/src/main/res/values-lt/strings.xml b/app/src/main/res/values-lt/strings.xml index fe205dab7..cc68d77eb 100644 --- a/app/src/main/res/values-lt/strings.xml +++ b/app/src/main/res/values-lt/strings.xml @@ -163,10 +163,8 @@ Įvertinta Praleisti šį atnaujinimą Veiksmai - Kopijuoti nuorodą Paleisti programoje Sinchronizuoti - Paleisti naršyklėje Pašalinti puslapį Perkrauti nuorodos Išjungti @@ -192,7 +190,6 @@ Mobilūs duomenys šaunusPrisijungimoVardas Autoriai - Naršyklė Visos kalbos 4K Pradėta siųsti %1$d %2$s… @@ -206,7 +203,6 @@ Kalbos kodas (lt) Baigta Išvalyti istoriją - VLC Redaguoti Wi-Fi Greitai būs… @@ -227,7 +223,6 @@ UHD Dydis Palaikoma - MPV ManoŠaunusPuslapis Anonsas Istorija diff --git a/app/src/main/res/values-lv/strings.xml b/app/src/main/res/values-lv/strings.xml index 8f13b93c0..9469aa8e8 100644 --- a/app/src/main/res/values-lv/strings.xml +++ b/app/src/main/res/values-lv/strings.xml @@ -241,8 +241,6 @@ Chromecast morror Palaist aplikācijā Atskaņot uekšā %s - Atskaņot internetā - Kopēt linku Automātiski ielādēt Ielādēt spoguli Pārlādēt saites @@ -437,8 +435,6 @@ HLS atskaņošanas saraksts Vēlamais video atskaņotājs Iekšējais atskaņotājs - MPV - Web video apraide Aplikācijs nav atrasta Visas valodas Beigas @@ -513,8 +509,6 @@ Lejupielādējiet to vietņu sarakstu, kuras vēlaties izmantot Vispirms instalējiet paplašinājumu Atvēršana - VLC - Interneta mekletājs Sākums Izlaist %s Noņemt no skatītajiem diff --git a/app/src/main/res/values-mk/strings.xml b/app/src/main/res/values-mk/strings.xml index 671257492..79dc1ee7e 100644 --- a/app/src/main/res/values-mk/strings.xml +++ b/app/src/main/res/values-mk/strings.xml @@ -164,8 +164,6 @@ Огледало на Chromecastr Пушти во апликацијата Пушти на %s - Пушти на прелистувач - Копирај линк Авто превземање Превземи Mirror Вчитај повторно врски @@ -297,7 +295,6 @@ Износот на барањето што се користи кога плеерот е скриен Преземи преводи Јавна листа - MPV Инсталатор на пакети ОВА Ажурирање и резервна копија @@ -425,7 +422,6 @@ /?? hello@world.com +30 - VLC Рестартирај Цртан филм Почна да презема %1$d %2$s… @@ -448,7 +444,6 @@ Камера Камера SDR - Веб-прелистувач Апликацијата не е пронајдена Корисничко име Отвори со @@ -488,7 +483,6 @@ Сите екстензии беа исклучени поради пад за да ви помогнат да ја пронајдете онаа што предизвикува проблеми. Оцена: %s Големина - Веб-видео Cast Сите јазици Исчисти историја Обележи како гледано @@ -611,7 +605,6 @@ Сега е направена резервна копија на вашите податоци на CloudStream. Иако можноста за ова е многу мала, сите уреди можат да се однесуваат поинаку. Во ретки случаи, кога ќе се заклучите од пристап до апликацијата, целосно исчистете ги податоците на апликацијата и вратете ги од резервна копија. Многу ни е жал за какви било непријатности што произлегуваат од ова. Ресетирај Сезона %1$d Епизода %2$d ќе биде објавена за - Fcast Одбери уред да кастираш Оневозможи оптимизација на батерија Отклучи CloudStream diff --git a/app/src/main/res/values-ml/strings.xml b/app/src/main/res/values-ml/strings.xml index 1c2d855e5..bf0fede72 100644 --- a/app/src/main/res/values-ml/strings.xml +++ b/app/src/main/res/values-ml/strings.xml @@ -151,8 +151,6 @@ Chromecast Mirror --> ആപ്പിൽ പ്ലേയ് ചെയ്യുക %sയിൽ പ്ലേയ് ചെയ്യുക - ബ്രൗസറിൽ പ്ലേയ് ചെയ്യുക - ലിങ്ക് പകർത്തുക ഡൌൺലോഡ് ചെയ്യൂ മിറർ ഡൗണ്ലോഡ് ലിങ്ക്സ് വീണ്ടും ലോഡുചെയ്യുക diff --git a/app/src/main/res/values-ms/strings.xml b/app/src/main/res/values-ms/strings.xml index 07154776d..e865d58db 100644 --- a/app/src/main/res/values-ms/strings.xml +++ b/app/src/main/res/values-ms/strings.xml @@ -2,7 +2,6 @@ Semua bahasa Langkau %s - Pelayar web Sejarah Kosongkan sejarah Pengenalan @@ -232,7 +231,6 @@ Dinaikkan Lihat video dalam bahasa-bahasa ini Normal - Main dalam pelayar Tambah Diguna Anime @@ -323,7 +321,6 @@ Chromecast episod Main dalam %s Muat turun gagal, cek keizinan storan - Salin pautan Muat turun cermin Muat turun sari kata Label sub @@ -449,8 +446,6 @@ Pengesahan Password/PIN Sari kata belum tetapkan lagi Disokong - MPV - Fcast Ralat tidak dapat akses Clipboard, Sila cuba sekali lagi. Ralat menyalin, Sila salin logcat dan hubungi penyokong aplikasi. Amaran @@ -462,8 +457,6 @@ Maks Amaran: CloudStream 3 tidak bertanggungjawab atas penggunaan tambahan pihak ketiga dan tidak memberi sumbang kepada mereka! Mula semula aplikasi untuk lihat perubahan. - VLC - MPV YTDL Senarai ini kosong. Sila tukar yang lain. Data mudah alih Tambah ke kegemaran diff --git a/app/src/main/res/values-my/strings.xml b/app/src/main/res/values-my/strings.xml index 31e6ef276..9d82dd47d 100644 --- a/app/src/main/res/values-my/strings.xml +++ b/app/src/main/res/values-my/strings.xml @@ -157,8 +157,6 @@ Chromecast ဖန်သားပြင် အက်ပ်တွင်းဖွင့် ဖွင့်ရန် %s - ဘရောက်ဇာထဲမှာ ဖွင့်ရန် - လင့်ကူးယူရန် အလိုအလျောက်ဒေါင်းလုဒ် လင့်များကို ပြန်စစ်ရန် အရည်အသွေး အမှတ်အသား @@ -338,7 +336,6 @@ နောက်သို့ အပ်ဒိတ်လုပ်ပြီး %d ဖြည့်စွက်များ ဒေါင်းလုဒ်မလုပ်ရသေး: %d - ဝဘ်ဘရောက်ဇာ အက်ပ်မတွေ့ပါ ဘာသာစကားအားလုံး ကျော်ရန် %s @@ -422,9 +419,6 @@ ထောက်ပံ့ထားသော ဘာသာစကား အဆက်များကိုအရင်သွင်းပါ - VLC - MPV - ဝဘ်ထဲတွင်ဖွင့်ရန် အစပိုင်း အဆုံးပိုင်း ကြည့်ရှုခဲ့သည်များကိုရှင်းရန် diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml index 4bef20cc2..6518eb0e7 100644 --- a/app/src/main/res/values-nl/strings.xml +++ b/app/src/main/res/values-nl/strings.xml @@ -235,8 +235,6 @@ Chromecast mirror Speel in app Speel in %s - Speel in browser - Kopieer link Automatisch downloaden Download mirror Herlaad Linkss @@ -409,7 +407,6 @@ Kan %s niet laden Alle %s reeds gedownload plugin - VLC Sla %s over Links App updates @@ -468,10 +465,7 @@ Herhaal installatieproces Automatisch bijwerken plugin Sommige telefoons ondersteunen het nieuwe installatieprogramma niet. Probeer de oude optie als de updates niet worden geïnstalleerd. - Web Video Cast Interne speler - MPV - Web browser Gemengd einde Herhaling Start diff --git a/app/src/main/res/values-nn/strings.xml b/app/src/main/res/values-nn/strings.xml index 33ebe1b51..5b5577c2e 100644 --- a/app/src/main/res/values-nn/strings.xml +++ b/app/src/main/res/values-nn/strings.xml @@ -149,8 +149,6 @@ Kjeldefeil Spel av i programmet Spel av i %s - Spel av i nettlesaren - Kopier lenke Automatisk nedlasting Last inn lenker på nytt Last ned undertekstar diff --git a/app/src/main/res/values-no/strings.xml b/app/src/main/res/values-no/strings.xml index 41117f104..ac13f57f9 100644 --- a/app/src/main/res/values-no/strings.xml +++ b/app/src/main/res/values-no/strings.xml @@ -171,8 +171,6 @@ Støpt Speil Spill i appen Spill i %s - Spill i nettleseren - Kopier link Automatisk nedlasting Last ned speil Last inn lenker på nytt @@ -250,7 +248,6 @@ HLS-spilleliste Foretrukket videospiller Intern spiller - VLC Alle språk Hopp over %s Tøm historikk @@ -283,7 +280,6 @@ Beskrivelse Legg til konto Normal - MPV Dobbelttrykk for å sette på pause +30 Skygge @@ -416,7 +412,6 @@ Kunne ikke logge inn på %s Store bokstaver i undertekster Utviklere - Nettleser Sensurerbart Vev Lenke til strøm @@ -450,7 +445,6 @@ Fjern unødvendig informasjon fra undertekster Ekstra Filtrer etter foretrukket mediaspråk - Vev-videosending Tilbakeblikk SD Forfilm diff --git a/app/src/main/res/values-or/strings.xml b/app/src/main/res/values-or/strings.xml index a9cff7edf..1a7d9c72f 100644 --- a/app/src/main/res/values-or/strings.xml +++ b/app/src/main/res/values-or/strings.xml @@ -28,14 +28,12 @@ ଟି ଅଧ୍ୟାୟ ଅଧ୍ୟାୟ %s‌ରେ ଚଲାଅ - ବ୍ରାଉଜର୍‌ରେ ଚଲାଅ ଉପଶୀର୍ଷକ ଡାଉନଲୋଡ୍ କରିବା /%d /?? ଅଧ୍ୟାୟ %d ମୁକ୍ତିଲାଭ କଲା! ସ୍ୱତଃ ଡାଉନଲୋଡ୍ ଲିଙ୍କ୍‌ଗୁଡ଼ିକୁ ପୁନଃଲୋଡ୍ କରିବା - ଲିଙ୍କ୍ କପି କରିନେବା ଆପ୍‌ରେ ଚଲାଅ Chromecast ଅଧ୍ୟାୟ @@ -61,8 +59,6 @@ ପ୍ରାନ୍ତ ଆପ୍ ମିଳିଲା ନାହିଁ ସବୁ ଭାଷା - VLC - MPV ମିଶ୍ରିତ ପ୍ରାନ୍ତ ମିଶ୍ରିତ ଆଦ୍ୟ ଶ୍ରେୟ diff --git a/app/src/main/res/values-pl/array.xml b/app/src/main/res/values-pl/array.xml index a43d7bcfe..45a8e56e1 100644 --- a/app/src/main/res/values-pl/array.xml +++ b/app/src/main/res/values-pl/array.xml @@ -161,32 +161,6 @@ @string/show_title_key - - @string/episode_action_chromecast_episode - @string/episode_action_chromecast_mirror - @string/episode_action_play_in_app - @string/episode_action_play_in_format - @string/episode_action_play_in_browser - @string/episode_action_copy_link - @string/episode_action_auto_download - @string/episode_action_download_mirror - @string/episode_action_download_subtitle - @string/episode_action_reload_links - - - - 4 - 5 - 1 - 2 - 3 - 9 - 6 - 7 - 13 - 8 - - @string/automatic @string/phone_layout diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index 8f0c0b125..2f26c3f5b 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -232,8 +232,6 @@ Mirror dla Chromecast Odtwórz w aplikacji Odtwórz w %s - Odtwórz w przeglądarce - Kopiuj link Automatyczne pobieranie Pobierz mirror Odśwież linki @@ -421,10 +419,6 @@ Playlista HLS Preferowany odtwarzacz wideo Odtwarzacz wewnętrzny - VLC - MPV - Web Video Cast - Przeglądarka Aplikacja nie została znaleziona Wszystkie języki Wyczyść historię @@ -621,7 +615,6 @@ Resetuj Nadchodzące w %s Odcinek %2$d sezonu %1$d wyjdzie za - Fcast Wybierz urządzenie do transmisji Mirror transmisji Wiki CloudStream @@ -664,6 +657,5 @@ Usuń (%1$d | %2$s) Podgląd paska przewijania Włącz podgląd miniatury na pasku wyszukiwania - MPV YTDL Nie wczytano jeszcze napisów \ No newline at end of file diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml index 2afd50310..7fdbc6bee 100644 --- a/app/src/main/res/values-pt/strings.xml +++ b/app/src/main/res/values-pt/strings.xml @@ -228,8 +228,6 @@ Alternativa pelo Chromecast Reproduzir na app Reproduzir no %s - Reproduzir no navegador - Copiar link Transferência Automática Transferir por servidor alternativo Recarregar links @@ -441,18 +439,14 @@ Abertura Selecionar Biblioteca Contorna o bloqueio de URLs raw do GitHub usando jsDelivr. Pode atrasar as atualizações por uns dias. - VLC Todas as linguagens Atualizado (Novo para Antigo) Inscrito HDR Reiniciar - Navegador Web Atualizado (Antigo para Novo) - Web Video Cast DVD Instalador de pacotes - MPV Remover dos assistidos Não foi possível instalar a nova versão do aplicativo Inscrição cancelada em %s @@ -616,8 +610,7 @@ Desativar a otimização da bateria Para garantir descarregamentos ininterruptos e notificações de programas de TV subscritos, o CloudStream precisa de permissão para ser executado em segundo plano. Ao premir OK, será direcionado para informações da aplicação. Aí, desloque-se para utilização da bateria da aplicação e defina a utilização da bateria para sem restrições. Tenha em atenção que esta permissão não significa que o CS3 irá esgotar a sua bateria. Este só funcionará em segundo plano quando necessário, como ao receber notificações ou baixar vídeos de extensões oficiais. Se optar por cancelar, pode ajustar esta definição mais tarde em definições gerais. Reiniciar - Episódio %2$d da Temporada %1$d vai ser lançado em - Fcast + Episódio %1$d Episódio %2$d vai ser lançado em Escolha o dispositivo Transmitir hide_player_control_names_key diff --git a/app/src/main/res/values-qt/strings.xml b/app/src/main/res/values-qt/strings.xml index 378e3aaec..8f0e14cbc 100644 --- a/app/src/main/res/values-qt/strings.xml +++ b/app/src/main/res/values-qt/strings.xml @@ -144,8 +144,6 @@ aoohaaahhu ahouuhhh ooo-ahahaauuh aaahhu ooo-ahah ohaauuh %s - ahoha ooo-ahahohoohah oooohh - aauugghhahhaauugghh aaaghhoooohh aaahhu ahooo ohooo-ahahaohaohahhhoouuh ahoooaaahhuahaaahhuoha @@ -318,7 +316,6 @@ aaahh uuuugggh oooohh oooogggoog uuuuhhhaagg - uuh uuh aahh uugg oooogg ag aagg ug ooooggguh ooooggg %d aahh @@ -472,8 +469,6 @@ ooh oooohhhooh oogg oooogg ooh uuh uh g ooogg oh uuhh uug uuhh ooh aah uuuuggg ooooggg ooooggg aaaagggh uuuugg - ooh uuuhh aahh - uuh uuuuhhh aah ooh uuugg uuuuhhh uuuuhh aagg oooohhh @@ -617,8 +612,6 @@ %s (Disabled) Rating: %s aaaagg - oog - uuuhh aaaagg aahh oooohh uuuuuk aaagg aaaahhh diff --git a/app/src/main/res/values-ro/strings.xml b/app/src/main/res/values-ro/strings.xml index 8105aa3e8..ec1115112 100644 --- a/app/src/main/res/values-ro/strings.xml +++ b/app/src/main/res/values-ro/strings.xml @@ -228,8 +228,6 @@ Chromecast alternativ Redă în Aplicație Redă în %s - Redă în Browser - Copiază link-ul Auto-descărcare Descărcă prin Alernativă Reîncărcare link-uri @@ -467,7 +465,6 @@ Nu Abonat la %s Aplicația va fi actualizată la ieșire - Web Video Cast Ocoliri ISP Anterior Sortează @@ -475,7 +472,6 @@ Filtrați în funcție de limba media preferată Episodul %d a fost lansat! Android TV - VLC Urmăriți videoclipuri în aceste limbi Revenire Acțiuni @@ -483,7 +479,6 @@ URL invalid Toate extensiile au fost dezactivate din cauza unei defecțiuni pentru a vă ajuta să o găsiți pe cea care cauzează probleme. Se descarcă actualizarea aplicației… - Browser web CloudStream nu are niciun site instalat din start. Trebuie să instalați site-urile din depozite. \n \nAlăturați-vă Discord-ului nostru sau căutați online. @@ -522,7 +517,6 @@ Se actualizează emisiunile abonate Abonat Lista publică - MPV Moştenit Test de furnizor Furnizori @@ -640,6 +634,5 @@ Sezonul %1$d Episod %2$d va fi lansat în Selectați divece-ul pe care doriți să faceți cast Cast mirror - Fcast hide_player_control_names_key \ No newline at end of file diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index e2f6a4b13..c251ca9bb 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -190,7 +190,6 @@ Торренты Другое Ошибка загрузки, проверьте разрешения хранилища - Копировать ссылку Автоскачивание Загрузка. Зеркало Сезон @@ -270,8 +269,6 @@ Размер Авторы Поддерживается - VLC - MPV Пропустить %s Концовка Используйте яркость системы в проигрывателе приложения вместо темного наложения @@ -293,7 +290,6 @@ Неожиданная ошибка плеера Эпизод Chromecast Воспроизведение на %s - Воспроизвести в браузере Скачать субтитры Знак качества Переключение элементов интерфейса на плакате @@ -309,7 +305,6 @@ %d из 10 Посмотреть информацию о сбое Предпочитаемый видеоплеер - Веб-браузер Приложение не найдено Все языки Вступление @@ -492,7 +487,6 @@ Отображать рандомную кнопку в библиотеке и главной странице Рандомная кнопка Legacy (старый) - Web Video Cast Не отправляет данные Перезагрузить ссылки Предпочтительные медиа @@ -620,7 +614,6 @@ Сброс Сезон %1$d Эпизод %2$d выйдет Выйдет %s - Fcast Выберите девайс для трансляции hide_player_control_names_key В данный момент загрузок нет. diff --git a/app/src/main/res/values-sk/strings.xml b/app/src/main/res/values-sk/strings.xml index 4e38be6b9..196ed1d60 100644 --- a/app/src/main/res/values-sk/strings.xml +++ b/app/src/main/res/values-sk/strings.xml @@ -188,7 +188,6 @@ Žiadne titulky Anime Kreslené - Skopírovať odkaz Automaticky stiahnuť Zrkadlo sťahovania Zamknúť @@ -320,7 +319,6 @@ Ázijské drámy Anime Chyba zdroja - Prehrať v prehliadači Štítok dabingu Štítok titulkov Názov diff --git a/app/src/main/res/values-so/strings.xml b/app/src/main/res/values-so/strings.xml index e4ee98f96..8b1e4cc15 100644 --- a/app/src/main/res/values-so/strings.xml +++ b/app/src/main/res/values-so/strings.xml @@ -119,7 +119,6 @@ Asalkiisa Isla appkan ku daawo Ku daawo %s - Ku daawo barawsarka Dejinta iskeed ah Deji toorentiga(mirror) Cusbooneysii lifaaqyada @@ -239,7 +238,6 @@ Eeg xogaha hoose 🐈 Badhinka xajmiga daaraha Fashil ka yimi dhiibaha - Koobu garee lifaaqa Sharraxaad ma leh Sharraxaadda Duluc ma leh @@ -472,10 +470,6 @@ Kordhiyeyaasha Liiska bulshada kale Muqaal daaraha appka - VLC - MPV - Web Video Cast - Barawsarka Kuuguma jiro appkaasi Dhammaan luuqadaha Is dhaafi %s diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml index 9757fdf67..06f388848 100644 --- a/app/src/main/res/values-sv/strings.xml +++ b/app/src/main/res/values-sv/strings.xml @@ -148,8 +148,6 @@ Chromecasta en Länk Spela upp i appen Spela upp i %s - Spela upp i webbläsaren - Kopiera länk Automatisk nerladdning Ladda ner en specifik länk Ladda om alla länkar @@ -379,13 +377,11 @@ Visa sub Kunde inte öppna appen GitHub Proxy - Webbläsarens videospelare Installerar uppdatering till appen… Kunde inte nå GitHub, sätter på jsDelivr proxy… Leverantörer Nytt webbplatsnamn Ta bort reklam från undertexter - VLC Alla språk Rensa historik PackageInstaller @@ -409,8 +405,6 @@ Videospelare Öppna med Synkronisera undertexter - MPV - Web Video Cast Misslyckades Ja Videospår @@ -619,7 +613,6 @@ Kommer ut om %s Fel vid kopiering, kopiera logcat och kontakta appsupport. Media - Fcast Cast mirror Säsong %1$d Avsnitt %2$d kommer att släppas om Välj cast-enhet diff --git a/app/src/main/res/values-ta/strings.xml b/app/src/main/res/values-ta/strings.xml index c8c3243cd..a2b4cadd2 100644 --- a/app/src/main/res/values-ta/strings.xml +++ b/app/src/main/res/values-ta/strings.xml @@ -266,8 +266,6 @@ மறுதொடக்கம் விவரம் ஆசிரியர்கள் - வலை வீடியோ நடிகர்கள் - இணைய உலாவி %s ஐத் தவிர்க்கவும் மறுபரிசீலனை செய்யுங்கள் அறிமுகம் @@ -365,7 +363,6 @@ முன்மாதிரி தளவமைப்பு பதிவிறக்கம் செய்யப்பட்ட கோப்பு பகுத்தல் - எம்.பி.வி. உங்கள் நூலகம் காலியாக உள்ளது :( \n நூலகக் கணக்கில் உள்நுழைக அல்லது உங்கள் உள்ளக நூலகத்தில் காட்சிகளைச் சேர்க்கவும். குழுவிலகவும் @@ -431,8 +428,6 @@ மூல பிழை தொலை பிழை ரெண்டரர் பிழை - உலாவியில் விளையாடுங்கள் - இணைப்பை நகலெடுக்கவும் ஆட்டோ பதிவிறக்கம் கண்ணாடியைப் பதிவிறக்கவும் இணைப்புகளை மீண்டும் ஏற்றவும் @@ -520,7 +515,6 @@ அளவு ஆதரிக்கப்பட்டது முதலில் நீட்டிப்பை நிறுவவும் - Fcast காச்ட் சாதனத்தைத் தேர்ந்தெடுக்கவும் அனைத்து மொழிகளும் ஆம் @@ -551,7 +545,6 @@ பதிவிறக்கம் செய்யப்படவில்லை: %d புதுப்பிக்கப்பட்டது %d செருகுநிரல்கள் உள் வீரர் - வி.எல்.சி. திறப்பு கலப்பு திறப்பு வரவு diff --git a/app/src/main/res/values-tl/strings.xml b/app/src/main/res/values-tl/strings.xml index d832144dd..5fd25031e 100644 --- a/app/src/main/res/values-tl/strings.xml +++ b/app/src/main/res/values-tl/strings.xml @@ -174,8 +174,6 @@ Chromecast Mirror I-play sa App I-play sa %s - I-play sa browser - Kopyahin ang Link Awtomatiking i-download Download mirror Subukan muli diff --git a/app/src/main/res/values-tr/array.xml b/app/src/main/res/values-tr/array.xml index 22a94ebf0..4ec45e6d1 100644 --- a/app/src/main/res/values-tr/array.xml +++ b/app/src/main/res/values-tr/array.xml @@ -33,22 +33,6 @@ 6 - - @string/player_settings_play_in_app - @string/player_settings_play_in_vlc - @string/player_settings_play_in_mpv - @string/player_settings_play_in_web - @string/player_settings_play_in_browser - - - - 1 - 2 - 5 - 4 - 3 - - @string/resolution_and_title @string/title @@ -187,32 +171,6 @@ @string/show_title_key - - @string/episode_action_chromecast_episode - @string/episode_action_chromecast_mirror - @string/episode_action_play_in_app - @string/episode_action_play_in_format - @string/episode_action_play_in_browser - @string/episode_action_copy_link - @string/episode_action_auto_download - @string/episode_action_download_mirror - @string/episode_action_download_subtitle - @string/episode_action_reload_links - - - - 4 - 5 - 1 - 2 - 3 - 9 - 6 - 7 - 13 - 8 - - @string/automatic @string/phone_layout diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index d40e5d7aa..b516de738 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -258,8 +258,6 @@ Bağlantıyı Chromecast ile yayınla Burada oynat %s üzerinden oynat - Tarayıcıda oynat - Bağlantıyı kopyala Otomatik indir Şu kaynaktan indir Bağlantıları yenile @@ -482,10 +480,6 @@ HLS Oynatma Listesi Tercih edilen video oynatıcısı Dahili oynatıcı - VLC - MPV - Web Video Yayını - İnternet tarayıcısı Uygulama bulunamadı Geçmiş İzlendi olarak işaretle @@ -669,7 +663,6 @@ Sezon %1$d Bölüm %2$d tarihinde yayınlanacak Yansıtılacak cihaz seç Ekran yansıtma - Fcast CloudStream Viki Güvenlik Hesaplar diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index 010af23c9..c5e234f0d 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -248,7 +248,6 @@ Змінити розмір Короткий зміст Фільми - Скопіювати посилання Перезавантажити посилання Документальні фільми NSFW @@ -257,7 +256,6 @@ Торент Мітка якості NSFW - Переглянути в браузері Несподівана помилка плеєра Помилка завантаження, перевірте дозволи на зберігання Епізод Chromecast @@ -445,10 +443,6 @@ Спочатку встановіть розширення Список відтворення HLS Вбудований плеєр - VLC - MPV - Web Video Cast - Веббраузер Ендінґ Коротке повторення Пропустити %s @@ -620,7 +614,6 @@ Скинути Наступний через %s %1$d сезон %2$d епізод вийде через - Fcast Оберіть пристрій для трансляції Трансляція через дзеркало CloudStream Wiki @@ -663,6 +656,5 @@ \n%s Попередній перегляд повзунка Ввімкнути мініатюру попереднього перегляду на повзунку - MPV YTDL Субтитри ще не завантажено \ No newline at end of file diff --git a/app/src/main/res/values-ur/strings.xml b/app/src/main/res/values-ur/strings.xml index 5a32dfe8a..06508bc9e 100644 --- a/app/src/main/res/values-ur/strings.xml +++ b/app/src/main/res/values-ur/strings.xml @@ -243,7 +243,6 @@ Chromecast mirror ایپ میں چلائیں %s میں چلائیں - کاپی لنک ڈاؤنلوڈ mirror لنکس کو دوبارہ لوڈ کریں سب ٹائٹلز ڈاؤن لوڈ @@ -336,7 +335,6 @@ کوئی زیرنویس میں دیری نہیں این ایس ایف ڈبلیو آٹو ڈاؤن لوڈ - browser میں چلائیں بہت زیادہ سیٹ ہونے پر کم میموری والی ڈیوائس(جیسے کہ Android TV) پر کریشوں کا سبب بنتا ہے. Remove site Add a clone of an existing site, with a different URL @@ -361,7 +359,6 @@ قرارداد اور عنوان HDR %s سے ان سبسکرائب کیا گیا - ویب ویڈیو کاسٹ 18+ لاگ https://example.com/example.mp4 @@ -427,11 +424,8 @@ حالت سائز زبان - وی ایل سی ترجیحی ویڈیو پلیئر اندرونی پلیئر - ایم پی وی - ویب براؤزر ایپ نہیں ملی Recap مخلوط اختتام diff --git a/app/src/main/res/values-vi/array.xml b/app/src/main/res/values-vi/array.xml index f363befda..c6ff1c4e2 100644 --- a/app/src/main/res/values-vi/array.xml +++ b/app/src/main/res/values-vi/array.xml @@ -153,32 +153,6 @@ @string/show_title_key - - @string/episode_action_chromecast_episode - @string/episode_action_chromecast_mirror - @string/episode_action_play_in_app - @string/episode_action_play_in_format - @string/episode_action_play_in_browser - @string/episode_action_copy_link - @string/episode_action_auto_download - @string/episode_action_download_mirror - @string/episode_action_download_subtitle - @string/episode_action_reload_links - - - - 4 - 5 - 1 - 2 - 3 - 9 - 6 - 7 - 13 - 8 - - @string/automatic @string/phone_layout diff --git a/app/src/main/res/values-vi/strings.xml b/app/src/main/res/values-vi/strings.xml index 53b19bd8b..5c4cd380e 100644 --- a/app/src/main/res/values-vi/strings.xml +++ b/app/src/main/res/values-vi/strings.xml @@ -243,8 +243,6 @@ Chiếu Chromecast Xem với trình phát mặc định Xem với trình phát %s - Xem tại trình duyệt - Sao chép liên kết Tự động tải xuống Nguồn tải xuống Lấy link mới nhất @@ -472,10 +470,6 @@ Hỗ trợ Ngôn ngữ Cài đặt tiện ích trước - VLC - MPV - Web Video Cast - Trình duyệt web Không thấy ứng dụng Tất cả ngôn ngữ Tua %s @@ -671,11 +665,9 @@ \n \n%s Xóa plugin - Fcast Ngày phát hành (Cũ đến mới) Ẩn tên các nút điều khiển Bật chế độ xem trước hình thu nhỏ trên seekbar Xem trước Seekbar - MPV YTDL Chưa tải phụ đề \ No newline at end of file diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index b8b8b4884..3c002c29a 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -258,8 +258,6 @@ Chromecast 鏡像 在應用程式中播放 在 %s 中播放 - 在瀏覽器中播放 - 複製連結 自動下載 下載鏡像 重新載入連結 @@ -482,10 +480,6 @@ HLS 播放清單 偏好影片播放器 內部播放器 - VLC - MPV - 網路影片播放 - 網頁瀏覽器 未找到應用程式 所有語言 跳過 %s @@ -663,7 +657,6 @@ 使用指紋、面容 ID、PIN、圖案和密碼解除鎖定應用程式。 由於多次嘗試失敗,此畫面已關閉。請重新啟動應用程式。 剪貼簿存取失敗,請再試一次。 - Fcast 複製失敗,請複製 logcat 內容並聯繫應用程式支援者。 無法開啟 CloudStream 的應用程式資訊頁面。 您的 CloudStream 資料已完成備份。儘管可能性非常低,但因不同裝置的行為都有所不同,在極少數情況下,您可能會無法存取本應用程式。此時請完全清除本應用程式的資料,再使用已有的備份進行還原。若因此造成任何不便,我們深感抱歉。 diff --git a/app/src/main/res/values-zh/strings.xml b/app/src/main/res/values-zh/strings.xml index ff85df32e..45e350439 100644 --- a/app/src/main/res/values-zh/strings.xml +++ b/app/src/main/res/values-zh/strings.xml @@ -259,8 +259,6 @@ Chromecast 镜像 在应用中播放 在 %s 中播放 - 在浏览器中播放 - 复制链接 自动下载 下载镜像 重新加载链接 @@ -483,10 +481,6 @@ HLS 播放列表 首选视频播放器 内部播放器 - VLC - MPV - 投屏 - 浏览器 未找到应用 所有语言 跳过 %s @@ -665,7 +659,6 @@ 在多次尝试失败后,提示将关闭。只需重启应用程序再试。 即将在 %s CloudStream Wiki - Fcast 选择投射设备 %1$d季%2$d集将在 投射镜像 @@ -674,7 +667,6 @@ 打开本地视频 安全 访问智能手机或电脑上的 %s 并输入上述代码 - MPV YTDL 进度条预览 启用进度条预览缩略图 删除插件 diff --git a/app/src/main/res/values/array.xml b/app/src/main/res/values/array.xml index b077997fe..a987420e9 100644 --- a/app/src/main/res/values/array.xml +++ b/app/src/main/res/values/array.xml @@ -50,24 +50,6 @@ @string/nsfw - - @string/player_settings_play_in_app - @string/player_settings_play_in_vlc - @string/player_settings_play_in_mpv - @string/player_settings_play_in_mpvytdl - @string/player_settings_play_in_web - @string/player_settings_play_in_browser - - - - 1 - 2 - 5 - 6 - 4 - 3 - - @string/resolution_and_title @string/title @@ -226,32 +208,6 @@ @string/show_title_key - - @string/episode_action_chromecast_episode - @string/episode_action_chromecast_mirror - @string/episode_action_play_in_app - @string/episode_action_play_in_format - @string/episode_action_play_in_browser - @string/episode_action_copy_link - @string/episode_action_auto_download - @string/episode_action_download_mirror - @string/episode_action_download_subtitle - @string/episode_action_reload_links - - - - 4 - 5 - 1 - 2 - 3 - 9 - 6 - 7 - 13 - 8 - - @string/automatic @string/phone_layout diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 9d9362bec..56f2465d2 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -17,7 +17,7 @@ subtitle_settings_chromecast_key quality_pref_key quality_pref_mobile_data_key - player_pref_key + player_default_key prefer_limit_title_key prefer_limit_title_rez_key apk_installer_key @@ -381,8 +381,6 @@ Cast mirror Play in app Play in %s - Play in browser - Copy link Auto download Download mirror Reload links @@ -662,12 +660,6 @@ HLS Playlist Preferred video player Internal player - VLC - MPV - MPV YTDL - Web Video Cast - Fcast - Web browser Select cast device App not found All Languages diff --git a/app/src/main/res/xml/settings_player.xml b/app/src/main/res/xml/settings_player.xml index 73f9bb5bf..a2575e315 100644 --- a/app/src/main/res/xml/settings_player.xml +++ b/app/src/main/res/xml/settings_player.xml @@ -22,7 +22,7 @@