dsh-music-player 0.6.3 → 0.6.4

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 (2) hide show
  1. package/lib/client.js +20 -9
  2. package/package.json +1 -1
package/lib/client.js CHANGED
@@ -1921,6 +1921,10 @@ window.__ModuleLoader__.load({
1921
1921
  if (bookFromRef + 1 < bookTotal) {
1922
1922
  // 进入新块:每个块各拥有一次自动重试的机会。
1923
1923
  bookAutoRetried = false;
1924
+ // 恢复定位钉只属于「被恢复的那一块」:切到下一块必须丢弃,否则下一块的
1925
+ // 音频会被 seek 回上一块的恢复位置(跳到末尾即刻结束 → 卡住/无声音/字幕不动)。
1926
+ bookRestorePos = -1;
1927
+ restoredMusicPos = null;
1924
1928
  const endedDur = Number.isFinite(audio.duration) ? audio.duration : (audio.currentTime || 0);
1925
1929
  if (Number.isFinite(endedDur)) bookBaseTime += endedDur;
1926
1930
  playBookFrom(id, bookFromRef + 1, true);
@@ -2175,8 +2179,13 @@ window.__ModuleLoader__.load({
2175
2179
  // start until then) — anchored on top of the book-wide clock.
2176
2180
  if (bookRestorePos >= 0 && String(store.currentId).startsWith('book:')) {
2177
2181
  const ct = audio.currentTime || 0;
2178
- if (ct > bookRestorePos + 1) {
2179
- bookRestorePos = -1; // real playback advanced past the spot
2182
+ // 释放条件:真实播放已明显越过恢复点,或恢复点已超出本块的实际时长
2183
+ // (块可能被重新合成得更短——此时继续 pin 会反复 seek 到块末尾并即刻
2184
+ // 结束,表现为卡住/无声音/字幕不动)。超出时放弃该恢复点、从块头正常播。
2185
+ const pastSpot = ct > bookRestorePos + 1;
2186
+ const pastEnd = Number.isFinite(audio.duration) && audio.duration > 0 && bookRestorePos >= audio.duration;
2187
+ if (pastSpot || pastEnd) {
2188
+ bookRestorePos = -1; // real playback advanced past the spot / spot unreachable
2180
2189
  } else {
2181
2190
  if (store.playing && ct < bookRestorePos - 0.5) {
2182
2191
  try { audio.currentTime = bookRestorePos; } catch (e) {}
@@ -2604,7 +2613,7 @@ window.__ModuleLoader__.load({
2604
2613
  // 播放控制图标(上一首/播放/暂停/下一首/停止):用 SVG 替代 ⏮▶⏸⏭⏹ 文本字形。
2605
2614
  // 这些 Unicode 符号(尤其 ⏸ 常以 emoji 呈现)宽高/基线不一致,点击切换会让按钮
2606
2615
  // 大小与位置偏移;统一用同尺寸 viewBox=24 的 SVG,保证按钮恒定尺寸、图标精确居中。
2607
- const iconSvg = (path, w = 14) => (props) => React.createElement('svg', { className: props.className || '', width: w, height: w, viewBox: '0 0 24 24', fill: 'currentColor', 'aria-hidden': true },
2616
+ const iconSvg = (path, w = 16) => (props) => React.createElement('svg', { className: props.className || '', width: w, height: w, viewBox: '0 0 24 24', fill: 'currentColor', 'aria-hidden': true },
2608
2617
  React.createElement('path', { d: path }));
2609
2618
  const PlayIcon = iconSvg('M8 5v14l11-7z');
2610
2619
  const PauseIcon = iconSvg('M6 19h4V5H6v14zm8-14v14h4V5h-4z');
@@ -2800,7 +2809,7 @@ window.__ModuleLoader__.load({
2800
2809
  title: faved ? '取消收藏(从「我最喜欢」移除)' : '收藏到「我最喜欢」',
2801
2810
  onClick: toggleFav,
2802
2811
  }, React.createElement('svg', {
2803
- viewBox: '0 0 24 24', width: 14, height: 14,
2812
+ viewBox: '0 0 24 24', width: 16, height: 16,
2804
2813
  fill: faved ? 'currentColor' : 'none', stroke: 'currentColor', strokeWidth: 2, 'aria-hidden': true,
2805
2814
  }, React.createElement('path', { d: 'M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z' }))) : null;
2806
2815
  const showBarBtns = () => { if (hoverTimerRef.current !== null) { clearTimeout(hoverTimerRef.current); hoverTimerRef.current = null; } setBarHover(true); };
@@ -4667,9 +4676,9 @@ window.__ModuleLoader__.load({
4667
4676
  '.dsh-music-bar-lyric { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; text-align: center; color: var(--dsw-alias-label-primary, #e6e6e6); font-size: 14px; animation: dsh-music-lyric-in 0.3s ease 0.3s backwards; }\n' +
4668
4677
  '@keyframes dsh-music-lyric-in { from { opacity: 0; } to { opacity: 1; } }\n' +
4669
4678
  '.dsh-music-bar-warn { background: transparent; border: none; color: var(--dsw-alias-state-warn-primary, #d9a441); font-size: 12px; cursor: pointer; padding: 0; white-space: nowrap; }\n' +
4670
- '.dsh-music-bar-btn { display: inline-flex; align-items: center; justify-content: center; flex: none; height: 20px; background: transparent; border: none; color: var(--dsw-alias-label-secondary, #8a8f98); cursor: pointer; font-size: 13px; line-height: 1; padding: 0 4px; border-radius: 4px; }\n' +
4671
- '.dsh-music-bar-btn:hover { color: var(--dsw-alias-brand-primary, #4f8cff); }\n' +
4672
- '.dsh-music-bar-btn.active { color: var(--dsw-alias-brand-primary, #4f8cff); }\n' +
4679
+ '.dsh-music-bar-btn { display: inline-flex; align-items: center; justify-content: center; flex: none; width: 24px; height: 24px; border-radius: 50%; border: 1px solid var(--dsw-alias-border-l1, rgba(128,128,128,0.25)); background: var(--dsw-alias-bg-layer-2, rgba(255,255,255,0.05)); color: var(--dsh-music-accent, #2f9e6e); cursor: pointer; font-size: 13px; line-height: 1; padding: 0; }\n' +
4680
+ '.dsh-music-bar-btn:hover { color: var(--dsh-music-accent-fg, #fff); background: var(--dsh-music-accent, #2f9e6e); }\n' +
4681
+ '.dsh-music-bar-btn.active { color: var(--dsh-music-accent, #2f9e6e); }\n' +
4673
4682
  '.dsh-music-bar-vol { position: relative; flex: none; display: inline-flex; align-self: center; }\n' +
4674
4683
  '.dsh-music-bar-vol-pop { position: absolute; bottom: calc(100% + 6px); left: 50%; transform: translateX(-50%); display: flex; align-items: center; justify-content: center; width: 36px; height: 108px; box-sizing: border-box; background: var(--dsw-alias-bg-overlay, #1e1f22); border: 1px solid var(--dsw-alias-border-l2, rgba(128,128,128,0.35)); border-radius: 8px; box-shadow: 0 8px 20px rgba(0,0,0,0.3); z-index: 60; }\n' +
4675
4684
  // 讲书时音量弹层加宽,容纳 AI 声音选择 + 音量条。
@@ -4701,7 +4710,7 @@ window.__ModuleLoader__.load({
4701
4710
  '@keyframes dsh-music-spin { to { transform: rotate(360deg); } }\n' +
4702
4711
  '.dsh-music-bar-berr { margin-left: 8px; color: var(--dsw-alias-state-error-primary, #e5534b); font-size: 11px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 220px; display: inline-flex; align-items: center; gap: 4px; }\n' +
4703
4712
  '.dsh-music-bar-berr-text { overflow: hidden; text-overflow: ellipsis; }\n' +
4704
- '.dsh-music-bar-btn.retry { color: var(--dsw-alias-state-error-primary, #e5534b); border: 1px solid var(--dsw-alias-border-l1, rgba(128,128,128,0.3)); border-radius: 6px; padding: 0 6px; height: 18px; flex: none; }\n' +
4713
+ '.dsh-music-bar-btn.retry { width: auto; color: var(--dsw-alias-state-error-primary, #e5534b); border: 1px solid var(--dsw-alias-border-l1, rgba(128,128,128,0.3)); border-radius: 6px; padding: 0 6px; height: 18px; flex: none; }\n' +
4705
4714
  '.dsh-music-bar-btn.retry:hover { background: var(--dsw-alias-state-error-primary, #e5534b); color: #fff; }\n' +
4706
4715
  '.dsh-music-bar .dsh-music-mode-trigger { width: 24px; height: 24px; }\n' +
4707
4716
  '.dsh-music-bar .dsh-music-mode-trigger svg { flex: none; }\n' +
@@ -4920,7 +4929,9 @@ window.__ModuleLoader__.load({
4920
4929
  '.dsh-music-panel-toast.err { background: var(--dsw-alias-state-error-primary, #e5534b); }\n' +
4921
4930
  '@keyframes dsh-music-toast-in { from { opacity: 0; transform: translate(-50%, -50%) scale(0.94); } to { opacity: 1; transform: translate(-50%, -50%) scale(1); } }\n' +
4922
4931
  '.dsh-music-bar-btn.fav { color: var(--dsw-alias-label-secondary, #8a8f98); }\n' +
4923
- '.dsh-music-bar-btn.fav.on { color: var(--dsh-music-accent, #2f9e6e); }\n';
4932
+ '.dsh-music-bar-btn.fav:hover { color: var(--dsh-music-accent-fg, #fff); }\n' +
4933
+ '.dsh-music-bar-btn.fav.on { color: var(--dsh-music-accent, #2f9e6e); }\n' +
4934
+ '.dsh-music-bar-btn.fav.on:hover { color: var(--dsh-music-accent-fg, #fff); }\n';
4924
4935
 
4925
4936
  return module.exports;
4926
4937
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-music-player",
3
- "version": "0.6.3",
3
+ "version": "0.6.4",
4
4
  "description": "DeepSeek Harness 本地音乐 + AI 讲书插件:Host 扫描音乐目录并以 HTTP 流式提供音频、解析 .txt 小说结构并经 MiMo TTS 合成朗读,浏览器侧提供播放条/播放面板/章节目录跳转/多声音选择/实时频谱,并注册 music_play 模型工具",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",