summaryrefslogtreecommitdiff
path: root/core/src/main
diff options
context:
space:
mode:
Diffstat (limited to 'core/src/main')
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/asynctask/PicassoProvider.java65
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/feed/FeedItem.java6
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/feed/FeedMedia.java72
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/gpoddernet/GpodnetService.java7
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/download/HttpDownloader.java77
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java29
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java14
7 files changed, 198 insertions, 72 deletions
diff --git a/core/src/main/java/de/danoeh/antennapod/core/asynctask/PicassoProvider.java b/core/src/main/java/de/danoeh/antennapod/core/asynctask/PicassoProvider.java
index b6ece6dc8..4f2d5b204 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/asynctask/PicassoProvider.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/asynctask/PicassoProvider.java
@@ -6,8 +6,12 @@ import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.media.MediaMetadataRetriever;
import android.net.Uri;
+import android.text.TextUtils;
import android.util.Log;
+import com.squareup.okhttp.Interceptor;
+import com.squareup.okhttp.OkHttpClient;
+import com.squareup.okhttp.Response;
import com.squareup.picasso.Cache;
import com.squareup.picasso.LruCache;
import com.squareup.picasso.OkHttpDownloader;
@@ -22,13 +26,18 @@ import org.apache.commons.lang3.StringUtils;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.net.HttpURLConnection;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
+import de.danoeh.antennapod.core.service.download.HttpDownloader;
+import de.danoeh.antennapod.core.storage.DBReader;
+
/**
* Provides access to Picasso instances.
*/
public class PicassoProvider {
+
private static final String TAG = "PicassoProvider";
private static final boolean DEBUG = false;
@@ -56,10 +65,12 @@ public class PicassoProvider {
if (picassoSetup) {
return;
}
+ OkHttpClient client = new OkHttpClient();
+ client.interceptors().add(new BasicAuthenticationInterceptor(appContext));
Picasso picasso = new Picasso.Builder(appContext)
.indicatorsEnabled(DEBUG)
.loggingEnabled(DEBUG)
- .downloader(new OkHttpDownloader(appContext))
+ .downloader(new OkHttpDownloader(client))
.addRequestHandler(new MediaRequestHandler(appContext))
.executor(getExecutorService())
.memoryCache(getMemoryCache(appContext))
@@ -75,6 +86,48 @@ public class PicassoProvider {
picassoSetup = true;
}
+ private static class BasicAuthenticationInterceptor implements Interceptor {
+
+ private final Context context;
+
+ public BasicAuthenticationInterceptor(Context context) {
+ this.context = context;
+ }
+
+ @Override
+ public Response intercept(Chain chain) throws IOException {
+ com.squareup.okhttp.Request request = chain.request();
+ String url = request.urlString();
+ String authentication = DBReader.getImageAuthentication(context, url);
+
+ if(TextUtils.isEmpty(authentication)) {
+ Log.d(TAG, "no credentials for '" + url + "'");
+ return chain.proceed(request);
+ }
+
+ // add authentication
+ String[] auth = authentication.split(":");
+ String credentials = HttpDownloader.encodeCredentials(auth[0], auth[1], "ISO-8859-1");
+ com.squareup.okhttp.Request newRequest = request
+ .newBuilder()
+ .addHeader("Authorization", credentials)
+ .build();
+ Log.d(TAG, "Basic authentication with ISO-8859-1 encoding");
+ Response response = chain.proceed(newRequest);
+ if (!response.isSuccessful() && response.code() == HttpURLConnection.HTTP_UNAUTHORIZED) {
+ credentials = HttpDownloader.encodeCredentials(auth[0], auth[1], "UTF-8");
+ newRequest = request
+ .newBuilder()
+ .addHeader("Authorization", credentials)
+ .build();
+ Log.d(TAG, "Basic authentication with UTF-8 encoding");
+ return chain.proceed(newRequest);
+ } else {
+ return response;
+ }
+ }
+ }
+
private static class MediaRequestHandler extends RequestHandler {
final Context context;
@@ -90,7 +143,7 @@ public class PicassoProvider {
}
@Override
- public Result load(Request data) throws IOException {
+ public Result load(Request data, int networkPolicy) throws IOException {
Bitmap bitmap = null;
MediaMetadataRetriever mmr = null;
try {
@@ -109,13 +162,7 @@ public class PicassoProvider {
}
if (bitmap == null) {
- // check for fallback Uri
- String fallbackParam = data.uri.getQueryParameter(PicassoImageResource.PARAM_FALLBACK);
-
- if (fallbackParam != null) {
- Uri fallback = Uri.parse(fallbackParam);
- bitmap = decodeStreamFromFile(data, fallback);
- }
+ Log.wtf(TAG, "THIS SHOULD NEVER EVER HAPPEN!!");
}
return new Result(bitmap, Picasso.LoadedFrom.DISK);
diff --git a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItem.java b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItem.java
index 4fd7a184c..b74875175 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItem.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItem.java
@@ -315,10 +315,10 @@ public class FeedItem extends FeedComponent implements ShownotesProvider, Flattr
@Override
public Uri getImageUri() {
- if (hasItemImageDownloaded()) {
- return image.getImageUri();
- } else if (hasMedia()) {
+ if(media.hasEmbeddedPicture()) {
return media.getImageUri();
+ } else if (hasItemImageDownloaded()) {
+ return image.getImageUri();
} else if (feed != null) {
return feed.getImageUri();
} else {
diff --git a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedMedia.java b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedMedia.java
index 93f826894..3dda291fa 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedMedia.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedMedia.java
@@ -2,9 +2,11 @@ package de.danoeh.antennapod.core.feed;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
+import android.media.MediaMetadataRetriever;
import android.net.Uri;
import android.os.Parcel;
import android.os.Parcelable;
+import android.util.Log;
import java.util.Date;
import java.util.List;
@@ -34,6 +36,7 @@ public class FeedMedia extends FeedFile implements Playable {
private String mime_type;
private volatile FeedItem item;
private Date playbackCompletionDate;
+ private boolean hasEmbeddedPicture;
/* Used for loading item when restoring from parcel. */
private long itemID;
@@ -50,6 +53,7 @@ public class FeedMedia extends FeedFile implements Playable {
long size, String mime_type, String file_url, String download_url,
boolean downloaded, Date playbackCompletionDate, int played_duration) {
super(file_url, download_url, downloaded);
+ checkEmbeddedPicture();
this.id = id;
this.item = item;
this.duration = duration;
@@ -61,12 +65,6 @@ public class FeedMedia extends FeedFile implements Playable {
? null : (Date) playbackCompletionDate.clone();
}
- public FeedMedia(long id, FeedItem item) {
- super();
- this.id = id;
- this.item = item;
- }
-
@Override
public String getHumanReadableIdentifier() {
if (item != null && item.getTitle() != null) {
@@ -227,18 +225,16 @@ public class FeedMedia extends FeedFile implements Playable {
return (this.position > 0);
}
- public FeedImage getImage() {
- if (item != null) {
- return (item.hasItemImageDownloaded()) ? item.getImage() : item.getFeed().getImage();
- }
- return null;
- }
-
@Override
public int describeContents() {
return 0;
}
+ public boolean hasEmbeddedPicture() {
+ Log.d(TAG, "hasEmbeddedPicture() -> " + hasEmbeddedPicture);
+ return this.hasEmbeddedPicture;
+ }
+
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeLong(id);
@@ -415,28 +411,46 @@ public class FeedMedia extends FeedFile implements Playable {
@Override
public Uri getImageUri() {
- final Uri feedImgUri = getFeedImageUri();
-
- if (localFileAvailable()) {
+ if (hasEmbeddedPicture) {
Uri.Builder builder = new Uri.Builder();
- builder.scheme(SCHEME_MEDIA)
- .encodedPath(getLocalMediaUrl());
- if (feedImgUri != null) {
- builder.appendQueryParameter(PARAM_FALLBACK, feedImgUri.toString());
- }
+ builder.scheme(SCHEME_MEDIA).encodedPath(getLocalMediaUrl());
return builder.build();
- } else if (item.hasItemImageDownloaded()) {
- return item.getImage().getImageUri();
} else {
- return feedImgUri;
+ return item.getImageUri();
}
}
- private Uri getFeedImageUri() {
- if (item != null && item.getFeed() != null) {
- return item.getFeed().getImageUri();
- } else {
- return null;
+ @Override
+ public void setDownloaded(boolean downloaded) {
+ super.setDownloaded(downloaded);
+ checkEmbeddedPicture();
+ }
+
+ @Override
+ public void setFile_url(String file_url) {
+ super.setFile_url(file_url);
+ checkEmbeddedPicture();
+ }
+
+ private void checkEmbeddedPicture() {
+ Log.d(TAG, "checkEmbeddedPicture()");
+ if (!localFileAvailable()) {
+ hasEmbeddedPicture = false;
+ return;
+ }
+ MediaMetadataRetriever mmr = new MediaMetadataRetriever();
+ try {
+ mmr.setDataSource(getLocalMediaUrl());
+ byte[] image = mmr.getEmbeddedPicture();
+ if(image != null) {
+ hasEmbeddedPicture = true;
+ }
+ else {
+ hasEmbeddedPicture = false;
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ hasEmbeddedPicture = false;
}
}
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/GpodnetService.java b/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/GpodnetService.java
index db242c3bc..23d89a3a3 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/GpodnetService.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/GpodnetService.java
@@ -726,7 +726,12 @@ public class GpodnetService {
Validate.notNull(body);
ByteArrayOutputStream outputStream;
- int contentLength = (int) body.contentLength();
+ int contentLength = 0;
+ try {
+ contentLength = (int) body.contentLength();
+ } catch (IOException ignore) {
+ // ignore
+ }
if (contentLength > 0) {
outputStream = new ByteArrayOutputStream(contentLength);
} else {
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/download/HttpDownloader.java b/core/src/main/java/de/danoeh/antennapod/core/service/download/HttpDownloader.java
index 7abb6df5e..ac0fe8036 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/download/HttpDownloader.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/download/HttpDownloader.java
@@ -2,7 +2,6 @@ package de.danoeh.antennapod.core.service.download;
import android.util.Log;
-import com.squareup.okhttp.Credentials;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.Request;
import com.squareup.okhttp.Response;
@@ -18,19 +17,20 @@ import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
+import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.SocketTimeoutException;
import java.net.URI;
import java.net.UnknownHostException;
import java.util.Date;
-import de.danoeh.antennapod.core.BuildConfig;
import de.danoeh.antennapod.core.ClientConfig;
import de.danoeh.antennapod.core.R;
import de.danoeh.antennapod.core.feed.FeedImage;
import de.danoeh.antennapod.core.util.DownloadError;
import de.danoeh.antennapod.core.util.StorageUtils;
import de.danoeh.antennapod.core.util.URIUtil;
+import okio.ByteString;
public class HttpDownloader extends Downloader {
private static final String TAG = "HttpDownloader";
@@ -81,11 +81,12 @@ public class HttpDownloader extends Downloader {
if (userInfo != null) {
String[] parts = userInfo.split(":");
if (parts.length == 2) {
- String credentials = Credentials.basic(parts[0], parts[1]);
+ String credentials = encodeCredentials(parts[0], parts[1], "ISO-8859-1");
httpReq.header("Authorization", credentials);
}
} else if (!StringUtils.isEmpty(request.getUsername()) && request.getPassword() != null) {
- String credentials = Credentials.basic(request.getUsername(), request.getPassword());
+ String credentials = encodeCredentials(request.getUsername(), request.getPassword(),
+ "ISO-8859-1");
httpReq.header("Authorization", credentials);
}
@@ -99,13 +100,29 @@ public class HttpDownloader extends Downloader {
Response response = httpClient.newCall(httpReq.build()).execute();
responseBody = response.body();
-
String contentEncodingHeader = response.header("Content-Encoding");
-
- final boolean isGzip = StringUtils.equalsIgnoreCase(contentEncodingHeader, "gzip");
-
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Response code is " + response.code());
+ boolean isGzip = StringUtils.equalsIgnoreCase(contentEncodingHeader, "gzip");
+
+ Log.d(TAG, "Response code is " + response.code());
+
+ if(!response.isSuccessful() && response.code() == HttpURLConnection.HTTP_UNAUTHORIZED) {
+ Log.d(TAG, "Authorization failed, re-trying with UTF-8 encoding");
+ if (userInfo != null) {
+ String[] parts = userInfo.split(":");
+ if (parts.length == 2) {
+ String credentials = encodeCredentials(parts[0], parts[1], "UTF-8");
+ httpReq.header("Authorization", credentials);
+ }
+ } else if (!StringUtils.isEmpty(request.getUsername()) && request.getPassword() != null) {
+ String credentials = encodeCredentials(request.getUsername(), request.getPassword(),
+ "UTF-8");
+ httpReq.header("Authorization", credentials);
+ }
+ response = httpClient.newCall(httpReq.build()).execute();
+ responseBody = response.body();
+ contentEncodingHeader = response.header("Content-Encoding");
+ isGzip = StringUtils.equalsIgnoreCase(contentEncodingHeader, "gzip");
+ }
if(!response.isSuccessful() && response.code() == HttpURLConnection.HTTP_NOT_MODIFIED) {
Log.d(TAG, "Feed '" + request.getSource() + "' not modified since last update, Download canceled");
@@ -151,22 +168,18 @@ public class HttpDownloader extends Downloader {
out = new RandomAccessFile(destination, "rw");
}
-
byte[] buffer = new byte[BUFFER_SIZE];
int count = 0;
request.setStatusMsg(R.string.download_running);
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Getting size of download");
+ Log.d(TAG, "Getting size of download");
request.setSize(responseBody.contentLength() + request.getSoFar());
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Size is " + request.getSize());
+ Log.d(TAG, "Size is " + request.getSize());
if (request.getSize() < 0) {
request.setSize(DownloadStatus.SIZE_UNKNOWN);
}
long freeSpace = StorageUtils.getFreeSpaceAvailable();
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Free space is " + freeSpace);
+ Log.d(TAG, "Free space is " + freeSpace);
if (request.getSize() != DownloadStatus.SIZE_UNKNOWN
&& request.getSize() > freeSpace) {
@@ -174,8 +187,7 @@ public class HttpDownloader extends Downloader {
return;
}
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Starting download");
+ Log.d(TAG, "Starting download");
while (!cancelled
&& (count = connection.read(buffer)) != -1) {
out.write(buffer, 0, count);
@@ -226,15 +238,12 @@ public class HttpDownloader extends Downloader {
}
private void onSuccess() {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Download was successful");
+ Log.d(TAG, "Download was successful");
result.setSuccessful();
}
private void onFail(DownloadError reason, String reasonDetailed) {
- if (BuildConfig.DEBUG) {
- Log.d(TAG, "Download failed");
- }
+ Log.d(TAG, "Download failed");
result.setFailed(reason, reasonDetailed);
if (request.isDeleteOnFailure()) {
cleanup();
@@ -242,8 +251,7 @@ public class HttpDownloader extends Downloader {
}
private void onCancelled() {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Download was cancelled");
+ Log.d(TAG, "Download was cancelled");
result.setCancelled();
cleanup();
}
@@ -256,14 +264,23 @@ public class HttpDownloader extends Downloader {
File dest = new File(request.getDestination());
if (dest.exists()) {
boolean rc = dest.delete();
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Deleted file " + dest.getName() + "; Result: "
+ Log.d(TAG, "Deleted file " + dest.getName() + "; Result: "
+ rc);
} else {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "cleanup() didn't delete file: does not exist.");
+ Log.d(TAG, "cleanup() didn't delete file: does not exist.");
}
}
}
+ public static String encodeCredentials(String username, String password, String charset) {
+ try {
+ String credentials = username + ":" + password;
+ byte[] bytes = credentials.getBytes(charset);
+ String encoded = ByteString.of(bytes).base64();
+ return "Basic " + encoded;
+ } catch (UnsupportedEncodingException e) {
+ throw new AssertionError();
+ }
+ }
+
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java b/core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java
index a7c98c7c6..aafe4071a 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java
@@ -712,6 +712,35 @@ public final class DBReader {
}
/**
+ * Returns credentials based on image URL
+ *
+ * @param context A context that is used for opening a database connection.
+ * @param imageUrl The URL of the image
+ * @return Credentials in format "<Username>:<Password>", empty String if no authorization given
+ */
+ public static String getImageAuthentication(final Context context, final String imageUrl) {
+ Log.d(TAG, "Loading credentials for image with URL " + imageUrl);
+
+ PodDBAdapter adapter = new PodDBAdapter(context);
+ adapter.open();
+ String credentials = getImageAuthentication(context, imageUrl, adapter);
+ adapter.close();
+ return credentials;
+
+ }
+
+ static String getImageAuthentication(final Context context, final String imageUrl, PodDBAdapter adapter) {
+ String credentials = null;
+ Cursor cursor = adapter.getImageAuthenticationCursor(imageUrl);
+ if (cursor.moveToFirst()) {
+ String username = cursor.getString(0);
+ String password = cursor.getString(1);
+ return username + ":" + password;
+ }
+ return "";
+ }
+
+ /**
* Loads a specific FeedItem from the database.
*
* @param context A context that is used for opening a database connection.
diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java b/core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java
index f518a4f5f..229f3d034 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java
@@ -1146,6 +1146,20 @@ public class PodDBAdapter {
return db.rawQuery(query, null);
}
+ public Cursor getImageAuthenticationCursor(final String imageUrl) {
+ final String query = "SELECT " + KEY_USERNAME + "," + KEY_PASSWORD + " FROM "
+ + TABLE_NAME_FEED_IMAGES + " INNER JOIN " + TABLE_NAME_FEEDS + " ON " +
+ TABLE_NAME_FEED_IMAGES + "." + KEY_ID + "=" + TABLE_NAME_FEEDS + "." + KEY_IMAGE + " WHERE "
+ + TABLE_NAME_FEED_IMAGES + "." + KEY_DOWNLOAD_URL + "='" + imageUrl + "' UNION SELECT "
+ + KEY_USERNAME + "," + KEY_PASSWORD + " FROM " + TABLE_NAME_FEED_IMAGES + " INNER JOIN "
+ + TABLE_NAME_FEED_ITEMS + " ON " + TABLE_NAME_FEED_IMAGES + "." + KEY_ID + "=" +
+ TABLE_NAME_FEED_ITEMS + "." + KEY_IMAGE + " INNER JOIN " + TABLE_NAME_FEEDS + " ON "
+ + TABLE_NAME_FEED_ITEMS + "." + KEY_FEED + "=" + TABLE_NAME_FEEDS + "." + KEY_ID + " WHERE "
+ + TABLE_NAME_FEED_IMAGES + "." + KEY_DOWNLOAD_URL + "='" + imageUrl + "'";
+ Log.d(TAG, "Query: " + query);
+ return db.rawQuery(query, null);
+ }
+
public int getQueueSize() {
final String query = String.format("SELECT COUNT(%s) FROM %s", KEY_ID, TABLE_NAME_QUEUE);
Cursor c = db.rawQuery(query, null);