mirror of
https://gitlab.futo.org/videostreaming/grayjay.git
synced 2025-04-20 03:24:50 +00:00
Experimentation code
This commit is contained in:
parent
3f9477c246
commit
e87a1c079c
11 changed files with 109 additions and 10 deletions
|
@ -8,6 +8,7 @@ import androidx.work.WorkManager
|
|||
import com.caoccao.javet.values.primitive.V8ValueInteger
|
||||
import com.caoccao.javet.values.primitive.V8ValueString
|
||||
import com.futo.platformplayer.activities.DeveloperActivity
|
||||
import com.futo.platformplayer.activities.MainActivity
|
||||
import com.futo.platformplayer.activities.SettingsActivity
|
||||
import com.futo.platformplayer.api.http.ManagedHttpClient
|
||||
import com.futo.platformplayer.api.media.models.contents.IPlatformContent
|
||||
|
@ -491,6 +492,13 @@ class SettingsDev : FragmentedStorageFileJson() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@FormField(R.string.test_playback, FieldForm.BUTTON,
|
||||
R.string.test_playback, 1)
|
||||
fun testPlayback(context: Context) {
|
||||
context.startActivity(MainActivity.getActionIntent(context, "TEST_PLAYBACK"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -538,6 +538,11 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
|
|||
"IMPORT_OPTIONS" -> {
|
||||
UIDialogs.showImportOptionsDialog(this);
|
||||
}
|
||||
"ACTION" -> {
|
||||
val action = intent.getStringExtra("ACTION");
|
||||
StateDeveloper.instance.testState = "TestPlayback";
|
||||
StateDeveloper.instance.testPlayback();
|
||||
}
|
||||
"TAB" -> {
|
||||
when(intent.getStringExtra("TAB")){
|
||||
"Sources" -> {
|
||||
|
@ -1180,6 +1185,13 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
|
|||
sourcesIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||
return sourcesIntent;
|
||||
}
|
||||
fun getActionIntent(context: Context, action: String) : Intent {
|
||||
val sourcesIntent = Intent(context, MainActivity::class.java);
|
||||
sourcesIntent.action = "ACTION";
|
||||
sourcesIntent.putExtra("ACTION", action);
|
||||
sourcesIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||
return sourcesIntent;
|
||||
}
|
||||
|
||||
fun getImportOptionsIntent(context: Context): Intent {
|
||||
val sourcesIntent = Intent(context, MainActivity::class.java);
|
||||
|
|
|
@ -5,6 +5,7 @@ import com.futo.platformplayer.SignatureProvider
|
|||
import com.futo.platformplayer.api.media.Serializer
|
||||
import com.futo.platformplayer.engine.IV8PluginConfig
|
||||
import com.futo.platformplayer.states.StatePlugins
|
||||
import kotlinx.serialization.Contextual
|
||||
import java.net.URL
|
||||
import java.util.UUID
|
||||
|
||||
|
@ -77,7 +78,8 @@ class SourcePluginConfig(
|
|||
private var _allowUrlsLowerVal: List<String>? = null;
|
||||
private val _allowUrlsLower: List<String> get() {
|
||||
if(_allowUrlsLowerVal == null)
|
||||
_allowUrlsLowerVal = allowUrls.map { it.lowercase() };
|
||||
_allowUrlsLowerVal = allowUrls.map { it.lowercase() }
|
||||
.filter { it.length > 0 && (it[0] != '*' || (_allowRegex.matches(it))) };
|
||||
return _allowUrlsLowerVal!!;
|
||||
};
|
||||
|
||||
|
@ -170,10 +172,12 @@ class SourcePluginConfig(
|
|||
return true;
|
||||
val uri = Uri.parse(url);
|
||||
val host = uri.host?.lowercase() ?: "";
|
||||
return _allowUrlsLower.any { it == host };
|
||||
return _allowUrlsLower.any { it == host || (it.length > 0 && it[0] == '*' && host.endsWith(it.substring(1))) };
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val _allowRegex = Regex("\\*\\.[a-z0-9]*\\.[a-z]*");
|
||||
|
||||
fun fromJson(json: String, sourceUrl: String? = null): SourcePluginConfig {
|
||||
val obj = Serializer.json.decodeFromString<SourcePluginConfig>(json);
|
||||
if(obj.sourceUrl == null)
|
||||
|
|
|
@ -35,4 +35,9 @@ class JSAudioUrlRangeSource : JSAudioUrlSource, IStreamMetaDataSource {
|
|||
indexEnd = _obj.getOrDefault(config, "indexEnd", contextName, null);
|
||||
audioChannels = _obj.getOrDefault(config, "audioChannels", contextName, 2) ?: 2;
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "RangeSource(url=[${getAudioUrl()}], itagId=[${itagId}], initStart=[${initStart}], initEnd=[${initEnd}], indexStart=[${indexStart}], indexEnd=[${indexEnd}]))";
|
||||
return super.toString()
|
||||
}
|
||||
}
|
|
@ -33,4 +33,9 @@ class JSVideoUrlRangeSource : JSVideoUrlSource, IStreamMetaDataSource {
|
|||
indexStart = _obj.getOrDefault(config, "indexStart", contextName, null);
|
||||
indexEnd = _obj.getOrDefault(config, "indexEnd", contextName, null);
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "RangeSource(url=[${getVideoUrl()}], itagId=[${itagId}], initStart=[${initStart}], initEnd=[${initEnd}], indexStart=[${indexStart}], indexEnd=[${indexEnd}]))";
|
||||
return super.toString()
|
||||
}
|
||||
}
|
|
@ -52,6 +52,7 @@ class PackageBridge : V8Package {
|
|||
|
||||
@V8Function
|
||||
fun toast(str: String) {
|
||||
Logger.i(TAG, "Plugin toast [${_config.name}]: ${str}");
|
||||
StateApp.instance.scopeOrNull?.launch(Dispatchers.Main) {
|
||||
try {
|
||||
UIDialogs.toast(str);
|
||||
|
|
|
@ -102,6 +102,7 @@ import com.futo.platformplayer.selectBestImage
|
|||
import com.futo.platformplayer.states.AnnouncementType
|
||||
import com.futo.platformplayer.states.StateAnnouncement
|
||||
import com.futo.platformplayer.states.StateApp
|
||||
import com.futo.platformplayer.states.StateDeveloper
|
||||
import com.futo.platformplayer.states.StateDownloads
|
||||
import com.futo.platformplayer.states.StateHistory
|
||||
import com.futo.platformplayer.states.StatePlatform
|
||||
|
@ -1772,19 +1773,21 @@ class VideoDetailView : ConstraintLayout {
|
|||
}
|
||||
}
|
||||
|
||||
val bestVideoSources = (videoSources?.map { it.height * it.width }
|
||||
val doDedup = false;
|
||||
|
||||
val bestVideoSources = if(doDedup) (videoSources?.map { it.height * it.width }
|
||||
?.distinct()
|
||||
?.map { x -> VideoHelper.selectBestVideoSource(videoSources.filter { x == it.height * it.width }, -1, FutoVideoPlayerBase.PREFERED_VIDEO_CONTAINERS) }
|
||||
?.plus(videoSources.filter { it is IHLSManifestSource || it is IDashManifestSource }))
|
||||
?.distinct()
|
||||
?.filter { it != null }
|
||||
?.toList() ?: listOf();
|
||||
?.toList() ?: listOf() else videoSources?.toList() ?: listOf()
|
||||
val bestAudioContainer = audioSources?.let { VideoHelper.selectBestAudioSource(it, FutoVideoPlayerBase.PREFERED_AUDIO_CONTAINERS)?.container };
|
||||
val bestAudioSources = audioSources
|
||||
val bestAudioSources = if(doDedup) audioSources
|
||||
?.filter { it.container == bestAudioContainer }
|
||||
?.plus(audioSources.filter { it is IHLSManifestAudioSource || it is IDashManifestSource })
|
||||
?.distinct()
|
||||
?.toList() ?: listOf();
|
||||
?.toList() ?: listOf() else audioSources?.toList() ?: listOf();
|
||||
|
||||
val canSetSpeed = !_isCasting || StateCasting.instance.activeDevice?.canSetSpeed == true
|
||||
val currentPlaybackRate = if (_isCasting) StateCasting.instance.activeDevice?.speed else _player.getPlaybackRate()
|
||||
|
@ -2312,6 +2315,15 @@ class VideoDetailView : ConstraintLayout {
|
|||
}
|
||||
|
||||
updateTracker(positionMilliseconds, isPlaying, false);
|
||||
|
||||
if(StateDeveloper.instance.isPlaybackTesting) {
|
||||
if((positionMilliseconds > 1000 * 70 || positionMilliseconds > (video!!.duration * 1000 - 1000))) {
|
||||
StateDeveloper.instance.testPlayback();
|
||||
}
|
||||
else if(video!!.duration > 70 && positionMilliseconds < 10000) {
|
||||
handleSeek(40000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateTracker(positionMs: Long, isPlaying: Boolean, forceUpdate: Boolean = false) {
|
||||
|
|
|
@ -1,11 +1,19 @@
|
|||
package com.futo.platformplayer.states
|
||||
|
||||
import android.content.Context
|
||||
import com.futo.platformplayer.SettingsDev
|
||||
import com.futo.platformplayer.UIDialogs
|
||||
import com.futo.platformplayer.activities.MainActivity
|
||||
import com.futo.platformplayer.api.http.server.ManagedHttpServer
|
||||
import com.futo.platformplayer.api.media.models.contents.IPlatformContent
|
||||
import com.futo.platformplayer.api.media.structures.IPager
|
||||
import com.futo.platformplayer.api.media.structures.PlatformContentPager
|
||||
import com.futo.platformplayer.developer.DeveloperEndpoints
|
||||
import com.futo.platformplayer.engine.exceptions.ScriptExecutionException
|
||||
import com.futo.platformplayer.fragment.mainactivity.main.VideoDetailView
|
||||
import com.futo.platformplayer.logging.Logger
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlin.system.measureTimeMillis
|
||||
|
||||
/***
|
||||
|
@ -23,6 +31,12 @@ class StateDeveloper {
|
|||
|
||||
var devProxy: DevProxySettings? = null;
|
||||
|
||||
var testState: String? = null;
|
||||
val isPlaybackTesting: Boolean get() {
|
||||
return SettingsDev.instance.developerMode && testState == "TestPlayback";
|
||||
};
|
||||
|
||||
|
||||
fun initializeDev(id: String) {
|
||||
currentDevID = id;
|
||||
synchronized(_devLogs) {
|
||||
|
@ -135,6 +149,37 @@ class StateDeveloper {
|
|||
}
|
||||
|
||||
|
||||
private var homePager: IPager<IPlatformContent>? = null;
|
||||
private var pagerIndex = 0;
|
||||
fun testPlayback(){
|
||||
val mainActivity = if(StateApp.instance.isMainActive) StateApp.instance.context as MainActivity else return;
|
||||
StateApp.instance.scope.launch(Dispatchers.IO) {
|
||||
if(homePager == null)
|
||||
homePager = StatePlatform.instance.getHome();
|
||||
var pager = homePager ?: return@launch;
|
||||
pagerIndex++;
|
||||
val video = if(pager.getResults().size <= pagerIndex) {
|
||||
if(!pager.hasMorePages()) {
|
||||
homePager = StatePlatform.instance.getHome();
|
||||
pager = homePager as IPager<IPlatformContent>;
|
||||
}
|
||||
pager.nextPage();
|
||||
pagerIndex = 0;
|
||||
val results = pager.getResults();
|
||||
if(results.size <= 0)
|
||||
null;
|
||||
else
|
||||
results[0];
|
||||
}
|
||||
else
|
||||
pager.getResults()[pagerIndex];
|
||||
|
||||
StateApp.instance.scope.launch(Dispatchers.Main) {
|
||||
mainActivity.navigate(mainActivity._fragVideoDetail, video);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val DEV_ID = "DEV";
|
||||
|
||||
|
@ -152,6 +197,7 @@ class StateDeveloper {
|
|||
it._server?.stop();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@kotlinx.serialization.Serializable
|
||||
|
|
|
@ -645,13 +645,14 @@ abstract class FutoVideoPlayerBase : RelativeLayout {
|
|||
|
||||
when (error.errorCode) {
|
||||
PlaybackException.ERROR_CODE_IO_BAD_HTTP_STATUS -> {
|
||||
Logger.w(TAG, "ERROR_CODE_IO_BAD_HTTP_STATUS ${error.cause?.javaClass?.simpleName}");
|
||||
if(error.cause is HttpDataSource.InvalidResponseCodeException) {
|
||||
val cause = error.cause as HttpDataSource.InvalidResponseCodeException
|
||||
|
||||
Logger.v(TAG, null) {
|
||||
Logger.w(TAG, null) {
|
||||
"ERROR BAD HTTP ${cause.responseCode},\n" +
|
||||
"Video Source: ${V8RemoteObject.gsonStandard.toJson(lastVideoSource)}\n" +
|
||||
"Audio Source: ${V8RemoteObject.gsonStandard.toJson(lastAudioSource)}\n" +
|
||||
"Video Source: ${lastVideoSource?.toString()}\n" +
|
||||
"Audio Source: ${lastAudioSource?.toString()}\n" +
|
||||
"Dash: ${_lastGeneratedDash}"
|
||||
};
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ import androidx.media3.datasource.HttpDataSource;
|
|||
import androidx.media3.datasource.HttpUtil;
|
||||
import androidx.media3.datasource.TransferListener;
|
||||
|
||||
import com.futo.platformplayer.engine.dev.V8RemoteObject;
|
||||
import com.futo.platformplayer.logging.Logger;
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.ForwardingMap;
|
||||
|
@ -46,6 +47,8 @@ import java.util.Map;
|
|||
import java.util.Set;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
|
||||
import kotlinx.serialization.json.Json;
|
||||
|
||||
/*
|
||||
* Based on the default ExoPlayer DefaultHttpDataSource
|
||||
*/
|
||||
|
@ -583,7 +586,7 @@ public class JSHttpDataSource extends BaseDataSource implements HttpDataSource {
|
|||
requestHeaders = result.getHeaders();
|
||||
}
|
||||
|
||||
Logger.Companion.v("JSHttpDataSource", "DataSource REQ: " + requestUrl, null);
|
||||
Logger.Companion.v("JSHttpDataSource", "DataSource REQ: " + requestUrl + "\nHEADERS: [" + V8RemoteObject.Companion.getGsonStandard().toJson(requestHeaders)+ "]", null);
|
||||
|
||||
HttpURLConnection connection = openConnection(new URL(requestUrl));
|
||||
connection.setConnectTimeout(connectTimeoutMillis);
|
||||
|
|
|
@ -477,6 +477,8 @@
|
|||
<string name="removes_all_subscriptions">Removes all subscriptions</string>
|
||||
<string name="settings_related_to_development_server_be_careful_as_it_may_open_your_phone_to_security_vulnerabilities">Settings related to development server, be careful as it may open your phone to security vulnerabilities</string>
|
||||
<string name="start_server">Start Server</string>
|
||||
<string name="test_playback">Test Playback</string>
|
||||
<string name="test_playback_desc">Keeps playing videos</string>
|
||||
<string name="subscriptions_cache_5000">Subscriptions Cache 5000</string>
|
||||
<string name="history_cache_100">History Cache 100</string>
|
||||
<string name="start_server_on_boot">Start Server on boot</string>
|
||||
|
|
Loading…
Add table
Reference in a new issue