diff --git a/.gitignore b/.gitignore index 5d3e303..abe0eab 100644 --- a/.gitignore +++ b/.gitignore @@ -24,36 +24,33 @@ plugin_config/obs-websocket/ # Machine-local generated data # ============================================================ -# Generated wrapper for telemetry.json — built by telemetry.sh, not edited. -# (The JSON itself is tracked: it's the hand-edited source for the wrapper.) -landing/telemetry.js - -# Per-session manifest written by loading.sh — ephemeral, not version-controlled. -loading/loading.json -loading/loading.js - -# Playlist manifest — generated from the audio in /playlist/, machine-local. -loading/playlist.json -loading/playlist.js - -# Music daemon command file — written by playlist.sh skip/prev/pause/resume. -loading/cmd.js - -# Audio files for the loading scene (any format). Kept out of git regardless -# of how they got there (yt-dlp, manual copy, etc.). -/playlist/ +# Per-session rig data written by `php artisan rig:loading`, `rig:playlist`, +# `rig:telemetry`. Re-derived on demand from the live system + Twitch API. +webapp/storage/data/*.json # OBS WebSocket connection details (port + password) — auto-generated by -# setup.sh from your existing plugin_config/obs-websocket/config.json. -vendor/obs-config.js +# `php artisan rig:setup` from plugin_config/obs-websocket/config.json. +webapp/public/js/obs-config.js # Album-art cache written by bridges/mpd-state.py on every track change — -# overlays load it as ``. Pure runtime state. +# the music-box/cover overlay loads it through `/cover.jpg?v=`. bridges/cover.jpg -# Local backups created during edits — keep out of git noise. -landing/*.manual -loading/*.manual +# Audio files for the loading/music-box scenes (any format). Kept out of git +# regardless of how they got there (yt-dlp, manual copy, etc.). +/playlist/ + +# Local backups created during rig:telemetry review. +webapp/storage/data/*.manual + +# Laravel-native ignores (composer deps, log + cache + session dirs). +/webapp/vendor/ +/webapp/node_modules/ +/webapp/storage/logs/*.log +/webapp/storage/framework/cache/data/ +/webapp/storage/framework/sessions/ +/webapp/storage/framework/views/ +/webapp/bootstrap/cache/*.php # ============================================================ # OBS runtime / generated state — no value in version control @@ -99,3 +96,4 @@ __pycache__/ *.pyc *.pyo temp +.claude/ diff --git a/basic/scenes/Default_Stream_HUD.json b/basic/scenes/Default_Stream_HUD.json index c134ca9..adcb693 100644 --- a/basic/scenes/Default_Stream_HUD.json +++ b/basic/scenes/Default_Stream_HUD.json @@ -269,7 +269,8 @@ "id": "browser_source", "versioned_id": "browser_source", "settings": { - "url": "file:///home/jin/.config/obs-studio/landing/index.html", + "is_local_file": false, + "url": "http://127.0.0.1:1118/landing", "width": 2560, "height": 1336, "fps": 30, @@ -309,7 +310,7 @@ "id": "ffmpeg_source", "versioned_id": "ffmpeg_source", "settings": { - "local_file": "/home/jin/.config/obs-studio/landing/static-hum.wav", + "local_file": "/home/jin/.config/obs-studio/webapp/public/audio/static-hum.wav", "close_when_inactive": false, "hw_decode": false, "is_local_file": true, @@ -350,9 +351,8 @@ "id": "browser_source", "versioned_id": "browser_source", "settings": { - "is_local_file": true, - "local_file": "/home/jin/.config/obs-studio/loading/index.html", - "url": "file:///home/jin/.config/obs-studio/loading/index.html", + "is_local_file": false, + "url": "http://127.0.0.1:1118/loading", "width": 2560, "height": 1336, "restart_when_active": true, @@ -419,8 +419,8 @@ "id": "browser_source", "versioned_id": "browser_source", "settings": { - "is_local_file": true, - "local_file": "/home/jin/.config/obs-studio/music/index.html", + "is_local_file": false, + "url": "http://127.0.0.1:1118/music-daemon", "width": 400, "height": 100, "shutdown": true, @@ -456,8 +456,8 @@ "id": "browser_source", "versioned_id": "browser_source", "settings": { - "is_local_file": true, - "local_file": "/home/jin/.config/obs-studio/game/index.html", + "is_local_file": false, + "url": "http://127.0.0.1:1118/game", "width": 2560, "height": 1336, "fps": 15, @@ -494,8 +494,8 @@ "id": "browser_source", "versioned_id": "browser_source", "settings": { - "is_local_file": true, - "local_file": "/home/jin/.config/obs-studio/goodbye/index.html", + "is_local_file": false, + "url": "http://127.0.0.1:1118/goodbye", "width": 2560, "height": 1336, "fps_custom": true, @@ -536,7 +536,7 @@ "mixers": 255, "sync": 0, "flags": 0, - "volume": 0.20938195288181305, + "volume": 0.19247779250144958, "balance": 0.5, "enabled": true, "muted": false, @@ -567,7 +567,7 @@ "mixers": 255, "sync": 0, "flags": 0, - "volume": 0.0053968820720911026, + "volume": 0.01389647088944912, "balance": 0.5, "enabled": true, "muted": false, @@ -593,8 +593,8 @@ "id": "browser_source", "versioned_id": "browser_source", "settings": { - "is_local_file": true, - "local_file": "/home/jin/.config/obs-studio/desktop/index.html", + "is_local_file": false, + "url": "http://127.0.0.1:1118/desktop", "width": 2560, "height": 1336, "fps": 15, @@ -631,8 +631,8 @@ "id": "browser_source", "versioned_id": "browser_source", "settings": { - "is_local_file": true, - "local_file": "/home/jin/.config/obs-studio/music-box/index.html", + "is_local_file": false, + "url": "http://127.0.0.1:1118/music-box", "width": 2560, "height": 1336, "fps": 30, @@ -670,9 +670,9 @@ "id": "browser_source", "versioned_id": "browser_source", "settings": { - "is_local_file": true, - "local_file": "/home/jin/.config/obs-studio/music-box/widget.html", + "is_local_file": false, "undo_uuid": "f662d513-6fe6-49fd-99f6-ea7f44e8de18", + "url": "http://127.0.0.1:1118/music-box/widget", "width": 549, "height": 880, "fps": 15, @@ -709,7 +709,8 @@ "id": "browser_source", "versioned_id": "browser_source", "settings": { - "url": "file:///home/jin/.config/obs-studio/music-box/cover.html" + "is_local_file": false, + "url": "http://127.0.0.1:1118/music-box/cover" }, "mixers": 255, "sync": 0, @@ -741,7 +742,8 @@ "id": "browser_source", "versioned_id": "browser_source", "settings": { - "url": "file:///home/jin/.config/obs-studio/music-box/cover.html?bars=0" + "is_local_file": false, + "url": "http://127.0.0.1:1118/music-box/cover?bars=0" }, "mixers": 255, "sync": 0, @@ -773,7 +775,8 @@ "id": "browser_source", "versioned_id": "browser_source", "settings": { - "url": "file:///home/jin/.config/obs-studio/music-box/nc-music-box.html", + "is_local_file": false, + "url": "http://127.0.0.1:1118/music-box/nc", "width": 2560, "height": 1331, "fps": 15, @@ -3683,8 +3686,8 @@ "name": "Good Bye" } ], - "current_scene": "Good Bye", - "current_program_scene": "Good Bye", + "current_scene": "Music Box", + "current_program_scene": "Music Box", "canvases": [], "current_transition": "Luma Wipe", "transition_duration": 1000, @@ -3716,7 +3719,7 @@ "saved_projectors": [], "preview_locked": false, "scaling_enabled": false, - "scaling_level": -12, + "scaling_level": -14, "scaling_off_x": 0.0, "scaling_off_y": 0.0, "modules": { diff --git a/basic/scenes/Default_Stream_HUD.json.pre-webapp b/basic/scenes/Default_Stream_HUD.json.pre-webapp new file mode 100644 index 0000000..e0ef678 --- /dev/null +++ b/basic/scenes/Default_Stream_HUD.json.pre-webapp @@ -0,0 +1,3757 @@ +{ + "name": "Default Stream HUD", + "DesktopAudioDevice1": { + "prev_ver": 536936450, + "name": "Desktop Audio", + "uuid": "5c879e8d-88e7-41d6-8371-474b9369d8a5", + "id": "pulse_output_capture", + "versioned_id": "pulse_output_capture", + "settings": { + "device_id": "alsa_output.pci-0000_2b_00.3.analog-stereo.monitor" + }, + "mixers": 255, + "sync": 0, + "flags": 0, + "volume": 0.0, + "balance": 0.5, + "enabled": true, + "muted": false, + "push-to-mute": false, + "push-to-mute-delay": 0, + "push-to-talk": false, + "push-to-talk-delay": 0, + "hotkeys": { + "libobs.mute": [], + "libobs.unmute": [], + "libobs.push-to-mute": [], + "libobs.push-to-talk": [] + }, + "deinterlace_mode": 0, + "deinterlace_field_order": 0, + "monitoring_type": 0, + "private_settings": {} + }, + "AuxAudioDevice1": { + "prev_ver": 536936450, + "name": "Mic/Aux", + "uuid": "fe24bff3-762e-416b-862a-6273326c13d0", + "id": "pulse_input_capture", + "versioned_id": "pulse_input_capture", + "settings": { + "device_id": "default" + }, + "mixers": 255, + "sync": 0, + "flags": 0, + "volume": 0.0, + "balance": 0.5, + "enabled": true, + "muted": false, + "push-to-mute": false, + "push-to-mute-delay": 0, + "push-to-talk": false, + "push-to-talk-delay": 0, + "hotkeys": { + "libobs.mute": [], + "libobs.unmute": [], + "libobs.push-to-mute": [], + "libobs.push-to-talk": [] + }, + "deinterlace_mode": 0, + "deinterlace_field_order": 0, + "monitoring_type": 0, + "private_settings": {} + }, + "sources": [ + { + "prev_ver": 536936450, + "name": "Starting Soon", + "uuid": "4b902d7f-9205-444c-8c8b-b559479d5bea", + "id": "image_source", + "versioned_id": "image_source", + "settings": { + "file": "/home/jin/HDD/Images/Gifs/stamd.png" + }, + "mixers": 0, + "sync": 0, + "flags": 0, + "volume": 1.0, + "balance": 0.5, + "enabled": true, + "muted": false, + "push-to-mute": false, + "push-to-mute-delay": 0, + "push-to-talk": false, + "push-to-talk-delay": 0, + "hotkeys": {}, + "deinterlace_mode": 0, + "deinterlace_field_order": 0, + "monitoring_type": 0, + "private_settings": {} + }, + { + "prev_ver": 536936450, + "name": "Doomguard Logo", + "uuid": "ee77caf1-a490-45fa-80d9-4072f7e63d9a", + "id": "image_source", + "versioned_id": "image_source", + "settings": { + "file": "/home/jin/cloud.jakubzych.com/_img/logos/dgw.png" + }, + "mixers": 0, + "sync": 0, + "flags": 0, + "volume": 1.0, + "balance": 0.5, + "enabled": true, + "muted": false, + "push-to-mute": false, + "push-to-mute-delay": 0, + "push-to-talk": false, + "push-to-talk-delay": 0, + "hotkeys": {}, + "deinterlace_mode": 0, + "deinterlace_field_order": 0, + "monitoring_type": 0, + "private_settings": {} + }, + { + "prev_ver": 536936450, + "name": "info", + "uuid": "cfcf2652-2777-4b92-a53b-54703f23deff", + "id": "text_ft2_source", + "versioned_id": "text_ft2_source_v2", + "settings": { + "text": "Helping twitch.tv/eisenhowler setup stream", + "font": { + "face": "Sansation", + "flags": 0, + "size": 14, + "style": "Regular" + } + }, + "mixers": 0, + "sync": 0, + "flags": 0, + "volume": 1.0, + "balance": 0.5, + "enabled": true, + "muted": false, + "push-to-mute": false, + "push-to-mute-delay": 0, + "push-to-talk": false, + "push-to-talk-delay": 0, + "hotkeys": {}, + "deinterlace_mode": 0, + "deinterlace_field_order": 0, + "monitoring_type": 0, + "private_settings": {} + }, + { + "prev_ver": 536936450, + "name": "Camera", + "uuid": "a8b362a1-91a6-491b-8751-26e2dad55ccd", + "id": "v4l2_input", + "versioned_id": "v4l2_input", + "settings": { + "device_id": "/dev/video0", + "Brightness": 0, + "Contrast": 35, + "Saturation": 64, + "Gamma": 99, + "Gain": 2, + "input": 0, + "pixelformat": 1196444237, + "resolution": -1 + }, + "mixers": 0, + "sync": 0, + "flags": 0, + "volume": 1.0, + "balance": 0.5, + "enabled": true, + "muted": false, + "push-to-mute": false, + "push-to-mute-delay": 0, + "push-to-talk": false, + "push-to-talk-delay": 0, + "hotkeys": {}, + "deinterlace_mode": 0, + "deinterlace_field_order": 0, + "monitoring_type": 0, + "private_settings": {}, + "filters": [ + { + "prev_ver": 536936450, + "name": "Crop/Pad", + "uuid": "8ea7885e-70c6-4dfd-b5f9-a7581f61b7c2", + "id": "crop_filter", + "versioned_id": "crop_filter", + "settings": { + "top": 360, + "right": 700 + }, + "mixers": 0, + "sync": 0, + "flags": 0, + "volume": 1.0, + "balance": 0.5, + "enabled": true, + "muted": false, + "push-to-mute": false, + "push-to-mute-delay": 0, + "push-to-talk": false, + "push-to-talk-delay": 0, + "hotkeys": {}, + "deinterlace_mode": 0, + "deinterlace_field_order": 0, + "monitoring_type": 0, + "private_settings": {} + } + ] + }, + { + "prev_ver": 536936450, + "name": "Screen Capture (PipeWire)", + "uuid": "8f6ef725-1eec-4fdf-930a-2aab93d84c06", + "id": "pipewire-screen-capture-source", + "versioned_id": "pipewire-screen-capture-source", + "settings": { + "RestoreToken": "3951c703-09cb-4e8a-9dfd-14b4090da608" + }, + "mixers": 0, + "sync": 0, + "flags": 0, + "volume": 1.0, + "balance": 0.5, + "enabled": true, + "muted": false, + "push-to-mute": false, + "push-to-mute-delay": 0, + "push-to-talk": false, + "push-to-talk-delay": 0, + "hotkeys": {}, + "deinterlace_mode": 0, + "deinterlace_field_order": 0, + "monitoring_type": 0, + "private_settings": {} + }, + { + "prev_ver": 536936450, + "name": "Screen Capture (PipeWire) 2", + "uuid": "1e23924b-8260-4246-b7ee-74456fb62e65", + "id": "pipewire-screen-capture-source", + "versioned_id": "pipewire-screen-capture-source", + "settings": { + "RestoreToken": "2b7b68cb-b5aa-4da2-b7b7-3c1e54e997e4" + }, + "mixers": 0, + "sync": 0, + "flags": 0, + "volume": 1.0, + "balance": 0.5, + "enabled": true, + "muted": false, + "push-to-mute": false, + "push-to-mute-delay": 0, + "push-to-talk": false, + "push-to-talk-delay": 0, + "hotkeys": {}, + "deinterlace_mode": 0, + "deinterlace_field_order": 0, + "monitoring_type": 0, + "private_settings": {} + }, + { + "prev_ver": 536936450, + "name": "Landing — Stand By (Browser)", + "uuid": "dd513385-f6d8-44da-a459-20acbe620823", + "id": "browser_source", + "versioned_id": "browser_source", + "settings": { + "url": "file:///home/jin/.config/obs-studio/landing/index.html", + "width": 2560, + "height": 1336, + "fps": 30, + "fps_custom": true, + "shutdown": false, + "restart_when_active": false, + "webpage_control_level": 1, + "reroute_audio": false + }, + "mixers": 0, + "sync": 0, + "flags": 0, + "volume": 1.0, + "balance": 0.5, + "enabled": true, + "muted": false, + "push-to-mute": false, + "push-to-mute-delay": 0, + "push-to-talk": false, + "push-to-talk-delay": 0, + "hotkeys": { + "libobs.mute": [], + "libobs.unmute": [], + "libobs.push-to-mute": [], + "libobs.push-to-talk": [], + "ObsBrowser.Refresh": [] + }, + "deinterlace_mode": 0, + "deinterlace_field_order": 0, + "monitoring_type": 0, + "private_settings": {} + }, + { + "prev_ver": 536936450, + "name": "Landing — Static Hum", + "uuid": "16cc92de-4b9b-4b1c-b405-8f089991ac86", + "id": "ffmpeg_source", + "versioned_id": "ffmpeg_source", + "settings": { + "local_file": "/home/jin/.config/obs-studio/landing/static-hum.wav", + "close_when_inactive": false, + "hw_decode": false, + "is_local_file": true, + "looping": true, + "clear_on_media_end": false, + "restart_on_activate": true + }, + "mixers": 255, + "sync": 0, + "flags": 0, + "volume": 0.35087639093399048, + "balance": 0.5, + "enabled": true, + "muted": false, + "push-to-mute": false, + "push-to-mute-delay": 0, + "push-to-talk": false, + "push-to-talk-delay": 0, + "hotkeys": { + "libobs.mute": [], + "libobs.unmute": [], + "libobs.push-to-mute": [], + "libobs.push-to-talk": [], + "MediaSource.Restart": [], + "MediaSource.Play": [], + "MediaSource.Pause": [], + "MediaSource.Stop": [] + }, + "deinterlace_mode": 0, + "deinterlace_field_order": 0, + "monitoring_type": 0, + "private_settings": {} + }, + { + "prev_ver": 536936450, + "name": "Loading Project", + "uuid": "6642f830-fbae-4020-8292-a9cb7991e6fc", + "id": "browser_source", + "versioned_id": "browser_source", + "settings": { + "is_local_file": true, + "local_file": "/home/jin/.config/obs-studio/loading/index.html", + "url": "file:///home/jin/.config/obs-studio/loading/index.html", + "width": 2560, + "height": 1336, + "restart_when_active": true, + "reroute_audio": false + }, + "mixers": 255, + "sync": 0, + "flags": 0, + "volume": 0.1156293973326683, + "balance": 0.5, + "enabled": true, + "muted": false, + "push-to-mute": false, + "push-to-mute-delay": 0, + "push-to-talk": false, + "push-to-talk-delay": 0, + "hotkeys": { + "libobs.mute": [], + "libobs.unmute": [], + "libobs.push-to-mute": [], + "libobs.push-to-talk": [], + "ObsBrowser.Refresh": [] + }, + "deinterlace_mode": 0, + "deinterlace_field_order": 0, + "monitoring_type": 2, + "private_settings": {} + }, + { + "prev_ver": 536936450, + "name": "Audio", + "uuid": "fc5dfd34-bc55-4c92-8b5e-ef305afd1d8e", + "id": "pulse_input_capture", + "versioned_id": "pulse_input_capture", + "settings": { + "device_id": "alsa_input.usb-Creative_Technology_Ltd_Creative_Live__Cam_Sync_V3_SN0001-02.analog-stereo" + }, + "mixers": 255, + "sync": 0, + "flags": 0, + "volume": 0.0, + "balance": 0.5, + "enabled": true, + "muted": false, + "push-to-mute": false, + "push-to-mute-delay": 0, + "push-to-talk": false, + "push-to-talk-delay": 0, + "hotkeys": { + "libobs.mute": [], + "libobs.unmute": [], + "libobs.push-to-mute": [], + "libobs.push-to-talk": [] + }, + "deinterlace_mode": 0, + "deinterlace_field_order": 0, + "monitoring_type": 0, + "private_settings": {} + }, + { + "prev_ver": 536936450, + "name": "Audio Player", + "uuid": "b7b89406-53f4-45ba-aa1a-c20d17b1c905", + "id": "browser_source", + "versioned_id": "browser_source", + "settings": { + "is_local_file": true, + "local_file": "/home/jin/.config/obs-studio/music/index.html", + "width": 400, + "height": 100, + "shutdown": true, + "reroute_audio": true + }, + "mixers": 255, + "sync": 0, + "flags": 0, + "volume": 0.13031470775604248, + "balance": 0.5, + "enabled": true, + "muted": false, + "push-to-mute": false, + "push-to-mute-delay": 0, + "push-to-talk": false, + "push-to-talk-delay": 0, + "hotkeys": { + "libobs.mute": [], + "libobs.unmute": [], + "libobs.push-to-mute": [], + "libobs.push-to-talk": [], + "ObsBrowser.Refresh": [] + }, + "deinterlace_mode": 0, + "deinterlace_field_order": 0, + "monitoring_type": 2, + "private_settings": {} + }, + { + "prev_ver": 536936450, + "name": "HUD", + "uuid": "f409a999-358f-488d-98db-c5c6a01d01b9", + "id": "browser_source", + "versioned_id": "browser_source", + "settings": { + "is_local_file": true, + "local_file": "/home/jin/.config/obs-studio/game/index.html", + "width": 2560, + "height": 1336, + "fps": 15, + "fps_custom": true, + "shutdown": true + }, + "mixers": 255, + "sync": 0, + "flags": 0, + "volume": 1.0, + "balance": 0.5, + "enabled": true, + "muted": false, + "push-to-mute": false, + "push-to-mute-delay": 0, + "push-to-talk": false, + "push-to-talk-delay": 0, + "hotkeys": { + "libobs.mute": [], + "libobs.unmute": [], + "libobs.push-to-mute": [], + "libobs.push-to-talk": [], + "ObsBrowser.Refresh": [] + }, + "deinterlace_mode": 0, + "deinterlace_field_order": 0, + "monitoring_type": 0, + "private_settings": {} + }, + { + "prev_ver": 536936450, + "name": "GB", + "uuid": "38306c90-5bb8-4603-a21c-09383c300097", + "id": "browser_source", + "versioned_id": "browser_source", + "settings": { + "is_local_file": true, + "local_file": "/home/jin/.config/obs-studio/goodbye/index.html", + "width": 2560, + "height": 1336, + "fps_custom": true, + "restart_when_active": true + }, + "mixers": 255, + "sync": 0, + "flags": 0, + "volume": 1.0, + "balance": 0.5, + "enabled": true, + "muted": false, + "push-to-mute": false, + "push-to-mute-delay": 0, + "push-to-talk": false, + "push-to-talk-delay": 0, + "hotkeys": { + "libobs.mute": [], + "libobs.unmute": [], + "libobs.push-to-mute": [], + "libobs.push-to-talk": [], + "ObsBrowser.Refresh": [] + }, + "deinterlace_mode": 0, + "deinterlace_field_order": 0, + "monitoring_type": 0, + "private_settings": {} + }, + { + "prev_ver": 536936450, + "name": "MPD", + "uuid": "25440930-0606-46d9-ba2c-be786ff4a3ae", + "id": "pulse_output_capture", + "versioned_id": "pulse_output_capture", + "settings": { + "device_id": "mpd_stream.monitor" + }, + "mixers": 255, + "sync": 0, + "flags": 0, + "volume": 0.19247779250144958, + "balance": 0.5, + "enabled": true, + "muted": false, + "push-to-mute": false, + "push-to-mute-delay": 0, + "push-to-talk": false, + "push-to-talk-delay": 0, + "hotkeys": { + "libobs.mute": [], + "libobs.unmute": [], + "libobs.push-to-mute": [], + "libobs.push-to-talk": [] + }, + "deinterlace_mode": 0, + "deinterlace_field_order": 0, + "monitoring_type": 0, + "private_settings": {} + }, + { + "prev_ver": 536936450, + "name": "MPD Silent", + "uuid": "41387cb0-801b-49df-92e6-75c7293bec3f", + "id": "pulse_output_capture", + "versioned_id": "pulse_output_capture", + "settings": { + "device_id": "mpd_stream.monitor" + }, + "mixers": 255, + "sync": 0, + "flags": 0, + "volume": 0.01389647088944912, + "balance": 0.5, + "enabled": true, + "muted": false, + "push-to-mute": false, + "push-to-mute-delay": 0, + "push-to-talk": false, + "push-to-talk-delay": 0, + "hotkeys": { + "libobs.mute": [], + "libobs.unmute": [], + "libobs.push-to-mute": [], + "libobs.push-to-talk": [] + }, + "deinterlace_mode": 0, + "deinterlace_field_order": 0, + "monitoring_type": 0, + "private_settings": {} + }, + { + "prev_ver": 536936450, + "name": "Desktop HUD", + "uuid": "8acfb832-cfb4-4310-8ebb-b58fad2b3509", + "id": "browser_source", + "versioned_id": "browser_source", + "settings": { + "is_local_file": true, + "local_file": "/home/jin/.config/obs-studio/desktop/index.html", + "width": 2560, + "height": 1336, + "fps": 15, + "fps_custom": true, + "shutdown": true + }, + "mixers": 255, + "sync": 0, + "flags": 0, + "volume": 1.0, + "balance": 0.5, + "enabled": true, + "muted": false, + "push-to-mute": false, + "push-to-mute-delay": 0, + "push-to-talk": false, + "push-to-talk-delay": 0, + "hotkeys": { + "libobs.mute": [], + "libobs.unmute": [], + "libobs.push-to-mute": [], + "libobs.push-to-talk": [], + "ObsBrowser.Refresh": [] + }, + "deinterlace_mode": 0, + "deinterlace_field_order": 0, + "monitoring_type": 0, + "private_settings": {} + }, + { + "prev_ver": 536936450, + "name": "Music Box HUD", + "uuid": "1b9f5436-864d-4f24-9f92-f45702a23953", + "id": "browser_source", + "versioned_id": "browser_source", + "settings": { + "is_local_file": true, + "local_file": "/home/jin/.config/obs-studio/music-box/index.html", + "width": 2560, + "height": 1336, + "fps": 30, + "fps_custom": true, + "shutdown": true, + "restart_when_active": true + }, + "mixers": 255, + "sync": 0, + "flags": 0, + "volume": 1.0, + "balance": 0.5, + "enabled": true, + "muted": false, + "push-to-mute": false, + "push-to-mute-delay": 0, + "push-to-talk": false, + "push-to-talk-delay": 0, + "hotkeys": { + "libobs.mute": [], + "libobs.unmute": [], + "libobs.push-to-mute": [], + "libobs.push-to-talk": [], + "ObsBrowser.Refresh": [] + }, + "deinterlace_mode": 0, + "deinterlace_field_order": 0, + "monitoring_type": 0, + "private_settings": {} + }, + { + "prev_ver": 536936450, + "name": "Music Box Widget", + "uuid": "f662d513-6fe6-49fd-99f6-ea7f44e8de18", + "id": "browser_source", + "versioned_id": "browser_source", + "settings": { + "is_local_file": true, + "local_file": "/home/jin/.config/obs-studio/music-box/widget.html", + "undo_uuid": "f662d513-6fe6-49fd-99f6-ea7f44e8de18", + "width": 549, + "height": 880, + "fps": 15, + "fps_custom": true, + "shutdown": true + }, + "mixers": 255, + "sync": 0, + "flags": 0, + "volume": 1.0, + "balance": 0.5, + "enabled": true, + "muted": false, + "push-to-mute": false, + "push-to-mute-delay": 0, + "push-to-talk": false, + "push-to-talk-delay": 0, + "hotkeys": { + "libobs.mute": [], + "libobs.unmute": [], + "libobs.push-to-mute": [], + "libobs.push-to-talk": [], + "ObsBrowser.Refresh": [] + }, + "deinterlace_mode": 0, + "deinterlace_field_order": 0, + "monitoring_type": 0, + "private_settings": {} + }, + { + "prev_ver": 536936450, + "name": "Cover", + "uuid": "54d4ac81-e354-431a-a2dc-a00e5555e8d9", + "id": "browser_source", + "versioned_id": "browser_source", + "settings": { + "url": "file:///home/jin/.config/obs-studio/music-box/cover.html" + }, + "mixers": 255, + "sync": 0, + "flags": 0, + "volume": 1.0, + "balance": 0.5, + "enabled": true, + "muted": false, + "push-to-mute": false, + "push-to-mute-delay": 0, + "push-to-talk": false, + "push-to-talk-delay": 0, + "hotkeys": { + "libobs.mute": [], + "libobs.unmute": [], + "libobs.push-to-mute": [], + "libobs.push-to-talk": [], + "ObsBrowser.Refresh": [] + }, + "deinterlace_mode": 0, + "deinterlace_field_order": 0, + "monitoring_type": 0, + "private_settings": {} + }, + { + "prev_ver": 536936450, + "name": "Cover Simple", + "uuid": "7062784f-7b1b-4728-9067-27128c0d5748", + "id": "browser_source", + "versioned_id": "browser_source", + "settings": { + "url": "file:///home/jin/.config/obs-studio/music-box/cover.html?bars=0" + }, + "mixers": 255, + "sync": 0, + "flags": 0, + "volume": 1.0, + "balance": 0.5, + "enabled": true, + "muted": false, + "push-to-mute": false, + "push-to-mute-delay": 0, + "push-to-talk": false, + "push-to-talk-delay": 0, + "hotkeys": { + "libobs.mute": [], + "libobs.unmute": [], + "libobs.push-to-mute": [], + "libobs.push-to-talk": [], + "ObsBrowser.Refresh": [] + }, + "deinterlace_mode": 0, + "deinterlace_field_order": 0, + "monitoring_type": 0, + "private_settings": {} + }, + { + "prev_ver": 536936450, + "name": "NC Music Box HUD", + "uuid": "edbd893d-ce53-4c91-bf6c-4d52fbf394d6", + "id": "browser_source", + "versioned_id": "browser_source", + "settings": { + "url": "file:///home/jin/.config/obs-studio/music-box/nc-music-box.html", + "width": 2560, + "height": 1331, + "fps": 15, + "fps_custom": true + }, + "mixers": 255, + "sync": 0, + "flags": 0, + "volume": 1.0, + "balance": 0.5, + "enabled": true, + "muted": false, + "push-to-mute": false, + "push-to-mute-delay": 0, + "push-to-talk": false, + "push-to-talk-delay": 0, + "hotkeys": { + "libobs.mute": [], + "libobs.unmute": [], + "libobs.push-to-mute": [], + "libobs.push-to-talk": [], + "ObsBrowser.Refresh": [] + }, + "deinterlace_mode": 0, + "deinterlace_field_order": 0, + "monitoring_type": 0, + "private_settings": {} + }, + { + "prev_ver": 536936450, + "name": "Waveform Visualizer", + "uuid": "f28cc995-6966-4afa-b831-ebb50d89ebe8", + "id": "phandasm_waveform_source", + "versioned_id": "phandasm_waveform_source", + "settings": { + "pulse_mode": "peak_magnitude", + "audio_source": "MPD", + "display_mode": "stepped_bars", + "channel_mode": "mono", + "render_mode": "solid", + "color_base": 4278216704, + "step_gap": 3 + }, + "mixers": 0, + "sync": 0, + "flags": 0, + "volume": 1.0, + "balance": 0.5, + "enabled": true, + "muted": false, + "push-to-mute": false, + "push-to-mute-delay": 0, + "push-to-talk": false, + "push-to-talk-delay": 0, + "hotkeys": {}, + "deinterlace_mode": 0, + "deinterlace_field_order": 0, + "monitoring_type": 0, + "private_settings": {} + }, + { + "prev_ver": 536936450, + "name": "Waveform Stereo", + "uuid": "bc63aaf3-2ae2-4de9-9c7a-c05e55fa2a11", + "id": "phandasm_waveform_source", + "versioned_id": "phandasm_waveform_source", + "settings": { + "audio_source": "MPD", + "display_mode": "stepped_bars", + "channel_mode": "single", + "temporal_smoothing": "exp_moving_avg", + "color_base": 4278216704, + "bar_width": 28 + }, + "mixers": 0, + "sync": 0, + "flags": 0, + "volume": 1.0, + "balance": 0.5, + "enabled": true, + "muted": false, + "push-to-mute": false, + "push-to-mute-delay": 0, + "push-to-talk": false, + "push-to-talk-delay": 0, + "hotkeys": {}, + "deinterlace_mode": 0, + "deinterlace_field_order": 0, + "monitoring_type": 0, + "private_settings": {} + }, + { + "prev_ver": 536936450, + "name": "Discord", + "uuid": "0d7d9693-0a0c-4a52-af3a-1ec742590358", + "id": "pulse_output_capture", + "versioned_id": "pulse_output_capture", + "settings": { + "device_id": "discord_stream.monitor" + }, + "mixers": 255, + "sync": 0, + "flags": 0, + "volume": 1.0, + "balance": 0.5, + "enabled": true, + "muted": false, + "push-to-mute": false, + "push-to-mute-delay": 0, + "push-to-talk": false, + "push-to-talk-delay": 0, + "hotkeys": { + "libobs.mute": [], + "libobs.unmute": [], + "libobs.push-to-mute": [], + "libobs.push-to-talk": [] + }, + "deinterlace_mode": 0, + "deinterlace_field_order": 0, + "monitoring_type": 0, + "private_settings": {} + }, + { + "prev_ver": 536936450, + "name": "Desktop", + "uuid": "af8849dc-ea94-40bf-b018-3297518b1b04", + "id": "scene", + "versioned_id": "scene", + "settings": { + "custom_size": false, + "id_counter": 18, + "items": [ + { + "name": "Screen Capture (PipeWire)", + "source_uuid": "8f6ef725-1eec-4fdf-930a-2aab93d84c06", + "visible": true, + "locked": false, + "rot": 0.0, + "scale_ref": { + "x": 2560.0, + "y": 1336.0 + }, + "align": 5, + "bounds_type": 1, + "bounds_align": 0, + "bounds_crop": false, + "crop_left": 0, + "crop_top": 0, + "crop_right": 0, + "crop_bottom": 0, + "id": 13, + "group_item_backup": false, + "pos": { + "x": 534.0, + "y": 7.0 + }, + "pos_rel": { + "x": -1.1167664527893066, + "y": -0.98952096700668335 + }, + "scale": { + "x": 1.0, + "y": 1.0 + }, + "scale_rel": { + "x": 1.0, + "y": 1.0 + }, + "bounds": { + "x": 2017.0, + "y": 1213.0 + }, + "bounds_rel": { + "x": 3.0194611549377441, + "y": 1.8158682584762573 + }, + "scale_filter": "disable", + "blend_method": "default", + "blend_type": "normal", + "show_transition": { + "duration": 0 + }, + "hide_transition": { + "duration": 0 + }, + "private_settings": {} + }, + { + "name": "MPD", + "source_uuid": "25440930-0606-46d9-ba2c-be786ff4a3ae", + "visible": true, + "locked": false, + "rot": 0.0, + "scale_ref": { + "x": 2560.0, + "y": 1336.0 + }, + "align": 5, + "bounds_type": 0, + "bounds_align": 0, + "bounds_crop": false, + "crop_left": 0, + "crop_top": 0, + "crop_right": 0, + "crop_bottom": 0, + "id": 14, + "group_item_backup": false, + "pos": { + "x": 0.0, + "y": 0.0 + }, + "pos_rel": { + "x": -1.9161676168441772, + "y": -1.0 + }, + "scale": { + "x": 1.0, + "y": 1.0 + }, + "scale_rel": { + "x": 1.0, + "y": 1.0 + }, + "bounds": { + "x": 0.0, + "y": 0.0 + }, + "bounds_rel": { + "x": 0.0, + "y": 0.0 + }, + "scale_filter": "disable", + "blend_method": "default", + "blend_type": "normal", + "show_transition": { + "duration": 300 + }, + "hide_transition": { + "duration": 300 + }, + "private_settings": {} + }, + { + "name": "Desktop HUD", + "source_uuid": "8acfb832-cfb4-4310-8ebb-b58fad2b3509", + "visible": true, + "locked": false, + "rot": 0.0, + "scale_ref": { + "x": 2560.0, + "y": 1336.0 + }, + "align": 5, + "bounds_type": 1, + "bounds_align": 0, + "bounds_crop": false, + "crop_left": 0, + "crop_top": 0, + "crop_right": 0, + "crop_bottom": 0, + "id": 15, + "group_item_backup": false, + "pos": { + "x": 0.0, + "y": 0.0 + }, + "pos_rel": { + "x": -1.9161676168441772, + "y": -1.0 + }, + "scale": { + "x": 1.0, + "y": 1.0 + }, + "scale_rel": { + "x": 1.0, + "y": 1.0 + }, + "bounds": { + "x": 2560.0, + "y": 1336.0 + }, + "bounds_rel": { + "x": 3.8323352336883545, + "y": 2.0 + }, + "scale_filter": "disable", + "blend_method": "default", + "blend_type": "normal", + "show_transition": { + "duration": 300 + }, + "hide_transition": { + "duration": 300 + }, + "private_settings": {} + }, + { + "name": "Camera", + "source_uuid": "a8b362a1-91a6-491b-8751-26e2dad55ccd", + "visible": true, + "locked": false, + "rot": 0.0, + "scale_ref": { + "x": 1920.0, + "y": 1080.0 + }, + "align": 5, + "bounds_type": 0, + "bounds_align": 0, + "bounds_crop": false, + "crop_left": 0, + "crop_top": 0, + "crop_right": 0, + "crop_bottom": 0, + "id": 16, + "group_item_backup": false, + "pos": { + "x": 22.0, + "y": 902.0 + }, + "pos_rel": { + "x": -1.8832335472106934, + "y": 0.35029935836791992 + }, + "scale": { + "x": 0.39754101634025574, + "y": 0.39722222089767456 + }, + "scale_rel": { + "x": 0.32136547565460205, + "y": 0.32110777497291565 + }, + "bounds": { + "x": 0.0, + "y": 0.0 + }, + "bounds_rel": { + "x": 0.0, + "y": 0.0 + }, + "scale_filter": "disable", + "blend_method": "default", + "blend_type": "normal", + "show_transition": { + "duration": 0 + }, + "hide_transition": { + "duration": 0 + }, + "private_settings": {} + }, + { + "name": "Music Box Widget", + "source_uuid": "f662d513-6fe6-49fd-99f6-ea7f44e8de18", + "visible": true, + "locked": false, + "rot": 0.0, + "scale_ref": { + "x": 549.0, + "y": 880.0 + }, + "align": 5, + "bounds_type": 0, + "bounds_align": 0, + "bounds_crop": false, + "crop_left": 0, + "crop_top": 0, + "crop_right": 0, + "crop_bottom": 0, + "id": 17, + "group_item_backup": false, + "pos": { + "x": 12.0, + "y": 6.0 + }, + "pos_rel": { + "x": -1.8982036113739014, + "y": -0.99101793766021729 + }, + "scale": { + "x": 0.91985428333282471, + "y": 0.91931825876235962 + }, + "scale_rel": { + "x": 0.60589206218719482, + "y": 0.60553896427154541 + }, + "bounds": { + "x": 0.0, + "y": 0.0 + }, + "bounds_rel": { + "x": 0.0, + "y": 0.0 + }, + "scale_filter": "disable", + "blend_method": "default", + "blend_type": "normal", + "show_transition": { + "duration": 300 + }, + "hide_transition": { + "duration": 300 + }, + "private_settings": {} + }, + { + "name": "Discord", + "source_uuid": "0d7d9693-0a0c-4a52-af3a-1ec742590358", + "visible": true, + "locked": false, + "rot": 0.0, + "scale_ref": { + "x": 2560.0, + "y": 1336.0 + }, + "align": 5, + "bounds_type": 0, + "bounds_align": 0, + "bounds_crop": false, + "crop_left": 0, + "crop_top": 0, + "crop_right": 0, + "crop_bottom": 0, + "id": 18, + "group_item_backup": false, + "pos": { + "x": 0.0, + "y": 0.0 + }, + "pos_rel": { + "x": -1.9161676168441772, + "y": -1.0 + }, + "scale": { + "x": 1.0, + "y": 1.0 + }, + "scale_rel": { + "x": 1.0, + "y": 1.0 + }, + "bounds": { + "x": 0.0, + "y": 0.0 + }, + "bounds_rel": { + "x": 0.0, + "y": 0.0 + }, + "scale_filter": "disable", + "blend_method": "default", + "blend_type": "normal", + "show_transition": { + "duration": 0 + }, + "hide_transition": { + "duration": 0 + }, + "private_settings": {} + } + ] + }, + "mixers": 0, + "sync": 0, + "flags": 0, + "volume": 1.0, + "balance": 0.5, + "enabled": true, + "muted": false, + "push-to-mute": false, + "push-to-mute-delay": 0, + "push-to-talk": false, + "push-to-talk-delay": 0, + "hotkeys": { + "OBSBasic.SelectScene": [ + { + "control": true, + "key": "OBS_KEY_COMMA" + } + ], + "libobs.show_scene_item.13": [], + "libobs.hide_scene_item.13": [], + "libobs.show_scene_item.14": [], + "libobs.hide_scene_item.14": [], + "libobs.show_scene_item.15": [], + "libobs.hide_scene_item.15": [], + "libobs.show_scene_item.16": [], + "libobs.hide_scene_item.16": [], + "libobs.show_scene_item.17": [], + "libobs.hide_scene_item.17": [], + "libobs.show_scene_item.18": [], + "libobs.hide_scene_item.18": [] + }, + "deinterlace_mode": 0, + "deinterlace_field_order": 0, + "monitoring_type": 0, + "canvas_uuid": "6c69626f-6273-4c00-9d88-c5136d61696e", + "private_settings": {} + }, + { + "prev_ver": 536936450, + "name": "Game", + "uuid": "45b37004-1f57-4395-aeb1-06599415317d", + "id": "scene", + "versioned_id": "scene", + "settings": { + "custom_size": false, + "id_counter": 25, + "items": [ + { + "name": "Screen Capture (PipeWire) 2", + "source_uuid": "1e23924b-8260-4246-b7ee-74456fb62e65", + "visible": true, + "locked": false, + "rot": 0.0, + "scale_ref": { + "x": 2560.0, + "y": 1336.0 + }, + "align": 5, + "bounds_type": 1, + "bounds_align": 0, + "bounds_crop": false, + "crop_left": 0, + "crop_top": 0, + "crop_right": 0, + "crop_bottom": 0, + "id": 21, + "group_item_backup": false, + "pos": { + "x": 0.0, + "y": 0.0 + }, + "pos_rel": { + "x": -1.9161676168441772, + "y": -1.0 + }, + "scale": { + "x": 1.0, + "y": 1.0 + }, + "scale_rel": { + "x": 1.0, + "y": 1.0 + }, + "bounds": { + "x": 2560.0, + "y": 1336.0 + }, + "bounds_rel": { + "x": 3.8323352336883545, + "y": 2.0 + }, + "scale_filter": "disable", + "blend_method": "default", + "blend_type": "normal", + "show_transition": { + "duration": 300 + }, + "hide_transition": { + "duration": 300 + }, + "private_settings": {} + }, + { + "name": "Doomguard Logo", + "source_uuid": "ee77caf1-a490-45fa-80d9-4072f7e63d9a", + "visible": true, + "locked": false, + "rot": 0.0, + "scale_ref": { + "x": 1920.0, + "y": 1080.0 + }, + "align": 5, + "bounds_type": 0, + "bounds_align": 0, + "bounds_crop": false, + "crop_left": 0, + "crop_top": 0, + "crop_right": 0, + "crop_bottom": 0, + "id": 6, + "group_item_backup": true, + "pos": { + "x": 2350.0, + "y": -0.99993896484375 + }, + "pos_rel": { + "x": 1.6017963886260986, + "y": -1.0014969110488892 + }, + "scale": { + "x": 0.35290849208831787, + "y": 0.35290849208831787 + }, + "scale_rel": { + "x": 0.28528529405593872, + "y": 0.28528529405593872 + }, + "bounds": { + "x": 0.0, + "y": 0.0 + }, + "bounds_rel": { + "x": 0.0, + "y": 0.0 + }, + "scale_filter": "disable", + "blend_method": "default", + "blend_type": "normal", + "show_transition": { + "duration": 0 + }, + "hide_transition": { + "duration": 0 + }, + "private_settings": {} + }, + { + "name": "Starting Soon", + "source_uuid": "4b902d7f-9205-444c-8c8b-b559479d5bea", + "visible": true, + "locked": false, + "rot": 0.0, + "scale_ref": { + "x": 1920.0, + "y": 1080.0 + }, + "align": 5, + "bounds_type": 0, + "bounds_align": 0, + "bounds_crop": false, + "crop_left": 0, + "crop_top": 0, + "crop_right": 0, + "crop_bottom": 0, + "id": 10, + "group_item_backup": true, + "pos": { + "x": 835.35546875, + "y": 488.00006103515625 + }, + "pos_rel": { + "x": -0.66563552618026733, + "y": -0.26946097612380981 + }, + "scale": { + "x": 2.042553186416626, + "y": 2.0388350486755371 + }, + "scale_rel": { + "x": 1.6511658430099487, + "y": 1.6481600999832153 + }, + "bounds": { + "x": 0.0, + "y": 0.0 + }, + "bounds_rel": { + "x": 0.0, + "y": 0.0 + }, + "scale_filter": "disable", + "blend_method": "default", + "blend_type": "normal", + "show_transition": { + "id": "wipe_transition", + "versioned_id": "wipe_transition", + "name": "Starting Soon Show Transition", + "transition": {}, + "duration": 1000 + }, + "hide_transition": { + "duration": 0 + }, + "private_settings": {} + }, + { + "name": "info", + "source_uuid": "cfcf2652-2777-4b92-a53b-54703f23deff", + "visible": false, + "locked": false, + "rot": 0.0, + "scale_ref": { + "x": 1920.0, + "y": 1080.0 + }, + "align": 5, + "bounds_type": 0, + "bounds_align": 0, + "bounds_crop": false, + "crop_left": 0, + "crop_top": 0, + "crop_right": 0, + "crop_bottom": 0, + "id": 8, + "group_item_backup": true, + "pos": { + "x": 911.3555908203125, + "y": 1192.0 + }, + "pos_rel": { + "x": -0.55186289548873901, + "y": 0.7844310998916626 + }, + "scale": { + "x": 2.5, + "y": 2.5 + }, + "scale_rel": { + "x": 2.0209579467773438, + "y": 2.0209579467773438 + }, + "bounds": { + "x": 0.0, + "y": 0.0 + }, + "bounds_rel": { + "x": 0.0, + "y": 0.0 + }, + "scale_filter": "disable", + "blend_method": "default", + "blend_type": "normal", + "show_transition": { + "duration": 0 + }, + "hide_transition": { + "duration": 0 + }, + "private_settings": {} + }, + { + "name": "STAND BY", + "source_uuid": "d730eeb6-8969-4265-b033-5f777686ce2d", + "visible": false, + "locked": false, + "rot": 0.0, + "scale_ref": { + "x": 1920.0, + "y": 1080.0 + }, + "align": 5, + "bounds_type": 0, + "bounds_align": 0, + "bounds_crop": false, + "crop_left": 0, + "crop_top": 0, + "crop_right": 0, + "crop_bottom": 0, + "id": 12, + "group_item_backup": false, + "pos": { + "x": 835.35546875, + "y": -0.99993896484375 + }, + "pos_rel": { + "x": -0.66563552618026733, + "y": -1.0014969110488892 + }, + "scale": { + "x": 1.0, + "y": 1.0 + }, + "scale_rel": { + "x": 1.0, + "y": 1.0 + }, + "bounds": { + "x": 0.0, + "y": 0.0 + }, + "bounds_rel": { + "x": 0.0, + "y": 0.0 + }, + "scale_filter": "disable", + "blend_method": "default", + "blend_type": "normal", + "show_transition": { + "duration": 0 + }, + "hide_transition": { + "duration": 0 + }, + "private_settings": { + "collapsed": false + } + }, + { + "name": "Audio Player", + "source_uuid": "b7b89406-53f4-45ba-aa1a-c20d17b1c905", + "visible": true, + "locked": false, + "rot": 0.0, + "scale_ref": { + "x": 2560.0, + "y": 1336.0 + }, + "align": 5, + "bounds_type": 0, + "bounds_align": 0, + "bounds_crop": false, + "crop_left": 0, + "crop_top": 0, + "crop_right": 0, + "crop_bottom": 0, + "id": 22, + "group_item_backup": false, + "pos": { + "x": -315.0, + "y": 87.0 + }, + "pos_rel": { + "x": -2.3877246379852295, + "y": -0.86976051330566406 + }, + "scale": { + "x": 0.5975000262260437, + "y": 0.60000002384185791 + }, + "scale_rel": { + "x": 0.5975000262260437, + "y": 0.60000002384185791 + }, + "bounds": { + "x": 0.0, + "y": 0.0 + }, + "bounds_rel": { + "x": 0.0, + "y": 0.0 + }, + "scale_filter": "disable", + "blend_method": "default", + "blend_type": "normal", + "show_transition": { + "duration": 300 + }, + "hide_transition": { + "duration": 300 + }, + "private_settings": {} + }, + { + "name": "HUD", + "source_uuid": "f409a999-358f-488d-98db-c5c6a01d01b9", + "visible": true, + "locked": false, + "rot": 0.0, + "scale_ref": { + "x": 2560.0, + "y": 1336.0 + }, + "align": 5, + "bounds_type": 1, + "bounds_align": 0, + "bounds_crop": false, + "crop_left": 0, + "crop_top": 0, + "crop_right": 0, + "crop_bottom": 0, + "id": 23, + "group_item_backup": false, + "pos": { + "x": 0.0, + "y": 0.0 + }, + "pos_rel": { + "x": -1.9161676168441772, + "y": -1.0 + }, + "scale": { + "x": 1.0, + "y": 1.0 + }, + "scale_rel": { + "x": 1.0, + "y": 1.0 + }, + "bounds": { + "x": 2560.0, + "y": 1336.0 + }, + "bounds_rel": { + "x": 3.8323352336883545, + "y": 2.0 + }, + "scale_filter": "disable", + "blend_method": "default", + "blend_type": "normal", + "show_transition": { + "duration": 300 + }, + "hide_transition": { + "duration": 300 + }, + "private_settings": {} + }, + { + "name": "Camera", + "source_uuid": "a8b362a1-91a6-491b-8751-26e2dad55ccd", + "visible": false, + "locked": false, + "rot": 0.0, + "scale_ref": { + "x": 1920.0, + "y": 1080.0 + }, + "align": 5, + "bounds_type": 0, + "bounds_align": 0, + "bounds_crop": false, + "crop_left": 0, + "crop_top": 0, + "crop_right": 0, + "crop_bottom": 0, + "id": 16, + "group_item_backup": false, + "pos": { + "x": 83.0, + "y": 88.0 + }, + "pos_rel": { + "x": -1.7919161319732666, + "y": -0.86826348304748535 + }, + "scale": { + "x": 0.24262295663356781, + "y": 0.24318182468414307 + }, + "scale_rel": { + "x": 0.19613233208656311, + "y": 0.19658410549163818 + }, + "bounds": { + "x": 0.0, + "y": 0.0 + }, + "bounds_rel": { + "x": 0.0, + "y": 0.0 + }, + "scale_filter": "disable", + "blend_method": "default", + "blend_type": "normal", + "show_transition": { + "id": "wipe_transition", + "versioned_id": "wipe_transition", + "name": "Camera Show Transition", + "transition": { + "luma_image": "checkerboard-small.png" + }, + "duration": 1000 + }, + "hide_transition": { + "id": "wipe_transition", + "versioned_id": "wipe_transition", + "name": "Camera Hide Transition", + "transition": { + "luma_image": "checkerboard-small.png" + }, + "duration": 1000 + }, + "private_settings": {} + }, + { + "name": "MPD", + "source_uuid": "25440930-0606-46d9-ba2c-be786ff4a3ae", + "visible": true, + "locked": false, + "rot": 0.0, + "scale_ref": { + "x": 2560.0, + "y": 1336.0 + }, + "align": 5, + "bounds_type": 0, + "bounds_align": 0, + "bounds_crop": false, + "crop_left": 0, + "crop_top": 0, + "crop_right": 0, + "crop_bottom": 0, + "id": 24, + "group_item_backup": false, + "pos": { + "x": 0.0, + "y": 0.0 + }, + "pos_rel": { + "x": -1.9161676168441772, + "y": -1.0 + }, + "scale": { + "x": 1.0, + "y": 1.0 + }, + "scale_rel": { + "x": 1.0, + "y": 1.0 + }, + "bounds": { + "x": 0.0, + "y": 0.0 + }, + "bounds_rel": { + "x": 0.0, + "y": 0.0 + }, + "scale_filter": "disable", + "blend_method": "default", + "blend_type": "normal", + "show_transition": { + "duration": 300 + }, + "hide_transition": { + "duration": 300 + }, + "private_settings": {} + }, + { + "name": "Discord", + "source_uuid": "0d7d9693-0a0c-4a52-af3a-1ec742590358", + "visible": true, + "locked": false, + "rot": 0.0, + "scale_ref": { + "x": 2560.0, + "y": 1336.0 + }, + "align": 5, + "bounds_type": 0, + "bounds_align": 0, + "bounds_crop": false, + "crop_left": 0, + "crop_top": 0, + "crop_right": 0, + "crop_bottom": 0, + "id": 25, + "group_item_backup": false, + "pos": { + "x": 0.0, + "y": 0.0 + }, + "pos_rel": { + "x": -1.9161676168441772, + "y": -1.0 + }, + "scale": { + "x": 1.0, + "y": 1.0 + }, + "scale_rel": { + "x": 1.0, + "y": 1.0 + }, + "bounds": { + "x": 0.0, + "y": 0.0 + }, + "bounds_rel": { + "x": 0.0, + "y": 0.0 + }, + "scale_filter": "disable", + "blend_method": "default", + "blend_type": "normal", + "show_transition": { + "duration": 0 + }, + "hide_transition": { + "duration": 0 + }, + "private_settings": {} + } + ] + }, + "mixers": 0, + "sync": 0, + "flags": 0, + "volume": 1.0, + "balance": 0.5, + "enabled": true, + "muted": false, + "push-to-mute": false, + "push-to-mute-delay": 0, + "push-to-talk": false, + "push-to-talk-delay": 0, + "hotkeys": { + "OBSBasic.SelectScene": [ + { + "control": true, + "key": "OBS_KEY_PERIOD" + } + ], + "libobs.show_scene_item.21": [], + "libobs.hide_scene_item.21": [], + "libobs.show_scene_item.12": [], + "libobs.hide_scene_item.12": [], + "libobs.show_scene_item.22": [], + "libobs.hide_scene_item.22": [], + "libobs.show_scene_item.23": [], + "libobs.hide_scene_item.23": [], + "libobs.show_scene_item.16": [], + "libobs.hide_scene_item.16": [], + "libobs.show_scene_item.24": [], + "libobs.hide_scene_item.24": [], + "libobs.show_scene_item.25": [], + "libobs.hide_scene_item.25": [] + }, + "deinterlace_mode": 0, + "deinterlace_field_order": 0, + "monitoring_type": 0, + "canvas_uuid": "6c69626f-6273-4c00-9d88-c5136d61696e", + "private_settings": { + "transition": "" + } + }, + { + "prev_ver": 536936450, + "name": "Landing", + "uuid": "2b56b1b1-2f3e-44f0-ac0f-5d33cad38551", + "id": "scene", + "versioned_id": "scene", + "settings": { + "id_counter": 6, + "custom_size": false, + "items": [ + { + "name": "Landing — Stand By (Browser)", + "source_uuid": "dd513385-f6d8-44da-a459-20acbe620823", + "visible": true, + "locked": false, + "rot": 0.0, + "scale_ref": { + "x": 2560.0, + "y": 1336.0 + }, + "align": 5, + "bounds_type": 1, + "bounds_align": 0, + "bounds_crop": false, + "crop_left": 0, + "crop_top": 0, + "crop_right": 0, + "crop_bottom": 0, + "id": 1, + "group_item_backup": false, + "pos": { + "x": 4.0, + "y": 0.0 + }, + "pos_rel": { + "x": -1.910179615020752, + "y": -1.0 + }, + "scale": { + "x": 1.0, + "y": 1.0 + }, + "scale_rel": { + "x": 1.0, + "y": 1.0 + }, + "bounds": { + "x": 2560.0, + "y": 1336.0 + }, + "bounds_rel": { + "x": 3.8323352336883545, + "y": 2.0 + }, + "scale_filter": "disable", + "blend_method": "default", + "blend_type": "normal", + "show_transition": { + "duration": 300 + }, + "hide_transition": { + "id": "wipe_transition", + "versioned_id": "wipe_transition", + "name": "Landing — Stand By (Browser) Hide Transition", + "transition": { + "luma_image": "cloud.png" + }, + "duration": 300 + }, + "private_settings": {} + }, + { + "name": "Landing — Static Hum", + "source_uuid": "16cc92de-4b9b-4b1c-b405-8f089991ac86", + "visible": true, + "locked": false, + "rot": 0.0, + "scale_ref": { + "x": 2560.0, + "y": 1336.0 + }, + "align": 5, + "bounds_type": 0, + "bounds_align": 0, + "bounds_crop": false, + "crop_left": 0, + "crop_top": 0, + "crop_right": 0, + "crop_bottom": 0, + "id": 2, + "group_item_backup": false, + "pos": { + "x": 0.0, + "y": 0.0 + }, + "pos_rel": { + "x": -1.9161676168441772, + "y": -1.0 + }, + "scale": { + "x": 1.0, + "y": 1.0 + }, + "scale_rel": { + "x": 1.0, + "y": 1.0 + }, + "bounds": { + "x": 0.0, + "y": 0.0 + }, + "bounds_rel": { + "x": 0.0, + "y": 0.0 + }, + "scale_filter": "disable", + "blend_method": "default", + "blend_type": "normal", + "show_transition": { + "duration": 300 + }, + "hide_transition": { + "duration": 300 + }, + "private_settings": {} + }, + { + "name": "Doomguard Logo", + "source_uuid": "ee77caf1-a490-45fa-80d9-4072f7e63d9a", + "visible": false, + "locked": false, + "rot": 0.0, + "scale_ref": { + "x": 2560.0, + "y": 1336.0 + }, + "align": 5, + "bounds_type": 0, + "bounds_align": 0, + "bounds_crop": false, + "crop_left": 0, + "crop_top": 0, + "crop_right": 0, + "crop_bottom": 0, + "id": 4, + "group_item_backup": false, + "pos": { + "x": 1213.0, + "y": 119.0 + }, + "pos_rel": { + "x": -0.1002994030714035, + "y": -0.82185626029968262 + }, + "scale": { + "x": 0.42642644047737122, + "y": 0.42642644047737122 + }, + "scale_rel": { + "x": 0.42642644047737122, + "y": 0.42642644047737122 + }, + "bounds": { + "x": 0.0, + "y": 0.0 + }, + "bounds_rel": { + "x": 0.0, + "y": 0.0 + }, + "scale_filter": "disable", + "blend_method": "default", + "blend_type": "normal", + "show_transition": { + "duration": 300 + }, + "hide_transition": { + "duration": 300 + }, + "private_settings": {} + }, + { + "name": "MPD Silent", + "source_uuid": "41387cb0-801b-49df-92e6-75c7293bec3f", + "visible": true, + "locked": false, + "rot": 0.0, + "scale_ref": { + "x": 2560.0, + "y": 1336.0 + }, + "align": 5, + "bounds_type": 0, + "bounds_align": 0, + "bounds_crop": false, + "crop_left": 0, + "crop_top": 0, + "crop_right": 0, + "crop_bottom": 0, + "id": 6, + "group_item_backup": false, + "pos": { + "x": 0.0, + "y": 0.0 + }, + "pos_rel": { + "x": -1.9161676168441772, + "y": -1.0 + }, + "scale": { + "x": 1.0, + "y": 1.0 + }, + "scale_rel": { + "x": 1.0, + "y": 1.0 + }, + "bounds": { + "x": 0.0, + "y": 0.0 + }, + "bounds_rel": { + "x": 0.0, + "y": 0.0 + }, + "scale_filter": "disable", + "blend_method": "default", + "blend_type": "normal", + "show_transition": { + "duration": 300 + }, + "hide_transition": { + "duration": 300 + }, + "private_settings": {} + } + ] + }, + "mixers": 0, + "sync": 0, + "flags": 0, + "volume": 1.0, + "balance": 0.5, + "enabled": true, + "muted": false, + "push-to-mute": false, + "push-to-mute-delay": 0, + "push-to-talk": false, + "push-to-talk-delay": 0, + "hotkeys": { + "OBSBasic.SelectScene": [], + "libobs.show_scene_item.1": [], + "libobs.hide_scene_item.1": [], + "libobs.show_scene_item.2": [], + "libobs.hide_scene_item.2": [], + "libobs.show_scene_item.4": [], + "libobs.hide_scene_item.4": [], + "libobs.show_scene_item.6": [], + "libobs.hide_scene_item.6": [] + }, + "deinterlace_mode": 0, + "deinterlace_field_order": 0, + "monitoring_type": 0, + "canvas_uuid": "6c69626f-6273-4c00-9d88-c5136d61696e", + "private_settings": { + "transition": "" + } + }, + { + "prev_ver": 536936450, + "name": "Project Loading", + "uuid": "6b8e29a8-a66b-44f2-856e-bd41fb18720d", + "id": "scene", + "versioned_id": "scene", + "settings": { + "id_counter": 7, + "custom_size": false, + "items": [ + { + "name": "Loading Project", + "source_uuid": "6642f830-fbae-4020-8292-a9cb7991e6fc", + "visible": true, + "locked": false, + "rot": 0.0, + "scale_ref": { + "x": 2560.0, + "y": 1336.0 + }, + "align": 5, + "bounds_type": 0, + "bounds_align": 0, + "bounds_crop": false, + "crop_left": 0, + "crop_top": 0, + "crop_right": 0, + "crop_bottom": 0, + "id": 1, + "group_item_backup": false, + "pos": { + "x": 0.0, + "y": 0.0 + }, + "pos_rel": { + "x": -1.9161676168441772, + "y": -1.0 + }, + "scale": { + "x": 1.0, + "y": 1.0 + }, + "scale_rel": { + "x": 1.0, + "y": 1.0 + }, + "bounds": { + "x": 0.0, + "y": 0.0 + }, + "bounds_rel": { + "x": 0.0, + "y": 0.0 + }, + "scale_filter": "disable", + "blend_method": "default", + "blend_type": "normal", + "show_transition": { + "duration": 300 + }, + "hide_transition": { + "duration": 300 + }, + "private_settings": {} + }, + { + "name": "Audio", + "source_uuid": "fc5dfd34-bc55-4c92-8b5e-ef305afd1d8e", + "visible": true, + "locked": false, + "rot": 0.0, + "scale_ref": { + "x": 2560.0, + "y": 1336.0 + }, + "align": 5, + "bounds_type": 0, + "bounds_align": 0, + "bounds_crop": false, + "crop_left": 0, + "crop_top": 0, + "crop_right": 0, + "crop_bottom": 0, + "id": 2, + "group_item_backup": false, + "pos": { + "x": 0.0, + "y": 0.0 + }, + "pos_rel": { + "x": -1.9161676168441772, + "y": -1.0 + }, + "scale": { + "x": 1.0, + "y": 1.0 + }, + "scale_rel": { + "x": 1.0, + "y": 1.0 + }, + "bounds": { + "x": 0.0, + "y": 0.0 + }, + "bounds_rel": { + "x": 0.0, + "y": 0.0 + }, + "scale_filter": "disable", + "blend_method": "default", + "blend_type": "normal", + "show_transition": { + "duration": 300 + }, + "hide_transition": { + "duration": 300 + }, + "private_settings": {} + }, + { + "name": "MPD", + "source_uuid": "25440930-0606-46d9-ba2c-be786ff4a3ae", + "visible": true, + "locked": false, + "rot": 0.0, + "scale_ref": { + "x": 2560.0, + "y": 1336.0 + }, + "align": 5, + "bounds_type": 0, + "bounds_align": 0, + "bounds_crop": false, + "crop_left": 0, + "crop_top": 0, + "crop_right": 0, + "crop_bottom": 0, + "id": 7, + "group_item_backup": false, + "pos": { + "x": 0.0, + "y": 0.0 + }, + "pos_rel": { + "x": -1.9161676168441772, + "y": -1.0 + }, + "scale": { + "x": 1.0, + "y": 1.0 + }, + "scale_rel": { + "x": 1.0, + "y": 1.0 + }, + "bounds": { + "x": 0.0, + "y": 0.0 + }, + "bounds_rel": { + "x": 0.0, + "y": 0.0 + }, + "scale_filter": "disable", + "blend_method": "default", + "blend_type": "normal", + "show_transition": { + "duration": 300 + }, + "hide_transition": { + "duration": 300 + }, + "private_settings": {} + } + ] + }, + "mixers": 0, + "sync": 0, + "flags": 0, + "volume": 1.0, + "balance": 0.5, + "enabled": true, + "muted": false, + "push-to-mute": false, + "push-to-mute-delay": 0, + "push-to-talk": false, + "push-to-talk-delay": 0, + "hotkeys": { + "OBSBasic.SelectScene": [], + "libobs.show_scene_item.1": [], + "libobs.hide_scene_item.1": [], + "libobs.show_scene_item.2": [], + "libobs.hide_scene_item.2": [], + "libobs.show_scene_item.7": [], + "libobs.hide_scene_item.7": [] + }, + "deinterlace_mode": 0, + "deinterlace_field_order": 0, + "monitoring_type": 0, + "canvas_uuid": "6c69626f-6273-4c00-9d88-c5136d61696e", + "private_settings": {} + }, + { + "prev_ver": 536936450, + "name": "Good Bye", + "uuid": "ff28214d-6519-4b4b-a00a-c68498c606ef", + "id": "scene", + "versioned_id": "scene", + "settings": { + "id_counter": 3, + "custom_size": false, + "items": [ + { + "name": "Audio Player", + "source_uuid": "b7b89406-53f4-45ba-aa1a-c20d17b1c905", + "visible": true, + "locked": false, + "rot": 0.0, + "scale_ref": { + "x": 2560.0, + "y": 1336.0 + }, + "align": 5, + "bounds_type": 0, + "bounds_align": 0, + "bounds_crop": false, + "crop_left": 0, + "crop_top": 0, + "crop_right": 0, + "crop_bottom": 0, + "id": 1, + "group_item_backup": false, + "pos": { + "x": -101.0, + "y": 173.0 + }, + "pos_rel": { + "x": -2.0673651695251465, + "y": -0.74101793766021729 + }, + "scale": { + "x": 1.5, + "y": 1.5 + }, + "scale_rel": { + "x": 1.5, + "y": 1.5 + }, + "bounds": { + "x": 0.0, + "y": 0.0 + }, + "bounds_rel": { + "x": 0.0, + "y": 0.0 + }, + "scale_filter": "disable", + "blend_method": "default", + "blend_type": "normal", + "show_transition": { + "duration": 300 + }, + "hide_transition": { + "duration": 300 + }, + "private_settings": {} + }, + { + "name": "GB", + "source_uuid": "38306c90-5bb8-4603-a21c-09383c300097", + "visible": true, + "locked": false, + "rot": 0.0, + "scale_ref": { + "x": 2560.0, + "y": 1336.0 + }, + "align": 5, + "bounds_type": 0, + "bounds_align": 0, + "bounds_crop": false, + "crop_left": 0, + "crop_top": 0, + "crop_right": 0, + "crop_bottom": 0, + "id": 2, + "group_item_backup": false, + "pos": { + "x": 0.0, + "y": 0.0 + }, + "pos_rel": { + "x": -1.9161676168441772, + "y": -1.0 + }, + "scale": { + "x": 1.0, + "y": 1.0 + }, + "scale_rel": { + "x": 1.0, + "y": 1.0 + }, + "bounds": { + "x": 0.0, + "y": 0.0 + }, + "bounds_rel": { + "x": 0.0, + "y": 0.0 + }, + "scale_filter": "disable", + "blend_method": "default", + "blend_type": "normal", + "show_transition": { + "duration": 300 + }, + "hide_transition": { + "duration": 300 + }, + "private_settings": {} + }, + { + "name": "MPD", + "source_uuid": "25440930-0606-46d9-ba2c-be786ff4a3ae", + "visible": true, + "locked": false, + "rot": 0.0, + "scale_ref": { + "x": 2560.0, + "y": 1336.0 + }, + "align": 5, + "bounds_type": 0, + "bounds_align": 0, + "bounds_crop": false, + "crop_left": 0, + "crop_top": 0, + "crop_right": 0, + "crop_bottom": 0, + "id": 3, + "group_item_backup": false, + "pos": { + "x": 0.0, + "y": 0.0 + }, + "pos_rel": { + "x": -1.9161676168441772, + "y": -1.0 + }, + "scale": { + "x": 1.0, + "y": 1.0 + }, + "scale_rel": { + "x": 1.0, + "y": 1.0 + }, + "bounds": { + "x": 0.0, + "y": 0.0 + }, + "bounds_rel": { + "x": 0.0, + "y": 0.0 + }, + "scale_filter": "disable", + "blend_method": "default", + "blend_type": "normal", + "show_transition": { + "duration": 300 + }, + "hide_transition": { + "duration": 300 + }, + "private_settings": {} + } + ] + }, + "mixers": 0, + "sync": 0, + "flags": 0, + "volume": 1.0, + "balance": 0.5, + "enabled": true, + "muted": false, + "push-to-mute": false, + "push-to-mute-delay": 0, + "push-to-talk": false, + "push-to-talk-delay": 0, + "hotkeys": { + "OBSBasic.SelectScene": [], + "libobs.show_scene_item.1": [], + "libobs.hide_scene_item.1": [], + "libobs.show_scene_item.2": [], + "libobs.hide_scene_item.2": [], + "libobs.show_scene_item.3": [], + "libobs.hide_scene_item.3": [] + }, + "deinterlace_mode": 0, + "deinterlace_field_order": 0, + "monitoring_type": 0, + "canvas_uuid": "6c69626f-6273-4c00-9d88-c5136d61696e", + "private_settings": {} + }, + { + "prev_ver": 536936450, + "name": "Music Box", + "uuid": "747b2411-45a9-471a-b0dc-dfe39b0d6385", + "id": "scene", + "versioned_id": "scene", + "settings": { + "id_counter": 9, + "custom_size": false, + "items": [ + { + "name": "MPD", + "source_uuid": "25440930-0606-46d9-ba2c-be786ff4a3ae", + "visible": true, + "locked": false, + "rot": 0.0, + "scale_ref": { + "x": 2560.0, + "y": 1336.0 + }, + "align": 5, + "bounds_type": 0, + "bounds_align": 0, + "bounds_crop": false, + "crop_left": 0, + "crop_top": 0, + "crop_right": 0, + "crop_bottom": 0, + "id": 1, + "group_item_backup": false, + "pos": { + "x": 0.0, + "y": 0.0 + }, + "pos_rel": { + "x": -1.9161676168441772, + "y": -1.0 + }, + "scale": { + "x": 1.0, + "y": 1.0 + }, + "scale_rel": { + "x": 1.0, + "y": 1.0 + }, + "bounds": { + "x": 0.0, + "y": 0.0 + }, + "bounds_rel": { + "x": 0.0, + "y": 0.0 + }, + "scale_filter": "disable", + "blend_method": "default", + "blend_type": "normal", + "show_transition": { + "duration": 300 + }, + "hide_transition": { + "duration": 300 + }, + "private_settings": {} + }, + { + "name": "Music Box HUD", + "source_uuid": "1b9f5436-864d-4f24-9f92-f45702a23953", + "visible": true, + "locked": false, + "rot": 0.0, + "scale_ref": { + "x": 2560.0, + "y": 1336.0 + }, + "align": 5, + "bounds_type": 1, + "bounds_align": 0, + "bounds_crop": false, + "crop_left": 0, + "crop_top": 0, + "crop_right": 0, + "crop_bottom": 0, + "id": 2, + "group_item_backup": false, + "pos": { + "x": 0.0, + "y": 0.0 + }, + "pos_rel": { + "x": -1.9161676168441772, + "y": -1.0 + }, + "scale": { + "x": 1.0, + "y": 1.0 + }, + "scale_rel": { + "x": 1.0, + "y": 1.0 + }, + "bounds": { + "x": 2560.0, + "y": 1336.0 + }, + "bounds_rel": { + "x": 3.8323352336883545, + "y": 2.0 + }, + "scale_filter": "disable", + "blend_method": "default", + "blend_type": "normal", + "show_transition": { + "duration": 300 + }, + "hide_transition": { + "duration": 300 + }, + "private_settings": {} + }, + { + "name": "Cover Simple", + "source_uuid": "7062784f-7b1b-4728-9067-27128c0d5748", + "visible": false, + "locked": false, + "rot": 0.0, + "scale_ref": { + "x": 2560.0, + "y": 1336.0 + }, + "align": 5, + "bounds_type": 0, + "bounds_align": 0, + "bounds_crop": false, + "crop_left": 0, + "crop_top": 0, + "crop_right": 0, + "crop_bottom": 0, + "id": 4, + "group_item_backup": false, + "pos": { + "x": 1711.0, + "y": 176.0 + }, + "pos_rel": { + "x": 0.64520961046218872, + "y": -0.7365269660949707 + }, + "scale": { + "x": 0.36875000596046448, + "y": 0.36833333969116211 + }, + "scale_rel": { + "x": 0.36875000596046448, + "y": 0.36833333969116211 + }, + "bounds": { + "x": 0.0, + "y": 0.0 + }, + "bounds_rel": { + "x": 0.0, + "y": 0.0 + }, + "scale_filter": "disable", + "blend_method": "default", + "blend_type": "normal", + "show_transition": { + "duration": 300 + }, + "hide_transition": { + "duration": 300 + }, + "private_settings": {} + }, + { + "name": "NC Music Box HUD", + "source_uuid": "edbd893d-ce53-4c91-bf6c-4d52fbf394d6", + "visible": true, + "locked": false, + "rot": 0.0, + "scale_ref": { + "x": 2560.0, + "y": 1336.0 + }, + "align": 5, + "bounds_type": 0, + "bounds_align": 0, + "bounds_crop": false, + "crop_left": 0, + "crop_top": 0, + "crop_right": 0, + "crop_bottom": 0, + "id": 5, + "group_item_backup": false, + "pos": { + "x": 0.0, + "y": 0.0 + }, + "pos_rel": { + "x": -1.9161676168441772, + "y": -1.0 + }, + "scale": { + "x": 1.0, + "y": 1.0 + }, + "scale_rel": { + "x": 1.0, + "y": 1.0 + }, + "bounds": { + "x": 0.0, + "y": 0.0 + }, + "bounds_rel": { + "x": 0.0, + "y": 0.0 + }, + "scale_filter": "disable", + "blend_method": "default", + "blend_type": "normal", + "show_transition": { + "id": "wipe_transition", + "versioned_id": "wipe_transition", + "name": "NC Music Box HUD Show Transition", + "transition": { + "luma_image": "checkerboard-small.png" + }, + "duration": 300 + }, + "hide_transition": { + "id": "wipe_transition", + "versioned_id": "wipe_transition", + "name": "NC Music Box HUD Hide Transition", + "transition": { + "luma_image": "checkerboard-small.png" + }, + "duration": 300 + }, + "private_settings": {} + }, + { + "name": "Waveform Visualizer", + "source_uuid": "f28cc995-6966-4afa-b831-ebb50d89ebe8", + "visible": true, + "locked": false, + "rot": 0.0, + "scale_ref": { + "x": 2560.0, + "y": 1336.0 + }, + "align": 5, + "bounds_type": 0, + "bounds_align": 0, + "bounds_crop": false, + "crop_left": 0, + "crop_top": 0, + "crop_right": 0, + "crop_bottom": 0, + "id": 6, + "group_item_backup": false, + "pos": { + "x": 2166.0, + "y": 1078.0 + }, + "pos_rel": { + "x": 1.3263473510742188, + "y": 0.61377251148223877 + }, + "scale": { + "x": 0.38249999284744263, + "y": 0.38222223520278931 + }, + "scale_rel": { + "x": 0.38249999284744263, + "y": 0.38222223520278931 + }, + "bounds": { + "x": 0.0, + "y": 0.0 + }, + "bounds_rel": { + "x": 0.0, + "y": 0.0 + }, + "scale_filter": "disable", + "blend_method": "default", + "blend_type": "normal", + "show_transition": { + "duration": 300 + }, + "hide_transition": { + "duration": 300 + }, + "private_settings": {} + }, + { + "name": "Discord", + "source_uuid": "0d7d9693-0a0c-4a52-af3a-1ec742590358", + "visible": true, + "locked": false, + "rot": 0.0, + "scale_ref": { + "x": 2560.0, + "y": 1336.0 + }, + "align": 5, + "bounds_type": 0, + "bounds_align": 0, + "bounds_crop": false, + "crop_left": 0, + "crop_top": 0, + "crop_right": 0, + "crop_bottom": 0, + "id": 7, + "group_item_backup": false, + "pos": { + "x": 0.0, + "y": 0.0 + }, + "pos_rel": { + "x": -1.9161676168441772, + "y": -1.0 + }, + "scale": { + "x": 1.0, + "y": 1.0 + }, + "scale_rel": { + "x": 1.0, + "y": 1.0 + }, + "bounds": { + "x": 0.0, + "y": 0.0 + }, + "bounds_rel": { + "x": 0.0, + "y": 0.0 + }, + "scale_filter": "disable", + "blend_method": "default", + "blend_type": "normal", + "show_transition": { + "duration": 0 + }, + "hide_transition": { + "duration": 0 + }, + "private_settings": {} + } + ] + }, + "mixers": 0, + "sync": 0, + "flags": 0, + "volume": 1.0, + "balance": 0.5, + "enabled": true, + "muted": false, + "push-to-mute": false, + "push-to-mute-delay": 0, + "push-to-talk": false, + "push-to-talk-delay": 0, + "hotkeys": { + "OBSBasic.SelectScene": [ + { + "control": true, + "key": "OBS_KEY_M" + } + ], + "libobs.show_scene_item.1": [], + "libobs.hide_scene_item.1": [], + "libobs.show_scene_item.2": [], + "libobs.hide_scene_item.2": [], + "libobs.show_scene_item.4": [], + "libobs.hide_scene_item.4": [], + "libobs.show_scene_item.5": [], + "libobs.hide_scene_item.5": [], + "libobs.show_scene_item.6": [], + "libobs.hide_scene_item.6": [], + "libobs.show_scene_item.7": [], + "libobs.hide_scene_item.7": [] + }, + "deinterlace_mode": 0, + "deinterlace_field_order": 0, + "monitoring_type": 0, + "canvas_uuid": "6c69626f-6273-4c00-9d88-c5136d61696e", + "private_settings": {} + }, + { + "prev_ver": 536936450, + "name": "Desktop (No Cam)", + "uuid": "e68f67a3-f90b-4e81-a89b-308a0ea83e57", + "id": "scene", + "versioned_id": "scene", + "settings": { + "id_counter": 10, + "custom_size": false, + "items": [ + { + "name": "Screen Capture (PipeWire)", + "source_uuid": "8f6ef725-1eec-4fdf-930a-2aab93d84c06", + "visible": true, + "locked": false, + "rot": 0.0, + "scale_ref": { + "x": 2560.0, + "y": 1336.0 + }, + "align": 5, + "bounds_type": 1, + "bounds_align": 0, + "bounds_crop": false, + "crop_left": 0, + "crop_top": 0, + "crop_right": 0, + "crop_bottom": 0, + "id": 1, + "group_item_backup": false, + "pos": { + "x": 10.0, + "y": 10.0 + }, + "pos_rel": { + "x": -1.9011975526809692, + "y": -0.98502993583679199 + }, + "scale": { + "x": 1.0, + "y": 1.0 + }, + "scale_rel": { + "x": 1.0, + "y": 1.0 + }, + "bounds": { + "x": 2127.0, + "y": 1289.0 + }, + "bounds_rel": { + "x": 3.1841316223144531, + "y": 1.9296407699584961 + }, + "scale_filter": "disable", + "blend_method": "default", + "blend_type": "normal", + "show_transition": { + "duration": 0 + }, + "hide_transition": { + "duration": 0 + }, + "private_settings": {} + }, + { + "name": "MPD", + "source_uuid": "25440930-0606-46d9-ba2c-be786ff4a3ae", + "visible": true, + "locked": false, + "rot": 0.0, + "scale_ref": { + "x": 2560.0, + "y": 1336.0 + }, + "align": 5, + "bounds_type": 0, + "bounds_align": 0, + "bounds_crop": false, + "crop_left": 0, + "crop_top": 0, + "crop_right": 0, + "crop_bottom": 0, + "id": 2, + "group_item_backup": false, + "pos": { + "x": 0.0, + "y": 0.0 + }, + "pos_rel": { + "x": -1.9161676168441772, + "y": -1.0 + }, + "scale": { + "x": 1.0, + "y": 1.0 + }, + "scale_rel": { + "x": 1.0, + "y": 1.0 + }, + "bounds": { + "x": 0.0, + "y": 0.0 + }, + "bounds_rel": { + "x": 0.0, + "y": 0.0 + }, + "scale_filter": "disable", + "blend_method": "default", + "blend_type": "normal", + "show_transition": { + "duration": 300 + }, + "hide_transition": { + "duration": 300 + }, + "private_settings": {} + }, + { + "name": "Desktop HUD", + "source_uuid": "8acfb832-cfb4-4310-8ebb-b58fad2b3509", + "visible": true, + "locked": false, + "rot": 0.0, + "scale_ref": { + "x": 2560.0, + "y": 1336.0 + }, + "align": 5, + "bounds_type": 1, + "bounds_align": 0, + "bounds_crop": false, + "crop_left": 0, + "crop_top": 0, + "crop_right": 0, + "crop_bottom": 0, + "id": 3, + "group_item_backup": false, + "pos": { + "x": -1.0, + "y": 0.0 + }, + "pos_rel": { + "x": -1.917664647102356, + "y": -1.0 + }, + "scale": { + "x": 1.0, + "y": 1.0 + }, + "scale_rel": { + "x": 1.0, + "y": 1.0 + }, + "bounds": { + "x": 2560.0, + "y": 1336.0 + }, + "bounds_rel": { + "x": 3.8323352336883545, + "y": 2.0 + }, + "scale_filter": "disable", + "blend_method": "default", + "blend_type": "normal", + "show_transition": { + "duration": 300 + }, + "hide_transition": { + "duration": 300 + }, + "private_settings": {} + }, + { + "name": "Camera", + "source_uuid": "a8b362a1-91a6-491b-8751-26e2dad55ccd", + "visible": false, + "locked": false, + "rot": 0.0, + "scale_ref": { + "x": 2560.0, + "y": 1336.0 + }, + "align": 5, + "bounds_type": 0, + "bounds_align": 0, + "bounds_crop": false, + "crop_left": 0, + "crop_top": 0, + "crop_right": 0, + "crop_bottom": 0, + "id": 4, + "group_item_backup": false, + "pos": { + "x": 2019.0, + "y": 22.0 + }, + "pos_rel": { + "x": 1.1062874794006348, + "y": -0.96706587076187134 + }, + "scale": { + "x": 0.34521940350532532, + "y": 0.3454001247882843 + }, + "scale_rel": { + "x": 0.34521940350532532, + "y": 0.3454001247882843 + }, + "bounds": { + "x": 0.0, + "y": 0.0 + }, + "bounds_rel": { + "x": 0.0, + "y": 0.0 + }, + "scale_filter": "disable", + "blend_method": "default", + "blend_type": "normal", + "show_transition": { + "duration": 0 + }, + "hide_transition": { + "duration": 0 + }, + "private_settings": {} + }, + { + "name": "Music Box Widget", + "source_uuid": "f662d513-6fe6-49fd-99f6-ea7f44e8de18", + "visible": true, + "locked": false, + "rot": 0.0, + "scale_ref": { + "x": 2560.0, + "y": 1336.0 + }, + "align": 5, + "bounds_type": 0, + "bounds_align": 0, + "bounds_crop": false, + "crop_left": 0, + "crop_top": 0, + "crop_right": 0, + "crop_bottom": 0, + "id": 5, + "group_item_backup": false, + "pos": { + "x": 2156.0, + "y": 597.0 + }, + "pos_rel": { + "x": 1.3113772869110107, + "y": -0.10628741979598999 + }, + "scale": { + "x": 0.7012750506401062, + "y": 0.70113635063171387 + }, + "scale_rel": { + "x": 0.7012750506401062, + "y": 0.70113635063171387 + }, + "bounds": { + "x": 0.0, + "y": 0.0 + }, + "bounds_rel": { + "x": 0.0, + "y": 0.0 + }, + "scale_filter": "disable", + "blend_method": "default", + "blend_type": "normal", + "show_transition": { + "duration": 300 + }, + "hide_transition": { + "duration": 300 + }, + "private_settings": {} + }, + { + "name": "Cover", + "source_uuid": "54d4ac81-e354-431a-a2dc-a00e5555e8d9", + "visible": true, + "locked": false, + "rot": 0.0, + "scale_ref": { + "x": 2560.0, + "y": 1336.0 + }, + "align": 5, + "bounds_type": 0, + "bounds_align": 0, + "bounds_crop": false, + "crop_left": 0, + "crop_top": 0, + "crop_right": 0, + "crop_bottom": 0, + "id": 6, + "group_item_backup": false, + "pos": { + "x": 2158.0, + "y": 13.0 + }, + "pos_rel": { + "x": 1.3143712282180786, + "y": -0.98053890466690063 + }, + "scale": { + "x": 0.48124998807907104, + "y": 0.48166665434837341 + }, + "scale_rel": { + "x": 0.48124998807907104, + "y": 0.48166665434837341 + }, + "bounds": { + "x": 0.0, + "y": 0.0 + }, + "bounds_rel": { + "x": 0.0, + "y": 0.0 + }, + "scale_filter": "disable", + "blend_method": "default", + "blend_type": "normal", + "show_transition": { + "duration": 300 + }, + "hide_transition": { + "duration": 300 + }, + "private_settings": {} + }, + { + "name": "Waveform Stereo", + "source_uuid": "bc63aaf3-2ae2-4de9-9c7a-c05e55fa2a11", + "visible": true, + "locked": false, + "rot": 0.0, + "scale_ref": { + "x": 2560.0, + "y": 1336.0 + }, + "align": 5, + "bounds_type": 0, + "bounds_align": 0, + "bounds_crop": false, + "crop_left": 0, + "crop_top": 0, + "crop_right": 0, + "crop_bottom": 0, + "id": 8, + "group_item_backup": false, + "pos": { + "x": 2160.0, + "y": 470.0 + }, + "pos_rel": { + "x": 1.317365288734436, + "y": -0.29640716314315796 + }, + "scale": { + "x": 0.49625000357627869, + "y": 0.4977777898311615 + }, + "scale_rel": { + "x": 0.49625000357627869, + "y": 0.4977777898311615 + }, + "bounds": { + "x": 0.0, + "y": 0.0 + }, + "bounds_rel": { + "x": 0.0, + "y": 0.0 + }, + "scale_filter": "disable", + "blend_method": "default", + "blend_type": "normal", + "show_transition": { + "duration": 300 + }, + "hide_transition": { + "duration": 300 + }, + "private_settings": {} + }, + { + "name": "Discord", + "source_uuid": "0d7d9693-0a0c-4a52-af3a-1ec742590358", + "visible": true, + "locked": false, + "rot": 0.0, + "scale_ref": { + "x": 2560.0, + "y": 1336.0 + }, + "align": 5, + "bounds_type": 0, + "bounds_align": 0, + "bounds_crop": false, + "crop_left": 0, + "crop_top": 0, + "crop_right": 0, + "crop_bottom": 0, + "id": 10, + "group_item_backup": false, + "pos": { + "x": 0.0, + "y": 0.0 + }, + "pos_rel": { + "x": -1.9161676168441772, + "y": -1.0 + }, + "scale": { + "x": 1.0, + "y": 1.0 + }, + "scale_rel": { + "x": 1.0, + "y": 1.0 + }, + "bounds": { + "x": 0.0, + "y": 0.0 + }, + "bounds_rel": { + "x": 0.0, + "y": 0.0 + }, + "scale_filter": "disable", + "blend_method": "default", + "blend_type": "normal", + "show_transition": { + "duration": 0 + }, + "hide_transition": { + "duration": 0 + }, + "private_settings": {} + } + ] + }, + "mixers": 0, + "sync": 0, + "flags": 0, + "volume": 1.0, + "balance": 0.5, + "enabled": true, + "muted": false, + "push-to-mute": false, + "push-to-mute-delay": 0, + "push-to-talk": false, + "push-to-talk-delay": 0, + "hotkeys": { + "OBSBasic.SelectScene": [], + "libobs.show_scene_item.1": [], + "libobs.hide_scene_item.1": [], + "libobs.show_scene_item.2": [], + "libobs.hide_scene_item.2": [], + "libobs.show_scene_item.3": [], + "libobs.hide_scene_item.3": [], + "libobs.show_scene_item.4": [], + "libobs.hide_scene_item.4": [], + "libobs.show_scene_item.5": [], + "libobs.hide_scene_item.5": [], + "libobs.show_scene_item.6": [], + "libobs.hide_scene_item.6": [], + "libobs.show_scene_item.8": [], + "libobs.hide_scene_item.8": [], + "libobs.show_scene_item.10": [], + "libobs.hide_scene_item.10": [] + }, + "deinterlace_mode": 0, + "deinterlace_field_order": 0, + "monitoring_type": 0, + "canvas_uuid": "6c69626f-6273-4c00-9d88-c5136d61696e", + "private_settings": {} + } + ], + "groups": [ + { + "prev_ver": 536936450, + "name": "STAND BY", + "uuid": "d730eeb6-8969-4265-b033-5f777686ce2d", + "id": "group", + "versioned_id": "group", + "settings": { + "custom_size": true, + "cx": 1633, + "cy": 1233, + "id_counter": 0, + "items": [ + { + "name": "Doomguard Logo", + "source_uuid": "ee77caf1-a490-45fa-80d9-4072f7e63d9a", + "visible": true, + "locked": false, + "rot": 0.0, + "scale_ref": { + "x": 1920.0, + "y": 1080.0 + }, + "align": 5, + "bounds_type": 0, + "bounds_align": 0, + "bounds_crop": false, + "crop_left": 0, + "crop_top": 0, + "crop_right": 0, + "crop_bottom": 0, + "id": 6, + "group_item_backup": false, + "pos": { + "x": 1514.64453125, + "y": 0.0 + }, + "pos_rel": { + "x": 0.35126429796218872, + "y": -1.0 + }, + "scale": { + "x": 0.35290849208831787, + "y": 0.35290849208831787 + }, + "scale_rel": { + "x": 0.28528529405593872, + "y": 0.28528529405593872 + }, + "bounds": { + "x": 0.0, + "y": 0.0 + }, + "bounds_rel": { + "x": 0.0, + "y": 0.0 + }, + "scale_filter": "disable", + "blend_method": "default", + "blend_type": "normal", + "show_transition": { + "duration": 0 + }, + "hide_transition": { + "duration": 0 + }, + "private_settings": {} + }, + { + "name": "Starting Soon", + "source_uuid": "4b902d7f-9205-444c-8c8b-b559479d5bea", + "visible": true, + "locked": false, + "rot": 0.0, + "scale_ref": { + "x": 1920.0, + "y": 1080.0 + }, + "align": 5, + "bounds_type": 0, + "bounds_align": 0, + "bounds_crop": false, + "crop_left": 0, + "crop_top": 0, + "crop_right": 0, + "crop_bottom": 0, + "id": 10, + "group_item_backup": false, + "pos": { + "x": 0.0, + "y": 489.0 + }, + "pos_rel": { + "x": -1.9161676168441772, + "y": -0.26796406507492065 + }, + "scale": { + "x": 2.042553186416626, + "y": 2.0388350486755371 + }, + "scale_rel": { + "x": 1.6511657238006592, + "y": 1.6481600999832153 + }, + "bounds": { + "x": 0.0, + "y": 0.0 + }, + "bounds_rel": { + "x": 0.0, + "y": 0.0 + }, + "scale_filter": "disable", + "blend_method": "default", + "blend_type": "normal", + "show_transition": { + "id": "wipe_transition", + "versioned_id": "wipe_transition", + "name": "Starting Soon Show Transition", + "transition": {}, + "duration": 1000 + }, + "hide_transition": { + "duration": 0 + }, + "private_settings": {} + }, + { + "name": "info", + "source_uuid": "cfcf2652-2777-4b92-a53b-54703f23deff", + "visible": false, + "locked": false, + "rot": 0.0, + "scale_ref": { + "x": 1920.0, + "y": 1080.0 + }, + "align": 5, + "bounds_type": 0, + "bounds_align": 0, + "bounds_crop": false, + "crop_left": 0, + "crop_top": 0, + "crop_right": 0, + "crop_bottom": 0, + "id": 8, + "group_item_backup": false, + "pos": { + "x": 76.0001220703125, + "y": 1193.0 + }, + "pos_rel": { + "x": -1.8023951053619385, + "y": 0.78592813014984131 + }, + "scale": { + "x": 2.5, + "y": 2.5 + }, + "scale_rel": { + "x": 2.0209579467773438, + "y": 2.0209579467773438 + }, + "bounds": { + "x": 0.0, + "y": 0.0 + }, + "bounds_rel": { + "x": 0.0, + "y": 0.0 + }, + "scale_filter": "disable", + "blend_method": "default", + "blend_type": "normal", + "show_transition": { + "duration": 0 + }, + "hide_transition": { + "duration": 0 + }, + "private_settings": {} + } + ] + }, + "mixers": 0, + "sync": 0, + "flags": 0, + "volume": 1.0, + "balance": 0.5, + "enabled": true, + "muted": false, + "push-to-mute": false, + "push-to-mute-delay": 0, + "push-to-talk": false, + "push-to-talk-delay": 0, + "hotkeys": { + "libobs.show_scene_item.6": [], + "libobs.hide_scene_item.6": [], + "libobs.show_scene_item.10": [], + "libobs.hide_scene_item.10": [], + "libobs.show_scene_item.8": [], + "libobs.hide_scene_item.8": [] + }, + "deinterlace_mode": 0, + "deinterlace_field_order": 0, + "monitoring_type": 0, + "canvas_uuid": "6c69626f-6273-4c00-9d88-c5136d61696e", + "private_settings": {} + } + ], + "scene_order": [ + { + "name": "Landing" + }, + { + "name": "Project Loading" + }, + { + "name": "Game" + }, + { + "name": "Desktop" + }, + { + "name": "Desktop (No Cam)" + }, + { + "name": "Music Box" + }, + { + "name": "Good Bye" + } + ], + "current_scene": "Good Bye", + "current_program_scene": "Good Bye", + "canvases": [], + "current_transition": "Luma Wipe", + "transition_duration": 1000, + "transitions": [ + { + "name": "Luma Wipe", + "id": "wipe_transition", + "settings": { + "luma_image": "checkerboard-small.png" + } + } + ], + "quick_transitions": [ + { + "name": "Cut", + "duration": 300, + "hotkeys": [], + "id": 1, + "fade_to_black": false + }, + { + "name": "Fade", + "duration": 300, + "hotkeys": [], + "id": 2, + "fade_to_black": false + } + ], + "saved_projectors": [], + "preview_locked": false, + "scaling_enabled": false, + "scaling_level": -14, + "scaling_off_x": 0.0, + "scaling_off_y": 0.0, + "modules": { + "scripts-tool": [], + "output-timer": { + "streamTimerHours": 0, + "streamTimerMinutes": 0, + "streamTimerSeconds": 30, + "recordTimerHours": 0, + "recordTimerMinutes": 0, + "recordTimerSeconds": 30, + "autoStartStreamTimer": false, + "autoStartRecordTimer": false, + "pauseRecordTimer": false + }, + "auto-scene-switcher": { + "interval": 300, + "non_matching_scene": "Nuclear", + "switch_if_not_matching": true, + "active": false, + "switches": [ + { + "scene": "Game", + "window_title": "Heroes of Might and Magic III: Horn of the Abyss" + } + ] + } + }, + "resolution": { + "x": 2560, + "y": 1336 + }, + "migration_resolution": { + "x": 1920, + "y": 1080 + }, + "version": 2 +} \ No newline at end of file diff --git a/scripts/obs-webapp.supervisord.conf b/scripts/obs-webapp.supervisord.conf new file mode 100644 index 0000000..cbdaa4d --- /dev/null +++ b/scripts/obs-webapp.supervisord.conf @@ -0,0 +1,31 @@ +; supervisord program file for the OPHI-118 scene overlay webapp. +; +; Listens on 127.0.0.1:1118 (CH 118.0 in the overlay lore, easy to remember). +; +; Install: +; sudo install -m 644 scripts/obs-webapp.supervisord.conf /etc/supervisor.d/obs-webapp.conf +; sudo supervisorctl reread && sudo supervisorctl update +; +; Restart after config / route / env changes: +; sudo supervisorctl restart obs-webapp +; +; Logs: +; tail -F webapp/storage/logs/supervisord.{out,err}.log + +[program:obs-webapp] +command=/usr/bin/php artisan serve --host=127.0.0.1 --port=1118 +directory=/home/jin/.config/obs-studio/webapp +user=jin +environment=HOME="/home/jin",USER="jin",PATH="/usr/local/sbin:/usr/local/bin:/usr/bin" +autostart=true +autorestart=true +startsecs=2 +startretries=3 +stopwaitsecs=10 +stopsignal=TERM +stdout_logfile=/home/jin/.config/obs-studio/webapp/storage/logs/supervisord.out.log +stderr_logfile=/home/jin/.config/obs-studio/webapp/storage/logs/supervisord.err.log +stdout_logfile_maxbytes=10MB +stdout_logfile_backups=3 +stderr_logfile_maxbytes=10MB +stderr_logfile_backups=3 diff --git a/scripts/rewrite-scene-urls.py b/scripts/rewrite-scene-urls.py new file mode 100755 index 0000000..0215ee9 --- /dev/null +++ b/scripts/rewrite-scene-urls.py @@ -0,0 +1,82 @@ +#!/usr/bin/env python3 +"""Rewrite OBS browser_source URLs in a scene-collection JSON from `file://` to +`http://127.0.0.1:1118/`. + +Usage: + python3 scripts/rewrite-scene-urls.py basic/scenes/Default_Stream_HUD.json + +Idempotent: runs against a partially-converted file are no-ops. + +Also moves the landing/static-hum.wav ffmpeg_source path to its new home under +webapp/public/audio/. + +OBS MUST be closed when this runs — OBS rewrites scene files on exit. +""" +import json +import re +import sys + + +BROWSER_MAPPING = { + 'landing/index.html': 'http://127.0.0.1:1118/landing', + 'loading/index.html': 'http://127.0.0.1:1118/loading', + 'game/index.html': 'http://127.0.0.1:1118/game', + 'desktop/index.html': 'http://127.0.0.1:1118/desktop', + 'goodbye/index.html': 'http://127.0.0.1:1118/goodbye', + 'music/index.html': 'http://127.0.0.1:1118/music-daemon', + 'music-box/index.html': 'http://127.0.0.1:1118/music-box', + 'music-box/widget.html': 'http://127.0.0.1:1118/music-box/widget', + 'music-box/cover.html': 'http://127.0.0.1:1118/music-box/cover', + 'music-box/nc-music-box.html': 'http://127.0.0.1:1118/music-box/nc', +} + +AUDIO_OLD = 'landing/static-hum.wav' +AUDIO_NEW = 'webapp/public/audio/static-hum.wav' + + +def rewrite_browser_source(src): + s = src.get('settings', {}) + for old, new in BROWSER_MAPPING.items(): + for k in ('url', 'local_file'): + v = s.get(k, '') + if old in v: + # Preserve query strings (e.g. ?bars=0). + m = re.search(r'\?[^"\s]*$', v) + qs = m.group(0) if m else '' + s['url'] = new + qs + s.pop('local_file', None) + s['is_local_file'] = False + return True + return False + + +def rewrite_audio_source(src): + s = src.get('settings', {}) + lf = s.get('local_file', '') + if lf.endswith(AUDIO_OLD): + s['local_file'] = lf.replace(AUDIO_OLD, AUDIO_NEW) + return True + return False + + +def main(): + if len(sys.argv) != 2: + print(__doc__, file=sys.stderr) + return 2 + path = sys.argv[1] + doc = json.load(open(path)) + rewrites = 0 + for src in doc.get('sources', []): + sid = src.get('id', '') + if sid == 'browser_source': + if rewrite_browser_source(src): + rewrites += 1 + elif sid == 'ffmpeg_source': + if rewrite_audio_source(src): + rewrites += 1 + json.dump(doc, open(path, 'w'), indent=4, ensure_ascii=False) + print(f'wrote {path} ({rewrites} sources rewritten)') + + +if __name__ == '__main__': + sys.exit(main() or 0) diff --git a/webapp/.editorconfig b/webapp/.editorconfig new file mode 100644 index 0000000..6df8428 --- /dev/null +++ b/webapp/.editorconfig @@ -0,0 +1,18 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +indent_size = 4 +indent_style = space +insert_final_newline = true +trim_trailing_whitespace = true + +[*.md] +trim_trailing_whitespace = false + +[*.{yml,yaml}] +indent_size = 2 + +[{compose,docker-compose}.{yml,yaml}] +indent_size = 4 diff --git a/webapp/.gitattributes b/webapp/.gitattributes new file mode 100644 index 0000000..fcb21d3 --- /dev/null +++ b/webapp/.gitattributes @@ -0,0 +1,11 @@ +* text=auto eol=lf + +*.blade.php diff=html +*.css diff=css +*.html diff=html +*.md diff=markdown +*.php diff=php + +/.github export-ignore +CHANGELOG.md export-ignore +.styleci.yml export-ignore diff --git a/webapp/.gitignore b/webapp/.gitignore new file mode 100644 index 0000000..7be55e2 --- /dev/null +++ b/webapp/.gitignore @@ -0,0 +1,27 @@ +*.log +.DS_Store +.env +.env.backup +.env.production +.phpactor.json +.phpunit.result.cache +/.codex +/.cursor/ +/.idea +/.nova +/.phpunit.cache +/.vscode +/.zed +/auth.json +/node_modules +/public/build +/public/fonts-manifest.dev.json +/public/hot +/public/storage +/storage/*.key +/storage/pail +/vendor +_ide_helper.php +Homestead.json +Homestead.yaml +Thumbs.db diff --git a/webapp/README.md b/webapp/README.md new file mode 100644 index 0000000..5ad1377 --- /dev/null +++ b/webapp/README.md @@ -0,0 +1,58 @@ +

