<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Picture-in-Picture Lyrics</title>
<style>
#pip-button {
position: absolute;
top: 10px;
right: 10px;
padding: 10px 20px;
background-color: #007bff;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
}
#pip-button:hover {
background-color: #0056b3;
}
#pip-video {
display: none;
}
</style>
</head>
<body>
<button id="pip-button">画中画歌词</button>
<video id="pip-video" width="375" height="480" muted></video>
<script>
(function() {
'use strict';
const lyrics = [
[0.00, { lrc: "第一行歌词", tlrc: "First line" }],
[2.00, { lrc: "第二行歌词", tlrc: "Second line" }],
[4.00, { lrc: "第三行歌词", tlrc: "Third line" }],
[6.00, { lrc: "第四行歌词", tlrc: "Fourth line" }],
[8.00, { lrc: "第五行歌词", tlrc: "Fifth line" }],
[10.00, { lrc: "第六行歌词", tlrc: "Sixth line" }],
[12.00, { lrc: "第七行歌词", tlrc: "Seventh line" }],
[14.00, { lrc: "第八行歌词", tlrc: "Eighth line" }],
[16.00, { lrc: "第九行歌词", tlrc: "Ninth line" }],
[18.00, { lrc: "第十行歌词", tlrc: "Tenth line" }],
[20.00, { lrc: "第十一行歌词", tlrc: "Eleventh line" }],
[22.00, { lrc: "第十二行歌词", tlrc: "Twelfth line" }],
[24.00, { lrc: "第十三行歌词", tlrc: "Thirteenth line" }],
[26.00, { lrc: "第十四行歌词", tlrc: "Fourteenth line" }],
[28.00, { lrc: "第十五行歌词", tlrc: "Fifteenth line" }],
[30.00, { lrc: "第十六行歌词", tlrc: "Sixteenth line" }],
[32.00, { lrc: "第十七行歌词", tlrc: "Seventeenth line" }],
[34.00, { lrc: "第十八行歌词", tlrc: "Eighteenth line" }],
[36.00, { lrc: "第十九行歌词", tlrc: "Nineteenth line" }],
[38.00, { lrc: "第二十行歌词", tlrc: "Twentieth line" }]
];
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
canvas.width = 375;
canvas.height = 480;
const video = document.getElementById('pip-video');
const button = document.getElementById('pip-button');
let currentLyricIndex = 0;
let isPip = false;
let startTime = null;
let targetScrollPosition = 0;
let scrollSpeed = 0.1;
let lyricFontSize = 30;
let lyricHeight = 35;
let lyricColor = 'white';
let currentLyricColor = 'yellow';
const lyricDisplayPosition = canvas.height / 2 - lyricHeight / 2;
let scrollPosition = 0;
const stream = canvas.captureStream(30);
video.srcObject = stream;
function drawLyrics(time) {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = lyricColor;
ctx.font = `${lyricFontSize}px Arial`;
let currentLyricFound = false;
for (let i = 0; i < lyrics.length; i++) {
if (time >= lyrics[i][0]) {
currentLyricIndex = i;
currentLyricFound = true;
}
}
if (!currentLyricFound) {
currentLyricIndex = 0;
}
const maxVisibleLyrics = Math.floor(canvas.height / lyricHeight);
const startLyricIndex = Math.max(0, currentLyricIndex - Math.floor(maxVisibleLyrics / 2));
const endLyricIndex = Math.min(lyrics.length, startLyricIndex + maxVisibleLyrics);
targetScrollPosition = (currentLyricIndex * lyricHeight) - lyricDisplayPosition;
scrollPosition += (targetScrollPosition - scrollPosition) * scrollSpeed;
for (let i = startLyricIndex; i < endLyricIndex; i++) {
const [ , { lrc }] = lyrics[i];
const y = (i * lyricHeight) - scrollPosition;
if (y > -lyricHeight && y < canvas.height) {
ctx.fillStyle = (i === currentLyricIndex) ? currentLyricColor : lyricColor;
ctx.fillText(lrc, 50, y);
}
}
}
function animate(timestamp) {
if (!startTime) startTime = timestamp;
const elapsed = (timestamp - startTime) / 1000;
drawLyrics(elapsed);
requestAnimationFrame(animate);
}
function togglePip() {
if (isPip) {
document.exitPictureInPicture();
} else {
video.requestPictureInPicture();
}
}
video.addEventListener('enterpictureinpicture', () => {
isPip = true;
});
video.addEventListener('leavepictureinpicture', () => {
isPip = false;
});
video.addEventListener('loadedmetadata', () => {
video.play().catch(error => {
console.error('Error playing video:', error);
});
});
button.addEventListener('click', togglePip);
animate();
})();
</script>
</body>
</html>