Commit Graph
17 Commits
Author SHA1 Message Date
ubuntuandClaude Opus 5.5 ad82a96440 Stream M3U playlists line by line during analysis
readlines() loaded whole playlists into memory; a 336 MB file needs
roughly 500-600 MB of RAM on a VPS with ~800 MB available.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 00:03:12 +00:00
ubuntuandClaude Opus 5.5 4fa53e7a64 Add per-playlist max connections and viewing quota alerts
Each playlist gets a max_connections setting (default 1), editable in the
playlist modal without re-importing. Active viewings are tracked in the
shared db_iptv.viewings collection (also used by serverIPTV_2): devices
are counted from 'on'/'off' commands and their 10 s polling. When
starting a channel pushes a playlist above its limit, the web UI shows a
quota alert. The playlist list shows active/max connections.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 02:02:10 +00:00
ubuntuandClaude Opus 5.5 16e979fe77 Fix arbitrary file write in /upload and /analyse_m3u_file
/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>
2026-10-15 11:54:14 +00:00
ubuntuandClaude Sonnet 5 4e596114c1 Rank channel search results by relevance, run search off the event loop
list_channel previously matched every playlist with one unranked
".*keyword.*" regex, so a specific channel name could be buried pages
behind unrelated names that merely contained the keyword mid-word.
Split matches into two tiers (word-boundary match first, then
anywhere-else) using a cheap count+skip/limit per tier so pagination
still avoids pulling every match into memory.

Also found while testing against a 1.19M-channel playlist: searching
scans an unindexed regex and can take several seconds, and it was
running synchronously inside the async handler, freezing every other
request/socket for that whole time. Moved it to run_in_executor;
verified a concurrent request now returns in ~2ms while a 3.6s search
is in flight.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-31 01:33:27 +00:00
ubuntuandClaude Sonnet 5 2eaa0fee64 Remove dead code and tighten error handling
- Drop analyse_m3u_file2: an unrouted, unused ~90%-duplicate of
  analyse_m3u_file (a bug fixed in one would never apply to the other).
- Drop the in-memory `devices` list from polling/list_devices: it was
  only ever written to, never read (list_devices already returns from
  devices_db, the real source of truth).
- Remove the resulting unused NUM_MAX_CHANNEL variable and duplicate
  `from pymongo import MongoClient` import.
- Narrow a bare `except:` to `except KeyError:` so it can't also
  swallow SystemExit/KeyboardInterrupt.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-30 23:36:07 +00:00
ubuntuandClaude Sonnet 5 3eff9519db Stop Xtream imports from freezing the server while fetching from the provider
run_xtream_import made 6 sequential synchronous requests.get() calls
(60s timeout each) directly inside an asyncio task, so the whole
event loop — and every other request/socket the server was handling
— stalled for the full duration of each Xtream import, same failure
mode as the logo-download freeze fixed earlier. Run them through
run_in_executor instead so the loop stays free.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-30 23:35:57 +00:00
ubuntuandClaude Sonnet 5 0fa98c7283 Read the client IP from X-Real-IP behind the nginx reverse proxy
Since TLS termination moved to nginx, aiohttp's request.remote is
nginx's own address on the docker network (172.21.0.1), a private IP
that resolve_ip_country() correctly refuses to geolocate. Nginx
already forwards the real client address via X-Real-IP
(iptv.mrk.ovh.conf); read that first so device IP/country tracking
works again.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-30 23:29:10 +00:00
ubuntuandClaude Sonnet 5 6881839e31 Fix crashing /init_db and remove dead proxy_image handler
/init_db dropped the channels/playlists collections then crashed on
an undefined `res` variable, so the "Reset DB" button in the UI
always surfaced a 500 even though the wipe had already happened.
proxy_image used aiohttp.ClientSession without importing aiohttp and
was never routed or called from the frontend, so it's just removed.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-30 23:29:04 +00:00
ubuntuandClaude Sonnet 5 55cefe47f4 Fix path traversal in file-serving and file-writing endpoints
playlist_download, download_epg, upload_snapshot, and get_logo all
built filesystem paths by concatenating a caller-supplied string
(filename/id_channel/id_device) with no validation, so a '../'
payload could read or write files outside the intended directory.
upload_snapshot was the most exploitable: fully attacker-controlled
bytes written to an attacker-chosen path with no prior lookup gating
it. Add a safe_join() helper that resolves the path and rejects
anything that escapes the base directory, and use it at all four
call sites.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-30 23:19:54 +00:00
ubuntuandClaude Sonnet 5 21d40c932e Stop leaking the Gemini API key through /gemini_key
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>
2026-08-30 23:16:39 +00:00
ubuntuandClaude Sonnet 5 b16a0a811c Fix server freeze from unresponsive logo/image hosts
requests.get() calls had no timeout and ran directly on the aiohttp
event loop, so a single dead logo host would hang for minutes and
block every other request. Add timeouts and move logo downloads in
get_logo to a thread executor so a slow/dead host no longer stalls
the whole server.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-30 18:05:19 +00:00
ubuntu df36139bd5 Delegate TLS termination to the nginx reverse proxy
The app now listens on plain HTTP (127.0.0.1:5023 only) instead of
binding 443 and terminating TLS itself. Nginx handles TLS for
iptv.mrk.ovh and proxies to the app internally.
2026-08-30 11:47:25 +00:00
ubuntuandClaude Sonnet 5 3eb0d5e8cd Add device-side log file, remote terminal, and streaming error reporting
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>
2026-08-16 22:09:51 +00:00
ubuntu 10fd5106f8 Show device country next to its IP address, resolved via ip-api.com 2026-08-16 10:39:17 +00:00
ubuntu 7a5dba7dbf Run Xtream imports in background to avoid long-held HTTP connections dropping silently 2026-08-16 01:28:31 +00:00
ubuntu e34a71b910 Fix Xtream API requests blocked by provider due to default python-requests User-Agent 2026-08-16 00:52:30 +00:00
ubuntu a4b23c5f5d Commit initial du projet serverIPTV 2026-08-03 13:14:43 +00:00