fix: media progress bar initial width and duration labels
This commit is contained in:
@@ -301,6 +301,16 @@ body {
|
||||
transition: width .3s linear;
|
||||
}
|
||||
|
||||
/* 时长文字:当前时长 / 总时长 */
|
||||
/* Time labels: current / total duration */
|
||||
.media-card .time-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
font-size: 11px;
|
||||
color: var(--text-dim);
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
/* 无时长信息时的活动脉冲进度条 */
|
||||
/* Indeterminate pulse when no duration is available */
|
||||
.media-card .bar.indeterminate {
|
||||
|
||||
@@ -161,6 +161,7 @@ function renderMediaCard(info) {
|
||||
const playIcon = info.playing ? ICON_PAUSE : ICON_PLAY;
|
||||
// title/artist 来自任意应用元数据,转义后插入,防 XSS
|
||||
// title/artist come from arbitrary app metadata; escape before insert (XSS)
|
||||
const pct = info.duration ? Math.min(100, (info.position / info.duration) * 100) : 0;
|
||||
el.innerHTML = `
|
||||
<div class="media-layout">
|
||||
${coverHtml}
|
||||
@@ -169,7 +170,11 @@ function renderMediaCard(info) {
|
||||
<div class="ar">${escapeHtml(info.artist)}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="prog"><div class="bar"></div></div>
|
||||
<div class="prog"><div class="bar" style="width:${pct}%"></div></div>
|
||||
<div class="time-row">
|
||||
<span class="t-cur">${fmtDuration(info.position)}</span>
|
||||
<span class="t-total">${fmtDuration(info.duration)}</span>
|
||||
</div>
|
||||
<div class="controls">
|
||||
<button class="ctl" data-act="prev" title="上一首">${ICON_PREV}</button>
|
||||
<button class="ctl play" data-act="play" title="播放/暂停">${playIcon}</button>
|
||||
@@ -209,20 +214,35 @@ function updateMediaProgressState(info) {
|
||||
let mediaTicker = null;
|
||||
function startMediaTicker() {
|
||||
if (mediaTicker) return;
|
||||
mediaTicker = setInterval(() => {
|
||||
const tick = () => {
|
||||
if (!mediaProgressState) return;
|
||||
const bar = document.querySelector('.media-card .bar');
|
||||
if (!bar || !mediaProgressState) return;
|
||||
const cur = document.querySelector('.media-card .t-cur');
|
||||
const { position, duration, playing, updatedAt } = mediaProgressState;
|
||||
if (!duration) {
|
||||
// 无时长信息(部分 App 不提供 duration):显示活动脉冲而非空白
|
||||
// No duration (some apps omit it): show an indeterminate pulse instead of blank
|
||||
bar.classList.add('indeterminate');
|
||||
if (bar) bar.classList.add('indeterminate');
|
||||
return;
|
||||
}
|
||||
bar.classList.remove('indeterminate');
|
||||
const pos = playing ? position + (Date.now() - updatedAt) : position;
|
||||
bar.style.width = Math.min(100, (pos / duration) * 100) + '%';
|
||||
}, 1000);
|
||||
if (bar) {
|
||||
bar.classList.remove('indeterminate');
|
||||
bar.style.width = Math.min(100, (pos / duration) * 100) + '%';
|
||||
}
|
||||
if (cur) cur.textContent = fmtDuration(pos);
|
||||
};
|
||||
tick(); // 立即执行一次,避免初始 1 秒内进度条空白
|
||||
mediaTicker = setInterval(tick, 1000);
|
||||
}
|
||||
|
||||
// 时长格式化:毫秒 -> m:ss(未知返回 --:--)
|
||||
// Duration format: ms -> m:ss (--:-- when unknown)
|
||||
function fmtDuration(ms) {
|
||||
if (!ms || ms <= 0) return '--:--';
|
||||
const s = Math.floor(ms / 1000);
|
||||
const m = Math.floor(s / 60);
|
||||
return m + ':' + String(s % 60).padStart(2, '0');
|
||||
}
|
||||
|
||||
// 布局方向:默认上下(封面在上、信息在下),横条(宽>高)时左右
|
||||
|
||||
Reference in New Issue
Block a user