Update shortcodes.js

This commit is contained in:
Vaica committed 2026-06-24 21:02:53 +08:00
1 parent e3ef5e6767
commit 6fbeb89db8
1 file changed
+228 -20
+228 -20
View File
@@ -3,6 +3,189 @@
* 移植自 Hugo-Theme-Amigo * 移植自 Hugo-Theme-Amigo
*/ */
// ============================================================
// Global Audio Manager - 全局音频/视频管理器
// 确保所有音频控件互斥播放,PJAX 切换时保存进度
// ============================================================
var AudioManager = {
currentPlaying: null,
currentType: null,
savedStates: {},
pauseAll: function() {
// Pause all voice bubbles
document.querySelectorAll('.amigo-voice-bubble.is-playing').forEach(function(bubble) {
if (bubble.__audio) {
try {
bubble.__audio.pause();
bubble.__audio.currentTime = 0;
} catch (e) {}
}
bubble.classList.remove('is-playing');
});
// Pause all music cards
document.querySelectorAll('.amigo-music-card[data-playing="true"]').forEach(function(card) {
if (card.__audio) {
try { card.__audio.pause(); } catch (e) {}
}
card.setAttribute('data-playing', 'false');
var playBtn = card.querySelector('.amigo-music-card__play');
if (playBtn) playBtn.setAttribute('aria-pressed', 'false');
});
// Pause all live photos
document.querySelectorAll('.amigo-livephoto.is-playing').forEach(function(livePhoto) {
var video = livePhoto.querySelector('.amigo-livephoto-video');
if (video) {
try { video.pause(); video.currentTime = 0; } catch (e) {}
}
livePhoto.classList.remove('is-playing');
});
this.currentPlaying = null;
this.currentType = null;
},
registerPlay: function(element, type) {
if (this.currentPlaying && this.currentPlaying !== element) {
this.pauseAll();
}
this.currentPlaying = element;
this.currentType = type;
},
saveState: function() {
var states = [];
// Save music card states
document.querySelectorAll('.amigo-music-card').forEach(function(card, index) {
var audio = card.__audio;
if (audio && audio.src) {
states.push({
type: 'music',
src: card.dataset.src,
currentTime: audio.currentTime,
isPlaying: card.getAttribute('data-playing') === 'true',
index: index
});
}
});
// Save live photo states
document.querySelectorAll('.amigo-livephoto').forEach(function(livePhoto, index) {
var video = livePhoto.querySelector('.amigo-livephoto-video');
if (video && video.src) {
states.push({
type: 'livephoto',
src: livePhoto.dataset.src,
currentTime: video.currentTime,
isPlaying: livePhoto.classList.contains('is-playing'),
index: index
});
}
});
this.savedStates[window.location.pathname] = states;
},
restoreState: function() {
var path = window.location.pathname;
var states = this.savedStates[path];
if (!states || states.length === 0) return;
states.forEach(function(state) {
if (state.type === 'music') {
var cards = document.querySelectorAll('.amigo-music-card');
var card = cards[state.index];
if (card && card.__audio && card.dataset.src === state.src) {
var audio = card.__audio;
var playBtn = card.querySelector('.amigo-music-card__play');
var seekInput = card.querySelector('.amigo-music-card__seek');
var currentTimeEl = card.querySelector('.amigo-music-card__time--current');
audio.addEventListener('loadedmetadata', function onLoaded() {
audio.currentTime = state.currentTime;
audio.removeEventListener('loadedmetadata', onLoaded);
if (currentTimeEl) {
currentTimeEl.textContent = formatTime(state.currentTime);
}
if (seekInput && audio.duration) {
var progress = (state.currentTime / audio.duration) * 100;
seekInput.value = (state.currentTime / audio.duration * 1000).toString();
card.style.setProperty('--music-progress', progress + '%');
}
if (state.isPlaying) {
audio.play().catch(function() {});
card.setAttribute('data-playing', 'true');
if (playBtn) playBtn.setAttribute('aria-pressed', 'true');
AudioManager.currentPlaying = card;
AudioManager.currentType = 'music';
}
});
if (audio.readyState >= 1) {
audio.currentTime = state.currentTime;
if (currentTimeEl) {
currentTimeEl.textContent = formatTime(state.currentTime);
}
if (seekInput && audio.duration) {
var progress = (state.currentTime / audio.duration) * 100;
seekInput.value = (state.currentTime / audio.duration * 1000).toString();
card.style.setProperty('--music-progress', progress + '%');
}
if (state.isPlaying) {
audio.play().catch(function() {});
card.setAttribute('data-playing', 'true');
if (playBtn) playBtn.setAttribute('aria-pressed', 'true');
AudioManager.currentPlaying = card;
AudioManager.currentType = 'music';
}
}
}
} else if (state.type === 'livephoto') {
var photos = document.querySelectorAll('.amigo-livephoto');
var livePhoto = photos[state.index];
if (livePhoto && livePhoto.dataset.src === state.src) {
var video = livePhoto.querySelector('.amigo-livephoto-video');
if (video) {
var src = livePhoto.dataset.src || '';
if (src && !video.getAttribute('src')) {
video.setAttribute('src', src);
video.src = src;
}
video.addEventListener('loadedmetadata', function onLoaded() {
video.currentTime = state.currentTime;
video.removeEventListener('loadedmetadata', onLoaded);
if (state.isPlaying) {
video.play().catch(function() {});
livePhoto.classList.add('is-playing');
AudioManager.currentPlaying = livePhoto;
AudioManager.currentType = 'livephoto';
}
});
if (video.readyState >= 1) {
video.currentTime = state.currentTime;
if (state.isPlaying) {
video.play().catch(function() {});
livePhoto.classList.add('is-playing');
AudioManager.currentPlaying = livePhoto;
AudioManager.currentType = 'livephoto';
}
}
}
}
}
});
}
};
// ============================================================ // ============================================================
// Live Photo // Live Photo
// ============================================================ // ============================================================
@@ -47,6 +230,7 @@ function initLivePhotoShortcodes() {
function playVideo() { function playVideo() {
ensureLoaded(); ensureLoaded();
AudioManager.registerPlay(livePhoto, 'livephoto');
livePhoto.classList.add('is-playing'); livePhoto.classList.add('is-playing');
try { video.play(); } catch (e) {} try { video.play(); } catch (e) {}
} }
@@ -54,6 +238,10 @@ function initLivePhotoShortcodes() {
function stopVideo() { function stopVideo() {
livePhoto.classList.remove('is-playing'); livePhoto.classList.remove('is-playing');
try { video.pause(); video.currentTime = 0; } catch (e) {} try { video.pause(); video.currentTime = 0; } catch (e) {}
if (AudioManager.currentPlaying === livePhoto) {
AudioManager.currentPlaying = null;
AudioManager.currentType = null;
}
} }
function togglePlay() { function togglePlay() {
@@ -94,6 +282,16 @@ function initLivePhotoShortcodes() {
}); });
} }
// Video ended
video.addEventListener('ended', function() {
livePhoto.classList.remove('is-playing');
isUserToggled = false;
if (AudioManager.currentPlaying === livePhoto) {
AudioManager.currentPlaying = null;
AudioManager.currentType = null;
}
});
// Initialize muted state // Initialize muted state
setMuted(livePhoto.classList.contains('is-muted')); setMuted(livePhoto.classList.contains('is-muted'));
}); });
@@ -116,6 +314,7 @@ function initVoiceBubbles() {
// Load audio duration // Load audio duration
if (audioSrc) { if (audioSrc) {
audio = new Audio(audioSrc); audio = new Audio(audioSrc);
bubble.__audio = audio;
audio.addEventListener('loadedmetadata', function() { audio.addEventListener('loadedmetadata', function() {
var duration = Math.round(audio.duration); var duration = Math.round(audio.duration);
if (durationSpan) { if (durationSpan) {
@@ -132,14 +331,12 @@ function initVoiceBubbles() {
audio.currentTime = 0; audio.currentTime = 0;
bubble.classList.remove('is-playing'); bubble.classList.remove('is-playing');
isPlaying = false; isPlaying = false;
if (AudioManager.currentPlaying === bubble) {
AudioManager.currentPlaying = null;
AudioManager.currentType = null;
}
} else { } else {
// Stop other playing voices AudioManager.registerPlay(bubble, 'voice');
document.querySelectorAll('.amigo-voice-bubble.is-playing').forEach(function(other) {
if (other !== bubble) {
other.classList.remove('is-playing');
}
});
audio.play(); audio.play();
bubble.classList.add('is-playing'); bubble.classList.add('is-playing');
isPlaying = true; isPlaying = true;
@@ -149,6 +346,10 @@ function initVoiceBubbles() {
audio.addEventListener('ended', function() { audio.addEventListener('ended', function() {
bubble.classList.remove('is-playing'); bubble.classList.remove('is-playing');
isPlaying = false; isPlaying = false;
if (AudioManager.currentPlaying === bubble) {
AudioManager.currentPlaying = null;
AudioManager.currentType = null;
}
}); });
}); });
} }
@@ -198,20 +399,12 @@ function initMusicCards() {
card.setAttribute('data-playing', 'false'); card.setAttribute('data-playing', 'false');
if (playBtn) playBtn.setAttribute('aria-pressed', 'false'); if (playBtn) playBtn.setAttribute('aria-pressed', 'false');
isPlaying = false; isPlaying = false;
if (AudioManager.currentPlaying === card) {
AudioManager.currentPlaying = null;
AudioManager.currentType = null;
}
} else { } else {
// Stop other playing music AudioManager.registerPlay(card, 'music');
document.querySelectorAll('.amigo-music-card[data-playing="true"]').forEach(function(other) {
if (other !== card) {
other.setAttribute('data-playing', 'false');
var otherPlayBtn = other.querySelector('.amigo-music-card__play');
if (otherPlayBtn) otherPlayBtn.setAttribute('aria-pressed', 'false');
var otherAudio = other.__audio;
if (otherAudio) {
try { otherAudio.pause(); } catch(e) {}
}
}
});
audio.play(); audio.play();
card.setAttribute('data-playing', 'true'); card.setAttribute('data-playing', 'true');
if (playBtn) playBtn.setAttribute('aria-pressed', 'true'); if (playBtn) playBtn.setAttribute('aria-pressed', 'true');
@@ -244,6 +437,10 @@ function initMusicCards() {
card.setAttribute('data-playing', 'false'); card.setAttribute('data-playing', 'false');
if (playBtn) playBtn.setAttribute('aria-pressed', 'false'); if (playBtn) playBtn.setAttribute('aria-pressed', 'false');
isPlaying = false; isPlaying = false;
if (AudioManager.currentPlaying === card) {
AudioManager.currentPlaying = null;
AudioManager.currentType = null;
}
}); });
}); });
} }
@@ -298,9 +495,15 @@ function cleanupLivePhotos() {
} }
function cleanupAllShortcodes() { function cleanupAllShortcodes() {
// Save playback state before cleanup
AudioManager.saveState();
cleanupVoiceBubbles(); cleanupVoiceBubbles();
cleanupMusicCards(); cleanupMusicCards();
cleanupLivePhotos(); cleanupLivePhotos();
AudioManager.currentPlaying = null;
AudioManager.currentType = null;
} }
// ============================================================ // ============================================================
@@ -311,6 +514,11 @@ function initAllShortcodes() {
initLivePhotoShortcodes(); initLivePhotoShortcodes();
initVoiceBubbles(); initVoiceBubbles();
initMusicCards(); initMusicCards();
// Restore playback state after initialization
setTimeout(function() {
AudioManager.restoreState();
}, 50);
} }
// DOMContentLoaded // DOMContentLoaded