魔改原项目展示位置修改为音乐播放器

修改方法

主题文件修改

打开 themes\anzhiyu\layout\includes\top\top.pug 文件
将原本代码修改为

`

- let home_top_config = theme.home_top
- let { title, subTitle, siteText,default_descr } = home_top_config
if home_top_config.enable
#home_top
.swiper_container_card(style='height: auto;width: 100%')
#bannerGroup
#random-banner
if theme.peoplecanvas.enable
canvas#peoplecanvas
else
.banners-title
.banners-title-big=title
.banners-title-big=subTitle
.banners-title-small=siteText
include ../anzhiyu/tags-group-all.pug

a#random-hover(href='javascript:toRandomPost()')
i.anzhiyufont.anzhiyu-icon-paper-plane
.bannerText 随便逛逛
i.anzhiyufont.anzhiyu-icon-arrow-right
.categoryGroup
each item in home_top_config.category
.categoryItem(style=`box-shadow:${item.shadow}`)
a.categoryButton(href=url_for(item.path) class=`${item.class}`)
span.categoryButtonText=item.name
if (item.icon.startsWith("fa"))
i(class=`${item.icon}`)
else if (item.icon.startsWith("icon"))
svg.icon(aria-hidden="true")
use(xlink:href=`#`+ item.icon)
else if (item.icon.startsWith("anzhiyu"))
i.anzhiyufont(class=`${item.icon}`)
#custom-music-player-placeholder(style="width: 625px; min-height: 340px; margin-left: 0.5rem;")

添加js文件

新建一个music-index.js文件并添加以下代码

