<!
DOCTYPE
html>
<
html
lang
=
"en"
>
<
head
>
<
meta
charset
=
"UTF-8"
>
<
title
>MIDI Player</
title
>
<
script
src
=
'midijs/midi.js'
></
script
>
<
script
src
=
"midijs/jquery.min.js"
></
script
>
<
style
>
html {
background: silver;
}
body {
overflow: hidden;
width: 100%;
height: 100%;
margin: 0;
font-family: Arial, sans-serif;
}
ul {
padding: 0;
margin: 0;
display: none;
}
li {
padding: 10px;
cursor: pointer;
list-style: none;
background-color: #f9f9f9;
border-bottom: 1px solid #ddd;
}
#playlist > ul > li:nth-child(2n) {
background-color: #eee;
}
li:hover,
#playlist > ul > li:nth-child(2n):hover {
background: #C3FF00;
color: #000;
}
#folders {
width: 100%;
color: black;
position: fixed;
top: 30px;
left: 0;
padding: 7px;
background: darkgray;
height: 36px;
border-bottom: 1px solid gray;
}
#console {
width: 100%;
background: black;
color: #C3FF00;
border: 5px solid black;
position: fixed;
top: 0;
left: 0;
height: 30px;
padding: 3px;
line-height: 30px;
font-size: 14px;
}
#console:hover {
background: red;
border: 5px solid red;
cursor: not-allowed;
}
#playlist {
position: absolute;
top: 67px;
background: white;
left: 0;
width: 100%;
height: calc(100% - 67px);
overflow-y: scroll;
overflow-x: hidden;
}
.folder {
cursor: pointer;
text-align: center;
padding: 5px 10px;
background: #ccc;
border: 1px solid #999;
margin-right: 5px;
}
.folder:hover {
background: #C3FF00;
color: #000;
}
button.fClicked {
background-color: gray;
color: #dfdfdf;
border: 1px solid gray;
box-shadow: inset 1px 1px #000, 1px 0 #dfdfdf, 0 1px #dfdfdf, 1px 1px #dfdfdf;
}
#download {
display: none;
padding: 5px 10px;
background: #ccc;
border: 1px solid #999;
cursor: pointer;
}
.playing {
background: #C3FF00 !important;
color: #000 !important;
}
/* 原有样式保持不变,新增以下歌词相关样式 */
#console {
display: flex;
flex-direction: column;
height: 60px; /* 增加高度以显示歌词 */
}
#status-bar {
height: 30px;
line-height: 30px;
}
#lyric-container {
flex: 1;
white-space: nowrap;
text-overflow: ellipsis;
padding: 0 5px;
}
</
style
>
</
head
>
<
body
>
<
div
id
=
'console'
>
<
div
id
=
"status-bar"
>Choose a song.</
div
>
<
div
id
=
"lyric-container"
></
div
>
</
div
>
<
div
id
=
'folders'
>
<
button
id
=
'download'
>Download</
button
>
</
div
>
<
div
id
=
"playlist"
></
div
>
<
script
>
// 新增歌词相关变量
let lyrics = [];
let timeStamps = [];
let lyricIndex = 0;
let playbackStartTime = 0;
let lyricInterval;
var current = 0;
var midiFile = "";
$(function () {
// Load song list from song-list.txt
$.get('song-list.txt', function (data) {
var folders = {};
var lines = data.split('\n');
// Parse song list
lines.forEach(function (line) {
if (line.trim() === "") return;
var parts = line.split('/');
if (parts.length === 2) {
var folderId = parts[0];
var songName = parts[1].trim();
if (!folders[folderId]) {
folders[folderId] = [];
}
folders[folderId].push(songName);
}
});
// Generate folders and songs
Object.keys(folders).forEach(function (folderId) {
$('#folders').prepend(
$('<
button
>').addClass('folder').text(folderId)
.data('folderId', folderId)
);
var $ul = $('<
ul
>').attr('id', 'f_' + folderId).hide();
folders[folderId].forEach(function (song) {
$ul.append($('<
li
>').addClass('song').text(song));
});
$('#playlist').append($ul);
});
});
// Folder click handler
$('#folders').on('click', '.folder', function () {
var folderId = $(this).data('folderId');
var $ul = $('#f_' + folderId);
$ul.slideToggle(function () {
$(this).toggleClass('fClicked', $ul.is(':visible'));
});
});
// Song click handler
$('#playlist').on('click', '.song', function () {
lyricIndex = 0;
clearTimeout(window.playbackTimeout);
MIDIjs.stop();
clearInterval(lyricInterval);
$('#lyric-container').text('');
var $song = $(this);
var folderId = $song.closest('ul').attr('id').replace('f_', '');
midiFile = 'songs/' + folderId + '/' + $song.text();
$('.song').removeClass('playing');
$song.addClass('playing');
$('#download').show();
$('#console').text('Loading: ' + $song.text() + '...');
current = $('.song').index($song);
// 加载歌词文件
const lrcFile = midiFile.replace(/\.mid$/, '.lrc');
fetch(lrcFile)
.then(response => response.text())
.then(parseLRC)
.catch(() => console.log('No lyrics found'));
// 更新状态显示
$('#status-bar').text('Loading: ' + $song.text() + '...');
MIDIjs.play(midiFile);
playbackStartTime = Date.now();
// 启动歌词更新
lyricInterval = setInterval(updateLyrics, 100);
// Playback ended handler
MIDIjs.onended = function () {
next(current + 1);
};
});
// Console click handler
$('#console').click(function () {
MIDIjs.stop();
clearInterval(lyricInterval);
$('#lyric-container').text('');
$('#console').text('Playback stopped');
$('.playing').removeClass('playing');
setTimeout(function () {
$('#console').text('Choose a song');
}, 2000);
});
// Download handler
$('#download').click(function () {
window.location.href = midiFile;
});
});
function parseLRC(lrcContent) {
lyrics = [];
timeStamps = [];
const lines = lrcContent.split('\n');
lines.forEach(line => {
const matches = line.match(/\[(\d{2}):(\d{2})\.(\d{2,3})\](.*)/);
if (matches) {
const min = parseInt(matches[1]);
const sec = parseInt(matches[2]);
const ms = parseInt(matches[3].padEnd(3, '0'));
const time = min * 60 + sec + ms / 1000;
timeStamps.push(time);
lyrics.push(matches[4].trim());
}
});
}
function updateLyrics() {
if (!playbackStartTime) return;
const elapsed = (Date.now() - playbackStartTime) / 1000;
while (lyricIndex <
timeStamps.length
&& timeStamps[lyricIndex] <= elapsed) {
lyricIndex++;
}
const
currentLyric
=
lyricIndex
> 0 ? lyrics[lyricIndex - 1] : '';
$('#lyric-container').text(currentLyric);
}
function next(index) {
var $songs = $('.song');
if (index >= $songs.length) index = 0;
if (index <
0
) index = $songs.length - 1;
$songs.eq(index).trigger('click');
}
</script>
</
body
>
</
html
>