aboutsummaryrefslogtreecommitdiff
path: root/subsonic-android/src
diff options
context:
space:
mode:
Diffstat (limited to 'subsonic-android/src')
-rw-r--r--subsonic-android/src/github/daneren2005/dsub/activity/MainActivity.java8
-rw-r--r--subsonic-android/src/github/daneren2005/dsub/fragments/DownloadFragment.java19
-rw-r--r--subsonic-android/src/github/daneren2005/dsub/fragments/MainFragment.java90
-rw-r--r--subsonic-android/src/github/daneren2005/dsub/service/DownloadFile.java14
-rw-r--r--subsonic-android/src/github/daneren2005/dsub/service/DownloadServiceImpl.java8
-rw-r--r--subsonic-android/src/github/daneren2005/dsub/service/OfflineMusicService.java13
-rw-r--r--subsonic-android/src/github/daneren2005/dsub/service/RESTMusicService.java51
-rw-r--r--subsonic-android/src/github/daneren2005/dsub/service/StreamProxy.java12
-rw-r--r--subsonic-android/src/github/daneren2005/dsub/util/Constants.java1
-rw-r--r--subsonic-android/src/github/daneren2005/dsub/util/Util.java37
10 files changed, 192 insertions, 61 deletions
diff --git a/subsonic-android/src/github/daneren2005/dsub/activity/MainActivity.java b/subsonic-android/src/github/daneren2005/dsub/activity/MainActivity.java
index 2709db46..1095d8e3 100644
--- a/subsonic-android/src/github/daneren2005/dsub/activity/MainActivity.java
+++ b/subsonic-android/src/github/daneren2005/dsub/activity/MainActivity.java
@@ -40,6 +40,7 @@ public class MainActivity extends SubsonicActivity {
private static final String TAG = MainActivity.class.getSimpleName();
private static boolean infoDialogDisplayed;
private ScheduledExecutorService executorService;
+ private View bottomBar;
private View coverArtView;
private TextView trackView;
private TextView artistView;
@@ -61,7 +62,7 @@ public class MainActivity extends SubsonicActivity {
setContentView(R.layout.main);
loadSettings();
- View bottomBar = findViewById(R.id.bottom_bar);
+ bottomBar = findViewById(R.id.bottom_bar);
bottomBar.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Intent intent = new Intent();
@@ -248,12 +249,11 @@ public class MainActivity extends SubsonicActivity {
DownloadFile current = getDownloadService().getCurrentPlaying();
if(current == null) {
- trackView.setText("Title");
- artistView.setText("Artist");
- getImageLoader().loadImage(coverArtView, null, false, false);
+ bottomBar.setVisibility(View.GONE);
return;
}
+ bottomBar.setVisibility(View.VISIBLE);
MusicDirectory.Entry song = current.getSong();
trackView.setText(song.getTitle());
artistView.setText(song.getArtist());
diff --git a/subsonic-android/src/github/daneren2005/dsub/fragments/DownloadFragment.java b/subsonic-android/src/github/daneren2005/dsub/fragments/DownloadFragment.java
index 9bcb4a05..19fccfc3 100644
--- a/subsonic-android/src/github/daneren2005/dsub/fragments/DownloadFragment.java
+++ b/subsonic-android/src/github/daneren2005/dsub/fragments/DownloadFragment.java
@@ -530,6 +530,23 @@ public class DownloadFragment extends SubsonicFragment implements OnGestureListe
intent.putExtra(Constants.INTENT_EXTRA_NAME_PARENT_ID, entry.getGrandParent());
intent.putExtra(Constants.INTENT_EXTRA_NAME_PARENT_NAME, entry.getArtist());
}
+
+ if(Util.isOffline(context)) {
+ try {
+ // This should only be succesful if this is a online song in offline mode
+ Integer.parseInt(entry.getParent());
+ String root = FileUtil.getMusicDirectory(context).getPath();
+ String id = root + "/" + entry.getPath();
+ id = id.substring(0, id.lastIndexOf("/"));
+ intent.putExtra(Constants.INTENT_EXTRA_NAME_ID, id);
+ id = id.substring(0, id.lastIndexOf("/"));
+ intent.putExtra(Constants.INTENT_EXTRA_NAME_PARENT_ID, id);
+ intent.putExtra(Constants.INTENT_EXTRA_NAME_PARENT_NAME, entry.getArtist());
+ } catch(Exception e) {
+ // Do nothing, entry.getParent() is fine
+ }
+ }
+
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
Util.startActivityWithoutTransition(context, intent);
return true;
@@ -820,12 +837,12 @@ public class DownloadFragment extends SubsonicFragment implements OnGestureListe
}
private void toggleFullscreenAlbumArt() {
- scrollToCurrent();
if (playlistFlipper.getDisplayedChild() == 1) {
playlistFlipper.setInAnimation(AnimationUtils.loadAnimation(context, R.anim.push_down_in));
playlistFlipper.setOutAnimation(AnimationUtils.loadAnimation(context, R.anim.push_down_out));
playlistFlipper.setDisplayedChild(0);
} else {
+ scrollToCurrent();
playlistFlipper.setInAnimation(AnimationUtils.loadAnimation(context, R.anim.push_up_in));
playlistFlipper.setOutAnimation(AnimationUtils.loadAnimation(context, R.anim.push_up_out));
playlistFlipper.setDisplayedChild(1);
diff --git a/subsonic-android/src/github/daneren2005/dsub/fragments/MainFragment.java b/subsonic-android/src/github/daneren2005/dsub/fragments/MainFragment.java
index 45d6eb49..bf8cfdbb 100644
--- a/subsonic-android/src/github/daneren2005/dsub/fragments/MainFragment.java
+++ b/subsonic-android/src/github/daneren2005/dsub/fragments/MainFragment.java
@@ -14,6 +14,7 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
+import android.widget.CheckBox;
import android.widget.ListView;
import android.widget.TextView;
import github.daneren2005.dsub.R;
@@ -207,7 +208,7 @@ public class MainFragment extends SubsonicFragment {
if(isOffline) {
int count = Util.offlineScrobblesCount(context);
if(count > 0){
- showOfflineScrobblesDialog(count);
+ showOfflineSyncDialog(count);
}
}
}
@@ -228,36 +229,33 @@ public class MainFragment extends SubsonicFragment {
}
}
- private void showOfflineScrobblesDialog(final int count) {
+ private void showOfflineSyncDialog(final int scrobbleCount) {
+ String syncDefault = Util.getSyncDefault(context);
+ if(syncDefault != null) {
+ if("sync".equals(syncDefault)) {
+ syncOffline(scrobbleCount);
+ return;
+ } else if("delete".equals(syncDefault)) {
+ deleteOffline();
+ return;
+ }
+ }
+
+ View checkBoxView = context.getLayoutInflater().inflate(R.layout.sync_dialog, null);
+ final CheckBox checkBox = (CheckBox)checkBoxView.findViewById(R.id.sync_default);
+
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setIcon(android.R.drawable.ic_dialog_info)
- .setTitle(R.string.offline_scrobbles_dialog_title)
- .setMessage(R.string.offline_scrobbles_dialog_message)
+ .setTitle(R.string.offline_sync_dialog_title)
+ .setMessage(context.getResources().getString(R.string.offline_sync_dialog_message, scrobbleCount))
+ .setView(checkBoxView)
.setPositiveButton(R.string.common_ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
- new SilentBackgroundTask<Integer>(context) {
- @Override
- protected Integer doInBackground() throws Throwable {
- MusicService musicService = MusicServiceFactory.getMusicService(context);
- return musicService.processOfflineScrobbles(context, null);
- }
-
- @Override
- protected void done(Integer result) {
- if(result == count) {
- Util.toast(context, context.getResources().getString(R.string.offline_scrobbles_success, result));
- } else {
- Util.toast(context, context.getResources().getString(R.string.offline_scrobbles_partial, result, count));
- }
- }
-
- @Override
- protected void error(Throwable error) {
- String msg = context.getResources().getString(R.string.offline_scrobbles_error) + " " + getErrorMessage(error);
- Util.toast(context, msg);
- }
- }.execute();
+ if(checkBox.isChecked()) {
+ Util.setSyncDefault(context, "sync");
+ }
+ syncOffline(scrobbleCount);
}
}).setNeutralButton(R.string.common_cancel, new DialogInterface.OnClickListener() {
@Override
@@ -267,15 +265,45 @@ public class MainFragment extends SubsonicFragment {
}).setNegativeButton(R.string.common_delete, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
- dialogInterface.dismiss();
- SharedPreferences.Editor offline = Util.getOfflineSync(context).edit();
- offline.putInt(Constants.OFFLINE_SCROBBLE_COUNT, 0);
- offline.commit();
+ if(checkBox.isChecked()) {
+ Util.setSyncDefault(context, "delete");
+ }
+ deleteOffline();
}
});
builder.create().show();
- }
+ }
+
+ private void syncOffline(final int scrobbleCount) {
+ new SilentBackgroundTask<Integer>(context) {
+ @Override
+ protected Integer doInBackground() throws Throwable {
+ MusicService musicService = MusicServiceFactory.getMusicService(context);
+ return musicService.processOfflineScrobbles(context, null);
+ }
+
+ @Override
+ protected void done(Integer result) {
+ if(result == scrobbleCount) {
+ Util.toast(context, context.getResources().getString(R.string.offline_sync_success, result));
+ } else {
+ Util.toast(context, context.getResources().getString(R.string.offline_sync_partial, result, scrobbleCount));
+ }
+ }
+
+ @Override
+ protected void error(Throwable error) {
+ String msg = context.getResources().getString(R.string.offline_sync_error) + " " + getErrorMessage(error);
+ Util.toast(context, msg);
+ }
+ }.execute();
+ }
+ private void deleteOffline() {
+ SharedPreferences.Editor offline = Util.getOfflineSync(context).edit();
+ offline.putInt(Constants.OFFLINE_SCROBBLE_COUNT, 0);
+ offline.commit();
+ }
private void showAboutDialog() {
try {
diff --git a/subsonic-android/src/github/daneren2005/dsub/service/DownloadFile.java b/subsonic-android/src/github/daneren2005/dsub/service/DownloadFile.java
index 3fa38bdf..5ab7ad70 100644
--- a/subsonic-android/src/github/daneren2005/dsub/service/DownloadFile.java
+++ b/subsonic-android/src/github/daneren2005/dsub/service/DownloadFile.java
@@ -34,6 +34,7 @@ import github.daneren2005.dsub.util.CancellableTask;
import github.daneren2005.dsub.util.FileUtil;
import github.daneren2005.dsub.util.Util;
import github.daneren2005.dsub.util.CacheCleaner;
+import org.apache.http.Header;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
@@ -59,6 +60,7 @@ public class DownloadFile {
private boolean isPlaying = false;
private boolean saveWhenDone = false;
private boolean completeWhenDone = false;
+ private Integer contentLength = null;
public DownloadFile(Context context, MusicDirectory.Entry song, boolean save) {
this.context = context;
@@ -89,6 +91,10 @@ public class DownloadFile {
}
return song.getBitRate() == null ? 160 : song.getBitRate();
}
+
+ public Integer getContentLength() {
+ return contentLength;
+ }
public synchronized void download() {
FileUtil.createDirectoryForParent(saveFile);
@@ -270,6 +276,14 @@ public class DownloadFile {
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 = Integer.parseInt(contentLengthString);
+ }
+ }
in = response.getEntity().getContent();
boolean partial = response.getStatusLine().getStatusCode() == HttpStatus.SC_PARTIAL_CONTENT;
if (partial) {
diff --git a/subsonic-android/src/github/daneren2005/dsub/service/DownloadServiceImpl.java b/subsonic-android/src/github/daneren2005/dsub/service/DownloadServiceImpl.java
index ba8ea1e4..4c02a831 100644
--- a/subsonic-android/src/github/daneren2005/dsub/service/DownloadServiceImpl.java
+++ b/subsonic-android/src/github/daneren2005/dsub/service/DownloadServiceImpl.java
@@ -282,16 +282,22 @@ public class DownloadServiceImpl extends Service implements DownloadService {
}
revision++;
} else {
+ int size = size();
+ int index = getCurrentPlayingIndex();
for (MusicDirectory.Entry song : songs) {
DownloadFile downloadFile = new DownloadFile(this, song, save);
downloadList.add(downloadFile);
}
+ if(!autoplay && (size - 1) == index) {
+ setNextPlaying();
+ }
revision++;
}
updateJukeboxPlaylist();
- if(shuffle)
+ if(shuffle) {
shuffle();
+ }
if (autoplay) {
play(0);
diff --git a/subsonic-android/src/github/daneren2005/dsub/service/OfflineMusicService.java b/subsonic-android/src/github/daneren2005/dsub/service/OfflineMusicService.java
index 0c7dba27..40c1cdb0 100644
--- a/subsonic-android/src/github/daneren2005/dsub/service/OfflineMusicService.java
+++ b/subsonic-android/src/github/daneren2005/dsub/service/OfflineMusicService.java
@@ -152,11 +152,20 @@ public class OfflineMusicService extends RESTMusicService {
entry.setParent(file.getParent());
entry.setSize(file.length());
String root = FileUtil.getMusicDirectory(context).getPath();
+ if(!file.getParentFile().getParentFile().getPath().equals(root)) {
+ entry.setGrandParent(file.getParentFile().getParent());
+ }
entry.setPath(file.getPath().replaceFirst("^" + root + "/" , ""));
String title = name;
if (file.isFile()) {
- entry.setArtist(file.getParentFile().getParentFile().getName());
- entry.setAlbum(file.getParentFile().getName());
+ File artistFolder = file.getParentFile().getParentFile();
+ File albumFolder = file.getParentFile();
+ if(artistFolder.getPath().equals(root)) {
+ entry.setArtist(albumFolder.getName());
+ } else {
+ entry.setArtist(artistFolder.getName());
+ }
+ entry.setAlbum(albumFolder.getName());
int index = name.indexOf('-');
if(index != -1) {
diff --git a/subsonic-android/src/github/daneren2005/dsub/service/RESTMusicService.java b/subsonic-android/src/github/daneren2005/dsub/service/RESTMusicService.java
index ee8a384c..fae950c7 100644
--- a/subsonic-android/src/github/daneren2005/dsub/service/RESTMusicService.java
+++ b/subsonic-android/src/github/daneren2005/dsub/service/RESTMusicService.java
@@ -274,6 +274,19 @@ public class RESTMusicService implements MusicService {
@Override
public MusicDirectory getMusicDirectory(String id, String name, boolean refresh, Context context, ProgressListener progressListener) throws Exception {
+ SharedPreferences prefs = Util.getPreferences(context);
+ String cacheLocn = prefs.getString(Constants.PREFERENCES_KEY_CACHE_LOCATION, null);
+ if(id.indexOf(cacheLocn) != -1) {
+ String search = Util.parseOfflineIDSearch(context, id, cacheLocn);
+ SearchCritera critera = new SearchCritera(search, 1, 1, 0);
+ SearchResult result = searchNew(critera, context, progressListener);
+ if(result.getArtists().size() == 1) {
+ id = result.getArtists().get(0).getId();
+ } else if(result.getAlbums().size() == 1) {
+ id = result.getAlbums().get(0).getId();
+ }
+ }
+
Reader reader = getReader(context, progressListener, "getMusicDirectory", null, "id", id);
try {
return new MusicDirectoryParser(context).parse(name, reader, progressListener);
@@ -384,7 +397,7 @@ public class RESTMusicService implements MusicService {
}
for (MusicDirectory.Entry entry : entries) {
parameterNames.add("songId");
- parameterValues.add(entry.getId());
+ parameterValues.add(getOfflineSongId(entry.getId(), context, progressListener));
}
Reader reader = getReader(context, progressListener, "createPlaylist", null, parameterNames, parameterValues);
@@ -414,7 +427,7 @@ public class RESTMusicService implements MusicService {
values.add(id);
for(MusicDirectory.Entry song: toAdd) {
names.add("songIdToAdd");
- values.add(song.getId());
+ values.add(getOfflineSongId(song.getId(), context, progressListener));
}
Reader reader = getReader(context, progressListener, "updatePlaylist", null, names, values);
try {
@@ -491,19 +504,8 @@ public class RESTMusicService implements MusicService {
@Override
public void scrobble(String id, boolean submission, Context context, ProgressListener progressListener) throws Exception {
- SharedPreferences prefs = Util.getPreferences(context);
- String cacheLocn = prefs.getString(Constants.PREFERENCES_KEY_CACHE_LOCATION, null);
-
- if(id.indexOf(cacheLocn) != -1 && submission) {
- String scrobbleSearchCriteria = Util.parseOfflineIDSearch(context, id, cacheLocn);
- SearchCritera critera = new SearchCritera(scrobbleSearchCriteria, 0, 0, 1);
- SearchResult result = searchNew(critera, context, progressListener);
- if(result.getSongs().size() == 1){
- scrobble(result.getSongs().get(0).getId(), true, 0, context, progressListener);
- }
- } else {
- scrobble(id, submission, 0, context, progressListener);
- }
+ id = getOfflineSongId(id, context, progressListener);
+ scrobble(id, submission, 0, context, progressListener);
}
public void scrobble(String id, boolean submission, long time, Context context, ProgressListener progressListener) throws Exception {
@@ -778,7 +780,9 @@ public class RESTMusicService implements MusicService {
@Override
public void setStarred(String id, boolean starred, Context context, ProgressListener progressListener) throws Exception {
checkServerVersion(context, "1.8", "Starring is not supported.");
- Reader reader = getReader(context, progressListener, starred ? "star" : "unstar", null, "id", id);
+ id = getOfflineSongId(id, context, progressListener);
+
+ Reader reader = getReader(context, progressListener, starred ? "star" : "unstar", null, "id", id);
try {
new ErrorParser(context).parse(reader);
} finally {
@@ -919,6 +923,21 @@ public class RESTMusicService implements MusicService {
return count - retry;
}
+
+ private String getOfflineSongId(String id, Context context, ProgressListener progressListener) throws Exception {
+ SharedPreferences prefs = Util.getPreferences(context);
+ String cacheLocn = prefs.getString(Constants.PREFERENCES_KEY_CACHE_LOCATION, null);
+ if(id.indexOf(cacheLocn) != -1) {
+ String searchCriteria = Util.parseOfflineIDSearch(context, id, cacheLocn);
+ SearchCritera critera = new SearchCritera(searchCriteria, 0, 0, 1);
+ SearchResult result = searchNew(critera, context, progressListener);
+ if(result.getSongs().size() == 1){
+ id = result.getSongs().get(0).getId();
+ }
+ }
+
+ return id;
+ }
private Reader getReader(Context context, ProgressListener progressListener, String method, HttpParams requestParams) throws Exception {
return getReader(context, progressListener, method, requestParams, Collections.<String>emptyList(), Collections.emptyList());
diff --git a/subsonic-android/src/github/daneren2005/dsub/service/StreamProxy.java b/subsonic-android/src/github/daneren2005/dsub/service/StreamProxy.java
index 13dbf479..24c1b201 100644
--- a/subsonic-android/src/github/daneren2005/dsub/service/StreamProxy.java
+++ b/subsonic-android/src/github/daneren2005/dsub/service/StreamProxy.java
@@ -157,12 +157,20 @@ public class StreamProxy implements Runnable {
Log.i(TAG, "Streaming song in background");
DownloadFile downloadFile = downloadService.getCurrentPlaying();
MusicDirectory.Entry song = downloadFile.getSong();
- long fileSize = downloadFile.getBitRate() * ((song.getDuration() != null) ? song.getDuration() : 0) * 1000 / 8;
- Log.i(TAG, "Streaming fileSize: " + fileSize);
// Create HTTP header
String headers = "HTTP/1.0 200 OK\r\n";
headers += "Content-Type: " + "application/octet-stream" + "\r\n";
+
+ Integer contentLength = downloadFile.getContentLength();
+ long fileSize;
+ if(contentLength == null) {
+ fileSize = downloadFile.getBitRate() * ((song.getDuration() != null) ? song.getDuration() : 0) * 1000 / 8;
+ } else {
+ fileSize = contentLength;
+ headers += "Content-Length: " + fileSize + "\r\n";
+ }
+ Log.i(TAG, "Streaming fileSize: " + fileSize);
headers += "Connection: close\r\n";
headers += "\r\n";
diff --git a/subsonic-android/src/github/daneren2005/dsub/util/Constants.java b/subsonic-android/src/github/daneren2005/dsub/util/Constants.java
index a2f43dcd..7c7f67a4 100644
--- a/subsonic-android/src/github/daneren2005/dsub/util/Constants.java
+++ b/subsonic-android/src/github/daneren2005/dsub/util/Constants.java
@@ -126,6 +126,7 @@ public final class Constants {
// Name of the preferences file.
public static final String PREFERENCES_FILE_NAME = "github.daneren2005.dsub_preferences";
public static final String OFFLINE_SYNC_NAME = "github.daneren2005.dsub.offline";
+ public static final String OFFLINE_SYNC_DEFAULT = "syncDefaults";
// Number of free trial days for non-licensed servers.
public static final int FREE_TRIAL_DAYS = 30;
diff --git a/subsonic-android/src/github/daneren2005/dsub/util/Util.java b/subsonic-android/src/github/daneren2005/dsub/util/Util.java
index 3ad4c623..b8cc9471 100644
--- a/subsonic-android/src/github/daneren2005/dsub/util/Util.java
+++ b/subsonic-android/src/github/daneren2005/dsub/util/Util.java
@@ -363,6 +363,16 @@ public final class Util {
return context.getSharedPreferences(Constants.OFFLINE_SYNC_NAME, 0);
}
+ public static String getSyncDefault(Context context) {
+ SharedPreferences prefs = Util.getOfflineSync(context);
+ return prefs.getString(Constants.OFFLINE_SYNC_DEFAULT, null);
+ }
+ public static void setSyncDefault(Context context, String defaultValue) {
+ SharedPreferences.Editor editor = Util.getOfflineSync(context).edit();
+ editor.putString(Constants.OFFLINE_SYNC_DEFAULT, defaultValue);
+ editor.commit();
+ }
+
public static int offlineScrobblesCount(Context context) {
SharedPreferences offline = getOfflineSync(context);
return offline.getInt(Constants.OFFLINE_SCROBBLE_COUNT, 0);
@@ -378,11 +388,30 @@ public final class Util {
name = index == -1 ? name : name.substring(0, index);
String[] details = name.split("/");
- String artist = "artist:\"" + details[0] + "\"";
String title = details[details.length - 1];
- title = "title:\"" + title.substring(title.indexOf('-') + 1) + "\"";
-
- name = artist + " AND " + title;
+ if(index == -1) {
+ if(details.length > 1) {
+ String artist = "artist:\"" + details[details.length - 2] + "\"";
+ String simpleArtist = "artist:\"" + title + "\"";
+ title = "album:\"" + title + "\"";
+ if(details[details.length - 1].equals(details[details.length - 2])) {
+ name = title;
+ } else {
+ name = "(" + artist + " AND " + title + ")" + " OR " + simpleArtist;
+ }
+ } else {
+ name = "artist:\"" + title + "\" OR album:\"" + title + "\"";
+ }
+ } else {
+ String artist;
+ if(details.length > 2) {
+ artist = "artist:\"" + details[details.length - 3] + "\"";
+ } else {
+ artist = "(artist:\"" + details[0] + "\" OR album:\"" + details[0] + "\")";
+ }
+ title = "title:\"" + title.substring(title.indexOf('-') + 1) + "\"";
+ name = artist + " AND " + title;
+ }
return name;
}