Update shortcodes.js
This commit is contained in:
1 parent
e3ef5e6767
commit
6fbeb89db8
1 file changed
+228
-20
@@ -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
|
||||||
|
|||||||
Reference in new issue
Block a user