Skip to content

Commit

Permalink
Adapt Webapp to new play_content and play_from_reader API
Browse files Browse the repository at this point in the history
  • Loading branch information
pabera committed Nov 17, 2024
1 parent 0a54a81 commit c3040d1
Show file tree
Hide file tree
Showing 26 changed files with 145 additions and 97 deletions.
14 changes: 7 additions & 7 deletions src/jukebox/components/playermpd/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -577,24 +577,24 @@ def play_content(self, content: Union[str, Dict[str, Any]], content_type: str =
:param content: Content identifier:
- For singles/folders: file/folder path as string
- For albums: dict with 'artist' and 'album' keys
- For albums: dict with 'albumartist' and 'album' keys
:param content_type: Type of content ('single', 'album', 'folder')
:param recursive: Add folder recursively (only used for folder type)
"""
try:
content_type = content_type.lower()
if content_type == 'album':
if isinstance(content, dict):
artist = content.get('artist')
albumartist = content.get('albumartist')
album = content.get('album')
if not artist or not album:
raise ValueError("Album content must contain both 'artist' and 'album' keys")
if not albumartist or not album:
raise ValueError("Album content must contain both 'albumartist' and 'album' keys")
else:
raise ValueError("Album content must be a dictionary with 'artist' and 'album' keys")
raise ValueError("Album content must be a dictionary with 'albumartist' and 'album' keys")

play_content = PlayContent(
type=PlayContentType.ALBUM,
content=(artist, album)
content=(albumartist, album)
)
elif content_type == 'single':
if isinstance(content, dict):
Expand Down Expand Up @@ -635,7 +635,7 @@ def play_from_reader(self, content: Union[str, Dict[str, str]], content_type: st
:param content: Content identifier, either:
- string path for single/folder types
- dict with 'artist' and 'album' keys for album type
- dict with 'albumartist' and 'album' keys for album type
:param content_type: Type of content ('single', 'album', 'folder')
:param recursive: Add folder recursively (only used for folder type)
:param second_swipe: Override default second swipe action for this reader:
Expand Down
46 changes: 26 additions & 20 deletions src/jukebox/components/rfid/cards/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

import logging
import time
from typing import (List, Dict, Optional)
from typing import List, Dict, Optional, Union
import jukebox.utils as utils
import jukebox.cfghandler
import jukebox.plugs as plugs
Expand Down Expand Up @@ -89,42 +89,48 @@ def delete_card(card_id: str, auto_save: bool = True):

@plugs.register
def register_card(card_id: str, cmd_alias: str,
args: Optional[List] = None, kwargs: Optional[Dict] = None,
ignore_card_removal_action: Optional[bool] = None, ignore_same_id_delay: Optional[bool] = None,
overwrite: bool = False,
auto_save: bool = True):
"""Register a new card based on quick-selection
If you are going to call this through the RPC it will get a little verbose
**Example:** Registering a new card with ID *0009* for increment volume with a custom argument to inc_volume
(*here: 15*) and custom *ignore_same_id_delay value*::
plugin.call_ignore_errors('cards', 'register_card',
args=['0009', 'inc_volume'],
kwargs={'args': [15], 'ignore_same_id_delay': True, 'overwrite': True})
"""
args: Optional[Union[List, Dict]] = None,
kwargs: Optional[Dict] = None,
ignore_card_removal_action: Optional[bool] = None,
ignore_same_id_delay: Optional[bool] = None,
overwrite: bool = False,
auto_save: bool = True):
"""Register a new card based on quick-selection"""
if cmd_alias not in cmd_alias_definitions.keys():
msg = f"Unknown RPC command alias: '{cmd_alias}'"
log.error(msg)
raise KeyError(msg)

with cfg_cards:
if not overwrite and card_id in cfg_cards.keys():
msg = f"Card already registered: '{card_id}'. Abort. (use overwrite=True to overrule)"
log.error(msg)
raise KeyError(msg)

cfg_cards[card_id] = {'alias': cmd_alias}
if args is not None:

# For play_from_reader, expect a single dict of args
if cmd_alias == 'play_from_reader':
# Use either kwargs or args if it's a dict
if kwargs is not None:
cfg_cards[card_id]['args'] = kwargs
elif isinstance(args, dict):
cfg_cards[card_id]['args'] = args
else:
log.error(f"play_from_reader requires dict arguments, got: {type(args)}")
raise ValueError("play_from_reader requires dict arguments")
# For other commands, maintain list args support
elif args is not None:
cfg_cards[card_id]['args'] = args
if kwargs is not None:
cfg_cards[card_id]['kwargs'] = args

if ignore_same_id_delay is not None:
cfg_cards[card_id]['ignore_same_id_delay'] = ignore_same_id_delay
if ignore_card_removal_action is not None:
cfg_cards[card_id]['ignore_card_removal_action'] = ignore_card_removal_action

if auto_save:
cfg_cards.save()

publishing.get_publisher().send(f'{plugs.loaded_as(__name__)}.database.has_changed', time.ctime())


Expand Down
6 changes: 3 additions & 3 deletions src/jukebox/components/rpc_command_alias.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@
# --------------------------------------------------------------
cmd_alias_definitions = {
# Player
'play_card': {
'title': 'Play music folder triggered by card swipe',
'play_from_reader': {
'title': 'Play content triggered by card swipe, supports second swipe',
'note': "This function you'll want to use most often",
'package': 'player',
'plugin': 'ctrl',
'method': 'play_card'},
'method': 'play_from_reader'},
'play_album': {
'title': 'Play Album triggered by card swipe',
'note': "This function plays the content of a given album",
Expand Down
17 changes: 9 additions & 8 deletions src/webapp/public/locales/de/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
"next_song": "Nächster Song",
"pause": "Pause",
"play": "Abspielen",
"play_content": "Inhalte abspielen",
"prev_song": "Vorheriger Song",
"shuffle": "Zufallswiedergabe",
"repeat": "Wiedergabe wiederholen",
Expand All @@ -40,7 +41,7 @@
"label": "Aktionen",
"placeholder": "Wähle eine Aktion aus",
"actions": {
"play_music": "Musik abspielen",
"play_content": "Inhalte abspielen",
"audio": "Audio & Lautstärke",
"host": "System",
"timers": "Timer",
Expand All @@ -53,15 +54,15 @@
"label-full": "Gesamte Addresse (z.B. 192.168.1.53)",
"label-short": "Letzter Quadrant (z.B. 53)"
},
"play-music": {
"play-content": {
"commands": {
"play_album": "Ausgewähltes Album",
"play_folder": "Ausgewählter Ordner",
"play_single": "Ausgewählter Song"
"album": "Ausgewähltes Album",
"folder": "Ausgewählter Ordner",
"single": "Ausgewählter Song"
},
"button-label": "Musik auswählen",
"no-music-selected": "Es ist keine Musik ausgewählt.",
"loading-song-error": "Während des Ladens des Songs ist ein Fehler aufgetreten."
"button-label": "Inhalt auswählen",
"no-music-selected": "Es sind keine Inhalte ausgewählt.",
"loading-song-error": "Während des Ladens des Inhalts ist ein Fehler aufgetreten."
},
"audio": {
"repeat": {
Expand Down
17 changes: 9 additions & 8 deletions src/webapp/public/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
"next_song": "Next song",
"pause": "Pause",
"play": "Play",
"play_content": "Play content",
"prev_song": "Previous song",
"shuffle": "Shuffle",
"repeat": "Repeat",
Expand All @@ -40,7 +41,7 @@
"label": "Actions",
"placeholder": "Select an action",
"actions": {
"play_music": "Play music",
"play_content": "Play content",
"audio": "Audio & Volume",
"host": "System",
"timers": "Timers",
Expand All @@ -53,15 +54,15 @@
"label-full": "Full address (e.g. 192.168.1.53)",
"label-short": "Last quadrant (e.g. 53)"
},
"play-music": {
"play-content": {
"commands": {
"play_album": "Selected album",
"play_folder": "Selected folder",
"play_single": "Selected song"
"album": "Selected album",
"folder": "Selected folder",
"single": "Selected song"
},
"button-label": "Select music",
"no-music-selected": "No music selected",
"loading-song-error": "An error occurred while loading song."
"button-label": "Select content",
"no-music-selected": "No content selected",
"loading-song-error": "An error occurred while loading the content."
},
"audio": {
"repeat": {
Expand Down
18 changes: 18 additions & 0 deletions src/webapp/src/commands/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,24 @@ const commands = {
method: 'play_content',
argKeys: ['content', 'content_type', 'recursive']
},
// play_single: {
// _package: 'player',
// plugin: 'ctrl',
// method: 'play_single',
// argKeys: ['song_url']
// },
// play_folder: {
// _package: 'player',
// plugin: 'ctrl',
// method: 'play_folder',
// argKeys: ['folder']
// },
// play_album: {
// _package: 'player',
// plugin: 'ctrl',
// method: 'play_album',
// argKeys: ['albumartist', 'album']
// },
pause: {
_package: 'player',
plugin: 'ctrl',
Expand Down
8 changes: 4 additions & 4 deletions src/webapp/src/components/Cards/controls/actions-controls.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import {
import CardsDeleteDialog from '../dialogs/delete';
import request from '../../../utils/request';
import {
cleanObject,
getActionAndCommand,
getArgsValues
} from '../utils';

const ActionsControls = ({
Expand All @@ -24,14 +24,14 @@ const ActionsControls = ({
const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);

const handleRegisterCard = async () => {
const args = getArgsValues(actionData);
const { args } = actionData.command || {};
const { command: cmd_alias } = getActionAndCommand(actionData);

const kwargs = {
card_id: cardId.toString(),
cmd_alias,
cmd_alias: cmd_alias === 'play_content' ? 'play_from_reader' : cmd_alias,
overwrite: true,
...(args.length && { args }),
args: cleanObject(args),
};

const { error } = await request('registerCard', kwargs);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,18 @@ import SelectedAlbum from './selected-album';
import SelectedFolder from './selected-folder';
import SelectedSingle from './selected-single';

const SelectPlayMusic = ({
const SelectPlayContent = ({
actionData,
cardId,
}) => {
const { t } = useTranslation();
const navigate = useNavigate();

const { command } = getActionAndCommand(actionData);
const { content_type } = actionData.command.args || {};

const values = getArgsValues(actionData);

const selectMusic = () => {
const selectContent = () => {
const searchParams = createSearchParams({
isSelecting: true,
cardId
Expand All @@ -44,30 +45,30 @@ const SelectPlayMusic = ({

return (
<Grid container>
{command &&
{content_type &&
<Grid item xs={12}>
<Typography>
{t(`cards.controls.actions.play-music.commands.${command}`)}
{t(`cards.controls.actions.play-content.commands.${content_type}`)}
</Typography>
</Grid>
}
<Grid item xs={12}>
{command === 'play_album' && <SelectedAlbum values={values} />}
{command === 'play_folder' && <SelectedFolder values={values} />}
{command === 'play_single' && <SelectedSingle values={values} />}
{content_type === 'album' && <SelectedAlbum values={values} />}
{content_type === 'folder' && <SelectedFolder values={values} />}
{content_type === 'single' && <SelectedSingle values={values} />}
</Grid>

<Grid item xs={12} sx={{ display: 'flex', justifyContent: 'center' }}>
<Button
variant="outlined"
onClick={selectMusic}
onClick={selectContent}
endIcon={<KeyboardArrowRightIcon />}
>
{t('cards.controls.actions.play-music.button-label')}
{t('cards.controls.actions.play-content.button-label')}
</Button>
</Grid>
</Grid>
);
};

export default SelectPlayMusic;
export default SelectPlayContent;
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const NoMusicSelected = () => {

return (
<Typography>
{t('cards.controls.actions.play-music.no-music-selected')}
{t('cards.controls.actions.play-content.no-music-selected')}
</Typography>
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { List } from '@mui/material';
import AlbumListItem from '../../../../Library/lists/albums/album-list/album-list-item'
import NoMusicSelected from './no-music-selected';

const SelectedAlbum = ({ values: [albumartist, album] }) => {
const SelectedAlbum = ({ values: [{ albumartist, album }] }) => {
if (albumartist && album) {
return (
<List sx={{ width: '100%' }}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ const SelectecSingle = ({ values: [song_url] }) => {
if (error) {
return (
<Typography>
{t('cards.controls.actions.play-music.loading-song-error')}
{t('cards.controls.actions.play-content.loading-song-error')}
</Typography>
);
}
Expand Down
6 changes: 3 additions & 3 deletions src/webapp/src/components/Cards/controls/controls-selector.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
} from '@mui/material';

import SelectCommandAliases from './select-command-aliases';
import SelectPlayMusic from './actions/play-music';
import SelectPlayContent from './actions/play-content';
import SelectTimers from './actions/timers';
import SelectAudio from './actions/audio';
import { buildActionData } from '../utils';
Expand Down Expand Up @@ -61,8 +61,8 @@ const ControlsSelector = ({
/>
}

{actionData.action === 'play_music' &&
<SelectPlayMusic
{actionData.action === 'play_content' &&
<SelectPlayContent
actionData={actionData}
cardId={cardId}
/>
Expand Down
4 changes: 3 additions & 1 deletion src/webapp/src/components/Cards/edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,11 @@ const CardsEdit = () => {
if (result && result[cardId]) {
const {
action: { args },
from_alias: command
from_alias,
} = result[cardId];

const command = from_alias === 'play_from_reader' ? 'play_content' : from_alias;

const action = findActionByCommand(command);
const actionData = buildActionData(action, command, args);

Expand Down
Loading

0 comments on commit c3040d1

Please sign in to comment.