import Quickshell import Quickshell.Bluetooth import Quickshell.Io import Quickshell.Services.Mpris import Quickshell.Wayland import Quickshell.Hyprland import QtQuick import QtMultimedia PanelWindow { id: overlay anchors { top: true left: true right: true bottom: true } WlrLayershell.layer: WlrLayer.Overlay WlrLayershell.focusable: true WlrLayershell.keyboardFocus: WlrKeyboardFocus.Exclusive WlrLayershell.namespace: "deltarune-startup-overlay" color: "#000000" exclusionMode: ExclusionMode.Ignore aboveWindows: true focusable: true property var bluetoothTargetNames: ["JBL Tune 525BT", "JBL GO"] property int bluetoothConnectAttemptMs: 3000 property bool waitingForBluetooth: true property bool animationLaunchScheduled: false property bool animationStarted: false property bool isEnding: false property bool postIntroSongTriggered: false property bool waitingForPostIntroSong: false property bool waitingForChromiumSong: false property bool finishDelayScheduled: false property bool bluetoothConnectRequested: false property int bluetoothTargetAttemptIndex: 0 property string bluetoothActiveTargetName: "" function bluetoothModelCount() { if (bluetoothDeviceRepeater) return bluetoothDeviceRepeater.count; return 0; } function bluetoothDeviceAt(index) { const item = bluetoothDeviceRepeater.itemAt(index); if (!item) return null; return item.device || null; } function bluetoothDeviceName(device) { if (!device) return ""; if (device.name && device.name.length > 0) return String(device.name); if (device.deviceName && device.deviceName.length > 0) return String(device.deviceName); return ""; } function findBluetoothDeviceByName(targetName) { for (var i = 0; i < bluetoothModelCount(); i++) { var device = bluetoothDeviceAt(i); var deviceName = bluetoothDeviceName(device); console.log("Startup BT: candidate", i, deviceName, device ? Boolean(device.connected) : false); if (deviceName === targetName) return device; } console.log("Startup BT: target not found", targetName, "count", bluetoothModelCount()); return null; } function findConnectedPreferredBluetoothDevice() { for (var i = 0; i < bluetoothTargetNames.length; i++) { var device = findBluetoothDeviceByName(bluetoothTargetNames[i]); if (device && device.connected) return device; } return null; } function resetBluetoothAttemptState() { bluetoothConnectRequested = false; bluetoothTargetAttemptIndex = 0; bluetoothActiveTargetName = ""; bluetoothConnectAttemptTimer.stop(); } function maybeStartBluetoothOrSkip() { console.log("Startup BT: maybeStartBluetoothOrSkip", "waiting", waitingForBluetooth, "requested", bluetoothConnectRequested, "active", bluetoothActiveTargetName, "attemptIndex", bluetoothTargetAttemptIndex); if (!waitingForBluetooth) return; const connectedDevice = findConnectedPreferredBluetoothDevice(); if (connectedDevice) { console.log("Startup BT: preferred device connected, starting animation", bluetoothDeviceName(connectedDevice)); beginAnimation(); return; } if (bluetoothConnectRequested) { console.log("Startup BT: connect already requested, waiting on", bluetoothActiveTargetName); return; } for (var i = bluetoothTargetAttemptIndex; i < bluetoothTargetNames.length; i++) { var targetName = bluetoothTargetNames[i]; var targetDevice = findBluetoothDeviceByName(targetName); if (!targetDevice) continue; bluetoothConnectRequested = true; bluetoothTargetAttemptIndex = i; bluetoothActiveTargetName = targetName; bluetoothConnectAttemptTimer.restart(); console.log("Startup BT: requesting connect", targetName); targetDevice.connect(); return; } console.log("Startup BT: no preferred devices available yet"); } function beginAnimation() { console.log("Startup: beginAnimation", "started", animationStarted, "scheduled", animationLaunchScheduled); if (animationStarted || animationLaunchScheduled) return; waitingForBluetooth = false; bluetoothRetryTimer.stop(); bluetoothConnectAttemptTimer.stop(); animationLaunchScheduled = true; startupDelayTimer.restart(); } function handlePrimaryAction() { console.log("Startup: handlePrimaryAction", "animationStarted", animationStarted, "waitingForBluetooth", waitingForBluetooth); if (!animationStarted) beginAnimation(); else finishStartup(); } function finishStartup() { console.log("Startup: finishStartup", "playbackState", player.playbackState); if (player.playbackState !== MediaPlayer.StoppedState) player.stop(); else Qt.quit(); } function triggerPostIntroSong() { if (postIntroSongTriggered) return; postIntroSongTriggered = true; isEnding = true; waitingForPostIntroSong = true; waitingForChromiumSong = true; console.log("Startup: Triggering post-intro song..."); postIntroSongTimeout.restart(); chromiumSongTimeout.restart(); postIntroSongProcess.exec(["curl", "-s", "-X", "POST", "-H", "Content-Type: application/json", "-d", "{\"type\":\"songs\",\"id\":\"i.WmYR0zXC68B2g50\"}", "http://localhost:10767/api/v1/playback/play-item"]); } function chromiumSongReady() { for (var i = 0; i < mprisPlayerRepeater.count; i++) { var item = mprisPlayerRepeater.itemAt(i); if (!item || !item.player) continue; var player = item.player; var identity = String(player.identity || "").toLowerCase(); var desktopEntry = String(player.desktopEntry || "").toLowerCase(); var dbusName = String(player.dbusName || "").toLowerCase(); var isChromium = identity.indexOf("chromium") !== -1 || desktopEntry.indexOf("chromium") !== -1 || dbusName.indexOf("chromium") !== -1; if (!isChromium) continue; var album = String(player.trackAlbum || ""); var artist = String(player.trackArtist || ""); var title = String(player.trackTitle || ""); console.log("Startup: chromium metadata", identity, album, artist, title); if (album === "Deltarune Chapters 3+4 (Original Game Soundtrack)" && artist === "Toby Fox" && title === "With Hope Crossed on Our Hearts") return true; } return false; } function maybeFinishAfterSongReady() { if (!isEnding) return; if (waitingForPostIntroSong) return; if (chromiumSongReady()) { console.log("Startup: chromium MPRIS metadata matched, waiting 1s before closing overlay"); waitingForChromiumSong = false; chromiumSongTimeout.stop(); if (!finishDelayScheduled) { finishDelayScheduled = true; finishDelayTimer.restart(); } return; } console.log("Startup: waiting for chromium MPRIS metadata"); } HyprlandFocusGrab { active: true windows: [overlay] } Component.onCompleted: { console.log("Startup: overlay completed", "btCount", bluetoothModelCount(), "targets", JSON.stringify(bluetoothTargetNames)); maybeStartBluetoothOrSkip(); } FocusScope { id: overlayFocus anchors.fill: parent focus: true Component.onCompleted: overlayFocus.forceActiveFocus() onVisibleChanged: if (visible) overlayFocus.forceActiveFocus() onFocusChanged: if (focus) overlayFocus.forceActiveFocus() Keys.onReleased: function (event) { switch (event.key) { case Qt.Key_Z: case Qt.Key_Return: case Qt.Key_Enter: event.accepted = true; overlay.handlePrimaryAction(); return; } } } Connections { target: Bluetooth.devices ignoreUnknownSignals: true function onCountChanged() { if (overlay.waitingForBluetooth) { console.log("Startup BT: devices count changed", overlay.bluetoothModelCount(), "repeater", bluetoothDeviceRepeater.count); overlay.resetBluetoothAttemptState(); overlay.maybeStartBluetoothOrSkip(); } } function onModelReset() { if (overlay.waitingForBluetooth) { console.log("Startup BT: devices model reset"); overlay.resetBluetoothAttemptState(); overlay.maybeStartBluetoothOrSkip(); } } function onRowsInserted() { if (overlay.waitingForBluetooth) { console.log("Startup BT: device rows inserted"); overlay.resetBluetoothAttemptState(); overlay.maybeStartBluetoothOrSkip(); } } function onRowsRemoved() { if (overlay.waitingForBluetooth) { console.log("Startup BT: device rows removed"); overlay.resetBluetoothAttemptState(); overlay.maybeStartBluetoothOrSkip(); } } } Repeater { id: bluetoothDeviceRepeater model: Bluetooth.devices delegate: Item { property var device: modelData Component.onCompleted: { console.log("Startup BT: delegate ready", index, overlay.bluetoothDeviceName(device), Boolean(device ? device.connected : false), "repeaterCount", bluetoothDeviceRepeater.count); overlay.maybeStartBluetoothOrSkip(); } Connections { target: device ignoreUnknownSignals: true function onConnectedChanged() { console.log("Startup BT: connected changed", overlay.bluetoothDeviceName(device), Boolean(device ? device.connected : false)); if (overlay.waitingForBluetooth) { if (Boolean(device ? device.connected : false)) overlay.bluetoothConnectAttemptTimer.stop(); overlay.maybeStartBluetoothOrSkip(); } } function onNameChanged() { if (overlay.waitingForBluetooth) { console.log("Startup BT: name changed", overlay.bluetoothDeviceName(device)); overlay.resetBluetoothAttemptState(); overlay.maybeStartBluetoothOrSkip(); } } function onDeviceNameChanged() { if (overlay.waitingForBluetooth) { console.log("Startup BT: deviceName changed", overlay.bluetoothDeviceName(device)); overlay.resetBluetoothAttemptState(); overlay.maybeStartBluetoothOrSkip(); } } } } } Repeater { id: mprisPlayerRepeater model: Mpris.players delegate: Item { required property var modelData property var player: modelData visible: false Connections { target: player function onTrackChanged() { overlay.maybeFinishAfterSongReady(); } function onPostTrackChanged() { overlay.maybeFinishAfterSongReady(); } function onMetadataChanged() { overlay.maybeFinishAfterSongReady(); } function onTrackTitleChanged() { overlay.maybeFinishAfterSongReady(); } function onTrackArtistChanged() { overlay.maybeFinishAfterSongReady(); } function onTrackAlbumChanged() { overlay.maybeFinishAfterSongReady(); } function onIdentityChanged() { overlay.maybeFinishAfterSongReady(); } function onDesktopEntryChanged() { overlay.maybeFinishAfterSongReady(); } } } } Connections { target: Mpris.players ignoreUnknownSignals: true function onCountChanged() { overlay.maybeFinishAfterSongReady(); } function onModelReset() { overlay.maybeFinishAfterSongReady(); } function onRowsInserted() { overlay.maybeFinishAfterSongReady(); } function onRowsRemoved() { overlay.maybeFinishAfterSongReady(); } } MediaPlayer { id: player source: "deltarune.mp4" autoPlay: false videoOutput: videoOutput playbackRate: 1 audioOutput: startupAudioOutput onMediaStatusChanged: { console.log("Startup: Media Status:", player.mediaStatus); if (player.mediaStatus === MediaPlayer.EndOfMedia) overlay.triggerPostIntroSong(); } onPlaybackStateChanged: { if (player.playbackState === MediaPlayer.StoppedState && !overlay.isEnding) { console.log("Startup: Video stopped unexpectedly, shutting down."); overlay.finishStartup(); } } } Process { id: postIntroSongProcess onExited: (exitCode, exitStatus) => { console.log("Startup: post-intro song request exited", exitCode, exitStatus); postIntroSongTimeout.stop(); overlay.waitingForPostIntroSong = false; overlay.maybeFinishAfterSongReady(); } } Timer { id: postIntroSongTimeout interval: 3000 repeat: false onTriggered: { console.log("Startup: post-intro song request timed out"); if (overlay.waitingForPostIntroSong) { postIntroSongProcess.running = false; overlay.waitingForPostIntroSong = false; overlay.maybeFinishAfterSongReady(); } } } Timer { id: chromiumSongTimeout interval: 8000 repeat: false onTriggered: { console.log("Startup: chromium MPRIS metadata wait timed out"); if (overlay.waitingForChromiumSong) { overlay.waitingForChromiumSong = false; overlay.finishStartup(); } } } Timer { id: finishDelayTimer interval: 1000 repeat: false onTriggered: { overlay.finishDelayScheduled = false; overlay.finishStartup(); } } Timer { id: startupDelayTimer interval: 1500 repeat: false onTriggered: { console.log("Startup: startup delay elapsed, playing video"); overlay.animationLaunchScheduled = false; overlay.animationStarted = true; overlay.isEnding = false; overlay.finishDelayScheduled = false; player.play(); } } Timer { id: bluetoothRetryTimer interval: 250 running: true repeat: true onTriggered: { if (!overlay.waitingForBluetooth) { console.log("Startup BT: retry timer stopping"); stop(); return; } console.log("Startup BT: retry timer fired"); overlay.maybeStartBluetoothOrSkip(); } } Timer { id: bluetoothConnectAttemptTimer interval: overlay.bluetoothConnectAttemptMs running: false repeat: false onTriggered: { console.log("Startup BT: connect attempt timed out", overlay.bluetoothActiveTargetName); overlay.bluetoothConnectRequested = false; overlay.bluetoothActiveTargetName = ""; overlay.bluetoothTargetAttemptIndex = Math.min(overlay.bluetoothTargetAttemptIndex + 1, overlay.bluetoothTargetNames.length); overlay.maybeStartBluetoothOrSkip(); } } MediaDevices { id: mediaDevices onDefaultAudioOutputChanged: { console.log("Startup Audio: default output changed", mediaDevices.defaultAudioOutput.description); startupAudioOutput.device = mediaDevices.defaultAudioOutput; } } AudioOutput { id: startupAudioOutput device: mediaDevices.defaultAudioOutput } VideoOutput { id: videoOutput anchors.fill: parent } // Text { // visible: overlay.waitingForBluetooth // anchors.horizontalCenter: parent.horizontalCenter // anchors.verticalCenter: parent.verticalCenter // color: "#ffffff" // font.family: "Determination Mono" // font.pixelSize: 28 // text: "CONNECTING TO " + overlay.bluetoothTargetName.toUpperCase() // z: 1 // } MouseArea { anchors.fill: parent acceptedButtons: Qt.NoButton hoverEnabled: true cursorShape: Qt.BlankCursor } }