mirror of
https://gitlab.futo.org/videostreaming/grayjay.git
synced 2026-05-16 21:12:39 +02:00
Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f1ce0078fd | |||
| 32de3649ef | |||
| 1a301236da | |||
| c695379885 | |||
| 73466892f7 | |||
| bb8a9d4dd7 | |||
| 43ed2b16ab |
@@ -1,3 +1,6 @@
|
||||
variables:
|
||||
GIT_SUBMODULE_STRATEGY: recursive
|
||||
|
||||
buildAndDeployApkUnstable:
|
||||
stage: build
|
||||
script:
|
||||
|
||||
@@ -882,7 +882,7 @@ class Settings : FragmentedStorageFileJson() {
|
||||
|
||||
@FormField(R.string.background_download, FieldForm.TOGGLE, R.string.configure_if_background_download_should_be_used, 1)
|
||||
//@DropdownFieldOptionsId(R.array.background_download)
|
||||
var shouldBackgroundDownload: Boolean = false;
|
||||
var shouldBackgroundDownload: Boolean = true;
|
||||
|
||||
@FormField(R.string.download_when, FieldForm.DROPDOWN, R.string.configure_when_updates_should_be_downloaded, 2)
|
||||
@DropdownFieldOptionsId(R.array.when_download)
|
||||
|
||||
@@ -132,7 +132,7 @@ class UpdateDownloadService : Service() {
|
||||
}
|
||||
|
||||
try {
|
||||
performDownload(StateUpdate.APK_URL, partialFile, version, {
|
||||
performDownload(StateUpdate.getApkUrl(version), partialFile, version, {
|
||||
try {
|
||||
if (announcement != null)
|
||||
announcement?.setProgress(it);
|
||||
|
||||
+2
-2
@@ -170,12 +170,12 @@ class SourcePluginConfig(
|
||||
"Unrestricted Http Header access",
|
||||
"Allows this plugin to access all headers (including cookies and authorization headers) for unauthenticated requests."
|
||||
))
|
||||
if(packagesOptional.contains("Browser") || packages.contains("Browser")) {
|
||||
/*if(packagesOptional.contains("Browser") || packages.contains("Browser")) {
|
||||
list.add(Pair(
|
||||
"Browser Interop",
|
||||
"This plugin requires webbrowser interop. May access urls outside of the restricted urls. This will only work for official plugins and during development builds."
|
||||
))
|
||||
}
|
||||
}*/
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
+17
@@ -79,6 +79,7 @@ open class JSDashManifestRawSource(
|
||||
_obj.getOrDefault<Boolean>(cfg, "canMerge", ctx, false) ?: false
|
||||
|
||||
override var streamMetaData: StreamMetaData? = null
|
||||
var audioStreamMetaData: StreamMetaData? = null
|
||||
|
||||
private var _pregenerate: V8Deferred<String?>? = null
|
||||
fun pregenerateAsync(scope: CoroutineScope): V8Deferred<String?>? {
|
||||
@@ -125,6 +126,14 @@ open class JSDashManifestRawSource(
|
||||
streamMetaData = StreamMetaData(initStart, initEnd, indexStart, indexEnd);
|
||||
}
|
||||
|
||||
val audioInitStart = _obj.getOrDefault<Int>(_config, "audioInitStart", "JSDashManifestRawSource", null) ?: 0;
|
||||
val audioInitEnd = _obj.getOrDefault<Int>(_config, "audioInitEnd", "JSDashManifestRawSource", null) ?: 0;
|
||||
val audioIndexStart = _obj.getOrDefault<Int>(_config, "audioIndexStart", "JSDashManifestRawSource", null) ?: 0;
|
||||
val audioIndexEnd = _obj.getOrDefault<Int>(_config, "audioIndexEnd", "JSDashManifestRawSource", null) ?: 0;
|
||||
if(audioInitEnd > 0 && audioIndexStart > 0 && audioIndexEnd > 0) {
|
||||
audioStreamMetaData = StreamMetaData(audioInitStart, audioInitEnd, audioIndexStart, audioIndexEnd);
|
||||
}
|
||||
|
||||
return@busy result.convert {
|
||||
it.value
|
||||
};
|
||||
@@ -162,6 +171,14 @@ open class JSDashManifestRawSource(
|
||||
if(initEnd > 0 && indexStart > 0 && indexEnd > 0) {
|
||||
streamMetaData = StreamMetaData(initStart, initEnd, indexStart, indexEnd);
|
||||
}
|
||||
|
||||
val audioInitStart = _obj.getOrDefault<Int>(_config, "audioInitStart", "JSDashManifestRawSource", null) ?: 0;
|
||||
val audioInitEnd = _obj.getOrDefault<Int>(_config, "audioInitEnd", "JSDashManifestRawSource", null) ?: 0;
|
||||
val audioIndexStart = _obj.getOrDefault<Int>(_config, "audioIndexStart", "JSDashManifestRawSource", null) ?: 0;
|
||||
val audioIndexEnd = _obj.getOrDefault<Int>(_config, "audioIndexEnd", "JSDashManifestRawSource", null) ?: 0;
|
||||
if(audioInitEnd > 0 && audioIndexStart > 0 && audioIndexEnd > 0) {
|
||||
audioStreamMetaData = StreamMetaData(audioInitStart, audioInitEnd, audioIndexStart, audioIndexEnd);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
|
||||
@@ -134,7 +134,7 @@ class AutoUpdateDialog(context: Context?) : AlertDialog(context) {
|
||||
var inputStream: InputStream? = null;
|
||||
try {
|
||||
val client = ManagedHttpClient();
|
||||
val response = client.get(StateUpdate.APK_URL);
|
||||
val response = client.get(StateUpdate.getApkUrl(_maxVersion));
|
||||
if (response.isOk && response.body != null) {
|
||||
inputStream = response.body.byteStream();
|
||||
val dataLength = response.body.contentLength();
|
||||
|
||||
@@ -15,6 +15,7 @@ import com.futo.platformplayer.R
|
||||
import com.futo.platformplayer.Settings
|
||||
import com.futo.platformplayer.UIDialogs
|
||||
import com.futo.platformplayer.logging.Logger
|
||||
import com.futo.platformplayer.states.StateAnnouncement
|
||||
import com.futo.platformplayer.states.StateApp
|
||||
import com.futo.platformplayer.states.StateBackup
|
||||
import com.google.android.material.button.MaterialButton
|
||||
@@ -81,6 +82,8 @@ class AutomaticBackupDialog(context: Context) : AlertDialog(context) {
|
||||
Settings.instance.backup.didAskAutoBackup = true
|
||||
Settings.instance.save()
|
||||
|
||||
StateAnnouncement.instance.deleteAnnouncement("backup")
|
||||
|
||||
UIDialogs.toast(context, context.getString(R.string.automatic_backup_enabled))
|
||||
try {
|
||||
StateBackup.startAutomaticBackup(true)
|
||||
|
||||
@@ -1462,6 +1462,9 @@ class VideoDownload {
|
||||
if(localAudioSource != null && audioSourceToUse != null && audioSourceToUse is IStreamMetaDataSource)
|
||||
localAudioSource.streamMetaData = (audioSourceToUse as IStreamMetaDataSource).streamMetaData;
|
||||
|
||||
if(localAudioSource != null && localAudioSource.streamMetaData == null && videoSourceToUse is JSDashManifestRawSource)
|
||||
localAudioSource.streamMetaData = (videoSourceToUse as JSDashManifestRawSource).audioStreamMetaData;
|
||||
|
||||
if(existing != null) {
|
||||
existing.videoSerialized = videoDetails!!;
|
||||
if(localVideoSource != null) {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.futo.platformplayer.states
|
||||
|
||||
import android.content.Context
|
||||
import android.view.View
|
||||
import android.view.WindowManager
|
||||
import com.futo.platformplayer.R
|
||||
@@ -122,7 +123,7 @@ class StateAnnouncement {
|
||||
//Special Announcements
|
||||
fun registerPluginUpdate(oldConfig: SourcePluginConfig, newConfig: SourcePluginConfig): SessionAnnouncement {
|
||||
val announcement = SessionAnnouncement(
|
||||
"update-plugin-" + UUID.randomUUID().toString(),
|
||||
"update-plugin-" + oldConfig.id + "-v" + newConfig.version,
|
||||
"${newConfig.name} update v${newConfig.version} available!",
|
||||
"An update is available to upgrade from ${oldConfig.version} to ${newConfig.version}.",
|
||||
AnnouncementType.SESSION,
|
||||
@@ -130,19 +131,62 @@ class StateAnnouncement {
|
||||
null, null,oldConfig.id,
|
||||
newConfig?.absoluteIconUrl?.let { ImageVariable.fromUrl(it) }
|
||||
).withExtraAction("Changelog", StateAnnouncement.ACTION_CHANGELOG, oldConfig.id);
|
||||
announcement.extraObj = newConfig;
|
||||
registerAnnouncementSession(announcement);
|
||||
return announcement;
|
||||
}
|
||||
fun registerPluginUpdated(newConfig: SourcePluginConfig) {
|
||||
registerAnnouncementSession(SessionAnnouncement(
|
||||
"updated-plugin-" + UUID.randomUUID().toString(),
|
||||
val announcement = SessionAnnouncement(
|
||||
"updated-plugin-" + newConfig.id + "-v" + newConfig.version,
|
||||
"${newConfig.name} updated to v${newConfig.version}!",
|
||||
"You have succesfully been updated to v${newConfig.version}.",
|
||||
AnnouncementType.SESSION,
|
||||
null, "updates", null, null,
|
||||
null, null,null,
|
||||
newConfig?.absoluteIconUrl?.let { ImageVariable.fromUrl(it) }
|
||||
).withExtraAction("Changelog", StateAnnouncement.ACTION_CHANGELOG, newConfig.id));
|
||||
).withExtraAction("Changelog", StateAnnouncement.ACTION_CHANGELOG, newConfig.id);
|
||||
announcement.extraObj = newConfig;
|
||||
registerAnnouncementSession(announcement);
|
||||
}
|
||||
|
||||
fun tryAutoUpdatePlugin(oldConfig: SourcePluginConfig, newConfig: SourcePluginConfig) {
|
||||
val context = StateApp.instance.contextOrNull;
|
||||
if(context == null) {
|
||||
registerPluginUpdate(oldConfig, newConfig);
|
||||
return;
|
||||
}
|
||||
StateApp.instance.scopeOrNull?.launch(Dispatchers.IO) {
|
||||
try {
|
||||
val client = ManagedHttpClient();
|
||||
client.setTimeout(10000);
|
||||
val oldScript = StatePlugins.instance.getScript(oldConfig.id) ?: "";
|
||||
val newScript = client.get(newConfig.absoluteScriptUrl)?.body?.string();
|
||||
if(newScript.isNullOrEmpty()) {
|
||||
Logger.w(TAG, "Auto-update for ${oldConfig.name}: no script returned, falling back to notification");
|
||||
withContext(Dispatchers.Main) { registerPluginUpdate(oldConfig, newConfig); }
|
||||
return@launch;
|
||||
}
|
||||
|
||||
if(!oldConfig.isLowRiskUpdate(oldScript, newConfig, newScript)) {
|
||||
withContext(Dispatchers.Main) { registerPluginUpdate(oldConfig, newConfig); }
|
||||
return@launch;
|
||||
}
|
||||
|
||||
StatePlugins.instance.installPluginBackground(context, StateApp.instance.scope, newConfig, newScript,
|
||||
{ _: String, _: Double -> },
|
||||
{ ex ->
|
||||
if(ex == null) {
|
||||
registerPluginUpdated(newConfig);
|
||||
} else {
|
||||
Logger.e(TAG, "Auto-update for ${newConfig.name} failed during install", ex);
|
||||
UIDialogs.appToast("Update for ${newConfig.name} failed\n" + ex.message);
|
||||
}
|
||||
});
|
||||
} catch(ex: Throwable) {
|
||||
Logger.e(TAG, "Auto-update for ${oldConfig.name} failed", ex);
|
||||
withContext(Dispatchers.Main) { registerPluginUpdate(oldConfig, newConfig); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun registerLoading(title: String, description: String, icon: ImageVariable? = null, customId: String? = null): SessionAnnouncement {
|
||||
@@ -282,7 +326,7 @@ class StateAnnouncement {
|
||||
when (actionId) {
|
||||
ACTION_NEVER -> neverAnnouncement(item.id);
|
||||
ACTION_SOMETHING -> actionSomething();
|
||||
ACTION_CHANGELOG -> actionChangelog(actionData);
|
||||
ACTION_CHANGELOG -> actionChangelog(item, actionData);
|
||||
ACTION_UPDATE_PLUGIN -> actionUpdatePlugin(item.id, actionData);
|
||||
}
|
||||
}
|
||||
@@ -314,27 +358,35 @@ class StateAnnouncement {
|
||||
|
||||
}
|
||||
|
||||
private fun actionChangelog(id: String?) {
|
||||
if(id == null)
|
||||
private fun actionChangelog(item: Announcement, id: String?) {
|
||||
val context = StateApp.instance.contextOrNull ?: return;
|
||||
|
||||
val cached = (item as? SessionAnnouncement)?.extraObj as? SourcePluginConfig;
|
||||
if(cached != null) {
|
||||
showPluginChangelog(context, cached);
|
||||
return;
|
||||
}
|
||||
|
||||
StateApp.instance.contextOrNull?.let { context ->
|
||||
StateApp.instance.scopeOrNull?.launch(Dispatchers.IO) {
|
||||
val plugin = StatePlugins.instance.getPlugin(id);
|
||||
if (plugin == null)
|
||||
return@launch
|
||||
val update = StatePlugins.instance.checkForUpdates(plugin.config);
|
||||
if(update == null)
|
||||
return@launch;
|
||||
if(id == null) return;
|
||||
|
||||
StateApp.instance.scopeOrNull?.launch(Dispatchers.Main) {
|
||||
UIDialogs.showChangelogDialog(context, update.version, update.changelog!!.filterKeys { it.toIntOrNull() != null }
|
||||
.mapKeys { it.key.toInt() }
|
||||
.mapValues { update.getChangelogString(it.key.toString()) ?: "" });
|
||||
}
|
||||
StateApp.instance.scopeOrNull?.launch(Dispatchers.IO) {
|
||||
val plugin = StatePlugins.instance.getPlugin(id) ?: return@launch;
|
||||
val update = StatePlugins.instance.checkForUpdates(plugin.config) ?: return@launch;
|
||||
withContext(Dispatchers.Main) {
|
||||
showPluginChangelog(context, update);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun showPluginChangelog(context: Context, config: SourcePluginConfig) {
|
||||
if(config.changelog?.any() != true) {
|
||||
UIDialogs.toast(context, "No changelog available");
|
||||
return;
|
||||
}
|
||||
UIDialogs.showChangelogDialog(context, config.version, config.changelog!!.filterKeys { it.toIntOrNull() != null }
|
||||
.mapKeys { it.key.toInt() }
|
||||
.mapValues { config.getChangelogString(it.key.toString()) ?: "" });
|
||||
}
|
||||
private fun actionUpdatePlugin(notifId: String?, id: String?) {
|
||||
if(id == null)
|
||||
return;
|
||||
@@ -363,7 +415,7 @@ class StateAnnouncement {
|
||||
if(newScript.isNullOrEmpty())
|
||||
throw IllegalStateException("No script found");
|
||||
|
||||
if(true || plugin.config.isLowRiskUpdate(script, update, newScript)) {
|
||||
if(plugin.config.isLowRiskUpdate(script, update, newScript)) {
|
||||
StatePlugins.instance.installPluginBackground(context, StateApp.instance.scope, update, newScript,
|
||||
{ text: String, progress: Double -> },
|
||||
{ ex ->
|
||||
|
||||
@@ -34,6 +34,7 @@ import com.futo.platformplayer.activities.IWithResultLauncher
|
||||
import com.futo.platformplayer.activities.MainActivity
|
||||
import com.futo.platformplayer.api.media.platforms.js.DevJSClient
|
||||
import com.futo.platformplayer.api.media.platforms.js.JSClient
|
||||
import com.futo.platformplayer.api.media.platforms.js.SourcePluginConfig
|
||||
import com.futo.platformplayer.background.BackgroundWorker
|
||||
import com.futo.platformplayer.casting.StateCasting
|
||||
import com.futo.platformplayer.constructs.Event0
|
||||
@@ -804,15 +805,24 @@ class StateApp {
|
||||
if(StateHistory.instance.shouldMigrateLegacyHistory())
|
||||
StateHistory.instance.migrateLegacyHistory();
|
||||
|
||||
StateAnnouncement.instance.deleteAnnouncement("plugin-update")
|
||||
|
||||
scopeOrNull?.launch(Dispatchers.IO) {
|
||||
val updateAvailable = StatePlugins.instance.checkForUpdates()
|
||||
|
||||
withContext(Dispatchers.Main) {
|
||||
if (updateAvailable.isNotEmpty()) {
|
||||
val toNotify = mutableListOf<Pair<SourcePluginConfig, SourcePluginConfig>>();
|
||||
for(update in updateAvailable) {
|
||||
if(!StatePlatform.instance.isClientEnabled(update.first.id))
|
||||
continue;
|
||||
val descriptor = StatePlugins.instance.getPlugin(update.first.id);
|
||||
if(descriptor?.appSettings?.automaticUpdate == true)
|
||||
StateAnnouncement.instance.tryAutoUpdatePlugin(update.first, update.second);
|
||||
else
|
||||
toNotify.add(update);
|
||||
}
|
||||
|
||||
if(toNotify.isNotEmpty()) {
|
||||
UIDialogs.appToast(
|
||||
ToastView.Toast(updateAvailable
|
||||
ToastView.Toast(toNotify
|
||||
.map { " - " + it.first.name }
|
||||
.joinToString("\n"),
|
||||
true,
|
||||
@@ -820,11 +830,8 @@ class StateApp {
|
||||
"Plugin updates available"
|
||||
));
|
||||
|
||||
for(update in updateAvailable)
|
||||
if(StatePlatform.instance.isClientEnabled(update.first.id)) {
|
||||
//UIDialogs.showPluginUpdateDialog(context, update.first, update.second);
|
||||
StateAnnouncement.instance.registerPluginUpdate(update.first, update.second);
|
||||
}
|
||||
for(update in toNotify)
|
||||
StateAnnouncement.instance.registerPluginUpdate(update.first, update.second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,16 +97,16 @@ class StateUpdate {
|
||||
throw Exception("App is not compatible. Supported ABIS: ${Build.SUPPORTED_ABIS.joinToString()}}.");
|
||||
};
|
||||
val VERSION_URL = if (BuildConfig.IS_UNSTABLE_BUILD) {
|
||||
"https://releases.grayjay.app/version-unstable.txt"
|
||||
"https://rel.grayjay.app/version-unstable.txt"
|
||||
} else {
|
||||
"https://releases.grayjay.app/version.txt"
|
||||
"https://rel.grayjay.app/version.txt"
|
||||
}
|
||||
val APK_URL = if (BuildConfig.IS_UNSTABLE_BUILD) {
|
||||
"https://releases.grayjay.app/app-$DESIRED_ABI-release-unstable.apk"
|
||||
fun getApkUrl(version: Int): String = if (BuildConfig.IS_UNSTABLE_BUILD) {
|
||||
"https://rel.grayjay.app/$version/app-$DESIRED_ABI-release-unstable.apk"
|
||||
} else {
|
||||
"https://releases.grayjay.app/app-$DESIRED_ABI-release.apk"
|
||||
"https://rel.grayjay.app/$version/app-$DESIRED_ABI-release.apk"
|
||||
}
|
||||
val CHANGELOG_BASE_URL = "https://releases.grayjay.app/changelogs";
|
||||
val CHANGELOG_BASE_URL = "https://rel.grayjay.app/changelogs";
|
||||
|
||||
fun getApkFile(context: Context, version: Int): File {
|
||||
val dir = File(context.filesDir, "updates");
|
||||
|
||||
Reference in New Issue
Block a user