/*
* Copyright 2008-2013, ETH Zürich, Samuel Welten, Michael Kuhn, Tobias Langner,
* Sandro Affentranger, Lukas Bossard, Michael Grob, Rahul Jain,
* Dominic Langenegger, Sonia Mayor Alonso, Roger Odermatt, Tobias Schlueter,
* Yannick Stucki, Sebastian Wendland, Samuel Zehnder, Samuel Zihlmann,
* Samuel Zweifel
*
* This file is part of Jukefox.
*
* Jukefox is free software: you can redistribute it and/or modify it under the
* terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or any later version. Jukefox is
* distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* Jukefox. If not, see <http://www.gnu.org/licenses/>.
*/
package ch.ethz.dcg.jukefox.manager.libraryimport;
import java.io.File;
import java.io.FilenameFilter;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import org.apache.http.impl.client.DefaultHttpClient;
import ch.ethz.dcg.jukefox.commons.utils.JoinableThread;
import ch.ethz.dcg.jukefox.commons.utils.Log;
import ch.ethz.dcg.jukefox.data.HttpHelper;
import ch.ethz.dcg.jukefox.model.AbstractCollectionModelManager;
import ch.ethz.dcg.jukefox.model.collection.AlbumStatus;
import ch.ethz.dcg.jukefox.model.collection.CompleteAlbum;
import ch.ethz.dcg.jukefox.model.libraryimport.ImportState;
import ch.ethz.dcg.jukefox.model.providers.AlbumProvider;
import ch.ethz.dcg.jukefox.model.providers.ModifyProvider;
import ch.ethz.dcg.jukefox.model.providers.OtherDataProvider;
public abstract class AbstractAlbumCoverFetcherThread extends JoinableThread implements ICoordinateFetcherConsumer {
public static final String TAG = AbstractAlbumCoverFetcherThread.class.getSimpleName();
public static class AlbumFetcherResult {
private final int albumId;
private final String highResPath;
private final String lowResPath;
private final int color;
private final AlbumStatus status;
public AlbumFetcherResult(String highResPath, String lowResPath, int color, AlbumStatus status, int albumId) {
this.albumId = albumId;
this.highResPath = highResPath;
this.lowResPath = lowResPath;
this.color = color;
this.status = status;
}
public String getHighResPath() {
return highResPath;
}
public String getLowResPath() {
return lowResPath;
}
public int getColor() {
return color;
}
public AlbumStatus getStatus() {
return status;
}
public int getAlbumId() {
return albumId;
}
}
protected AlbumProvider albumProvider;
protected ModifyProvider modifyProvider;
protected OtherDataProvider otherDataProvider;
protected FilenameFilter imageFilter;
protected DefaultHttpClient httpClient;
protected BlockingQueue<Integer> inQueue;
protected boolean producerFinished;
protected ImportState importState;
protected int fetchedNr;
protected int numberOfAlbums;
public AbstractAlbumCoverFetcherThread(AbstractCollectionModelManager collectionModelManager,
List<AlbumCoverFetcherListener> listeners, ImportState importState) {
this.albumProvider = collectionModelManager.getAlbumProvider();
this.otherDataProvider = collectionModelManager.getOtherDataProvider();
this.modifyProvider = collectionModelManager.getModifyProvider();
this.inQueue = new LinkedBlockingQueue<Integer>();
this.importState = importState;
createFileNameFilter();
initializeHttpClient();
}
protected void initializeHttpClient() {
// Initialize Http client
httpClient = HttpHelper.createHttpClientWithDefaultSettings();
}
private void createFileNameFilter() {
imageFilter = new FilenameFilter() {
@Override
public boolean accept(File dir, String filename) {
if (filename == null) {
return false;
}
String lowercase = filename.toLowerCase();
if (lowercase.endsWith("cover.jpg") || lowercase.endsWith("cover.png")
|| lowercase.endsWith("folder.png") || lowercase.endsWith("folder.jpg")
|| lowercase.endsWith("albumart.png") || lowercase.endsWith("albumart.jpg")) {
return true;
}
return false;
}
};
}
@Override
public void run() {
Set<AlbumFetcherResult> results = new HashSet<AlbumFetcherResult>();
while (inQueue.size() > 0 || !isProducerFinished()) {
if (importState.shouldAbortImport()) {
importState.setCoordinatesProgress(1, 1, "fetched album covers");
return;
}
if (!isReadyToDownloadCovers()) {
break;
}
try {
fetchedNr++;
Integer albumId = inQueue.poll(1, TimeUnit.SECONDS);
if (albumId != null) {
CompleteAlbum album = albumProvider.getCompleteAlbum(albumId);
importState.setCoversProgress(fetchedNr, numberOfAlbums, "Getting cover for: " + album.getName());
Log.v(TAG, "processAlbum: " + album.getName());
AlbumFetcherResult result = getAlbumCovers(album);
if (result != null) {
results.add(result);
// modifyProvider.insertAlbumArtInfo(album, result.getHighResPath(), result.getLowResPath(),
// result.getColor(), result.getStatus());
}
}
} catch (Exception e) {
// TODO: should we react differently to (repeated?)
// save-exceptions?
Log.w(TAG, e);
}
}
// execute update Batch
modifyProvider.batchInsertAlbumArtInfo(results);
importState.setCoversProgress(1, 1, "fetched album covers");
// Log.v(TAG, "AlbumCoverFetcher completed()");
}
protected abstract boolean isReadyToDownloadCovers();
public boolean isProducerFinished() {
return producerFinished;
}
public void setProducerFinished(boolean producerFinished) {
this.producerFinished = producerFinished;
}
/**
*
* @param album
* Album for which the album art has to be fetched
* @return an Array with the paths to two files: 1. The high Resolution album art, 2. the low resolution album art
* @throws Exception
*/
protected abstract AlbumFetcherResult getAlbumCovers(CompleteAlbum album) throws Exception;
@Override
public BlockingQueue<Integer> getQueue() {
return inQueue;
}
@Override
public void setNumberOfAlbums(int n) {
this.numberOfAlbums = n;
}
}