summaryrefslogtreecommitdiff
path: root/net/download/service-interface
diff options
context:
space:
mode:
authorByteHamster <ByteHamster@users.noreply.github.com>2024-03-29 19:27:53 +0100
committerGitHub <noreply@github.com>2024-03-29 19:27:53 +0100
commit2fd73b148d012fba7308c86494689103b8aaace4 (patch)
tree75782c565600eadd67d0fca46acf637370fcf4a3 /net/download/service-interface
parent6f3a9b16764a57e43994ccbeeada5224dee93f44 (diff)
downloadAntennaPod-2fd73b148d012fba7308c86494689103b8aaace4.zip
Move download service to module (#7041)
Diffstat (limited to 'net/download/service-interface')
-rw-r--r--net/download/service-interface/build.gradle3
-rw-r--r--net/download/service-interface/src/main/java/de/danoeh/antennapod/net/download/serviceinterface/DownloadRequestCreator.java122
-rw-r--r--net/download/service-interface/src/main/java/de/danoeh/antennapod/net/download/serviceinterface/FileNameGenerator.java76
3 files changed, 201 insertions, 0 deletions
diff --git a/net/download/service-interface/build.gradle b/net/download/service-interface/build.gradle
index 84a8dfd05..a6ecd8c58 100644
--- a/net/download/service-interface/build.gradle
+++ b/net/download/service-interface/build.gradle
@@ -16,8 +16,11 @@ android {
dependencies {
implementation project(':model')
implementation project(':net:common')
+ implementation project(':storage:preferences')
annotationProcessor "androidx.annotation:annotation:$annotationVersion"
+ implementation "org.apache.commons:commons-lang3:$commonslangVersion"
+ implementation "commons-io:commons-io:$commonsioVersion"
testImplementation "junit:junit:$junitVersion"
testImplementation "org.robolectric:robolectric:$robolectricVersion"
diff --git a/net/download/service-interface/src/main/java/de/danoeh/antennapod/net/download/serviceinterface/DownloadRequestCreator.java b/net/download/service-interface/src/main/java/de/danoeh/antennapod/net/download/serviceinterface/DownloadRequestCreator.java
new file mode 100644
index 000000000..c0d70523c
--- /dev/null
+++ b/net/download/service-interface/src/main/java/de/danoeh/antennapod/net/download/serviceinterface/DownloadRequestCreator.java
@@ -0,0 +1,122 @@
+package de.danoeh.antennapod.net.download.serviceinterface;
+
+import android.util.Log;
+import android.webkit.URLUtil;
+import de.danoeh.antennapod.model.feed.Feed;
+import de.danoeh.antennapod.model.feed.FeedMedia;
+import de.danoeh.antennapod.storage.preferences.UserPreferences;
+import org.apache.commons.io.FilenameUtils;
+
+import java.io.File;
+
+/**
+ * Creates download requests that can be sent to the DownloadService.
+ */
+public class DownloadRequestCreator {
+ private static final String TAG = "DownloadRequestCreat";
+ private static final String FEED_DOWNLOADPATH = "cache/";
+ private static final String MEDIA_DOWNLOADPATH = "media/";
+
+ public static DownloadRequestBuilder create(Feed feed) {
+ File dest = new File(getFeedfilePath(), getFeedfileName(feed));
+ if (dest.exists()) {
+ boolean deleted = dest.delete();
+ Log.d(TAG, "deleted" + dest.getPath() + ": " + deleted);
+ }
+ Log.d(TAG, "Requesting download of url " + feed.getDownloadUrl());
+
+ String username = (feed.getPreferences() != null) ? feed.getPreferences().getUsername() : null;
+ String password = (feed.getPreferences() != null) ? feed.getPreferences().getPassword() : null;
+
+ return new DownloadRequestBuilder(dest.toString(), feed)
+ .withAuthentication(username, password)
+ .lastModified(feed.getLastModified());
+ }
+
+ public static DownloadRequestBuilder create(FeedMedia media) {
+ final boolean partiallyDownloadedFileExists =
+ media.getLocalFileUrl() != null && new File(media.getLocalFileUrl()).exists();
+ File dest;
+ if (partiallyDownloadedFileExists) {
+ dest = new File(media.getLocalFileUrl());
+ } else {
+ dest = new File(getMediafilePath(media), getMediafilename(media));
+ }
+
+ if (dest.exists() && !partiallyDownloadedFileExists) {
+ dest = findUnusedFile(dest);
+ }
+ Log.d(TAG, "Requesting download of url " + media.getDownloadUrl());
+
+ String username = (media.getItem().getFeed().getPreferences() != null)
+ ? media.getItem().getFeed().getPreferences().getUsername() : null;
+ String password = (media.getItem().getFeed().getPreferences() != null)
+ ? media.getItem().getFeed().getPreferences().getPassword() : null;
+
+ return new DownloadRequestBuilder(dest.toString(), media)
+ .withAuthentication(username, password);
+ }
+
+ private static File findUnusedFile(File dest) {
+ // find different name
+ File newDest = null;
+ for (int i = 1; i < Integer.MAX_VALUE; i++) {
+ String newName = FilenameUtils.getBaseName(dest
+ .getName())
+ + "-"
+ + i
+ + FilenameUtils.EXTENSION_SEPARATOR
+ + FilenameUtils.getExtension(dest.getName());
+ Log.d(TAG, "Testing filename " + newName);
+ newDest = new File(dest.getParent(), newName);
+ if (!newDest.exists()) {
+ Log.d(TAG, "File doesn't exist yet. Using " + newName);
+ break;
+ }
+ }
+ return newDest;
+ }
+
+ private static String getFeedfilePath() {
+ return UserPreferences.getDataFolder(FEED_DOWNLOADPATH).toString() + "/";
+ }
+
+ private static String getFeedfileName(Feed feed) {
+ String filename = feed.getDownloadUrl();
+ if (feed.getTitle() != null && !feed.getTitle().isEmpty()) {
+ filename = feed.getTitle();
+ }
+ return "feed-" + FileNameGenerator.generateFileName(filename) + feed.getId();
+ }
+
+ private static String getMediafilePath(FeedMedia media) {
+ String mediaPath = MEDIA_DOWNLOADPATH
+ + FileNameGenerator.generateFileName(media.getItem().getFeed().getTitle());
+ return UserPreferences.getDataFolder(mediaPath).toString() + "/";
+ }
+
+ private static String getMediafilename(FeedMedia media) {
+ String titleBaseFilename = "";
+
+ // Try to generate the filename by the item title
+ if (media.getItem() != null && media.getItem().getTitle() != null) {
+ String title = media.getItem().getTitle();
+ titleBaseFilename = FileNameGenerator.generateFileName(title);
+ }
+
+ String urlBaseFilename = URLUtil.guessFileName(media.getDownloadUrl(), null, media.getMimeType());
+
+ String baseFilename;
+ if (!titleBaseFilename.equals("")) {
+ baseFilename = titleBaseFilename;
+ } else {
+ baseFilename = urlBaseFilename;
+ }
+ final int filenameMaxLength = 220;
+ if (baseFilename.length() > filenameMaxLength) {
+ baseFilename = baseFilename.substring(0, filenameMaxLength);
+ }
+ return baseFilename + FilenameUtils.EXTENSION_SEPARATOR + media.getId()
+ + FilenameUtils.EXTENSION_SEPARATOR + FilenameUtils.getExtension(urlBaseFilename);
+ }
+}
diff --git a/net/download/service-interface/src/main/java/de/danoeh/antennapod/net/download/serviceinterface/FileNameGenerator.java b/net/download/service-interface/src/main/java/de/danoeh/antennapod/net/download/serviceinterface/FileNameGenerator.java
new file mode 100644
index 000000000..85e73836f
--- /dev/null
+++ b/net/download/service-interface/src/main/java/de/danoeh/antennapod/net/download/serviceinterface/FileNameGenerator.java
@@ -0,0 +1,76 @@
+package de.danoeh.antennapod.net.download.serviceinterface;
+
+import android.text.TextUtils;
+
+import androidx.annotation.VisibleForTesting;
+import org.apache.commons.lang3.ArrayUtils;
+import org.apache.commons.lang3.StringUtils;
+
+import java.io.UnsupportedEncodingException;
+import java.security.NoSuchAlgorithmException;
+
+
+/** Generates valid filenames for a given string. */
+public class FileNameGenerator {
+ @VisibleForTesting
+ public static final int MAX_FILENAME_LENGTH = 242; // limited by CircleCI
+ private static final int MD5_HEX_LENGTH = 32;
+
+ private static final char[] validChars =
+ ("abcdefghijklmnopqrstuvwxyz"
+ + "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ + "0123456789"
+ + " _-").toCharArray();
+
+ private FileNameGenerator() {
+ }
+
+ /**
+ * This method will return a new string that doesn't contain any illegal
+ * characters of the given string.
+ */
+ public static String generateFileName(String string) {
+ string = StringUtils.stripAccents(string);
+ StringBuilder buf = new StringBuilder();
+ for (int i = 0; i < string.length(); i++) {
+ char c = string.charAt(i);
+ if (Character.isSpaceChar(c)
+ && (buf.length() == 0 || Character.isSpaceChar(buf.charAt(buf.length() - 1)))) {
+ continue;
+ }
+ if (ArrayUtils.contains(validChars, c)) {
+ buf.append(c);
+ }
+ }
+ String filename = buf.toString().trim();
+ if (TextUtils.isEmpty(filename)) {
+ return randomString(8);
+ } else if (filename.length() >= MAX_FILENAME_LENGTH) {
+ return filename.substring(0, MAX_FILENAME_LENGTH - MD5_HEX_LENGTH - 1) + "_" + md5(filename);
+ } else {
+ return filename;
+ }
+ }
+
+ private static String randomString(int length) {
+ StringBuilder sb = new StringBuilder(length);
+ for (int i = 0; i < length; i++) {
+ sb.append(validChars[(int) (Math.random() * validChars.length)]);
+ }
+ return sb.toString();
+ }
+
+ private static String md5(String md5) {
+ try {
+ java.security.MessageDigest md = java.security.MessageDigest.getInstance("MD5");
+ byte[] array = md.digest(md5.getBytes("UTF-8"));
+ StringBuilder sb = new StringBuilder();
+ for (byte b : array) {
+ sb.append(Integer.toHexString((b & 0xFF) | 0x100).substring(1, 3));
+ }
+ return sb.toString();
+ } catch (NoSuchAlgorithmException | UnsupportedEncodingException e) {
+ return null;
+ }
+ }
+}