BarInsta/app/src/main/java/awais/instagrabber/utils/DownloadUtils.java

343 lines
14 KiB
Java
Raw Normal View History

package awais.instagrabber.utils;
import android.Manifest;
import android.app.Activity;
import android.content.Context;
2020-11-03 10:01:59 +00:00
import android.content.DialogInterface;
import android.content.pm.PackageManager;
import android.os.Environment;
import android.util.Log;
2020-10-17 10:07:03 +00:00
import android.webkit.MimeTypeMap;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
2020-11-03 10:01:59 +00:00
import androidx.appcompat.app.AlertDialog;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
2020-10-17 10:07:03 +00:00
import androidx.work.Constraints;
import androidx.work.Data;
import androidx.work.NetworkType;
import androidx.work.OneTimeWorkRequest;
import androidx.work.WorkManager;
import androidx.work.WorkRequest;
import com.google.gson.Gson;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
2020-10-17 10:07:03 +00:00
import java.util.Collections;
import java.util.HashMap;
2020-11-06 12:46:31 +00:00
import java.util.LinkedList;
import java.util.List;
2020-10-17 10:07:03 +00:00
import java.util.Map;
import java.util.UUID;
import java.util.regex.Pattern;
import awais.instagrabber.R;
2020-10-17 10:07:03 +00:00
import awais.instagrabber.models.FeedModel;
import awais.instagrabber.models.PostChild;
2020-11-06 12:46:31 +00:00
import awais.instagrabber.models.StoryModel;
import awais.instagrabber.models.enums.MediaItemType;
2020-10-17 10:07:03 +00:00
import awais.instagrabber.workers.DownloadWorker;
import static awais.instagrabber.utils.Constants.FOLDER_PATH;
import static awais.instagrabber.utils.Constants.FOLDER_SAVE_TO;
public final class DownloadUtils {
private static final String TAG = "DownloadUtils";
2020-10-17 10:07:03 +00:00
public static final String WRITE_PERMISSION = Manifest.permission.WRITE_EXTERNAL_STORAGE;
public static final String[] PERMS = new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE};
2020-11-05 18:34:01 +00:00
@NonNull
private static File getDownloadDir() {
File dir = new File(Environment.getExternalStorageDirectory(), "Download");
2020-11-05 18:34:01 +00:00
if (Utils.settingsHelper.getBoolean(FOLDER_SAVE_TO)) {
final String customPath = Utils.settingsHelper.getString(FOLDER_PATH);
if (!TextUtils.isEmpty(customPath)) {
dir = new File(customPath);
}
}
2020-11-05 18:34:01 +00:00
return dir;
}
2020-10-17 10:07:03 +00:00
@Nullable
private static File getDownloadDir(@NonNull final Context context, @Nullable final String username) {
2020-11-06 12:46:31 +00:00
return getDownloadDir(context, username, false);
}
@Nullable
private static File getDownloadDir(final Context context,
@Nullable final String username,
final boolean skipCreateDir) {
2020-11-05 18:34:01 +00:00
File dir = getDownloadDir();
2020-10-17 10:07:03 +00:00
if (Utils.settingsHelper.getBoolean(Constants.DOWNLOAD_USER_FOLDER) && !TextUtils.isEmpty(username)) {
2020-11-30 17:46:44 +00:00
final String finaleUsername = username.startsWith("@") ? username.substring(1) : username;
2020-10-17 10:07:03 +00:00
dir = new File(dir, finaleUsername);
}
2020-11-06 12:46:31 +00:00
if (context != null && !skipCreateDir && !dir.exists() && !dir.mkdirs()) {
2020-10-17 10:07:03 +00:00
Toast.makeText(context, R.string.error_creating_folders, Toast.LENGTH_SHORT).show();
return null;
}
return dir;
}
public static void dmDownload(@NonNull final Context context,
@Nullable final String username,
final String modelId,
final String url) {
if (url == null) return;
if (ContextCompat.checkSelfPermission(context, PERMS[0]) == PackageManager.PERMISSION_GRANTED) {
dmDownloadImpl(context, username, modelId, url);
} else if (context instanceof Activity) {
ActivityCompat.requestPermissions((Activity) context, PERMS, 8020);
}
}
2020-10-17 10:07:03 +00:00
private static void dmDownloadImpl(@NonNull final Context context,
@Nullable final String username,
final String modelId,
final String url) {
final File dir = getDownloadDir(context, username);
if (dir.exists() || dir.mkdirs()) {
download(context,
url,
getDownloadSaveFile(dir, modelId, url).getAbsolutePath());
return;
}
Toast.makeText(context, R.string.error_creating_folders, Toast.LENGTH_SHORT).show();
}
@NonNull
2020-10-17 10:07:03 +00:00
private static File getDownloadSaveFile(final File finalDir,
final String postId,
final String displayUrl) {
return getDownloadSaveFile(finalDir, postId, "", displayUrl);
}
private static File getDownloadChildSaveFile(final File downloadDir,
final String postId,
final int childPosition,
final String url) {
final String sliderPostfix = "_slide_" + childPosition;
return getDownloadSaveFile(downloadDir, postId, sliderPostfix, url);
}
@NonNull
2020-10-17 10:07:03 +00:00
private static File getDownloadSaveFile(final File finalDir,
final String postId,
final String sliderPostfix,
final String displayUrl) {
final String fileName = postId + sliderPostfix + "." + getFileExtensionFromUrl(displayUrl);
return new File(finalDir, fileName);
}
2020-11-05 18:34:01 +00:00
@NonNull
public static File getTempFile() {
final File dir = getDownloadDir();
return new File(dir, UUID.randomUUID().toString());
}
2020-10-17 10:07:03 +00:00
/**
* Copied from {@link MimeTypeMap#getFileExtensionFromUrl(String)})
* <p>
* Returns the file extension or an empty string if there is no
* extension. This method is a convenience method for obtaining the
* extension of a url and has undefined results for other Strings.
*
* @param url URL
* @return The file extension of the given url.
*/
public static String getFileExtensionFromUrl(String url) {
if (!TextUtils.isEmpty(url)) {
int fragment = url.lastIndexOf('#');
if (fragment > 0) {
url = url.substring(0, fragment);
}
int query = url.lastIndexOf('?');
if (query > 0) {
url = url.substring(0, query);
}
int filenamePos = url.lastIndexOf('/');
String filename =
0 <= filenamePos ? url.substring(filenamePos + 1) : url;
// if the filename contains special characters, we don't
// consider it valid for our matching purposes:
if (!filename.isEmpty() &&
Pattern.matches("[a-zA-Z_0-9.\\-()%]+", filename)) {
int dotPos = filename.lastIndexOf('.');
if (0 <= dotPos) {
2020-11-13 23:44:33 +00:00
return filename.substring(dotPos);
2020-10-17 10:07:03 +00:00
}
}
}
2020-10-17 10:07:03 +00:00
return "";
}
2020-11-06 12:46:31 +00:00
public static List<Boolean> checkDownloaded(@NonNull final FeedModel feedModel) {
final List<Boolean> checkList = new LinkedList<>();
final File downloadDir = getDownloadDir(null, "@" + feedModel.getProfileModel().getUsername(), true);
switch (feedModel.getItemType()) {
case MEDIA_TYPE_IMAGE:
case MEDIA_TYPE_VIDEO: {
final String url = feedModel.getDisplayUrl();
final File file = getDownloadSaveFile(downloadDir, feedModel.getShortCode(), url);
2020-11-06 12:46:31 +00:00
checkList.add(file.exists());
break;
}
2020-11-06 12:46:31 +00:00
case MEDIA_TYPE_SLIDER:
final List<PostChild> sliderItems = feedModel.getSliderItems();
for (int i = 0; i < sliderItems.size(); i++) {
final PostChild child = sliderItems.get(i);
final String url = child.getDisplayUrl();
final File file = getDownloadChildSaveFile(downloadDir, feedModel.getShortCode(), i + 1, url);
2020-11-06 12:46:31 +00:00
checkList.add(file.exists());
}
break;
default:
}
2020-11-06 12:46:31 +00:00
return checkList;
}
2020-10-17 10:07:03 +00:00
2020-11-03 10:01:59 +00:00
public static void showDownloadDialog(@NonNull Context context,
@NonNull final FeedModel feedModel,
final int childPosition) {
if (childPosition >= 0) {
final DialogInterface.OnClickListener clickListener = (dialog, which) -> {
switch (which) {
case 0:
DownloadUtils.download(context, feedModel, childPosition);
break;
case 1:
DownloadUtils.download(context, feedModel);
break;
case DialogInterface.BUTTON_NEGATIVE:
default:
dialog.dismiss();
break;
}
};
final String[] items = new String[]{
context.getString(R.string.post_viewer_download_current),
context.getString(R.string.post_viewer_download_album),
};
new AlertDialog.Builder(context)
.setTitle(R.string.post_viewer_download_dialog_title)
.setItems(items, clickListener)
.setNegativeButton(R.string.cancel, null)
.show();
return;
}
DownloadUtils.download(context, feedModel);
}
2020-11-06 12:46:31 +00:00
public static void download(@NonNull final Context context,
@NonNull final StoryModel storyModel) {
final File downloadDir = getDownloadDir(context, "@" + storyModel.getUsername());
final String url = storyModel.getItemType() == MediaItemType.MEDIA_TYPE_VIDEO
? storyModel.getVideoUrl()
: storyModel.getStoryUrl();
final File saveFile = new File(downloadDir,
storyModel.getStoryMediaId()
+ "_" + storyModel.getTimestamp()
+ DownloadUtils.getFileExtensionFromUrl(url));
download(context, url, saveFile.getAbsolutePath());
}
2020-10-17 10:07:03 +00:00
public static void download(@NonNull final Context context,
@NonNull final FeedModel feedModel) {
download(context, feedModel, -1);
}
public static void download(@NonNull final Context context,
@NonNull final FeedModel feedModel,
final int position) {
download(context, Collections.singletonList(feedModel), position);
}
2020-10-17 10:07:03 +00:00
public static void download(@NonNull final Context context,
@NonNull final List<FeedModel> feedModels) {
download(context, feedModels, -1);
2020-10-17 10:07:03 +00:00
}
private static void download(@NonNull final Context context,
@NonNull final List<FeedModel> feedModels,
final int childPositionIfSingle) {
final Map<String, String> map = new HashMap<>();
for (final FeedModel feedModel : feedModels) {
final File downloadDir = getDownloadDir(context, "@" + feedModel.getProfileModel().getUsername());
if (downloadDir == null) return;
switch (feedModel.getItemType()) {
case MEDIA_TYPE_IMAGE:
case MEDIA_TYPE_VIDEO: {
final String url = feedModel.getDisplayUrl();
final File file = getDownloadSaveFile(downloadDir, feedModel.getShortCode(), url);
map.put(url, file.getAbsolutePath());
break;
}
case MEDIA_TYPE_SLIDER:
final List<PostChild> sliderItems = feedModel.getSliderItems();
for (int i = 0; i < sliderItems.size(); i++) {
2020-11-03 10:01:59 +00:00
if (childPositionIfSingle >= 0 && feedModels.size() == 1 && i != childPositionIfSingle) {
continue;
}
final PostChild child = sliderItems.get(i);
final String url = child.getDisplayUrl();
final File file = getDownloadChildSaveFile(downloadDir, feedModel.getShortCode(), i + 1, url);
map.put(url, file.getAbsolutePath());
}
break;
default:
}
}
download(context, map);
2020-10-17 10:07:03 +00:00
}
2020-11-03 10:01:59 +00:00
public static void download(final Context context,
final String url,
final String filePath) {
if (context == null || url == null || filePath == null) return;
download(context, Collections.singletonMap(url, filePath));
}
2020-10-17 10:07:03 +00:00
private static void download(final Context context, final Map<String, String> urlFilePathMap) {
final Constraints constraints = new Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.build();
final DownloadWorker.DownloadRequest request = DownloadWorker.DownloadRequest.builder()
.setUrlToFilePathMap(urlFilePathMap)
.build();
final String requestJson = new Gson().toJson(request);
final File tempFile = getTempFile();
try (BufferedWriter writer = new BufferedWriter(new FileWriter(tempFile))) {
writer.write(requestJson);
} catch (IOException e) {
Log.e(TAG, "download: Error writing request to file", e);
//noinspection ResultOfMethodCallIgnored
tempFile.delete();
return;
}
2020-10-17 10:07:03 +00:00
final WorkRequest downloadWorkRequest = new OneTimeWorkRequest.Builder(DownloadWorker.class)
.setInputData(
new Data.Builder()
.putString(DownloadWorker.KEY_DOWNLOAD_REQUEST_JSON, tempFile.getAbsolutePath())
2020-10-17 10:07:03 +00:00
.build()
)
.setConstraints(constraints)
.addTag("download")
.build();
WorkManager.getInstance(context)
.enqueue(downloadWorkRequest);
}
}