Commit Graph

25 Commits

Author SHA1 Message Date
ComputerTech 20e56f37b8 Fix Qt client music not playing on listener page
Replace PulseAudio monitor capture with direct file streaming.
Qt6's FFmpeg/PipeWire-native audio backend ignores PULSE_SINK so
the monitor captured silence. StreamingWorker now receives the
playing file path via a command queue and pipes it through ffmpeg
-re (real-time rate) directly to the server as audio_chunk events.

- Add switch_file() / stop_file() to StreamingWorker
- Replace ffmpeg pulse capture loop with file-based cmd loop
- DeckWidget.play() calls switch_file(path, position_ms)
- DeckWidget.pause()/stop() calls stop_file()
- Add now_playing socket relay in server.py
- listener.js handles now_playing event to show track title
- Add deck_glow emission from Qt deck play/pause/stop
2026-04-03 14:18:28 +01:00
ComputerTech 46128f5c58 fix: use listener port (no auth) for server library fetch and track downloads
Previously, fetch_server_library() and populate_server_library() used
get_server_base_url() which resolves to the DJ panel port (5000). When
dj_panel_password is set, ALL routes on port 5000 require an authenticated
session cookie. The Qt client had no cookie, so every library.json request
was redirected to /login (HTML), json.loads() failed, and the server list
stayed empty.

Fix:
- Add get_listener_base_url() that derives the listener port (DJ port + 1,
  default 5001) from the configured stream_server_url
- fetch_server_library() now fetches /library.json from the listener port
- Track download URLs built in populate_server_library() now point to the
  listener port's /music_proxy/ route — both are auth-free on the listener
  server (port 5001)
- upload_track() still correctly POSTs to the DJ port (5000) since the
  listener server blocks /upload; it now also authenticates with the DJ
  panel cookie before uploading so uploads work with a password too
2026-04-03 13:47:47 +01:00
ComputerTech eb3e66ba61 Implement Duplicate Upload Prevention
- Server: /upload rejects existing files with 409 Conflict
- Web: handleFileUpload skips duplicates with toast feedback
- Qt: upload_track blocks duplicate imports and uploads with dialog alert
2026-03-12 19:12:07 +00:00
ComputerTech 6027f2e973 Fix streaming: bypass ffmpeg for MP3 input, fix PyQt latency, fix routing bugs
- server.py: Add _distribute_mp3() to route MP3 chunks directly to listener
  queues without a second ffmpeg passthrough (halves pipeline latency, removes
  the eventlet/subprocess blocking read that caused the Qt client to fail)
- server.py: dj_start no longer starts ffmpeg for is_mp3_input=True
- server.py: dj_audio routes to _distribute_mp3 vs _feed_transcoder based on format
- server.py: _transcoder_watchdog skips MP3-direct mode
- server.py: stream_mp3 endpoint no longer waits for ffmpeg proc when MP3 direct
- techdj_qt.py: Add -fflags nobuffer + -flush_packets 1 to reduce source latency
- techdj_qt.py: bufsize=0 and read(4096) instead of read(8192) for ~260ms chunks
- listener.js: Reduce broadcast_started connect delay 800ms -> 300ms
2026-03-10 19:54:06 +00:00
ComputerTech dfccec2b48 Stability fixes: loop end-of-track guard, DJ disconnect grace period, StreamingWorker race condition fix, various audit cleanups 2026-03-10 18:53:17 +00:00
ComputerTech 8c3c2613b1 Fix broadcast broken: reconnect loop, listener stuck on waiting
- server.py: Increase ping_timeout 10->60, ping_interval 5->25 to prevent
  frequent socket disconnects during audio streaming
- server.py: Guard dj_start() against reconnect loops - only clear pre-roll
  and emit broadcast_started on a fresh broadcast, not on DJ reconnects
- listener.js: Add polling fallback to transports (websocket-only caused
  silent failure on upgrade error), set reconnectionAttempts to Infinity
- script.js: Same transport fallback fix for DJ panel socket
- techdj_qt.py: Add _broadcast_started flag to StreamingWorker.on_connect
  so streaming_started signal only fires once; reconnects resume silently.
  Reset flag in stop_streaming() for clean next session.
2026-03-09 20:47:52 +00:00
ComputerTech 5ba5c45e64 Fix: audio isolation via PULSE_SINK env var before QApplication
- Replace fragile PID-based PulseAudioIsolator class with module-level
  PULSE_SINK approach: create virtual null sink BEFORE QApplication()
  so Qt routes all audio there automatically
- Add verification that the monitor source actually exists before trusting it
- Add clear startup diagnostics (✓ confirmations for each step)
- get_audio_capture_source() now double-checks monitor still exists
- Fails loudly instead of silently falling back to default.monitor
- Remove threading import (no longer needed)
- Add atexit cleanup for virtual sink teardown
2026-03-09 20:26:36 +00:00
ComputerTech cddce99b29 Fix: isolate DJ audio from system audio in streaming/recording
The Qt app was using PulseAudio's 'default.monitor' which captures ALL
system audio (YouTube Music, Spotify, browser, etc.). This caused listeners
to hear whatever was playing on the DJ's system, not just the DJ mix.

