Initial OkHttp conversion

This commit is contained in:
Andrew Rabert 2017-03-12 01:58:17 -05:00
parent 2bd2ec3bf4
commit b42143ed10
26 changed files with 1101 additions and 1676 deletions

View File

@ -35,4 +35,5 @@ dependencies {
compile 'com.esotericsoftware:kryo:4.0.0'
compile 'com.android.support:design:25.2.0'
compile 'com.sothree.slidinguppanel:library:3.3.1'
compile 'com.squareup.okhttp3:okhttp:3.6.0'
}

View File

@ -674,7 +674,7 @@ public class SubsonicFragmentActivity extends SubsonicActivity implements Downlo
editor.putString(Constants.PREFERENCES_KEY_SERVER_NAME + 1, "Demo Server");
editor.putString(Constants.PREFERENCES_KEY_SERVER_URL + 1, "http://demo.subsonic.org");
editor.putString(Constants.PREFERENCES_KEY_USERNAME + 1, "guest");
editor.putString(Constants.PREFERENCES_KEY_USERNAME + 1, "guest5");
editor.putString(Constants.PREFERENCES_KEY_PASSWORD + 1, "guest");
editor.putInt(Constants.PREFERENCES_KEY_SERVER_INSTANCE, 1);
editor.commit();

View File

