fix
This commit is contained in:
parent
52f3af0758
commit
87925a57de
@ -251,28 +251,7 @@ public final class XtreamPlayerApplication {
|
||||
List<String> attemptErrors = new ArrayList<>();
|
||||
for (URI candidate : attempts) {
|
||||
try {
|
||||
HttpRequest.Builder requestBuilder = HttpRequest.newBuilder(candidate)
|
||||
.GET()
|
||||
.timeout(Duration.ofSeconds(60))
|
||||
.header("User-Agent", firstNonBlank(
|
||||
exchange.getRequestHeaders().getFirst("User-Agent"),
|
||||
DEFAULT_BROWSER_UA
|
||||
))
|
||||
.header("Accept", firstNonBlank(
|
||||
exchange.getRequestHeaders().getFirst("Accept"),
|
||||
"*/*"
|
||||
));
|
||||
copyRequestHeaderIfPresent(exchange, requestBuilder, "Range");
|
||||
copyRequestHeaderIfPresent(exchange, requestBuilder, "If-Range");
|
||||
if (!sourceUrl.isBlank()) {
|
||||
requestBuilder.header("Referer", sourceUrl);
|
||||
String origin = originFromUrl(sourceUrl);
|
||||
if (!origin.isBlank()) {
|
||||
requestBuilder.header("Origin", origin);
|
||||
}
|
||||
}
|
||||
HttpRequest request = requestBuilder.build();
|
||||
HttpResponse<byte[]> candidateResponse = HTTP_CLIENT.send(request, HttpResponse.BodyHandlers.ofByteArray());
|
||||
HttpResponse<byte[]> candidateResponse = sendStreamRequest(exchange, candidate, sourceUrl);
|
||||
if (response == null || response.statusCode() >= 400) {
|
||||
response = candidateResponse;
|
||||
usedTarget = candidate;
|
||||
@ -298,6 +277,17 @@ public final class XtreamPlayerApplication {
|
||||
}
|
||||
String contentType = response.headers().firstValue("Content-Type").orElse("application/octet-stream");
|
||||
byte[] body = response.body() == null ? new byte[0] : response.body();
|
||||
|
||||
if (response.statusCode() == 403 && !sourceUrl.isBlank() && !isHlsPlaylist(usedTarget, contentType)) {
|
||||
UpstreamResult retried = retrySegmentUsingFreshPlaylist(exchange, target, sourceUrl);
|
||||
if (retried != null) {
|
||||
response = retried.response();
|
||||
usedTarget = retried.uri();
|
||||
contentType = response.headers().firstValue("Content-Type").orElse("application/octet-stream");
|
||||
body = response.body() == null ? new byte[0] : response.body();
|
||||
}
|
||||
}
|
||||
|
||||
if (response.statusCode() >= 400) {
|
||||
LOGGER.warn(
|
||||
"Stream proxy upstream returned status={} uri={} bytes={} contentType={}",
|
||||
@ -811,6 +801,86 @@ public final class XtreamPlayerApplication {
|
||||
return "/api/stream-proxy?url=" + urlEncode(absoluteUrl) + "&src=" + urlEncode(sourceUrl);
|
||||
}
|
||||
|
||||
private static UpstreamResult retrySegmentUsingFreshPlaylist(HttpExchange exchange, URI originalSegmentUri, String sourceUrl)
|
||||
throws IOException, InterruptedException {
|
||||
URI sourceUri = URI.create(sourceUrl);
|
||||
HttpResponse<byte[]> playlistResponse = sendStreamRequest(exchange, sourceUri, sourceUrl);
|
||||
if (playlistResponse.statusCode() >= 400) {
|
||||
return null;
|
||||
}
|
||||
String playlistType = playlistResponse.headers().firstValue("Content-Type").orElse("");
|
||||
if (!isHlsPlaylist(sourceUri, playlistType)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String segmentName = pathBasename(originalSegmentUri);
|
||||
if (segmentName.isBlank()) {
|
||||
return null;
|
||||
}
|
||||
String playlist = new String(
|
||||
playlistResponse.body() == null ? new byte[0] : playlistResponse.body(),
|
||||
StandardCharsets.UTF_8
|
||||
);
|
||||
String[] lines = playlist.split("\\r?\\n");
|
||||
UpstreamResult fallback = null;
|
||||
for (String line : lines) {
|
||||
String trimmed = line.trim();
|
||||
if (trimmed.isBlank() || trimmed.startsWith("#")) {
|
||||
continue;
|
||||
}
|
||||
URI candidate = sourceUri.resolve(trimmed);
|
||||
if (!segmentName.equals(pathBasename(candidate))) {
|
||||
continue;
|
||||
}
|
||||
HttpResponse<byte[]> response = sendStreamRequest(exchange, candidate, sourceUrl);
|
||||
UpstreamResult result = new UpstreamResult(response, candidate);
|
||||
fallback = result;
|
||||
if (response.statusCode() < 400) {
|
||||
LOGGER.info("Segment retry via fresh playlist succeeded uri={}", maskUri(candidate));
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return fallback;
|
||||
}
|
||||
|
||||
private static HttpResponse<byte[]> sendStreamRequest(HttpExchange exchange, URI candidate, String sourceUrl)
|
||||
throws IOException, InterruptedException {
|
||||
HttpRequest.Builder requestBuilder = HttpRequest.newBuilder(candidate)
|
||||
.GET()
|
||||
.timeout(Duration.ofSeconds(60))
|
||||
.header("User-Agent", firstNonBlank(
|
||||
exchange.getRequestHeaders().getFirst("User-Agent"),
|
||||
DEFAULT_BROWSER_UA
|
||||
))
|
||||
.header("Accept", firstNonBlank(
|
||||
exchange.getRequestHeaders().getFirst("Accept"),
|
||||
"*/*"
|
||||
));
|
||||
copyRequestHeaderIfPresent(exchange, requestBuilder, "Range");
|
||||
copyRequestHeaderIfPresent(exchange, requestBuilder, "If-Range");
|
||||
if (sourceUrl != null && !sourceUrl.isBlank()) {
|
||||
requestBuilder.header("Referer", sourceUrl);
|
||||
String origin = originFromUrl(sourceUrl);
|
||||
if (!origin.isBlank()) {
|
||||
requestBuilder.header("Origin", origin);
|
||||
}
|
||||
}
|
||||
HttpRequest request = requestBuilder.build();
|
||||
return HTTP_CLIENT.send(request, HttpResponse.BodyHandlers.ofByteArray());
|
||||
}
|
||||
|
||||
private static String pathBasename(URI uri) {
|
||||
String path = uri == null || uri.getPath() == null ? "" : uri.getPath();
|
||||
int index = path.lastIndexOf('/');
|
||||
if (index < 0 || index == path.length() - 1) {
|
||||
return path;
|
||||
}
|
||||
return path.substring(index + 1);
|
||||
}
|
||||
|
||||
private record UpstreamResult(HttpResponse<byte[]> response, URI uri) {
|
||||
}
|
||||
|
||||
private static String originFromUrl(String url) {
|
||||
try {
|
||||
URI uri = URI.create(url);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user