diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml
index 247f71d9..6a48fecb 100755
--- a/.idea/jarRepositories.xml
+++ b/.idea/jarRepositories.xml
@@ -31,5 +31,10 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
index 3c15763b..5ff087f8 100755
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -51,7 +51,9 @@ dependencies {
def nav_version = '2.3.1'
implementation 'com.google.android.material:material:1.3.0-alpha03'
- implementation 'com.google.android.exoplayer:exoplayer:2.12.0'
+
+ implementation 'com.google.android.exoplayer:exoplayer-core:2.12.0'
+ implementation 'com.google.android.exoplayer:exoplayer-ui:2.12.0'
implementation "androidx.appcompat:appcompat:$appcompat_version"
implementation "androidx.appcompat:appcompat-resources:$appcompat_version"
@@ -67,8 +69,7 @@ dependencies {
implementation 'com.google.guava:guava:27.0.1-android'
-// implementation 'com.github.hendrawd:StorageUtil:1.1.0'
-// implementation 'com.github.armcha:AutoLinkTextViewV2:2.1.1'
+ // implementation 'com.github.hendrawd:StorageUtil:1.1.0'
implementation 'com.github.ammargitham:AutoLinkTextViewV2:master-SNAPSHOT'
implementation 'org.jsoup:jsoup:1.13.1'
@@ -79,6 +80,9 @@ dependencies {
implementation 'com.squareup.retrofit2:converter-scalars:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
+ implementation 'com.github.dragon66:icafe:master-SNAPSHOT'
+ implementation 'javax.media:jai_imageio:1.1.1'
+
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.5'
testImplementation 'org.junit.jupiter:junit-jupiter:5.7.0'
diff --git a/app/src/main/java/awais/instagrabber/utils/DownloadUtils.java b/app/src/main/java/awais/instagrabber/utils/DownloadUtils.java
index 76c2702e..c718ed74 100644
--- a/app/src/main/java/awais/instagrabber/utils/DownloadUtils.java
+++ b/app/src/main/java/awais/instagrabber/utils/DownloadUtils.java
@@ -5,7 +5,6 @@ import android.app.Activity;
import android.content.Context;
import android.content.DialogInterface;
import android.content.pm.PackageManager;
-import android.os.AsyncTask;
import android.os.Environment;
import android.util.Log;
import android.util.Pair;
@@ -37,13 +36,9 @@ import java.util.regex.Pattern;
import awais.instagrabber.BuildConfig;
import awais.instagrabber.R;
-import awais.instagrabber.asyncs.DownloadAsync;
-import awais.instagrabber.asyncs.PostFetcher;
import awais.instagrabber.models.BasePostModel;
import awais.instagrabber.models.FeedModel;
import awais.instagrabber.models.PostChild;
-import awais.instagrabber.models.enums.DownloadMethod;
-import awais.instagrabber.models.enums.MediaItemType;
import awais.instagrabber.workers.DownloadWorker;
import awaisomereport.LogCollector;
@@ -63,96 +58,22 @@ public final class DownloadUtils {
return lastNotificationId;
}
- public static void batchDownload(@NonNull final Context context,
- @Nullable String username,
- final DownloadMethod method,
- final List extends BasePostModel> itemsToDownload) {
- if (Utils.settingsHelper == null) Utils.settingsHelper = new SettingsHelper(context);
-
- if (itemsToDownload == null || itemsToDownload.size() < 1) return;
-
- if (username != null && username.charAt(0) == '@') username = username.substring(1);
-
- if (ContextCompat.checkSelfPermission(context, PERMS[0]) == PackageManager.PERMISSION_GRANTED)
- batchDownloadImpl(context, username, method, itemsToDownload);
- else if (context instanceof Activity)
- ActivityCompat.requestPermissions((Activity) context, PERMS, 8020);
- }
-
- private static void batchDownloadImpl(@NonNull final Context context,
- @Nullable final String username,
- final DownloadMethod method,
- final List extends BasePostModel> itemsToDownload) {
- final File dir = getDownloadDir(context, username);
- if (dir == null) return;
- boolean checkEachPost = false;
- switch (method) {
- case DOWNLOAD_SAVED:
- case DOWNLOAD_MAIN:
- case DOWNLOAD_DISCOVER:
- checkEachPost = true;
- break;
- }
- final int itemsToDownloadSize = itemsToDownload.size();
- for (int i = 0; i < itemsToDownloadSize; i++) {
- final BasePostModel selectedItem = itemsToDownload.get(i);
- if (!checkEachPost) {
- final boolean isSlider = itemsToDownloadSize > 1;
- final File saveFile = getDownloadSaveFile(dir,
- selectedItem.getShortCode(),
- isSlider ? "_slide_" + (i + 1) : "",
- selectedItem.getDisplayUrl()
- );
- new DownloadAsync(context,
- selectedItem.getDisplayUrl(),
- saveFile,
- file -> selectedItem.setDownloaded(true))
- .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
- } else {
- final File finalDir = dir;
- new PostFetcher(selectedItem.getShortCode(), result -> {
- if (result == null) return;
- final boolean isSlider = result.getItemType() == MediaItemType.MEDIA_TYPE_SLIDER;
- if (isSlider) {
- for (int j = 0; j < result.getSliderItems().size(); j++) {
- final PostChild model = result.getSliderItems().get(j);
- final File saveFile = getDownloadSaveFile(
- finalDir,
- model.getShortCode(),
- "_slide_" + (j + 1),
- model.getDisplayUrl()
- );
- new DownloadAsync(context,
- model.getDisplayUrl(),
- saveFile,
- file -> {}/*model.setDownloaded(true)*/)
- .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
- }
- } else {
- final File saveFile = getDownloadSaveFile(
- finalDir,
- result.getPostId(),
- result.getDisplayUrl()
- );
- new DownloadAsync(context,
- result.getDisplayUrl(),
- saveFile,
- file -> result.setDownloaded(true))
- .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
- }
- }).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
- }
- }
- }
-
- @Nullable
- private static File getDownloadDir(@NonNull final Context context, @Nullable final String username) {
+ @NonNull
+ private static File getDownloadDir() {
File dir = new File(Environment.getExternalStorageDirectory(), "Download");
if (Utils.settingsHelper.getBoolean(FOLDER_SAVE_TO)) {
final String customPath = Utils.settingsHelper.getString(FOLDER_PATH);
- if (!TextUtils.isEmpty(customPath)) dir = new File(customPath);
+ if (!TextUtils.isEmpty(customPath)) {
+ dir = new File(customPath);
+ }
}
+ return dir;
+ }
+
+ @Nullable
+ private static File getDownloadDir(@NonNull final Context context, @Nullable final String username) {
+ File dir = getDownloadDir();
if (Utils.settingsHelper.getBoolean(Constants.DOWNLOAD_USER_FOLDER) && !TextUtils.isEmpty(username)) {
final String finaleUsername = username.startsWith("@") ? username : "@" + username;
@@ -216,6 +137,12 @@ public final class DownloadUtils {
return new File(finalDir, fileName);
}
+ @NonNull
+ public static File getTempFile() {
+ final File dir = getDownloadDir();
+ return new File(dir, UUID.randomUUID().toString());
+ }
+
/**
* Copied from {@link MimeTypeMap#getFileExtensionFromUrl(String)})
*
diff --git a/app/src/main/java/awais/instagrabber/workers/DownloadWorker.java b/app/src/main/java/awais/instagrabber/workers/DownloadWorker.java
index 7d63e4c6..b3b03829 100644
--- a/app/src/main/java/awais/instagrabber/workers/DownloadWorker.java
+++ b/app/src/main/java/awais/instagrabber/workers/DownloadWorker.java
@@ -26,9 +26,12 @@ import androidx.work.WorkerParameters;
import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException;
+import com.icafe4j.image.meta.Metadata;
+import com.icafe4j.image.meta.MetadataType;
import java.io.BufferedInputStream;
import java.io.File;
+import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.URL;
@@ -45,6 +48,7 @@ import awais.instagrabber.BuildConfig;
import awais.instagrabber.R;
import awais.instagrabber.services.DeleteImageIntentService;
import awais.instagrabber.utils.Constants;
+import awais.instagrabber.utils.DownloadUtils;
import awais.instagrabber.utils.TextUtils;
import awais.instagrabber.utils.Utils;
import awaisomereport.LogCollector;
@@ -121,7 +125,9 @@ public class DownloadWorker extends Worker {
final int total,
final String url,
final String filePath) {
- final File outFile = new File(filePath);
+ final boolean isJpg = filePath.endsWith("jpg");
+ // using temp file approach to remove IPTC so that download progress can be reported
+ final File outFile = isJpg ? DownloadUtils.getTempFile() : new File(filePath);
try {
final URLConnection urlConnection = new URL(url).openConnection();
final long fileSize = Build.VERSION.SDK_INT >= 24 ? urlConnection.getContentLengthLong() :
@@ -131,44 +137,32 @@ public class DownloadWorker extends Worker {
final FileOutputStream fos = new FileOutputStream(outFile)) {
final byte[] buffer = new byte[0x2000];
int count;
- boolean deletedIPTC = false;
while ((count = bis.read(buffer, 0, 0x2000)) != -1) {
totalRead = totalRead + count;
- // if (!deletedIPTC) {
- // int iptcStart = -1;
- // int fbmdStart = -1;
- // int fbmdBytesLen = -1;
- // for (int i = 0; i < buffer.length; ++i) {
- // if (buffer[i] == (byte) 0xFF && buffer[i + 1] == (byte) 0xED)
- // iptcStart = i;
- // else if (buffer[i] == (byte) 'F' && buffer[i + 1] == (byte) 'B'
- // && buffer[i + 2] == (byte) 'M' && buffer[i + 3] == (byte) 'D') {
- // fbmdStart = i;
- // fbmdBytesLen = buffer[i - 10] << 24 | (buffer[i - 9] & 0xFF) << 16 |
- // (buffer[i - 8] & 0xFF) << 8 | (buffer[i - 7] & 0xFF) |
- // (buffer[i - 6] & 0xFF);
- // break;
- // }
- // }
- // if (iptcStart != -1 && fbmdStart != -1 && fbmdBytesLen != -1) {
- // final int fbmdDataLen = (iptcStart + (fbmdStart - iptcStart) + (fbmdBytesLen - iptcStart)) - 4;
- // fos.write(buffer, 0, iptcStart);
- // fos.write(buffer, fbmdDataLen + iptcStart, count - fbmdDataLen - iptcStart);
- // // setProgressAsync(new Data.Builder().putString(URL, url)
- // // .putFloat(PROGRESS, totalRead * 100f / fileSize)
- // // .build());
- // updateDownloadProgress(notificationId, position, total, totalRead * 100f / fileSize);
- // deletedIPTC = true;
- // continue;
- // }
- // }
fos.write(buffer, 0, count);
- // setProgressAsync(new Data.Builder().putString(URL, url)
- // .putFloat(PROGRESS, totalRead * 100f / fileSize)
- // .build());
+ setProgressAsync(new Data.Builder().putString(URL, url)
+ .putFloat(PROGRESS, totalRead * 100f / fileSize)
+ .build());
updateDownloadProgress(notificationId, position, total, totalRead * 100f / fileSize);
}
fos.flush();
+ } catch (final Exception e) {
+ Log.e(TAG, "Error while writing data from url: " + url + " to file: " + outFile.getAbsolutePath(), e);
+ }
+ if (isJpg) {
+ final File finalFile = new File(filePath);
+ try (FileInputStream bis = new FileInputStream(outFile);
+ FileOutputStream fos = new FileOutputStream(finalFile)) {
+ Metadata.removeMetadata(bis, fos, MetadataType.IPTC);
+ } catch (Exception e) {
+ Log.e(TAG, "Error while removing iptc: url: " + url
+ + ", tempFile: " + outFile.getAbsolutePath()
+ + ", finalFile: " + finalFile.getAbsolutePath(), e);
+ }
+ final boolean deleted = outFile.delete();
+ if (!deleted) {
+ Log.w(TAG, "download: tempFile not deleted!");
+ }
}
} catch (final Exception e) {
Log.e(TAG, "Error while downloading: " + url, e);
@@ -176,23 +170,6 @@ public class DownloadWorker extends Worker {
updateDownloadProgress(notificationId, position, total, 100);
}
- // private void showCompleteNotification(final String url) {
- // final Context context = getApplicationContext();
- // final Notification notification = new NotificationCompat.Builder(context, Constants.DOWNLOAD_CHANNEL_ID)
- // .setCategory(NotificationCompat.CATEGORY_STATUS)
- // .setSmallIcon(R.drawable.ic_download)
- // .setAutoCancel(false)
- // .setOnlyAlertOnce(true)
- // .setContentTitle(context.getString(R.string.downloader_complete))
- // .setGroup(DOWNLOAD_GROUP)
- // .build();
- // final int id = Math.abs(url.hashCode());
- // Log.d(TAG, "showCompleteNotification: cancelling: " + id);
- // notificationManager.cancel(id);
- // // WorkManager.getInstance(getApplicationContext()).
- // notificationManager.notify(id + 1, notification);
- // }
-
private void updateDownloadProgress(final int notificationId,
final int position,
final int total,
diff --git a/build.gradle b/build.gradle
index 18c01d6e..da4ac225 100755
--- a/build.gradle
+++ b/build.gradle
@@ -16,6 +16,7 @@ allprojects {
google()
jcenter()
mavenCentral()
+ maven { url 'http://maven.geotoolkit.org/' }
maven { url 'https://jitpack.io' }
}
}