v10.1.11: Fix mensajes de error - eliminar HTML crudo que mostraba símbolos extraños

- StreamUrlResolver ya no muestra HTML crudo en mensajes de error
- Agregada validación para detectar respuestas comprimidas/binarias
- Mejorados mensajes de error para ser más claros y sin caracteres raros
- Agregados más patrones de extracción de URLs
- Eliminado Accept-Encoding para evitar respuestas comprimidas
This commit is contained in:
Renato
2026-02-15 19:08:52 -03:00
parent 98473e3b30
commit 43439e0a88

View File

@@ -14,16 +14,15 @@ import okhttp3.Response;
public final class StreamUrlResolver {
// Múltiples patrones para extraer la URL del stream
// El proveedor cambia frecuentemente el formato
private static final Pattern[] URL_PATTERNS = {
// Patrón original
Pattern.compile("var\\s+playbackURL\\s*=\\s*[\"']([^\"']+)[\"']"),
// Alternativas comunes
Pattern.compile("source\\s*:\\s*[\"']([^\"']+\\.m3u8[^\"']*)[\"']"),
Pattern.compile("src\\s*:\\s*[\"']([^\"']+\\.m3u8[^\"']*)[\"']"),
Pattern.compile("file\\s*:\\s*[\"']([^\"']+\\.m3u8[^\"']*)[\"']"),
Pattern.compile("[\"'](https?://[^\"']+\\.m3u8[^\"']*)[\"']"),
Pattern.compile("url\\s*:\\s*[\"']([^\"']+)[\"']"),
Pattern.compile("player\\s+src=\"([^\"]+)\""),
Pattern.compile("data-url=\"([^\"]+)\""),
};
private StreamUrlResolver() {
@@ -32,60 +31,84 @@ public final class StreamUrlResolver {
public static String resolve(String pageUrl) throws IOException {
String html = downloadPage(pageUrl);
// Verificar si es HTML válido o recibimos basura/compresión
if (!html.contains("<") && !html.contains(">")) {
// Probablemente respuesta comprimida o binaria
throw new IOException("El servidor devolvió una respuesta no válida. Posible bloqueo del ISP.");
}
// Intentar todos los patrones
for (Pattern pattern : URL_PATTERNS) {
Matcher matcher = pattern.matcher(html);
if (matcher.find()) {
String url = matcher.group(1);
if (url != null && !url.isEmpty() && url.startsWith("http")) {
// Limpiar la URL si tiene caracteres de escape
url = url.replace("\\", "").replace("&amp;", "&");
return url;
}
}
}
// Si no encontramos la URL, verificar si hay un mensaje de geobloqueo o similar
if (html.contains("Access Denied") || html.contains("403 Forbidden")) {
throw new IOException("Acceso bloqueado por el servidor. Posible geobloqueo o restricción de IP.");
// Verificar mensajes de error comunes en el HTML
String htmlLower = html.toLowerCase();
if (html.contains("Access Denied") || html.contains("403 Forbidden") ||
htmlLower.contains("acceso denegado") || htmlLower.contains("access denied")) {
throw new IOException("Acceso bloqueado por el servidor. El proveedor del stream puede estar restringiendo el acceso desde tu ubicación.");
}
if (html.contains("404") || html.contains("Not Found")) {
throw new IOException("Canal no encontrado (404). El canal puede estar temporalmente fuera de servicio.");
if (html.contains("404") || html.contains("Not Found") ||
htmlLower.contains("no encontrado")) {
throw new IOException("Canal no disponible (404). El canal puede estar temporalmente fuera de servicio.");
}
// Mostrar un fragmento del HTML para debug
String preview = html.length() > 800 ? html.substring(0, 800) : html;
throw new IOException("No se encontró la URL del stream. Vista previa: " + preview);
if (htmlLower.contains("maintenance") || htmlLower.contains("mantenimiento")) {
throw new IOException("El servidor está en mantenimiento. Intenta más tarde.");
}
if (htmlLower.contains("banned") || htmlLower.contains("blocked") ||
htmlLower.contains("bloqueado") || htmlLower.contains("suspendido")) {
throw new IOException("Acceso suspendido o bloqueado por el proveedor.");
}
// Error genérico sin mostrar HTML crudo (evita símbolos extraños)
throw new IOException("No se pudo obtener el stream. El proveedor puede haber cambiado el formato o el canal está offline.");
}
private static String downloadPage(String pageUrl) throws IOException {
Request request = new Request.Builder()
.url(pageUrl)
.header("User-Agent", NetworkUtils.getUserAgent())
.header("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8")
.header("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8")
.header("Accept-Language", "es-ES,es;q=0.9,en;q=0.8")
.header("Accept-Encoding", "gzip, deflate, br")
.header("Referer", "https://streamtp10.com/")
.header("Connection", "keep-alive")
.header("Upgrade-Insecure-Requests", "1")
.build();
try (Response response = NetworkUtils.getClient().newCall(request).execute()) {
if (!response.isSuccessful()) {
if (response.code() == 403) {
throw new IOException("Acceso denegado (403). El servidor puede estar bloqueando tu conexión.");
throw new IOException("Acceso denegado (403). El servidor está bloqueando la conexión.");
} else if (response.code() == 404) {
throw new IOException("Canal no encontrado (404).");
} else if (response.code() == 401) {
throw new IOException("Acceso no autorizado (401).");
} else {
throw new IOException("Error HTTP " + response.code() + " al cargar la página del stream");
throw new IOException("Error HTTP " + response.code());
}
}
if (response.body() == null) {
throw new IOException("Respuesta vacía del servidor");
}
return response.body().string();
String body = response.body().string();
// Limitar tamaño para evitar problemas de memoria
if (body.length() > 500000) {
body = body.substring(0, 500000);
}
return body;
}
}
}