diff --git a/app/build.gradle b/app/build.gradle index b84720ed..0d66e752 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -92,6 +92,7 @@ dependencies { implementation "androidx.media3:media3-exoplayer-hls:$media3_version" implementation "androidx.media3:media3-ui:$media3_version" implementation "androidx.media3:media3-exoplayer-smoothstreaming:$media3_version" + implementation "androidx.media3:media3-datasource-okhttp:$media3_version" /** Third-party **/ diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/AppModule.java b/app/src/main/java/ml/docilealligator/infinityforreddit/AppModule.java index ca3aefd8..0fd0f3d2 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/AppModule.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/AppModule.java @@ -9,6 +9,7 @@ import androidx.media3.common.util.UnstableApi; import androidx.media3.database.StandaloneDatabaseProvider; import androidx.media3.datasource.cache.LeastRecentlyUsedCacheEvictor; import androidx.media3.datasource.cache.SimpleCache; +import androidx.media3.datasource.okhttp.OkHttpDataSource; import androidx.preference.PreferenceManager; import java.io.File; @@ -23,12 +24,14 @@ import dagger.Module; import dagger.Provides; import ml.docilealligator.infinityforreddit.customtheme.CustomThemeWrapper; import ml.docilealligator.infinityforreddit.customviews.LoopAvailableExoCreator; +import ml.docilealligator.infinityforreddit.utils.APIUtils; import ml.docilealligator.infinityforreddit.utils.CustomThemeSharedPreferencesUtils; import ml.docilealligator.infinityforreddit.utils.SharedPreferencesUtils; import ml.docilealligator.infinityforreddit.videoautoplay.Config; import ml.docilealligator.infinityforreddit.videoautoplay.ExoCreator; import ml.docilealligator.infinityforreddit.videoautoplay.MediaSourceBuilder; import ml.docilealligator.infinityforreddit.videoautoplay.ToroExo; +import okhttp3.OkHttpClient; @Module abstract class AppModule { @@ -188,13 +191,15 @@ abstract class AppModule { @OptIn(markerClass = UnstableApi.class) @Provides - static Config providesMediaConfig(Application application, SimpleCache simpleCache) { + static Config providesMediaConfig(Application application, SimpleCache simpleCache, @Named("media3")OkHttpClient okHttpClient) { return new Config.Builder(application) + .setDataSourceFactory(new OkHttpDataSource.Factory(okHttpClient).setUserAgent(APIUtils.USER_AGENT)) .setMediaSourceBuilder(MediaSourceBuilder.DEFAULT) .setCache(simpleCache) .build(); } + @OptIn(markerClass = UnstableApi.class) @Provides static ToroExo providesToroExo(Application application) { return ToroExo.with(application); diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/NetworkModule.java b/app/src/main/java/ml/docilealligator/infinityforreddit/NetworkModule.java index 5d440010..ffcb9856 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/NetworkModule.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/NetworkModule.java @@ -2,6 +2,9 @@ package ml.docilealligator.infinityforreddit; import android.content.SharedPreferences; +import androidx.annotation.NonNull; + +import java.io.IOException; import java.net.InetSocketAddress; import java.net.Proxy; import java.util.concurrent.TimeUnit; @@ -19,8 +22,11 @@ import ml.docilealligator.infinityforreddit.network.SortTypeConverterFactory; import ml.docilealligator.infinityforreddit.utils.APIUtils; import ml.docilealligator.infinityforreddit.utils.SharedPreferencesUtils; import okhttp3.ConnectionPool; +import okhttp3.HttpUrl; import okhttp3.Interceptor; import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; import retrofit2.Retrofit; import retrofit2.adapter.guava.GuavaCallAdapterFactory; import retrofit2.converter.scalars.ScalarsConverterFactory; @@ -113,6 +119,48 @@ abstract class NetworkModule { .build(); } + @Provides + @Named("media3") + @Singleton + static OkHttpClient provideMedia3OkHttpClient(@Named("base") OkHttpClient httpClient, + ConnectionPool connectionPool) { + return httpClient.newBuilder() + .connectionPool(connectionPool) + .followRedirects(false) + .addInterceptor(new Interceptor() { + @NonNull + @Override + public Response intercept(@NonNull Chain chain) throws IOException { + Request request = chain.request(); + Response response = chain.proceed(request); + + int redirectCount = 0; + while (isRedirect(response.code()) && redirectCount < 5) { + String location = response.header("Location"); + if (location == null) break; + + HttpUrl newUrl = response.request().url().resolve(location); + if (newUrl == null) break; + + request = request.newBuilder() + .url(newUrl) + .build(); + + response.close(); // Close the previous response before continuing + response = chain.proceed(request); + redirectCount++; + } + + return response; + } + + private boolean isRedirect(int code) { + return code == 301 || code == 302 || code == 303 || code == 307 || code == 308; + } + }) + .build(); + } + @Provides @Named("oauth_without_authenticator") @Singleton diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/activities/ViewVideoActivity.java b/app/src/main/java/ml/docilealligator/infinityforreddit/activities/ViewVideoActivity.java index cc658f0f..10c8717e 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/activities/ViewVideoActivity.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/activities/ViewVideoActivity.java @@ -63,9 +63,9 @@ import androidx.media3.common.VideoSize; import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.Util; import androidx.media3.datasource.DataSource; -import androidx.media3.datasource.DefaultHttpDataSource; import androidx.media3.datasource.cache.CacheDataSource; import androidx.media3.datasource.cache.SimpleCache; +import androidx.media3.datasource.okhttp.OkHttpDataSource; import androidx.media3.exoplayer.DefaultRenderersFactory; import androidx.media3.exoplayer.ExoPlayer; import androidx.media3.exoplayer.hls.HlsMediaSource; @@ -112,6 +112,7 @@ import ml.docilealligator.infinityforreddit.thing.StreamableVideo; import ml.docilealligator.infinityforreddit.utils.APIUtils; import ml.docilealligator.infinityforreddit.utils.SharedPreferencesUtils; import ml.docilealligator.infinityforreddit.utils.Utils; +import okhttp3.OkHttpClient; import retrofit2.Retrofit; public class ViewVideoActivity extends AppCompatActivity implements CustomFontReceiver { @@ -179,6 +180,10 @@ public class ViewVideoActivity extends AppCompatActivity implements CustomFontRe private boolean useBottomAppBar; private ViewVideoActivityBindingAdapter binding; + @Inject + @Named("media3") + OkHttpClient mOkHttpClient; + @Inject @Named("no_oauth") Retrofit mRetrofit; @@ -654,7 +659,7 @@ public class ViewVideoActivity extends AppCompatActivity implements CustomFontRe // Produces DataSource instances through which media data is loaded. dataSourceFactory = new CacheDataSource.Factory().setCache(mSimpleCache) - .setUpstreamDataSourceFactory(new DefaultHttpDataSource.Factory().setAllowCrossProtocolRedirects(true).setUserAgent(APIUtils.USER_AGENT)); + .setUpstreamDataSourceFactory(new OkHttpDataSource.Factory(mOkHttpClient).setUserAgent(APIUtils.USER_AGENT)); String redgifsId = null; if (videoType == VIDEO_TYPE_STREAMABLE) { if (savedInstanceState != null) { diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/fragments/ViewImgurVideoFragment.java b/app/src/main/java/ml/docilealligator/infinityforreddit/fragments/ViewImgurVideoFragment.java index 0d0c7212..46af7563 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/fragments/ViewImgurVideoFragment.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/fragments/ViewImgurVideoFragment.java @@ -32,9 +32,9 @@ import androidx.media3.common.Tracks; import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.Util; import androidx.media3.datasource.DataSource; -import androidx.media3.datasource.DefaultHttpDataSource; import androidx.media3.datasource.cache.CacheDataSource; import androidx.media3.datasource.cache.SimpleCache; +import androidx.media3.datasource.okhttp.OkHttpDataSource; import androidx.media3.exoplayer.DefaultRenderersFactory; import androidx.media3.exoplayer.ExoPlayer; import androidx.media3.exoplayer.source.ProgressiveMediaSource; @@ -58,6 +58,7 @@ import ml.docilealligator.infinityforreddit.services.DownloadMediaService; import ml.docilealligator.infinityforreddit.utils.APIUtils; import ml.docilealligator.infinityforreddit.utils.SharedPreferencesUtils; import ml.docilealligator.infinityforreddit.utils.Utils; +import okhttp3.OkHttpClient; public class ViewImgurVideoFragment extends Fragment { @@ -78,6 +79,9 @@ public class ViewImgurVideoFragment extends Fragment { private boolean isDownloading = false; private int playbackSpeed = 100; @Inject + @Named("media3") + OkHttpClient mOkHttpClient; + @Inject @Named("default") SharedPreferences mSharedPreferences; @UnstableApi @@ -153,7 +157,7 @@ public class ViewImgurVideoFragment extends Fragment { .build(); binding.getRoot().setPlayer(player); dataSourceFactory = new CacheDataSource.Factory().setCache(mSimpleCache) - .setUpstreamDataSourceFactory(new DefaultHttpDataSource.Factory().setAllowCrossProtocolRedirects(true).setUserAgent(APIUtils.USER_AGENT)); + .setUpstreamDataSourceFactory(new OkHttpDataSource.Factory(mOkHttpClient).setUserAgent(APIUtils.USER_AGENT)); player.prepare(); player.setMediaSource(new ProgressiveMediaSource.Factory(dataSourceFactory).createMediaSource(MediaItem.fromUri(imgurMedia.getLink()))); diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/fragments/ViewRedditGalleryVideoFragment.java b/app/src/main/java/ml/docilealligator/infinityforreddit/fragments/ViewRedditGalleryVideoFragment.java index a272e1ef..8b9c08a8 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/fragments/ViewRedditGalleryVideoFragment.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/fragments/ViewRedditGalleryVideoFragment.java @@ -33,9 +33,9 @@ import androidx.media3.common.Tracks; import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.Util; import androidx.media3.datasource.DataSource; -import androidx.media3.datasource.DefaultHttpDataSource; import androidx.media3.datasource.cache.CacheDataSource; import androidx.media3.datasource.cache.SimpleCache; +import androidx.media3.datasource.okhttp.OkHttpDataSource; import androidx.media3.exoplayer.DefaultRenderersFactory; import androidx.media3.exoplayer.ExoPlayer; import androidx.media3.exoplayer.source.ProgressiveMediaSource; @@ -58,6 +58,7 @@ import ml.docilealligator.infinityforreddit.services.DownloadMediaService; import ml.docilealligator.infinityforreddit.utils.APIUtils; import ml.docilealligator.infinityforreddit.utils.SharedPreferencesUtils; import ml.docilealligator.infinityforreddit.utils.Utils; +import okhttp3.OkHttpClient; public class ViewRedditGalleryVideoFragment extends Fragment { @@ -82,6 +83,9 @@ public class ViewRedditGalleryVideoFragment extends Fragment { private boolean isDownloading = false; private int playbackSpeed = 100; @Inject + @Named("media3") + OkHttpClient mOkHttpClient; + @Inject @Named("default") SharedPreferences mSharedPreferences; @UnstableApi @@ -156,7 +160,7 @@ public class ViewRedditGalleryVideoFragment extends Fragment { .build(); binding.getPlayerView().setPlayer(player); dataSourceFactory = new CacheDataSource.Factory().setCache(mSimpleCache) - .setUpstreamDataSourceFactory(new DefaultHttpDataSource.Factory().setAllowCrossProtocolRedirects(true).setUserAgent(APIUtils.USER_AGENT)); + .setUpstreamDataSourceFactory(new OkHttpDataSource.Factory(mOkHttpClient).setUserAgent(APIUtils.USER_AGENT)); player.prepare(); player.setMediaSource(new ProgressiveMediaSource.Factory(dataSourceFactory).createMediaSource(MediaItem.fromUri(galleryVideo.url)));