Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,4 +67,10 @@ Demo:[runlingdev.github.io/ClassAlbum](https://runlingdev.github.io/ClassAlbum
}
```

## Donate

如果这个新手项目对你有所启发,还请多多支持!

[Afdian](https://afdian.net/a/runling/plan)

---
12 changes: 5 additions & 7 deletions detail.html → aDetail.html
Original file line number Diff line number Diff line change
@@ -1,20 +1,18 @@
<!DOCTYPE html>
<html lang="zh-CN">
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Song Details</title>
<title>Audio Details</title>
<link rel="stylesheet" href="styles.css">
<link rel="icon" type="image/x-icon" href="img/favicon.ico">
</head>
<body>
<div class="detail-container">
<h1 id="songTitle"></h1>
<h2 id="albumTitle"></h2>
<div class="video-container">
<iframe id="videoFrame" width="100%" height="500" frameborder="0" allowfullscreen></iframe>
</div>
<div id="mediaContainer"></div>
<div id="lyricsContainer"></div>
</div>
<script src="detailjs.js"></script>
<script src="aDetailjs.js"></script>
</body>
</html>
129 changes: 129 additions & 0 deletions aDetailjs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
const songDataUrls = [
'songs.json',
'https://example.com/songs.json',
'https://backup.example.com/songs.json'
];

function loadSongsData(callback) {
const xhr = new XMLHttpRequest();

function tryNextUrl() {
if (songDataUrls.length > 0) {
const url = songDataUrls.shift();
xhr.open('GET', url, true);
xhr.send();
} else {
console.error('Failed to load song data from all provided URLs.');
}
}

xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
try {
const songs = JSON.parse(xhr.responseText);
callback(songs);
} catch (error) {
console.error('Failed to parse song data:', error);
tryNextUrl();
}
} else {
tryNextUrl();
}
}
};

tryNextUrl();
}

// 为音频详情页面加载媒体和歌词
const urlParams = new URLSearchParams(window.location.search);
const songTitle = urlParams.get('song');

if (songTitle) {
loadSongsData(songs => {
const song = songs.find(s => s.title === decodeURIComponent(songTitle));
if (song && song.type === 'audio') {
const songTitleElement = document.getElementById('songTitle');
const albumTitleElement = document.getElementById('albumTitle');
const mediaContainer = document.getElementById('mediaContainer');
const lyricsContainer = document.getElementById('lyricsContainer');

songTitleElement.textContent = song.title;
albumTitleElement.textContent = `${song.album} - ${song.artist}`;
mediaContainer.innerHTML = `<audio id="audioPlayer" src="${song.source}" controls></audio>`;

if (song.lrc !== 'none') {
if( song.lrc.includes("music.163.com") ){
const parser = new LrcParser();
const lyrics = parser.parse(getSongLrc(song.lrc));
displayLyrics(lyrics);
}else{
fetch(song.lrc)
.then(response => response.text())
.then(data => {
const parser = new LrcParser();
const lyrics = parser.parse(data);
displayLyrics(lyrics);
});
}
}
} else {
console.error('Song data not found or invalid media type.');
}
});
}


// 解析 .lrc 文件内容
class LrcParser {
parse(data) {
const lyrics = [];
const lines = data.split('\n');
for (let i = 0; i < lines.length; i++) {
const line = lines[i].trim();
if (line) {
const parts = line.split(']');
const timestamp = parseTimeString(parts[0].substr(1));
const text = parts[1];
lyrics.push({ timestamp, text });
}
}
return lyrics;
}
}

function parseTimeString(timeString) {
const parts = timeString.split(':');
const minutes = parseFloat(parts[0]);
const seconds = parseFloat(parts[1]);
return minutes * 60 + seconds;
}

// 渲染歌词
function displayLyrics(lyrics) {
const audio = document.getElementById('audioPlayer');
const lyricsDiv = document.getElementById('lyricsContainer');

audio.addEventListener('timeupdate', () => {
const currentTime = audio.currentTime;
for (let i = 0; i < lyrics.length; i++) {
if (lyrics[i].timestamp > currentTime) {
lyricsDiv.innerText = lyrics[i - 1].text;
lyricsDiv.scrollTop = lyricsDiv.scrollHeight;
break;
}
}
});
}

async function getSongLrc(url) {
try {
const response = await fetch(url);
const data = await response.json();
return data.lyric;
} catch (error) {
console.error('获取歌词失败:', error);
return '获取歌词失败';
}
}
23 changes: 0 additions & 23 deletions detailjs.js

This file was deleted.

5 changes: 2 additions & 3 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,11 @@
<body>
<div class="container">
<div class="column">
<ul class="song-list fixed"></ul>
<ul class="song-list random"></ul>
<ul class="song-list"></ul>
</div>
<div class="empty"></div>
<div class="column">
<ul class="song-list random"></ul>
<ul class="song-list"></ul>
</div>
</div>
<script src="indexjs.js"></script>
Expand Down
161 changes: 121 additions & 40 deletions indexjs.js
Original file line number Diff line number Diff line change
@@ -1,48 +1,129 @@
// 从配置文件加载歌曲数据
fetch('songs.json')
.then(response => response.json())
.then(songs => {
const fixedSongList = document.querySelector('.song-list.fixed');
const randomSongLists = document.querySelectorAll('.song-list.random');

// 固定展示的歌曲
const fixedSongs = songs.filter(song => song.isFixed);
fixedSongs.forEach(song => {
fixedSongList.innerHTML += `
// 歌曲数据的请求地址列表
const songDataUrls = [
'songs.json',
'https://example.com/songs.json',
'https://backup.example.com/songs.json'
];

