想在博客首页增加音乐播放功能,找了网上的各种方案,有的需要授权,有的不能和主题完美搭配,正好安装了腾讯的qclaw小龙虾,就让它打造一个侧边栏音乐播放器,思路是用最简单的代码来实现,因为本人收藏了大量无损音乐,所以音乐源也不采用其它网站的音乐,自己上传到云存储来实现。经过几次修改,现在还算初步满意了。
效果见本博客首页
具体操作是在主题的sidebar.php侧边栏文件中,增加一个调用选项
<?php require_once 'widgets/widget-musicplayer.php'; ?> <!-- 音乐播放 -->
新建一个播放器文件widget-musicplayer.php和歌单文件music-list.json。以后直接编辑歌单文件增加歌曲就行了。
播放器主文件widget-musicplayer.php
<?php
/**
* 迷你音乐播放器
*
* @author 子夜歌
* @link https://ziyege.com
* @update 2026-4-26 添加随机播放功能
*/
if ( ! defined('__TYPECHO_ROOT_DIR__')) {
exit;
}
// 读取歌单文件
$musicList = json_decode(file_get_contents(__DIR__ . '/music-list.json'), true);
?>
<!-- 迷你音乐播放器 -->
<div class="hh-widget mt-3">
<div class="widget-title p-2 w-100">
<div class="widget-title-top-bg" style="background:linear-gradient(45deg, #66bb6a, rgba(255,255,255,0.2));"></div>
<svg viewBox="0 0 24 24" width="16" height="16" fill="currentColor" style="display:inline-block;vertical-align:middle;margin-right:4px;"><path d="M12 3v10.55A4 4 0 1 0 14 17V7h4V3h-6z"/></svg>清韵悠扬播放器
</div>
<div class="widget-content p-2">
<div id="mini-player" class="mini-player">
<div class="mini-player-now" id="miniNow">选择歌曲播放</div>
<div class="mini-player-progress" id="miniProgress">
<div class="mini-player-progress-bar" id="miniProgressBar"></div>
</div>
<div class="mini-player-time">
<span id="miniCurrentTime">00:00</span><span id="miniTotalTime">00:00</span>
</div>
<div class="mini-player-controls">
<button class="mini-player-btn" id="miniPrev" title="上一首">
<svg viewBox="0 0 24 24" width="16" height="16" fill="currentColor"><path d="M6 6h2v12H6zm3.5 6l8.5 6V6z"/></svg>
</button>
<button class="mini-player-btn mini-player-btn-play" id="miniPlay" title="播放">
<svg viewBox="0 0 24 24" width="18" height="18" fill="currentColor"><path d="M8 5v14l11-7z"/></svg>
</button>
<button class="mini-player-btn" id="miniNext" title="下一首">
<svg viewBox="0 0 24 24" width="16" height="16" fill="currentColor"><path d="M6 18l8.5-6L6 6v12zM16 6v12h2V6h-2z"/></svg>
</button>
<button class="mini-player-btn mini-player-shuffle" id="miniShuffle" title="随机播放">
<span class="mini-player-shuffle-label">顺序</span>
</button>
</div>
<div class="mini-player-list" id="miniList"></div>
</div>
<audio id="miniAudio" preload="metadata"></audio>
</div>
</div>
<style>
.mini-player{font-size:.85rem;color:var(--font-color-main)}
.mini-player-now{font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;margin-bottom:.4rem;font-size:.9rem}
.mini-player-progress{width:100%;height:4px;background-color:var(--overlay-color-dark-1);border-radius:2px;cursor:pointer;position:relative}
.mini-player-progress-bar{height:100%;width:0;background:linear-gradient(90deg,#66bb6a,#43a047);border-radius:2px;transition:width .15s linear}
.mini-player-time{display:flex;justify-content:space-between;font-size:.7rem;color:var(--font-color-main-light);margin:2px 0 .4rem}
.mini-player-controls{display:flex;justify-content:center;align-items:center;gap:1rem;margin-bottom:.5rem}
.mini-player-btn{background:none;border:none;cursor:pointer;color:var(--font-color-main);padding:4px;border-radius:50%;display:flex;align-items:center;justify-content:center;transition:all .2s ease}
.mini-player-btn:hover{background-color:var(--overlay-color-dark-1)}
.mini-player-btn-play{width:36px;height:36px;background-color:#43a047;color:var(--white)}
.mini-player-btn-play:hover{background-color:#388e3c}
.mini-player-shuffle{padding:4px 12px;border-radius:16px;background-color:var(--overlay-color-dark-1);font-size:.7rem;color:var(--font-color-main-light);transition:all .2s ease}
.mini-player-shuffle:hover{background-color:rgba(0,0,0,.12)}
.mini-player-shuffle.active{background-color:#43a047;color:var(--white)}
.mini-player-shuffle.active:hover{background-color:#388e3c}
.mini-player-shuffle-label{font-size:.7rem}
.mini-player-list{height:10rem;overflow-y:auto;border-top:1px solid var(--border-color-main,rgba(0,0,0,.08));padding-top:.3rem}
.mini-player-list::-webkit-scrollbar{width:2px!important;-webkit-appearance:none;appearance:none}
.mini-player-list::-webkit-scrollbar-track{background-color:transparent}
.mini-player-song{padding:.3rem .4rem;border-radius:4px;cursor:pointer;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;font-size:.8rem;color:var(--font-color-main-light);transition:all .2s ease}
.mini-player-song:hover{background-color:rgba(255,152,0,.1);color:#ff9800}
.mini-player-song.playing{color:#43a047;font-weight:600;background-color:rgba(67,160,71,.08)}
.mini-player-song.playing:hover{background-color:rgba(255,152,0,.1);color:#ff9800}
</style>
<script>
(function(){
var songs=<?php echo json_encode($musicList); ?>;
// 随机初始化索引
var idx=Math.floor(Math.random()*songs.length);
var shuffle=false; // false=顺序播放, true=随机播放
var audio=document.getElementById('miniAudio'),
now=document.getElementById('miniNow'),
bar=document.getElementById('miniProgressBar'),
prog=document.getElementById('miniProgress'),
curT=document.getElementById('miniCurrentTime'),
totT=document.getElementById('miniTotalTime'),
list=document.getElementById('miniList'),
playBtn=document.getElementById('miniPlay'),
shuffleBtn=document.getElementById('miniShuffle'),
shuffleLabel=shuffleBtn.querySelector('.mini-player-shuffle-label');
songs.forEach(function(s,i){
var d=document.createElement('div');
d.className='mini-player-song';
d.textContent=(i+1)+'. '+s.t;
d.onclick=function(){play(i)};
list.appendChild(d);
});
function fmt(t){
if(!t||!isFinite(t))return'--:--';
var m=Math.floor(t/60),s=Math.floor(t%60);
return(m<10?'0':'')+m+':'+(s<10?'0':'')+s;
}
function play(i){
if(i<0||i>=songs.length)return;
idx=i;audio.src=songs[i].f;audio.play().catch(function(){});
now.textContent=songs[i].t;
playBtn.innerHTML='<svg viewBox="0 0 24 24" width="18" height="18" fill="currentColor"><path d="M6 19h4V5H6v14zm8-14v14h4V5h-4z"/></svg>';
highlight();
}
function highlight(){
var items=list.children;
for(var i=0;i<items.length;i++)
items[i].className=i===idx?'mini-player-song playing':'mini-player-song';
}
function updateShuffleUI(){
if(shuffle){
shuffleBtn.classList.add('active');
shuffleLabel.textContent='随机';
shuffleBtn.title='随机播放中,点击切换为顺序播放';
}else{
shuffleBtn.classList.remove('active');
shuffleLabel.textContent='顺序';
shuffleBtn.title='顺序播放中,点击切换为随机播放';
}
}
function getNextIndex(){
if(shuffle){
// 随机模式:随机选择一首(避免连续相同)
var next;
do{next=Math.floor(Math.random()*songs.length)}while(next===idx&&songs.length>1);
return next;
}else{
return (idx+1)%songs.length;
}
}
audio.addEventListener('timeupdate',function(){
if(audio.duration&&isFinite(audio.duration)){
bar.style.width=(audio.currentTime/audio.duration*100)+'%';
curT.textContent=fmt(audio.currentTime);totT.textContent=fmt(audio.duration);
}
});
audio.addEventListener('ended',function(){
play(getNextIndex());
});
prog.addEventListener('click',function(e){
if(!audio.duration)return;var r=prog.getBoundingClientRect();
audio.currentTime=((e.clientX-r.left)/r.width)*audio.duration;
});
playBtn.onclick=function(){
if(!audio.src||audio.src===location.href){play(0);return;}
if(audio.paused){audio.play();playBtn.innerHTML='<svg viewBox="0 0 24 24" width="18" height="18" fill="currentColor"><path d="M6 19h4V5H6v14zm8-14v14h4V5h-4z"/></svg>';}
else{audio.pause();playBtn.innerHTML='<svg viewBox="0 0 24 24" width="18" height="18" fill="currentColor"><path d="M8 5v14l11-7z"/></svg>';}
};
document.getElementById('miniPrev').onclick=function(){
var prevIdx=(idx-1+songs.length)%songs.length;
play(prevIdx);
};
document.getElementById('miniNext').onclick=function(){
play(getNextIndex());
};
shuffleBtn.onclick=function(){
shuffle=!shuffle;
updateShuffleUI();
};
// 初始化随机播放按钮状态
updateShuffleUI();
// 页面加载后尝试自动播放(需用户交互才能成功)
function tryAutoPlay(){
audio.src=songs[idx].f;
audio.load();
audio.play().then(function(){
now.textContent=songs[idx].t;
playBtn.innerHTML='<svg viewBox="0 0 24 24" width="18" height="18" fill="currentColor"><path d="M6 19h4V5H6v14zm8-14v14h4V5h-4z"/></svg>';
highlight();
}).catch(function(){
// 浏览器阻止自动播放,等待用户交互后播放
now.textContent='点击任意位置开始播放';
function startOnInteraction(){
audio.play().then(function(){
now.textContent=songs[idx].t;
playBtn.innerHTML='<svg viewBox="0 0 24 24" width="18" height="18" fill="currentColor"><path d="M6 19h4V5H6v14zm8-14v14h4V5h-4z"/></svg>';
highlight();
}).catch(function(){});
document.removeEventListener('click',startOnInteraction);
document.removeEventListener('touchstart',startOnInteraction);
document.removeEventListener('keydown',startOnInteraction);
}
document.addEventListener('click',startOnInteraction,{once:true});
document.addEventListener('touchstart',startOnInteraction,{once:true});
document.addEventListener('keydown',startOnInteraction,{once:true});
});
}
// 延迟一点执行,确保 DOM 完全就绪
setTimeout(tryAutoPlay,100);
})();
</script>
歌单文件music-list.json
[
{"f": "https://***.com/muc/music/a01.mp3", "t": "JinriCP直播秀配乐一"},
{"f": "https://***.com/muc/music/a02.mp3", "t": "JinriCP直播秀配乐二"},
{"f": "https://***.com/muc/music/a03.mp3", "t": "Bressanone布列瑟农-马修连恩"}
]
暂无评论