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

402 lines
16 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-11-06 12:46:31 +00:00
import awais.instagrabber.models.StoryModel;
import awais.instagrabber.models.enums.MediaItemType;
import awais.instagrabber.repositories.responses.Audio;
import awais.instagrabber.repositories.responses.Media;
import awais.instagrabber.repositories.responses.User;
import awais.instagrabber.repositories.responses.VideoVersion;
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);
2020-10-17 10:07:03 +00:00
return new File(finalDir, fileName);
}
2020-11-05 18:34:01 +00:00
@NonNull
public static File getTempFile() {
return getTempFile(null, null);
}
public static File getTempFile(final String fileName, final String extension) {
2020-11-05 18:34:01 +00:00
final File dir = getDownloadDir();
String name = fileName;
if (TextUtils.isEmpty(name)) {
name = UUID.randomUUID().toString();
}
if (!TextUtils.isEmpty(extension)) {
name += "." + extension;
}
return new File(dir, name);
2020-11-05 18:34:01 +00:00
}
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 "";
}
public static List<Boolean> checkDownloaded(@NonNull final Media media) {
2020-11-06 12:46:31 +00:00
final List<Boolean> checkList = new LinkedList<>();
final User user = media.getUser();
String username = "username";
if (user != null) {
username = user.getUsername();
}
final File downloadDir = getDownloadDir(null, "@" + username, true);
switch (media.getMediaType()) {
2020-11-06 12:46:31 +00:00
case MEDIA_TYPE_IMAGE:
case MEDIA_TYPE_VIDEO: {
final String url = ResponseBodyUtils.getImageUrl(media);
final File file = getDownloadSaveFile(downloadDir, media.getCode(), 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<Media> sliderItems = media.getCarouselMedia();
2020-11-06 12:46:31 +00:00
for (int i = 0; i < sliderItems.size(); i++) {
final Media child = sliderItems.get(i);
if (child == null) continue;
final String url = ResponseBodyUtils.getImageUrl(child);
final File file = getDownloadChildSaveFile(downloadDir, media.getCode(), 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 Media feedModel,
2020-11-03 10:01:59 +00:00
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 Media feedModel) {
2020-10-17 10:07:03 +00:00
download(context, feedModel, -1);
}
public static void download(@NonNull final Context context,
@NonNull final Media feedModel,
2020-10-17 10:07:03 +00:00
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<Media> feedModels) {
download(context, feedModels, -1);
2020-10-17 10:07:03 +00:00
}
private static void download(@NonNull final Context context,
@NonNull final List<Media> feedModels,
final int childPositionIfSingle) {
final Map<String, String> map = new HashMap<>();
for (final Media media : feedModels) {
final File downloadDir = getDownloadDir(context, "@" + media.getUser().getUsername());
if (downloadDir == null) return;
switch (media.getMediaType()) {
case MEDIA_TYPE_IMAGE:
case MEDIA_TYPE_VIDEO: {
final String url = getUrlOfType(media);
final File file = getDownloadSaveFile(downloadDir, media.getCode(), url);
map.put(url, file.getAbsolutePath());
break;
}
case MEDIA_TYPE_VOICE: {
final String url = getUrlOfType(media);
String fileName = media.getId();
final User user = media.getUser();
if (user != null) {
fileName = user.getUsername() + "_" + fileName;
}
final File file = getDownloadSaveFile(downloadDir, fileName, url);
map.put(url, file.getAbsolutePath());
break;
}
case MEDIA_TYPE_SLIDER:
final List<Media> sliderItems = media.getCarouselMedia();
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 Media child = sliderItems.get(i);
final String url = getUrlOfType(child);
final File file = getDownloadChildSaveFile(downloadDir, media.getCode(), i + 1, url);
map.put(url, file.getAbsolutePath());
}
break;
default:
}
}
download(context, map);
2020-10-17 10:07:03 +00:00
}
@Nullable
private static String getUrlOfType(@NonNull final Media media) {
switch (media.getMediaType()) {
case MEDIA_TYPE_IMAGE: {
return ResponseBodyUtils.getImageUrl(media);
}
case MEDIA_TYPE_VIDEO: {
final List<VideoVersion> videoVersions = media.getVideoVersions();
String url = null;
if (videoVersions != null && !videoVersions.isEmpty()) {
final VideoVersion videoVersion = videoVersions.get(0);
if (videoVersion != null) {
url = videoVersion.getUrl();
}
}
return url;
}
case MEDIA_TYPE_VOICE: {
final Audio audio = media.getAudio();
String url = null;
if (audio != null) {
url = audio.getAudioSrc();
}
return url;
}
}
return null;
}
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);
}
}