Merge branch 'master' of gitlab.futo.org:videostreaming/grayjay

This commit is contained in:
Kelvin 2025-07-29 01:39:48 +02:00
commit ac9a51f105
3 changed files with 56 additions and 25 deletions

View file

@ -62,6 +62,7 @@ class ChromecastCastingDevice : CastingDevice {
private val MAX_LAUNCH_RETRIES = 3
private var _lastLaunchTime_ms = 0L
private var _retryJob: Job? = null
private var _autoLaunchEnabled = true
constructor(name: String, addresses: Array<InetAddress>, port: Int) : super() {
this.name = name;
@ -305,6 +306,7 @@ class ChromecastCastingDevice : CastingDevice {
return;
}
_autoLaunchEnabled = true
_started = true;
_sessionId = null;
_launchRetries = 0
@ -546,6 +548,7 @@ class ChromecastCastingDevice : CastingDevice {
if (appId == "CC1AD845") {
sessionIsRunning = true;
_autoLaunchEnabled = false
if (_sessionId == null) {
connectionState = CastConnectionState.CONNECTED;
@ -558,7 +561,6 @@ class ChromecastCastingDevice : CastingDevice {
_transportId = transportId;
requestMediaStatus();
playVideo();
}
}
}
@ -568,21 +570,22 @@ class ChromecastCastingDevice : CastingDevice {
if (System.currentTimeMillis() - _lastLaunchTime_ms > 5000) {
_sessionId = null
_mediaSessionId = null
setTime(0.0)
_transportId = null
if (_launching && _launchRetries < MAX_LAUNCH_RETRIES) {
Logger.i(TAG, "No player yet; attempting launch #${_launchRetries + 1}")
_launchRetries++
launchPlayer()
} else if (!_launching && _launchRetries < MAX_LAUNCH_RETRIES) {
// Maybe the first GET_STATUS came back empty; still try launching
Logger.i(TAG, "Player not found; triggering launch #${_launchRetries + 1}")
_launching = true
_launchRetries++
launchPlayer()
if (_autoLaunchEnabled) {
if (_launching && _launchRetries < MAX_LAUNCH_RETRIES) {
Logger.i(TAG, "No player yet; attempting launch #${_launchRetries + 1}")
_launchRetries++
launchPlayer()
} else {
// Maybe the first GET_STATUS came back empty; still try launching
Logger.i(TAG, "Player not found; triggering launch #${_launchRetries + 1}")
_launching = true
_launchRetries++
launchPlayer()
}
} else {
Logger.e(TAG, "Player not found after $_launchRetries attempts; giving up.")
Logger.e(TAG, "Player not found ($_launchRetries, _autoLaunchEnabled = $_autoLaunchEnabled); giving up.")
Logger.i(TAG, "Unable to start media receiver on device")
stop()
}
@ -599,6 +602,7 @@ class ChromecastCastingDevice : CastingDevice {
} else {
_launching = false
_launchRetries = 0
_autoLaunchEnabled = false
}
val volume = status.getJSONObject("volume");
@ -636,10 +640,16 @@ class ChromecastCastingDevice : CastingDevice {
stopVideo();
}
}
val needsLoad = statuses.length() == 0 || (statuses.getJSONObject(0).getString("playerState") == "IDLE")
if (needsLoad && _contentId != null && _mediaSessionId == null) {
Logger.i(TAG, "Receiver idle, sending initial LOAD")
playVideo()
}
} else if (type == "CLOSE") {
if (message.sourceId == "receiver-0") {
Logger.i(TAG, "Close received.");
stop();
stopCasting();
} else if (_transportId == message.sourceId) {
throw Exception("Transport id closed.")
}
@ -676,6 +686,10 @@ class ChromecastCastingDevice : CastingDevice {
localAddress = null;
_started = false;
_contentId = null
_contentType = null
_streamType = null
_retryJob?.cancel()
_retryJob = null

View file

@ -649,7 +649,7 @@ class VideoDetailView : ConstraintLayout {
}
if (!isInEditMode) {
StateCasting.instance.onActiveDeviceConnectionStateChanged.subscribe(this) { _, connectionState ->
StateCasting.instance.onActiveDeviceConnectionStateChanged.subscribe(this) { device, connectionState ->
if (_onPauseCalled) {
return@subscribe;
}
@ -661,7 +661,7 @@ class VideoDetailView : ConstraintLayout {
setCastEnabled(true);
}
CastConnectionState.DISCONNECTED -> {
loadCurrentVideo(lastPositionMilliseconds);
loadCurrentVideo(lastPositionMilliseconds, playWhenReady = device.isPlaying);
updatePillButtonVisibilities();
setCastEnabled(false);
@ -1880,7 +1880,7 @@ class VideoDetailView : ConstraintLayout {
}
//Source Loads
private fun loadCurrentVideo(resumePositionMs: Long = 0) {
private fun loadCurrentVideo(resumePositionMs: Long = 0, playWhenReady: Boolean = true) {
_didStop = false;
val video = (videoLocal ?: video) ?: return;
@ -1925,7 +1925,7 @@ class VideoDetailView : ConstraintLayout {
else
_player.setArtwork(null);
}
_player.setSource(videoSource, audioSource, _playWhenReady, false, resume = resumePositionMs > 0);
_player.setSource(videoSource, audioSource, _playWhenReady && playWhenReady, false, resume = resumePositionMs > 0);
if(subtitleSource != null)
_player.swapSubtitles(fragment.lifecycleScope, subtitleSource);
_player.seekTo(resumePositionMs);

View file

@ -48,6 +48,7 @@ class DownloadService : Service() {
private val _scope: CoroutineScope = CoroutineScope(Dispatchers.Default);
private var _notificationManager: NotificationManager? = null;
private var _notificationChannel: NotificationChannel? = null;
private var _isForeground = false
private val _client = ManagedHttpClient(OkHttpClient.Builder()
//.proxy(Proxy(Proxy.Type.HTTP, InetSocketAddress(InetAddress.getByName("192.168.1.175"), 8081)))
@ -66,6 +67,7 @@ class DownloadService : Service() {
if(!FragmentedStorage.isInitialized) {
Logger.i(TAG, "Attempted to start DownloadService without initialized files");
stopSelf()
closeDownloadSession();
return START_NOT_STICKY;
}
@ -116,6 +118,22 @@ class DownloadService : Service() {
override fun onCreate() {
Logger.i(TAG, "onCreate");
super.onCreate()
setupNotificationRequirements()
val bootstrapNotif = NotificationCompat.Builder(this, DOWNLOAD_NOTIF_CHANNEL_ID)
.setSmallIcon(R.drawable.ic_download)
.setContentTitle("Preparing downloads...")
.setOngoing(true)
.setSilent(true)
.build()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
startForeground(DOWNLOAD_NOTIF_ID, bootstrapNotif, FOREGROUND_SERVICE_TYPE_DATA_SYNC)
else
startForeground(DOWNLOAD_NOTIF_ID, bootstrapNotif)
_isForeground = true
}
override fun onBind(p0: Intent?): IBinder? {
@ -246,15 +264,14 @@ class DownloadService : Service() {
}
private fun notifyDownload(download: VideoDownload?) {
val channel = _notificationChannel ?: return;
val channelId = DOWNLOAD_NOTIF_CHANNEL_ID
val bringUpIntent = Intent(this, MainActivity::class.java);
bringUpIntent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
bringUpIntent.action = "TAB";
bringUpIntent.putExtra("TAB", "Downloads");
var builder = if(download != null)
NotificationCompat.Builder(this, DOWNLOAD_NOTIF_TAG)
val builder = if(download != null)
NotificationCompat.Builder(this, channelId)
.setSmallIcon(R.drawable.ic_download)
.setOngoing(true)
.setSilent(true)
@ -262,16 +279,16 @@ class DownloadService : Service() {
.setContentTitle("${download.state}: ${download.name}")
.setContentText(download.getDownloadInfo())
.setProgress(100, (download.progress * 100).toInt(), download.progress == 0.0)
.setChannelId(channel.id)
.setChannelId(channelId)
else
NotificationCompat.Builder(this, DOWNLOAD_NOTIF_TAG)
NotificationCompat.Builder(this, channelId)
.setSmallIcon(R.drawable.ic_download)
.setOngoing(true)
.setSilent(true)
.setContentIntent(PendingIntent.getActivity(this, 5, bringUpIntent, PendingIntent.FLAG_IMMUTABLE))
.setContentTitle("Preparing for download...")
.setContentText("Initializing download process...")
.setChannelId(channel.id)
.setChannelId(channelId)
val notif = builder.build();
notif.flags = notif.flags or NotificationCompat.FLAG_ONGOING_EVENT or NotificationCompat.FLAG_NO_CLEAR;