douyin_to_youtube / tabs /youtube_player_tab.py
qgyd2021's picture
update
0e920a7
#!/usr/bin/python3
# -*- coding: utf-8 -*-
import json
import re
import gradio as gr
from jinja2 import Template
import tempfile
html_content = """
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>YouTube视频连续播放器</title>
<style>
body {
font-family: Arial, sans-serif;
max-width: 1600px;
margin: 0 auto;
padding: 20px;
text-align: center;
}
#player {
width: 1200px;
height: 675px;
# aspect-ratio: 16/9;
}
#playlist {
text-align: left;
margin: 20px 0;
}
.current {
font-weight: bold;
color: #ff0000;
}
</style>
</head>
<body>
<h1>YouTube视频连续播放器</h1>
<div id="player"></div>
<div id="playlist"></div>
<div id="status">准备播放...</div>
<script>
// 获取所有视频ID
const videoIds = {{ video_ids }};
let currentVideoIndex = 0;
let player;
// 加载YouTube IFrame API
function onYouTubeIframeAPIReady() {
player = new YT.Player('player', {
height: '390',
width: '640',
events: {
'onReady': onPlayerReady,
'onStateChange': onPlayerStateChange
}
});
}
// 播放器准备就绪
function onPlayerReady(event) {
loadAndPlayVideo(currentVideoIndex);
updatePlaylist();
}
// 播放器状态变化
function onPlayerStateChange(event) {
if (event.data === YT.PlayerState.ENDED) {
// 当前视频结束,播放下一个
currentVideoIndex++;
if (currentVideoIndex < videoIds.length) {
loadAndPlayVideo(currentVideoIndex);
updatePlaylist();
} else {
document.getElementById('status').textContent = '所有视频播放完毕';
}
}
}
// 加载并播放指定索引的视频
function loadAndPlayVideo(index) {
if (index >= 0 && index < videoIds.length) {
player.loadVideoById(videoIds[index]);
document.getElementById('status').textContent = `正在播放: 视频 ${index + 1}/${videoIds.length}`;
}
}
// 更新播放列表显示
function updatePlaylist() {
const playlistElement = document.getElementById('playlist');
playlistElement.innerHTML = '<h3>播放列表:</h3>';
videoIds.forEach((id, index) => {
const item = document.createElement('div');
item.textContent = `视频 ${index + 1}: https://youtu.be/${id}`;
if (index === currentVideoIndex) {
item.className = 'current';
}
playlistElement.appendChild(item);
});
}
// 动态加载YouTube IFrame API
const tag = document.createElement('script');
tag.src = "https://www.youtube.com/iframe_api";
const firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
</script>
</body>
</html>
"""
def make_file(content: str):
with tempfile.NamedTemporaryFile(mode='w', delete=False, suffix='.html') as tmp:
tmp.write(content)
tmp_path = tmp.name
return tmp_path
def get_video_id(url: str):
"""
从各种YouTube URL格式中提取视频ID
支持的格式包括:
- 普通URL: https://www.youtube.com/watch?v=dQw4w9WgXcQ
- 短链接: https://youtu.be/dQw4w9WgXcQ
- 嵌入链接: https://www.youtube.com/embed/dQw4w9WgXcQ
- 带时间戳: https://youtu.be/dQw4w9WgXcQ?t=120
- 带其他参数: https://www.youtube.com/watch?v=dQw4w9WgXcQ&feature=share
- 移动端链接: https://m.youtube.com/watch?v=dQw4w9WgXcQ
- 无协议链接: youtube.com/watch?v=dQw4w9WgXcQ
- 仅视频ID: dQw4w9WgXcQ
"""
pattern = r'(?:youtube\.com\/(?:watch\?v=|embed\/|shorts\/|live\/)|youtu\.be\/)([^"&?\/\s]{11})'
match = re.search(pattern, url)
if match is None:
return None
video_id = match.group(1)
return video_id
def when_click_make_html_button(playlist: str):
urls = [url.strip() for url in playlist.split("\n") if url.strip()]
video_ids = [get_video_id(url) for url in urls]
video_ids = [video_id for video_id in video_ids if video_id is not None]
video_ids_ = json.dumps(video_ids, ensure_ascii=False)
template = Template(html_content)
variables = {
"video_ids": video_ids_
}
html_content_ = template.render(variables)
filename = make_file(html_content_)
return filename
def get_youtube_player_tab():
with gr.TabItem("youtube_player"):
with gr.Row():
with gr.Column(scale=5):
yp_playlist = gr.Textbox(
label="playlist",
value="https://www.youtube.com/watch?v=tvRNE-ULe94\nhttps://www.youtube.com/watch?v=VQmaDgmyIBc\nhttps://www.youtube.com/watch?v=e_sFLaQUN3k\nhttps://www.youtube.com/watch?v=-VDYnk0jM8Q",
placeholder="每行输入一个YouTube视频链接\n例如:\nhttps://www.youtube.com/watch?v=dQw4w9WgXcQ\nhttps://youtu.be/9bZkp7q19f0",
lines=10,
)
yp_make_html_button = gr.Button("make_html")
with gr.Column(scale=5):
yp_video_output = gr.File(label="play_html_file")
yp_make_html_button.click(
fn=when_click_make_html_button,
inputs=[yp_playlist],
outputs=[yp_video_output]
)
return locals()
if __name__ == "__main__":
with gr.Blocks() as block:
fs_components = get_youtube_player_tab()
block.launch()