Added PulseAudioIsolator class that:
- Creates a virtual PulseAudio null sink ('techdj_stream')
- Routes only this app's audio to the virtual sink
- Creates a loopback so the DJ still hears their mix through speakers
- Captures from the virtual sink's monitor (only DJ audio)
- Reference-counted: shared between streaming and recording workers
- Automatically cleans up stale sinks from previous crashes
- Periodically re-routes audio to catch new tracks/streams
- Falls back to default.monitor if pactl is unavailable

Both StreamingWorker and RecordingWorker now use the isolator.
2026-03-09 19:45:43 +00:00
ComputerTech abf907ddfb Fix 6 bugs: remove dead listener code from DJ panel, fix StreamingWorker socket reuse, fix GUI-blocking time.sleep, fix abort import
- script.js: Remove ~500 lines of dead listener mode code (initListenerMode, enableListenerAudio, setListenerVolume, startListenerVUMeter, getMp3FallbackUrl, listener variables). Listener page now uses listener.js exclusively.
- script.js: Remove ?listen=true detection from DOMContentLoaded that could activate broken listener UI on DJ panel.
- script.js: Clean up initSocket() to remove dead listener mode detection logic.
- index.html: Remove dead #listener-mode div (now served by listener.html).
- server.py: Move 'abort' import to top-level Flask import instead of per-request import.
- techdj_qt.py: Fix StreamingWorker to create fresh socketio.Client on each streaming session, preventing stale socket state on reconnect.
- techdj_qt.py: Fix time.sleep(0.2) blocking GUI thread in stop_streaming() by removing it and using try/except for clean disconnect.
2026-03-09 19:16:42 +00:00
ComputerTech df283498eb Add config.json system; fix bugs across server.py, script.js, techdj_qt.py
- Add config.example.json with all options: host, dj_port, listener_port,
  dj_panel_password, secret_key, music_folder, stream_bitrate, max_upload_mb,
  cors_origins, debug (copy to config.json to use)
- server.py: drive host/ports/secrets/CORS/upload limit from config.json;
  fix serve_static to use allowlist only; move re import to top-level;
  fix inconsistent indentation in login/logout/before_request handlers
- script.js: fix undefined decks.crossfader in updateUIFromMixerStatus;
  declare mediaRecorder as a proper let variable
- techdj_qt.py: replace blocking time.sleep poll in YTDownloadWorker with
  non-blocking QTimer; fix fragile or-chained lambda in recording reset
2026-03-09 18:02:47 +00:00
ComputerTech b5ea9e8d01 Final bug sweep: fix event param, remove dead code, dedupe CSS; add .gitignore recordings/ 2026-03-05 14:28:17 +00:00
ComputerTech 12c01faa83 feat: add integrated deck queues and track loop functionality 2026-02-07 20:14:04 +00:00
ComputerTech c2085291c0 hm 2026-01-20 20:04:39 +00:00
ComputerTech 02f72e2372 Fix buffering issue and app bugs: improve stream delivery, fixed reset UI desync, and EQ naming 2026-01-20 18:14:50 +00:00
ComputerTech 1776f631ef Fix filter sliders - connect low-pass and high-pass to audio engine 2026-01-20 18:05:50 +00:00
ComputerTech 740fa34f93 Make deck header more compact with smaller fonts and tighter spacing 2026-01-20 18:01:45 +00:00
ComputerTech de973b2a0e Add loop/repeat and queue features for both decks 2026-01-20 17:57:19 +00:00
ComputerTech ee26294106 Fix critical bugs: broadcast thread, resource cleanup, and Socket.IO error handling 2026-01-20 17:49:00 +00:00
ComputerTech d7a11c2af2 Add window icon to PyQt5 application 2026-01-20 17:30:56 +00:00
ComputerTech c9fc389d94 Fix reset button crash by removing non-existent slider references 2026-01-20 17:10:13 +00:00
ComputerTech 410ecae3dd Implement reset button functionality for deck controls 2026-01-20 17:08:35 +00:00
ComputerTech 06beed2110 Add detailed error logging and timeout to remote track downloads 2026-01-20 17:05:24 +00:00
ComputerTech bd87eb719d Fix Socket.IO connection with enhanced error handling and remote server detection in launch script 2026-01-20 17:01:37 +00:00
ComputerTech 6fc538336a Add remote server support with configurable ports and auto-refresh settings UI 2026-01-20 16:57:01 +00:00
ComputerTech 1606a3a83c Implement native PyQt5 DJ app with ultra-low latency broadcasting and stability fixes 2026-01-19 14:27:06 +00:00