From afd0e474af59f193992865dd7f6190d140c9b5a4 Mon Sep 17 00:00:00 2001 From: s-martin Date: Fri, 12 Apr 2024 23:00:57 +0200 Subject: [PATCH 1/5] maint: Update actions (#2334) * Update action versions * Trigger python action * Update Python action * Use correct env variable * Revert change for triggering action --- .github/workflows/codeql-analysis_v3.yml | 6 +++--- .github/workflows/pythonpackage_future3.yml | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/codeql-analysis_v3.yml b/.github/workflows/codeql-analysis_v3.yml index d06cce1a5..a284d7691 100644 --- a/.github/workflows/codeql-analysis_v3.yml +++ b/.github/workflows/codeql-analysis_v3.yml @@ -38,7 +38,7 @@ jobs: uses: actions/checkout@v4 - name: Set up Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: '3.x' - name: Install dependencies @@ -51,9 +51,9 @@ jobs: python -m pip install --upgrade pip pip install -r requirements.txt - # Set the `CODEQL-PYTHON` environment variable to the Python executable + # Set the `CODEQL_EXTRACTOR_PYTHON_ANALYSIS_VERSION` environment variable to the Python executable # that includes the dependencies - echo "CODEQL_PYTHON=$(which python)" >> $GITHUB_ENV + echo "CODEQL_EXTRACTOR_PYTHON_ANALYSIS_VERSION=$(which python)" >> $GITHUB_ENV # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL diff --git a/.github/workflows/pythonpackage_future3.yml b/.github/workflows/pythonpackage_future3.yml index da7007b97..3bc2c1174 100644 --- a/.github/workflows/pythonpackage_future3.yml +++ b/.github/workflows/pythonpackage_future3.yml @@ -22,9 +22,9 @@ jobs: python-version: ['3.9', '3.10', '3.11', '3.12'] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - name: Install dependencies From a9ab571ac90cce21b94fef705855b9598c941a30 Mon Sep 17 00:00:00 2001 From: Christian Hoffmann Date: Fri, 12 Apr 2024 21:10:24 +0000 Subject: [PATCH 2/5] Fix PlayerMPD.prev/next() when stopped (#2326) * utils: Add get_config_action This abstracts away the functionality to resolve a given config option to an action in a pre-defined dict. Co-authored-by: Christian Hoffmann * Fix PlayerMPD.prev/next() when stopped * Avoid MPD-related crashes during all prev/next() calls. * Explicitly handle prev() in stopped state, configurable via `playermpd.stopped_prev_action`. * Explicitly handle next() in stopped state, configurable via `playermpd.stopped_next_action`. * Explicitly handle next() when reaching the end of the playlist: jukebox-daemon will now ignore the action by default (similar to v2). It can also be configured to rewind the playlist instead by setting the new config option `playermpd.end_of_playlist_next_action: rewind` or to stop playing. Fixes #2294 Fixes #2327 Co-authored-by: pabera <1260686+pabera@users.noreply.github.com> --------- Co-authored-by: pabera <1260686+pabera@users.noreply.github.com> --- .../default-settings/jukebox.default.yaml | 6 ++ src/jukebox/components/playermpd/__init__.py | 59 ++++++++++++++++++- src/jukebox/jukebox/utils.py | 13 ++++ 3 files changed, 76 insertions(+), 2 deletions(-) diff --git a/resources/default-settings/jukebox.default.yaml b/resources/default-settings/jukebox.default.yaml index c087cc024..b8e429333 100644 --- a/resources/default-settings/jukebox.default.yaml +++ b/resources/default-settings/jukebox.default.yaml @@ -87,6 +87,12 @@ playermpd: update_on_startup: true check_user_rights: true mpd_conf: ~/.config/mpd/mpd.conf + # Must be one of: 'none', 'stop', 'rewind': + end_of_playlist_next_action: none + # Must be one of: 'none', 'prev', 'rewind': + stopped_prev_action: prev + # Must be one of: 'none', 'next', 'rewind': + stopped_next_action: next rpc: tcp_port: 5555 websocket_port: 5556 diff --git a/src/jukebox/components/playermpd/__init__.py b/src/jukebox/components/playermpd/__init__.py index dcbef2ea8..772b8c654 100644 --- a/src/jukebox/components/playermpd/__init__.py +++ b/src/jukebox/components/playermpd/__init__.py @@ -156,6 +156,28 @@ def __init__(self): self.second_swipe_action = None self.decode_2nd_swipe_option() + self.end_of_playlist_next_action = utils.get_config_action(cfg, + 'playermpd', + 'end_of_playlist_next_action', + {'rewind': self.rewind, + 'stop': self.stop, + 'none': lambda: None}, + logger) + self.stopped_prev_action = utils.get_config_action(cfg, + 'playermpd', + 'stopped_prev_action', + {'rewind': self.rewind, + 'prev': self._prev_in_stopped_state, + 'none': lambda: None}, + logger) + self.stopped_next_action = utils.get_current_song(cfg, + 'playermpd', + 'stopped_next_action', + {'rewind': self.rewind, + 'next': self._next_in_stopped_state, + 'none': lambda: None}, + logger) + self.mpd_client = mpd.MPDClient() self.coverart_cache_manager = CoverartCacheManager() @@ -327,15 +349,48 @@ def pause(self, state: int = 1): @plugs.tag def prev(self): logger.debug("Prev") + if self.mpd_status['state'] == 'stop': + logger.debug('Player is stopped, calling stopped_prev_action') + return self.stopped_prev_action() + try: + with self.mpd_lock: + self.mpd_client.previous() + except mpd.base.CommandError: + # This shouldn't happen in reality, but we still catch + # this error to avoid crashing the player thread: + logger.warning('Failed to go to previous song, ignoring') + + def _prev_in_stopped_state(self): with self.mpd_lock: - self.mpd_client.previous() + self.mpd_client.play(max(0, int(self.mpd_status['pos']) - 1)) @plugs.tag def next(self): """Play next track in current playlist""" logger.debug("Next") + if self.mpd_status['state'] == 'stop': + logger.debug('Player is stopped, calling stopped_next_action') + return self.stopped_next_action() + playlist_len = int(self.mpd_status.get('playlistlength', -1)) + current_pos = int(self.mpd_status.get('pos', 0)) + if current_pos == playlist_len - 1: + logger.debug(f'next() called during last song ({current_pos}) of ' + f'playlist (len={playlist_len}), running end_of_playlist_next_action.') + return self.end_of_playlist_next_action() + try: + with self.mpd_lock: + self.mpd_client.next() + except mpd.base.CommandError: + # This shouldn't happen in reality, but we still catch + # this error to avoid crashing the player thread: + logger.warning('Failed to go to next song, ignoring') + + def _next_in_stopped_state(self): + pos = int(self.mpd_status['pos']) + 1 + if pos > int(self.mpd_status['playlistlength']) - 1: + return self.end_of_playlist_next_action() with self.mpd_lock: - self.mpd_client.next() + self.mpd_client.play(pos) @plugs.tag def seek(self, new_time): diff --git a/src/jukebox/jukebox/utils.py b/src/jukebox/jukebox/utils.py index dbd647490..4cc0270ae 100644 --- a/src/jukebox/jukebox/utils.py +++ b/src/jukebox/jukebox/utils.py @@ -183,6 +183,19 @@ def rpc_call_to_str(cfg_rpc_call: Dict, with_args=True) -> str: return readable +def get_config_action(cfg, section, option, default, valid_actions_dict, logger): + """ + Looks up the given {section}.{option} config option and returns + the associated entry from valid_actions_dict, if valid. Falls back to the given + default otherwise. + """ + action = cfg.setndefault(section, option, value='').lower() + if action not in valid_actions_dict: + logger.error(f"Config {section}.{option} must be one of {valid_actions_dict.keys()}. Using default '{default}'") + action = default + return valid_actions_dict[action] + + def indent(doc, spaces=4): lines = doc.split('\n') for i in range(0, len(lines)): From fa110b49662cc4309c4e659fd2e2ef553820ea63 Mon Sep 17 00:00:00 2001 From: s-martin Date: Sat, 13 Apr 2024 23:05:42 +0200 Subject: [PATCH 3/5] fix a typo (#2336) --- documentation/developers/docker.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/developers/docker.md b/documentation/developers/docker.md index 74d95c112..6a0af80c7 100644 --- a/documentation/developers/docker.md +++ b/documentation/developers/docker.md @@ -123,7 +123,7 @@ They can be run individually or in combination. To do that, we use load-module module-native-protocol-tcp auth-ip-acl=127.0.0.1 ``` -1. Edit `$INSTALL_DIR/etc/pulse//etc/pulse/daemon.conf`, find the +1. Edit `$INSTALL_DIR/etc/pulse/daemon.conf`, find the following line and change it to: ``` bash From 33fec6465a5ca66613172dae0d5d78f8ea87365b Mon Sep 17 00:00:00 2001 From: Christian Hoffmann Date: Mon, 15 Apr 2024 15:53:04 +0000 Subject: [PATCH 4/5] fix: bad utils.get_config_action invocations (#2339) --- src/jukebox/components/playermpd/__init__.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/jukebox/components/playermpd/__init__.py b/src/jukebox/components/playermpd/__init__.py index 772b8c654..86dbc60ab 100644 --- a/src/jukebox/components/playermpd/__init__.py +++ b/src/jukebox/components/playermpd/__init__.py @@ -159,6 +159,7 @@ def __init__(self): self.end_of_playlist_next_action = utils.get_config_action(cfg, 'playermpd', 'end_of_playlist_next_action', + 'none', {'rewind': self.rewind, 'stop': self.stop, 'none': lambda: None}, @@ -166,13 +167,15 @@ def __init__(self): self.stopped_prev_action = utils.get_config_action(cfg, 'playermpd', 'stopped_prev_action', + 'prev', {'rewind': self.rewind, 'prev': self._prev_in_stopped_state, 'none': lambda: None}, logger) - self.stopped_next_action = utils.get_current_song(cfg, + self.stopped_next_action = utils.get_config_action(cfg, 'playermpd', 'stopped_next_action', + 'next', {'rewind': self.rewind, 'next': self._next_in_stopped_state, 'none': lambda: None}, From 0ab75c1d28955e85c2069503b5a8428a69967d0d Mon Sep 17 00:00:00 2001 From: Alvin Schiller <103769832+AlvinSchiller@users.noreply.github.com> Date: Wed, 17 Apr 2024 23:30:46 +0200 Subject: [PATCH 5/5] hotfix pyzmq installation on bullseye (pin version <26) (#2345) * fix: pin pyzmq version to <26 * fix: add checks for installed ZMQ version and DRAFT_API * Bump version to hotfix v3.5.3 --- installation/routines/setup_jukebox_core.sh | 16 +++++++++++++++- src/jukebox/jukebox/version.py | 2 +- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/installation/routines/setup_jukebox_core.sh b/installation/routines/setup_jukebox_core.sh index cb85198be..f5ef2eec2 100644 --- a/installation/routines/setup_jukebox_core.sh +++ b/installation/routines/setup_jukebox_core.sh @@ -86,7 +86,7 @@ _jukebox_core_build_and_install_pyzmq() { fi ZMQ_PREFIX="${JUKEBOX_ZMQ_PREFIX}" ZMQ_DRAFT_API=1 \ - pip install -v --no-binary pyzmq pyzmq + pip install -v --no-binary pyzmq 'pyzmq<26' else print_lc " Skipping. pyzmq already installed" fi @@ -120,6 +120,20 @@ _jukebox_core_check() { local pip_modules=$(get_args_from_file "${INSTALLATION_PATH}/requirements.txt") verify_pip_modules pyzmq $pip_modules + log " Verify ZMQ version '${JUKEBOX_ZMQ_VERSION}'" + local zmq_version=$(python -c 'import zmq; print(f"{zmq.zmq_version()}")') + if [[ "${zmq_version}" != "${JUKEBOX_ZMQ_VERSION}" ]]; then + exit_on_error "ERROR: ZMQ version '${zmq_version}' differs from expected '${JUKEBOX_ZMQ_VERSION}'!" + fi + log " CHECK" + + log " Verify ZMQ has 'DRAFT-API' activated" + local zmq_hasDraftApi=$(python -c 'import zmq; print(f"{zmq.DRAFT_API}")') + if [[ "${zmq_hasDraftApi}" != "True" ]]; then + exit_on_error "ERROR: ZMQ has 'DRAFT-API' '${zmq_hasDraftApi}' differs from expected 'True'!" + fi + log " CHECK" + verify_files_chmod_chown 644 "${CURRENT_USER}" "${CURRENT_USER_GROUP}" "${JUKEBOX_PULSE_CONFIG}" verify_files_chmod_chown 644 "${CURRENT_USER}" "${CURRENT_USER_GROUP}" "${SETTINGS_PATH}/jukebox.yaml" diff --git a/src/jukebox/jukebox/version.py b/src/jukebox/jukebox/version.py index b97391207..d62ef3e93 100644 --- a/src/jukebox/jukebox/version.py +++ b/src/jukebox/jukebox/version.py @@ -1,7 +1,7 @@ VERSION_MAJOR = 3 VERSION_MINOR = 5 -VERSION_PATCH = 2 +VERSION_PATCH = 3 VERSION_EXTRA = "" # build a version string in compliance with the SemVer specification