Laravel Logo

+ +

+Build Status +Total Downloads +Latest Stable Version +License +

+ +## About Laravel + +Laravel is a web application framework with expressive, elegant syntax. We believe development must be an enjoyable and creative experience to be truly fulfilling. Laravel takes the pain out of development by easing common tasks used in many web projects, such as: + +- [Simple, fast routing engine](https://laravel.com/docs/routing). +- [Powerful dependency injection container](https://laravel.com/docs/container). +- Multiple back-ends for [session](https://laravel.com/docs/session) and [cache](https://laravel.com/docs/cache) storage. +- Expressive, intuitive [database ORM](https://laravel.com/docs/eloquent). +- Database agnostic [schema migrations](https://laravel.com/docs/migrations). +- [Robust background job processing](https://laravel.com/docs/queues). +- [Real-time event broadcasting](https://laravel.com/docs/broadcasting). + +Laravel is accessible, powerful, and provides tools required for large, robust applications. + +## Learning Laravel + +Laravel has the most extensive and thorough [documentation](https://laravel.com/docs) and video tutorial library of all modern web application frameworks, making it a breeze to get started with the framework. + +In addition, [Laracasts](https://laracasts.com) contains thousands of video tutorials on a range of topics including Laravel, modern PHP, unit testing, and JavaScript. Boost your skills by digging into our comprehensive video library. + +You can also watch bite-sized lessons with real-world projects on [Laravel Learn](https://laravel.com/learn), where you will be guided through building a Laravel application from scratch while learning PHP fundamentals. + +## Agentic Development + +Laravel's predictable structure and conventions make it ideal for AI coding agents like Claude Code, Cursor, and GitHub Copilot. Install [Laravel Boost](https://laravel.com/docs/ai) to supercharge your AI workflow: + +```bash +composer require laravel/boost --dev + +php artisan boost:install +``` + +Boost provides your agent 15+ tools and skills that help agents build Laravel applications while following best practices. + +## Contributing + +Thank you for considering contributing to the Laravel framework! The contribution guide can be found in the [Laravel documentation](https://laravel.com/docs/contributions). + +## Code of Conduct + +In order to ensure that the Laravel community is welcoming to all, please review and abide by the [Code of Conduct](https://laravel.com/docs/contributions#code-of-conduct). + +## Security Vulnerabilities + +If you discover a security vulnerability within Laravel, please send an e-mail to Taylor Otwell via [taylor@laravel.com](mailto:taylor@laravel.com). All security vulnerabilities will be promptly addressed. + +## License + +The Laravel framework is open-sourced software licensed under the [MIT license](https://opensource.org/licenses/MIT). diff --git a/webapp/app/Console/Commands/RigCmdCommand.php b/webapp/app/Console/Commands/RigCmdCommand.php new file mode 100644 index 0000000..a5e672c --- /dev/null +++ b/webapp/app/Console/Commands/RigCmdCommand.php @@ -0,0 +1,30 @@ +argument('type')); + if (!in_array($type, ['skip', 'prev', 'pause', 'resume'], true)) { + $this->error('type must be one of: skip, prev, pause, resume'); + return self::FAILURE; + } + try { + $ws->broadcast('mpd:cmd', ['type' => $type]); + } catch (Throwable $e) { + $this->error($e->getMessage()); + return self::FAILURE; + } + $this->info(" → {$type}"); + return self::SUCCESS; + } +} diff --git a/webapp/app/Console/Commands/RigLoadingCommand.php b/webapp/app/Console/Commands/RigLoadingCommand.php new file mode 100644 index 0000000..83b001c --- /dev/null +++ b/webapp/app/Console/Commands/RigLoadingCommand.php @@ -0,0 +1,101 @@ +loading(); + + $this->line('── Project Loading manifest ──'); + $this->line(' (press Enter to keep [defaults])'); + $this->line(''); + + $game = null; + $gameId = null; + $defaultGame = (string) ($prev['game'] ?? ''); + while (true) { + $query = (string) $this->ask('Game (search)', $defaultGame ?: null); + if ($query === '') { + $this->error(' ✗ Game is required'); + continue; + } + if ($twitch->enabled()) { + $cachedId = (string) ($prev['gameId'] ?? ''); + if ($query === $defaultGame && preg_match('/^\d+$/', $cachedId)) { + $game = $defaultGame; + $gameId = $cachedId; + $this->line(" ↻ reusing cached: {$game} (id={$gameId})"); + break; + } + try { + $hit = $twitch->searchCategory($query); + } catch (Throwable $e) { + $this->warn(' ! Twitch search failed: ' . $e->getMessage()); + if ($this->confirm('Use the raw input without resolving an id?', true)) { + $game = $query; + break; + } + continue; + } + if ($hit === null) { + $this->warn(' ! no Twitch matches for "' . $query . '"'); + continue; + } + $game = $hit['name']; + $gameId = $hit['id']; + $this->line(" ↳ matched: {$game} (id={$gameId})"); + break; + } + $game = $query; + break; + } + + $subtitle = (string) $this->ask('Subtitle (mode / episode / note)', $prev['subtitle'] ?? null); + $countdown = (int) $this->ask('Countdown (minutes)', (string) ($prev['countdownMin'] ?? 5)); + $camera = $this->confirm('Camera', (bool) ($prev['camera'] ?? true)); + $microphone = $this->confirm('Microphone', (bool) ($prev['microphone'] ?? true)); + + $data = [ + 'compiledAt' => gmdate('Y-m-d\TH:i:s\Z'), + 'game' => $game, + 'gameId' => $gameId, + 'subtitle' => $subtitle ?: null, + 'countdownMin' => $countdown, + 'camera' => $camera, + 'microphone' => $microphone, + ]; + $path = rtrim(config('rig.storage_data'), '/') . '/loading.json'; + @mkdir(dirname($path), 0775, true); + file_put_contents( + $path, + json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) . "\n" + ); + $this->info(''); + $this->info(" ✓ wrote {$path}"); + + // Push to Twitch — soft-fail so a network blip doesn't block the local manifest. + if (!$this->option('no-twitch') && $twitch->enabled() && $gameId) { + $title = $subtitle ?: $game; + try { + $twitch->setChannel($title, $gameId); + $this->info(" ✓ Twitch channel updated → \"{$title}\" / category {$game}"); + } catch (Throwable $e) { + $this->warn(' ! Twitch sync failed (manifest still saved): ' . $e->getMessage()); + } + } + + $this->line(''); + $this->line(' → refresh the Project Loading browser source in OBS.'); + return self::SUCCESS; + } +} diff --git a/webapp/app/Console/Commands/RigPlaylistCommand.php b/webapp/app/Console/Commands/RigPlaylistCommand.php new file mode 100644 index 0000000..1add435 --- /dev/null +++ b/webapp/app/Console/Commands/RigPlaylistCommand.php @@ -0,0 +1,125 @@ +warn(' ! no music dirs configured (set MUSIC_DIR_1 in .env)'); + } + + $ffprobe = (string) config('rig.ffprobe', '/usr/bin/ffprobe'); + if (!is_executable($ffprobe)) { + $this->error(" ✗ ffprobe not found at {$ffprobe} (install ffmpeg or set FFPROBE_BIN)"); + return self::FAILURE; + } + + $this->line('── Indexing audio roots ──'); + foreach ($roots as $r) { + $this->line(is_dir($r) ? " + {$r}" : " ! {$r} (missing — skipped)"); + } + + $tracks = []; + foreach ($roots as $root) { + if (!is_dir($root)) continue; + $finder = (new Finder()) + ->files() + ->in($root) + ->name('/\.(' . implode('|', self::EXTS) . ')$/i') + ->ignoreUnreadableDirs() + ->sortByName(); + + foreach ($finder as $file) { + $name = $file->getFilename(); + $base = $file->getFilenameWithoutExtension(); + // Skip yt-dlp intermediates (e.g. foo.f140.m4a, foo.temp.opus). + if (preg_match('/\.(?:f\d+|temp|part)$/i', $base)) continue; + + $path = $file->getRealPath(); + $meta = $this->probe($ffprobe, $path); + $tracks[] = [ + 'title' => $this->cleanTitle($base), + 'file' => 'file://' . $this->urlEncodePath($path), + 'durationSec' => isset($meta['durationSec']) ? (int) $meta['durationSec'] : null, + ]; + } + } + + $doc = [ + 'syncedAt' => gmdate('Y-m-d\TH:i:s\Z'), + 'sourceDirs' => $roots, + 'trackCount' => count($tracks), + 'tracks' => $tracks, + ]; + $path = rtrim(config('rig.storage_data'), '/') . '/playlist.json'; + @mkdir(dirname($path), 0775, true); + file_put_contents( + $path, + json_encode($doc, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) + ); + + $this->line(''); + $this->info(" ✓ wrote {$path} ({$doc['trackCount']} tracks)"); + $this->line(' → refresh the Music Daemon browser source in OBS to reload the queue.'); + return self::SUCCESS; + } + + private function probe(string $ffprobe, string $path): array + { + try { + $proc = new Process([ + $ffprobe, '-v', 'error', + '-show_entries', 'format=duration:format_tags=title,artist', + '-of', 'json', + $path, + ]); + $proc->setTimeout(10); + $proc->run(); + if (!$proc->isSuccessful()) return []; + $json = json_decode($proc->getOutput(), true) ?: []; + $fmt = $json['format'] ?? []; + return [ + 'durationSec' => isset($fmt['duration']) ? (float) $fmt['duration'] : null, + ]; + } catch (Throwable) { + return []; + } + } + + /** + * Mirrors scripts/playlist.sh's clean_title(): + * - drop "| ..." (or fullwidth |) tails (genre/label noise) + * - strip trailing YouTube IDs in brackets like "[-XxZTgMWKV0]" + * - strip "[NCS Release]" / "(NCS10 Release)" suffixes + */ + private function cleanTitle(string $t): string + { + $t = preg_replace('/\s*[||].*$/u', '', $t) ?? $t; + $t = preg_replace('/\s*\[[A-Za-z0-9_-]{11}\]\s*$/', '', $t) ?? $t; + $t = preg_replace( + '/\s*[\[(](?:NCS\d*|No Copyright Sounds)(?:\s+Release)?[\])]\s*$/i', + '', + $t + ) ?? $t; + return trim($t); + } + + private function urlEncodePath(string $path): string + { + // Same as Python's urllib.parse.quote(..., safe='/') — keep separators, encode the rest. + return implode('/', array_map('rawurlencode', explode('/', $path))); + } +} diff --git a/webapp/app/Console/Commands/RigSetupCommand.php b/webapp/app/Console/Commands/RigSetupCommand.php new file mode 100644 index 0000000..433f123 --- /dev/null +++ b/webapp/app/Console/Commands/RigSetupCommand.php @@ -0,0 +1,84 @@ +error(" ✗ {$src} not found."); + $this->line(' Open OBS once with obs-websocket loaded so it generates the config.'); + return self::FAILURE; + } + $cfg = json_decode((string) file_get_contents($src), true); + if (!is_array($cfg)) { + $this->error(" ✗ {$src} did not parse as JSON."); + return self::FAILURE; + } + $port = (int) ($cfg['server_port'] ?? 4455); + $pass = (string) ($cfg['server_password'] ?? ''); + $url = "ws://localhost:{$port}"; + + $out = (string) config('rig.obs_config_js'); + @mkdir(dirname($out), 0775, true); + $js = <<jsString($url)}, + password: {$this->jsString($pass)}, +}; + +JS; + file_put_contents($out, $js); + $this->info(" ✓ wrote {$out}"); + + // Mirror into .env so MusicCommandController / ObsWsClient can authenticate. + $this->writeEnv('OBS_WS_URL', $url); + $this->writeEnv('OBS_WS_PASSWORD', $pass); + $this->info(' ✓ updated .env OBS_WS_URL / OBS_WS_PASSWORD'); + + $this->line(''); + $this->line(" url = {$url}"); + $this->line(' password = ' . ($pass === '' ? '(none)' : '(set, ' . strlen($pass) . ' chars)')); + $this->line(''); + $this->line(' → if obs-webapp is running under supervisord, restart it so the new env takes effect:'); + $this->line(' sudo supervisorctl restart obs-webapp'); + + return self::SUCCESS; + } + + private function jsString(string $s): string + { + return json_encode($s, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE); + } + + private function writeEnv(string $key, string $value): void + { + $env = base_path('.env'); + $raw = is_file($env) ? file_get_contents($env) : ''; + $line = $key . '=' . $this->escapeEnvValue($value); + if (preg_match("/^{$key}=.*$/m", $raw)) { + $raw = preg_replace("/^{$key}=.*$/m", $line, $raw); + } else { + $raw = rtrim($raw, "\n") . "\n" . $line . "\n"; + } + file_put_contents($env, $raw); + } + + private function escapeEnvValue(string $v): string + { + if ($v === '') return ''; + if (preg_match('/[\s"#=]/', $v)) { + return '"' . str_replace('"', '\"', $v) . '"'; + } + return $v; + } +} diff --git a/webapp/app/Console/Commands/RigTelemetryCommand.php b/webapp/app/Console/Commands/RigTelemetryCommand.php new file mode 100644 index 0000000..3183619 --- /dev/null +++ b/webapp/app/Console/Commands/RigTelemetryCommand.php @@ -0,0 +1,42 @@ +option('collect') || !is_file($path)) { + $data = $snap->collect(); + @mkdir(dirname($path), 0775, true); + file_put_contents( + $path, + json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) . "\n" + ); + $this->info(" ✓ wrote {$path}"); + } else { + $this->line(" · {$path} already exists — use --collect to re-read hardware."); + } + + $current = $rig->telemetry(); + $this->line(''); + $this->line(" rig = " . ($current['rig'] ?? '?')); + $this->line(" cpu = " . ($current['cpu']['model'] ?? '?')); + if (!empty($current['gpu']['name'])) { + $this->line(" gpu = " . $current['gpu']['name']); + } + if (!empty($current['obs']['output']['w'])) { + $this->line(" output = {$current['obs']['output']['w']}×{$current['obs']['output']['h']} @ {$current['obs']['fps']} fps"); + } + return self::SUCCESS; + } +} diff --git a/webapp/app/Http/Controllers/AudioController.php b/webapp/app/Http/Controllers/AudioController.php new file mode 100644 index 0000000..3a94d6f --- /dev/null +++ b/webapp/app/Http/Controllers/AudioController.php @@ -0,0 +1,71 @@ +query('p', ''); + if ($b64 === '') abort(400, 'missing p'); + + // URL-safe base64; pad back to a multiple of 4 for strict decoding. + $padded = $b64 . str_repeat('=', (4 - strlen($b64) % 4) % 4); + $path = base64_decode(strtr($padded, '-_', '+/'), true); + if ($path === false || $path === '') abort(400, 'bad encoding'); + + $real = realpath($path); + if ($real === false || !is_file($real)) abort(404, 'file not found: ' . $path); + + $allowed = false; + foreach ((array) config('rig.music_dirs') as $root) { + $rootReal = realpath($root); + if ($rootReal && str_starts_with($real . '/', rtrim($rootReal, '/') . '/')) { + $allowed = true; + break; + } + } + if (!$allowed) abort(403, 'outside allowed roots'); + + $ext = strtolower(pathinfo($real, PATHINFO_EXTENSION)); + $mime = match ($ext) { + 'm4a', 'aac' => 'audio/mp4', + 'mp3' => 'audio/mpeg', + 'opus', 'ogg'=> 'audio/ogg', + 'flac' => 'audio/flac', + 'webm' => 'audio/webm', + 'wav' => 'audio/wav', + default => 'application/octet-stream', + }; + + // BinaryFileResponse handles Range requests automatically, which the + // HTML5