aboutsummaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorAlex Ning <chineseperson5@gmail.com>2021-12-09 13:29:35 +0000
committerAlex Ning <chineseperson5@gmail.com>2021-12-09 13:29:35 +0000
commit1abc703d7edb51f990984ad6d897cd0e3cac8e3e (patch)
tree2fe480822f64944657c738602f2ed1d01cb23f78 /app
parent35cbd2431899221d35fc449f34c4e7e5a78e4213 (diff)
downloadinfinity-for-reddit-1abc703d7edb51f990984ad6d897cd0e3cac8e3e.tar
infinity-for-reddit-1abc703d7edb51f990984ad6d897cd0e3cac8e3e.tar.gz
infinity-for-reddit-1abc703d7edb51f990984ad6d897cd0e3cac8e3e.tar.bz2
infinity-for-reddit-1abc703d7edb51f990984ad6d897cd0e3cac8e3e.tar.lz
infinity-for-reddit-1abc703d7edb51f990984ad6d897cd0e3cac8e3e.tar.xz
infinity-for-reddit-1abc703d7edb51f990984ad6d897cd0e3cac8e3e.tar.zst
infinity-for-reddit-1abc703d7edb51f990984ad6d897cd0e3cac8e3e.zip
Support Streamable.
Diffstat (limited to 'app')
-rw-r--r--app/src/main/java/ml/docilealligator/infinityforreddit/AppModule.java10
-rw-r--r--app/src/main/java/ml/docilealligator/infinityforreddit/FetchStreamableVideo.java57
-rw-r--r--app/src/main/java/ml/docilealligator/infinityforreddit/StreamableVideo.java29
-rw-r--r--app/src/main/java/ml/docilealligator/infinityforreddit/activities/LinkResolverActivity.java15
-rw-r--r--app/src/main/java/ml/docilealligator/infinityforreddit/activities/ViewVideoActivity.java91
-rw-r--r--app/src/main/java/ml/docilealligator/infinityforreddit/apis/StreamableAPI.java10
-rw-r--r--app/src/main/java/ml/docilealligator/infinityforreddit/utils/APIUtils.java1
-rw-r--r--app/src/main/java/ml/docilealligator/infinityforreddit/utils/JSONUtils.java2
-rw-r--r--app/src/main/res/values/strings.xml1
9 files changed, 197 insertions, 19 deletions
diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/AppModule.java b/app/src/main/java/ml/docilealligator/infinityforreddit/AppModule.java
index 2b8351bb..f9cde414 100644
--- a/app/src/main/java/ml/docilealligator/infinityforreddit/AppModule.java
+++ b/app/src/main/java/ml/docilealligator/infinityforreddit/AppModule.java
@@ -168,6 +168,16 @@ class AppModule {
}
@Provides
+ @Named("streamable")
+ @Singleton
+ Retrofit provideStreamableRetrofit(@Named("default") OkHttpClient okHttpClient) {
+ return new Retrofit.Builder()
+ .baseUrl(APIUtils.STREAMABLE_API_BASE_URI)
+ .addConverterFactory(ScalarsConverterFactory.create())
+ .build();
+ }
+
+ @Provides
@Named("default")
@Singleton
OkHttpClient provideOkHttpClient(@Named("no_oauth") Retrofit retrofit, RedditDataRoomDatabase accountRoomDatabase,
diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/FetchStreamableVideo.java b/app/src/main/java/ml/docilealligator/infinityforreddit/FetchStreamableVideo.java
new file mode 100644
index 00000000..ac7c2116
--- /dev/null
+++ b/app/src/main/java/ml/docilealligator/infinityforreddit/FetchStreamableVideo.java
@@ -0,0 +1,57 @@
+package ml.docilealligator.infinityforreddit;
+
+import android.os.Handler;
+
+import androidx.annotation.Nullable;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.IOException;
+import java.util.concurrent.Executor;
+
+import ml.docilealligator.infinityforreddit.apis.StreamableAPI;
+import ml.docilealligator.infinityforreddit.utils.JSONUtils;
+import retrofit2.Response;
+import retrofit2.Retrofit;
+
+public class FetchStreamableVideo {
+ public interface FetchStreamableVideoListener {
+ void success(StreamableVideo streamableVideo);
+ void failed();
+ }
+
+ public static void fetchStreamableVideo(Executor executor, Handler handler, Retrofit streamableRetrofit,
+ String videoUrl, FetchStreamableVideoListener fetchStreamableVideoListener) {
+ executor.execute(() -> {
+ try {
+ Response<String> response = streamableRetrofit.create(StreamableAPI.class).getStreamableData(videoUrl).execute();
+ if (response.isSuccessful()) {
+ JSONObject jsonObject = new JSONObject(response.body());
+ String title = jsonObject.getString(JSONUtils.TITLE_KEY);
+ JSONObject filesObject = jsonObject.getJSONObject(JSONUtils.FILES_KEY);
+ StreamableVideo.Media mp4 = parseMedia(filesObject.getJSONObject(JSONUtils.MP4_KEY));
+ StreamableVideo.Media mp4Mobile = parseMedia(filesObject.getJSONObject(JSONUtils.MP4_MOBILE_KEY));
+ handler.post(() -> fetchStreamableVideoListener.success(new StreamableVideo(title, mp4, mp4Mobile)));
+ } else {
+ handler.post(fetchStreamableVideoListener::failed);
+ }
+ } catch (IOException | JSONException e) {
+ e.printStackTrace();
+ }
+ });
+ }
+
+ @Nullable
+ private static StreamableVideo.Media parseMedia(JSONObject jsonObject) {
+ try {
+ return new StreamableVideo.Media(
+ jsonObject.getString(JSONUtils.URL_KEY),
+ jsonObject.getInt(JSONUtils.WIDTH_KEY),
+ jsonObject.getInt(JSONUtils.HEIGHT_KEY));
+ } catch (JSONException e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+}
diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/StreamableVideo.java b/app/src/main/java/ml/docilealligator/infinityforreddit/StreamableVideo.java
new file mode 100644
index 00000000..909e890c
--- /dev/null
+++ b/app/src/main/java/ml/docilealligator/infinityforreddit/StreamableVideo.java
@@ -0,0 +1,29 @@
+package ml.docilealligator.infinityforreddit;
+
+import androidx.annotation.Nullable;
+
+public class StreamableVideo {
+ public String title;
+ @Nullable
+ public Media mp4;
+ @Nullable
+ public Media mp4Mobile;
+
+ public StreamableVideo(String title, @Nullable Media mp4, @Nullable Media mp4Mobile) {
+ this.title = title;
+ this.mp4 = mp4;
+ this.mp4Mobile = mp4Mobile;
+ }
+
+ public static class Media {
+ public String url;
+ public int width;
+ public int height;
+
+ public Media(String url, int width, int height) {
+ this.url = url;
+ this.width = width;
+ this.height = height;
+ }
+ }
+}
diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/activities/LinkResolverActivity.java b/app/src/main/java/ml/docilealligator/infinityforreddit/activities/LinkResolverActivity.java
index b16348c8..fe7c89c3 100644
--- a/app/src/main/java/ml/docilealligator/infinityforreddit/activities/LinkResolverActivity.java
+++ b/app/src/main/java/ml/docilealligator/infinityforreddit/activities/LinkResolverActivity.java
@@ -51,6 +51,7 @@ public class LinkResolverActivity extends AppCompatActivity {
private static final String RPAN_BROADCAST_PATTERN = "/rpan/r/[\\w-]+/\\w+/?\\w+/?";
private static final String WIKI_PATTERN = "/[rR]/[\\w-]+/(wiki|w)?(?:/\\w+)+";
private static final String GOOGLE_AMP_PATTERN = "/amp/s/amp.reddit.com/.*";
+ private static final String STREAMABLE_PATTERN = "/\\w+/?";
@Inject
@Named("default")
@@ -270,12 +271,22 @@ public class LinkResolverActivity extends AppCompatActivity {
deepLinkError(uri);
}
} else if (authority.contains("google.com")) {
- if ( path.matches(GOOGLE_AMP_PATTERN) ) {
- String url = path.substring(11, path.length()); // skipping past amp straight to reddit
+ if (path.matches(GOOGLE_AMP_PATTERN)) {
+ String url = path.substring(11);
handleUri(Uri.parse("https://" + url));
} else {
deepLinkError(uri);
}
+ } else if (authority.equals("streamable.com")) {
+ if (path.matches(STREAMABLE_PATTERN)) {
+ String shortCode = segments.get(0);
+ Intent intent = new Intent(this, ViewVideoActivity.class);
+ intent.putExtra(ViewVideoActivity.EXTRA_VIDEO_TYPE, ViewVideoActivity.VIDEO_TYPE_STREAMABLE);
+ intent.putExtra(ViewVideoActivity.EXTRA_STREAMABLE_SHORT_CODE, shortCode);
+ startActivity(intent);
+ } else {
+ deepLinkError(uri);
+ }
} else {
deepLinkError(uri);
}
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 8fd09be5..93c9649e 100644
--- a/app/src/main/java/ml/docilealligator/infinityforreddit/activities/ViewVideoActivity.java
+++ b/app/src/main/java/ml/docilealligator/infinityforreddit/activities/ViewVideoActivity.java
@@ -82,8 +82,10 @@ import app.futured.hauler.LockableNestedScrollView;
import butterknife.BindView;
import butterknife.ButterKnife;
import ml.docilealligator.infinityforreddit.FetchGfycatOrRedgifsVideoLinks;
+import ml.docilealligator.infinityforreddit.FetchStreamableVideo;
import ml.docilealligator.infinityforreddit.Infinity;
import ml.docilealligator.infinityforreddit.R;
+import ml.docilealligator.infinityforreddit.StreamableVideo;
import ml.docilealligator.infinityforreddit.apis.VReddIt;
import ml.docilealligator.infinityforreddit.bottomsheetfragments.PlaybackSpeedBottomSheetFragment;
import ml.docilealligator.infinityforreddit.customtheme.CustomThemeWrapper;
@@ -122,7 +124,9 @@ public class ViewVideoActivity extends AppCompatActivity {
public static final String EXTRA_VIDEO_TYPE = "EVT";
public static final String EXTRA_GFYCAT_ID = "EGI";
public static final String EXTRA_V_REDD_IT_URL = "EVRIU";
+ public static final String EXTRA_STREAMABLE_SHORT_CODE = "ESSC";
public static final String EXTRA_IS_NSFW = "EIN";
+ public static final int VIDEO_TYPE_STREAMABLE = 5;
public static final int VIDEO_TYPE_V_REDD_IT = 4;
public static final int VIDEO_TYPE_DIRECT = 3;
public static final int VIDEO_TYPE_REDGIFS = 2;
@@ -175,7 +179,6 @@ public class ViewVideoActivity extends AppCompatActivity {
private boolean wasPlaying;
private boolean isDownloading = false;
private boolean isMute = false;
- private String postTitle;
private boolean isNSFW;
private long resumePosition = -1;
private int videoType;
@@ -183,6 +186,7 @@ public class ViewVideoActivity extends AppCompatActivity {
private boolean isHd;
private Integer originalOrientation;
private int playbackSpeed = 100;
+ private boolean useBottomAppBar;
@Inject
@Named("no_oauth")
@@ -201,6 +205,10 @@ public class ViewVideoActivity extends AppCompatActivity {
Retrofit vReddItRetrofit;
@Inject
+ @Named("streamable")
+ Retrofit streamableRetrofit;
+
+ @Inject
@Named("default")
SharedPreferences mSharedPreferences;
@@ -281,7 +289,7 @@ public class ViewVideoActivity extends AppCompatActivity {
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
- boolean useBottomAppBar = mSharedPreferences.getBoolean(SharedPreferencesUtils.USE_BOTTOM_TOOLBAR_IN_MEDIA_VIEWER, false);
+ useBottomAppBar = mSharedPreferences.getBoolean(SharedPreferencesUtils.USE_BOTTOM_TOOLBAR_IN_MEDIA_VIEWER, false);
if (useBottomAppBar) {
getSupportActionBar().hide();
bottomAppBar.setVisibility(View.VISIBLE);
@@ -345,7 +353,6 @@ public class ViewVideoActivity extends AppCompatActivity {
});
Intent intent = getIntent();
- postTitle = intent.getStringExtra(EXTRA_POST_TITLE);
isNSFW = intent.getBooleanExtra(EXTRA_IS_NSFW, false);
if (savedInstanceState == null) {
resumePosition = intent.getLongExtra(EXTRA_PROGRESS_SECONDS, -1);
@@ -377,18 +384,8 @@ public class ViewVideoActivity extends AppCompatActivity {
}
}
-
- if (postTitle != null) {
- if (useBottomAppBar) {
- titleTextView.setText(Html.fromHtml(String.format("<font color=\"#FFFFFF\"><small>%s</small></font>", postTitle)));
- } else {
- setTitle(Html.fromHtml(String.format("<font color=\"#FFFFFF\"><small>%s</small></font>", postTitle)));
- }
- } else {
- if (!useBottomAppBar) {
- setTitle("");
- }
- }
+ String postTitle = intent.getStringExtra(EXTRA_POST_TITLE);
+ setSmallTitle(postTitle);
playerControlView.setVisibilityListener(visibility -> {
switch (visibility) {
@@ -476,7 +473,25 @@ public class ViewVideoActivity extends AppCompatActivity {
}
setPlaybackSpeed(Integer.parseInt(mSharedPreferences.getString(SharedPreferencesUtils.DEFAULT_PLAYBACK_SPEED, "100")));
- if (videoType == VIDEO_TYPE_V_REDD_IT) {
+ if (videoType == VIDEO_TYPE_STREAMABLE) {
+ if (savedInstanceState != null) {
+ videoDownloadUrl = savedInstanceState.getString(VIDEO_DOWNLOAD_URL_STATE);
+ } else {
+ videoDownloadUrl = intent.getStringExtra(EXTRA_VIDEO_DOWNLOAD_URL);
+ }
+
+ String shortCode = intent.getStringExtra(EXTRA_STREAMABLE_SHORT_CODE);
+ videoFileName = "Streamable-" + shortCode + ".mp4";
+ if (mVideoUri == null) {
+ loadStreamableVideo(shortCode, savedInstanceState);
+ } else {
+ dataSourceFactory = new CacheDataSourceFactory(mSimpleCache,
+ new DefaultDataSourceFactory(ViewVideoActivity.this,
+ Util.getUserAgent(ViewVideoActivity.this, "Infinity")));
+ player.prepare(new ProgressiveMediaSource.Factory(dataSourceFactory).createMediaSource(mVideoUri));
+ preparePlayer(savedInstanceState);
+ }
+ } else if (videoType == VIDEO_TYPE_V_REDD_IT) {
loadVReddItVideo(savedInstanceState);
} else if (videoType == VIDEO_TYPE_GFYCAT || videoType == VIDEO_TYPE_REDGIFS) {
if (savedInstanceState != null) {
@@ -531,6 +546,20 @@ public class ViewVideoActivity extends AppCompatActivity {
}
}
+ private void setSmallTitle(String title) {
+ if (title != null) {
+ if (useBottomAppBar) {
+ titleTextView.setText(Html.fromHtml(String.format("<font color=\"#FFFFFF\"><small>%s</small></font>", title)));
+ } else {
+ setTitle(Html.fromHtml(String.format("<font color=\"#FFFFFF\"><small>%s</small></font>", title)));
+ }
+ } else {
+ if (!useBottomAppBar) {
+ setTitle("");
+ }
+ }
+ }
+
private void preparePlayer(Bundle savedInstanceState) {
if (mSharedPreferences.getBoolean(SharedPreferencesUtils.LOOP_VIDEO, true)) {
player.setRepeatMode(Player.REPEAT_MODE_ALL);
@@ -688,7 +717,7 @@ public class ViewVideoActivity extends AppCompatActivity {
}
loadGfycatOrRedgifsVideo(redgifsRetrofit, gfycatId, savedInstanceState, false);
} else {
- progressBar.setVisibility(View.INVISIBLE);
+ progressBar.setVisibility(View.GONE);
if (post.getVideoUrl() != null) {
mVideoUri = Uri.parse(post.getVideoUrl());
subredditName = post.getSubredditName();
@@ -727,6 +756,34 @@ public class ViewVideoActivity extends AppCompatActivity {
});
}
+ private void loadStreamableVideo(String shortCode, Bundle savedInstanceState) {
+ progressBar.setVisibility(View.VISIBLE);
+ FetchStreamableVideo.fetchStreamableVideo(mExecutor, new Handler(), streamableRetrofit, shortCode,
+ new FetchStreamableVideo.FetchStreamableVideoListener() {
+ @Override
+ public void success(StreamableVideo streamableVideo) {
+ if (streamableVideo.mp4 == null && streamableVideo.mp4Mobile == null) {
+ Toast.makeText(ViewVideoActivity.this, R.string.fetch_streamable_video_failed, Toast.LENGTH_SHORT).show();
+ return;
+ }
+ setSmallTitle(streamableVideo.title);
+ progressBar.setVisibility(View.GONE);
+ videoDownloadUrl = streamableVideo.mp4 == null ? streamableVideo.mp4Mobile.url : streamableVideo.mp4.url;
+ mVideoUri = Uri.parse(videoDownloadUrl);
+ dataSourceFactory = new CacheDataSourceFactory(mSimpleCache,
+ new DefaultDataSourceFactory(ViewVideoActivity.this,
+ Util.getUserAgent(ViewVideoActivity.this, "Infinity")));
+ preparePlayer(savedInstanceState);
+ player.prepare(new ProgressiveMediaSource.Factory(dataSourceFactory).createMediaSource(mVideoUri));
+ }
+
+ @Override
+ public void failed() {
+ Toast.makeText(ViewVideoActivity.this, R.string.fetch_streamable_video_failed, Toast.LENGTH_SHORT).show();
+ }
+ });
+ }
+
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.view_video_activity, menu);
diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/apis/StreamableAPI.java b/app/src/main/java/ml/docilealligator/infinityforreddit/apis/StreamableAPI.java
new file mode 100644
index 00000000..9113c78f
--- /dev/null
+++ b/app/src/main/java/ml/docilealligator/infinityforreddit/apis/StreamableAPI.java
@@ -0,0 +1,10 @@
+package ml.docilealligator.infinityforreddit.apis;
+
+import retrofit2.Call;
+import retrofit2.http.GET;
+import retrofit2.http.Path;
+
+public interface StreamableAPI {
+ @GET("videos/{shortcode}")
+ Call<String> getStreamableData(@Path("shortcode") String shortCode);
+}
diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/utils/APIUtils.java b/app/src/main/java/ml/docilealligator/infinityforreddit/utils/APIUtils.java
index 5078692d..2303b924 100644
--- a/app/src/main/java/ml/docilealligator/infinityforreddit/utils/APIUtils.java
+++ b/app/src/main/java/ml/docilealligator/infinityforreddit/utils/APIUtils.java
@@ -23,6 +23,7 @@ public class APIUtils {
public static final String IMGUR_API_BASE_URI = "https://api.imgur.com/3/";
public static final String PUSHSHIFT_API_BASE_URI = "https://api.pushshift.io/";
public static final String STRAPI_BASE_URI = "https://strapi.reddit.com";
+ public static final String STREAMABLE_API_BASE_URI = "https://api.streamable.com";
public static final String CLIENT_ID_KEY = "client_id";
public static final String CLIENT_ID = "NOe2iKrPPzwscA";
diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/utils/JSONUtils.java b/app/src/main/java/ml/docilealligator/infinityforreddit/utils/JSONUtils.java
index 19ea43cb..42e13ce1 100644
--- a/app/src/main/java/ml/docilealligator/infinityforreddit/utils/JSONUtils.java
+++ b/app/src/main/java/ml/docilealligator/infinityforreddit/utils/JSONUtils.java
@@ -173,4 +173,6 @@ public class JSONUtils {
public static final String CONTENT_MD_KEY = "content_md";
public static final String CAPTION_KEY = "caption";
public static final String CAPTION_URL_KEY = "outbound_url";
+ public static final String FILES_KEY = "files";
+ public static final String MP4_MOBILE_KEY = "mp4-mobile";
}
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 7c5c5180..ded35ce5 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -988,6 +988,7 @@
<string name="fetch_gfycat_video_failed">Fetch Gfycat video failed</string>
<string name="fetch_redgifs_video_failed">Fetch Redgifs video failed</string>
<string name="fetching_video_info_please_wait">Fetching video info. Please wait.</string>
+ <string name="fetch_streamable_video_failed">Fetch Streamable video failed</string>
<string name="error_fetching_imgur_media">Cannot load images</string>