// 加载歌曲数据
function loadSongsData(callback) {
const xhr = new XMLHttpRequest();

function tryNextUrl() {
if (songDataUrls.length > 0) {
const url = songDataUrls.shift();
xhr.open('GET', url, true);
xhr.send();
} else {
console.error('Failed to load song data from all provided URLs.');
}
}

xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
try {
const songs = JSON.parse(xhr.responseText);
if (Array.isArray(songs) && songs.every(isValidSong)) {
callback(songs);
} else {
console.error('Invalid song data format.');
tryNextUrl();
}
} catch (error) {
console.error('Failed to parse song data:', error);
tryNextUrl();
}
} else {
tryNextUrl();
}
}
};

tryNextUrl();
}

// 检查歌曲对象是否有效
function isValidSong(song) {
return (
typeof song.title === 'string' &&
typeof song.artist === 'string' &&
typeof song.album === 'string' &&
typeof song.weight === 'number' &&
song.weight >= 0 &&
song.weight <= 2 &&
typeof song.type === 'string' &&
(song.type === 'video' || song.type === 'audio') &&
typeof song.source === 'string' &&
typeof song.lrc === 'string'
);
}

// 设置歌曲对象的缺省值
function setDefaultSongValues(song) {
if (song.weight === undefined) {
song.weight = 1;
}// 防止weight===0时default为1.
song.lrc = song.lrc || 'none';
return song;
}

// 根据权重随机选择歌曲
function selectSongs(songs) {
const selectedSongs = [];
while (selectedSongs.length < songs.length && selectedSongs.length <= getMaxDisplayCount()*2) {
const randomIndex = Math.floor(Math.random() * songs.length);
const song = songs[randomIndex];
if (!selectedSongs.includes(song)) {
selectedSongs.push(song);
}
}

return selectedSongs;
}

// 获取最大显示条数
function getMaxDisplayCount() {
const screenHeight = window.innerHeight || document.documentElement.clientHeight;
const songItemHeight = 50;
const maxDisplayCount = Math.floor((screenHeight - 230) / songItemHeight);
return maxDisplayCount;
}

// 在页面中显示歌曲列表
function displaySongs(songs) {
const songLists = document.querySelectorAll('.song-list');
const weightedSongs = songs.filter(song => song.weight > 0);
const fixedSongs = weightedSongs.filter(song => song.weight === 2);
const randomSongs = weightedSongs.filter(song => song.weight === 1);
const selectedSongs = fixedSongs.concat(selectSongs(randomSongs));

const songsPerList = Math.min((selectedSongs.length/2),getMaxDisplayCount());
songLists.forEach((list,index) => {
const startIndex = index === 0 ? 0 : songsPerList;
const endIndex = index === 0 ? songsPerList : (songsPerList*2);
console.log(startIndex,endIndex);
console.log(selectedSongs);
console.log(songsPerList);
selectedSongs.slice(startIndex, endIndex).forEach(song => {
const detailPage = song.type === 'video' ? 'vDetail.html' : 'aDetail.html';
list.innerHTML += `
<li>
<a href="detail.html?song=${song.title}">
<a href="${detailPage}?song=${encodeURIComponent(song.title)}">
<span class="song-title">${song.title}</span>
<span class="album-title">${song.album} - ${song.artist}</span>
</a>
<a href="${song.videoSource}" target="_blank"><img class="play-icon" src="img/play-icon.png" alt="Play"></a>
<a href="${song.source}" target="_blank"><img class="play-icon" src="img/play-icon.png" alt="Play"></a>
</li>
`;
});
});
}

// 随机展示的歌曲
const randomSongs = shuffleArray(songs.filter(song => !song.isFixed));
randomSongLists.forEach(list => {
randomSongs.slice(0, 5).forEach(song => {
list.innerHTML += `
<li>
<a href="detail.html?song=${song.title}">
<span class="song-title">${song.title}</span>
<span class="album-title">${song.album} - ${song.artist}</span>
</a>
<a href="${song.videoSource}" target="_blank"><img class="play-icon" src="img/play-icon.png" alt="Play"></a>
</li>
`;
});
randomSongs.splice(0, 5);
});
})
.catch(error => console.error('Error fetching song data:', error));

// 用于随机打乱数组顺序
function shuffleArray(array) {
for (let i = array.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[array[i], array[j]] = [array[j], array[i]];
}
return array;
}
// 处理主页面加载
window.onload = function() {
loadSongsData(songs => {
const validSongs = songs.filter(isValidSong).map(setDefaultSongValues);
displaySongs(validSongs);
});
};
Loading