前提摘要

2024最新python使用yt-dlp
2024最新YT-DLP使用demo网页端渲染-LMLPHP

1.使用python的fastapi库和jinjia2库进行前端渲染

功能如下
使用YT-DLP,缓存文件到本地,预览文件信息

2024最新YT-DLP使用demo网页端渲染-LMLPHP
2024最新YT-DLP使用demo网页端渲染-LMLPHP

2.代码实现

1)目录结构

2024最新YT-DLP使用demo网页端渲染-LMLPHP

2)代码

style.css

body {
    font-family: Arial, sans-serif;
    margin: 0;
    padding: 20px;
    background-color: #f0f0f0;
}

.container {
    max-width: 800px;
    margin: 0 auto;
    background-color: white;
    padding: 20px;
    border-radius: 8px;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}

/* 添加 logo 相关样式 */
.logo {
    display: flex;
    justify-content: center;
    gap: 8px;
    margin-bottom: 20px;
}

.youtube-icon, .download-icon {
    width: 32px;  /* 调整图标大小 */
    height: 32px; /* 调整图标大小 */
}

.header {
    text-align: center;
    margin-bottom: 30px;
}

h1 {
    font-size: 24px;
    margin: 10px 0;
}

.subtitle {
    color: #666;
    margin-bottom: 20px;
}

form {
    margin: 20px 0;
}

.input-group {
    display: flex;
    gap: 10px;
}

input[type="text"] {
    flex: 1;
    padding: 10px;
    border: 1px solid #ddd;
    border-radius: 4px;
}

button {
    background-color: #007bff;
    color: white;
    padding: 10px 20px;
    border: none;
    border-radius: 4px;
    cursor: pointer;
}

button:hover {
    background-color: #0056b3;
}

.disclaimer {
    text-align: center;
    color: #666;
    font-size: 14px;
    margin: 20px 0;
}

.info-icon {
    color: #007bff;
    cursor: help;
}

.footer {
    text-align: center;
    margin-top: 30px;
    color: #666;
    font-size: 14px;
}

index.html

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>YouTube 视频下载器</title>
    <link rel="stylesheet" href="{{ url_for('static', path='style.css') }}">
</head>
<body>
    <div class="container">
        <div class="header">
            <div class="logo">
                <svg class="youtube-icon" viewBox="0 0 24 24">
                    <path fill="#FF0000" d="M23.498 6.186a3.016 3.016 0 0 0-2.122-2.136C19.505 3.545 12 3.545 12 3.545s-7.505 0-9.377.505A3.017 3.017 0 0 0 .502 6.186C0 8.07 0 12 0 12s0 3.93.502 5.814a3.016 3.016 0 0 0 2.122 2.136c1.871.505 9.376.505 9.376.505s7.505 0 9.377-.505a3.015 3.015 0 0 0 2.122-2.136C24 15.93 24 12 24 12s0-3.93-.502-5.814zM9.545 15.568V8.432L15.818 12l-6.273 3.568z"/>
                </svg>
                <svg class="download-icon" viewBox="0 0 24 24">
                    <path fill="#4285f4" d="M19 9h-4V3H9v6H5l7 7 7-7zM5 18v2h14v-2H5z"/>
                </svg>
            </div>
            <h1>YT-DLP-DEMO</h1>
            <p class="subtitle">YTDownload</p>
        </div>

        <form action="/download" method="POST">
            <div class="input-group">
                <input type="text" 
                       name="url" 
                       placeholder="https://www.youtube.com/watch?v=..." 
                       required>
                <button type="submit">下载</button>
            </div>
        </form>

        <div class="footer">
            <p>由 FastAPI 和 yt-dlp 提供技术支持</p>
        </div>
    </div>
</body>
</html> 

result.html

<!DOCTYPE html>
<html>
<head>
    <title>Download Result</title>
    <link rel="stylesheet" href="{{ url_for('static', path='style.css') }}">
</head>
<body>
    <div class="container">
        {% if success %}
            <div class="result-info">
                <div class="video-header">
                    <div class="video-details">
                        <h2>{{ video_info.title }}</h2>
                        <div class="meta-info">
                            <p><strong>作者:</strong> {{ video_info.author }}</p>
                            <p><strong>时长:</strong> {{ video_info.length }}</p>
                            <p><strong>观看次数:</strong> {{ '{:,}'.format(video_info.views) }}</p>
                        </div>
                    </div>
                </div>
                
                <div class="download-sections">
                    <div class="preview-section">
                        <h3>视频预览</h3>
                        <div class="preview-container">
                            <video controls>
                                <source src="{{ video_path }}" type="video/mp4">
                                您的浏览器不支持视频标签。
                            </video>
                        </div>
                        <a href="{{ video_path }}" class="download-button" download>
                            <span class="icon"></span> 下载视频
                        </a>
                    </div>
                    
                    <div class="preview-section">
                        <h3>音频预览</h3>
                        <div class="preview-container">
                            <audio controls>
                                <source src="{{ audio_path }}" type="audio/mp4">
                                您的浏览器不支持音频标签。
                            </audio>
                        </div>
                        <a href="{{ audio_path }}" class="download-button" download>
                            <span class="icon"></span> 下载音频
                        </a>
                    </div>
                </div>
            </div>
        {% else %}
            <div class="error-container">
                <h2>下载失败</h2>
                <p class="error-message">{{ error }}</p>
            </div>
        {% endif %}
        
        <a href="/" class="back-button">返回首页</a>
    </div>
