diff options
| author | Pinapelz <yukais@pinapelz.com> | 2026-02-26 16:29:51 -0800 |
|---|---|---|
| committer | Pinapelz <yukais@pinapelz.com> | 2026-02-26 16:29:51 -0800 |
| commit | c908c1a88db0ef0bae86922e48ebb8c3c62db83a (patch) | |
| tree | 3eb2dc2784fa70a86f9f6f7ec6ddff99ecd048b9 | |
| parent | a73dd2b5563ef5c7603126078338dedf9288857f (diff) | |
stop broadcast when no subscribers
| -rw-r--r-- | README.md | 7 | ||||
| -rw-r--r-- | kpop.radio (renamed from links.radio) | 0 | ||||
| -rw-r--r-- | yt_radio.py | 11 |
3 files changed, 18 insertions, 0 deletions
@@ -15,3 +15,10 @@ uv run gunicorn yt_radio:app --bind 0.0.0.0:8000 -k gthread --threads 50 --worke ## Example Landing Page <img width="936" height="992" alt="image" src="https://github.com/user-attachments/assets/e70879ad-bdff-46b0-8018-130211d950a1" /> + +## Local Playlist +In case when fetching from YouTube takes too long for some reason, you can also specify a local `.radio` file. An example file has been included in this repo. + +The radio code will parse links from this file as the playlist instead. Set `PLAYLIST_URL="PATH_TO_.RADIO_FILE"` + +The file must end with `.radio` diff --git a/yt_radio.py b/yt_radio.py index 5740d3f..234e84b 100644 --- a/yt_radio.py +++ b/yt_radio.py @@ -44,6 +44,7 @@ SUBSCRIBERS = {} # sid -> Queue[bytes] SUBSCRIBERS_LOCK = threading.Lock() RADIO_THREAD = None RADIO_STOP = threading.Event() +SUBSCRIBER_EVENT = threading.Event() CHUNK_SIZE = 8192 QUEUE_MAX_CHUNKS = 256 @@ -271,6 +272,7 @@ def add_subscriber(): sid = uuid.uuid4().hex with SUBSCRIBERS_LOCK: SUBSCRIBERS[sid] = q + SUBSCRIBER_EVENT.set() logger.info("Subscriber added sid=%s (total=%d)", sid, len(SUBSCRIBERS)) return sid, q @@ -280,6 +282,8 @@ def remove_subscriber(sid): if sid in SUBSCRIBERS: SUBSCRIBERS.pop(sid, None) logger.info("Subscriber removed sid=%s (total=%d)", sid, len(SUBSCRIBERS)) + if not SUBSCRIBERS: + SUBSCRIBER_EVENT.clear() def broadcast_chunk(chunk: bytes): @@ -300,6 +304,9 @@ def broadcast_chunk(chunk: bytes): def _radio_loop(): played = [] while not RADIO_STOP.is_set(): + if not SUBSCRIBER_EVENT.wait(timeout=1): + continue + if not PLAYLIST: logger.error("Playlist is empty, cannot stream") time.sleep(1) @@ -316,6 +323,10 @@ def _radio_loop(): for chunk in _stream_track(index): if RADIO_STOP.is_set(): break + with SUBSCRIBERS_LOCK: + if not SUBSCRIBERS: + logger.info("No subscribers remaining; stopping track early") + break broadcast_chunk(chunk) except Exception: logger.exception("Error in radio producer, skipping track") |
