Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New card actions: play, pause, prev, next, toggle, repeat, shuffle #2179

Merged
merged 19 commits into from
Jan 4, 2024
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion documentation/developers/docker.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,20 @@ They can be run individually or in combination. To do that, we use
### Mac

1. [Install Docker & Compose (Mac)](https://docs.docker.com/docker-for-mac/install/)
2. [Install pulseaudio](https://gist.github.com/seongyongkim/b7d630a03e74c7ab1c6b53473b592712) (Other references: [[1]](https://devops.datenkollektiv.de/running-a-docker-soundbox-on-mac.html), [[2]](https://stackoverflow.com/a/50939994/1062438))
2. Install pulseaudio
1. Use Homebrew to install
```
$ brew install pulseaudio
```
2. Enable pulseaudio network capabilities. In an editor, open `/opt/homebrew/Cellar/pulseaudio/16.1/etc/pulse/default.pa` (you might need to adapt this path to your own system settings). Uncomment the following line.
```
load-module module-native-protocol-tcp
```
3. Restart the pulseaudio service
```
$ brew services restart pulseaudio
```
4. If you have trouble with your audio, try these resources to troubleshoot: [[1]](https://gist.github.com/seongyongkim/b7d630a03e74c7ab1c6b53473b592712), [[2]](https://devops.datenkollektiv.de/running-a-docker-soundbox-on-mac.html), [[3]](https://stackoverflow.com/a/50939994/1062438)

> [!NOTE]
> In order for Pulseaudio to work properly with Docker on your Mac, you need to start Pulseaudio in a specific way. Otherwise MPD will throw an exception. See [Pulseaudio issues on Mac](#pulseaudio-issue-on-mac) for more info.
Expand Down
7 changes: 3 additions & 4 deletions documentation/developers/status.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,10 +107,9 @@ Topics marked _in progress_ are already in the process of implementation by comm
- [ ] Folder configuration (_in progress_)
- [ ] [Reference](https://github.com/MiczFlor/RPi-Jukebox-RFID/wiki/MANUAL#manage-playout-behaviour)
- [ ] Resume: Save and restore position (how interact with shuffle?)
- [ ] Single: Enable mpc single
- [ ] Shuffle: Enable mpc random (not shuffle)
- Rename to random, as this is mpc random
- [ ] Loop: Loop playlist
- [x] Repeat Playlist
pabera marked this conversation as resolved.
Show resolved Hide resolved
- [x] Repeat Song
- [X] Shuffle

### MPD Player

Expand Down
55 changes: 48 additions & 7 deletions src/jukebox/components/playermpd/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -335,11 +335,6 @@ def seek(self, new_time):
with self.mpd_lock:
self.mpd_client.seekcur(new_time)

@plugs.tag
def shuffle(self, random):
# As long as we don't work with waiting lists (aka playlist), this implementation is ok!
self.mpd_retry_with_mutex(self.mpd_client.random, 1 if random else 0)

@plugs.tag
def rewind(self):
"""
Expand All @@ -363,7 +358,6 @@ def replay(self):
@plugs.tag
def toggle(self):
pabera marked this conversation as resolved.
Show resolved Hide resolved
"""Toggle pause state, i.e. do a pause / resume depending on current state"""
logger.debug("Toggle")
with self.mpd_lock:
self.mpd_client.pause()

Expand All @@ -378,8 +372,27 @@ def replay_if_stopped(self):
if self.mpd_status['state'] == 'stop':
self.play_folder(self.music_player_status['player_status']['last_played_folder'])

# Shuffle
def _shuffle(self, random):
# As long as we don't work with waiting lists (aka playlist), this implementation is ok!
self.mpd_retry_with_mutex(self.mpd_client.random, 1 if random else 0)

@plugs.tag
def repeatmode(self, mode):
def set_shuffle(self, option='toggle'):
if option == 'toggle':
if self.mpd_status['random'] == '0':
self._shuffle(1)
else:
self._shuffle(0)
elif option == 'enable':
self._shuffle(1)
elif option == 'disable':
self._shuffle(0)
else:
logger.error(f"'{option}' does not exist for set_shuffle")

# Repeat
def _repeatmode(self, mode):
if mode == 'repeat':
repeat = 1
single = 0
Expand All @@ -394,6 +407,34 @@ def repeatmode(self, mode):
self.mpd_client.repeat(repeat)
self.mpd_client.single(single)

@plugs.tag
def set_repeat(self, option='toggle'):
pabera marked this conversation as resolved.
Show resolved Hide resolved
if option == 'toggle':
if self.mpd_status['repeat'] == '0':
self._repeatmode('repeat')
elif self.mpd_status['repeat'] == '1' and self.mpd_status['single'] == '0':
self._repeatmode('single')
else:
self._repeatmode(None)
elif option == 'toggle_repeat':
if self.mpd_status['repeat'] == '0':
self._repeatmode('repeat')
else:
self._repeatmode(None)
elif option == 'toggle_repeat_single':
if self.mpd_status['single'] == '0':
self._repeatmode('single')
else:
self._repeatmode(None)
elif option == 'enable_repeat':
self._repeatmode('repeat')
elif option == 'enable_repeat_single':
self._repeatmode('single')
elif option == 'disable':
self._repeatmode(None)
else:
logger.error(f"'{option}' does not exist for set_repeat")

@plugs.tag
def get_current_song(self, param):
return self.mpd_status
Expand Down
18 changes: 18 additions & 0 deletions src/jukebox/components/rpc_command_alias.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,12 @@
'package': 'player',
'plugin': 'ctrl',
'method': 'play_folder'},
'play': {
'package': 'player',
'plugin': 'ctrl',
'method': 'play',
'note': 'Play the currently selected song',
'ignore_card_removal_action': True},
'pause': {
'package': 'player',
'plugin': 'ctrl',
Expand All @@ -57,6 +63,18 @@
'plugin': 'ctrl',
'method': 'toggle',
'ignore_card_removal_action': True},
'set_shuffle': {
'package': 'player',
'plugin': 'ctrl',
'method': 'set_shuffle',
'note': 'Shuffle',
'ignore_card_removal_action': True},
'set_repeat': {
'package': 'player',
'plugin': 'ctrl',
'method': 'set_repeat',
'note': 'Repeat',
'ignore_card_removal_action': True},

# VOLUME
'set_volume': {
Expand Down
44 changes: 34 additions & 10 deletions src/webapp/public/locales/de/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,14 @@
"timer_fade_volume": "Fade volume",
"toggle_output": "Audio-Ausgang umschalten",
"sync_rfidcards_all": "Alle Audiodateien und Karteneinträge synchronisieren",
"sync_rfidcards_change_on_rfid_scan": "Aktivierung ändern für 'on RFID scan' "
"sync_rfidcards_change_on_rfid_scan": "Aktivierung ändern für 'on RFID scan'",
"next_song": "Nächster Song",
"pause": "Pause",
"play": "Abspielen",
"prev_song": "Vorheriger Song",
"set_shuffle": "Zufallswiedergabe",
"set_repeat": "Wiedergabe wiederholen",
"toggle": "Abspielen/Pause umschalten"
}
},
"controls-selector": {
Expand Down Expand Up @@ -56,8 +63,25 @@
"no-music-selected": "Es ist keine Musik ausgewählt.",
"loading-song-error": "Während des Ladens des Songs ist ein Fehler aufgetreten."
},
"volume": {
"title": "Lautstärke Stufen"
"audio": {
"repeat": {
"description": "Wähle den zu setzenden Status.",
"label-toggle": "Umschalten - Schaltet durch 1) Wiedergabeliste Wiederholen, 2) Song Wiederholen, 3) Wiederholen Deaktiveren",
"label-toggle-repeat": "Wiedergabeliste Wiederholen umschalten",
"label-toggle-repeat-single": "Song Wiederholen umschalten",
"label-enable-repeat": "Wiedergabeliste Wiederholen aktivieren",
"label-enable-repeat-single": "Song Wiederholen aktivieren",
"label-disable": "Wiederholen deaktivieren"
},
"shuffle": {
"description": "Wähle den zu setzenden Status.",
"label-toggle": "Umschalten",
"label-enable": "Aktivieren",
"label-disable": "Deaktivieren"
},
"volume": {
"title": "Lautstärke Stufen"
}
},
"timers": {
"description": "Wähle die Anzahl der Minuten nachdem die Aktion ausgeführt werden soll."
Expand Down Expand Up @@ -138,17 +162,17 @@
"player": {
"controls": {
"shuffle": {
"activate": "Shuffle aktivieren",
"deactivate": "Shuffle deaktivieren"
"enable": "Zufallswiedergabe aktivieren",
"disable": "Zufallswiedergabe deaktivieren"
},
"skip": "Zurück",
"prev_song": "Zurück",
"play": "Abspielen",
"pause": "Pause",
"next": "Weiter",
"next_song": "Weiter",
"repeat": {
"activate": "Wiederholen aktivieren",
"activate-single": "1 Wiederholen aktivieren",
"deactivate": "Wiederholen deaktivieren"
"enable": "Wiedergabeliste Wiederholen aktivieren",
"enable-single": "Song Wiederholen aktivieren",
"disable": "Wiederholen deaktivieren"
}
},
"cover": {
Expand Down
45 changes: 35 additions & 10 deletions src/webapp/public/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,14 @@
"timer_fade_volume": "Fade volume",
"toggle_output": "Toggle audio output",
"sync_rfidcards_all": "Sync all audiofiles and card entries",
"sync_rfidcards_change_on_rfid_scan": "Change activation of 'on RFID scan'"
"sync_rfidcards_change_on_rfid_scan": "Change activation of 'on RFID scan'",
"next_song": "Next song",
"pause": "Pause",
"play": "Play",
"prev_song": "Previous song",
"set_shuffle": "Shuffle",
"set_repeat": "Repeat",
"toggle": "Toggle Play/Pause"
}
},
"controls-selector": {
Expand Down Expand Up @@ -56,8 +63,25 @@
"no-music-selected": "No music selected",
"loading-song-error": "An error occurred while loading song."
},
"volume": {
"title": "Volume steps"
"audio": {
"repeat": {
"description": "Choose the state to set.",
"label-toggle": "Toggle - Loops through 1) Repeat playlist, 2) Repeat song, 3) Disable repeat",
"label-toggle-repeat": "Toggle Repeat Playlist",
"label-toggle-repeat-single": "Toggle Repeat Song",
"label-enable-repeat": "Enable Repeat Playlist",
"label-enable-repeat-single": "Enable Repeat Song",
"label-disable": "Disable"
},
"shuffle": {
"description": "Choose the state to set.",
"label-toggle": "Toggle",
"label-enable": "Enable",
"label-disable": "Disable"
},
"volume": {
"title": "Volume steps"
}
},
"timers": {
"description": "Choose the amount of minutes you want the action to be performed."
Expand Down Expand Up @@ -138,17 +162,17 @@
"player": {
"controls": {
"shuffle": {
"activate": "Activate shuffle",
"deactivate": "Deactivate shuffle"
"enable": "Enable shuffle",
"disable": "Disable shuffle"
},
"skip": "Skip previous track",
"prev_song": "Skip to previous track",
"play": "Play",
"pause": "Pause",
"next": "Skip next track",
"next_song": "Skip to next track",
"repeat": {
"activate": "Activate repeat",
"activate-single": "Activate single repeat",
"deactivate": "Deactivate repeat"
"enable": "Enable Playlist repeat",
"enable-single": "Enable Song repeat",
"disable": "Disable repeat"
}
},
"cover": {
Expand Down Expand Up @@ -207,6 +231,7 @@
},
"secondswipe": {
"title": "Second Swipe",
"description": "Second action after the same card swiped again",
"restart": "Restart playlist",
"toggle": "Toggle pause / play",
"skip": "Skip to next track",
Expand Down
19 changes: 13 additions & 6 deletions src/webapp/src/commands/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,25 +82,32 @@ const commands = {
plugin: 'ctrl',
method: 'pause',
},
previous: {
prev_song: {
_package: 'player',
plugin: 'ctrl',
method: 'prev',
},
next: {
next_song: {
_package: 'player',
plugin: 'ctrl',
method: 'next',
},
shuffle: {
toggle: {
_package: 'player',
plugin: 'ctrl',
method: 'shuffle',
method: 'toggle',
},
repeat: {
set_shuffle: {
_package: 'player',
plugin: 'ctrl',
method: 'repeatmode',
method: 'set_shuffle',
argKeys: ['option'],
},
set_repeat: {
_package: 'player',
plugin: 'ctrl',
method: 'set_repeat',
argKeys: ['option'],
},
seek: {
_package: 'player',
Expand Down
34 changes: 32 additions & 2 deletions src/webapp/src/components/Cards/controls/actions/audio/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@ import React from 'react';

import CommandSelector from '../../command-selector';
import SliderChangeVolume from './slider-change-volume';
import OptionsSelector from '../../options-selector';

import { getActionAndCommand } from '../../../utils';

const SelectVolume = ({
const SelectAudioVolume = ({
actionData,
handleActionDataChange,
}) => {
Expand All @@ -23,8 +24,37 @@ const SelectVolume = ({
handleActionDataChange={handleActionDataChange}
/>
}
{command === 'set_shuffle' &&
<OptionsSelector
actionType="audio_shuffle"
actionData={actionData}
handleActionDataChange={handleActionDataChange}
optionLabel="cards.controls.actions.audio.shuffle.description"
options={[
{ labelKey: 'cards.controls.actions.audio.shuffle.label-toggle', value: 'toggle' },
{ labelKey: 'cards.controls.actions.audio.shuffle.label-enable', value: 'enable' },
{ labelKey: 'cards.controls.actions.audio.shuffle.label-disable', value: 'disable' },
]}
/>
}
{command === 'set_repeat' &&
<OptionsSelector
actionType="audio_repeat"
actionData={actionData}
handleActionDataChange={handleActionDataChange}
optionLabel="cards.controls.actions.audio.repeat.description"
options={[
{ labelKey: 'cards.controls.actions.audio.repeat.label-toggle', value: 'toggle' },
{ labelKey: 'cards.controls.actions.audio.repeat.label-toggle-repeat', value: 'toggle_repeat' },
{ labelKey: 'cards.controls.actions.audio.repeat.label-toggle-repeat-single', value: 'toggle_repeat_single' },
{ labelKey: 'cards.controls.actions.audio.repeat.label-enable-repeat', value: 'enable_repeat' },
{ labelKey: 'cards.controls.actions.audio.repeat.label-enable-repeat-single', value: 'enable_repeat_single' },
{ labelKey: 'cards.controls.actions.audio.repeat.label-disable', value: 'disable' },
]}
/>
}
</>
);
};

export default SelectVolume;
export default SelectAudioVolume;
Loading