Merge pull request #116 from OHermesJunior/vreddit-download

Make downloaded vreddit video visible for galleries.
This commit is contained in:
Docile-Alligator 2020-06-07 10:24:01 +08:00 committed by GitHub
commit aa36d0c267
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 132 additions and 139 deletions

View File

@ -3,6 +3,7 @@ package ml.docilealligator.infinityforreddit.Service;
import android.app.Notification; import android.app.Notification;
import android.app.NotificationChannel; import android.app.NotificationChannel;
import android.app.NotificationManager; import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service; import android.app.Service;
import android.content.ContentResolver; import android.content.ContentResolver;
import android.content.ContentValues; import android.content.ContentValues;
@ -12,6 +13,7 @@ import android.media.MediaCodec;
import android.media.MediaExtractor; import android.media.MediaExtractor;
import android.media.MediaFormat; import android.media.MediaFormat;
import android.media.MediaMuxer; import android.media.MediaMuxer;
import android.media.MediaScannerConnection;
import android.net.Uri; import android.net.Uri;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.os.Build; import android.os.Build;
@ -20,10 +22,10 @@ import android.os.IBinder;
import android.provider.MediaStore; import android.provider.MediaStore;
import android.util.Log; import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi; import androidx.annotation.RequiresApi;
import androidx.core.app.NotificationCompat; import androidx.core.app.NotificationCompat;
import androidx.core.app.NotificationManagerCompat; import androidx.core.app.NotificationManagerCompat;
import androidx.core.content.FileProvider;
import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.EventBus;
@ -38,6 +40,7 @@ import java.nio.ByteBuffer;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Named; import javax.inject.Named;
import ml.docilealligator.infinityforreddit.API.DownloadRedditVideo;
import ml.docilealligator.infinityforreddit.CustomTheme.CustomThemeWrapper; import ml.docilealligator.infinityforreddit.CustomTheme.CustomThemeWrapper;
import ml.docilealligator.infinityforreddit.Event.DownloadRedditVideoEvent; import ml.docilealligator.infinityforreddit.Event.DownloadRedditVideoEvent;
import ml.docilealligator.infinityforreddit.Infinity; import ml.docilealligator.infinityforreddit.Infinity;
@ -52,6 +55,7 @@ import retrofit2.Retrofit;
import static android.os.Environment.getExternalStoragePublicDirectory; import static android.os.Environment.getExternalStoragePublicDirectory;
public class DownloadRedditVideoService extends Service { public class DownloadRedditVideoService extends Service {
public static final String EXTRA_VIDEO_URL = "EVU"; public static final String EXTRA_VIDEO_URL = "EVU";
public static final String EXTRA_SUBREDDIT = "ES"; public static final String EXTRA_SUBREDDIT = "ES";
public static final String EXTRA_POST_ID = "EPI"; public static final String EXTRA_POST_ID = "EPI";
@ -61,6 +65,7 @@ public class DownloadRedditVideoService extends Service {
Retrofit retrofit; Retrofit retrofit;
@Inject @Inject
CustomThemeWrapper mCustomThemeWrapper; CustomThemeWrapper mCustomThemeWrapper;
String resultFile;
public DownloadRedditVideoService() { public DownloadRedditVideoService() {
} }
@ -88,162 +93,148 @@ public class DownloadRedditVideoService extends Service {
manager.createNotificationChannel(serviceChannel); manager.createNotificationChannel(serviceChannel);
} }
String fileNameWithoutExtension = intent.getStringExtra(EXTRA_SUBREDDIT) String fileName = intent.getStringExtra(EXTRA_SUBREDDIT) + "-" + intent.getStringExtra(EXTRA_POST_ID);
+ "-" + intent.getStringExtra(EXTRA_POST_ID);
startForeground(NotificationUtils.DOWNLOAD_REDDIT_VIDEO_NOTIFICATION_ID, startForeground(
createNotification(R.string.downloading_reddit_video, fileNameWithoutExtension + ".mp4")); NotificationUtils.DOWNLOAD_REDDIT_VIDEO_NOTIFICATION_ID,
createNotification(R.string.downloading_reddit_video, fileName + ".mp4", false, null)
);
ml.docilealligator.infinityforreddit.API.DownloadRedditVideo downloadRedditVideo = retrofit.create(ml.docilealligator.infinityforreddit.API.DownloadRedditVideo.class); DownloadRedditVideo downloadRedditVideo = retrofit.create(DownloadRedditVideo.class);
downloadRedditVideo.downloadFile(videoUrl).enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(@NonNull Call<ResponseBody> call, @NonNull Response<ResponseBody> videoResponse) {
if (videoResponse.isSuccessful() && videoResponse.body() != null) {
updateNotification(R.string.downloading_reddit_video_audio_track, fileNameWithoutExtension + ".mp3");
downloadRedditVideo.downloadFile(audioUrl).enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(@NonNull Call<ResponseBody> call, @NonNull Response<ResponseBody> audioResponse) {
File directory = getExternalCacheDir(); File directory = getExternalCacheDir();
if (directory != null) { if (directory != null) {
String directoryPath = directory.getAbsolutePath() + "/"; String directoryPath = directory.getAbsolutePath() + "/";
downloadRedditVideo.downloadFile(videoUrl).enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> videoResponse) {
if (videoResponse.isSuccessful() && videoResponse.body() != null) {
String videoFilePath = writeResponseBodyToDisk(videoResponse.body(), directoryPath + fileName + "-cache.mp4");
if (videoFilePath != null) {
resultFile = videoFilePath;
updateNotification(R.string.downloading_reddit_video_audio_track, fileName + ".mp3", false);
downloadRedditVideo.downloadFile(audioUrl).enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> audioResponse) {
if (audioResponse.isSuccessful() && audioResponse.body() != null) { if (audioResponse.isSuccessful() && audioResponse.body() != null) {
updateNotification(R.string.downloading_reddit_video_muxing, null); String audioFilePath = writeResponseBodyToDisk(audioResponse.body(), directoryPath + fileName + "-cache.mp3");
String videoFilePath = writeResponseBodyToDisk(videoResponse.body(), directoryPath + fileNameWithoutExtension+ "-cache.mp4");
if (videoFilePath != null) {
String audioFilePath = writeResponseBodyToDisk(audioResponse.body(), directoryPath + fileNameWithoutExtension + "-cache.mp3");
if (audioFilePath != null) { if (audioFilePath != null) {
String outputFilePath = directoryPath + fileNameWithoutExtension + ".mp4"; updateNotification(R.string.downloading_reddit_video_muxing, null, false);
String outputFilePath = directoryPath + fileName + ".mp4";
if (muxVideoAndAudio(videoFilePath, audioFilePath, outputFilePath)) { if (muxVideoAndAudio(videoFilePath, audioFilePath, outputFilePath)) {
new CopyFileAsyncTask(new File(outputFilePath), fileNameWithoutExtension + ".mp4", resultFile = outputFilePath;
getContentResolver(), new CopyFileAsyncTask.CopyFileAsyncTaskListener() { }
@Override
public void successful() {
new File(videoFilePath).delete();
new File(audioFilePath).delete(); new File(audioFilePath).delete();
new File(outputFilePath).delete(); }
}
updateNotification(R.string.downloading_reddit_video_finished, fileNameWithoutExtension + ".mp4"); copyVideoToPublicDir(resultFile, fileName, new String[]{videoFilePath, resultFile});
EventBus.getDefault().post(new DownloadRedditVideoEvent(true));
stopService();
} }
@Override @Override
public void failed() { public void onFailure(Call<ResponseBody> call, Throwable t) {
new File(videoFilePath).delete(); copyVideoToPublicDir(resultFile, fileName, new String[]{videoFilePath, resultFile});
new File(audioFilePath).delete();
new File(outputFilePath).delete();
EventBus.getDefault().post(new DownloadRedditVideoEvent(false));
stopService();
} }
}).execute(); });
} else {
EventBus.getDefault().post(new DownloadRedditVideoEvent(false));
stopService(); } else {
downloadFinished(false);
} }
} else { } else {
new File(videoFilePath).delete(); downloadFinished(false);
EventBus.getDefault().post(new DownloadRedditVideoEvent(false));
stopService();
}
} else {
EventBus.getDefault().post(new DownloadRedditVideoEvent(false));
stopService();
}
} else {
//No audio
String videoFilePath = writeResponseBodyToDisk(videoResponse.body(), directoryPath + fileNameWithoutExtension+ ".mp4");
if (videoFilePath != null) {
new CopyFileAsyncTask(new File(videoFilePath), fileNameWithoutExtension + ".mp4",
getContentResolver(), new CopyFileAsyncTask.CopyFileAsyncTaskListener() {
@Override
public void successful() {
new File(videoFilePath).delete();
updateNotification(R.string.downloading_reddit_video_finished, null);
EventBus.getDefault().post(new DownloadRedditVideoEvent(true));
stopService();
}
@Override
public void failed() {
new File(videoFilePath).delete();
EventBus.getDefault().post(new DownloadRedditVideoEvent(false));
stopService();
}
}).execute();
} else {
EventBus.getDefault().post(new DownloadRedditVideoEvent(false));
stopService();
}
}
} else {
EventBus.getDefault().post(new DownloadRedditVideoEvent(false));
stopService();
} }
} }
@Override @Override
public void onFailure(@NonNull Call<ResponseBody> call, @NonNull Throwable t) { public void onFailure(Call<ResponseBody> call, Throwable t) {
EventBus.getDefault().post(new DownloadRedditVideoEvent(false)); downloadFinished(false);
stopService();
} }
}); });
} else { } else {
EventBus.getDefault().post(new DownloadRedditVideoEvent(false)); downloadFinished(false);
stopService();
} }
}
@Override
public void onFailure(@NonNull Call<ResponseBody> call, @NonNull Throwable t) {
EventBus.getDefault().post(new DownloadRedditVideoEvent(false));
stopService();
}
});
return START_NOT_STICKY; return START_NOT_STICKY;
} }
private Notification createNotification(int stringResId, String fileName) { private void addMediaFileAndShareNotification(File f, int stringResId, String fileName) {
MediaScannerConnection.scanFile(
this, new String[]{f.getAbsolutePath()}, null,
(path, uri) -> openVideoNotification(f, stringResId, fileName)
);
}
private void openVideoNotification(File f, int stringResId, String fileName) {
final Intent viewIntent = new Intent(Intent.ACTION_VIEW);
Uri selectedUri = FileProvider.getUriForFile(this, getApplicationContext().getPackageName() + ".provider", f);
viewIntent.setDataAndType(selectedUri, getContentResolver().getType(selectedUri));
viewIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, viewIntent, PendingIntent.FLAG_CANCEL_CURRENT);
updateNotification(stringResId, fileName, true, contentIntent);
}
private void downloadFinished(boolean isSuccessful) {
EventBus.getDefault().post(new DownloadRedditVideoEvent(isSuccessful));
if (!isSuccessful)
updateNotification(R.string.downloading_reddit_video_failed, null, true);
stopService();
}
private Notification createNotification(int stringResId, String fileName, boolean finished, PendingIntent contentIntent) {
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, NotificationUtils.CHANNEL_ID_DOWNLOAD_REDDIT_VIDEO); NotificationCompat.Builder builder = new NotificationCompat.Builder(this, NotificationUtils.CHANNEL_ID_DOWNLOAD_REDDIT_VIDEO);
if (fileName != null) { if (fileName != null) {
builder.setContentTitle(getString(stringResId, fileName)); builder.setContentTitle(getString(stringResId, fileName));
} else { } else {
builder.setContentTitle(getString(stringResId)); builder.setContentTitle(getString(stringResId));
} }
return builder.setContentText(getString(R.string.please_wait)) if (!finished)
.setSmallIcon(R.drawable.ic_notification) builder.setContentText(getString(R.string.please_wait));
if (contentIntent != null)
builder.setContentIntent(contentIntent);
return builder.setSmallIcon(R.drawable.ic_notification)
.setColor(mCustomThemeWrapper.getColorPrimaryLightTheme()) .setColor(mCustomThemeWrapper.getColorPrimaryLightTheme())
.build(); .build();
} }
private void updateNotification(int stringResId, String fileName) { private void updateNotification(int stringResId, String fileName, boolean finished) {
updateNotification(stringResId, fileName, finished, null);
}
private void updateNotification(int stringResId, String fileName, boolean finished, PendingIntent contentIntent) {
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
if (notificationManager != null) { if (notificationManager != null) {
notificationManager.notify(NotificationUtils.DOWNLOAD_REDDIT_VIDEO_NOTIFICATION_ID, notificationManager.notify(NotificationUtils.DOWNLOAD_REDDIT_VIDEO_NOTIFICATION_ID,
createNotification(stringResId, fileName)); createNotification(stringResId, fileName, finished, contentIntent));
} }
} }
private void copyVideoToPublicDir(String resFilePath, String newFileName, String[] tempFiles) {
new CopyFileAsyncTask(new File(resFilePath), newFileName + ".mp4",
getContentResolver(), new CopyFileAsyncTask.CopyFileAsyncTaskListener() {
@Override
public void successful(File dstFile) {
if (dstFile != null) {
addMediaFileAndShareNotification(dstFile, R.string.downloading_reddit_video_finished, newFileName + ".mp4");
} else {
updateNotification(R.string.downloading_reddit_video_finished, newFileName + ".mp4", true);
}
for (int i = 0; i < tempFiles.length; i++) {
new File(tempFiles[i]).delete();
}
downloadFinished(true);
}
@Override
public void failed() {
for (int i = 0; i < tempFiles.length; i++) {
new File(tempFiles[i]).delete();
}
downloadFinished(false);
}
}).execute();
}
private String writeResponseBodyToDisk(ResponseBody body, String filePath) { private String writeResponseBodyToDisk(ResponseBody body, String filePath) {
try { try {
File file = new File(filePath); File file = new File(filePath);
@ -322,14 +313,12 @@ public class DownloadRedditVideoService extends Service {
muxer.start(); muxer.start();
while (!sawEOS) while (!sawEOS) {
{
videoBufferInfo.offset = offset; videoBufferInfo.offset = offset;
videoBufferInfo.size = videoExtractor.readSampleData(videoBuf, offset); videoBufferInfo.size = videoExtractor.readSampleData(videoBuf, offset);
if (videoBufferInfo.size < 0 || audioBufferInfo.size < 0) if (videoBufferInfo.size < 0 || audioBufferInfo.size < 0) {
{
// Log.d(TAG, "saw input EOS."); // Log.d(TAG, "saw input EOS.");
sawEOS = true; sawEOS = true;
videoBufferInfo.size = 0; videoBufferInfo.size = 0;
@ -342,8 +331,7 @@ public class DownloadRedditVideoService extends Service {
} }
boolean sawEOS2 = false; boolean sawEOS2 = false;
while (!sawEOS2) while (!sawEOS2) {
{
audioBufferInfo.offset = offset; audioBufferInfo.offset = offset;
audioBufferInfo.size = audioExtractor.readSampleData(audioBuf, offset); audioBufferInfo.size = audioExtractor.readSampleData(audioBuf, offset);
@ -374,17 +362,14 @@ public class DownloadRedditVideoService extends Service {
} }
private static class CopyFileAsyncTask extends AsyncTask<Void, Void, Void> { private static class CopyFileAsyncTask extends AsyncTask<Void, Void, Void> {
private File src; private File src;
private String destinationFileName; private String destinationFileName;
private File destinationFile;
private ContentResolver contentResolver; private ContentResolver contentResolver;
private CopyFileAsyncTaskListener copyFileAsyncTaskListener; private CopyFileAsyncTaskListener copyFileAsyncTaskListener;
private boolean successful; private boolean successful;
interface CopyFileAsyncTaskListener {
void successful();
void failed();
}
CopyFileAsyncTask(File src, String destinationFileName, ContentResolver contentResolver, CopyFileAsyncTaskListener copyFileAsyncTaskListener) { CopyFileAsyncTask(File src, String destinationFileName, ContentResolver contentResolver, CopyFileAsyncTaskListener copyFileAsyncTaskListener) {
this.src = src; this.src = src;
this.destinationFileName = destinationFileName; this.destinationFileName = destinationFileName;
@ -412,7 +397,7 @@ public class DownloadRedditVideoService extends Service {
protected void onPostExecute(Void aVoid) { protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid); super.onPostExecute(aVoid);
if (successful) { if (successful) {
copyFileAsyncTaskListener.successful(); copyFileAsyncTaskListener.successful(destinationFile);
} else { } else {
copyFileAsyncTaskListener.failed(); copyFileAsyncTaskListener.failed();
} }
@ -472,11 +457,11 @@ public class DownloadRedditVideoService extends Service {
private boolean copy(File src, String outputFileName) { private boolean copy(File src, String outputFileName) {
File directory = getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES); File directory = getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
if (directory != null) { if (directory != null) {
String directoryPath = directory.getAbsolutePath() + "/Infinity/";; String directoryPath = directory.getAbsolutePath() + "/Infinity/";
File dst = new File(directoryPath, outputFileName); destinationFile = new File(directoryPath, outputFileName);
try (InputStream in = new FileInputStream(src)) { try (InputStream in = new FileInputStream(src)) {
try (OutputStream out = new FileOutputStream(dst)) { try (OutputStream out = new FileOutputStream(destinationFile)) {
byte[] buf = new byte[1024]; byte[] buf = new byte[1024];
int len; int len;
while ((len = in.read(buf)) > 0) { while ((len = in.read(buf)) > 0) {
@ -496,5 +481,12 @@ public class DownloadRedditVideoService extends Service {
return false; return false;
} }
} }
interface CopyFileAsyncTaskListener {
void successful(File dstFile);
void failed();
}
} }
} }

View File

@ -744,5 +744,6 @@
<string name="downloading_reddit_video_audio_track">Downloading Audio Track For %1$s</string> <string name="downloading_reddit_video_audio_track">Downloading Audio Track For %1$s</string>
<string name="downloading_reddit_video_muxing">Muxing Video</string> <string name="downloading_reddit_video_muxing">Muxing Video</string>
<string name="downloading_reddit_video_finished">%1$s Downloaded</string> <string name="downloading_reddit_video_finished">%1$s Downloaded</string>
<string name="downloading_reddit_video_failed">Failed To Download Video</string>
</resources> </resources>