Flask集成youtube-dlp:点击音视频链接直接下载而非跳转播放页问题
问题
我使用Flask编写后端服务器,通过youtube-dlp按需为用户提供YouTube音视频格式的直接下载链接。当前代码已成功生成并在页面展示所有下载链接,但存在问题:用户点击链接时会跳转到音视频播放页面,需手动操作才能下载。我期望点击链接后直接触发音视频下载,无需跳转至播放页面。
相关代码如下:
app.py
from flask import Flask, jsonify, request, render_template import yt_dlp app = Flask(__name__) def get_download_links(video_url): ydl_opts = { 'format': 'best', } with yt_dlp.YoutubeDL(ydl_opts) as ydl: info = ydl.extract_info(video_url, download=False) video_formats = [] audio_formats = [] for format in info['formats']: if 'url' in format: if 'acodec' in format and format['acodec'] != 'none': audio_formats.append({ 'format_id': format['format_id'], 'url': format['url'], }) else: video_formats.append({ 'format_id': format['format_id'], 'url': format['url'], }) return video_formats, audio_formats, info['title'] @app.route('/') def index(): return render_template('index.html') @app.route('/get_download_links', methods=['GET']) def get_download_links_api(): video_url = request.args.get('video_url') if not video_url: return jsonify({"error": "Il parametro 'video_url' è richiesto."}), 400 video_formats, audio_formats, video_title = get_download_links(video_url) return jsonify({ 'video_formats': video_formats, 'audio_formats': audio_formats, 'video_title': video_title }) if __name__ == '__main__': app.run(debug=True)
index.html
<!DOCTYPE html> <html> <head> <title>Download Links</title> </head> <body> <h1>Download Links</h1> <form id="video-form"> <label for="video-url">Inserisci il link del video di YouTube:</label> <input type="text" id="video-url" required> <button type="submit">Genera link di download</button> </form> <div id="video-links"></div> <div id="audio-links"></div> <script src="{{ url_for('static', filename='js/main.js') }}"></script> </body> </html>
main.js
document.addEventListener('DOMContentLoaded', function() { function createDownloadLink(url, filename) { var link = document.createElement('a'); link.href = url; link.download = filename; link.textContent = 'Download'; link.style.display = 'block'; // Nasconde i link di download precedenti link.style.marginTop = '10px'; // Aggiunge uno spazio tra i link return link; } function displayVideoLinks(videoFormats) { var videoLinksDiv = document.getElementById('video-links'); videoLinksDiv.innerHTML = '<h2>Video Download Links</h2>'; videoFormats.forEach(function(format) { var link = createDownloadLink(format.url, format.format_id + '.mp4'); videoLinksDiv.appendChild(link); }); } function displayAudioLinks(audioFormats) { var audioLinksDiv = document.getElementById('audio-links'); audioLinksDiv.innerHTML = '<h2>Audio Download Links</h2>'; audioFormats.forEach(function(format) { var link = createDownloadLink(format.url, format.format_id + '.mp3'); audioLinksDiv.appendChild(link); }); } function getDownloadLinks(videoUrl) { fetch('/get_download_links?video_url=' + encodeURIComponent(videoUrl)) .then(response => response.json()) .then(data => { displayVideoLinks(data.video_formats); displayAudioLinks(data.audio_formats); }) .catch(error => console.error('Error:', error)); } var form = document.getElementById('video-form'); form.addEventListener('submit', function(event) { event.preventDefault(); var videoUrlInput = document.getElementById('video-url'); var videoUrl = videoUrlInput.value.trim(); if (videoUrl !== '') { getDownloadLinks(videoUrl); } }); });
相关界面截图:


解决方案
问题根源在于YouTube返回的音视频直链未设置Content-Disposition: attachment响应头,浏览器识别为可直接播放的媒体资源,而非需要下载的文件。通过后端中转请求,手动添加该响应头即可触发直接下载。
步骤1:修改后端代码(app.py)
新增一个下载中转路由,同时安装requests依赖(用于转发请求):
pip install requests
修改后的app.py:
from flask import Flask, jsonify, request, render_template import yt_dlp import requests app = Flask(__name__) def get_download_links(video_url): ydl_opts = { 'format': 'best', } with yt_dlp.YoutubeDL(ydl_opts) as ydl: info = ydl.extract_info(video_url, download=False) video_formats = [] audio_formats = [] for format in info['formats']: if 'url' in format: if 'acodec' in format and format['acodec'] != 'none': audio_formats.append({ 'format_id': format['format_id'], 'url': format['url'], }) else: video_formats.append({ 'format_id': format['format_id'], 'url': format['url'], }) return video_formats, audio_formats, info['title'] @app.route('/') def index(): return render_template('index.html') @app.route('/get_download_links', methods=['GET']) def get_download_links_api(): video_url = request.args.get('video_url') if not video_url: return jsonify({"error": "Il parametro 'video_url' è richiesto."}), 400 video_formats, audio_formats, video_title = get_download_links(video_url) return jsonify({ 'video_formats': video_formats, 'audio_formats': audio_formats, 'video_title': video_title }) # 新增下载中转路由 @app.route('/download') def download(): target_url = request.args.get('url') filename = request.args.get('filename') if not target_url or not filename: return jsonify({"error": "缺少必要参数"}), 400 # 流式请求YouTube资源 response = requests.get(target_url, stream=True) # 设置触发下载的响应头 headers = { 'Content-Disposition': f'attachment; filename="{filename}"', 'Content-Type': response.headers.get('Content-Type', 'application/octet-stream') } return response.content, 200, headers if __name__ == '__main__': app.run(debug=True)
步骤2:修改前端代码(main.js)
将原来的YouTube直链替换为后端中转路由:
document.addEventListener('DOMContentLoaded', function() { function createDownloadLink(url, filename) { var link = document.createElement('a'); // 替换为后端下载路由,传递目标链接和文件名 link.href = `/download?url=${encodeURIComponent(url)}&filename=${encodeURIComponent(filename)}`; link.textContent = '下载'; link.style.display = 'block'; link.style.marginTop = '10px'; return link; } function displayVideoLinks(videoFormats) { var videoLinksDiv = document.getElementById('video-links'); videoLinksDiv.innerHTML = '<h2>视频下载链接</h2>'; videoFormats.forEach(function(format) { var link = createDownloadLink(format.url, format.format_id + '.mp4'); videoLinksDiv.appendChild(link); }); } function displayAudioLinks(audioFormats) { var audioLinksDiv = document.getElementById('audio-links'); audioLinksDiv.innerHTML = '<h2>音频下载链接</h2>'; audioFormats.forEach(function(format) { var link = createDownloadLink(format.url, format.format_id + '.mp3'); audioLinksDiv.appendChild(link); }); } function getDownloadLinks(videoUrl) { fetch('/get_download_links?video_url=' + encodeURIComponent(videoUrl)) .then(response => response.json()) .then(data => { displayVideoLinks(data.video_formats); displayAudioLinks(data.audio_formats); }) .catch(error => console.error('错误:', error)); } var form = document.getElementById('video-form'); form.addEventListener('submit', function(event) { event.preventDefault(); var videoUrlInput = document.getElementById('video-url'); var videoUrl = videoUrlInput.value.trim(); if (videoUrl !== '') { getDownloadLinks(videoUrl); } }); });
步骤3:修改前端文本(可选)
将index.html中的意大利语文本替换为中文,提升用户体验:
<!DOCTYPE html> <html> <head> <title>YouTube音视频下载</title> </head> <body> <h1>YouTube音视频下载</h1> <form id="video-form"> <label for="video-url">输入YouTube视频链接:</label> <input type="text" id="video-url" required> <button type="submit">生成下载链接</button> </form> <div id="video-links"></div> <div id="audio-links"></div> <script src="{{ url_for('static', filename='js/main.js') }}"></script> </body> </html>
现在点击下载链接时,后端会转发请求到YouTube资源,并添加强制下载的响应头,浏览器将直接触发文件下载,不再跳转至播放页面。
内容的提问来源于stack exchange,提问作者jfranz
相关产品推荐
相关产品推荐

