feat: proxy HLS through backend to eliminate CORS issues
This commit is contained in:
parent
3930f014df
commit
d730413cba
@ -662,6 +662,7 @@ func (u *UI) Routes() (chi.Router, error) {
|
|||||||
r.Get("/diagnostics", u.pageDiagnostics)
|
r.Get("/diagnostics", u.pageDiagnostics)
|
||||||
r.Get("/alarms", u.pageAlarms)
|
r.Get("/alarms", u.pageAlarms)
|
||||||
r.Get("/monitor", u.pageMonitor)
|
r.Get("/monitor", u.pageMonitor)
|
||||||
|
r.Get("/hls/{deviceID}/*", u.proxyHLS)
|
||||||
r.Get("/api/monitor/channels", u.apiMonitorChannels)
|
r.Get("/api/monitor/channels", u.apiMonitorChannels)
|
||||||
r.Get("/recognition", u.pageRecognition)
|
r.Get("/recognition", u.pageRecognition)
|
||||||
r.Get("/logs", u.pageLogs)
|
r.Get("/logs", u.pageLogs)
|
||||||
@ -3891,3 +3892,33 @@ func (u *UI) apiMonitorChannels(w http.ResponseWriter, r *http.Request) {
|
|||||||
w.WriteHeader(code)
|
w.WriteHeader(code)
|
||||||
w.Write(body)
|
w.Write(body)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u *UI) proxyHLS(w http.ResponseWriter, r *http.Request) {
|
||||||
|
deviceID := chi.URLParam(r, "deviceID")
|
||||||
|
dev, ok := u.findDevice(deviceID)
|
||||||
|
if !ok {
|
||||||
|
http.Error(w, "device not found", http.StatusNotFound)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
hlsPath := chi.URLParam(r, "*")
|
||||||
|
if hlsPath == "" {
|
||||||
|
http.Error(w, "missing path", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
body, code, err := u.agent.Do("GET", dev.IP, dev.MediaPort, "/"+hlsPath, nil)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusBadGateway)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Set HLS-friendly headers
|
||||||
|
if strings.HasSuffix(hlsPath, ".m3u8") {
|
||||||
|
w.Header().Set("Content-Type", "application/vnd.apple.mpegurl")
|
||||||
|
w.Header().Set("Access-Control-Allow-Origin", "*")
|
||||||
|
} else if strings.HasSuffix(hlsPath, ".ts") {
|
||||||
|
w.Header().Set("Content-Type", "video/mp2t")
|
||||||
|
w.Header().Set("Access-Control-Allow-Origin", "*")
|
||||||
|
}
|
||||||
|
w.Header().Set("Cache-Control", "no-cache")
|
||||||
|
w.WriteHeader(code)
|
||||||
|
w.Write(body)
|
||||||
|
}
|
||||||
|
|||||||
@ -34,7 +34,7 @@ function loadAll() {
|
|||||||
var promises = devices.map(function(dev) {
|
var promises = devices.map(function(dev) {
|
||||||
return fetch('/ui/api/monitor/channels?device_id=' + encodeURIComponent(dev.id))
|
return fetch('/ui/api/monitor/channels?device_id=' + encodeURIComponent(dev.id))
|
||||||
.then(function(r) { return r.json(); })
|
.then(function(r) { return r.json(); })
|
||||||
.then(function(data) { return (data.channels||[]).map(function(ch) { ch._dev = dev.name; return ch; }); })
|
.then(function(data) { return (data.channels||[]).map(function(ch) { ch._dev = dev.name; ch._devId = dev.id; return ch; }); })
|
||||||
.catch(function() { return []; });
|
.catch(function() { return []; });
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -49,6 +49,7 @@ function loadAll() {
|
|||||||
wall.style.gridTemplateColumns = "repeat(" + cols + ",minmax(0,1fr))";
|
wall.style.gridTemplateColumns = "repeat(" + cols + ",minmax(0,1fr))";
|
||||||
var html = "";
|
var html = "";
|
||||||
all.forEach(function(ch, i) {
|
all.forEach(function(ch, i) {
|
||||||
|
var proxyUrl = '/hls/' + ch._devId + '/hls/' + ch.name + '/index.m3u8';
|
||||||
html += '<div class="card" style="padding:8px">';
|
html += '<div class="card" style="padding:8px">';
|
||||||
html += '<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:6px">';
|
html += '<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:6px">';
|
||||||
html += '<span style="font-size:12px;font-weight:500">' + esc(ch._dev) + ' · ' + esc(ch.name) + '</span>';
|
html += '<span style="font-size:12px;font-weight:500">' + esc(ch._dev) + ' · ' + esc(ch.name) + '</span>';
|
||||||
@ -63,12 +64,13 @@ function loadAll() {
|
|||||||
wall.innerHTML = html;
|
wall.innerHTML = html;
|
||||||
// Initialize HLS players
|
// Initialize HLS players
|
||||||
all.forEach(function(ch, i) {
|
all.forEach(function(ch, i) {
|
||||||
if (!ch.hls_url) return;
|
if (!ch.hls_url || !ch._devId) return;
|
||||||
|
var proxyUrl = '/hls/' + ch._devId + '/hls/' + ch.name + '/index.m3u8';
|
||||||
var video = document.getElementById('v' + i);
|
var video = document.getElementById('v' + i);
|
||||||
if (!video) return;
|
if (!video) return;
|
||||||
if (Hls.isSupported()) {
|
if (Hls.isSupported()) {
|
||||||
var hls = new Hls();
|
var hls = new Hls();
|
||||||
hls.loadSource(ch.hls_url);
|
hls.loadSource(proxyUrl);
|
||||||
hls.attachMedia(video);
|
hls.attachMedia(video);
|
||||||
} else if (video.canPlayType('application/vnd.apple.mpegurl')) {
|
} else if (video.canPlayType('application/vnd.apple.mpegurl')) {
|
||||||
video.src = ch.hls_url;
|
video.src = ch.hls_url;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user