Schedule playing music for adjustable intervals during the day.
- automatic playing
- accepting/rejecting tracks in library
- proposing new tracks
- validation against tracks count, total scheduled duration etc.
- supports Youtube
- playing module can be run on different computer than the rest
This project was deliberately created with the concept of ports & adapters architecture in mind.
These include not only the Kafka message producer and consumer module or the database repository,
but also the playback of songs.
And finally, the trivial clock, which plays a crucial role in a project that relies on the passage of time.
The system consists of services listed:
frontend– TODO,- backend which serves the user via API (OpenAPI with Swagger – see /docs/),
- player which observes or waits until a next break to play music on,
- message broker (any Kafka-compatible; here Redpanda is used due to simplicity in deployment on-premise)
All unit tests can be run as integration tests using real database and real message broker.
Of course, there are more integration-only tests, but the former approach both reduces duplicated tests code and allows to debug problem with failures within memory (thus without external dependencies). What a relief!
The only requirement is Docker Compose installed.
Run
docker compose -f docker-compose.tests.yaml up --abort-on-container-failure backend-integrationWant to run another tests (scope or level)?
Simply change the last argument to any of:
- backend-units
- backend-integration
- player-units
- player-integration
No complex commands passed as execution arguments are needed – all of them are written in docker-compose.tests.yaml.
The command returns a non-zero exit code in case of fail apart from tests result in standard output logged.
$ docker compose -f docker-compose.tests.yaml up --abort-on-container-failure backend-integration
[+] Running 3/0
✔ Container redpanda-broker-0-tests Created 0.0s
✔ Container init-backend-tests Created 0.0s
✔ Container backend-tests-integration Created 0.0s
Attaching to backend-tests-integration
backend-tests-integration | ============================= test session starts ==============================
backend-tests-integration | platform linux -- Python 3.12.4, pytest-8.3.4, pluggy-1.5.0
backend-tests-integration | rootdir: /app/src
backend-tests-integration | configfile: pyproject.toml
backend-tests-integration | plugins: anyio-4.8.0, asyncio-0.25.3
backend-tests-integration | asyncio: mode=Mode.STRICT, asyncio_default_fixture_loop_scope=function
backend-tests-integration | collected 64 items
backend-tests-integration |
backend-tests-integration | src/tests/unit/test_duration.py ... [ 4%]
backend-tests-integration | src/tests/unit/test_events_exchange.py ....... [ 15%]
backend-tests-integration | src/tests/unit/test_library.py .. [ 18%]
backend-tests-integration | src/tests/unit/test_library_repository.py ...... [ 28%]
backend-tests-integration | src/tests/unit/test_playlist.py ...... [ 37%]
backend-tests-integration | src/tests/unit/test_playlist_repository.py ....... [ 48%]
backend-tests-integration | src/tests/unit/test_provider_youtube.py ......... [ 62%]
backend-tests-integration | src/tests/unit/test_requests.py .................. [ 90%]
backend-tests-integration | src/tests/unit/test_track_builder.py ...... [100%]
backend-tests-integration |
backend-tests-integration | ======================== 64 passed, 0 warnings in 6.99s ========================
backend-tests-integration exited with code 0-
firstly, run Kafka broker
docker compose up -d redpanda-0
-
backend
Setup the virtual environment
cd backend/ && python -m venv venv && source venv/bin/activate && pip install -r requirements.txt && pip install -e .
Run unit tests
pytest
Run integration tests
pytest --realdb --realmsgbroker src/tests/
-
player
Setup the virtual environment
cd player/ && python -m venv venv && source venv/bin/activate && pip install -r requirements.txt && pip install -e .
Run unit tests
pytest
Run integration tests
pytest --realdb --realmsgbroker tests/
Backend service needs Youtube APIv3 token written to .youtube-api-key.secret file (its value only).
Go to the APIs & Services dashboard to generate the token.
As simple as
docker compose up -d-
on one (main) machine which serves users
docker compose up -d backend redpanda-0
-
on second machine (with speakers connected)
docker compose up -d player
moreover, you may need to change interface on which backend and Kafka ports are exposed (with recommendation of VPN usage for the network) and – depending on DNS resolver configuration – also the hostnames of broker and schema registry defined in .env.compose.
WSL2 users can play music within Docker container if they use wslg and have /mnt/wslg/{PulseServer,PulseAudioRDPSink,PulseAudioRDPSource} sockets.
In order to use them, simply uncomment lines in docker-compose.yaml starting with # WSL2 (for the player container) and run again docker compose up -d.
After running
docker exec -it player python -c "import miniaudio; print(miniaudio.Devices().get_playbacks())"you should see at least one audio sink, e.g.
[{'name': 'RDP Sink', 'type': <DeviceType.PLAYBACK: 1>, 'id': <cdata 'union ma_device_id *' owning 256 bytes>,
'formats': [{'format': '16-bit Signed Integer', 'samplerate': 44100, 'channels': 2}]}]If so,
docker exec -it player python play_sample.pyshould play music to your ears!
Configuration files (backend, player) are mounted from the host so should be edited on the host.
They have schema declared for them so feel free to play around in any code editor supporting provided schema for yaml files.
The computer on which the player is running may not be precisely synchronised with the expected start of the break and thus the music playback.
If, for this or any other reason, you need to move the start of the interval by a few or several seconds, simply edit the breaks.offset.seconds parameter in the player/config.yaml according to the rule
program time is actual time plus offset (positive or negative)