@ -187,22 +187,6 @@ public class MainFragment extends SelectRecyclerFragment<Integer> {
}.execute();
}
private void rescanServer() {
new LoadingTask<Void>(context, false) {
@Override
protected Void doInBackground() throws Throwable {
MusicService musicService = MusicServiceFactory.getMusicService(context);
musicService.startRescan(context, this);
return null;
}
@Override
protected void done(Void value) {
Util.toast(context, R.string.main_scan_complete);
}
}.execute();
}
private void getLogs() {
try {
final PackageInfo packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);

View File

@ -391,17 +391,6 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Section
}.execute();
}
private void getTopTracks(final String id, final String name, final boolean refresh) {
setTitle(name);
new LoadTask(refresh) {
@Override
protected MusicDirectory load(MusicService service) throws Exception {
return service.getTopTrackSongs(name, 50, context, this);
}
}.execute();
}
private void getAlbumList(final String albumListType, final int size, final boolean refresh) {
if ("random".equals(albumListType)) {
setTitle(R.string.main_albums_random);

View File

@ -106,11 +106,6 @@ public class CachedMusicService implements MusicService {
return result;
}
@Override
public void startRescan(Context context, ProgressListener listener) throws Exception {
musicService.startRescan(context, listener);
}
@Override
public Indexes getIndexes(String musicFolderId, boolean refresh, Context context, ProgressListener progressListener) throws Exception {
checkSettingsChanged(context);
@ -661,11 +656,6 @@ public class CachedMusicService implements MusicService {
}
}
@Override
public MusicDirectory getTopTrackSongs(String artist, int size, Context context, ProgressListener progressListener) throws Exception {
return musicService.getTopTrackSongs(artist, size, context, progressListener);
}
@Override
public User getUser(boolean refresh, String username, Context context, ProgressListener progressListener) throws Exception {
User result = null;
@ -684,82 +674,6 @@ public class CachedMusicService implements MusicService {
return result;
}
@Override
public List<User> getUsers(boolean refresh, Context context, ProgressListener progressListener) throws Exception {
List<User> result = null;
if(!refresh) {
result = FileUtil.deserialize(context, getCacheName(context, "users"), ArrayList.class);
}
if(result == null) {
result = musicService.getUsers(refresh, context, progressListener);
FileUtil.serialize(context, new ArrayList<User>(result), getCacheName(context, "users"));
}
return result;
}
@Override
public void createUser(final User user, Context context, ProgressListener progressListener) throws Exception {
musicService.createUser(user, context, progressListener);
new UserUpdater(context, "") {
@Override
public boolean checkResult(User check) {
return true;
}
@Override
public void updateResult(List<User> users, User result) {
users.add(user);
}
}.execute();
}
@Override
public void updateUser(final User user, Context context, ProgressListener progressListener) throws Exception {
musicService.updateUser(user, context, progressListener);
new UserUpdater(context, user.getUsername()) {
@Override
public void updateResult(List<User> users, User result) {
result.setEmail(user.getEmail());
result.setSettings(user.getSettings());
}
}.execute();
}
@Override
public void deleteUser(String username, Context context, ProgressListener progressListener) throws Exception {
musicService.deleteUser(username, context, progressListener);
new UserUpdater(context, username) {
@Override
public void updateResult(List<User> users, User result) {
users.remove(result);
}
}.execute();
}
@Override
public void changeEmail(String username, final String email, Context context, ProgressListener progressListener) throws Exception {
musicService.changeEmail(username, email, context, progressListener);
// Update cached email for user
new UserUpdater(context, username) {
@Override
public void updateResult(List<User> users, User result) {
result.setEmail(email);
}
}.execute();
}
@Override
public void changePassword(String username, String password, Context context, ProgressListener progressListener) throws Exception {
musicService.changePassword(username, password, context, progressListener);
}
@Override
public Bitmap getBitmap(String url, int size, Context context, ProgressListener progressListener, SilentBackgroundTask task) throws Exception {
return musicService.getBitmap(url, size, context, progressListener, task);

View File

@ -59,15 +59,15 @@ public class DownloadFile implements BufferFile {
private final MediaStoreService mediaStoreService;
private DownloadTask downloadTask;
private boolean save;
private boolean failedDownload = false;
private boolean failedDownload = false;
private int failed = 0;
private int bitRate;
private boolean isPlaying = false;
private boolean saveWhenDone = false;
private boolean completeWhenDone = false;
private Long contentLength = null;
private long currentSpeed = 0;
private boolean rateLimit = false;
private boolean isPlaying = false;
private boolean saveWhenDone = false;
private boolean completeWhenDone = false;
private Long contentLength = null;
private long currentSpeed = 0;
private boolean rateLimit = false;
public DownloadFile(Context context, MusicDirectory.Entry song, boolean save) {
this.context = context;
@ -85,105 +85,105 @@ public class DownloadFile implements BufferFile {
public MusicDirectory.Entry getSong() {
return song;
}
public boolean isSong() {
return song.isSong();
}
public boolean isSong() {
return song.isSong();
}
public Context getContext() {
return context;
}
public Context getContext() {
return context;
}
/**
* Returns the effective bit rate.
*/
public int getBitRate() {
if(!partialFile.exists()) {
bitRate = getActualBitrate();
}
if(!partialFile.exists()) {
bitRate = getActualBitrate();
}
if (bitRate > 0) {
return bitRate;
}
return song.getBitRate() == null ? 160 : song.getBitRate();
}
private int getActualBitrate() {
int br = Util.getMaxBitrate(context);
if(br == 0 && song.getTranscodedSuffix() != null && "mp3".equals(song.getTranscodedSuffix().toLowerCase())) {
if(song.getBitRate() != null) {
br = Math.min(320, song.getBitRate());
} else {
br = 320;
}
} else if(song.getSuffix() != null && (song.getTranscodedSuffix() == null || song.getSuffix().equals(song.getTranscodedSuffix()))) {
// If just downsampling, don't try to upsample (ie: 128 kpbs -> 192 kpbs)
if(song.getBitRate() != null && (br == 0 || br > song.getBitRate())) {
br = song.getBitRate();
}
}
private int getActualBitrate() {
int br = Util.getMaxBitrate(context);
if(br == 0 && song.getTranscodedSuffix() != null && "mp3".equals(song.getTranscodedSuffix().toLowerCase())) {
if(song.getBitRate() != null) {
br = Math.min(320, song.getBitRate());
} else {
br = 320;
}
} else if(song.getSuffix() != null && (song.getTranscodedSuffix() == null || song.getSuffix().equals(song.getTranscodedSuffix()))) {
// If just downsampling, don't try to upsample (ie: 128 kpbs -> 192 kpbs)
if(song.getBitRate() != null && (br == 0 || br > song.getBitRate())) {
br = song.getBitRate();
}
}
return br;
}
public Long getContentLength() {
return contentLength;
}
return br;
}
public long getCurrentSize() {
if(partialFile.exists()) {
return partialFile.length();
} else {
File file = getCompleteFile();
if(file.exists()) {
return file.length();
} else {
return 0L;
}
}
}
public Long getContentLength() {
return contentLength;
}
@Override
public long getEstimatedSize() {
if(contentLength != null) {
return contentLength;
}
public long getCurrentSize() {
if(partialFile.exists()) {
return partialFile.length();
} else {
File file = getCompleteFile();
if(file.exists()) {
return file.length();
} else {
return 0L;
}
}
}
File file = getCompleteFile();
if(file.exists()) {
return file.length();
} else if(song.getDuration() == null) {
return 0;
} else {
int br = (getBitRate() * 1000) / 8;
int duration = song.getDuration();
return br * duration;
}
}
@Override
public long getEstimatedSize() {
if(contentLength != null) {
return contentLength;
}
public long getBytesPerSecond() {
return currentSpeed;
}
File file = getCompleteFile();
if(file.exists()) {
return file.length();
} else if(song.getDuration() == null) {
return 0;
} else {
int br = (getBitRate() * 1000) / 8;
int duration = song.getDuration();
return br * duration;
}
}
public long getBytesPerSecond() {
return currentSpeed;
}
public synchronized void download() {
rateLimit = false;
rateLimit = false;
preDownload();
downloadTask.execute();
}
public synchronized void downloadNow(MusicService musicService) {
rateLimit = true;
preDownload();
downloadTask.setMusicService(musicService);
try {
downloadTask.doInBackground();
} catch(InterruptedException e) {
// This should never be reached
}
rateLimit = true;
preDownload();
downloadTask.setMusicService(musicService);
try {
downloadTask.doInBackground();
} catch(InterruptedException e) {
// This should never be reached
}
}
private void preDownload() {
FileUtil.createDirectoryForParent(saveFile);
FileUtil.createDirectoryForParent(saveFile);
failedDownload = false;
if(!partialFile.exists()) {
bitRate = getActualBitrate();
}
downloadTask = new DownloadTask(context);
if(!partialFile.exists()) {
bitRate = getActualBitrate();
}
downloadTask = new DownloadTask(context);
}
public synchronized void cancelDownload() {
@ -192,16 +192,16 @@ public class DownloadFile implements BufferFile {
}
}
@Override
public File getFile() {
if (saveFile.exists()) {
return saveFile;
} else if (completeFile.exists()) {
return completeFile;
} else {
return partialFile;
}
}
@Override
public File getFile() {
if (saveFile.exists()) {
return saveFile;
} else if (completeFile.exists()) {
return completeFile;
} else {
return partialFile;
}
}
public File getCompleteFile() {
if (saveFile.exists()) {
@ -214,9 +214,9 @@ public class DownloadFile implements BufferFile {
return saveFile;
}
public File getSaveFile() {
return saveFile;
}
public File getSaveFile() {
return saveFile;
}
public File getPartialFile() {
return partialFile;
@ -230,29 +230,29 @@ public class DownloadFile implements BufferFile {
return saveFile.exists() || completeFile.exists();
}
@Override
@Override
public synchronized boolean isWorkDone() {
return saveFile.exists() || (completeFile.exists() && !save) || saveWhenDone || completeWhenDone;
}
@Override
public void onStart() {
setPlaying(true);
}
@Override
public void onStart() {
setPlaying(true);
}
@Override
public void onStop() {
setPlaying(false);
}
@Override
public void onStop() {
setPlaying(false);
}
@Override
public synchronized void onResume() {
if(!isWorkDone() && !isFailedMax() && !isDownloading() && !isDownloadCancelled()) {
download();
}
}
@Override
public synchronized void onResume() {
if(!isWorkDone() && !isFailedMax() && !isDownloading() && !isDownloadCancelled()) {
download();
}
}
public synchronized boolean isDownloading() {
public synchronized boolean isDownloading() {
return downloadTask != null && downloadTask.isRunning();
}
@ -268,28 +268,28 @@ public class DownloadFile implements BufferFile {
return failedDownload;
}
public boolean isFailedMax() {
return failed > MAX_FAILURES;
return failed > MAX_FAILURES;
}
public void delete() {
cancelDownload();
// Remove from mediaStore BEFORE deleting file since it calls getCompleteFile
deleteFromStore();
// Delete all possible versions of the file
File parent = partialFile.getParentFile();
deleteFromStore();
// Delete all possible versions of the file
File parent = partialFile.getParentFile();
Util.delete(partialFile);
Util.delete(completeFile);
Util.delete(saveFile);
FileUtil.deleteEmptyDir(parent);
FileUtil.deleteEmptyDir(parent);
}
public void unpin() {
if (saveFile.exists()) {
// Delete old store entry before renaming to pinned file
// Delete old store entry before renaming to pinned file
saveFile.renameTo(completeFile);
renameInStore(saveFile, completeFile);
renameInStore(saveFile, completeFile);
}
}
@ -319,97 +319,97 @@ public class DownloadFile implements BufferFile {
}
}
}
public void setPlaying(boolean isPlaying) {
try {
if(saveWhenDone && !isPlaying) {
Util.renameFile(completeFile, saveFile);
renameInStore(completeFile, saveFile);
saveWhenDone = false;
} else if(completeWhenDone && !isPlaying) {
if(save) {
Util.renameFile(partialFile, saveFile);
public void setPlaying(boolean isPlaying) {
try {
if(saveWhenDone && !isPlaying) {
Util.renameFile(completeFile, saveFile);
renameInStore(completeFile, saveFile);
saveWhenDone = false;
} else if(completeWhenDone && !isPlaying) {
if(save) {
Util.renameFile(partialFile, saveFile);
saveToStore();
} else {
Util.renameFile(partialFile, completeFile);
saveToStore();
}
completeWhenDone = false;
}
} catch(IOException ex) {
Log.w(TAG, "Failed to rename file " + completeFile + " to " + saveFile, ex);
}
this.isPlaying = isPlaying;
}
public void renamePartial() {
try {
Util.renameFile(partialFile, completeFile);
saveToStore();
} catch(IOException ex) {
Log.w(TAG, "Failed to rename file " + partialFile + " to " + completeFile, ex);
}
}
public boolean getPlaying() {
return isPlaying;
}
private void deleteFromStore() {
try {
mediaStoreService.deleteFromMediaStore(this);
} catch(Exception e) {
Log.w(TAG, "Failed to remove from store", e);
}
}
private void saveToStore() {
if(!Util.getPreferences(context).getBoolean(Constants.PREFERENCES_KEY_HIDE_MEDIA, false)) {
try {
mediaStoreService.saveInMediaStore(this);
} catch(Exception e) {
Log.w(TAG, "Failed to save in media store", e);
}
}
}
private void renameInStore(File start, File end) {
try {
mediaStoreService.renameInMediaStore(start, end);
} catch(Exception e) {
Log.w(TAG, "Failed to rename in store", e);
}
}
} else {
Util.renameFile(partialFile, completeFile);
saveToStore();
}
completeWhenDone = false;
}
} catch(IOException ex) {
Log.w(TAG, "Failed to rename file " + completeFile + " to " + saveFile, ex);
}
this.isPlaying = isPlaying;
}
public void renamePartial() {
try {
Util.renameFile(partialFile, completeFile);
saveToStore();
} catch(IOException ex) {
Log.w(TAG, "Failed to rename file " + partialFile + " to " + completeFile, ex);
}
}
public boolean getPlaying() {
return isPlaying;
}
private void deleteFromStore() {
try {
mediaStoreService.deleteFromMediaStore(this);
} catch(Exception e) {
Log.w(TAG, "Failed to remove from store", e);
}
}
private void saveToStore() {
if(!Util.getPreferences(context).getBoolean(Constants.PREFERENCES_KEY_HIDE_MEDIA, false)) {
try {
mediaStoreService.saveInMediaStore(this);
} catch(Exception e) {
Log.w(TAG, "Failed to save in media store", e);
}
}
}
private void renameInStore(File start, File end) {
try {
mediaStoreService.renameInMediaStore(start, end);
} catch(Exception e) {
Log.w(TAG, "Failed to rename in store", e);
}
}
@Override
public String toString() {
return "DownloadFile (" + song + ")";
}
// Don't do this. Causes infinite loop if two instances of same song
/*@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
// Don't do this. Causes infinite loop if two instances of same song
/*@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
DownloadFile downloadFile = (DownloadFile) o;
return Util.equals(this.getSong(), downloadFile.getSong());
}*/
DownloadFile downloadFile = (DownloadFile) o;
return Util.equals(this.getSong(), downloadFile.getSong());
}*/
private class DownloadTask extends SilentBackgroundTask<Void> {
private MusicService musicService;
private MusicService musicService;
public DownloadTask(Context context) {
super(context);
}
public DownloadTask(Context context) {
super(context);
}
@Override
public Void doInBackground() throws InterruptedException {
InputStream in = null;
FileOutputStream out = null;
PowerManager.WakeLock wakeLock = null;
WifiManager.WifiLock wifiLock = null;
WifiManager.WifiLock wifiLock = null;
try {
if (Util.isScreenLitOnDownload(context)) {
@ -417,9 +417,9 @@ public class DownloadFile implements BufferFile {
wakeLock = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE, toString());
wakeLock.acquire();
}
wifiLock = Util.createWifiLock(context, toString());
wifiLock.acquire();
wifiLock = Util.createWifiLock(context, toString());
wifiLock.acquire();
if (saveFile.exists()) {
Log.i(TAG, saveFile + " already exists. Skipping.");
@ -428,12 +428,12 @@ public class DownloadFile implements BufferFile {
}
if (completeFile.exists()) {
if (save) {
if(isPlaying) {
saveWhenDone = true;
} else {
Util.renameFile(completeFile, saveFile);
renameInStore(completeFile, saveFile);
}
if(isPlaying) {
saveWhenDone = true;
} else {
Util.renameFile(completeFile, saveFile);
renameInStore(completeFile, saveFile);
}
} else {
Log.i(TAG, completeFile + " already exists. Skipping.");
}
@ -441,82 +441,82 @@ public class DownloadFile implements BufferFile {
return null;
}
if(musicService == null) {
musicService = MusicServiceFactory.getMusicService(context);
}
if(musicService == null) {
musicService = MusicServiceFactory.getMusicService(context);
}
// Some devices seem to throw error on partial file which doesn't exist
boolean compare;
try {
compare = (bitRate == 0) || (song.getDuration() == 0) || (partialFile.length() == 0) || (bitRate * song.getDuration() * 1000 / 8) > partialFile.length();
} catch(Exception e) {
compare = true;
}
if(compare) {
// Attempt partial HTTP GET, appending to the file if it exists.
HttpResponse response = musicService.getDownloadInputStream(context, song, partialFile.length(), bitRate, DownloadTask.this);
Header contentLengthHeader = response.getFirstHeader("Content-Length");
if(contentLengthHeader != null) {
String contentLengthString = contentLengthHeader.getValue();
if(contentLengthString != null) {
Log.i(TAG, "Content Length: " + contentLengthString);
contentLength = Long.parseLong(contentLengthString);
}
}
in = response.getEntity().getContent();
boolean partial = response.getStatusLine().getStatusCode() == HttpStatus.SC_PARTIAL_CONTENT;
if (partial) {
Log.i(TAG, "Executed partial HTTP GET, skipping " + partialFile.length() + " bytes");
}
// Some devices seem to throw error on partial file which doesn't exist
boolean compare;
try {
compare = (bitRate == 0) || (song.getDuration() == 0) || (partialFile.length() == 0) || (bitRate * song.getDuration() * 1000 / 8) > partialFile.length();
} catch(Exception e) {
compare = true;
}
if(compare) {
// Attempt partial HTTP GET, appending to the file if it exists.
HttpResponse response = musicService.getDownloadInputStream(context, song, partialFile.length(), bitRate, DownloadTask.this);
Header contentLengthHeader = response.getFirstHeader("Content-Length");
if(contentLengthHeader != null) {
String contentLengthString = contentLengthHeader.getValue();
if(contentLengthString != null) {
Log.i(TAG, "Content Length: " + contentLengthString);
contentLength = Long.parseLong(contentLengthString);
}
}
in = response.getEntity().getContent();
boolean partial = response.getStatusLine().getStatusCode() == HttpStatus.SC_PARTIAL_CONTENT;
if (partial) {
Log.i(TAG, "Executed partial HTTP GET, skipping " + partialFile.length() + " bytes");
}
out = new FileOutputStream(partialFile, partial);
long n = copy(in, out);
Log.i(TAG, "Downloaded " + n + " bytes to " + partialFile);
out.flush();
out.close();
out = new FileOutputStream(partialFile, partial);
long n = copy(in, out);
Log.i(TAG, "Downloaded " + n + " bytes to " + partialFile);
out.flush();
out.close();
if (isCancelled()) {
throw new Exception("Download of '" + song + "' was cancelled");
} else if(partialFile.length() == 0) {
throw new Exception("Download of '" + song + "' failed. File is 0 bytes long.");
}
if (isCancelled()) {
throw new Exception("Download of '" + song + "' was cancelled");
} else if(partialFile.length() == 0) {
throw new Exception("Download of '" + song + "' failed. File is 0 bytes long.");
}
downloadAndSaveCoverArt(musicService);
}
downloadAndSaveCoverArt(musicService);
}
if(isPlaying) {
completeWhenDone = true;
} else {
if(save) {
Util.renameFile(partialFile, saveFile);
} else {
Util.renameFile(partialFile, completeFile);
}
DownloadFile.this.saveToStore();
}
if(isPlaying) {
completeWhenDone = true;
} else {
if(save) {
Util.renameFile(partialFile, saveFile);
} else {
Util.renameFile(partialFile, completeFile);
}
DownloadFile.this.saveToStore();
}
} catch(InterruptedException x) {
throw x;
} catch(FileNotFoundException x) {
Util.delete(completeFile);
Util.delete(saveFile);
if(!isCancelled()) {
failed = MAX_FAILURES + 1;
failedDownload = true;
Log.w(TAG, "Failed to download '" + song + "'.", x);
}
} catch(IOException x) {
Util.delete(completeFile);
Util.delete(saveFile);
if(!isCancelled()) {
failedDownload = true;
Log.w(TAG, "Failed to download '" + song + "'.", x);
}
} catch (Exception x) {
throw x;
} catch(FileNotFoundException x) {
Util.delete(completeFile);
Util.delete(saveFile);
if(!isCancelled()) {
failed = MAX_FAILURES + 1;
failedDownload = true;
Log.w(TAG, "Failed to download '" + song + "'.", x);
}
} catch(IOException x) {
Util.delete(completeFile);
Util.delete(saveFile);
if(!isCancelled()) {
failedDownload = true;
Log.w(TAG, "Failed to download '" + song + "'.", x);
}
} catch (Exception x) {
Util.delete(completeFile);
Util.delete(saveFile);
if (!isCancelled()) {
failed++;
failed++;
failedDownload = true;
Log.w(TAG, "Failed to download '" + song + "'.", x);
}
@ -527,26 +527,26 @@ public class DownloadFile implements BufferFile {
wakeLock.release();
Log.i(TAG, "Released wake lock " + wakeLock);
}
if (wifiLock != null) {
wifiLock.release();
}
}
// Only run these if not interrupted, ie: cancelled
DownloadService downloadService = DownloadService.getInstance();
if(downloadService != null && !isCancelled()) {
new CacheCleaner(context, downloadService).cleanSpace();
checkDownloads();
}
if (wifiLock != null) {
wifiLock.release();
}
}
return null;
// Only run these if not interrupted, ie: cancelled
DownloadService downloadService = DownloadService.getInstance();
if(downloadService != null && !isCancelled()) {
new CacheCleaner(context, downloadService).cleanSpace();
checkDownloads();
}
return null;
}
private void checkDownloads() {
DownloadService downloadService = DownloadService.getInstance();
if(downloadService != null) {
downloadService.checkDownloads();
}
DownloadService downloadService = DownloadService.getInstance();
if(downloadService != null) {
downloadService.checkDownloads();
}
}
@Override
@ -554,18 +554,18 @@ public class DownloadFile implements BufferFile {
return "DownloadTask (" + song + ")";
}
public void setMusicService(MusicService musicService) {
this.musicService = musicService;
}
public void setMusicService(MusicService musicService) {
this.musicService = musicService;
}
private void downloadAndSaveCoverArt(MusicService musicService) throws Exception {
try {
if (song.getCoverArt() != null) {
// Check if album art already exists, don't want to needlessly load into memory
File albumArtFile = FileUtil.getAlbumArtFile(context, song);
if(!albumArtFile.exists()) {
musicService.getCoverArt(context, song, 0, null, null);
}
// Check if album art already exists, don't want to needlessly load into memory
File albumArtFile = FileUtil.getAlbumArtFile(context, song);
if(!albumArtFile.exists()) {
musicService.getCoverArt(context, song, 0, null, null);
}
}
} catch (Exception x) {
Log.e(TAG, "Failed to get cover art.", x);
@ -596,35 +596,35 @@ public class DownloadFile implements BufferFile {
long count = 0;
int n;
long lastLog = System.currentTimeMillis();
long lastCount = 0;
long lastCount = 0;
boolean activeLimit = rateLimit;
boolean activeLimit = rateLimit;
while (!isCancelled() && (n = in.read(buffer)) != -1) {
out.write(buffer, 0, n);
count += n;
lastCount += n;
lastCount += n;
long now = System.currentTimeMillis();
if (now - lastLog > 3000L) { // Only every so often.
Log.i(TAG, "Downloaded " + Util.formatBytes(count) + " of " + song);
currentSpeed = lastCount / ((now - lastLog) / 1000L);
currentSpeed = lastCount / ((now - lastLog) / 1000L);
lastLog = now;
lastCount = 0;
// Re-establish every few seconds whether screen is on or not
if(rateLimit) {
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
if(pm.isScreenOn()) {
activeLimit = true;
} else {
activeLimit = false;
}
}
lastCount = 0;
// Re-establish every few seconds whether screen is on or not
if(rateLimit) {
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
if(pm.isScreenOn()) {
activeLimit = true;
} else {
activeLimit = false;
}
}
}
// If screen is on and rateLimit is true, stop downloading from exhausting bandwidth
if(activeLimit) {
Thread.sleep(10L);
Thread.sleep(10L);
}
}
return count;

View File

@ -48,8 +48,6 @@ public interface MusicService {
List<MusicFolder> getMusicFolders(boolean refresh, Context context, ProgressListener progressListener) throws Exception;
void startRescan(Context context, ProgressListener listener) throws Exception;
Indexes getIndexes(String musicFolderId, boolean refresh, Context context, ProgressListener progressListener) throws Exception;
MusicDirectory getMusicDirectory(String id, String name, boolean refresh, Context context, ProgressListener progressListener) throws Exception;
@ -97,22 +95,8 @@ public interface MusicService {
MusicDirectory getSongsByGenre(String genre, int count, int offset, Context context, ProgressListener progressListener) throws Exception;
MusicDirectory getTopTrackSongs(String artist, int size, Context context, ProgressListener progressListener) throws Exception;
User getUser(boolean refresh, String username, Context context, ProgressListener progressListener) throws Exception;
List<User> getUsers(boolean refresh, Context context, ProgressListener progressListener) throws Exception;
void createUser(User user, Context context, ProgressListener progressListener) throws Exception;
void updateUser(User user, Context context, ProgressListener progressListener) throws Exception;
void deleteUser(String username, Context context, ProgressListener progressListener) throws Exception;
void changeEmail(String username, String email, Context context, ProgressListener progressListener) throws Exception;
void changePassword(String username, String password, Context context, ProgressListener progressListener) throws Exception;
Bitmap getBitmap(String url, int size, Context context, ProgressListener progressListener, SilentBackgroundTask task) throws Exception;
void savePlayQueue(List<MusicDirectory.Entry> songs, MusicDirectory.Entry currentPlaying, int position, Context context, ProgressListener progressListener) throws Exception;

View File

@ -220,11 +220,6 @@ public class OfflineMusicService implements MusicService {
throw new OfflineException(ERRORMSG);
}
@Override
public void startRescan(Context context, ProgressListener listener) throws Exception {
throw new OfflineException(ERRORMSG);
}
@Override
public SearchResult search(SearchCritera criteria, Context context, ProgressListener progressListener) throws Exception {
List<Artist> artists = new ArrayList<Artist>();
@ -543,11 +538,6 @@ public class OfflineMusicService implements MusicService {
throw new OfflineException(ERRORMSG);
}
@Override
public MusicDirectory getTopTrackSongs(String artist, int size, Context context, ProgressListener progressListener) throws Exception {
throw new OfflineException(ERRORMSG);
}
@Override
public MusicDirectory getRandomSongs(int size, String folder, String genre, String startYear, String endYear, Context context, ProgressListener progressListener) throws Exception {
File root = FileUtil.getMusicDirectory(context);
@ -576,36 +566,6 @@ public class OfflineMusicService implements MusicService {
throw new OfflineException(ERRORMSG);
}
@Override
public List<User> getUsers(boolean refresh, Context context, ProgressListener progressListener) throws Exception {
throw new OfflineException(ERRORMSG);
}
@Override
public void createUser(User user, Context context, ProgressListener progressListener) throws Exception {
throw new OfflineException(ERRORMSG);
}
@Override
public void updateUser(User user, Context context, ProgressListener progressListener) throws Exception {
throw new OfflineException(ERRORMSG);
}
@Override
public void deleteUser(String username, Context context, ProgressListener progressListener) throws Exception {
throw new OfflineException(ERRORMSG);
}
@Override
public void changeEmail(String username, String email, Context context, ProgressListener progressListener) throws Exception {
throw new OfflineException(ERRORMSG);
}
@Override
public void changePassword(String username, String password, Context context, ProgressListener progressListener) throws Exception {
throw new OfflineException(ERRORMSG);
}
@Override
public Bitmap getBitmap(String url, int size, Context context, ProgressListener progressListener, SilentBackgroundTask task) throws Exception {
throw new OfflineException(ERRORMSG);

View File

@ -19,7 +19,7 @@
package net.nullsum.audinaut.service.parser;
import java.io.IOException;
import java.io.Reader;
import java.io.InputStream;
import org.xmlpull.v1.XmlPullParser;
@ -36,17 +36,17 @@ import net.nullsum.audinaut.util.Util;
*/
public abstract class AbstractParser {
private static final String TAG = AbstractParser.class.getSimpleName();
private static final String SUBSONIC_RESPONSE = "subsonic-response";
private static final String SUBSONIC = "subsonic";
private static final String SUBSONIC_RESPONSE = "subsonic-response";
private static final String SUBSONIC = "subsonic";
protected final Context context;
protected final int instance;
protected final int instance;
private XmlPullParser parser;
private boolean rootElementFound;
public AbstractParser(Context context, int instance) {
this.context = context;
this.instance = instance;
this.instance = instance;
}
protected Context getContext() {
@ -57,9 +57,9 @@ public abstract class AbstractParser {
int code = getInteger("code");
String message;
switch (code) {
case 0:
message = context.getResources().getString(R.string.parser_server_error, get("message"));
break;
case 0:
message = context.getResources().getString(R.string.parser_server_error, get("message"));
break;
case 20:
message = context.getResources().getString(R.string.parser_upgrade_client);
break;
@ -69,11 +69,11 @@ public abstract class AbstractParser {
case 40:
message = context.getResources().getString(R.string.parser_not_authenticated);
break;
case 41:
Util.setBlockTokenUse(context, instance, true);
case 41:
Util.setBlockTokenUse(context, instance, true);
// Throw IOException so RESTMusicService knows to retry
throw new IOException();
// Throw IOException so RESTMusicService knows to retry
throw new IOException();
case 50:
message = context.getResources().getString(R.string.parser_not_authorized);
break;
@ -128,18 +128,18 @@ public abstract class AbstractParser {
return s == null ? null : Float.valueOf(s);
}
protected void init(Reader reader) throws Exception {
protected void init(InputStream inputStream) throws Exception {
parser = Xml.newPullParser();
parser.setInput(reader);
parser.setInput(inputStream, "UTF-8");
rootElementFound = false;
}
protected int nextParseEvent() throws Exception {
try {
return parser.next();
} catch(Exception e) {
throw e;
}
try {
return parser.next();
} catch(Exception e) {
throw e;
}
}
protected String getElementName() {

View File

@ -24,7 +24,7 @@ import net.nullsum.audinaut.domain.MusicDirectory;
import net.nullsum.audinaut.util.ProgressListener;
import org.xmlpull.v1.XmlPullParser;
import java.io.Reader;
import java.io.InputStream;
/**
* @author Sindre Mehus
@ -35,8 +35,8 @@ public class EntryListParser extends MusicDirectoryEntryParser {
super(context, instance);
}
public MusicDirectory parse(Reader reader, ProgressListener progressListener) throws Exception {
init(reader);
public MusicDirectory parse(InputStream inputStream, ProgressListener progressListener) throws Exception {
init(inputStream);
MusicDirectory dir = new MusicDirectory();
int eventType;
@ -63,4 +63,4 @@ public class EntryListParser extends MusicDirectoryEntryParser {
return dir;
}
}
}

View File

@ -21,7 +21,7 @@ package net.nullsum.audinaut.service.parser;
import android.content.Context;
import org.xmlpull.v1.XmlPullParser;
import java.io.Reader;
import java.io.InputStream;
/**
* @author Sindre Mehus
@ -32,9 +32,9 @@ public class ErrorParser extends AbstractParser {
super(context, instance);
}
public void parse(Reader reader) throws Exception {
public void parse(InputStream inputStream) throws Exception {
init(reader);
init(inputStream);
int eventType;
do {
@ -46,4 +46,4 @@ public class ErrorParser extends AbstractParser {
validate();
}
}
}

View File

@ -27,10 +27,8 @@ import net.nullsum.audinaut.util.ProgressListener;
import org.xmlpull.v1.XmlPullParser;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
@ -38,56 +36,19 @@ import java.util.List;
* @author Joshua Bahnsen
*/
public class GenreParser extends AbstractParser {
private static final String TAG = GenreParser.class.getSimpleName();
private static final String TAG = GenreParser.class.getSimpleName();
public GenreParser(Context context, int instance) {
super(context, instance);
}
super(context, instance);
}
public List<Genre> parse(InputStream inputStream, ProgressListener progressListener) throws Exception {
init(inputStream);
public List<Genre> parse(Reader reader, ProgressListener progressListener) throws Exception {
List<Genre> result = new ArrayList<Genre>();
StringReader sr = null;
try {
BufferedReader br = new BufferedReader(reader);
String xml = null;
String line = null;
while ((line = br.readLine()) != null) {
if (xml == null) {
xml = line;
} else {
xml += line;
}
}
br.close();
// Replace double escaped ampersand (&amp;apos;)
xml = xml.replaceAll("(?:&amp;)(amp;|lt;|gt;|#37;|apos;)", "&$1");
// Replace unescaped ampersand
xml = xml.replaceAll("&(?!amp;|lt;|gt;|#37;|apos;)", "&amp;");
// Replace unescaped percent symbol
// No replacements for <> at this time
xml = xml.replaceAll("%", "&#37;");
xml = xml.replaceAll("'", "&apos;");
sr = new StringReader(xml);
} catch (IOException ioe) {
Log.e(TAG, "Error parsing Genre XML", ioe);
}
if (sr == null) {
Log.w(TAG, "Unable to parse Genre XML, returning empty list");
return result;
}
init(sr);
Genre genre = null;
int eventType;
do {
eventType = nextParseEvent();
@ -95,28 +56,28 @@ public class GenreParser extends AbstractParser {
String name = getElementName();
if ("genre".equals(name)) {
genre = new Genre();
genre.setSongCount(getInteger("songCount"));
genre.setAlbumCount(getInteger("albumCount"));
genre.setSongCount(getInteger("songCount"));
genre.setAlbumCount(getInteger("albumCount"));
} else if ("error".equals(name)) {
handleError();
} else {
genre = null;
genre = null;
}
} else if (eventType == XmlPullParser.TEXT) {
if (genre != null) {
String value = getText();
if (genre != null) {
genre.setName(Html.fromHtml(value).toString());
genre.setIndex(value.substring(0, 1));
result.add(genre);
genre = null;
}
String value = getText();
if (genre != null) {
genre.setName(Html.fromHtml(value).toString());
genre.setIndex(value.substring(0, 1));
result.add(genre);
genre = null;
}
}
}
} while (eventType != XmlPullParser.END_DOCUMENT);
validate();
return Genre.GenreComparator.sort(result);
}
}

View File

@ -18,7 +18,7 @@
*/
package net.nullsum.audinaut.service.parser;
import java.io.Reader;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.ArrayList;
@ -47,9 +47,9 @@ public class IndexesParser extends MusicDirectoryEntryParser {
super(context, instance);
}
public Indexes parse(Reader reader, ProgressListener progressListener) throws Exception {
public Indexes parse(InputStream inputStream, ProgressListener progressListener) throws Exception {
long t0 = System.currentTimeMillis();
init(reader);
init(inputStream);
List<Artist> artists = new ArrayList<Artist>();
List<Artist> shortcuts = new ArrayList<Artist>();

View File

@ -27,7 +27,7 @@ import net.nullsum.audinaut.util.ProgressListener;
import net.nullsum.audinaut.util.Util;
import org.xmlpull.v1.XmlPullParser;
import java.io.Reader;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
@ -44,8 +44,8 @@ public class MusicDirectoryParser extends MusicDirectoryEntryParser {
super(context, instance);
}
public MusicDirectory parse(String artist, Reader reader, ProgressListener progressListener) throws Exception {
init(reader);
public MusicDirectory parse(String artist, InputStream inputStream, ProgressListener progressListener) throws Exception {
init(inputStream);
MusicDirectory dir = new MusicDirectory();
int eventType;

View File

@ -18,7 +18,7 @@
*/
package net.nullsum.audinaut.service.parser;
import java.io.Reader;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
@ -35,11 +35,11 @@ import net.nullsum.audinaut.util.ProgressListener;
public class MusicFoldersParser extends AbstractParser {
public MusicFoldersParser(Context context, int instance) {
super(context, instance);
}
super(context, instance);
}
public List<MusicFolder> parse(Reader reader, ProgressListener progressListener) throws Exception {
init(reader);
public List<MusicFolder> parse(InputStream inputStream, ProgressListener progressListener) throws Exception {
init(inputStream);
List<MusicFolder> result = new ArrayList<MusicFolder>();
int eventType;
@ -62,4 +62,4 @@ public class MusicFoldersParser extends AbstractParser {
return result;
}
}
}

View File

@ -19,7 +19,7 @@ import android.content.Context;
import org.xmlpull.v1.XmlPullParser;
import java.io.Reader;
import java.io.InputStream;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Locale;
@ -36,8 +36,8 @@ public class PlayQueueParser extends MusicDirectoryEntryParser {
super(context, instance);
}
public PlayerQueue parse(Reader reader, ProgressListener progressListener) throws Exception {
init(reader);
public PlayerQueue parse(InputStream inputStream, ProgressListener progressListener) throws Exception {
init(inputStream);
PlayerQueue state = new PlayerQueue();
String currentId = null;

View File

@ -24,7 +24,7 @@ import net.nullsum.audinaut.domain.MusicDirectory;
import net.nullsum.audinaut.util.ProgressListener;
import org.xmlpull.v1.XmlPullParser;
import java.io.Reader;
import java.io.InputStream;
/**
* @author Sindre Mehus
@ -35,8 +35,8 @@ public class PlaylistParser extends MusicDirectoryEntryParser {
super(context, instance);
}
public MusicDirectory parse(Reader reader, ProgressListener progressListener) throws Exception {
init(reader);
public MusicDirectory parse(InputStream inputStream, ProgressListener progressListener) throws Exception {
init(inputStream);
MusicDirectory dir = new MusicDirectory();
int eventType;
@ -60,4 +60,4 @@ public class PlaylistParser extends MusicDirectoryEntryParser {
return dir;
}
}
}

View File

@ -24,7 +24,7 @@ import net.nullsum.audinaut.domain.Playlist;
import net.nullsum.audinaut.util.ProgressListener;
import org.xmlpull.v1.XmlPullParser;
import java.io.Reader;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
@ -37,8 +37,8 @@ public class PlaylistsParser extends AbstractParser {
super(context, instance);
}
public List<Playlist> parse(Reader reader, ProgressListener progressListener) throws Exception {
init(reader);
public List<Playlist> parse(InputStream inputStream, ProgressListener progressListener) throws Exception {
init(inputStream);
List<Playlist> result = new ArrayList<Playlist>();
int eventType;
@ -68,4 +68,4 @@ public class PlaylistsParser extends AbstractParser {
return Playlist.PlaylistComparator.sort(result);
}
}
}

View File

@ -24,7 +24,7 @@ import net.nullsum.audinaut.domain.MusicDirectory;
import net.nullsum.audinaut.util.ProgressListener;
import org.xmlpull.v1.XmlPullParser;
import java.io.Reader;
import java.io.InputStream;
/**
* @author Sindre Mehus
@ -35,8 +35,8 @@ public class RandomSongsParser extends MusicDirectoryEntryParser {
super(context, instance);
}
public MusicDirectory parse(Reader reader, ProgressListener progressListener) throws Exception {
init(reader);
public MusicDirectory parse(InputStream inputStream, ProgressListener progressListener) throws Exception {
init(inputStream);
MusicDirectory dir = new MusicDirectory();
int eventType;
@ -57,4 +57,4 @@ public class RandomSongsParser extends MusicDirectoryEntryParser {
return dir;
}
}
}

View File

@ -1,56 +0,0 @@
/*
This file is part of Subsonic.
Subsonic 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
(at your option) any later version.
Subsonic 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 Subsonic. If not, see <http://www.gnu.org/licenses/>.
Copyright 2014 (C) Scott Jackson
*/
package net.nullsum.audinaut.service.parser;
import android.content.Context;
import org.xmlpull.v1.XmlPullParser;
import java.io.Reader;
import net.nullsum.audinaut.R;
import net.nullsum.audinaut.util.ProgressListener;
public class ScanStatusParser extends AbstractParser {
public ScanStatusParser(Context context, int instance) {
super(context, instance);
}
public boolean parse(Reader reader, ProgressListener progressListener) throws Exception {
init(reader);
Boolean started = null;
int eventType;
do {
eventType = nextParseEvent();
if (eventType == XmlPullParser.START_TAG) {
String name = getElementName();
if("status".equals(name)) {
started = getBoolean("started");
String msg = context.getResources().getString(R.string.parser_scan_count, getInteger("count"));
progressListener.updateProgress(msg);
} else if ("error".equals(name)) {
handleError();
}
}
} while (eventType != XmlPullParser.END_DOCUMENT);
validate();
return started != null && started;
}
}

View File

@ -26,7 +26,7 @@ import net.nullsum.audinaut.domain.Artist;
import net.nullsum.audinaut.util.ProgressListener;
import org.xmlpull.v1.XmlPullParser;
import java.io.Reader;
import java.io.InputStream;
import java.util.List;
import java.util.ArrayList;
@ -39,8 +39,8 @@ public class SearchResult2Parser extends MusicDirectoryEntryParser {
super(context, instance);
}
public SearchResult parse(Reader reader, ProgressListener progressListener) throws Exception {
init(reader);
public SearchResult parse(InputStream inputStream, ProgressListener progressListener) throws Exception {
init(inputStream);
List<Artist> artists = new ArrayList<Artist>();
List<MusicDirectory.Entry> albums = new ArrayList<MusicDirectory.Entry>();
@ -72,4 +72,4 @@ public class SearchResult2Parser extends MusicDirectoryEntryParser {
return new SearchResult(artists, albums, songs);
}
}
}

View File

@ -1,65 +0,0 @@
/*
This file is part of Subsonic.
Subsonic 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
(at your option) any later version.
Subsonic 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 Subsonic. If not, see <http://www.gnu.org/licenses/>.
Copyright 2009 (C) Sindre Mehus
*/
package net.nullsum.audinaut.service.parser;
import android.content.Context;
import net.nullsum.audinaut.R;
import net.nullsum.audinaut.domain.MusicDirectory;
import net.nullsum.audinaut.domain.SearchResult;
import net.nullsum.audinaut.domain.Artist;
import net.nullsum.audinaut.util.ProgressListener;
import org.xmlpull.v1.XmlPullParser;
import java.io.Reader;
import java.util.Collections;
import java.util.List;
import java.util.ArrayList;
/**
* @author Sindre Mehus
*/
public class SearchResultParser extends MusicDirectoryEntryParser {
public SearchResultParser(Context context, int instance) {
super(context, instance);
}
public SearchResult parse(Reader reader, ProgressListener progressListener) throws Exception {
init(reader);
List<MusicDirectory.Entry> songs = new ArrayList<MusicDirectory.Entry>();
int eventType;
do {
eventType = nextParseEvent();
if (eventType == XmlPullParser.START_TAG) {
String name = getElementName();
if ("match".equals(name)) {
songs.add(parseEntry(""));
} else if ("error".equals(name)) {
handleError();
}
}
} while (eventType != XmlPullParser.END_DOCUMENT);
validate();
return new SearchResult(Collections.<Artist>emptyList(), Collections.<MusicDirectory.Entry>emptyList(), songs);
}
}

View File

@ -1,58 +0,0 @@
/*
This file is part of Subsonic.
Subsonic 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
(at your option) any later version.
Subsonic 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 Subsonic. If not, see <http://www.gnu.org/licenses/>.
Copyright 2016 (C) Scott Jackson
*/
package net.nullsum.audinaut.service.parser;
import android.content.Context;
import org.xmlpull.v1.XmlPullParser;
import java.io.Reader;
import net.nullsum.audinaut.domain.MusicDirectory;
import net.nullsum.audinaut.util.ProgressListener;
public class TopSongsParser extends MusicDirectoryEntryParser {
public TopSongsParser(Context context, int instance) {
super(context, instance);
}
public MusicDirectory parse(Reader reader, ProgressListener progressListener) throws Exception {
init(reader);
MusicDirectory dir = new MusicDirectory();
int eventType;
int trackNumber = 1;
do {
eventType = nextParseEvent();
if (eventType == XmlPullParser.START_TAG) {
String name = getElementName();
if ("song".equals(name)) {
MusicDirectory.Entry entry = parseEntry("");
entry.setTrack(trackNumber);
dir.addChild(entry);
trackNumber++;
} else if ("error".equals(name)) {
handleError();
}
}
} while (eventType != XmlPullParser.END_DOCUMENT);
validate();
return dir;
}
}

View File

@ -20,7 +20,7 @@ import android.util.Log;
import org.xmlpull.v1.XmlPullParser;
import java.io.Reader;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
@ -39,8 +39,8 @@ public class UserParser extends AbstractParser {
super(context, instance);
}
public List<User> parse(Reader reader, ProgressListener progressListener) throws Exception {
init(reader);
public List<User> parse(InputStream inputStream, ProgressListener progressListener) throws Exception {
init(inputStream);
List<User> result = new ArrayList<User>();
List<MusicFolder> musicFolders = null;
User user = null;

View File

@ -528,13 +528,6 @@ public final class Util {
}
}
public static String getContentType(HttpEntity entity) {
if (entity == null || entity.getContentType() == null) {
return null;
}
return entity.getContentType().getValue();
}
public static boolean isFirstLevelArtist(Context context) {
SharedPreferences prefs = getPreferences(context);
return prefs.getBoolean(Constants.PREFERENCES_KEY_FIRST_LEVEL_ARTIST + getActiveServer(context), true);