LRC-And-YouTube-Player / index-ver1.html
abdelhaqueidali's picture
Upload 12 files
d50155f verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>LRC & YouTube Player</title>
<style>
body {
font-family: Arial, sans-serif;
max-width: 800px;
margin: 0 auto;
padding: 20px;
background-color: #f5f5f5;
}
h1 {
color: #333;
text-align: center;
}
#songList {
list-style: none;
padding: 0;
background: white;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
#songList li {
cursor: pointer;
padding: 12px 20px;
margin: 0;
border-bottom: 1px solid #eee;
transition: background-color 0.2s;
}
#songList li:last-child {
border-bottom: none;
}
#songList li:hover {
background-color: #f0f0f0;
}
#playerContainer {
margin-top: 20px;
display: none;
background: white;
padding: 20px;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
#youtubePlayer {
width: 100%;
max-width: 640px;
height: 360px;
margin: 0 auto;
display: block;
}
#lyricsDisplay {
margin-top: 20px;
white-space: pre-wrap;
border: 1px solid #ddd;
padding: 15px;
border-radius: 4px;
overflow-y: auto;
height: 300px;
font-size: 16px;
line-height: 1.6;
background: #fff;
}
.highlighted-lyric {
background-color: #fff3cd;
padding: 2px 5px;
border-radius: 3px;
transition: background-color 0.3s;
}
#errorDisplay {
color: red;
margin: 10px 0;
padding: 10px;
border: 1px solid red;
display: none;
}
</style>
</head>
<body>
<h1>LRC & YouTube Player</h1>
<div id="errorDisplay"></div>
<ul id="songList"></ul>
<div id="playerContainer">
<div id="youtubePlayer"></div>
<div id="lyricsDisplay"></div>
</div>
<script>
let player;
let currentLyrics = [];
let currentLyricIndex = -1;
let syncInterval;
function showError(message) {
const errorDisplay = document.getElementById('errorDisplay');
errorDisplay.textContent = message;
errorDisplay.style.display = 'block';
console.error(message);
}
// Load song list from data.txt
console.log('Starting to load data.txt...');
fetch('data.txt')
.then(response => {
console.log('data.txt response status:', response.status);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return response.text();
})
.then(data => {
console.log('data.txt content:', data);
const songList = document.getElementById('songList');
if (!data.trim()) {
throw new Error('data.txt is empty');
}
data.trim().split('\n').forEach((line, index) => {
console.log(`Processing line ${index}:`, line);
const [filename, youtubeLink] = line.split('|');
if (!filename || !youtubeLink) {
showError(`Invalid line format in data.txt: ${line}`);
return;
}
const li = document.createElement('li');
li.textContent = filename.replace('.lrc', '');
li.dataset.filename = filename;
li.dataset.youtubeLink = youtubeLink;
li.onclick = () => loadSong(filename, youtubeLink);
songList.appendChild(li);
});
})
.catch(error => {
showError(`Error loading song list: ${error.message}`);
console.error('Full error:', error);
});
// Load the YouTube IFrame Player API
console.log('Loading YouTube IFrame API...');
const tag = document.createElement('script');
tag.src = "https://www.youtube.com/iframe_api";
document.head.appendChild(tag);
// Initialize YouTube player when API is ready
window.onYouTubeIframeAPIReady = function() {
console.log('YouTube IFrame API Ready');
player = new YT.Player('youtubePlayer', {
height: '360',
width: '640',
videoId: '',
events: {
'onReady': onPlayerReady,
'onStateChange': onPlayerStateChange,
'onError': onPlayerError
}
});
};
function onPlayerReady(event) {
console.log('YouTube player ready');
}
function onPlayerError(event) {
console.error('YouTube player error:', event.data);
showError('Error loading YouTube video');
}
function loadSong(filename, youtubeLink) {
console.log('Loading song:', filename, youtubeLink);
// Extract YouTube video ID
const videoId = youtubeLink.match(/[?&]v=([^&]+)/)?.[1] ||
youtubeLink.match(/youtu\.be\/([^?]+)/)?.[1];
if (!videoId) {
showError('Invalid YouTube URL');
return;
}
console.log('Loading lyrics file:', filename);
// Load lyrics file
fetch(filename)
.then(response => {
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return response.text();
})
.then(text => {
console.log('Lyrics loaded, parsing...');
currentLyrics = parseLRC(text);
console.log('Parsed lyrics:', currentLyrics);
displayLyrics();
currentLyricIndex = -1;
})
.catch(error => {
showError(`Error loading lyrics: ${error.message}`);
console.error('Full lyrics loading error:', error);
});
// Load video
if (player && player.loadVideoById) {
console.log('Loading YouTube video:', videoId);
player.loadVideoById(videoId);
document.getElementById('playerContainer').style.display = 'block';
} else {
showError('YouTube player not ready');
}
}
function parseLRC(text) {
const lines = text.split('\n');
const lyrics = [];
const timeRegex = /\[(\d+):(\d+)\.(\d+)\](.*)/;
lines.forEach((line, index) => {
const match = line.match(timeRegex);
if (match) {
const minutes = parseInt(match[1]);
const seconds = parseInt(match[2]);
const milliseconds = parseInt(match[3]);
const time = minutes * 60 + seconds + milliseconds / 1000;
const text = match[4].trim();
if (text) {
lyrics.push({ time, text });
}
} else {
console.log(`Line ${index} did not match LRC format:`, line);
}
});
return lyrics.sort((a, b) => a.time - b.time);
}
function displayLyrics() {
const container = document.getElementById('lyricsDisplay');
container.innerHTML = currentLyrics
.map((lyric, index) => `<p data-index="${index}">${lyric.text}</p>`)
.join('');
}
function syncLyrics() {
if (!player || !player.getCurrentTime) return;
const currentTime = player.getCurrentTime();
let index = currentLyrics.findIndex(lyric => lyric.time > currentTime) - 1;
if (index !== currentLyricIndex) {
// Remove previous highlight
const prevHighlight = document.querySelector('.highlighted-lyric');
if (prevHighlight) {
prevHighlight.classList.remove('highlighted-lyric');
}
// Add new highlight
if (index >= 0) {
const element = document.querySelector(`p[data-index="${index}"]`);
if (element) {
element.classList.add('highlighted-lyric');
element.scrollIntoView({ behavior: 'smooth', block: 'center' });
}
}
currentLyricIndex = index;
}
}
function onPlayerStateChange(event) {
console.log('Player state changed:', event.data);
if (event.data === YT.PlayerState.PLAYING) {
// Start syncing lyrics
if (syncInterval) clearInterval(syncInterval);
syncInterval = setInterval(syncLyrics, 100);
} else if (event.data === YT.PlayerState.PAUSED || event.data === YT.PlayerState.ENDED) {
// Stop syncing lyrics
if (syncInterval) clearInterval(syncInterval);
}
}
</script>
</body>
</html>