diff options
| author | Christophe Besson <cbesson@gmail.com> | 2026-08-24 17:39:41 +0200 |
|---|---|---|
| committer | Christophe Besson <cbesson@gmail.com> | 2026-08-24 17:39:41 +0200 |
| commit | 8c780b9928db8145b7fe18ecd137384ccfe25d8f (patch) | |
| tree | 5cfc06eec0fdf9bb7fe0a14f45e3ef803bb86a20 /packages/meshbay-hub/src/meshbay_hub/static/locales/es.js | |
| parent | 941d1a135dd7b03834576855e8e9fdaa24c4e406 (diff) | |
| download | meshbay-8c780b9928db8145b7fe18ecd137384ccfe25d8f.tar.gz | |
feat(hub): Music app client — album grid, flat list, persistent player
Implements the client half of docs/musicbay.md against MNP 0.8:
- music-app.js: album grid (grouped by artist -> album, from index-time
artist/album fields) or flat folder view, per-group localStorage
toggle like Videos. MusicBrainz (music_meta_req) is only looked up
when a track has no embedded cover at all — well-tagged files never
trigger a network call, unlike Videos where TMDB is unconditional.
Reuses video-app.js's MediaThumb/LazyTile (now exported) rather than
duplicating the chunk-path thumbnail decode + virtualization.
- music-player.js: the persistent player bar — queue, shuffle (Fisher-
Yates, keeps the current track in place when toggled), repeat (off/
all/one), volume (localStorage), prev/next, a one-track prefetch
cache. No MSE, no node-side streaming: a track is downloaded and
decrypted once via file-utils.js's pipelinedDownload, same chunk
pipeline Files already uses, then played from a blob URL.
- group-page.js: owns musicQueue/musicbrainzConfig state and renders
MusicPlayerBar outside the tab-switched area — deliberately, so
playback survives navigating to Chat/Files, the same reasoning the
video/preview modals are shell-owned rather than app-owned.
- apps.js: registers "music". transport.js: fetchMusicMeta (keyed by
path, same reordering-hazard fix as fetchMediaMeta),
setMusicbrainzConfig/setMusicbrainzEnabled (signed ops, mirroring
TMDB's), and the three new ack handlers. group-settings.js: a
MusicBrainz settings section (contact string, per-group toggle) —
the existing Applications checklist already picks up "music" for
free, per apps.md's own claim.
- icon.js: music/pause/skip-next/skip-prev/shuffle/repeat/volume,
drawn in the same stroked style as the existing set.
- i18n: group.tab_music, the music.* and settings_node.musicbrainz_*
keys, translated (not just copied) across all ten locales, Polish
carrying full one/few/many/other plural forms for music.n_tracks.
- webapp.py's _ASSETS, test_hook_ordering.py's STATIC_FILES and
test_transport_contracts.py's SPLIT_FILES gain the two new files.
Full suite (common + hub + node): 1116 passed, no regressions.
`npm run sync-ui` in meshbay-client confirmed both files copied.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KBi7ALLGfwcjBXt57yNMcy
Diffstat (limited to 'packages/meshbay-hub/src/meshbay_hub/static/locales/es.js')
| -rw-r--r-- | packages/meshbay-hub/src/meshbay_hub/static/locales/es.js | 31 |
1 files changed, 31 insertions, 0 deletions
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/es.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/es.js index d7f0f1e..113ae7a 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/locales/es.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/es.js @@ -75,6 +75,7 @@ export default { 'group.tab_files': 'Archivos', 'group.tab_chat': 'Chat', 'group.tab_video': 'Vídeos', + 'group.tab_music': 'Música', 'group.tab_members': 'Miembros', 'group.tab_settings': "Ajustes", 'members.danger_leave_hint': "Perderá el acceso a los archivos y al chat de este grupo.", @@ -174,6 +175,27 @@ export default { 'video.search_no_results': 'No se encontraron coincidencias.', 'video.search_apply_hint': 'Se aplica a todos los archivos agrupados actualmente bajo este título.', + // Música + 'music.mode_grid': 'Álbumes', + 'music.mode_flat': 'Lista plana', + 'music.empty': 'No se encontró música.', + 'music.unknown_album': 'Álbum desconocido', + 'music.play_all': 'Reproducir todo', + 'music.n_tracks': { + one: '{n} pista', + other: '{n} pistas', + }, + 'music.err_transport': 'Transporte no conectado', + 'music.player_play': 'Reproducir', + 'music.player_pause': 'Pausa', + 'music.player_prev': 'Anterior', + 'music.player_next': 'Siguiente', + 'music.player_shuffle': 'Aleatorio', + 'music.player_repeat_off': 'Repetición desactivada', + 'music.player_repeat_all': 'Repetir todo', + 'music.player_repeat_one': 'Repetir una', + 'music.player_volume': 'Volumen', + // LAN cast 'cast.start': 'Enviar a dispositivo', 'cast.stop': 'Detener envío', @@ -600,6 +622,15 @@ export default { 'settings_node.video_root_title': 'Carpeta raíz de Vídeos', 'settings_node.video_root_hint': 'Qué carpeta (o subcarpeta) trata la app Vídeos como su punto de entrada para este grupo. No se muestra nada en Vídeos, ni se realizan búsquedas en TMDB, hasta que se elija una.', 'settings_node.video_root_none': '— ninguna elegida —', + 'settings_node.musicbrainz_title': 'Metadatos de MusicBrainz', + 'settings_node.musicbrainz_hint': 'Permite que la app de Música muestre carátulas y nombres canónicos de MusicBrainz cuando una pista no tiene una carátula incrustada utilizable. Desactivado significa navegación solo por etiquetas/nombre de archivo, sin solicitudes a terceros.', + 'settings_node.musicbrainz_enabled': 'Activado', + 'settings_node.musicbrainz_disabled': 'Desactivado', + 'settings_node.musicbrainz_contact_label': 'Contacto (necesario para que MusicBrainz responda)', + 'settings_node.musicbrainz_contact_placeholder': 'tu@ejemplo.com o una URL de proyecto', + 'settings_node.musicbrainz_contact_set': 'Hay un contacto configurado.', + 'settings_node.musicbrainz_contact_unset': 'Sin contacto configurado — las búsquedas de MusicBrainz permanecen desactivadas hasta que se configure uno.', + 'settings_node.musicbrainz_save': 'Guardar', 'settings_node.video_root_save': 'Guardar', 'settings_node.video_root_change_confirm': 'Cambiar la raíz de Vídeos reemplaza lo que ve cada miembro en la pestaña Vídeos. ¿Continuar?', |