我正在构建一个 Flask 应用程序,它使用 m3u8 和请求来提供 m3u8 流视频文件。但是,当我尝试从外部 URL 获取 m3u8 文件时遇到 CORS 问题。 CORS 标头设置不正确,我需要确保视频播放器可以从我的服务器获取播放列表和 TS 文件,而不会遇到 CORS 错误。
这是我当前的设置:
from flask import Flask, request, jsonify, render_template
import m3u8
import requests
from flask_cors import CORS, cross_origin
app = Flask(__name__)
@app.route('/')
def index():
return render_template('index.html')
@app.route('/extract', methods=['POST'])
def extract_quality():
m3u8_url = request.json.get('url')
if not m3u8_url:
return jsonify({"error": "No URL provided"}), 400
try:
playlist = m3u8.load(m3u8_url)
qualities = []
for playlist_variant in playlist.playlists:
resolution = playlist_variant.stream_info.resolution
bandwidth = playlist_variant.stream_info.bandwidth
uri = playlist_variant.uri
qualities.append({
"resolution": resolution,
"bandwidth": bandwidth,
"uri": uri
})
return jsonify(qualities)
except Exception as e:
return jsonify({"error": f"An error occurred: {str(e)}"}), 500
CORS(app, resources={r"/*": {"origins": "*"}})
@app.route('/proxy', methods=['GET'])
@cross_origin()
def proxy():
url = request.args.get('url')
if not url:
return jsonify({"error": "No URL provided"}), 400
try:
response = requests.get(url)
if response.status_code == 200:
return response.content, response.status_code, {
'Access-Control-Allow-Origin': '*',
'Content-Type': response.headers.get('Content-Type', 'application/octet-stream')
}
else:
return jsonify({"error": f"Failed to fetch URL, status code: {response.status_code}"}), 500
except requests.exceptions.RequestException as e:
return jsonify({"error": f"An error occurred: {str(e)}"}), 500
@app.route('/tsproxy', methods=['GET'])
@cross_origin()
def ts_proxy():
ts_url = request.args.get('url')
if not ts_url:
return jsonify({"error": "No URL provided"}), 400
try:
response = requests.get(ts_url)
if response.status_code == 200:
return response.content, response.status_code, {
'Access-Control-Allow-Origin': '*',
'Content-Type': 'video/MP2T'
}
else:
return jsonify({"error": f"Failed to fetch TS file, status code: {response.status_code}"}), 500
except requests.exceptions.RequestException as e:
return jsonify({"error": f"An error occurred: {str(e)}"}), 500
if __name__ == '__main__':
app.run(debug=True, host='0.0.0.0', port=5500)
我在前端使用 Hls.js 和 Plyr 来播放视频。这是播放器的 JavaScript 代码:
// JavaScript to handle fetching and playing the video
function getQualities() {
const url = document.getElementById("m3u8_url").value;
if (!url) {
alert("Please enter a URL!");
return;
}
fetch("/extract", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ url: url }),
})
.then((response) => response.json())
.then((data) => {
if (data.error) {
alert(data.error);
} else {
const selector = document.getElementById("quality_selector");
selector.innerHTML = ""; // Clear previous results
data.forEach((item) => {
const option = document.createElement("option");
option.value = item.uri;
option.textContent = `${item.resolution ? item.resolution.join("x") : "N/A"} - ${item.bandwidth} bps`;
selector.appendChild(option);
});
document.getElementById("quality_options").classList.remove("hidden");
}
})
.catch((error) => {
console.error("Error:", error);
alert("An error occurred while fetching the data");
});
}
function playVideo() {
const video = document.getElementById("video");
const url = document.getElementById("quality_selector").value;
if (!url) {
alert("Please select a quality!");
return;
}
const proxyUrl = `http://192.168.1.15:5500/proxy?url=${encodeURIComponent(url)}`;
if (Hls.isSupported()) {
const hls = new Hls({
loader: function (config) {
const originalLoader = new Hls.DefaultConfig.loader(config);
const originalLoad = originalLoader.load.bind(originalLoader);
// Update the TS segment URL to use the '/tsproxy' route
originalLoader.load = function (context, config, callbacks) {
if (context.type === "fragment") {
context.url = `http://192.168.1.15:5500/tsproxy?url=${encodeURIComponent(context.url)}`;
}
return originalLoad(context, config, callbacks);
};
return originalLoader;
},
});
hls.loadSource(proxyUrl);
hls.attachMedia(video);
new Plyr(video);
} else if (video.canPlayType("application/vnd.apple.mpegurl")) {
video.src = proxyUrl;
new Plyr(video);
} else {
alert("Your browser does not support HLS!");
}
}
} 问题: 当我尝试从外部源获取 m3u8 和 TS 文件时,尽管在 Flask 中使用了 CORS 库,但我还是遇到了 CORS 错误。 我使用 /proxy 和 /tsproxy 路由通过 Flask 应用程序代理请求,但似乎 CORS 标头设置不正确或者浏览器仍然阻止请求。
我在代理响应中手动添加了 CORS 标头。 我尝试在代理路由上使用 @cross_origin() 。 我检查了浏览器的开发人员工具,在尝试获取视频片段时,它显示了与 CORS 相关的错误。 如何解决 CORS 问题并在 Flask 应用程序中成功从外部 URL 传输 m3u8 视频?
您可以创建一个服务器端 PHP 代理,通过所选的引荐来源网址获取视频并将其提供给您的 HTML 页面。
代理.php
<?php
$url = $_GET['url'];
// Set to your desired referrer
$referrer = 'http://www.example.com/';
// Set the referrer header
$opts = [
'http' => [
'header' => 'Referer: ' . $referrer
]
];
// Create stream context with referrer header
$context = stream_context_create($opts);
// Fetch video with the specified referrer
$videoContent = file_get_contents($url, false, $context);
// Set the Content-Type header
header('Content-Type: application/x-mpegURL');
echo $videoContent;
?>
将 HTML 指向服务器端脚本的 URL。
<body>
<video id="video" style="width: 100%; height: 100%;" controls="">
<source src="proxy.php?url=https://yoursite.com/video/720p/playlist.m3u8" type="application/x-mpegURL">
</video>
<script src="player.js"></script>
</body>