Replace shoutcast implementation with vlc+gtk app

This commit is contained in:
evilchili
2025-09-14 14:46:38 -07:00
parent 263e439a6d
commit 7a4cd1ba50
12 changed files with 282 additions and 579 deletions
-92
View File
@@ -1,92 +0,0 @@
import io
import threading
from pathlib import Path
from time import sleep
from unittest.mock import MagicMock
import pytest
import shout
from croaker import playlist, streamer
@pytest.fixture(scope="session")
def silence_bytes():
# return (Path(streamer.__file__).parent / "silence.mp3").read_bytes()
return (Path(__file__).parent / "fixtures" / "transcoded_silence.mp3").read_bytes()
@pytest.fixture
def output_stream():
return io.BytesIO()
@pytest.fixture
def mock_shout(output_stream, monkeypatch):
def handle_send(buf):
print(f"buffering {len(buf)} bytes to output_stream.")
output_stream.write(buf)
mm = MagicMock(spec=shout.Shout, **{"return_value.send.side_effect": handle_send})
monkeypatch.setattr("shout.Shout", mm)
return mm
@pytest.fixture
def audio_streamer(monkeypatch, mock_shout):
return streamer.AudioStreamer()
@pytest.fixture
def thread(audio_streamer):
thread = threading.Thread(target=audio_streamer.run)
thread.daemon = True
yield thread
audio_streamer.shutdown_requested.set()
thread.join()
def wait_for(condition, timeout=2.0):
elapsed = 0.0
while not condition() and elapsed < 2.0:
elapsed += 0.01
sleep(0.01)
return elapsed <= timeout
def wait_for_not(condition, timeout=2.0):
return wait_for(lambda: not condition(), timeout=timeout)
def test_streamer_clear(audio_streamer, thread):
# enqueue some tracks
pl = playlist.Playlist(name="test_playlist")
for track in pl.tracks:
audio_streamer.queue.put(bytes(track))
assert not audio_streamer.queue.empty()
# start the server and send it a clear request
thread.start()
audio_streamer.clear_requested.set()
assert wait_for(audio_streamer.queue.empty)
assert wait_for_not(audio_streamer.clear_requested.is_set)
def test_streamer_shutdown(audio_streamer, thread):
thread.start()
audio_streamer.shutdown_requested.set()
assert wait_for_not(audio_streamer.shutdown_requested.is_set)
def test_streamer_skip(audio_streamer, thread):
thread.start()
audio_streamer.skip_requested.set()
assert wait_for_not(audio_streamer.skip_requested.is_set)
def test_streamer_defaults_to_silence(audio_streamer, thread, output_stream, silence_bytes):
thread.start()
thread.join(timeout=1)
output_stream.seek(0, 0)
out = output_stream.read()
assert silence_bytes in out
-43
View File
@@ -1,43 +0,0 @@
from unittest.mock import MagicMock
import ffmpeg
import pytest
from croaker import playlist, transcoder
@pytest.fixture
def mock_mp3decoder(monkeypatch):
def read(stream):
return stream.read()
monkeypatch.setattr(transcoder, "MP3Decoder", MagicMock(**{"__enter__.return_value.read": read}))
@pytest.mark.xfail
@pytest.mark.parametrize(
"suffix, expected",
[
(".mp3", b"_theme.mp3\n"),
(".foo", b"transcoding!\n"),
],
)
def test_transcoder_open(monkeypatch, mock_mp3decoder, suffix, expected):
monkeypatch.setattr(
transcoder,
"ffmpeg",
MagicMock(
spec=ffmpeg,
**{
"input.return_value."
"output.return_value."
"global_args.return_value."
"compile.return_value": ["echo", "transcoding!"],
},
),
)
pl = playlist.Playlist(name="test_playlist")
track = [t for t in pl.tracks if t.suffix == suffix][0]
with transcoder.open(track) as handle:
assert handle.read() == expected