/upload stored files under the client-supplied filename (allowing .php
webshells and ../ traversal) and analyse_m3u_file renamed files from
unvalidated filename/id_playlist. Uploads are now always stored as
upload_<uuid>.m3u, id_playlist must be a UUID, and paths go through
safe_join.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Lower the default and minimum snapshot interval (10s/2s -> 2s/1s) and
refresh the selected device's thumbnail on its own 1s timer instead of
waiting for the 5s device-list poll, so the preview updates fast
enough to feel close to live video without building an actual
streaming pipeline.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Each channel already carries a Topic field, but search results only
showed the name and logo. Render it as a small badge in both the
list and grid views when present.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The search box only worked via mouse click on the Search button (no
keypress handler), and a search returning zero matches or failing
silently left the previous results or an empty panel with no
feedback. Add Enter-key submission and show a spinner while
searching, "No channels found" on empty results, and an error
message on request failure. Also fixes a dead '#list_channels'
selector (the actual container is '#listChannels') that silently
did nothing.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The settings endpoint returned the raw key to any caller, and the
frontend used that response to pre-fill the input field, which also
meant saving with an untouched field would silently resubmit the
plaintext key. /gemini_key now reports only whether a key is set and
a masked preview; the UI shows that as a placeholder and only updates
the stored key when the field is actually filled in.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
IPTV.py now writes logs to a rotating file and forwards critical VLC
playback errors (start timeout, MediaPlayerEncounteredError) to the
server instead of losing everything to unredirected print() calls.
The web UI's device menu gets a working Terminal (to run diagnostic
commands like tail on the log) and a Recent errors view backed by a
capped last_errors list on each device document, keeping DB volume
bounded to the last 5 entries per device.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>