Coder Social home page Coder Social logo

radiorabe / klangbecken Goto Github PK

View Code? Open in Web Editor NEW
11.0 6.0 5.0 4.54 MB

Klangbecken: The RaBe Endless Music Player

Home Page: https://rabe.ch/klangbecken/

License: GNU Affero General Public License v3.0

Python 97.64% Shell 2.36%
liquidsoap radio python

klangbecken's Introduction

Klangbecken

Python package Liquidsoap script Code Style Black

Klangbecken is the minimalistic endless music player for Radio Bern RaBe based on liquidsoap.

It supports configurable and editable playlists, jingle insertion, metadata publishing and more.

It is designed for stand-alone operation, robustness and good maintainability. All data is stored in common files in a single data directory.

This repository contains three components of the RaBe Klangbecken:

Two additional components are in their own repository:

How they interact can be seen in the system overview diagram:

System overview diagram

System requirements

  • Unix-like operating system environment
  • Python (>= v3.9)
    • docopt library for parsing command line arguments
    • Werkzeug library (>= v2.0) for WSGI support
    • PyJWT library (>= v2.0) for creating and verifying JWT authentication tokens
    • mutagen library for audio tag editing
  • ffmpeg binary (>= v2.8) for audio analysis
  • Liquidsoap audio player (v1.3 without inotify support)

Local Setup

Fork this repository and clone it from there:

git clone https://github.com/YOUR-GITHUB-USERNAME/klangbecken.git
cd klangbecken

Create a virtual environment (also see additional tools):

python -m venv .venv
source .venv/bin/activate

Install dependencies

Install Python dependencies:

pip install -r requirements.txt

Install ffmpeg with your system's package manager. E.g.:

yum install ffmpeg

Install Liquidsoap (Note: On CentOS 7 you can also use our prebuilt package):

yum install opam
opam init
# we need liquidsoap 1.3.7 which does not run after OCaml 4.07.0
opam switch create klangbecken 4.07.0
opam depext alsa mad lame vorbis taglib liquidsoap.1.3.7
opam install alsa mad lame vorbis taglib liquidsoap.1.3.7
eval $(opam env)

Install the client UI:

cd ..
git clone https://github.com/radiorabe/klangbecken-ui
cd klangbecken-ui
npm install

Run the programs

Initialize the data directory:

python -m klangbecken init

Run the development back-end server (API and data directory):

python -m klangbecken serve

Run the client development server (user interface):

cd ../klangbecken-ui
npm run serve

Browse to http://localhost:8080 and start uploading audio files.

Run the liquidsoap audio player:

eval $(opam env)
liquidsoap klangbecken.liq

Manually set the on-air status of the player using netcat:

echo "klangbecken.on_air True" | nc -U -w 1 klangbecken.sock

Development

For contributing to this project, fork this repository, and clone your local working copy from your personal fork. Push commits to your repository to create pull requests with your changes.

Python Package

The Python code is tested with a test suite and follows the flake8 coding guidelines.

Before submitting your code you might want to make sure that ...

  1. ... you have installed the test dependencies

    pip install -r requirements-test.txt
  2. ... the test suite runs without failure

    python -m unittest discover
  3. ... all your code is covered by (hopefully) meaningful unit tests

    coverage run -m unittest discover
    coverage report
  4. ... your code follows the coding style guidelines

    flake8

Recommended Tools (optional)

We recommend the use of tox, black and isort for development.

pip install tox black isort
tox

Instead of running all the above commands manually, tox lets you run them all at once for all installed Python versions. Make sure to have at least the Python version installed, that is used in production (currently Python 3.9). tox is also what we use in continuos integration, so using it locally helps you to make your code pass it. To call it simply type:

tox
black

Manually fixing coding style mistakes is a pain. black formats your code automatically.

black .
isort

Finally, isort helps to consistently organize package imports.

isort .

All development tools are preconfigured in setup.cfg. For additional tools and tips & tricks and see additional tools.

Liquidsoap Script

Liquidsoap lets you syntax check and type check your script:

liquidsoap --check klangbecken.liq

Simulation

Apart from type checking, the inherent nature of the liquidsoap language generating a live audio stream makes it difficult to test the code with unit tests. Observing the behavior of the player script and the effects of changes in real-time take lot of time, usually weeks or even months. Accelerated simulation runs help to observe the long-time player behavior in a reasonable amount of time.

Deployment

