package com.streamplayer; import android.content.Intent; import android.os.Bundle; import android.os.StrictMode; import android.view.View; import android.widget.Button; import android.widget.ProgressBar; import android.widget.TextView; import androidx.appcompat.app.AppCompatActivity; import com.google.android.exoplayer2.ExoPlayer; import com.google.android.exoplayer2.MediaItem; import com.google.android.exoplayer2.PlaybackException; import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.DefaultRenderersFactory; import com.google.android.exoplayer2.ext.okhttp.OkHttpDataSource; import com.google.android.exoplayer2.source.MediaSource; import com.google.android.exoplayer2.source.hls.HlsMediaSource; import com.google.android.exoplayer2.ui.PlayerView; import com.google.android.exoplayer2.util.Util; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.HashMap; import java.util.Map; import java.util.concurrent.TimeUnit; import okhttp3.HttpUrl; import okhttp3.OkHttpClient; import okhttp3.dnsoverhttps.DnsOverHttps; public class PlayerActivity extends AppCompatActivity { public static final String EXTRA_CHANNEL_NAME = "extra_channel_name"; public static final String EXTRA_CHANNEL_URL = "extra_channel_url"; private PlayerView playerView; private ProgressBar loadingIndicator; private TextView errorMessage; private TextView channelLabel; private Button closeButton; private View playerToolbar; private ExoPlayer player; private String channelName; private String channelUrl; private boolean overlayVisible = true; private OkHttpClient okHttpClient; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); StrictMode.setThreadPolicy( new StrictMode.ThreadPolicy.Builder().permitAll().build() ); setContentView(R.layout.activity_player); Intent intent = getIntent(); if (intent == null) { finish(); return; } channelName = intent.getStringExtra(EXTRA_CHANNEL_NAME); channelUrl = intent.getStringExtra(EXTRA_CHANNEL_URL); if (channelName == null || channelUrl == null) { finish(); return; } initViews(); channelLabel.setText(channelName); DNSSetter.configureDNSToGoogle(this); loadChannel(); } private void initViews() { playerView = findViewById(R.id.player_view); loadingIndicator = findViewById(R.id.loading_indicator); errorMessage = findViewById(R.id.error_message); channelLabel = findViewById(R.id.player_channel_label); closeButton = findViewById(R.id.close_button); playerToolbar = findViewById(R.id.player_toolbar); closeButton.setOnClickListener(v -> finish()); playerView.setOnClickListener(v -> toggleOverlay()); } private void loadChannel() { showLoading(true); new Thread(() -> { try { String resolvedUrl = StreamUrlResolver.resolve(channelUrl); runOnUiThread(() -> startPlayback(resolvedUrl)); } catch (Exception e) { runOnUiThread(() -> showError("Error al obtener stream: " + e.getMessage())); } }).start(); } private void startPlayback(String streamUrl) { try { releasePlayer(); DefaultRenderersFactory renderersFactory = new DefaultRenderersFactory(this) .setEnableDecoderFallback(true) .setExtensionRendererMode(DefaultRenderersFactory.EXTENSION_RENDERER_MODE_ON); player = new ExoPlayer.Builder(this, renderersFactory) .setSeekForwardIncrementMs(10_000) .setSeekBackIncrementMs(10_000) .build(); playerView.setPlayer(player); player.addListener(new Player.Listener() { @Override public void onPlaybackStateChanged(int playbackState) { if (playbackState == Player.STATE_READY) { showLoading(false); } else if (playbackState == Player.STATE_BUFFERING) { showLoading(true); } } @Override public void onPlayerError(PlaybackException error) { String detail = error.getCause() != null ? error.getCause().getMessage() : ""; showError("Error al reproducir: " + error.getMessage() + " " + detail); } }); MediaItem mediaItem = MediaItem.fromUri(streamUrl); player.setMediaSource(buildMediaSource(mediaItem)); player.prepare(); player.setPlayWhenReady(true); setOverlayVisible(false); } catch (Exception e) { showError("Error al inicializar reproductor: " + e.getMessage()); } } private void showLoading(boolean show) { loadingIndicator.setVisibility(show ? View.VISIBLE : View.GONE); errorMessage.setVisibility(View.GONE); playerView.setVisibility(show ? View.GONE : View.VISIBLE); if (show) { setOverlayVisible(true); } } private void showError(String message) { loadingIndicator.setVisibility(View.GONE); playerView.setVisibility(View.GONE); errorMessage.setVisibility(View.VISIBLE); errorMessage.setText(message); setOverlayVisible(true); } private void releasePlayer() { if (player != null) { player.release(); player = null; } } private MediaSource buildMediaSource(MediaItem mediaItem) { Map headers = new HashMap<>(); headers.put("Referer", channelUrl); headers.put("Origin", "https://streamtpmedia.com"); headers.put("Accept", "*/*"); headers.put("Connection", "keep-alive"); String userAgent = Util.getUserAgent(this, "StreamPlayer"); OkHttpDataSource.Factory factory = new OkHttpDataSource.Factory(provideOkHttpClient()) .setUserAgent(userAgent) .setDefaultRequestProperties(headers); return new HlsMediaSource.Factory(factory).createMediaSource(mediaItem); } private OkHttpClient provideOkHttpClient() { if (okHttpClient != null) { return okHttpClient; } try { OkHttpClient bootstrap = new OkHttpClient.Builder() .connectTimeout(15, TimeUnit.SECONDS) .readTimeout(15, TimeUnit.SECONDS) .retryOnConnectionFailure(true) .build(); DnsOverHttps dohDns = new DnsOverHttps.Builder() .client(bootstrap) .url(HttpUrl.get("https://dns.adguard-dns.com/dns-query")) .bootstrapDnsHosts( InetAddress.getByName("94.140.14.14"), InetAddress.getByName("94.140.15.15")) .build(); okHttpClient = bootstrap.newBuilder() .dns(dohDns) .build(); } catch (UnknownHostException e) { okHttpClient = new OkHttpClient.Builder() .connectTimeout(15, TimeUnit.SECONDS) .readTimeout(15, TimeUnit.SECONDS) .retryOnConnectionFailure(true) .build(); } return okHttpClient; } @Override protected void onStart() { super.onStart(); if (player != null) { playerView.onResume(); } } @Override protected void onResume() { super.onResume(); if (player != null) { playerView.onResume(); } } @Override protected void onPause() { super.onPause(); if (player != null) { playerView.onPause(); } } @Override protected void onStop() { super.onStop(); if (player != null) { playerView.onPause(); } } @Override protected void onDestroy() { super.onDestroy(); releasePlayer(); } private void toggleOverlay() { setOverlayVisible(!overlayVisible); } private void setOverlayVisible(boolean visible) { overlayVisible = visible; playerToolbar.setVisibility(visible ? View.VISIBLE : View.GONE); } @Override public void onBackPressed() { if (!overlayVisible) { setOverlayVisible(true); } else { super.onBackPressed(); } } }