From c15f117810eb2be5b93fcd06b3d018060520e00a Mon Sep 17 00:00:00 2001 From: Docile-Alligator <25734209+Docile-Alligator@users.noreply.github.com> Date: Mon, 16 Sep 2024 23:40:24 -0400 Subject: Add an option to download media in PostOptionsBottomSheetFragment. --- .../infinityforreddit/VideoLinkFetcher.java | 20 +++++- .../activities/ViewVideoActivity.java | 39 +++++----- .../PostOptionsBottomSheetFragment.java | 41 ++++++++++- .../infinityforreddit/post/FetchPost.java | 25 +++++++ .../post/FetchStreamableVideo.java | 30 ++++++++ .../infinityforreddit/post/ImgurMedia.java | 4 +- .../infinityforreddit/post/ParsePost.java | 22 +++++- .../services/DownloadMediaService.java | 82 ++++++++++++++++++---- .../thing/FetchRedgifsVideoLinks.java | 45 +++++++++++- .../layout/fragment_post_options_bottom_sheet.xml | 21 ++++++ app/src/main/res/values/strings.xml | 7 ++ 11 files changed, 293 insertions(+), 43 deletions(-) diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/VideoLinkFetcher.java b/app/src/main/java/ml/docilealligator/infinityforreddit/VideoLinkFetcher.java index 19d7e04b..54d072a5 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/VideoLinkFetcher.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/VideoLinkFetcher.java @@ -7,6 +7,7 @@ import android.os.Handler; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.OptIn; +import androidx.annotation.WorkerThread; import androidx.media3.common.util.UnstableApi; import org.apache.commons.io.FilenameUtils; @@ -24,6 +25,7 @@ import ml.docilealligator.infinityforreddit.post.FetchPost; import ml.docilealligator.infinityforreddit.post.FetchStreamableVideo; import ml.docilealligator.infinityforreddit.post.Post; import ml.docilealligator.infinityforreddit.thing.FetchRedgifsVideoLinks; +import ml.docilealligator.infinityforreddit.thing.StreamableVideo; import retrofit2.Call; import retrofit2.Callback; import retrofit2.Response; @@ -51,6 +53,22 @@ public class VideoLinkFetcher { } } + @WorkerThread + @Nullable + public static String fetchVideoLinkSync(Retrofit redgifsRetrofit, Provider streamableApiProvider, + SharedPreferences currentAccountSharedPreferences, int videoType, + @Nullable String redgifsId, @Nullable String shortCode) { + if (videoType == ViewVideoActivity.VIDEO_TYPE_STREAMABLE) { + StreamableVideo streamableVideo = FetchStreamableVideo.fetchStreamableVideoSync(streamableApiProvider, shortCode); + return streamableVideo == null ? null : (streamableVideo.mp4 == null ? null : streamableVideo.mp4.url); + } else if (videoType == ViewVideoActivity.VIDEO_TYPE_REDGIFS) { + return FetchRedgifsVideoLinks.fetchRedgifsVideoLinkSync(redgifsRetrofit, + currentAccountSharedPreferences, redgifsId); + } + + return null; + } + public static void loadVReddItVideo(Executor executor, Handler handler, Retrofit retrofit, Retrofit mVReddItRetrofit, Retrofit redgifsRetrofit, Provider streamableApiProvider, SharedPreferences currentAccountSharedPreferences, @@ -87,7 +105,7 @@ public class VideoLinkFetcher { FetchStreamableVideo.fetchStreamableVideo(executor, handler, streamableApiProvider, shortCode, fetchVideoLinkListener); } else if (post.isImgur()) { String videoDownloadUrl = post.getVideoDownloadUrl(); - String videoFileName = "imgur-" + FilenameUtils.getName(videoDownloadUrl); + String videoFileName = "Imgur-" + FilenameUtils.getName(videoDownloadUrl); fetchVideoLinkListener.onFetchImgurVideoLinkSuccess(post.getVideoUrl(), post.getVideoDownloadUrl(), videoFileName); } else { if (post.getVideoUrl() != null) { 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 e878196e..afb4a70d 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/activities/ViewVideoActivity.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/activities/ViewVideoActivity.java @@ -475,25 +475,22 @@ public class ViewVideoActivity extends AppCompatActivity implements CustomFontRe } else { PlayerView videoPlayerView = findViewById(R.id.player_view_view_video_activity); videoPlayerView.setPlayer(player); - videoPlayerView.setControllerVisibilityListener(new PlayerView.ControllerVisibilityListener() { - @Override - public void onVisibilityChanged(int visibility) { - switch (visibility) { - case View.GONE: - getWindow().getDecorView().setSystemUiVisibility( - View.SYSTEM_UI_FLAG_LAYOUT_STABLE - | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION - | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN - | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION - | View.SYSTEM_UI_FLAG_FULLSCREEN - | View.SYSTEM_UI_FLAG_IMMERSIVE); - break; - case View.VISIBLE: - getWindow().getDecorView().setSystemUiVisibility( - View.SYSTEM_UI_FLAG_LAYOUT_STABLE - | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION - | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN); - } + videoPlayerView.setControllerVisibilityListener((PlayerView.ControllerVisibilityListener) visibility -> { + switch (visibility) { + case View.GONE: + getWindow().getDecorView().setSystemUiVisibility( + View.SYSTEM_UI_FLAG_LAYOUT_STABLE + | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN + | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_FULLSCREEN + | View.SYSTEM_UI_FLAG_IMMERSIVE); + break; + case View.VISIBLE: + getWindow().getDecorView().setSystemUiVisibility( + View.SYSTEM_UI_FLAG_LAYOUT_STABLE + | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN); } }); } @@ -622,7 +619,7 @@ public class ViewVideoActivity extends AppCompatActivity implements CustomFontRe if (videoType == VIDEO_TYPE_DIRECT) { videoFileName = FilenameUtils.getName(videoDownloadUrl); } else { - videoFileName = "imgur-" + FilenameUtils.getName(videoDownloadUrl); + videoFileName = "Imgur-" + FilenameUtils.getName(videoDownloadUrl); } } else { videoDownloadUrl = intent.getStringExtra(EXTRA_VIDEO_DOWNLOAD_URL); @@ -665,7 +662,7 @@ public class ViewVideoActivity extends AppCompatActivity implements CustomFontRe binding.getProgressBar().setVisibility(View.GONE); mVideoUri = Uri.parse(videoUrl); ViewVideoActivity.this.videoDownloadUrl = videoDownloadUrl; - videoFileName = "imgur-" + FilenameUtils.getName(videoDownloadUrl); + videoFileName = "Imgur-" + FilenameUtils.getName(videoDownloadUrl); // Prepare the player with the source. player.prepare(); player.setMediaSource(new ProgressiveMediaSource.Factory(dataSourceFactory).createMediaSource(MediaItem.fromUri(mVideoUri))); diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/bottomsheetfragments/PostOptionsBottomSheetFragment.java b/app/src/main/java/ml/docilealligator/infinityforreddit/bottomsheetfragments/PostOptionsBottomSheetFragment.java index de834388..d10e0d5d 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/bottomsheetfragments/PostOptionsBottomSheetFragment.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/bottomsheetfragments/PostOptionsBottomSheetFragment.java @@ -1,8 +1,11 @@ package ml.docilealligator.infinityforreddit.bottomsheetfragments; +import android.app.job.JobInfo; +import android.app.job.JobScheduler; import android.content.Context; import android.content.Intent; import android.os.Bundle; +import android.os.PersistableBundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -24,6 +27,8 @@ import ml.docilealligator.infinityforreddit.activities.SubmitCrosspostActivity; import ml.docilealligator.infinityforreddit.customviews.LandscapeExpandedRoundedBottomSheetDialogFragment; import ml.docilealligator.infinityforreddit.databinding.FragmentPostOptionsBottomSheetBinding; import ml.docilealligator.infinityforreddit.post.Post; +import ml.docilealligator.infinityforreddit.services.DownloadMediaService; +import ml.docilealligator.infinityforreddit.services.DownloadRedditVideoService; /** * A simple {@link Fragment} subclass. @@ -33,6 +38,7 @@ import ml.docilealligator.infinityforreddit.post.Post; public class PostOptionsBottomSheetFragment extends LandscapeExpandedRoundedBottomSheetDialogFragment { private static final String EXTRA_POST = "EP"; + private static final String EXTRA_GALLERY_INDEX = "EGI"; private BaseActivity mBaseActivity; private Post mPost; @@ -76,13 +82,44 @@ public class PostOptionsBottomSheetFragment extends LandscapeExpandedRoundedBott if (mPost != null) { switch (mPost.getPostType()) { case Post.IMAGE_TYPE: + case Post.GALLERY_TYPE: + binding.downloadTextViewPostOptionsBottomSheetFragment.setVisibility(View.VISIBLE); + binding.downloadTextViewPostOptionsBottomSheetFragment.setText(R.string.download_image); break; case Post.GIF_TYPE: + binding.downloadTextViewPostOptionsBottomSheetFragment.setVisibility(View.VISIBLE); + binding.downloadTextViewPostOptionsBottomSheetFragment.setText(R.string.download_gif); break; case Post.VIDEO_TYPE: + binding.downloadTextViewPostOptionsBottomSheetFragment.setVisibility(View.VISIBLE); + binding.downloadTextViewPostOptionsBottomSheetFragment.setText(R.string.download_video); break; - case Post.GALLERY_TYPE: - break; + } + + if (binding.downloadTextViewPostOptionsBottomSheetFragment.getVisibility() == View.VISIBLE) { + binding.downloadTextViewPostOptionsBottomSheetFragment.setOnClickListener(view -> { + if (mPost.getPostType() == Post.VIDEO_TYPE) { + if (!mPost.isRedgifs() && !mPost.isStreamable() && !mPost.isImgur()) { + PersistableBundle extras = new PersistableBundle(); + extras.putString(DownloadRedditVideoService.EXTRA_VIDEO_URL, mPost.getVideoDownloadUrl()); + extras.putString(DownloadRedditVideoService.EXTRA_POST_ID, mPost.getId()); + extras.putString(DownloadRedditVideoService.EXTRA_SUBREDDIT, mPost.getSubredditName()); + extras.putInt(DownloadRedditVideoService.EXTRA_IS_NSFW, mPost.isNSFW() ? 1 : 0); + + //TODO: contentEstimatedBytes + JobInfo jobInfo = DownloadRedditVideoService.constructJobInfo(mBaseActivity, 5000000, extras); + ((JobScheduler) mBaseActivity.getSystemService(Context.JOB_SCHEDULER_SERVICE)).schedule(jobInfo); + + dismiss(); + return; + } + } + + JobInfo jobInfo = DownloadMediaService.constructJobInfo(mBaseActivity, 5000000, mPost, getArguments().getInt(EXTRA_GALLERY_INDEX, 0)); + ((JobScheduler) mBaseActivity.getSystemService(Context.JOB_SCHEDULER_SERVICE)).schedule(jobInfo); + + dismiss(); + }); } binding.addToPostFilterTextViewPostOptionsBottomSheetFragment.setOnClickListener(view -> { diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/post/FetchPost.java b/app/src/main/java/ml/docilealligator/infinityforreddit/post/FetchPost.java index 57895e17..6dbaf519 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/post/FetchPost.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/post/FetchPost.java @@ -4,7 +4,9 @@ import android.os.Handler; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.annotation.WorkerThread; +import java.io.IOException; import java.util.concurrent.Executor; import ml.docilealligator.infinityforreddit.account.Account; @@ -52,6 +54,29 @@ public class FetchPost { }); } + @WorkerThread + @Nullable + public static Post fetchPostSync(Retrofit retrofit, String id, @Nullable String accessToken, + @NonNull String accountName) { + Call postCall; + if (accountName.equals(Account.ANONYMOUS_ACCOUNT)) { + postCall = retrofit.create(RedditAPI.class).getPost(id); + } else { + postCall = retrofit.create(RedditAPI.class).getPostOauth(id, APIUtils.getOAuthHeader(accessToken)); + } + try { + Response response = postCall.execute(); + if (response.isSuccessful()) { + return ParsePost.parsePostSync(response.body()); + } else { + return null; + } + + } catch (IOException e) { + return null; + } + } + public static void fetchRandomPost(Executor executor, Handler handler, Retrofit retrofit, boolean isNSFW, FetchRandomPostListener fetchRandomPostListener) { Call call; diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/post/FetchStreamableVideo.java b/app/src/main/java/ml/docilealligator/infinityforreddit/post/FetchStreamableVideo.java index 747c7161..9e372d1b 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/post/FetchStreamableVideo.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/post/FetchStreamableVideo.java @@ -3,6 +3,7 @@ package ml.docilealligator.infinityforreddit.post; import android.os.Handler; import androidx.annotation.Nullable; +import androidx.annotation.WorkerThread; import org.json.JSONException; import org.json.JSONObject; @@ -50,6 +51,35 @@ public class FetchStreamableVideo { }); } + @WorkerThread + @Nullable + public static StreamableVideo fetchStreamableVideoSync(Provider streamableApiProvider, + String videoUrl) { + try { + Response response = streamableApiProvider.get().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 mp4MobileTemp = null; + if (filesObject.has(JSONUtils.MP4_MOBILE_KEY)) { + mp4MobileTemp = parseMedia(filesObject.getJSONObject(JSONUtils.MP4_MOBILE_KEY)); + } + if (mp4 == null && mp4MobileTemp == null) { + return null; + } + StreamableVideo.Media mp4Mobile = mp4MobileTemp; + return new StreamableVideo(title, mp4, mp4Mobile); + } else { + return null; + } + } catch (IOException | JSONException e) { + e.printStackTrace(); + return null; + } + } + public static void fetchStreamableVideoInRecyclerViewAdapter(Executor executor, Handler handler, Call streamableCall, FetchVideoLinkListener fetchVideoLinkListener) { executor.execute(() -> { diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/post/ImgurMedia.java b/app/src/main/java/ml/docilealligator/infinityforreddit/post/ImgurMedia.java index a9a09a50..e78838f1 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/post/ImgurMedia.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/post/ImgurMedia.java @@ -64,10 +64,10 @@ public class ImgurMedia implements Parcelable { public String getFileName() { if (type == TYPE_VIDEO) { - return "imgur-" + id + ".mp4"; + return "Imgur-" + id + ".mp4"; } - return "imgur-" + id + ".jpg"; + return "Imgur-" + id + ".jpg"; } @Override diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/post/ParsePost.java b/app/src/main/java/ml/docilealligator/infinityforreddit/post/ParsePost.java index e7dc35ed..6092d9e1 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/post/ParsePost.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/post/ParsePost.java @@ -5,6 +5,9 @@ import android.os.Handler; import android.text.Html; import android.text.TextUtils; +import androidx.annotation.Nullable; +import androidx.annotation.WorkerThread; + import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; @@ -82,9 +85,6 @@ public class ParsePost { public static void parsePost(Executor executor, Handler handler, String response, ParsePostListener parsePostListener) { - PostFilter postFilter = new PostFilter(); - postFilter.allowNSFW = true; - executor.execute(() -> { try { JSONArray allData = new JSONArray(response).getJSONObject(0).getJSONObject(JSONUtils.DATA_KEY).getJSONArray(JSONUtils.CHILDREN_KEY); @@ -102,6 +102,22 @@ public class ParsePost { }); } + @WorkerThread + @Nullable + public static Post parsePostSync(String response) { + try { + JSONArray allData = new JSONArray(response).getJSONObject(0).getJSONObject(JSONUtils.DATA_KEY).getJSONArray(JSONUtils.CHILDREN_KEY); + if (allData.length() == 0) { + return null; + } + JSONObject data = allData.getJSONObject(0).getJSONObject(JSONUtils.DATA_KEY); + return parseBasicData(data); + } catch (JSONException e) { + e.printStackTrace(); + return null; + } + } + public static void parseRandomPost(Executor executor, Handler handler, String response, boolean isNSFW, ParseRandomPostListener parseRandomPostListener) { executor.execute(() -> { diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/services/DownloadMediaService.java b/app/src/main/java/ml/docilealligator/infinityforreddit/services/DownloadMediaService.java index 331026c3..60194716 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/services/DownloadMediaService.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/services/DownloadMediaService.java @@ -26,22 +26,27 @@ import androidx.core.app.NotificationCompat; import androidx.core.app.NotificationManagerCompat; import androidx.documentfile.provider.DocumentFile; +import org.apache.commons.io.FilenameUtils; + import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.util.List; import java.util.Random; import java.util.concurrent.Executor; import javax.inject.Inject; import javax.inject.Named; +import javax.inject.Provider; import ml.docilealligator.infinityforreddit.DownloadProgressResponseBody; import ml.docilealligator.infinityforreddit.Infinity; import ml.docilealligator.infinityforreddit.R; +import ml.docilealligator.infinityforreddit.VideoLinkFetcher; +import ml.docilealligator.infinityforreddit.activities.ViewVideoActivity; import ml.docilealligator.infinityforreddit.apis.DownloadFile; +import ml.docilealligator.infinityforreddit.apis.StreamableAPI; import ml.docilealligator.infinityforreddit.broadcastreceivers.DownloadedMediaDeleteActionBroadcastReceiver; import ml.docilealligator.infinityforreddit.customtheme.CustomThemeWrapper; import ml.docilealligator.infinityforreddit.post.ImgurMedia; @@ -60,6 +65,8 @@ public class DownloadMediaService extends JobService { public static final String EXTRA_SUBREDDIT_NAME = "ESN"; public static final String EXTRA_MEDIA_TYPE = "EIG"; public static final String EXTRA_IS_NSFW = "EIN"; + public static final String EXTRA_REDGIFS_ID = "EGI"; + public static final String EXTRA_STREAMABLE_SHORT_CODE = "ESSC"; public static final int EXTRA_MEDIA_TYPE_IMAGE = 0; public static final int EXTRA_MEDIA_TYPE_GIF = 1; public static final int EXTRA_MEDIA_TYPE_VIDEO = 2; @@ -68,6 +75,8 @@ public class DownloadMediaService extends JobService { private static final int ERROR_CANNOT_GET_DESTINATION_DIRECTORY = 0; private static final int ERROR_FILE_CANNOT_DOWNLOAD = 1; private static final int ERROR_FILE_CANNOT_SAVE = 2; + private static final int ERROR_FILE_CANNOT_FETCH_REDGIFS_VIDEO_LINK = 3; + private static final int ERROR_FILE_CANNOT_FETCH_STREAMABLE_VIDEO_LINK = 4; private static int JOB_ID = 20000; @@ -75,9 +84,17 @@ public class DownloadMediaService extends JobService { @Named("download_media") Retrofit retrofit; @Inject + @Named("redgifs") + Retrofit mRedgifsRetrofit; + @Inject + Provider mStreamableApiProvider; + @Inject @Named("default") SharedPreferences mSharedPreferences; @Inject + @Named("current_account") + SharedPreferences mCurrentAccountSharedPreferences; + @Inject CustomThemeWrapper mCustomThemeWrapper; @Inject Executor mExecutor; @@ -102,15 +119,34 @@ public class DownloadMediaService extends JobService { extras.putString(DownloadMediaService.EXTRA_SUBREDDIT_NAME, post.getSubredditName()); extras.putInt(DownloadMediaService.EXTRA_IS_NSFW, post.isNSFW() ? 1 : 0); } else if (post.getPostType() == Post.VIDEO_TYPE) { - if (post.isImgur() || post.isRedgifs() || post.isStreamable()) { - //TODO fetch download links first - /*extras.putString(DownloadMediaService.EXTRA_URL, post.getVideoDownloadUrl()); - extras.putInt(DownloadMediaService.EXTRA_MEDIA_TYPE, DownloadMediaService.EXTRA_MEDIA_TYPE_VIDEO); - extras.putString(DownloadMediaService.EXTRA_FILE_NAME, videoFileName); + if (post.isStreamable()) { + if (post.isLoadRedgifsOrStreamableVideoSuccess()) { + extras.putString(DownloadMediaService.EXTRA_URL, post.getVideoUrl()); + } else { + extras.putString(DownloadMediaService.EXTRA_REDGIFS_ID, post.getRedgifsId()); + } - extras.putString(DownloadMediaService.EXTRA_SUBREDDIT_NAME, post.getSubredditName()); - extras.putInt(DownloadMediaService.EXTRA_IS_NSFW, post.isNSFW() ? 1 : 0);*/ + extras.putString(DownloadMediaService.EXTRA_FILE_NAME, "Streamable-" + post.getStreamableShortCode() + ".mp4"); + } else if (post.isRedgifs()) { + if (post.isLoadRedgifsOrStreamableVideoSuccess()) { + extras.putString(DownloadMediaService.EXTRA_URL, post.getVideoUrl()); + } else { + extras.putString(DownloadMediaService.EXTRA_STREAMABLE_SHORT_CODE, post.getStreamableShortCode()); + } + + String redgifsId = post.getRedgifsId(); + if (redgifsId != null && redgifsId.contains("-")) { + redgifsId = redgifsId.substring(0, redgifsId.indexOf('-')); + } + extras.putString(DownloadMediaService.EXTRA_FILE_NAME, "Redgifs-" + redgifsId + ".mp4"); + } else if (post.isImgur()) { + extras.putString(DownloadMediaService.EXTRA_URL, post.getVideoUrl()); + extras.putString(DownloadMediaService.EXTRA_FILE_NAME, "Imgur-" + FilenameUtils.getName(post.getVideoUrl())); } + + extras.putInt(DownloadMediaService.EXTRA_MEDIA_TYPE, DownloadMediaService.EXTRA_MEDIA_TYPE_VIDEO); + extras.putString(DownloadMediaService.EXTRA_SUBREDDIT_NAME, post.getSubredditName()); + extras.putInt(DownloadMediaService.EXTRA_IS_NSFW, post.isNSFW() ? 1 : 0); } else if (post.getPostType() == Post.GALLERY_TYPE) { Post.Gallery media = post.getGallery().get(galleryIndex); if (media.mediaType == Post.Gallery.TYPE_VIDEO) { @@ -145,14 +181,12 @@ public class DownloadMediaService extends JobService { public static JobInfo constructJobInfo(Context context, long contentEstimatedBytes, ImgurMedia imgurMedia) { PersistableBundle extras = new PersistableBundle(); + extras.putString(DownloadMediaService.EXTRA_URL, imgurMedia.getLink()); + extras.putString(DownloadMediaService.EXTRA_FILE_NAME, imgurMedia.getFileName()); if (imgurMedia.getType() == ImgurMedia.TYPE_VIDEO) { - extras.putString(DownloadMediaService.EXTRA_URL, imgurMedia.getLink()); extras.putInt(DownloadMediaService.EXTRA_MEDIA_TYPE, DownloadMediaService.EXTRA_MEDIA_TYPE_VIDEO); - extras.putString(DownloadMediaService.EXTRA_FILE_NAME, imgurMedia.getFileName()); } else { - extras.putString(DownloadMediaService.EXTRA_URL, imgurMedia.getLink()); extras.putInt(DownloadMediaService.EXTRA_MEDIA_TYPE, DownloadMediaService.EXTRA_MEDIA_TYPE_IMAGE); - extras.putString(DownloadMediaService.EXTRA_FILE_NAME, imgurMedia.getFileName()); } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { @@ -249,6 +283,22 @@ public class DownloadMediaService extends JobService { boolean isNsfw = intent.getInt(EXTRA_IS_NSFW, 0) == 1; String mimeType = mediaType == EXTRA_MEDIA_TYPE_VIDEO ? "video/*" : "image/*"; + if (fileUrl == null) { + // Only Redgifs and Streamble video can go inside this if clause. + String redgifsId = intent.getString(EXTRA_REDGIFS_ID, null); + String streamableShortCode = intent.getString(EXTRA_STREAMABLE_SHORT_CODE, null); + fileUrl = VideoLinkFetcher.fetchVideoLinkSync(mRedgifsRetrofit, mStreamableApiProvider, mCurrentAccountSharedPreferences, + redgifsId == null ? ViewVideoActivity.VIDEO_TYPE_STREAMABLE : ViewVideoActivity.VIDEO_TYPE_REDGIFS, + redgifsId, streamableShortCode); + + if (fileUrl == null) { + downloadFinished(params, builder, mediaType, randomNotificationIdOffset, mimeType, + null, + redgifsId == null ? ERROR_FILE_CANNOT_FETCH_STREAMABLE_VIDEO_LINK : ERROR_FILE_CANNOT_FETCH_REDGIFS_VIDEO_LINK); + return; + } + } + final DownloadProgressResponseBody.ProgressListener progressListener = new DownloadProgressResponseBody.ProgressListener() { long time = 0; @@ -586,6 +636,14 @@ public class DownloadMediaService extends JobService { updateNotification(builder, mediaType, R.string.downloading_media_failed_cannot_save_to_destination_directory, -1, randomNotificationIdOffset, null, null); break; + case ERROR_FILE_CANNOT_FETCH_REDGIFS_VIDEO_LINK: + updateNotification(builder, mediaType, R.string.downloading_media_failed_cannot_fetch_redgifs_url, + -1, randomNotificationIdOffset, null, null); + break; + case ERROR_FILE_CANNOT_FETCH_STREAMABLE_VIDEO_LINK: + updateNotification(builder, mediaType, R.string.downloading_media_failed_cannot_fetch_streamable_url, + -1, randomNotificationIdOffset, null, null); + break; } } else { MediaScannerConnection.scanFile( diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/thing/FetchRedgifsVideoLinks.java b/app/src/main/java/ml/docilealligator/infinityforreddit/thing/FetchRedgifsVideoLinks.java index ee2fc7ad..08c37f28 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/thing/FetchRedgifsVideoLinks.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/thing/FetchRedgifsVideoLinks.java @@ -3,6 +3,9 @@ package ml.docilealligator.infinityforreddit.thing; import android.content.SharedPreferences; import android.os.Handler; +import androidx.annotation.Nullable; +import androidx.annotation.WorkerThread; + import org.json.JSONException; import org.json.JSONObject; @@ -25,8 +28,12 @@ public class FetchRedgifsVideoLinks { FetchVideoLinkListener fetchVideoLinkListener) { executor.execute(() -> { try { - Response response = redgifsRetrofit.create(RedgifsAPI.class).getRedgifsData(APIUtils.getRedgifsOAuthHeader(currentAccountSharedPreferences.getString(SharedPreferencesUtils.REDGIFS_ACCESS_TOKEN, "")), - redgifsId, APIUtils.USER_AGENT).execute(); + Response response = redgifsRetrofit + .create(RedgifsAPI.class) + .getRedgifsData( + APIUtils.getRedgifsOAuthHeader(currentAccountSharedPreferences.getString(SharedPreferencesUtils.REDGIFS_ACCESS_TOKEN, "")), + redgifsId, APIUtils.USER_AGENT) + .execute(); if (response.isSuccessful()) { parseRedgifsVideoLinks(handler, response.body(), fetchVideoLinkListener); } else { @@ -39,6 +46,29 @@ public class FetchRedgifsVideoLinks { }); } + @WorkerThread + @Nullable + public static String fetchRedgifsVideoLinkSync(Retrofit redgifsRetrofit, + SharedPreferences currentAccountSharedPreferences, + String redgifsId) { + try { + Response response = redgifsRetrofit + .create(RedgifsAPI.class) + .getRedgifsData( + APIUtils.getRedgifsOAuthHeader(currentAccountSharedPreferences.getString(SharedPreferencesUtils.REDGIFS_ACCESS_TOKEN, "")), + redgifsId, APIUtils.USER_AGENT) + .execute(); + if (response.isSuccessful()) { + return parseRedgifsVideoLinks(response.body()); + } else { + return null; + } + } catch (IOException e) { + e.printStackTrace(); + return null; + } + } + public static void fetchRedgifsVideoLinksInRecyclerViewAdapter(Executor executor, Handler handler, Call redgifsCall, FetchVideoLinkListener fetchVideoLinkListener) { @@ -68,4 +98,15 @@ public class FetchRedgifsVideoLinks { handler.post(() -> fetchVideoLinkListener.failed(null)); } } + + @Nullable + private static String parseRedgifsVideoLinks(String response) { + try { + return new JSONObject(response).getJSONObject(JSONUtils.GIF_KEY).getJSONObject(JSONUtils.URLS_KEY) + .getString(JSONUtils.HD_KEY); + } catch (JSONException e) { + e.printStackTrace(); + return null; + } + } } diff --git a/app/src/main/res/layout/fragment_post_options_bottom_sheet.xml b/app/src/main/res/layout/fragment_post_options_bottom_sheet.xml index cf5074b3..647819de 100644 --- a/app/src/main/res/layout/fragment_post_options_bottom_sheet.xml +++ b/app/src/main/res/layout/fragment_post_options_bottom_sheet.xml @@ -90,6 +90,27 @@ android:textSize="?attr/font_default" app:drawableTint="?attr/primaryTextColor" /> + + Download failed: cannot access destination directory Download failed Download failed: cannot save the file to destination directory + Download failed: cannot fetch Redgifs video url + Download failed: cannot fetch Streamable video url Wallpaper set Cannot set wallpaper @@ -1496,4 +1498,9 @@ Toggle reply notifications failed Cannot find comment + Download Image + Download Gif + Download Video + Download All Gallery Images + -- cgit v1.2.3