tinyjukebox 0.47.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- tinyjukebox-0.47.0/.gitignore +40 -0
- tinyjukebox-0.47.0/LICENSE.txt +21 -0
- tinyjukebox-0.47.0/PKG-INFO +236 -0
- tinyjukebox-0.47.0/README.md +205 -0
- tinyjukebox-0.47.0/cpp/rfid-reader/tests/stub/MFRC522.h +412 -0
- tinyjukebox-0.47.0/deploy/README.md +41 -0
- tinyjukebox-0.47.0/docs/config.example.yaml +39 -0
- tinyjukebox-0.47.0/docs/config_schema.json +606 -0
- tinyjukebox-0.47.0/docs/developer/app.md +321 -0
- tinyjukebox-0.47.0/docs/developer/architecture.md +840 -0
- tinyjukebox-0.47.0/docs/developer/box.md +367 -0
- tinyjukebox-0.47.0/docs/developer/concept/desktop-box-concept.md +243 -0
- tinyjukebox-0.47.0/docs/developer/concept/spotify-advent-calendar-figures-concept.md +154 -0
- tinyjukebox-0.47.0/docs/developer/configuration.md +256 -0
- tinyjukebox-0.47.0/docs/developer/deployment.md +525 -0
- tinyjukebox-0.47.0/docs/developer/development.md +434 -0
- tinyjukebox-0.47.0/docs/developer/drivers.md +340 -0
- tinyjukebox-0.47.0/docs/developer/library.md +2774 -0
- tinyjukebox-0.47.0/docs/developer/operations.md +585 -0
- tinyjukebox-0.47.0/docs/developer/rest-api.md +336 -0
- tinyjukebox-0.47.0/docs/developer/rfid-reader.md +192 -0
- tinyjukebox-0.47.0/docs/developer/roadmap.md +194 -0
- tinyjukebox-0.47.0/docs/hardware/README.md +65 -0
- tinyjukebox-0.47.0/docs/images/back-panel-usb-bezel.jpg +0 -0
- tinyjukebox-0.47.0/docs/images/box-2026.jpg +0 -0
- tinyjukebox-0.47.0/docs/images/box-back.jpg +0 -0
- tinyjukebox-0.47.0/docs/images/box-model.png +0 -0
- tinyjukebox-0.47.0/docs/images/box-open-figure-2019.jpg +0 -0
- tinyjukebox-0.47.0/docs/images/case-with-feet.jpg +0 -0
- tinyjukebox-0.47.0/docs/images/feet.jpg +0 -0
- tinyjukebox-0.47.0/docs/images/inside-2019.jpg +0 -0
- tinyjukebox-0.47.0/docs/images/inside-2026.jpg +0 -0
- tinyjukebox-0.47.0/docs/images/lid-on-circuit-2019.jpg +0 -0
- tinyjukebox-0.47.0/docs/images/lid-top.jpg +0 -0
- tinyjukebox-0.47.0/docs/images/lid-wiring.jpg +0 -0
- tinyjukebox-0.47.0/docs/images/lock-screw-bracket.jpg +0 -0
- tinyjukebox-0.47.0/docs/images/logo-dark.svg +40 -0
- tinyjukebox-0.47.0/docs/images/logo-icon.svg +6 -0
- tinyjukebox-0.47.0/docs/images/logo-mark.svg +38 -0
- tinyjukebox-0.47.0/docs/images/logo.svg +40 -0
- tinyjukebox-0.47.0/docs/images/pi-and-amp-2026.jpg +0 -0
- tinyjukebox-0.47.0/docs/images/rfid-reader-holder.jpg +0 -0
- tinyjukebox-0.47.0/docs/site/tinyjukebox.css +28 -0
- tinyjukebox-0.47.0/docs/style-guide/README.md +322 -0
- tinyjukebox-0.47.0/docs/style-guide/palette-brand.svg +49 -0
- tinyjukebox-0.47.0/docs/style-guide/palette-web-dark.svg +49 -0
- tinyjukebox-0.47.0/docs/style-guide/palette-web-light.svg +49 -0
- tinyjukebox-0.47.0/docs/user/de/admin.md +528 -0
- tinyjukebox-0.47.0/docs/user/de/manual.md +774 -0
- tinyjukebox-0.47.0/docs/user/de/quick-guide.md +61 -0
- tinyjukebox-0.47.0/docs/user/en/admin.md +515 -0
- tinyjukebox-0.47.0/docs/user/en/manual.md +753 -0
- tinyjukebox-0.47.0/docs/user/en/quick-guide.md +61 -0
- tinyjukebox-0.47.0/hardware/README.md +79 -0
- tinyjukebox-0.47.0/pyproject.toml +180 -0
- tinyjukebox-0.47.0/src/tinyjukebox/__init__.py +7 -0
- tinyjukebox-0.47.0/src/tinyjukebox/albumplayer/__init__.py +1 -0
- tinyjukebox-0.47.0/src/tinyjukebox/albumplayer/aalbumplayer.py +402 -0
- tinyjukebox-0.47.0/src/tinyjukebox/albumplayer/clock.py +39 -0
- tinyjukebox-0.47.0/src/tinyjukebox/albumplayer/dummyplayer.py +49 -0
- tinyjukebox-0.47.0/src/tinyjukebox/albumplayer/player_interface.py +97 -0
- tinyjukebox-0.47.0/src/tinyjukebox/albumplayer/radioplayer.py +391 -0
- tinyjukebox-0.47.0/src/tinyjukebox/albumplayer/simpleplayer.py +419 -0
- tinyjukebox-0.47.0/src/tinyjukebox/albumplayer/spotifyplayer.py +671 -0
- tinyjukebox-0.47.0/src/tinyjukebox/backup.py +176 -0
- tinyjukebox-0.47.0/src/tinyjukebox/backups.py +340 -0
- tinyjukebox-0.47.0/src/tinyjukebox/cli.py +1076 -0
- tinyjukebox-0.47.0/src/tinyjukebox/control.py +1386 -0
- tinyjukebox-0.47.0/src/tinyjukebox/core/__init__.py +1 -0
- tinyjukebox-0.47.0/src/tinyjukebox/core/config.py +100 -0
- tinyjukebox-0.47.0/src/tinyjukebox/core/logging/__init__.py +113 -0
- tinyjukebox-0.47.0/src/tinyjukebox/core/microservice.py +303 -0
- tinyjukebox-0.47.0/src/tinyjukebox/core/pubsub/__init__.py +15 -0
- tinyjukebox-0.47.0/src/tinyjukebox/core/pubsub/base.py +196 -0
- tinyjukebox-0.47.0/src/tinyjukebox/core/pubsub/localqueue.py +102 -0
- tinyjukebox-0.47.0/src/tinyjukebox/core/pubsub/statistics.py +57 -0
- tinyjukebox-0.47.0/src/tinyjukebox/core/py.typed +0 -0
- tinyjukebox-0.47.0/src/tinyjukebox/core/schema/__init__.py +5 -0
- tinyjukebox-0.47.0/src/tinyjukebox/core/schema/logger.py +40 -0
- tinyjukebox-0.47.0/src/tinyjukebox/core/schema/microservice.py +48 -0
- tinyjukebox-0.47.0/src/tinyjukebox/core/threads.py +39 -0
- tinyjukebox-0.47.0/src/tinyjukebox/core/ui/__init__.py +5 -0
- tinyjukebox-0.47.0/src/tinyjukebox/core/ui/cli.py +120 -0
- tinyjukebox-0.47.0/src/tinyjukebox/core/ui/tools.py +73 -0
- tinyjukebox-0.47.0/src/tinyjukebox/core/unexpected.py +46 -0
- tinyjukebox-0.47.0/src/tinyjukebox/data/__init__.py +0 -0
- tinyjukebox-0.47.0/src/tinyjukebox/data/activities.py +175 -0
- tinyjukebox-0.47.0/src/tinyjukebox/data/activity.py +138 -0
- tinyjukebox-0.47.0/src/tinyjukebox/data/common.py +91 -0
- tinyjukebox-0.47.0/src/tinyjukebox/data/degraded.py +39 -0
- tinyjukebox-0.47.0/src/tinyjukebox/data/jsondata.py +218 -0
- tinyjukebox-0.47.0/src/tinyjukebox/data/sanitycheck.py +71 -0
- tinyjukebox-0.47.0/src/tinyjukebox/data/tag.py +98 -0
- tinyjukebox-0.47.0/src/tinyjukebox/data/tags.py +160 -0
- tinyjukebox-0.47.0/src/tinyjukebox/data/target.py +568 -0
- tinyjukebox-0.47.0/src/tinyjukebox/data/targetalbumtools.py +88 -0
- tinyjukebox-0.47.0/src/tinyjukebox/data/targets.py +256 -0
- tinyjukebox-0.47.0/src/tinyjukebox/data/volumelimits.py +68 -0
- tinyjukebox-0.47.0/src/tinyjukebox/data_folder.py +180 -0
- tinyjukebox-0.47.0/src/tinyjukebox/devices/__init__.py +1 -0
- tinyjukebox-0.47.0/src/tinyjukebox/devices/baseclasses/__init__.py +1 -0
- tinyjukebox-0.47.0/src/tinyjukebox/devices/baseclasses/adriver.py +115 -0
- tinyjukebox-0.47.0/src/tinyjukebox/devices/baseclasses/aevents.py +47 -0
- tinyjukebox-0.47.0/src/tinyjukebox/devices/baseclasses/gpiolevel.py +16 -0
- tinyjukebox-0.47.0/src/tinyjukebox/devices/bluetooth/__init__.py +1 -0
- tinyjukebox-0.47.0/src/tinyjukebox/devices/bluetooth/avrcp_input.py +118 -0
- tinyjukebox-0.47.0/src/tinyjukebox/devices/bluetooth/bluez.py +446 -0
- tinyjukebox-0.47.0/src/tinyjukebox/devices/bluetooth/link.py +396 -0
- tinyjukebox-0.47.0/src/tinyjukebox/devices/bluetooth/virtual.py +155 -0
- tinyjukebox-0.47.0/src/tinyjukebox/devices/drivermanager/__init__.py +1 -0
- tinyjukebox-0.47.0/src/tinyjukebox/devices/drivermanager/driverfactory.py +75 -0
- tinyjukebox-0.47.0/src/tinyjukebox/devices/drivermanager/drivermanager.py +151 -0
- tinyjukebox-0.47.0/src/tinyjukebox/devices/drivers/__init__.py +31 -0
- tinyjukebox-0.47.0/src/tinyjukebox/devices/drivers/bluetooth.py +257 -0
- tinyjukebox-0.47.0/src/tinyjukebox/devices/drivers/input.py +165 -0
- tinyjukebox-0.47.0/src/tinyjukebox/devices/drivers/rfid.py +297 -0
- tinyjukebox-0.47.0/src/tinyjukebox/devices/drivers/rgbled.py +215 -0
- tinyjukebox-0.47.0/src/tinyjukebox/devices/py.typed +0 -0
- tinyjukebox-0.47.0/src/tinyjukebox/devices/schema/__init__.py +1 -0
- tinyjukebox-0.47.0/src/tinyjukebox/devices/schema/adriver.py +33 -0
- tinyjukebox-0.47.0/src/tinyjukebox/devices/schema/bluetooth.py +31 -0
- tinyjukebox-0.47.0/src/tinyjukebox/devices/schema/drivermanager.py +41 -0
- tinyjukebox-0.47.0/src/tinyjukebox/devices/schema/input.py +23 -0
- tinyjukebox-0.47.0/src/tinyjukebox/devices/schema/rfid.py +44 -0
- tinyjukebox-0.47.0/src/tinyjukebox/devices/schema/rgbled.py +26 -0
- tinyjukebox-0.47.0/src/tinyjukebox/diagnostics.py +179 -0
- tinyjukebox-0.47.0/src/tinyjukebox/errors.py +91 -0
- tinyjukebox-0.47.0/src/tinyjukebox/headset.py +296 -0
- tinyjukebox-0.47.0/src/tinyjukebox/images.py +133 -0
- tinyjukebox-0.47.0/src/tinyjukebox/latency.py +43 -0
- tinyjukebox-0.47.0/src/tinyjukebox/library/__init__.py +2 -0
- tinyjukebox-0.47.0/src/tinyjukebox/library/diagnostics.py +183 -0
- tinyjukebox-0.47.0/src/tinyjukebox/library/journal.py +94 -0
- tinyjukebox-0.47.0/src/tinyjukebox/library/releases.py +348 -0
- tinyjukebox-0.47.0/src/tinyjukebox/library/schema.py +98 -0
- tinyjukebox-0.47.0/src/tinyjukebox/library/service.py +1115 -0
- tinyjukebox-0.47.0/src/tinyjukebox/library/statistics.py +288 -0
- tinyjukebox-0.47.0/src/tinyjukebox/library/store.py +1386 -0
- tinyjukebox-0.47.0/src/tinyjukebox/messages.py +202 -0
- tinyjukebox-0.47.0/src/tinyjukebox/metadata.py +133 -0
- tinyjukebox-0.47.0/src/tinyjukebox/py.typed +0 -0
- tinyjukebox-0.47.0/src/tinyjukebox/restore.py +391 -0
- tinyjukebox-0.47.0/src/tinyjukebox/rgbled.py +158 -0
- tinyjukebox-0.47.0/src/tinyjukebox/schema/__init__.py +1 -0
- tinyjukebox-0.47.0/src/tinyjukebox/schema/activities.py +27 -0
- tinyjukebox-0.47.0/src/tinyjukebox/schema/tags.py +54 -0
- tinyjukebox-0.47.0/src/tinyjukebox/schema/targets.py +83 -0
- tinyjukebox-0.47.0/src/tinyjukebox/schema/tinyjukebox.py +217 -0
- tinyjukebox-0.47.0/src/tinyjukebox/schema/volume.py +28 -0
- tinyjukebox-0.47.0/src/tinyjukebox/slots.py +234 -0
- tinyjukebox-0.47.0/src/tinyjukebox/spotify/__init__.py +1 -0
- tinyjukebox-0.47.0/src/tinyjukebox/spotify/account.py +647 -0
- tinyjukebox-0.47.0/src/tinyjukebox/spotify/engine.py +568 -0
- tinyjukebox-0.47.0/src/tinyjukebox/spotify/oembed.py +65 -0
- tinyjukebox-0.47.0/src/tinyjukebox/spotify/soloist.py +198 -0
- tinyjukebox-0.47.0/src/tinyjukebox/spotify/sound.py +316 -0
- tinyjukebox-0.47.0/src/tinyjukebox/stm/__init__.py +0 -0
- tinyjukebox-0.47.0/src/tinyjukebox/stm/base.py +174 -0
- tinyjukebox-0.47.0/src/tinyjukebox/stm/playradio.py +237 -0
- tinyjukebox-0.47.0/src/tinyjukebox/stm/playspotify.py +418 -0
- tinyjukebox-0.47.0/src/tinyjukebox/stm/stmoperation.py +769 -0
- tinyjukebox-0.47.0/src/tinyjukebox/stm/stmplayalbum.py +655 -0
- tinyjukebox-0.47.0/src/tinyjukebox/stm/stmvolume.py +221 -0
- tinyjukebox-0.47.0/src/tinyjukebox/sync/__init__.py +42 -0
- tinyjukebox-0.47.0/src/tinyjukebox/sync/box.py +486 -0
- tinyjukebox-0.47.0/src/tinyjukebox/sync/client.py +189 -0
- tinyjukebox-0.47.0/src/tinyjukebox/sync/data.py +489 -0
- tinyjukebox-0.47.0/src/tinyjukebox/sync/files.py +447 -0
- tinyjukebox-0.47.0/src/tinyjukebox/sync/handshake.py +42 -0
- tinyjukebox-0.47.0/src/tinyjukebox/sync/link.py +379 -0
- tinyjukebox-0.47.0/src/tinyjukebox/sync/manifest.py +162 -0
- tinyjukebox-0.47.0/src/tinyjukebox/sync/util.py +137 -0
- tinyjukebox-0.47.0/src/tinyjukebox/tinyjukebox.py +680 -0
- tinyjukebox-0.47.0/src/tinyjukebox/tools/__init__.py +1 -0
- tinyjukebox-0.47.0/src/tinyjukebox/tools/backup.py +173 -0
- tinyjukebox-0.47.0/src/tinyjukebox/tools/fill_library.py +120 -0
- tinyjukebox-0.47.0/src/tinyjukebox/tools/import_cards.py +274 -0
- tinyjukebox-0.47.0/src/tinyjukebox/tools/import_covers.py +138 -0
- tinyjukebox-0.47.0/src/tinyjukebox/tools/migrate_box01.py +151 -0
- tinyjukebox-0.47.0/src/tinyjukebox/volumemanager.py +355 -0
- tinyjukebox-0.47.0/src/tinyjukebox/web/__init__.py +1 -0
- tinyjukebox-0.47.0/src/tinyjukebox/web/auth.py +373 -0
- tinyjukebox-0.47.0/src/tinyjukebox/web/certificates.py +111 -0
- tinyjukebox-0.47.0/src/tinyjukebox/web/logbuffer.py +62 -0
- tinyjukebox-0.47.0/src/tinyjukebox/web/server.py +1237 -0
- tinyjukebox-0.47.0/src/tinyjukebox/web/uploads.py +262 -0
- tinyjukebox-0.47.0/src/tinyjukebox/web/users.py +106 -0
- tinyjukebox-0.47.0/src/tinyjukebox/web/web/app.js +3050 -0
- tinyjukebox-0.47.0/src/tinyjukebox/web/web/favicon.svg +6 -0
- tinyjukebox-0.47.0/src/tinyjukebox/web/web/help/de/admin.html +714 -0
- tinyjukebox-0.47.0/src/tinyjukebox/web/web/help/de/manual.html +1147 -0
- tinyjukebox-0.47.0/src/tinyjukebox/web/web/help/de/quick-guide.html +79 -0
- tinyjukebox-0.47.0/src/tinyjukebox/web/web/help/en/admin.html +701 -0
- tinyjukebox-0.47.0/src/tinyjukebox/web/web/help/en/manual.html +1126 -0
- tinyjukebox-0.47.0/src/tinyjukebox/web/web/help/en/quick-guide.html +79 -0
- tinyjukebox-0.47.0/src/tinyjukebox/web/web/help/help.css +25 -0
- tinyjukebox-0.47.0/src/tinyjukebox/web/web/help/images/box-2026.jpg +0 -0
- tinyjukebox-0.47.0/src/tinyjukebox/web/web/help/images/box-back.jpg +0 -0
- tinyjukebox-0.47.0/src/tinyjukebox/web/web/help/images/lid-top.jpg +0 -0
- tinyjukebox-0.47.0/src/tinyjukebox/web/web/help/images/logo-mark.svg +38 -0
- tinyjukebox-0.47.0/src/tinyjukebox/web/web/index.html +867 -0
- tinyjukebox-0.47.0/src/tinyjukebox/web/web/style.css +412 -0
- tinyjukebox-0.47.0/src/tinyjukebox/web/web/texts/de.json +892 -0
- tinyjukebox-0.47.0/src/tinyjukebox/web/web/texts/en.json +892 -0
- tinyjukebox-0.47.0/tests/__init__.py +0 -0
- tinyjukebox-0.47.0/tests/conftest.py +112 -0
- tinyjukebox-0.47.0/tests/core/__init__.py +0 -0
- tinyjukebox-0.47.0/tests/core/conftest.py +32 -0
- tinyjukebox-0.47.0/tests/core/support.py +76 -0
- tinyjukebox-0.47.0/tests/core/unit/__init__.py +0 -0
- tinyjukebox-0.47.0/tests/core/unit/test_config.py +96 -0
- tinyjukebox-0.47.0/tests/core/unit/test_logging.py +77 -0
- tinyjukebox-0.47.0/tests/core/unit/test_microservice.py +205 -0
- tinyjukebox-0.47.0/tests/core/unit/test_pubsub.py +261 -0
- tinyjukebox-0.47.0/tests/core/unit/test_schema.py +50 -0
- tinyjukebox-0.47.0/tests/core/unit/test_threads.py +25 -0
- tinyjukebox-0.47.0/tests/core/unit/test_ui.py +148 -0
- tinyjukebox-0.47.0/tests/data/activities/tags.json +46 -0
- tinyjukebox-0.47.0/tests/data/activities/testdata_empty_dict/activities.json +1 -0
- tinyjukebox-0.47.0/tests/data/activities/testdata_multiple/activities.json +26 -0
- tinyjukebox-0.47.0/tests/data/activities/testdata_one/activities.json +10 -0
- tinyjukebox-0.47.0/tests/data/albums/simple_album_a/1.mp3 +0 -0
- tinyjukebox-0.47.0/tests/data/albums/simple_album_a/2.mp3 +0 -0
- tinyjukebox-0.47.0/tests/data/albums/simple_album_a/3.mp3 +0 -0
- tinyjukebox-0.47.0/tests/data/albums/simple_album_a/4.mp3 +0 -0
- tinyjukebox-0.47.0/tests/data/albums/simple_album_a/5.mp3 +0 -0
- tinyjukebox-0.47.0/tests/data/albums/simple_album_a/playlist.m3u +5 -0
- tinyjukebox-0.47.0/tests/data/albums/simple_album_b/a.mp3 +0 -0
- tinyjukebox-0.47.0/tests/data/albums/simple_album_b/b.mp3 +0 -0
- tinyjukebox-0.47.0/tests/data/albums/simple_album_b/c.mp3 +0 -0
- tinyjukebox-0.47.0/tests/data/albums/simple_album_b/playlist.m3u +3 -0
- tinyjukebox-0.47.0/tests/data/albums/simple_album_c/1.mp3 +0 -0
- tinyjukebox-0.47.0/tests/data/albums/simple_album_c/playlist.m3u +2 -0
- tinyjukebox-0.47.0/tests/data/audio/short.mp3 +0 -0
- tinyjukebox-0.47.0/tests/data/config.yaml +19 -0
- tinyjukebox-0.47.0/tests/data/jsondata/empty_regular/filename.json +0 -0
- tinyjukebox-0.47.0/tests/data/jsondata/good/filename.json +4 -0
- tinyjukebox-0.47.0/tests/data/jsondata/schema.json +19 -0
- tinyjukebox-0.47.0/tests/data/jsondata/wrong_regular/filename.json +3 -0
- tinyjukebox-0.47.0/tests/data/tags/testdata_empty_dict/tags.json +1 -0
- tinyjukebox-0.47.0/tests/data/tags/testdata_multiple/tags.json +46 -0
- tinyjukebox-0.47.0/tests/data/tags/testdata_one/tags.json +13 -0
- tinyjukebox-0.47.0/tests/data/targets/albums/failmixed/1.mp3 +0 -0
- tinyjukebox-0.47.0/tests/data/targets/albums/failmixed/2.mp3 +0 -0
- tinyjukebox-0.47.0/tests/data/targets/albums/failmixed/4.mp3 +0 -0
- tinyjukebox-0.47.0/tests/data/targets/albums/failmixed/5.mp3 +0 -0
- tinyjukebox-0.47.0/tests/data/targets/albums/failmixed/playlist.m3u +5 -0
- tinyjukebox-0.47.0/tests/data/targets/albums/nested/nested_a/1.mp3 +0 -0
- tinyjukebox-0.47.0/tests/data/targets/albums/nested/nested_a/2.mp3 +0 -0
- tinyjukebox-0.47.0/tests/data/targets/albums/nested/nested_a/3.mp3 +0 -0
- tinyjukebox-0.47.0/tests/data/targets/albums/nested/nested_a/4.mp3 +0 -0
- tinyjukebox-0.47.0/tests/data/targets/albums/nested/nested_a/5.mp3 +0 -0
- tinyjukebox-0.47.0/tests/data/targets/albums/nested/nested_a/playlist.m3u +5 -0
- tinyjukebox-0.47.0/tests/data/targets/albums/nested/nested_b/a.mp3 +0 -0
- tinyjukebox-0.47.0/tests/data/targets/albums/nested/nested_b/b.mp3 +0 -0
- tinyjukebox-0.47.0/tests/data/targets/albums/nested/nested_b/c.mp3 +0 -0
- tinyjukebox-0.47.0/tests/data/targets/albums/nested/nested_b/playlist.m3u +3 -0
- tinyjukebox-0.47.0/tests/data/targets/albums/nomp3s/playlist.m3u +5 -0
- tinyjukebox-0.47.0/tests/data/targets/albums/noplaylist/1.mp3 +0 -0
- tinyjukebox-0.47.0/tests/data/targets/albums/nothing/empty.txt +0 -0
- tinyjukebox-0.47.0/tests/data/targets/albums/notvalidmp3s/1.mp3 +0 -0
- tinyjukebox-0.47.0/tests/data/targets/albums/notvalidmp3s/2.mp3 +0 -0
- tinyjukebox-0.47.0/tests/data/targets/albums/notvalidmp3s/3.mp3 +0 -0
- tinyjukebox-0.47.0/tests/data/targets/albums/notvalidmp3s/4.mp3 +0 -0
- tinyjukebox-0.47.0/tests/data/targets/albums/notvalidmp3s/5.mp3 +0 -0
- tinyjukebox-0.47.0/tests/data/targets/albums/notvalidmp3s/playlist.m3u +5 -0
- tinyjukebox-0.47.0/tests/data/targets/albums/simple_album_a/1.mp3 +0 -0
- tinyjukebox-0.47.0/tests/data/targets/albums/simple_album_a/2.mp3 +0 -0
- tinyjukebox-0.47.0/tests/data/targets/albums/simple_album_a/3.mp3 +0 -0
- tinyjukebox-0.47.0/tests/data/targets/albums/simple_album_a/4.mp3 +0 -0
- tinyjukebox-0.47.0/tests/data/targets/albums/simple_album_a/5.mp3 +0 -0
- tinyjukebox-0.47.0/tests/data/targets/albums/simple_album_a/playlist.m3u +5 -0
- tinyjukebox-0.47.0/tests/data/targets/albums/simple_album_b/a.mp3 +0 -0
- tinyjukebox-0.47.0/tests/data/targets/albums/simple_album_b/b.mp3 +0 -0
- tinyjukebox-0.47.0/tests/data/targets/albums/simple_album_b/c.mp3 +0 -0
- tinyjukebox-0.47.0/tests/data/targets/albums/simple_album_b/playlist.m3u +3 -0
- tinyjukebox-0.47.0/tests/data/targets/albums/simple_album_c/1.mp3 +0 -0
- tinyjukebox-0.47.0/tests/data/targets/albums/simple_album_c/5.mp3 +0 -0
- tinyjukebox-0.47.0/tests/data/targets/albums/simple_album_c/playlist.m3u +2 -0
- tinyjukebox-0.47.0/tests/data/targets/testdata_empty_dict/targets.json +1 -0
- tinyjukebox-0.47.0/tests/data/targets/testdata_multiple/targets.json +23 -0
- tinyjukebox-0.47.0/tests/data/targets/testdata_one/targets.json +9 -0
- tinyjukebox-0.47.0/tests/devices/__init__.py +0 -0
- tinyjukebox-0.47.0/tests/devices/bluezservice.py +181 -0
- tinyjukebox-0.47.0/tests/devices/configs/config_bluetooth.yaml +10 -0
- tinyjukebox-0.47.0/tests/devices/configs/config_drivermanager.yaml +12 -0
- tinyjukebox-0.47.0/tests/devices/configs/config_full.yaml +29 -0
- tinyjukebox-0.47.0/tests/devices/configs/config_input.yaml +9 -0
- tinyjukebox-0.47.0/tests/devices/configs/config_rfid.yaml +10 -0
- tinyjukebox-0.47.0/tests/devices/configs/config_rgbled.yaml +13 -0
- tinyjukebox-0.47.0/tests/devices/conftest.py +43 -0
- tinyjukebox-0.47.0/tests/devices/fakes.py +396 -0
- tinyjukebox-0.47.0/tests/devices/integration/__init__.py +0 -0
- tinyjukebox-0.47.0/tests/devices/integration/test_bluez_dbus.py +398 -0
- tinyjukebox-0.47.0/tests/devices/integration/test_rfid_reader.py +400 -0
- tinyjukebox-0.47.0/tests/devices/support.py +50 -0
- tinyjukebox-0.47.0/tests/devices/unit/__init__.py +0 -0
- tinyjukebox-0.47.0/tests/devices/unit/test_adriver.py +98 -0
- tinyjukebox-0.47.0/tests/devices/unit/test_avrcp_input.py +112 -0
- tinyjukebox-0.47.0/tests/devices/unit/test_bluetooth.py +480 -0
- tinyjukebox-0.47.0/tests/devices/unit/test_box.py +168 -0
- tinyjukebox-0.47.0/tests/devices/unit/test_drivermanager.py +199 -0
- tinyjukebox-0.47.0/tests/devices/unit/test_input.py +201 -0
- tinyjukebox-0.47.0/tests/devices/unit/test_rfid.py +434 -0
- tinyjukebox-0.47.0/tests/devices/unit/test_rgbled.py +173 -0
- tinyjukebox-0.47.0/tests/devices/unit/test_schema.py +97 -0
- tinyjukebox-0.47.0/tests/devices/unit/test_virtual_headset.py +108 -0
- tinyjukebox-0.47.0/tests/support.py +467 -0
- tinyjukebox-0.47.0/tests/sync/__init__.py +0 -0
- tinyjukebox-0.47.0/tests/sync/bed.py +210 -0
- tinyjukebox-0.47.0/tests/sync/card.py +58 -0
- tinyjukebox-0.47.0/tests/sync/conftest.py +111 -0
- tinyjukebox-0.47.0/tests/sync/gitserver.py +137 -0
- tinyjukebox-0.47.0/tests/sync/test_app.py +252 -0
- tinyjukebox-0.47.0/tests/sync/test_backup.py +811 -0
- tinyjukebox-0.47.0/tests/sync/test_box_releases.py +396 -0
- tinyjukebox-0.47.0/tests/sync/test_broken.py +98 -0
- tinyjukebox-0.47.0/tests/sync/test_covers.py +425 -0
- tinyjukebox-0.47.0/tests/sync/test_diagnostics.py +94 -0
- tinyjukebox-0.47.0/tests/sync/test_downloads.py +49 -0
- tinyjukebox-0.47.0/tests/sync/test_fill.py +69 -0
- tinyjukebox-0.47.0/tests/sync/test_install.py +119 -0
- tinyjukebox-0.47.0/tests/sync/test_library_and_box.py +701 -0
- tinyjukebox-0.47.0/tests/sync/test_package.py +120 -0
- tinyjukebox-0.47.0/tests/sync/test_recovery.py +80 -0
- tinyjukebox-0.47.0/tests/sync/test_recovery_mode.py +114 -0
- tinyjukebox-0.47.0/tests/sync/test_releases.py +256 -0
- tinyjukebox-0.47.0/tests/sync/test_slots.py +481 -0
- tinyjukebox-0.47.0/tests/sync/test_spotify_statistics.py +25 -0
- tinyjukebox-0.47.0/tests/sync/test_statistics.py +268 -0
- tinyjukebox-0.47.0/tests/sync/test_unlink.py +130 -0
- tinyjukebox-0.47.0/tests/unit/__init__.py +0 -0
- tinyjukebox-0.47.0/tests/unit/test_activities.py +270 -0
- tinyjukebox-0.47.0/tests/unit/test_activity.py +122 -0
- tinyjukebox-0.47.0/tests/unit/test_activityfactories.py +73 -0
- tinyjukebox-0.47.0/tests/unit/test_auth.py +239 -0
- tinyjukebox-0.47.0/tests/unit/test_backup.py +128 -0
- tinyjukebox-0.47.0/tests/unit/test_cli.py +658 -0
- tinyjukebox-0.47.0/tests/unit/test_clock.py +42 -0
- tinyjukebox-0.47.0/tests/unit/test_commandline.py +203 -0
- tinyjukebox-0.47.0/tests/unit/test_concurrency.py +138 -0
- tinyjukebox-0.47.0/tests/unit/test_config.py +120 -0
- tinyjukebox-0.47.0/tests/unit/test_data_folder.py +135 -0
- tinyjukebox-0.47.0/tests/unit/test_diagnostics.py +176 -0
- tinyjukebox-0.47.0/tests/unit/test_documents.py +57 -0
- tinyjukebox-0.47.0/tests/unit/test_dummyplayer.py +145 -0
- tinyjukebox-0.47.0/tests/unit/test_dummytrack.py +265 -0
- tinyjukebox-0.47.0/tests/unit/test_failures.py +165 -0
- tinyjukebox-0.47.0/tests/unit/test_handshake.py +25 -0
- tinyjukebox-0.47.0/tests/unit/test_headset.py +322 -0
- tinyjukebox-0.47.0/tests/unit/test_help.py +67 -0
- tinyjukebox-0.47.0/tests/unit/test_images.py +74 -0
- tinyjukebox-0.47.0/tests/unit/test_import_cards.py +349 -0
- tinyjukebox-0.47.0/tests/unit/test_installer.py +363 -0
- tinyjukebox-0.47.0/tests/unit/test_jsondata.py +208 -0
- tinyjukebox-0.47.0/tests/unit/test_latency.py +41 -0
- tinyjukebox-0.47.0/tests/unit/test_migrate_box01.py +148 -0
- tinyjukebox-0.47.0/tests/unit/test_persistence.py +209 -0
- tinyjukebox-0.47.0/tests/unit/test_player_interface.py +87 -0
- tinyjukebox-0.47.0/tests/unit/test_radio.py +572 -0
- tinyjukebox-0.47.0/tests/unit/test_restore.py +259 -0
- tinyjukebox-0.47.0/tests/unit/test_rgbled.py +92 -0
- tinyjukebox-0.47.0/tests/unit/test_sanitycheck.py +58 -0
- tinyjukebox-0.47.0/tests/unit/test_signals.py +49 -0
- tinyjukebox-0.47.0/tests/unit/test_simpleplayer.py +316 -0
- tinyjukebox-0.47.0/tests/unit/test_site.py +136 -0
- tinyjukebox-0.47.0/tests/unit/test_spotify_account.py +390 -0
- tinyjukebox-0.47.0/tests/unit/test_spotify_box.py +28 -0
- tinyjukebox-0.47.0/tests/unit/test_spotify_concurrency.py +633 -0
- tinyjukebox-0.47.0/tests/unit/test_spotify_entries.py +250 -0
- tinyjukebox-0.47.0/tests/unit/test_spotify_play.py +905 -0
- tinyjukebox-0.47.0/tests/unit/test_stm_base.py +229 -0
- tinyjukebox-0.47.0/tests/unit/test_stmoperation.py +286 -0
- tinyjukebox-0.47.0/tests/unit/test_stmplayalbum.py +574 -0
- tinyjukebox-0.47.0/tests/unit/test_sync_util.py +26 -0
- tinyjukebox-0.47.0/tests/unit/test_tag.py +125 -0
- tinyjukebox-0.47.0/tests/unit/test_tags.py +245 -0
- tinyjukebox-0.47.0/tests/unit/test_targetalbum.py +350 -0
- tinyjukebox-0.47.0/tests/unit/test_targetalbumtools.py +202 -0
- tinyjukebox-0.47.0/tests/unit/test_targetfactories.py +67 -0
- tinyjukebox-0.47.0/tests/unit/test_targets.py +290 -0
- tinyjukebox-0.47.0/tests/unit/test_texts.py +186 -0
- tinyjukebox-0.47.0/tests/unit/test_tinyjukebox.py +329 -0
- tinyjukebox-0.47.0/tests/unit/test_tolerant_data.py +110 -0
- tinyjukebox-0.47.0/tests/unit/test_uploads.py +69 -0
- tinyjukebox-0.47.0/tests/unit/test_volume.py +587 -0
- tinyjukebox-0.47.0/tests/unit/test_web.py +2170 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*.egg-info/
|
|
5
|
+
|
|
6
|
+
# build
|
|
7
|
+
build/
|
|
8
|
+
dist/
|
|
9
|
+
cpp/rfid-reader/rfid-reader
|
|
10
|
+
|
|
11
|
+
# tools
|
|
12
|
+
.venv/
|
|
13
|
+
.pytest_cache/
|
|
14
|
+
.mypy_cache/
|
|
15
|
+
.ruff_cache/
|
|
16
|
+
.ansible/
|
|
17
|
+
.coverage
|
|
18
|
+
.coverage.*
|
|
19
|
+
coverage.xml
|
|
20
|
+
coverage.json
|
|
21
|
+
htmlcov/
|
|
22
|
+
|
|
23
|
+
# runtime data and logs (the box keeps them under /srv/tinyjukebox, never in the repository)
|
|
24
|
+
*.log
|
|
25
|
+
*.log.[0-9]*
|
|
26
|
+
*.json_
|
|
27
|
+
*.json.tmp
|
|
28
|
+
execution/
|
|
29
|
+
.tinyjukebox-uploads/
|
|
30
|
+
|
|
31
|
+
# local configuration
|
|
32
|
+
config.local.yaml
|
|
33
|
+
credentials.yaml
|
|
34
|
+
|
|
35
|
+
# ide
|
|
36
|
+
.idea/
|
|
37
|
+
.vscode/
|
|
38
|
+
|
|
39
|
+
# the passwords of compose.yaml (deploy/docker/example.env)
|
|
40
|
+
deploy/docker/.env
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2018 Tobias Gawron-Deutsch
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: tinyjukebox
|
|
3
|
+
Version: 0.47.0
|
|
4
|
+
Summary: RFID-controlled audio player for albums: state machines, ffmpeg/aplay playback, REST API and web page.
|
|
5
|
+
Project-URL: Homepage, https://github.com/tgd1975/tinyjukebox
|
|
6
|
+
Project-URL: Documentation, https://github.com/tgd1975/tinyjukebox/tree/master/docs
|
|
7
|
+
Author-email: Tobias Gawron-Deutsch <tobias@strix.at>
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
License-File: LICENSE.txt
|
|
10
|
+
Keywords: audio player,kids,raspberry pi,rfid
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Environment :: Console
|
|
13
|
+
Classifier: Environment :: No Input/Output (Daemon)
|
|
14
|
+
Classifier: Environment :: Web Environment
|
|
15
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
16
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
17
|
+
Classifier: Topic :: Home Automation
|
|
18
|
+
Classifier: Topic :: Multimedia :: Sound/Audio :: Players
|
|
19
|
+
Classifier: Typing :: Typed
|
|
20
|
+
Requires-Python: >=3.11
|
|
21
|
+
Requires-Dist: jsonschema>=4.18
|
|
22
|
+
Requires-Dist: mutagen>=1.47
|
|
23
|
+
Requires-Dist: pyyaml>=6.0
|
|
24
|
+
Requires-Dist: segno>=1.6
|
|
25
|
+
Requires-Dist: tantamount<0.4,>=0.3.2
|
|
26
|
+
Provides-Extra: box
|
|
27
|
+
Requires-Dist: dbus-fast>=5.0; (sys_platform == 'linux') and extra == 'box'
|
|
28
|
+
Requires-Dist: pyalsaaudio>=0.11; (platform_machine == 'aarch64' or platform_machine == 'armv7l' or platform_machine == 'armv6l') and extra == 'box'
|
|
29
|
+
Requires-Dist: rpi-lgpio; (platform_machine == 'aarch64' or platform_machine == 'armv7l' or platform_machine == 'armv6l') and extra == 'box'
|
|
30
|
+
Description-Content-Type: text/markdown
|
|
31
|
+
|
|
32
|
+
<picture>
|
|
33
|
+
<source media="(prefers-color-scheme: dark)" srcset="docs/images/logo-dark.svg">
|
|
34
|
+
<img src="docs/images/logo.svg" alt="Tiny Jukebox" width="460">
|
|
35
|
+
</picture>
|
|
36
|
+
|
|
37
|
+
RFID-controlled music box for children: put a tag (a disc, a figure, a card – anything with an RFID chip) on the box,
|
|
38
|
+
and the linked album continues where it stopped last time. The tag is only ever read, never written; the UID is all
|
|
39
|
+
that counts.
|
|
40
|
+
|
|
41
|
+
<img src="docs/images/box-2026.jpg" alt="The box today: a white wooden case with a grille of rings at the front, on top the round lid with buttons, LED and a tag in its window" width="360">
|
|
42
|
+
|
|
43
|
+
## 1. What Tiny Jukebox does especially well
|
|
44
|
+
|
|
45
|
+
- **One library, any number of boxes.** `tinyjukebox-library` runs on a NAS or the PC and holds the tags, albums,
|
|
46
|
+
radio stations and covers. Every box keeps a copy, fetches the albums it lacks, plays without the library,
|
|
47
|
+
and the library shows what was played.
|
|
48
|
+
- **Updates with a way back.** A push to `master` that changes the software becomes a release. The library
|
|
49
|
+
fetches it, a box tries the new version at its next start and goes back to the one before by itself if it fails.
|
|
50
|
+
- **Set up with one line, run like an appliance.** One line on a fresh Raspberry Pi OS turns it into a box – fetched
|
|
51
|
+
from GitHub, or from the page of the library, which links the box to it at once. The library is a package for a
|
|
52
|
+
Synology NAS, a Docker image or `pip install`. Backups run by a schedule, users and roles are managed on the web
|
|
53
|
+
page.
|
|
54
|
+
- **Everything on one web page.** Link tags (also by scanning them with a phone), upload albums, set radio
|
|
55
|
+
stations and volume limits, change covers – over HTTPS, in English and German, with a REST API behind it.
|
|
56
|
+
- **Bluetooth headset as a first-class way to listen.** Pairing with a button gesture, own start volume and maximum,
|
|
57
|
+
pause when the connection is lost, headset buttons.
|
|
58
|
+
- **Reads reliably.** The RC522 is read by a small C++ program that recovers by itself after a crash or a reset of
|
|
59
|
+
the chip, and playback keeps its position over a power cut.
|
|
60
|
+
- **Spotify and phones, built but not yet tried for real.** A tag can also play an entry of Spotify – an album, a
|
|
61
|
+
playlist, a podcast – through Spotify Soloist, and the app for Android makes a phone a box
|
|
62
|
+
([app.md](https://github.com/tgd1975/tinyjukebox/blob/master/docs/developer/app.md)). Spotify is tested on the PC and has not played on a box yet; the app ran in the
|
|
63
|
+
Android emulator, not yet on a real phone ([roadmap.md](https://github.com/tgd1975/tinyjukebox/blob/master/docs/developer/roadmap.md), section 1).
|
|
64
|
+
|
|
65
|
+
## 2. Software and hardware
|
|
66
|
+
|
|
67
|
+
The software is one Python process (one systemd service) with device drivers, state machines, player and web page
|
|
68
|
+
that exchange messages over an in-process queue – no broker, no further services. State machines run tags, album
|
|
69
|
+
playback, radio, Spotify and volume. Playback is `ffmpeg | aplay`: the position is saved, with next/previous, pause and
|
|
70
|
+
internet radio stations. An entry of Spotify plays through Spotify Soloist, which the box starts with a PipeWire of
|
|
71
|
+
its own; its sound goes to `aplay` as well. The app for Android phones (`app/`, Kotlin) makes a phone a box: it reads
|
|
72
|
+
the tag with NFC and plays its album or station with the data of the library ([app.md](https://github.com/tgd1975/tinyjukebox/blob/master/docs/developer/app.md)).
|
|
73
|
+
|
|
74
|
+
**The software does not need a Raspberry Pi or a particular amplifier.** Our own box happens to be a Raspberry Pi 3
|
|
75
|
+
with an RC522, four buttons, an RGB LED and a Pimoroni Audio Amp SHIM; that is the platform we built and tested, not a
|
|
76
|
+
requirement of the application.
|
|
77
|
+
|
|
78
|
+
- **Sound:** any ALSA device and mixer control, set in the config. The Audio Amp SHIM is not mentioned in the code.
|
|
79
|
+
- **Core:** state machines, player, web page, REST API and library are plain Python on Linux; they run on a PC
|
|
80
|
+
without any hardware (`--no-hardware`), which is also how the tests run.
|
|
81
|
+
- **Drivers:** buttons, LED, RFID reader and Bluetooth are drivers selected and wired in the config
|
|
82
|
+
([drivers.md](https://github.com/tgd1975/tinyjukebox/blob/master/docs/developer/drivers.md)); the pins are config, not code.
|
|
83
|
+
- **RFID reader:** the driver starts any program that prints `ready`, `tag <UID>` and `removed`, one per line
|
|
84
|
+
([rfid-reader.md](https://github.com/tgd1975/tinyjukebox/blob/master/docs/developer/rfid-reader.md)). The C++ `rfid-reader` for the RC522 on a Raspberry Pi is the one
|
|
85
|
+
we ship; another reader or another board needs only such a program and the `command` of the driver.
|
|
86
|
+
- **What is tied to the Pi today:** the shipped GPIO drivers (`rpi-lgpio`) and `rfid-reader` (SPI through bcm2835).
|
|
87
|
+
Bluetooth uses BlueZ and BlueALSA, which are not specific to the Pi.
|
|
88
|
+
|
|
89
|
+
The box runs the released version of its slot and works with the library on the NAS. The web page and the user
|
|
90
|
+
documentation are English and German; code and developer documentation are English.
|
|
91
|
+
|
|
92
|
+
## 3. History
|
|
93
|
+
|
|
94
|
+
The first box was built for Christmas 2019: RFID, presence detection and four buttons, from the start. The
|
|
95
|
+
circuit and the printed parts are in [`hardware/`](https://github.com/tgd1975/tinyjukebox/blob/master/hardware/README.md); the software has been rebuilt several times
|
|
96
|
+
since. The [changelog](https://github.com/tgd1975/tinyjukebox/blob/master/CHANGELOG.md) tells the story from 2018 on.
|
|
97
|
+
|
|
98
|
+
| The lid on its circuit, December 2019 | The first box at work, a figure on the lid as tag |
|
|
99
|
+
| --- | --- |
|
|
100
|
+
| <img src="docs/images/lid-on-circuit-2019.jpg" alt="The wired lid with the LED on, lying on the printed circuit next to the Pi" width="360"> | <img src="docs/images/box-open-figure-2019.jpg" alt="The first box with its back open and a figure standing on the lid" width="270"> |
|
|
101
|
+
|
|
102
|
+
The hardware has changed as well, while the box stayed in use:
|
|
103
|
+
|
|
104
|
+
| Inside in 2019: Pi Zero, separate amplifier, power bank | Inside today: Pi 3 with the Audio Amp SHIM, power bank |
|
|
105
|
+
| --- | --- |
|
|
106
|
+
| <img src="docs/images/inside-2019.jpg" alt="The inside of the first box: a Pi Zero on the right wall, a separate amplifier on the left, the speaker in the middle, rainbow ribbon cables and the power bank in a black frame at the bottom" width="360"> | <img src="docs/images/inside-2026.jpg" alt="The inside of the box today, from the back: the Pi 3 with the Audio Amp SHIM on the left wall, the speaker in the middle, the power bank in its frame below, the open back panel with the USB socket and the switch" width="360"> |
|
|
107
|
+
|
|
108
|
+
## 4. Documentation
|
|
109
|
+
|
|
110
|
+
All documents as one site, with search and a menu by reader: <https://tgd1975.github.io/tinyjukebox/>.
|
|
111
|
+
|
|
112
|
+
### 4.1 For users and administrators (English and German)
|
|
113
|
+
|
|
114
|
+
| Document | Content |
|
|
115
|
+
| --- | --- |
|
|
116
|
+
| Quick guide: [English](https://github.com/tgd1975/tinyjukebox/blob/master/docs/user/en/quick-guide.md), [Deutsch](https://github.com/tgd1975/tinyjukebox/blob/master/docs/user/de/quick-guide.md) | text of the quick guide card (A6, two sides): tags, buttons, LED, headset; web page |
|
|
117
|
+
| Manual: [English](https://github.com/tgd1975/tinyjukebox/blob/master/docs/user/en/manual.md), [Deutsch](https://github.com/tgd1975/tinyjukebox/blob/master/docs/user/de/manual.md) | the full manual: operating the box, LED, pause, Bluetooth headset, web page, MP3 albums, radio, Spotify, volume limits, users, troubleshooting, library |
|
|
118
|
+
| Administration: [English](https://github.com/tgd1975/tinyjukebox/blob/master/docs/user/en/admin.md), [Deutsch](https://github.com/tgd1975/tinyjukebox/blob/master/docs/user/de/admin.md) | setting up a box and the library, updates, users and access, backups, logs, configuration, troubleshooting – the complete details in the developer documents below |
|
|
119
|
+
|
|
120
|
+
### 4.2 For developers and hardware, the complete details for administrators (English)
|
|
121
|
+
|
|
122
|
+
| Document | Content |
|
|
123
|
+
| --- | --- |
|
|
124
|
+
| [Architecture](https://github.com/tgd1975/tinyjukebox/blob/master/docs/developer/architecture.md) | components, state machines, volume, player, headset logic, data model, messages, framework, threads, latency measurement |
|
|
125
|
+
| [Drivers](https://github.com/tgd1975/tinyjukebox/blob/master/docs/developer/drivers.md) | driver framework, buttons, LED, RFID driver, Bluetooth stack and driver |
|
|
126
|
+
| [rfid-reader](https://github.com/tgd1975/tinyjukebox/blob/master/docs/developer/rfid-reader.md) | the C++ program that reads the RC522: interface, read loop, design decisions, build, tests |
|
|
127
|
+
| [REST API and web page](https://github.com/tgd1975/tinyjukebox/blob/master/docs/developer/rest-api.md) | server, authentication, roles, endpoints, server-sent events |
|
|
128
|
+
| [Configuration](https://github.com/tgd1975/tinyjukebox/blob/master/docs/developer/configuration.md) | command line, all keys of the config file |
|
|
129
|
+
| [The box](https://github.com/tgd1975/tinyjukebox/blob/master/docs/developer/box.md) | hardware, pins, operating system, audio, file layout, service, robustness, decisions |
|
|
130
|
+
| [Library, synchronization and self-update](https://github.com/tgd1975/tinyjukebox/blob/master/docs/developer/library.md) | the library on the NAS or the PC with its package, synchronization of the boxes and phones, the phone as reader, self-update with slots, play statistics, release pipeline, test bed, tests |
|
|
131
|
+
| [The app](https://github.com/tgd1975/tinyjukebox/blob/master/docs/developer/app.md) | the app for Android phones: simple mode (a phone as a box), expert mode (the page of the library), pairing, presence of a tag, the cache of albums, Spotify, delivery, the code |
|
|
132
|
+
| [Deployment](https://github.com/tgd1975/tinyjukebox/blob/master/docs/developer/deployment.md) | how software and setup reach the box, Ansible playbook, roles, variables, first setup, updates, changes on the box, acceptance checklist |
|
|
133
|
+
| [Operations](https://github.com/tgd1975/tinyjukebox/blob/master/docs/developer/operations.md) | service, logs, users, albums, console, latency, diagnostics, backups |
|
|
134
|
+
| [Development](https://github.com/tgd1975/tinyjukebox/blob/master/docs/developer/development.md) | setup, the box on the PC, repository layout, dependencies, tests, quality checks, conventions, releases, the app, the documentation site |
|
|
135
|
+
| [Style guide](https://github.com/tgd1975/tinyjukebox/blob/master/docs/style-guide/README.md) | name, logo, colours, type, shapes, the light of the box, how the documents are written |
|
|
136
|
+
| [Open points and roadmap](https://github.com/tgd1975/tinyjukebox/blob/master/docs/developer/roadmap.md) | what is not verified yet, known gaps, envisioned changes |
|
|
137
|
+
|
|
138
|
+
Reference files: [example config](https://github.com/tgd1975/tinyjukebox/blob/master/docs/config.example.yaml), [config of the box](https://github.com/tgd1975/tinyjukebox/blob/master/deploy/config/tinyjukebox.yaml),
|
|
139
|
+
[config schema](https://github.com/tgd1975/tinyjukebox/blob/master/docs/config_schema.json). Hardware: [circuit and printed parts](https://github.com/tgd1975/tinyjukebox/blob/master/hardware/README.md),
|
|
140
|
+
[key data and data sheets](https://github.com/tgd1975/tinyjukebox/blob/master/docs/hardware/README.md).
|
|
141
|
+
|
|
142
|
+
## 5. Quick start
|
|
143
|
+
|
|
144
|
+
**A box:** write Raspberry Pi OS Lite (64-bit) with the Raspberry Pi Imager, log in over SSH and run
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
curl -fsSL https://github.com/tgd1975/tinyjukebox/releases/latest/download/install.sh | sudo bash
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
([deployment.md](https://github.com/tgd1975/tinyjukebox/blob/master/docs/developer/deployment.md), section 5). **Library and a box without hardware to try it,** with
|
|
151
|
+
Docker – the two passwords are files next to `compose.yaml`:
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
cd deploy/docker && openssl rand -hex 12 > admin-password && openssl rand -hex 24 > bootstrap-password
|
|
155
|
+
docker compose up -d # https://localhost:8866/ and https://localhost:8443/, user admin, the password in admin-password
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
or with Python: `pip install tinyjukebox`, then `tinyjukebox-library --data ~/library` and
|
|
159
|
+
`tinyjukebox --data ~/box --no-hardware --no-audio` ([library.md](https://github.com/tgd1975/tinyjukebox/blob/master/docs/developer/library.md), section 3.9).
|
|
160
|
+
|
|
161
|
+
**Development**, on the PC, without hardware:
|
|
162
|
+
|
|
163
|
+
```bash
|
|
164
|
+
uv sync --all-groups
|
|
165
|
+
cp docs/config.example.yaml my-config.yaml # adjust the paths
|
|
166
|
+
uv run tinyjukebox -c my-config.yaml --no-hardware --no-audio # web page: https://localhost:8443/
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
Checks:
|
|
170
|
+
|
|
171
|
+
```bash
|
|
172
|
+
uv run pytest --cov # tests (need ffmpeg; no sound card, no Pi hardware)
|
|
173
|
+
uv run ruff format --check . && uv run ruff check . && uv run mypy
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
Library and box on the PC: `./start_library.sh` and `./start_sim.sh`
|
|
177
|
+
([library.md](https://github.com/tgd1975/tinyjukebox/blob/master/docs/developer/library.md), section 3.8).
|
|
178
|
+
|
|
179
|
+
Bring a change to the box: raise the version, add a section to `CHANGELOG.md`, push to `master`. The workflow
|
|
180
|
+
publishes the release and the box installs it by itself ([development.md](https://github.com/tgd1975/tinyjukebox/blob/master/docs/developer/development.md),
|
|
181
|
+
section 8). System setup and config of our box come from the playbook, which runs the installer of the clone:
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
./update_box.sh
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
Prerequisite: [uv](https://docs.astral.sh/uv/). The project uses Python 3.13 (package: ≥ 3.11).
|
|
188
|
+
|
|
189
|
+
## 6. Licence
|
|
190
|
+
|
|
191
|
+
The code of this repository is under the MIT licence ([`LICENSE.txt`](https://github.com/tgd1975/tinyjukebox/blob/master/LICENSE.txt)); for the circuit see
|
|
192
|
+
[`hardware/README.md`](https://github.com/tgd1975/tinyjukebox/blob/master/hardware/README.md).
|
|
193
|
+
|
|
194
|
+
**The files of a release contain software of others** that is not in the repository: the slot archive for the boxes
|
|
195
|
+
(`tinyjukebox-box-…`), the package of the library for the NAS (`tinyjukebox-library-…`), which brings a slot and the
|
|
196
|
+
app along, and the app for phones (`tinyjukebox-app-…`).
|
|
197
|
+
|
|
198
|
+
| Software | In | Licence |
|
|
199
|
+
| --- | --- | --- |
|
|
200
|
+
| Python ([python-build-standalone](https://github.com/astral-sh/python-build-standalone)) | slot | PSF-2.0; the libraries built into it have their own licences |
|
|
201
|
+
| mutagen | slot, package | **GPL-2.0-or-later** |
|
|
202
|
+
| jsonschema with attrs, referencing, rpds-py and jsonschema-specifications; PyYAML | slot, package | MIT |
|
|
203
|
+
| tantamount, asyncscheduler (our own) | slot, package | MIT |
|
|
204
|
+
| segno | slot, package | BSD-3-Clause |
|
|
205
|
+
| Kotlin standard library, kotlinx.serialization; AndroidX (core, activity, webkit and what they need); Media3 (ExoPlayer, session) with Guava; ZXing and ZXing Android Embedded; Spotify App Remote SDK (fetched from Spotify's release on GitHub, checked by its checksum) with Gson | app | Apache-2.0 |
|
|
206
|
+
| typing-extensions | package | PSF-2.0 |
|
|
207
|
+
| dbus-fast | slot | MIT |
|
|
208
|
+
| rpi-lgpio | slot | BSD-3-Clause |
|
|
209
|
+
| lgpio | slot | Unlicense (public domain) |
|
|
210
|
+
| pyalsaaudio | slot | PSF-2.0 |
|
|
211
|
+
| bcm2835, linked into `rfid-reader` | slot | **GPL-3.0** |
|
|
212
|
+
| RPi-MFRC522, compiled into `rfid-reader` | slot | Unlicense (public domain) |
|
|
213
|
+
|
|
214
|
+
Python and the Python packages of others bring their licence texts along (`python/lib/python3.13/LICENSE.txt`, the
|
|
215
|
+
folders `*.dist-info/licenses/`); those of bcm2835 and RPi-MFRC522 are in the slot next to `rfid-reader`
|
|
216
|
+
(`bin/rfid-reader-licenses/`); the app shows the Apache licence in its settings. `app/gradle/libs.versions.toml` names
|
|
217
|
+
the libraries of the app and their versions. The sources: `uv.lock` names the Python packages and their versions,
|
|
218
|
+
`deploy/ansible/group_vars/all/main.yaml` the versions of bcm2835 and RPi-MFRC522 and where they come from,
|
|
219
|
+
`cpp/rfid-reader/` is the source of `rfid-reader` itself. This is a description, not a legal opinion.
|
|
220
|
+
|
|
221
|
+
## 7. Repository
|
|
222
|
+
|
|
223
|
+
| Folder | Content |
|
|
224
|
+
| --- | --- |
|
|
225
|
+
| `src/tinyjukebox/`, `tests/` | the application and its tests |
|
|
226
|
+
| `app/` | the app for Android phones (Kotlin, Gradle): a phone as a box, and the page of the library ([docs/developer/app.md](https://github.com/tgd1975/tinyjukebox/blob/master/docs/developer/app.md)) |
|
|
227
|
+
| `cpp/rfid-reader/` | the RFID reader program of the box (C++), built with the slot of a release; `licenses/` holds the licence texts of the two libraries it is built with |
|
|
228
|
+
| `deploy/` | config, service units, the slot scripts of a box, the Ansible playbook that sets up the box, the package of the library for the NAS |
|
|
229
|
+
| `scripts/` | builds the slot, the installer, the image and the app of a release, the steps of the workflow, checks of both web pages, the documentation site (`site/`), `trust.sh` (the keys of DSM and of the library that the scripts on the PC accept) |
|
|
230
|
+
| `*.sh` in the root | `start_sim.sh`, `start_library.sh` (box and library on the PC), `update_box.sh` (playbook), `build_package.sh`, `fetch_release.sh`, `update_library.sh` (the package onto the NAS), `release.sh` (push, merge, install), `import_covers.sh` |
|
|
231
|
+
| `docs/` | documentation; `docs/hardware/` holds the key data of the components and the links to their data sheets, `docs/images/` the photos of the box and the logo |
|
|
232
|
+
| `hardware/` | the circuit of the box and printed parts |
|
|
233
|
+
|
|
234
|
+
The repository holds everything that belongs to the box and changes together. It has one version number
|
|
235
|
+
(`pyproject.toml`), set as git tag `vX.Y.Z`. What is deliberately not in the repository is listed in
|
|
236
|
+
[development.md](https://github.com/tgd1975/tinyjukebox/blob/master/docs/developer/development.md), section 3.
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
<picture>
|
|
2
|
+
<source media="(prefers-color-scheme: dark)" srcset="docs/images/logo-dark.svg">
|
|
3
|
+
<img src="docs/images/logo.svg" alt="Tiny Jukebox" width="460">
|
|
4
|
+
</picture>
|
|
5
|
+
|
|
6
|
+
RFID-controlled music box for children: put a tag (a disc, a figure, a card – anything with an RFID chip) on the box,
|
|
7
|
+
and the linked album continues where it stopped last time. The tag is only ever read, never written; the UID is all
|
|
8
|
+
that counts.
|
|
9
|
+
|
|
10
|
+
<img src="docs/images/box-2026.jpg" alt="The box today: a white wooden case with a grille of rings at the front, on top the round lid with buttons, LED and a tag in its window" width="360">
|
|
11
|
+
|
|
12
|
+
## 1. What Tiny Jukebox does especially well
|
|
13
|
+
|
|
14
|
+
- **One library, any number of boxes.** `tinyjukebox-library` runs on a NAS or the PC and holds the tags, albums,
|
|
15
|
+
radio stations and covers. Every box keeps a copy, fetches the albums it lacks, plays without the library,
|
|
16
|
+
and the library shows what was played.
|
|
17
|
+
- **Updates with a way back.** A push to `master` that changes the software becomes a release. The library
|
|
18
|
+
fetches it, a box tries the new version at its next start and goes back to the one before by itself if it fails.
|
|
19
|
+
- **Set up with one line, run like an appliance.** One line on a fresh Raspberry Pi OS turns it into a box – fetched
|
|
20
|
+
from GitHub, or from the page of the library, which links the box to it at once. The library is a package for a
|
|
21
|
+
Synology NAS, a Docker image or `pip install`. Backups run by a schedule, users and roles are managed on the web
|
|
22
|
+
page.
|
|
23
|
+
- **Everything on one web page.** Link tags (also by scanning them with a phone), upload albums, set radio
|
|
24
|
+
stations and volume limits, change covers – over HTTPS, in English and German, with a REST API behind it.
|
|
25
|
+
- **Bluetooth headset as a first-class way to listen.** Pairing with a button gesture, own start volume and maximum,
|
|
26
|
+
pause when the connection is lost, headset buttons.
|
|
27
|
+
- **Reads reliably.** The RC522 is read by a small C++ program that recovers by itself after a crash or a reset of
|
|
28
|
+
the chip, and playback keeps its position over a power cut.
|
|
29
|
+
- **Spotify and phones, built but not yet tried for real.** A tag can also play an entry of Spotify – an album, a
|
|
30
|
+
playlist, a podcast – through Spotify Soloist, and the app for Android makes a phone a box
|
|
31
|
+
([app.md](docs/developer/app.md)). Spotify is tested on the PC and has not played on a box yet; the app ran in the
|
|
32
|
+
Android emulator, not yet on a real phone ([roadmap.md](docs/developer/roadmap.md), section 1).
|
|
33
|
+
|
|
34
|
+
## 2. Software and hardware
|
|
35
|
+
|
|
36
|
+
The software is one Python process (one systemd service) with device drivers, state machines, player and web page
|
|
37
|
+
that exchange messages over an in-process queue – no broker, no further services. State machines run tags, album
|
|
38
|
+
playback, radio, Spotify and volume. Playback is `ffmpeg | aplay`: the position is saved, with next/previous, pause and
|
|
39
|
+
internet radio stations. An entry of Spotify plays through Spotify Soloist, which the box starts with a PipeWire of
|
|
40
|
+
its own; its sound goes to `aplay` as well. The app for Android phones (`app/`, Kotlin) makes a phone a box: it reads
|
|
41
|
+
the tag with NFC and plays its album or station with the data of the library ([app.md](docs/developer/app.md)).
|
|
42
|
+
|
|
43
|
+
**The software does not need a Raspberry Pi or a particular amplifier.** Our own box happens to be a Raspberry Pi 3
|
|
44
|
+
with an RC522, four buttons, an RGB LED and a Pimoroni Audio Amp SHIM; that is the platform we built and tested, not a
|
|
45
|
+
requirement of the application.
|
|
46
|
+
|
|
47
|
+
- **Sound:** any ALSA device and mixer control, set in the config. The Audio Amp SHIM is not mentioned in the code.
|
|
48
|
+
- **Core:** state machines, player, web page, REST API and library are plain Python on Linux; they run on a PC
|
|
49
|
+
without any hardware (`--no-hardware`), which is also how the tests run.
|
|
50
|
+
- **Drivers:** buttons, LED, RFID reader and Bluetooth are drivers selected and wired in the config
|
|
51
|
+
([drivers.md](docs/developer/drivers.md)); the pins are config, not code.
|
|
52
|
+
- **RFID reader:** the driver starts any program that prints `ready`, `tag <UID>` and `removed`, one per line
|
|
53
|
+
([rfid-reader.md](docs/developer/rfid-reader.md)). The C++ `rfid-reader` for the RC522 on a Raspberry Pi is the one
|
|
54
|
+
we ship; another reader or another board needs only such a program and the `command` of the driver.
|
|
55
|
+
- **What is tied to the Pi today:** the shipped GPIO drivers (`rpi-lgpio`) and `rfid-reader` (SPI through bcm2835).
|
|
56
|
+
Bluetooth uses BlueZ and BlueALSA, which are not specific to the Pi.
|
|
57
|
+
|
|
58
|
+
The box runs the released version of its slot and works with the library on the NAS. The web page and the user
|
|
59
|
+
documentation are English and German; code and developer documentation are English.
|
|
60
|
+
|
|
61
|
+
## 3. History
|
|
62
|
+
|
|
63
|
+
The first box was built for Christmas 2019: RFID, presence detection and four buttons, from the start. The
|
|
64
|
+
circuit and the printed parts are in [`hardware/`](hardware/README.md); the software has been rebuilt several times
|
|
65
|
+
since. The [changelog](CHANGELOG.md) tells the story from 2018 on.
|
|
66
|
+
|
|
67
|
+
| The lid on its circuit, December 2019 | The first box at work, a figure on the lid as tag |
|
|
68
|
+
| --- | --- |
|
|
69
|
+
| <img src="docs/images/lid-on-circuit-2019.jpg" alt="The wired lid with the LED on, lying on the printed circuit next to the Pi" width="360"> | <img src="docs/images/box-open-figure-2019.jpg" alt="The first box with its back open and a figure standing on the lid" width="270"> |
|
|
70
|
+
|
|
71
|
+
The hardware has changed as well, while the box stayed in use:
|
|
72
|
+
|
|
73
|
+
| Inside in 2019: Pi Zero, separate amplifier, power bank | Inside today: Pi 3 with the Audio Amp SHIM, power bank |
|
|
74
|
+
| --- | --- |
|
|
75
|
+
| <img src="docs/images/inside-2019.jpg" alt="The inside of the first box: a Pi Zero on the right wall, a separate amplifier on the left, the speaker in the middle, rainbow ribbon cables and the power bank in a black frame at the bottom" width="360"> | <img src="docs/images/inside-2026.jpg" alt="The inside of the box today, from the back: the Pi 3 with the Audio Amp SHIM on the left wall, the speaker in the middle, the power bank in its frame below, the open back panel with the USB socket and the switch" width="360"> |
|
|
76
|
+
|
|
77
|
+
## 4. Documentation
|
|
78
|
+
|
|
79
|
+
All documents as one site, with search and a menu by reader: <https://tgd1975.github.io/tinyjukebox/>.
|
|
80
|
+
|
|
81
|
+
### 4.1 For users and administrators (English and German)
|
|
82
|
+
|
|
83
|
+
| Document | Content |
|
|
84
|
+
| --- | --- |
|
|
85
|
+
| Quick guide: [English](docs/user/en/quick-guide.md), [Deutsch](docs/user/de/quick-guide.md) | text of the quick guide card (A6, two sides): tags, buttons, LED, headset; web page |
|
|
86
|
+
| Manual: [English](docs/user/en/manual.md), [Deutsch](docs/user/de/manual.md) | the full manual: operating the box, LED, pause, Bluetooth headset, web page, MP3 albums, radio, Spotify, volume limits, users, troubleshooting, library |
|
|
87
|
+
| Administration: [English](docs/user/en/admin.md), [Deutsch](docs/user/de/admin.md) | setting up a box and the library, updates, users and access, backups, logs, configuration, troubleshooting – the complete details in the developer documents below |
|
|
88
|
+
|
|
89
|
+
### 4.2 For developers and hardware, the complete details for administrators (English)
|
|
90
|
+
|
|
91
|
+
| Document | Content |
|
|
92
|
+
| --- | --- |
|
|
93
|
+
| [Architecture](docs/developer/architecture.md) | components, state machines, volume, player, headset logic, data model, messages, framework, threads, latency measurement |
|
|
94
|
+
| [Drivers](docs/developer/drivers.md) | driver framework, buttons, LED, RFID driver, Bluetooth stack and driver |
|
|
95
|
+
| [rfid-reader](docs/developer/rfid-reader.md) | the C++ program that reads the RC522: interface, read loop, design decisions, build, tests |
|
|
96
|
+
| [REST API and web page](docs/developer/rest-api.md) | server, authentication, roles, endpoints, server-sent events |
|
|
97
|
+
| [Configuration](docs/developer/configuration.md) | command line, all keys of the config file |
|
|
98
|
+
| [The box](docs/developer/box.md) | hardware, pins, operating system, audio, file layout, service, robustness, decisions |
|
|
99
|
+
| [Library, synchronization and self-update](docs/developer/library.md) | the library on the NAS or the PC with its package, synchronization of the boxes and phones, the phone as reader, self-update with slots, play statistics, release pipeline, test bed, tests |
|
|
100
|
+
| [The app](docs/developer/app.md) | the app for Android phones: simple mode (a phone as a box), expert mode (the page of the library), pairing, presence of a tag, the cache of albums, Spotify, delivery, the code |
|
|
101
|
+
| [Deployment](docs/developer/deployment.md) | how software and setup reach the box, Ansible playbook, roles, variables, first setup, updates, changes on the box, acceptance checklist |
|
|
102
|
+
| [Operations](docs/developer/operations.md) | service, logs, users, albums, console, latency, diagnostics, backups |
|
|
103
|
+
| [Development](docs/developer/development.md) | setup, the box on the PC, repository layout, dependencies, tests, quality checks, conventions, releases, the app, the documentation site |
|
|
104
|
+
| [Style guide](docs/style-guide/README.md) | name, logo, colours, type, shapes, the light of the box, how the documents are written |
|
|
105
|
+
| [Open points and roadmap](docs/developer/roadmap.md) | what is not verified yet, known gaps, envisioned changes |
|
|
106
|
+
|
|
107
|
+
Reference files: [example config](docs/config.example.yaml), [config of the box](deploy/config/tinyjukebox.yaml),
|
|
108
|
+
[config schema](docs/config_schema.json). Hardware: [circuit and printed parts](hardware/README.md),
|
|
109
|
+
[key data and data sheets](docs/hardware/README.md).
|
|
110
|
+
|
|
111
|
+
## 5. Quick start
|
|
112
|
+
|
|
113
|
+
**A box:** write Raspberry Pi OS Lite (64-bit) with the Raspberry Pi Imager, log in over SSH and run
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
curl -fsSL https://github.com/tgd1975/tinyjukebox/releases/latest/download/install.sh | sudo bash
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
([deployment.md](docs/developer/deployment.md), section 5). **Library and a box without hardware to try it,** with
|
|
120
|
+
Docker – the two passwords are files next to `compose.yaml`:
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
cd deploy/docker && openssl rand -hex 12 > admin-password && openssl rand -hex 24 > bootstrap-password
|
|
124
|
+
docker compose up -d # https://localhost:8866/ and https://localhost:8443/, user admin, the password in admin-password
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
or with Python: `pip install tinyjukebox`, then `tinyjukebox-library --data ~/library` and
|
|
128
|
+
`tinyjukebox --data ~/box --no-hardware --no-audio` ([library.md](docs/developer/library.md), section 3.9).
|
|
129
|
+
|
|
130
|
+
**Development**, on the PC, without hardware:
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
uv sync --all-groups
|
|
134
|
+
cp docs/config.example.yaml my-config.yaml # adjust the paths
|
|
135
|
+
uv run tinyjukebox -c my-config.yaml --no-hardware --no-audio # web page: https://localhost:8443/
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Checks:
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
uv run pytest --cov # tests (need ffmpeg; no sound card, no Pi hardware)
|
|
142
|
+
uv run ruff format --check . && uv run ruff check . && uv run mypy
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Library and box on the PC: `./start_library.sh` and `./start_sim.sh`
|
|
146
|
+
([library.md](docs/developer/library.md), section 3.8).
|
|
147
|
+
|
|
148
|
+
Bring a change to the box: raise the version, add a section to `CHANGELOG.md`, push to `master`. The workflow
|
|
149
|
+
publishes the release and the box installs it by itself ([development.md](docs/developer/development.md),
|
|
150
|
+
section 8). System setup and config of our box come from the playbook, which runs the installer of the clone:
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
./update_box.sh
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
Prerequisite: [uv](https://docs.astral.sh/uv/). The project uses Python 3.13 (package: ≥ 3.11).
|
|
157
|
+
|
|
158
|
+
## 6. Licence
|
|
159
|
+
|
|
160
|
+
The code of this repository is under the MIT licence ([`LICENSE.txt`](LICENSE.txt)); for the circuit see
|
|
161
|
+
[`hardware/README.md`](hardware/README.md).
|
|
162
|
+
|
|
163
|
+
**The files of a release contain software of others** that is not in the repository: the slot archive for the boxes
|
|
164
|
+
(`tinyjukebox-box-…`), the package of the library for the NAS (`tinyjukebox-library-…`), which brings a slot and the
|
|
165
|
+
app along, and the app for phones (`tinyjukebox-app-…`).
|
|
166
|
+
|
|
167
|
+
| Software | In | Licence |
|
|
168
|
+
| --- | --- | --- |
|
|
169
|
+
| Python ([python-build-standalone](https://github.com/astral-sh/python-build-standalone)) | slot | PSF-2.0; the libraries built into it have their own licences |
|
|
170
|
+
| mutagen | slot, package | **GPL-2.0-or-later** |
|
|
171
|
+
| jsonschema with attrs, referencing, rpds-py and jsonschema-specifications; PyYAML | slot, package | MIT |
|
|
172
|
+
| tantamount, asyncscheduler (our own) | slot, package | MIT |
|
|
173
|
+
| segno | slot, package | BSD-3-Clause |
|
|
174
|
+
| Kotlin standard library, kotlinx.serialization; AndroidX (core, activity, webkit and what they need); Media3 (ExoPlayer, session) with Guava; ZXing and ZXing Android Embedded; Spotify App Remote SDK (fetched from Spotify's release on GitHub, checked by its checksum) with Gson | app | Apache-2.0 |
|
|
175
|
+
| typing-extensions | package | PSF-2.0 |
|
|
176
|
+
| dbus-fast | slot | MIT |
|
|
177
|
+
| rpi-lgpio | slot | BSD-3-Clause |
|
|
178
|
+
| lgpio | slot | Unlicense (public domain) |
|
|
179
|
+
| pyalsaaudio | slot | PSF-2.0 |
|
|
180
|
+
| bcm2835, linked into `rfid-reader` | slot | **GPL-3.0** |
|
|
181
|
+
| RPi-MFRC522, compiled into `rfid-reader` | slot | Unlicense (public domain) |
|
|
182
|
+
|
|
183
|
+
Python and the Python packages of others bring their licence texts along (`python/lib/python3.13/LICENSE.txt`, the
|
|
184
|
+
folders `*.dist-info/licenses/`); those of bcm2835 and RPi-MFRC522 are in the slot next to `rfid-reader`
|
|
185
|
+
(`bin/rfid-reader-licenses/`); the app shows the Apache licence in its settings. `app/gradle/libs.versions.toml` names
|
|
186
|
+
the libraries of the app and their versions. The sources: `uv.lock` names the Python packages and their versions,
|
|
187
|
+
`deploy/ansible/group_vars/all/main.yaml` the versions of bcm2835 and RPi-MFRC522 and where they come from,
|
|
188
|
+
`cpp/rfid-reader/` is the source of `rfid-reader` itself. This is a description, not a legal opinion.
|
|
189
|
+
|
|
190
|
+
## 7. Repository
|
|
191
|
+
|
|
192
|
+
| Folder | Content |
|
|
193
|
+
| --- | --- |
|
|
194
|
+
| `src/tinyjukebox/`, `tests/` | the application and its tests |
|
|
195
|
+
| `app/` | the app for Android phones (Kotlin, Gradle): a phone as a box, and the page of the library ([docs/developer/app.md](docs/developer/app.md)) |
|
|
196
|
+
| `cpp/rfid-reader/` | the RFID reader program of the box (C++), built with the slot of a release; `licenses/` holds the licence texts of the two libraries it is built with |
|
|
197
|
+
| `deploy/` | config, service units, the slot scripts of a box, the Ansible playbook that sets up the box, the package of the library for the NAS |
|
|
198
|
+
| `scripts/` | builds the slot, the installer, the image and the app of a release, the steps of the workflow, checks of both web pages, the documentation site (`site/`), `trust.sh` (the keys of DSM and of the library that the scripts on the PC accept) |
|
|
199
|
+
| `*.sh` in the root | `start_sim.sh`, `start_library.sh` (box and library on the PC), `update_box.sh` (playbook), `build_package.sh`, `fetch_release.sh`, `update_library.sh` (the package onto the NAS), `release.sh` (push, merge, install), `import_covers.sh` |
|
|
200
|
+
| `docs/` | documentation; `docs/hardware/` holds the key data of the components and the links to their data sheets, `docs/images/` the photos of the box and the logo |
|
|
201
|
+
| `hardware/` | the circuit of the box and printed parts |
|
|
202
|
+
|
|
203
|
+
The repository holds everything that belongs to the box and changes together. It has one version number
|
|
204
|
+
(`pyproject.toml`), set as git tag `vX.Y.Z`. What is deliberately not in the repository is listed in
|
|
205
|
+
[development.md](docs/developer/development.md), section 3.
|