mp4, rtsp

This commit is contained in:
Radek Davidek 2026-03-04 15:33:04 +01:00
parent 28c5cb8c0c
commit c5d5685734
3 changed files with 46 additions and 4 deletions

View File

@ -338,7 +338,11 @@ public final class XtreamPlayerApplication {
String streamUrl;
String directUrl = query.getOrDefault("url", "").trim();
if (!directUrl.isBlank()) {
if (!directUrl.startsWith("http://") && !directUrl.startsWith("https://")) {
String lowerUrl = directUrl.toLowerCase(Locale.ROOT);
if (!lowerUrl.startsWith("http://")
&& !lowerUrl.startsWith("https://")
&& !lowerUrl.startsWith("rtsp://")
&& !lowerUrl.startsWith("rtsps://")) {
writeJson(exchange, 400, errorJson("Unsupported URL protocol."));
return;
}
@ -817,8 +821,13 @@ public final class XtreamPlayerApplication {
List<String> attemptErrors = new ArrayList<>();
for (URI candidate : attempts) {
try {
String incomingRange = firstNonBlank(
exchange.getRequestHeaders().getFirst("Range"),
"bytes=0-"
);
HttpRequest.Builder requestBuilder = HttpRequest.newBuilder(candidate)
.GET()
.timeout(Duration.ofSeconds(60))
.header("User-Agent", firstNonBlank(
exchange.getRequestHeaders().getFirst("User-Agent"),
DEFAULT_BROWSER_UA
@ -826,12 +835,16 @@ public final class XtreamPlayerApplication {
.header("Accept", firstNonBlank(
exchange.getRequestHeaders().getFirst("Accept"),
"*/*"
))
.header("Range", incomingRange)
.header("Accept-Encoding", firstNonBlank(
exchange.getRequestHeaders().getFirst("Accept-Encoding"),
"identity"
));
copyRequestHeaderIfPresent(exchange, requestBuilder, "Range");
copyRequestHeaderIfPresent(exchange, requestBuilder, "If-Range");
copyRequestHeaderIfPresent(exchange, requestBuilder, "Accept-Encoding");
copyRequestHeaderIfPresent(exchange, requestBuilder, "Cache-Control");
copyRequestHeaderIfPresent(exchange, requestBuilder, "Pragma");
copyRequestHeaderIfPresent(exchange, requestBuilder, "Origin");
String referer = resolveRefererForCandidate(exchange, candidate, sourceUrl);
if (!referer.isBlank()) {
requestBuilder.header("Referer", referer);

View File

@ -310,6 +310,10 @@
if (!name || !url) {
return;
}
if (!isSupportedCustomUrl(url)) {
setSettingsMessage("Custom stream URL must start with http://, https://, rtsp://, or rtsps://", "err");
return;
}
state.customStreams.push({
id: String(Date.now()),
name,
@ -1748,6 +1752,15 @@
setSubtitleStatus("No subtitle loaded.", false);
scheduleEmbeddedSubtitleScan();
if (isRtspUrl(playbackUrl)) {
state.currentStreamInfo.playbackEngine = "external player (RTSP)";
state.currentStreamInfo.resolution = "n/a";
state.currentStreamInfo.duration = "n/a";
renderStreamInfo();
setSettingsMessage("RTSP is not supported in browser player. Use Open in system player.", "err");
return;
}
if (isLikelyHls(playbackUrl) && shouldUseHlsJs()) {
state.currentStreamInfo.playbackEngine = "hls.js";
renderStreamInfo();
@ -1820,6 +1833,9 @@
if (!url) {
return url;
}
if (isRtspUrl(url)) {
return url;
}
try {
const pageIsHttps = window.location.protocol === "https:";
const target = new URL(url, window.location.href);
@ -1832,6 +1848,19 @@
return url;
}
function isRtspUrl(urlRaw) {
const value = String(urlRaw || "").trim().toLowerCase();
return value.startsWith("rtsp://") || value.startsWith("rtsps://");
}
function isSupportedCustomUrl(urlRaw) {
const value = String(urlRaw || "").trim().toLowerCase();
return value.startsWith("http://")
|| value.startsWith("https://")
|| value.startsWith("rtsp://")
|| value.startsWith("rtsps://");
}
function resetPlayerElement() {
disposeHls();
el.player.pause();

View File

@ -129,7 +129,7 @@
</label>
<label>
URL
<input id="custom-url" required placeholder="https://...m3u8">
<input id="custom-url" required placeholder="https://...m3u8 or rtsp://...">
</label>
<div class="actions">
<button type="submit">Add</button>