</body>
</html> 

main.py

from fastapi import FastAPI, Request, Form
from fastapi.templating import Jinja2Templates
from fastapi.staticfiles import StaticFiles
from fastapi.responses import FileResponse
import yt_dlp
from pathlib import Path
import os

app = FastAPI()

# 配置静态文件和模板
app.mount("/static", StaticFiles(directory="static"), name="static")
templates = Jinja2Templates(directory="templates")

# 配置下载目录
VIDEO_DIR = Path("downloads/video")
AUDIO_DIR = Path("downloads/audio")
VIDEO_DIR.mkdir(parents=True, exist_ok=True)
AUDIO_DIR.mkdir(parents=True, exist_ok=True)

def download_youtube_video(url):
    try:
        # yt-dlp 基础配置
        common_opts = {
            'cookiefile': r'www.youtube.com_cookies.txt',
            'quiet': False,
            'no_warnings': False,
            'verbose': True,
            'proxy': 'http://127.0.0.1:10809',
            'socket_timeout': 30,
            'retries': 3,
            'nocheckcertificate': True,
            'prefer_insecure': True
        }

        # 视频下载选项
        video_opts = {
            **common_opts,
            'format': 'best[ext=mp4][height<=720]/best[height<=720]/best',
            'outtmpl': str(VIDEO_DIR / '%(title)s.%(ext)s'),
        }

        # 音频下载选项
        audio_opts = {
            **common_opts,
            'format': 'bestaudio[ext=m4a]/bestaudio',
            'outtmpl': str(AUDIO_DIR / '%(title)s.%(ext)s'),
        }

        # 获取视频信息
        with yt_dlp.YoutubeDL(common_opts) as ydl:
            info = ydl.extract_info(url, download=False)
            title = info['title']
            duration = info['duration']
            thumbnail = info['thumbnail']
            author = info.get('uploader', 'Unknown')
            views = info.get('view_count', 0)

        # 下载视频
        with yt_dlp.YoutubeDL(video_opts) as ydl:
            ydl.download([url])

        # 下载音频
        with yt_dlp.YoutubeDL(audio_opts) as ydl:
            ydl.download([url])

        # 获取下载后的文件路径
        video_file = next(VIDEO_DIR.glob(f"{title}.*"))
        audio_file = next(AUDIO_DIR.glob(f"{title}.*"))

        return {
            "status": "success",
            "title": title,
            "author": author,
            "duration": f"{duration // 60}:{duration % 60:02d}",
            "views": views,
            "thumbnail": thumbnail,
            "video_path": str(video_file.name),
            "audio_path": str(audio_file.name)
        }
    except Exception as e:
        return {"status": "error", "message": str(e)}

@app.get("/")
async def home(request: Request):
    return templates.TemplateResponse("index.html", {"request": request})

@app.post("/download")
async def download_video_route(request: Request, url: str = Form(...)):
    try:
        result = download_youtube_video(url)
        
        if result["status"] == "success":
            video_info = {
                "title": result["title"],
                "author": result["author"],
                "length": result["duration"],
                "views": result["views"],
                "thumbnail": result["thumbnail"]
            }
            
            return templates.TemplateResponse("result.html", {
                "request": request,
                "video_info": video_info,
                "video_path": f"/downloads/video/{result['video_path']}",
                "audio_path": f"/downloads/audio/{result['audio_path']}",
                "success": True
            })
        else:
            raise Exception(result["message"])
            
    except Exception as e:
        return templates.TemplateResponse("result.html", {
            "request": request,
            "error": str(e),
            "success": False
        })

# 配置下载目录的静态文件服务
app.mount("/downloads", StaticFiles(directory="downloads"), name="downloads") 

run.py

import uvicorn
import os

def check_directories():
    """确保必要的目录存在"""
    directories = [
        'static',
        'templates',
        'downloads',
        'downloads/video',
        'downloads/audio'
    ]
    for directory in directories:
        if not os.path.exists(directory):
            os.makedirs(directory)
            print(f"Created directory: {directory}")

if __name__ == "__main__":
    # 检查并创建必要的目录
    check_directories()
    
    # 配置并启动服务器
    uvicorn.run(
        "main:app", 
        host="127.0.0.1", 
        port=8000, 
        reload=True,
        reload_dirs=["templates", "static"],
        log_level="info"
    ) 

3)运行测试

命令端运行

2024最新YT-DLP使用demo网页端渲染-LMLPHP

2024最新YT-DLP使用demo网页端渲染-LMLPHP

3.项目下载地址

https://github.com/unkownc/python_demo/tree/main
2024最新YT-DLP使用demo网页端渲染-LMLPHP

11-25 20:27