diff --git a/.env b/.env index 21b9916..65c01bd 100644 --- a/.env +++ b/.env @@ -1,4 +1,4 @@ -GITEA_TOKEN=7921aa22187b39125d29399d26f527ba26a2fb5b +GITEA_TOKEN=efeed2af00597883adb04da70bd6a7c2993ae92d GEMINI_API_KEY=AIzaSyDWOgyAJqscuPU6iSpS6gxupWBm4soNw5o TELEGRAM_BOT_TOKEN=8593525164:AAGCX9B_RJGN35_F7tSB72rEZhS_4Zpcszs TELEGRAM_CHAT_ID=692714536 diff --git a/app/build.gradle b/app/build.gradle index 5442c5d..df85da8 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -8,8 +8,8 @@ android { applicationId "com.streamplayer" minSdk 21 targetSdk 35 - versionCode 100101 - versionName "10.1.1" + versionCode 100102 + versionName "10.1.2" buildConfigField "String", "DEVICE_REGISTRY_URL", '"http://194.163.191.200:4000"' } diff --git a/app/src/main/java/com/streamplayer/PlayerActivity.java b/app/src/main/java/com/streamplayer/PlayerActivity.java index 5d1480d..cfe1393 100644 --- a/app/src/main/java/com/streamplayer/PlayerActivity.java +++ b/app/src/main/java/com/streamplayer/PlayerActivity.java @@ -55,6 +55,9 @@ public class PlayerActivity extends AppCompatActivity { private String channelUrl; private boolean overlayVisible = true; private OkHttpClient okHttpClient; + private int retryCount = 0; + private static final int MAX_RETRIES = 3; + private String lastStreamUrl; @Override protected void onCreate(Bundle savedInstanceState) { @@ -102,6 +105,7 @@ public class PlayerActivity extends AppCompatActivity { private void loadChannel() { showLoading(true); + retryCount = 0; // Resetear contador al cargar nuevo canal new Thread(() -> { try { String resolvedUrl = StreamUrlResolver.resolve(channelUrl); @@ -117,14 +121,17 @@ public class PlayerActivity extends AppCompatActivity { private void startPlayback(String streamUrl) { try { releasePlayer(); + lastStreamUrl = streamUrl; // Guardar URL para reintentos + retryCount = 0; // Resetear contador al iniciar nueva reproducción DefaultRenderersFactory renderersFactory = new DefaultRenderersFactory(this) .setEnableDecoderFallback(true) .setExtensionRendererMode(DefaultRenderersFactory.EXTENSION_RENDERER_MODE_ON); - // Configurar track selector para máxima calidad + // Configurar track selector para calidad adaptativa (no forzar máxima calidad) trackSelector = new DefaultTrackSelector(this); DefaultTrackSelector.Parameters params = trackSelector.buildUponParameters() - .setForceHighestSupportedBitrate(true) // Forzar máximo bitrate + .setForceHighestSupportedBitrate(false) // Permitir calidad adaptativa + .setMaxVideoBitrate(Integer.MAX_VALUE) // Sin límite máximo de bitrate .build(); trackSelector.setParameters(params); @@ -140,6 +147,7 @@ public class PlayerActivity extends AppCompatActivity { public void onPlaybackStateChanged(int playbackState) { if (playbackState == Player.STATE_READY) { showLoading(false); + retryCount = 0; // Resetear contador de reintentos al reproducir exitosamente } else if (playbackState == Player.STATE_BUFFERING) { showLoading(true); } @@ -147,9 +155,46 @@ public class PlayerActivity extends AppCompatActivity { @Override public void onPlayerError(PlaybackException error) { - String detail = error.getCause() != null ? + String errorMsg = error.getMessage() != null ? error.getMessage() : ""; + String detail = error.getCause() != null ? error.getCause().getMessage() : ""; - showError("Error al reproducir: " + error.getMessage() + " " + detail); + String fullError = errorMsg + " " + detail; + + // Verificar si es un error que justifica reintento (404, conectividad, etc.) + boolean isRetryableError = + fullError.contains("404") || + fullError.contains("403") || + fullError.contains("timeout") || + fullError.contains("Unable to connect") || + fullError.contains("Network") || + fullError.contains("source error") || + error.errorCode == PlaybackException.ERROR_CODE_IO_NETWORK_CONNECTION_FAILED || + error.errorCode == PlaybackException.ERROR_CODE_IO_NETWORK_CONNECTION_TIMEOUT || + error.errorCode == PlaybackException.ERROR_CODE_IO_BAD_HTTP_STATUS; + + if (isRetryableError && retryCount < MAX_RETRIES) { + retryCount++; + runOnUiThread(() -> { + showLoading(true); + showError("Error de conexión. Reintentando... (" + retryCount + "/" + MAX_RETRIES + ")"); + }); + + // Reintentar después de 2 segundos + new android.os.Handler(android.os.Looper.getMainLooper()).postDelayed(() -> { + if (lastStreamUrl != null) { + startPlayback(lastStreamUrl); + } else { + loadChannel(); + } + }, 2000); + } else { + // Mostrar error final después de agotar reintentos + String finalMessage = "Error al reproducir: " + fullError; + if (retryCount >= MAX_RETRIES) { + finalMessage += "\n\nSe agotaron los reintentos (" + MAX_RETRIES + ")."; + } + showError(finalMessage); + } } }); @@ -210,8 +255,8 @@ public class PlayerActivity extends AppCompatActivity { try { OkHttpClient bootstrap = new OkHttpClient.Builder() - .connectTimeout(15, TimeUnit.SECONDS) - .readTimeout(15, TimeUnit.SECONDS) + .connectTimeout(20, TimeUnit.SECONDS) + .readTimeout(30, TimeUnit.SECONDS) .retryOnConnectionFailure(true) .build(); @@ -228,8 +273,8 @@ public class PlayerActivity extends AppCompatActivity { .build(); } catch (UnknownHostException e) { okHttpClient = new OkHttpClient.Builder() - .connectTimeout(15, TimeUnit.SECONDS) - .readTimeout(15, TimeUnit.SECONDS) + .connectTimeout(20, TimeUnit.SECONDS) + .readTimeout(30, TimeUnit.SECONDS) .retryOnConnectionFailure(true) .build(); }