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/zh-CN.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/zh-CN.js')
| -rw-r--r-- | packages/meshbay-hub/src/meshbay_hub/static/locales/zh-CN.js | 31 |
1 files changed, 31 insertions, 0 deletions
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/zh-CN.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/zh-CN.js index 33a0e25..7e7676b 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/locales/zh-CN.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/zh-CN.js @@ -74,6 +74,7 @@ export default { 'group.tab_files': '文件', 'group.tab_chat': '聊天', 'group.tab_video': '视频', + 'group.tab_music': '音乐', 'group.tab_members': '成员', 'group.tab_settings': "设置", 'members.danger_leave_hint': "您将无法再访问该群组的文件和聊天。", @@ -169,6 +170,27 @@ export default { 'video.search_no_results': '未找到匹配项。', 'video.search_apply_hint': '将应用于当前归类在此标题下的所有文件。', + // 音乐 + 'music.mode_grid': '专辑', + 'music.mode_flat': '平铺列表', + 'music.empty': '未找到音乐。', + 'music.unknown_album': '未知专辑', + 'music.play_all': '全部播放', + 'music.n_tracks': { + one: '{n} 首曲目', + other: '{n} 首曲目', + }, + 'music.err_transport': '传输未连接', + 'music.player_play': '播放', + 'music.player_pause': '暂停', + 'music.player_prev': '上一首', + 'music.player_next': '下一首', + 'music.player_shuffle': '随机播放', + 'music.player_repeat_off': '不重复', + 'music.player_repeat_all': '全部重复', + 'music.player_repeat_one': '单曲重复', + 'music.player_volume': '音量', + // LAN cast 'cast.start': '投射到设备', 'cast.stop': '停止投射', @@ -584,6 +606,15 @@ export default { 'settings_node.video_root_title': '视频根目录', 'settings_node.video_root_hint': '该文件夹(或子文件夹)将作为此群组"视频"应用的入口。在选择之前,"视频"中不会显示任何内容,也不会执行任何 TMDB 查询。', 'settings_node.video_root_none': '— 未选择 —', + 'settings_node.musicbrainz_title': 'MusicBrainz 元数据', + 'settings_node.musicbrainz_hint': '当曲目没有可用的内嵌封面时,允许音乐应用显示来自 MusicBrainz 的封面和规范名称。关闭表示仅按标签/文件名浏览,不向第三方发送请求。', + 'settings_node.musicbrainz_enabled': '已启用', + 'settings_node.musicbrainz_disabled': '已禁用', + 'settings_node.musicbrainz_contact_label': '联系方式(MusicBrainz 需要它才能响应请求)', + 'settings_node.musicbrainz_contact_placeholder': 'you@example.com 或项目 URL', + 'settings_node.musicbrainz_contact_set': '已配置联系方式。', + 'settings_node.musicbrainz_contact_unset': '未配置联系方式 — 在设置之前,MusicBrainz 查询将保持关闭。', + 'settings_node.musicbrainz_save': '保存', 'settings_node.video_root_save': '保存', 'settings_node.video_root_change_confirm': '更改视频根目录会替换每位成员在"视频"标签页中看到的内容。是否继续?', |