Your code has passed continuous integration, and your pull request has been accepted. Now you want to deploy your (or somebody else's) code to production. First, some preparations are necessary, but then the deployment script deploy.sh automates most of the work deploying the code.

Preparations before deploying for the first time:

  • Make sure that you have access to the production server (e.g. SSH publik key authentication).
  • Configure a remote prod pointing at the repository on the production system:
    git add remote prod root@YOUR_PRODUCTION_VM_NAME:klangbecken.git
  • Optional: Install the Apache development libraries locally. E.g.:
    yum install httpd-devel
  • Configure a remote repository upstream pointing at the upstream repository:
    git remote add upstream [email protected]:radiorabe/klangbecken-ui.git
  • Configure git to automatically fetch tags from upstream:
    git config remote.upstream.tagOpt --tags

Preparation before deploying:

  • When deploying both, the front-end and the back-end app, deploy the front-end first.
  • Check again that the code you want to deploy passed continuous integration.
  • Make sure that your working directory is clean, and that you are on the master branch:
    git stash
    git checkout master
  • Bring your code in sync with the latest version from upstream:
    git fetch upstream
    git rebase upstream/master
  • Verify that you are indeed in sync with upstream:
    git show --no-patch

Run the script:

./deploy.sh [--no-mod-wsgi]

It performs the following steps:

  • Increment and commit a new version number.
  • Download all run-time dependencies.
  • Optionally download mod_wsgi (Requires httpd-devel libraries to be installed locally. Use --no-mod-wsgi to skip this step).
  • Copy the dependencies to production.
  • Push your code to production.
  • Install all dependencies in production.
  • Install the Python package (API and CLI) in production.
  • Reload the web server to load the new API code.
  • Copy the liquidsoap script to it's destination.
  • If everything was successful, tag the current commit with the new version number, and push it to the upstream repository.

Finalize deployment:

  • If the liquidsoap script klangbecken.liq changed, restart the liquidsoap player during an "off air" moment:
    systemctl restart liquidsoap@klangbecken

For detailed information on how to setup a productive server see Deployment.

License

Klangbecken is released under the terms of the GNU Affero General Public License. Copyright 2017-2022 Radio Bern RaBe. See LICENSE for further information.

klangbecken's People

Contributors

dependabot[bot] avatar hairmare avatar konradm avatar renovate-bot avatar renovate[bot] avatar smlz avatar spameier avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

klangbecken's Issues

Audio stockt wenn upload oder lösch i/o passiert

Also ich habe nun eine Track (Nattali Rize - Heart of a Lion) hochgeladen (zwischen 13:57 / 13:58) - nachdem Hochladen hat das Klangbecken gestottert - leider gut hörbar.

Danach habe ich den Track wieder gelöscht (13:58) und das Klangbecken hat nochmals gestottert - auch wieder hörbar.

Ich hab mal die SystemD units von liquidsoap angeschaut, das sollte eig oberste prio haben ist aber so:

[Service]
IOSchedulingClass=best-effort
IOSchedulingPriority=1
CPUSchedulingPolicy=rr
CPUSchedulingPriority=1

Aufgrund von @paraenggu's Input hab ich mir dann auch noch rotter auf einer rec-* node angeschaut (da hatten wir scheinbar das Problem auch aber es wurde dann gelöst) das scheint mir allerdings gans anders zu sein:

[Service]
# According to /etc/security/limits.d/95-jack.conf
LimitRTPRIO=70
LimitMEMLOCK=128M

Ich denke mir, dass ich gerne folgende Anpassungen machen würde:

[Service]
IOSchedulingClass=realtime
IOSchedulingPriority=0

Vielleicht macht es auch Sinn an der CPUSchedulingPolicy noch was zu ändern, da ist mir allerdings anhand von https://man7.org/linux/man-pages/man2/sched_setscheduler.2.html unklar ob "other", "batch" oder "fifo" mehr sinn machen.

Mir ist auch unklar ob/was LimitRTPRIO und LimitMEMLOCK machen und ob wir die auch wollen beim liquidsoap. Liquidsoap ist eher read lastig und rotter schreibt andauernd.

Daran was schrauben können wir während einem nicht-Klangbecken Fenster jederzeit... Ich passe mal süferli die IOSchedulingPriority während dem Grooveexress an und teste dann nach 22:00 Uhr mal obs nicht mehr stockt.

Getting connection timeouts when connecting to liquidsoap process

Getting timeouts:

Exception: <class 'ConnectionError'> Timeout while trying to read from player. Got no answer. <traceback object at 0x7f33a8841740>
ERROR ConnectionError: Timeout while trying to read from player. Got no answer.
Traceback (most recent call last):
  File "/usr/local/venvs/klangbecken-py39/lib/python3.9/site-packages/klangbecken/api_utils.py", line 201, in __call__
   response = endpoint(request, **values)
  File "/usr/local/venvs/klangbecken-py39/lib/python3.9/site-packages/klangbecken/api_utils.py", line 269, in wrapper
    return func(request, *args, **kwargs)
  File "/usr/local/venvs/klangbecken-py39/lib/python3.9/site-packages/klangbecken/api.py", line 178, in queue_push
    queue_id = client.push(path)
  File "/usr/local/venvs/klangbecken-py39/lib/python3.9/site-packages/klangbecken/player.py", line 186, in push
    rid = self.command(f"queue.push {path}").strip()
  File "/usr/local/venvs/klangbecken-py39/lib/python3.9/site-packages/klangbecken/player.py", line 79, in command
    raise ConnectionError(
ConnectionError: Timeout while trying to read from player. Got no answer.

Error source of radiorabe/klangbecken-ui#534.

Use gstreamer for audio analysis

The silence analysis with ffmpeg is not very precise, and differs a lot in the various existing ffmpeg versions. Gstreamer offers more specific plugins, and seems to be more stable.

Python: enforce 100% code-coverage

We need to reach a 100% coverage before we can enforce it, but I think we should enforce it the next time we reach it. That way we are forced to now write anything without consideration.

Action Required: Fix Renovate Configuration

There is an error with this repository's Renovate configuration that needs to be fixed. As a precaution, Renovate will stop PRs until it is resolved.

Error type: undefined. Note: this is a nested preset so please contact the preset author if you are unable to fix it yourself.

Failed to prepare track: request not ready.

A playlist can get blocked. In the logs we find the following entry:

Aug 25 12:37:23 vm-0016.audio.int.rabe.ch liquidsoap[31847]: 2021/08/25 12:37:23 [music:1] Failed to prepare track: request not ready.

Apparently this happens, when a track gets deleted but liquidsoap fails to reload the playlist. See AzuraCast/AzuraCast#1415 and savonet/liquidsoap#735.

Changing the order of what happens first (deleting the file vs. updating the playlist file) in https://github.com/radiorabe/klangbecken/blob/master/klangbecken/playlist.py#L392-L399 might solve the problem.

depedabot is not updating werkzeug

There are the following entries in dependabot's logs

updater | INFO <job_277638052> Checking if werkzeug 2.0.1 needs updating
  proxy | 2022/02/08 19:18:42 [066] GET https://pypi.org:443/simple/werkzeug/
  proxy | 2022/02/08 19:18:42 [066] 200 https://pypi.org:443/simple/werkzeug/
updater | INFO <job_277638052> Latest version is 2.0.3
  proxy | 2022/02/08 19:18:42 [068] GET https://pypi.org:443/simple/werkzeug/
  proxy | 2022/02/08 19:18:42 [068] 200 https://pypi.org:443/simple/werkzeug/
updater | INFO <job_277638052> Requirements to unlock update_not_possible
updater | INFO <job_277638052> Requirements update strategy bump_versions
updater | INFO <job_277638052> No update possible for werkzeug 2.0.1

I'm failing to understand why it doesn feel like opening a pr for 2.03.

One possible reason could be the versioning-strategy in the config, since it was introduced in 0866776 dependabot didn't create a single PR.

# Maintain dependencies for pip
- package-ecosystem: "pip"
directory: "/"
schedule:
interval: "daily"
versioning-strategy: lockfile-only

cat-page seems to have picked up the werkzeug bump and it uses the default auto versioning-strategy via the following config:

  - package-ecosystem: pip
    directory: "/"
    schedule:
      interval: "daily"

The docs have this to say on the version strategy thing:

When Dependabot edits a manifest file to update a version, it uses the following overall strategies:

  • For apps, the version requirements are increased, for example: npm, pip and Composer.
  • For libraries, the range of versions is widened, for example: Bundler and Cargo.

Use the versioning-strategy option to change this behavior for supported package managers.

Option Supported by Action
lockfile-only bundler, cargo, composer, mix, npm, pip Only create pull requests to update lockfiles. Ignore any new versions that would require package manifest changes.
auto bundler, cargo, composer, mix, npm, pip Follow the default strategy described above.

In a python setuptools context, i'm not sure what lockfile-only wants to achieve. With npm or composer there is clearly a *.lock file that lockfile-only can work on. I'm not sure what i'm missing but i don't think we have a lockfile.

I'm gonna read some more docs, but i guess my proposal would be to switch to auto so we get updates like the werkzeug one that made me ralise that dependabot isn't pulling it's weight

Make deployments visible

It is currently not possible to see the state of the code in production here on GitHub. It would be nice if the deployment script automatically created a tag object and pushed it to our main repository.

Missing entries in playlog (string encoding issue)

Example: There is a gap between 13:12 and 13:20
image

In the logs we have:

Dez 12 13:16:53 vm-0016.audio.int.rabe.ch liquidsoap[4858]: Playing:
Dez 12 13:16:53 vm-0016.audio.int.rabe.ch liquidsoap[4858]: Playing: /var/lib/klangbecken/music/2c486a8a-b0d9-48e9-bc8d-231a04334662.mp3
Dez 12 13:16:54 vm-0016.audio.int.rabe.ch liquidsoap[4858]: Traceback (most recent call last):
Dez 12 13:16:54 vm-0016.audio.int.rabe.ch liquidsoap[4858]: File "/usr/local/venvs/klangbecken-py36/bin/klangbecken", line 11, in <module>
Dez 12 13:16:54 vm-0016.audio.int.rabe.ch liquidsoap[4858]: load_entry_point('klangbecken==0.0.12', 'console_scripts', 'klangbecken')()
Dez 12 13:16:54 vm-0016.audio.int.rabe.ch liquidsoap[4858]: File "/usr/local/venvs/klangbecken-py36/lib64/python3.6/site-packages/klangbecken.py", line 1133, in main
Dez 12 13:16:54 vm-0016.audio.int.rabe.ch liquidsoap[4858]: playlog_cmd(data_dir, args['FILE'][0], dev_mode=dev_mode)
Dez 12 13:16:54 vm-0016.audio.int.rabe.ch liquidsoap[4858]: File "/usr/local/venvs/klangbecken-py36/lib64/python3.6/site-packages/klangbecken.py", line 1034, in playlog_cmd
Dez 12 13:16:54 vm-0016.audio.int.rabe.ch liquidsoap[4858]: writer.writerow(entry)
Dez 12 13:16:54 vm-0016.audio.int.rabe.ch liquidsoap[4858]: File "/usr/lib64/python3.6/csv.py", line 155, in writerow
Dez 12 13:16:54 vm-0016.audio.int.rabe.ch liquidsoap[4858]: return self.writer.writerow(self._dict_to_list(rowdict))
Dez 12 13:16:54 vm-0016.audio.int.rabe.ch liquidsoap[4858]: UnicodeEncodeError: 'ascii' codec can't encode character '\xe4' in position 85: ordinal not in range(128)

So, a unicode issue.

Logging "last_play" to mp3 does not work

The python script gets a permission denied on the server:

Aug 27 11:33:01 vm-0016.audio.int.rabe.ch liquidsoap[25906]: Traceback (most recent call last):
Aug 27 11:33:01 vm-0016.audio.int.rabe.ch liquidsoap[25906]: File "/usr/local/venvs/klangbecken-py36/lib64/python3.6/site-packages/mutagen/_util.py", line 235, in _openfile
Aug 27 11:33:01 vm-0016.audio.int.rabe.ch liquidsoap[25906]: fileobj = open(filename, "rb+" if writable else "rb")
Aug 27 11:33:01 vm-0016.audio.int.rabe.ch liquidsoap[25906]: PermissionError: [Errno 13] Permission denied: '/var/lib/klangbecken/music/a5f533a7-cc7d-42bf-a903-f8ebb5a7c7bf.mp3'
Aug 27 11:33:01 vm-0016.audio.int.rabe.ch liquidsoap[25906]: During handling of the above exception, another exception occurred:
Aug 27 11:33:01 vm-0016.audio.int.rabe.ch liquidsoap[25906]: Traceback (most recent call last):
Aug 27 11:33:01 vm-0016.audio.int.rabe.ch liquidsoap[25906]: File "/usr/local/venvs/klangbecken-py36/bin/klangbecken", line 11, in <module>
Aug 27 11:33:01 vm-0016.audio.int.rabe.ch liquidsoap[25906]: load_entry_point('klangbecken==0.0.12', 'console_scripts', 'klangbecken')()
Aug 27 11:33:01 vm-0016.audio.int.rabe.ch liquidsoap[25906]: File "/usr/local/venvs/klangbecken-py36/lib64/python3.6/site-packages/klangbecken.py", line 1178, in main
Aug 27 11:33:01 vm-0016.audio.int.rabe.ch liquidsoap[25906]: playlog_cmd(data_dir, args["FILE"][0], dev_mode=dev_mode)
Aug 27 11:33:01 vm-0016.audio.int.rabe.ch liquidsoap[25906]: File "/usr/local/venvs/klangbecken-py36/lib64/python3.6/site-packages/klangbecken.py", line 1046, in playlog_cmd
Aug 27 11:33:01 vm-0016.audio.int.rabe.ch liquidsoap[25906]: mutagenfile.save()
Aug 27 11:33:01 vm-0016.audio.int.rabe.ch liquidsoap[25906]: File "/usr/local/venvs/klangbecken-py36/lib64/python3.6/site-packages/mutagen/_util.py", line 139, in wrapper
Aug 27 11:33:01 vm-0016.audio.int.rabe.ch liquidsoap[25906]: writable, create) as h:
Aug 27 11:33:01 vm-0016.audio.int.rabe.ch liquidsoap[25906]: File "/usr/lib64/python3.6/contextlib.py", line 81, in __enter__
Aug 27 11:33:01 vm-0016.audio.int.rabe.ch liquidsoap[25906]: return next(self.gen)
Aug 27 11:33:01 vm-0016.audio.int.rabe.ch liquidsoap[25906]: File "/usr/local/venvs/klangbecken-py36/lib64/python3.6/site-packages/mutagen/_util.py", line 256, in _openfile
Aug 27 11:33:01 vm-0016.audio.int.rabe.ch liquidsoap[25906]: raise MutagenError(e)
Aug 27 11:33:01 vm-0016.audio.int.rabe.ch liquidsoap[25906]: mutagen.MutagenError: [Errno 13] Permission denied: '/var/lib/klangbecken/music/a5f533a7-cc7d-42bf-a903-f8ebb5a7c7bf.mp3'

The permission is as follows:

[root@vm-0016 music]# ls -l /var/lib/klangbecken/music/a5f533a7-cc7d-42bf-a903-f8ebb5a7c7bf.mp3
-rw-r--r--. 1 apache apache 5903777 Mar  2 11:33 /var/lib/klangbecken/music/a5f533a7-cc7d-42bf-a903-f8ebb5a7c7bf.mp3

What user is the script being run as?

EBU 128 vs. classical replaygain

Preferably we would like to use a loudness scanner like bs1770gain that is compliant with the EBU R128 flavour of ITU-R BS.1770. The EBU R128 algorithm is the one that was made by the EBU for our purposes and it's adoption is pretty much standardised in the broadcast sector with mainly internet and analog radios still being holdouts.

Switching to R128 from replaygain would only mean changing the algorithm used to calculate the TXXX tag in the ID3 file. Playback is not affected.

I found an example implementation that shells out to bs1770gain instead of a gst pipeline in beets:

https://github.com/beetbox/beets/blob/a62e4eff8c15f7ab67f082e7e0985f96266e6c48/beetsplug/replaygain.py#L93-L118

There doesn't seem to be a way to do R128 with a gstreamer pipeline as far as I can tell, but I didn't dig to deep.

There are CentOS packages for bs1770gain available at https://github.com/radiorabe/centos-rpm-bs1770gain as well as on the RaBe internal Spacewalk server.

Could not install mutagen 1.45.1 on server

remote: ##############
remote: # Installing #
remote: ##############
remote: Looking in links: /root/dependencies/
remote: Requirement already up-to-date: docopt==0.6.2 in /usr/local/venvs/klangbecken-py36/lib/python3.6/site-packages (from -r /root/klangbecken/requirements.txt (line 1)) (0.6.2)
remote: Collecting mutagen==1.45.1 (from -r /root/klangbecken/requirements.txt (line 2))
remote:   Could not find a version that satisfies the requirement mutagen==1.45.1 (from -r /root/klangbecken/requirements.txt (line 2)) (from versions: )
remote: No matching distribution found for mutagen==1.45.1 (from -r /root/klangbecken/requirements.txt (line 2))
remote: Looking in links: /root/dependencies/
remote: Requirement already up-to-date: mod_wsgi in /usr/local/venvs/klangbecken-py36/lib/python3.6/site-packages (4.7.1)
remote: rm: cannot remove ‘/root/dependencies/*’: No such file or directory
remote: Processing /root/klangbecken
remote: Installing collected packages: klangbecken
remote:   Found existing installation: klangbecken 0.0.12
remote:     Uninstalling klangbecken-0.0.12:
remote:       Successfully uninstalled klangbecken-0.0.12
remote:   Running setup.py install for klangbecken: started
remote:     Running setup.py install for klangbecken: finished with status 'done'
remote: Successfully installed klangbecken-0.0.12
remote: #############
remote: # Reloading #
remote: #############
remote: Done!

Disable or delete tracks on a schedule

It would be nice, especially for the jingles, to have the ability to set a deadline for a track. On this deadline the track would be deleted or disabled automatically.

Counter for skipped tracks is not reset when a track was ok

This track should not have been played, because it there was an accepted track in the meantime.

[root@vm-0016 ~]# journalctl --unit [email protected] --since "2020-08-14 11:30" | grep -E "track was recently played: |too many skipped tracks"
Aug 14 11:47:01 vm-0016.audio.int.rabe.ch liquidsoap[11066]: 2020/08/14 11:47:01 [check_next_func:3] track was recently played: /var/lib/klangbecken/music/db378175-5d46-488a-b1ea-20bc7f56ae32.mp3 (128685 seconds ago)
Aug 14 12:02:26 vm-0016.audio.int.rabe.ch liquidsoap[11066]: 2020/08/14 12:02:26 [check_next_func:3] track was recently played: /var/lib/klangbecken/music/ea7f0b81-8316-4f59-9fa8-d8e5945c6aed.mp3 (27725 seconds ago)
Aug 14 12:09:04 vm-0016.audio.int.rabe.ch liquidsoap[11066]: 2020/08/14 12:09:04 [check_next_func:3] track was recently played: /var/lib/klangbecken/music/9c0e36cc-7798-42c0-883c-6129158506f9.mp3 (25581 seconds ago)
Aug 14 12:12:39 vm-0016.audio.int.rabe.ch liquidsoap[11066]: 2020/08/14 12:12:39 [check_next_func:3] track was recently played: /var/lib/klangbecken/music/a6683e6d-6def-45cb-b3b3-8b00be4eea6d.mp3 (238572 seconds ago)
Aug 14 12:26:38 vm-0016.audio.int.rabe.ch liquidsoap[11066]: 2020/08/14 12:26:38 [check_next_func:3] track was recently played: /var/lib/klangbecken/music/28200f9a-4704-44ba-ba9e-11a76b045b24.mp3 (69360 seconds ago)
Aug 14 12:26:39 vm-0016.audio.int.rabe.ch liquidsoap[11066]: 2020/08/14 12:26:39 [check_next_func:3] track was recently played: /var/lib/klangbecken/music/4ba09c6a-e922-4b7f-a999-163306f3cd75.mp3 (63754 seconds ago)
Aug 14 12:47:25 vm-0016.audio.int.rabe.ch liquidsoap[11066]: 2020/08/14 12:47:25 [check_next_func:3] track was recently played: /var/lib/klangbecken/music/0c8782db-e9c2-4447-92f6-207510c44194.mp3 (163224 seconds ago)
Aug 14 12:50:16 vm-0016.audio.int.rabe.ch liquidsoap[11066]: 2020/08/14 12:50:16 [check_next_func:3] track was recently played: /var/lib/klangbecken/music/c38972ed-af1f-4928-a266-838b53ef519c.mp3 (172108 seconds ago)
Aug 14 14:14:50 vm-0016.audio.int.rabe.ch liquidsoap[11066]: 2020/08/14 14:14:50 [check_next_func:3] track was recently played: /var/lib/klangbecken/music/36bd58bd-c562-49a3-a034-e8a5c83f18d8.mp3 (172703 seconds ago)
Aug 14 14:14:50 vm-0016.audio.int.rabe.ch liquidsoap[11066]: 2020/08/14 14:14:50 [check_next_func:3] too many skipped tracks, playing /var/lib/klangbecken/music/36bd58bd-c562-49a3-a034-e8a5c83f18d8.mp3 anyway

Umlaut Probleme im Klangbecken

vgl. dieser twitter thread: https://twitter.com/frauxirah/status/1240937156438364160

März 2020: Laut eurer Playlist hätte um 06.37 "A.A.L (Against All Logic) - Fantasy" laufen sollen; es war aber Björks Jóga Smiling face with sunglasses

Das es ein Umlaut Problem ist, ist nur meine Vermutung. Der umlautige Björk Track ist nicht im Kangbecken log und nicht im Songticker, ACRCloud sieht den Track.

Jun 05 11:32:32 vm-0016.audio.int.rabe.ch liquidsoap[13145]: Traceback (most recent call last):
Jun 05 11:32:32 vm-0016.audio.int.rabe.ch liquidsoap[13145]: File "/usr/local/venvs/klangbecken-py36/bin/klangbecken", line 11, in <module>
Jun 05 11:32:32 vm-0016.audio.int.rabe.ch liquidsoap[13145]: load_entry_point('klangbecken==0.0.12', 'console_scripts', 'klangbecken')()
Jun 05 11:32:32 vm-0016.audio.int.rabe.ch liquidsoap[13145]: File "/usr/local/venvs/klangbecken-py36/lib64/python3.6/site-packages/klangbecken.py", line 1170, in main
Jun 05 11:32:32 vm-0016.audio.int.rabe.ch liquidsoap[13145]: playlog_cmd(data_dir, args["FILE"][0], dev_mode=dev_mode)
Jun 05 11:32:32 vm-0016.audio.int.rabe.ch liquidsoap[13145]: File "/usr/local/venvs/klangbecken-py36/lib64/python3.6/site-packages/klangbecken.py", line 1062, in playlog_cmd
Jun 05 11:32:32 vm-0016.audio.int.rabe.ch liquidsoap[13145]: subprocess.check_call(EXTERNAL_PLAY_LOGGER.format(**entry), shell=True)
Jun 05 11:32:32 vm-0016.audio.int.rabe.ch liquidsoap[13145]: File "/usr/lib64/python3.6/subprocess.py", line 306, in check_call
Jun 05 11:32:32 vm-0016.audio.int.rabe.ch liquidsoap[13145]: retcode = call(*popenargs, **kwargs)
Jun 05 11:32:32 vm-0016.audio.int.rabe.ch liquidsoap[13145]: File "/usr/lib64/python3.6/subprocess.py", line 287, in call
Jun 05 11:32:32 vm-0016.audio.int.rabe.ch liquidsoap[13145]: with Popen(*popenargs, **kwargs) as p:
Jun 05 11:32:32 vm-0016.audio.int.rabe.ch liquidsoap[13145]: File "/usr/lib64/python3.6/subprocess.py", line 729, in __init__
Jun 05 11:32:32 vm-0016.audio.int.rabe.ch liquidsoap[13145]: restore_signals, start_new_session)
Jun 05 11:32:32 vm-0016.audio.int.rabe.ch liquidsoap[13145]: File "/usr/lib64/python3.6/subprocess.py", line 1295, in _execute_child
Jun 05 11:32:32 vm-0016.audio.int.rabe.ch liquidsoap[13145]: restore_signals, start_new_session, preexec_fn)
Jun 05 11:32:32 vm-0016.audio.int.rabe.ch liquidsoap[13145]: UnicodeEncodeError: 'ascii' codec can't encode character '\xe9' in position 39: ordinal not in range(128)

replace xml file delivery with http push based system (eventing shiggalawahnsinn)

The idea is to replace the current ssh file-delivery approach with a http POST based API. Here is a bunch of links to previous work pertaining to this change:

I plan on supporting both XML file delivery and the new HTTP API in a coming nowplaying v2.x release so we don't need to switch over klangbecken at the same time. Support for the current XML file delivery mechanism will then be dropped in nowplaying v3 which is going to be released way after we switch klangbecken to use the new api.

Example Client

This is based on the same python-sdk used on the nowplaying side. The same can be acheived with any client that can send POST requests and headers, see the cURL example below for a simple bash example that demonstrates how the request works.

import requests

from cloudevents.http import CloudEvent, to_structured

def send_event(url, username, password):
    # This data defines a cloudevent
    attributes = {
        "specversion": "1.0",
        # as defined by the events-spec repo
        "type": "ch.rabe.api.events.track.v1.trackStarted",
        # for klangbecken the github link is always used as source (as per events-spec)
        "source": "https://github.com/radiorabe/klangbecken",
        # this should reference the actual broadcast and not some digital representation of it
        # one way to do thas is to use RFC 4087 `crid://` URLs as per the upcoming crid-spec thing.
        "id": "crid://rabe.ch/v1/klangbecken#t=clock=20220209T010400.00Z",
    }
    data = {
        "item.title": "Track Title",
        "item.artist": "Artist",
        # length in seconds, optional if you also implement sending the
        # not "completely specced yet" trackFinished event
        "item.length": 60,
    }

    event = CloudEvent(attributes, data)
    headers, body = to_structured(event)

    # send and print event
    requests.post(url, headers=headers, data=body, auth=(username, password))
    print(f"Sent {event['id']} from {event['source']} with {event.data}")

if __name__ == "__main__":
    # local config
    url = "https://nowplaing.service.int.example.org/webhook"
    username = "rabe"
    password = "rabe"

    # do work
    send_event(url, username, password)

The same event could be sent using cURL:

cat << EOF > event.json
{
    "specversion": "1.0",
    "type": "ch.rabe.api.events.track.v1.trackStarted",
    "source": "https://github.com/radiorabe/klangbecken",
    "id": "crid://rabe.ch/v1/klangbecken#t=clock=20211228T193100.00Z",
    "time": "2021-12-28T19:31:00Z",
    "datacontenttype": "application/json",
    "data": {
        "item.title": "Track Title",
        "item.artist": "Artist",
        "item.length": 60
    }
}
EOF
curl -vvv -u rabe:rabe -H 'Content-Type: application/json' -X POST -d '@event.json' \
  https://nowplaying.service.int.example.org/webhook

In the python-sdk example the time and datacontenttype are autogenerated. The fields are mandatory in any case.

The data fields are based on both the DAB+ MOT SLS/DL+ and ID3 standards as documented in the linked events-spec.

It might make sense to only send these events when klangbecken considers itself onair, i'm not sure about this yet tho.

For generating the CRIDs, there is also rabe-cridlib if that helps.

Tasks

Show next playing song

Und dann wäre noch sehr praktisch, wenn bei der Funktion "play next" zum einen der Track der als nächstes gespielt werden soll irgendwo angezeigt wird und ersetzt wird, wenn bei einem anderen Track play next gedrück wird.

Need to expand the API (implement GET for on_play_next). Part would be adjustements in the UI.

stutter on upload and edit of metadata

und auch beim bearbeiten / beschriften...

Am 15.10.2020 um 13:23 schrieb Martin Schneider:

Hallo zäme

Ich hoffe ihr seid alle wohlauf!

Beim upload der aktuellen Songs (50stk) hatte das KB grad etwas Mühe. Nicht mehr so stark wie gehabt aber doch etwas am stottern.
Dies zur Info

Lg Tinu

Determine whether tracks are being recognized by ACRCloud

Feature request

In order to improve the overall metadata quality, tracks shall be scanned and determined whether they are recognized by ACRCloud.

This would provided the ground work for certain use cases in the future, such as:

  • Track not yet recognized by ACRCloud: Allows one to submit new tracks/metadata to ACRCloud (either to their music DB or custom buckets)
  • Track is being recognized by ACRCLoud: Metadata of a track in klangbecken can be updated or improved from data provided by ACRCloud (self-updating/healing)
  • Gain statistics about recognized/unrecognized tracks
  • Improve metadata on back-feeds such as raar_acr_tracks_importer and suisa_sendemeldung in the long run.
  • Detect and reject duplicates (e.g. #32)

Ideally, a check whether a track is recognized by ACRCloud will be done during ingest (upload of a new track), including the possibility to manually trigger a scan of a specific track and to run a bulk-check on all available tracks. The result could be displayed in the UI (after upload) and also provided in a exportable format (bulk-check).
After a track has been recognized, the ACRCloud ID must be persisted and linked together with the track file path, to avoid expensive re-scans and duplicate detection in the future.

The ACRCloud track scanning should be made as an optional configurable feature which can be enabled or disabled.

Possible implementations

CLI helpers for testing:

Reload liquisoap playlists when new tracks are uploaded

Currently the liquidsoap script monitors the m3u files using inotify (reload_mode=watch). This behaviour lead to erros in the past.

It would be better to reload the liquidsoap playlists using the socket when a new track is added.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.