dsh-music-panel 0.3.1 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/client.js +63 -23
  3. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.3.2
4
+
5
+ ### 变更
6
+
7
+ - 播放顺序合并为三种互斥模式:顺序播放(播完停止)、随机播放(随机循环)、单曲循环;底栏、播放页、主面板 chips 三处按钮与图标同步
8
+ - 播放队列标题显示当前播放模式
9
+ - 旧状态归一化:升级后 `loop=all + order=list` 视为顺序播放
10
+
3
11
  ## 0.3.1
4
12
 
5
13
  ### 修复
package/client.js CHANGED
@@ -80,6 +80,9 @@ window.__ModuleLoader__.load({
80
80
  'page.done': '完成',
81
81
  'page.clear': '清空列表',
82
82
  'page.loopAll': '列表循环',
83
+ 'page.modeSequence': '顺序播放',
84
+ 'page.modeRandom': '随机播放',
85
+ 'page.modeOne': '单曲循环',
83
86
  'page.loopOne': '单曲循环',
84
87
  'page.loopNone': '不循环',
85
88
  'page.shuffle': '随机播放',
@@ -251,6 +254,9 @@ window.__ModuleLoader__.load({
251
254
  'page.done': 'Done',
252
255
  'page.clear': 'Clear list',
253
256
  'page.loopAll': 'Repeat all',
257
+ 'page.modeSequence': 'Play in order',
258
+ 'page.modeRandom': 'Shuffle',
259
+ 'page.modeOne': 'Repeat one',
254
260
  'page.loopOne': 'Repeat one',
255
261
  'page.loopNone': 'No repeat',
256
262
  'page.shuffle': 'Shuffle',
@@ -996,6 +1002,50 @@ window.__ModuleLoader__.load({
996
1002
  return order
997
1003
  }
998
1004
 
1005
+ // Three playback modes, mapped onto the engine's loop/order pair:
1006
+ // sequence → in order, stop at the end
1007
+ // random → shuffled, looping
1008
+ // one → repeat the current track
1009
+ var PLAY_MODES = ['sequence', 'random', 'one']
1010
+
1011
+ function playModeOf(snap) {
1012
+ if (snap.loop === 'one') return 'one'
1013
+ if (snap.order === 'random') return 'random'
1014
+ return 'sequence'
1015
+ }
1016
+
1017
+ function playModeLabel(mode) {
1018
+ return mode === 'one'
1019
+ ? t('page.modeOne')
1020
+ : mode === 'random'
1021
+ ? t('page.modeRandom')
1022
+ : t('page.modeSequence')
1023
+ }
1024
+
1025
+ function playModeIcon(mode) {
1026
+ return mode === 'one' ? 'repeatOne' : mode === 'random' ? 'shuffle' : 'list'
1027
+ }
1028
+
1029
+ function applyPlayMode(mode) {
1030
+ if (mode === 'one') {
1031
+ player.setLoop('one')
1032
+ player.setOrder('list')
1033
+ return
1034
+ }
1035
+ if (mode === 'random') {
1036
+ player.setLoop('all')
1037
+ player.setOrder('random')
1038
+ return
1039
+ }
1040
+ player.setLoop('none')
1041
+ player.setOrder('list')
1042
+ }
1043
+
1044
+ function cyclePlayMode(snap) {
1045
+ var current = playModeOf(snap)
1046
+ applyPlayMode(PLAY_MODES[(PLAY_MODES.indexOf(current) + 1) % PLAY_MODES.length])
1047
+ }
1048
+
999
1049
  function nextIndexOf(index, order, size, randomOrder) {
1000
1050
  if (size <= 1) return 0
1001
1051
  if (order === 'random') {
@@ -1059,8 +1109,8 @@ window.__ModuleLoader__.load({
1059
1109
  queue: [],
1060
1110
  index: -1,
1061
1111
  playing: false,
1062
- loop: prefs.loop === 'one' || prefs.loop === 'none' ? prefs.loop : 'all',
1063
- order: prefs.order === 'random' ? 'random' : 'list',
1112
+ loop: prefs.loop === 'one' ? 'one' : 'none',
1113
+ order: prefs.order === 'random' && prefs.loop !== 'one' ? 'random' : 'list',
1064
1114
  // Volume follows the system mixer: the plugin no longer exposes its own.
1065
1115
  volume: 1,
1066
1116
  muted: false,
@@ -1221,8 +1271,8 @@ window.__ModuleLoader__.load({
1221
1271
  state = Object.assign({}, state, {
1222
1272
  queue: queue,
1223
1273
  index: index,
1224
- loop: saved.loop === 'one' || saved.loop === 'none' ? saved.loop : 'all',
1225
- order: saved.order === 'random' ? 'random' : 'list',
1274
+ loop: saved.loop === 'one' ? 'one' : saved.order === 'random' ? 'all' : 'none',
1275
+ order: saved.order === 'random' && saved.loop !== 'one' ? 'random' : 'list',
1226
1276
  currentTime: saved.positionSec > 0 ? saved.positionSec : 0,
1227
1277
  duration: saved.durationSec > 0 ? saved.durationSec : 0,
1228
1278
  playing: false,
@@ -2306,11 +2356,11 @@ window.__ModuleLoader__.load({
2306
2356
  )
2307
2357
 
2308
2358
  function cycleLoop() {
2309
- player.setLoop(snap.loop === 'all' ? 'one' : snap.loop === 'one' ? 'none' : 'all')
2359
+ cyclePlayMode(snap)
2310
2360
  }
2311
2361
 
2312
2362
  function loopLabel() {
2313
- return snap.loop === 'one' ? t('page.loopOne') : snap.loop === 'none' ? t('page.loopNone') : t('page.loopAll')
2363
+ return playModeLabel(playModeOf(snap))
2314
2364
  }
2315
2365
 
2316
2366
  return h(
@@ -2623,7 +2673,7 @@ window.__ModuleLoader__.load({
2623
2673
  h(
2624
2674
  'button',
2625
2675
  { type: 'button', className: 'mu-icon-btn', title: loopLabel(), onClick: cycleLoop },
2626
- icon(snap.loop === 'one' ? 'repeatOne' : 'repeat', 18),
2676
+ icon(playModeIcon(playModeOf(snap)), 18),
2627
2677
  ),
2628
2678
  h(
2629
2679
  'button',
@@ -3324,11 +3374,11 @@ window.__ModuleLoader__.load({
3324
3374
  )
3325
3375
 
3326
3376
  function cycleLoop() {
3327
- player.setLoop(snap.loop === 'all' ? 'one' : snap.loop === 'one' ? 'none' : 'all')
3377
+ cyclePlayMode(snap)
3328
3378
  }
3329
3379
 
3330
3380
  function loopLabel() {
3331
- return snap.loop === 'one' ? t('page.loopOne') : snap.loop === 'none' ? t('page.loopNone') : t('page.loopAll')
3381
+ return playModeLabel(playModeOf(snap))
3332
3382
  }
3333
3383
 
3334
3384
  function toggleSelect(track) {
@@ -4445,7 +4495,7 @@ window.__ModuleLoader__.load({
4445
4495
  h(
4446
4496
  'button',
4447
4497
  { type: 'button', className: 'mu-chip', title: loopLabel(), onClick: cycleLoop },
4448
- icon(snap.loop === 'one' ? 'repeatOne' : 'repeat', 15),
4498
+ icon(playModeIcon(playModeOf(snap)), 15),
4449
4499
  h('span', null, loopLabel()),
4450
4500
  ),
4451
4501
  h(
@@ -4460,18 +4510,6 @@ window.__ModuleLoader__.load({
4460
4510
  icon('play', 13),
4461
4511
  h('span', null, t('page.playAll')),
4462
4512
  ),
4463
- h(
4464
- 'button',
4465
- {
4466
- type: 'button',
4467
- className: 'mu-chip mu-chip-round' + (snap.order === 'random' ? ' is-on' : ''),
4468
- title: t('page.shuffle'),
4469
- onClick: function () {
4470
- player.setOrder(snap.order === 'random' ? 'list' : 'random')
4471
- },
4472
- },
4473
- icon('shuffle', 15),
4474
- ),
4475
4513
  h(
4476
4514
  'button',
4477
4515
  {
@@ -4663,7 +4701,7 @@ window.__ModuleLoader__.load({
4663
4701
  title: loopLabel(),
4664
4702
  onClick: cycleLoop,
4665
4703
  },
4666
- icon(snap.loop === 'one' ? 'repeatOne' : 'repeat', 17),
4704
+ icon(playModeIcon(playModeOf(snap)), 17),
4667
4705
  ),
4668
4706
  h(
4669
4707
  'button',
@@ -4759,6 +4797,7 @@ window.__ModuleLoader__.load({
4759
4797
  'div',
4760
4798
  { className: 'mu-pop-head' },
4761
4799
  h('span', null, t('page.queue')),
4800
+ h('span', { className: 'mu-queue-mode' }, loopLabel()),
4762
4801
  snap.queue.length > 0
4763
4802
  ? h(
4764
4803
  'button',
@@ -5204,6 +5243,7 @@ window.__ModuleLoader__.load({
5204
5243
  '.mu-pop-head{display:flex;align-items:center;justify-content:space-between;padding:10px 12px 6px;font-size:12px;font-weight:600}',
5205
5244
  '.mu-pop-body{overflow-y:auto;padding:0 6px 8px}',
5206
5245
  '.mu-queue-row{display:grid;grid-template-columns:26px minmax(0,1fr) minmax(0,70px) auto;align-items:center;gap:8px;padding:5px 8px;border-radius:var(--dsw-radius-sm,6px);font-size:12px;cursor:pointer}',
5246
+ '.mu-queue-mode{font-size:11px;color:var(--dsw-alias-label-tertiary,#8a8a93);padding:1px 6px;border-radius:999px;background:var(--dsw-alias-bg-layer-3,rgba(255,255,255,.06));white-space:nowrap}',
5207
5247
  '.mu-queue-actions{display:inline-flex;align-items:center;gap:2px;justify-self:end}',
5208
5248
  '.mu-queue-btn{width:20px;height:20px;padding:0;border:0;border-radius:4px;background:transparent;color:var(--dsw-alias-label-tertiary,#8a8a93);font-size:12px;line-height:20px;cursor:pointer}',
5209
5249
  '.mu-queue-btn:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover,rgba(255,255,255,.06));color:var(--dsw-alias-label-primary,#f4f4f5)}',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-music-panel",
3
- "version": "0.3.1",
3
+ "version": "0.3.2",
4
4
  "type": "module",
5
5
  "description": "Local music library for DeepSeek Harness: scan a folder, browse tracks with cover art and tags, and play through a sidebar-panel player with loop, shuffle and volume. · DSH 本地音乐插件:扫描音乐目录、读取封面与标签、侧栏入口 + 全屏播放器。",
6
6
  "license": "MIT",