fix
This commit is contained in:
parent
52f3af0758
commit
87925a57de
@ -251,28 +251,7 @@ public final class XtreamPlayerApplication {
|
|||||||
List<String> attemptErrors = new ArrayList<>();
|
List<String> attemptErrors = new ArrayList<>();
|
||||||
for (URI candidate : attempts) {
|
for (URI candidate : attempts) {
|
||||||
try {
|
try {
|
||||||
HttpRequest.Builder requestBuilder = HttpRequest.newBuilder(candidate)
|
HttpResponse<byte[]> candidateResponse = sendStreamRequest(exchange, candidate, sourceUrl);
|
||||||
.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());
|
|
||||||
if (response == null || response.statusCode() >= 400) {
|
if (response == null || response.statusCode() >= 400) {
|
||||||
response = candidateResponse;
|
response = candidateResponse;
|
||||||
usedTarget = candidate;
|
usedTarget = candidate;
|
||||||
@ -298,6 +277,17 @@ public final class XtreamPlayerApplication {
|
|||||||
}
|
}
|
||||||
String contentType = response.headers().firstValue("Content-Type").orElse("application/octet-stream");
|
String contentType = response.headers().firstValue("Content-Type").orElse("application/octet-stream");
|
||||||
byte[] body = response.body() == null ? new byte[0] : response.body();
|
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) {
|
if (response.statusCode() >= 400) {
|
||||||
LOGGER.warn(
|
LOGGER.warn(
|
||||||
"Stream proxy upstream returned status={} uri={} bytes={} contentType={}",
|
"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);
|
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) {
|
private static String originFromUrl(String url) {
|
||||||
try {
|
try {
|
||||||
URI uri = URI.create(url);
|
URI uri = URI.create(url);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user