(function() {
// --- Anzhiyu 自定义音乐播放器 ---
// --- 主要配置 ---
const anzhiyuPlayerConfig = {
apiBaseUrl: "https://api.qcxz.ink/",
defaultPlaylistId: "7526297568",
defaultServer: "netease",
defaultCoverArt: "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7",
placeholderId: "custom-music-player-placeholder",
playerUniquePrefix: "anzhiyuCustomPlayer",
persistentPlayerContainerId: 'anzhiyu-persistent-player-container',
initializationFlag: '__anzhiyuPlayerInitialized'
};

const pfx = anzhiyuPlayerConfig.playerUniquePrefix;

let anzhiyuPlayerState = {
playlist: [],
currentTrackIndex: 0,
audioElement: null,
playerDOM: null,
songTitleElement: null,
artistNameElement: null,
playlistContainerElement: null,
coverArtImgElement: null,
};

async function anzhiyuPlayerFetchPlaylist(playlistId = anzhiyuPlayerConfig.defaultPlaylistId, server = anzhiyuPlayerConfig.defaultServer) {
const globalState = window[anzhiyuPlayerConfig.initializationFlag];
if (!globalState) return;
const { songTitleElement, artistNameElement, coverArtImgElement, playlistContainerElement } = globalState;

if (songTitleElement) songTitleElement.textContent = "正在加载歌单...";
if (artistNameElement) artistNameElement.textContent = "";
if (coverArtImgElement) coverArtImgElement.src = anzhiyuPlayerConfig.defaultCoverArt;
if (playlistContainerElement) playlistContainerElement.innerHTML = `<div class="${pfx}-playlist-item">正在加载...</div>`;

try {
const response = await fetch(`${anzhiyuPlayerConfig.apiBaseUrl}?server=${server}&type=playlist&id=${playlistId}`);
if (!response.ok) throw new Error(`HTTP 请求错误! 状态: ${response.status}`);
const data = await response.json();


if (Array.isArray(data) && data.length > 0) {
globalState.playlist = data;
if (typeof anzhiyuPlayerPopulatePlaylistDisplay === "function") anzhiyuPlayerPopulatePlaylistDisplay();
if (typeof anzhiyuPlayerLoadTrack === "function") anzhiyuPlayerLoadTrack(0);
} else {
globalState.playlist = [];
if (songTitleElement) songTitleElement.textContent = "歌单为空";
if (playlistContainerElement) playlistContainerElement.innerHTML = `<div class="${pfx}-playlist-item">歌单为空</div>`;
}
} catch (error) {
if (songTitleElement) songTitleElement.textContent = "歌单加载失败";
globalState.playlist = [];
if (playlistContainerElement) playlistContainerElement.innerHTML = `<div class="${pfx}-playlist-item">加载失败</div>`;
}
}

function anzhiyuPlayerLoadTrack(index, playImmediately = false) {
const globalState = window[anzhiyuPlayerConfig.initializationFlag];
if (!globalState) return;
const { playlist, audioElement, songTitleElement, artistNameElement, coverArtImgElement } = globalState;

if (!playlist || playlist.length === 0) {
return;
}
if (index >= 0 && index < playlist.length) {
globalState.currentTrackIndex = index;
const track = playlist[index];

if (songTitleElement) songTitleElement.textContent = track.name || "未知歌曲";
if (artistNameElement) artistNameElement.textContent = track.artist || "未知艺术家";
if (coverArtImgElement) coverArtImgElement.src = track.pic || anzhiyuPlayerConfig.defaultCoverArt;

if (audioElement) {
const wasPlaying = !audioElement.paused && audioElement.currentTime > 0;
const currentSrc = audioElement.currentSrc;
const newSrc = new URL(track.url, window.location.href).href;

if (currentSrc !== newSrc) {
audioElement.src = newSrc;
if (playImmediately || wasPlaying) {
audioElement.load();
const playPromise = audioElement.play();
if (playPromise !== undefined) {
playPromise.catch(error => {});
}
}
} else if (playImmediately && audioElement.paused) {
const playPromise = audioElement.play();
if (playPromise !== undefined) {
playPromise.catch(error => {});
}
}
}
if(typeof anzhiyuPlayerUpdatePlaylistActiveItem === "function") anzhiyuPlayerUpdatePlaylistActiveItem();
}
}

function anzhiyuPlayerNextSong() {
const globalState = window[anzhiyuPlayerConfig.initializationFlag];
if (!globalState) return;
const { playlist } = globalState;

if (!playlist || playlist.length === 0) return;
let newIndex = (globalState.currentTrackIndex + 1) % playlist.length;
if (typeof anzhiyuPlayerLoadTrack === "function") anzhiyuPlayerLoadTrack(newIndex, true);
}

function anzhiyuPlayerPopulatePlaylistDisplay() {
const globalState = window[anzhiyuPlayerConfig.initializationFlag];
if (!globalState) return;
const { playlistContainerElement, playlist } = globalState;

if (!playlistContainerElement || !playlist || playlist.length === 0) {
if(playlistContainerElement) playlistContainerElement.innerHTML = `<div class="${pfx}-playlist-item">歌单为空</div>`;
return;
}
playlistContainerElement.innerHTML = '';

playlist.forEach((track, index) => {
const item = document.createElement('div');
item.className = `${pfx}-playlist-item`;
item.dataset.index = index;

const trackNumber = document.createElement('span');
trackNumber.className = `${pfx}-playlist-item-number`;
trackNumber.textContent = (index + 1).toString().padStart(2, '0');

const trackInfo = document.createElement('span');
trackInfo.className = `${pfx}-playlist-item-info`;
trackInfo.textContent = `${track.name || '未知歌曲'} - ${track.artist || '未知艺术家'}`;
trackInfo.title = `${track.name || '未知歌曲'} - ${track.artist || '未知艺术家'}`;

item.appendChild(trackNumber);
item.appendChild(trackInfo);

item.addEventListener('click', () => {
if (typeof anzhiyuPlayerLoadTrack === "function") {
anzhiyuPlayerLoadTrack(index, true);
}
});
playlistContainerElement.appendChild(item);
});
anzhiyuPlayerUpdatePlaylistActiveItem();
}

function anzhiyuPlayerUpdatePlaylistActiveItem() {
const globalState = window[anzhiyuPlayerConfig.initializationFlag];
if (!globalState) return;
const { playlistContainerElement, currentTrackIndex } = globalState;

if (!playlistContainerElement) return;
const items = playlistContainerElement.querySelectorAll(`.${pfx}-playlist-item`);

items.forEach((item, index) => {
if (index === currentTrackIndex) {
item.classList.add(`${pfx}-playlist-item-active`);
} else {
item.classList.remove(`${pfx}-playlist-item-active`);
}
});
}

function initializeGlobalPlayer() {
if (window[anzhiyuPlayerConfig.initializationFlag]) {
return;
}

let persistentContainer = document.getElementById(anzhiyuPlayerConfig.persistentPlayerContainerId);
if (!persistentContainer) {
persistentContainer = document.createElement('div');
persistentContainer.id = anzhiyuPlayerConfig.persistentPlayerContainerId;
persistentContainer.style.display = 'none';
document.body.appendChild(persistentContainer);
}

let audioElement = document.getElementById(`${pfx}-audio-element`);
if (!audioElement) {
audioElement = document.createElement('audio');
audioElement.id = `${pfx}-audio-element`;
audioElement.controls = true;
}
anzhiyuPlayerState.audioElement = audioElement;


let playerUIDiv = document.querySelector(`.${pfx}-player-container-v3`);
if (!playerUIDiv) {
playerUIDiv = persistentContainer.querySelector(`.${pfx}-player-container-v3`);
if (!playerUIDiv) {
playerUIDiv = document.createElement('div');
playerUIDiv.className = `${pfx}-player-container-v3`;
playerUIDiv.innerHTML = `
<div class="${pfx}-left-column">
<div id="${pfx}-cover-art-wrapper" class="${pfx}-cover-art-wrapper">
<img id="${pfx}-cover-art-img" src="${anzhiyuPlayerConfig.defaultCoverArt}" alt="专辑封面">
</div>
<div class="${pfx}-song-info-left">
<h2 id="${pfx}-song-title" style="width: 150px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;"></h2>
<p id="${pfx}-artist-name" style="width: 150px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;"></p>
</div>
</div>
<div class="${pfx}-right-column">
<div id="${pfx}-playlist-container" class="${pfx}-playlist-container">
<div class="${pfx}-playlist-item">正在加载...</div>
</div>
<div class="${pfx}-controls-area">
</div>
</div>
`;
}
}
anzhiyuPlayerState.playerDOM = playerUIDiv;

const controlsArea = playerUIDiv.querySelector(`.${pfx}-controls-area`);
if (controlsArea) {
if (audioElement.parentNode !== controlsArea) {
controlsArea.appendChild(audioElement);
}
} else {
if (audioElement.parentNode !== playerUIDiv) {
playerUIDiv.appendChild(audioElement);
}
}

if (playerUIDiv.parentNode !== persistentContainer) {
persistentContainer.appendChild(playerUIDiv);
}


anzhiyuPlayerState.songTitleElement = playerUIDiv.querySelector(`#${pfx}-song-title`);
anzhiyuPlayerState.artistNameElement = playerUIDiv.querySelector(`#${pfx}-artist-name`);
anzhiyuPlayerState.playlistContainerElement = playerUIDiv.querySelector(`#${pfx}-playlist-container`);
anzhiyuPlayerState.coverArtImgElement = playerUIDiv.querySelector(`#${pfx}-cover-art-img`);

if (!document.getElementById(`${pfx}-styles-v3`)) {
const playerCSS = `
#${anzhiyuPlayerConfig.persistentPlayerContainerId} { display: none; }
.${pfx}-player-container-v3 { display: flex; height: 100%; box-sizing: border-box; padding: 15px; background-color: var(--anzhiyu-card-bg, white); box-shadow: var(--anzhiyu-shadow-border, 0 0 10px rgba(0,0,0,0.1)); border-radius: var(--anzhiyu-border-radius, 8px); color: var(--anzhiyu-fontcolor, black); gap: 20px; }
.${pfx}-left-column { flex: 0 0 200px; display: flex; flex-direction: column; align-items: center; justify-content: center; }
.${pfx}-cover-art-wrapper { width: 170px; height: 170px; border-radius: 50%; overflow: hidden; box-shadow: 0 5px 15px rgba(0,0,0,0.25); margin-bottom: 15px; background-color: #e0e0e0; }
#${pfx}-cover-art-img { width: 100%; height: 100%; object-fit: cover; display: block; transition: transform 0.3s ease-out; }
#${pfx}-cover-art-img.rotating { animation: ${pfx}-rotate 15s linear infinite; }
@keyframes ${pfx}-rotate { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
.${pfx}-song-info-left { text-align: center; width: 100%; padding: 0 5px; }
#${pfx}-song-title { font-size: 1.1em; margin: 0 0 4px 0; font-weight: bold; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--anzhiyu-fontcolor, black); display: block; max-width: 150px; }
#${pfx}-artist-name { font-size: 0.85em; margin: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--anzhiyu-second-fontcolor, gray); display: block; max-width: 150px; }
.${pfx}-right-column { flex: 1; display: flex; flex-direction: column; min-width: 0; }
.${pfx}-playlist-container { height: 200px; overflow-y: auto; border: 1px solid var(--anzhiyu-gray-c, #ddd); padding: 5px; border-radius: var(--anzhiyu-border-radius-small, 8px); background-color: var(--anzhiyu-background, #f9f9f9); margin-bottom: 10px; }
.${pfx}-playlist-item { display: flex; align-items: center; padding: 6px 8px; margin-bottom: 3px; cursor: pointer; border-radius: 6px; transition: background-color 0.2s ease-in-out; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.${pfx}-playlist-item:hover { background-color: var(--anzhiyu-gray-a, #eee); }
.${pfx}-playlist-item-active { background-color: var(--anzhiyu-theme-op, rgba(255, 102, 102, 0.15)); color: var(--anzhiyu-theme, #ff6666); font-weight: bold; }
.${pfx}-playlist-item-number { font-size: 0.8em; color: var(--anzhiyu-third-fontcolor, #999); margin-right: 8px; min-width: 20px; text-align: right; }
.${pfx}-playlist-item-active .${pfx}-playlist-item-number { color: var(--anzhiyu-theme, #ff6666); }
.${pfx}-playlist-item-info { font-size: 0.9em; overflow: hidden; text-overflow: ellipsis; color: var(--anzhiyu-second-fontcolor, #555); }
.${pfx}-playlist-item-active .${pfx}-playlist-item-info { color: var(--anzhiyu-theme, #ff6666); }
.${pfx}-controls-area { margin-top: auto; } /* audio 控件将在此区域显示 */
#${pfx}-audio-element { width: 100%; border-radius: 8px; display: block; }
#${pfx}-audio-element::-webkit-media-controls-panel { background-color: var(--anzhiyu-card-bg, #f0f0f0); border-radius: 8px; }
#${pfx}-audio-element::-webkit-media-controls-play-button { filter: invert(var(--anzhiyu-darkmode-invert-Molar, 0)); }
@media (max-width: 768px) { .${pfx}-player-container-v3 { flex-direction: column; padding: 10px; gap: 10px; } .${pfx}-left-column { flex-basis: auto; width: 100%; padding-top: 5px; align-items: center; justify-content: flex-start; } .${pfx}-cover-art-wrapper { width: 130px; height: 130px; margin-bottom: 10px; } .${pfx}-right-column { width: 100%; } .${pfx}-playlist-container { font-size: 0.85em; height: 150px; } #${pfx}-song-title { font-size: 1em; } #${pfx}-artist-name { font-size: 0.75em; } }
@media (max-width: 991px) { #home_top { display: none !important; } }
`;
const styleElement = document.createElement('style');
styleElement.type = 'text/css';
styleElement.id = `${pfx}-styles-v3`;
styleElement.textContent = playerCSS;
document.head.appendChild(styleElement);
}

if (anzhiyuPlayerState.audioElement) {
const audioEl = anzhiyuPlayerState.audioElement;
audioEl.removeEventListener('ended', anzhiyuPlayerNextSong);
audioEl.removeEventListener('play', handlePlayEvent);
audioEl.removeEventListener('playing', handlePlayEvent);
audioEl.removeEventListener('pause', handlePauseEvent);

audioEl.addEventListener('ended', anzhiyuPlayerNextSong);
audioEl.addEventListener('play', handlePlayEvent);
audioEl.addEventListener('playing', handlePlayEvent);
audioEl.addEventListener('pause', handlePauseEvent);
}

window[anzhiyuPlayerConfig.initializationFlag] = anzhiyuPlayerState;
anzhiyuPlayerFetchPlaylist();
}

function handlePlayEvent() {
const globalState = window[anzhiyuPlayerConfig.initializationFlag];
if (globalState && globalState.coverArtImgElement) {
globalState.coverArtImgElement.classList.add('rotating');
}
}
function handlePauseEvent() {
const globalState = window[anzhiyuPlayerConfig.initializationFlag];
if (globalState && globalState.coverArtImgElement) {
globalState.coverArtImgElement.classList.remove('rotating');
}
}

function mountPlayerUI() {
const globalState = window[anzhiyuPlayerConfig.initializationFlag];
if (!globalState || !globalState.playerDOM) {
return;
}

const placeholder = document.getElementById(anzhiyuPlayerConfig.placeholderId);
const playerDOM = globalState.playerDOM;
const persistentContainer = document.getElementById(anzhiyuPlayerConfig.persistentPlayerContainerId);

if (!persistentContainer) {
return;
}

if (placeholder) {
if (playerDOM.parentNode !== placeholder) {
placeholder.appendChild(playerDOM);
}
} else {
if (playerDOM.parentNode !== persistentContainer) {
persistentContainer.appendChild(playerDOM);
}
}
}

document.addEventListener('DOMContentLoaded', () => {
if (!window[anzhiyuPlayerConfig.initializationFlag]) {
initializeGlobalPlayer();
} else {
anzhiyuPlayerState = window[anzhiyuPlayerConfig.initializationFlag];
if (anzhiyuPlayerState.playerDOM) {
anzhiyuPlayerState.songTitleElement = anzhiyuPlayerState.playerDOM.querySelector(`#${pfx}-song-title`);
anzhiyuPlayerState.artistNameElement = anzhiyuPlayerState.playerDOM.querySelector(`#${pfx}-artist-name`);
anzhiyuPlayerState.playlistContainerElement = anzhiyuPlayerState.playerDOM.querySelector(`#${pfx}-playlist-container`);
anzhiyuPlayerState.coverArtImgElement = anzhiyuPlayerState.playerDOM.querySelector(`#${pfx}-cover-art-img`);
const audioElementInDOM = anzhiyuPlayerState.playerDOM.querySelector(`#${pfx}-audio-element`);
if (audioElementInDOM) {
anzhiyuPlayerState.audioElement = audioElementInDOM;
} else {
}

} else {
}
}
mountPlayerUI();
});

document.addEventListener('pjax:complete', () => {
const globalState = window[anzhiyuPlayerConfig.initializationFlag];

if (!globalState || !globalState.audioElement || !globalState.playerDOM) {

if (typeof anzhiyuPlayerUpdatePlaylistActiveItem === "function") {
requestAnimationFrame(() => {
requestAnimationFrame(() => {
anzhiyuPlayerUpdatePlaylistActiveItem();
});
});
}
return;
}

let musicWasPlayingBeforePjax = !globalState.audioElement.paused;

requestAnimationFrame(() => {
mountPlayerUI();
const currentPath = window.location.pathname;

if (currentPath.startsWith('/music')) {
if (!globalState.audioElement.paused) {
globalState.audioElement.pause();
}
} else {
if (musicWasPlayingBeforePjax && globalState.audioElement.paused) {
const playPromise = globalState.audioElement.play();
if (playPromise !== undefined) {
playPromise.catch(error => {
});
}
} else if (musicWasPlayingBeforePjax && !globalState.audioElement.paused) {
}
}

if (typeof anzhiyuPlayerUpdatePlaylistActiveItem === "function") {
requestAnimationFrame(() => {
anzhiyuPlayerUpdatePlaylistActiveItem();
});
}
});
});

})();

`

参数解释

名称 数值
apiBaseUrl 填入你的api地址,项目为Meting API
defaultPlaylistId 填入你的歌单id
defaultServer 数据源, netease 网易云音乐,tencent QQ音乐(但貌似无法正常获取了)

在主题文件中对js进行引入

`

bottom:
  # 自定义js
  - <script src="/js/music-index.js"></script>   #首页音乐