aboutsummaryrefslogtreecommitdiff
path: root/subsonic-android
diff options
context:
space:
mode:
authorScott Jackson <daneren2005@gmail.com>2013-05-31 21:31:22 -0700
committerScott Jackson <daneren2005@gmail.com>2013-05-31 21:31:22 -0700
commit8306a6ad9dd4875801d782caa2ca6df1bb8c2eb9 (patch)
tree51812ec3f903bdcba26ec236294f57e6eac9613a /subsonic-android
parent63bea6976413bb2e24ea9d606a8fe5cff2e3de44 (diff)
downloaddsub-8306a6ad9dd4875801d782caa2ca6df1bb8c2eb9.tar.gz
dsub-8306a6ad9dd4875801d782caa2ca6df1bb8c2eb9.tar.bz2
dsub-8306a6ad9dd4875801d782caa2ca6df1bb8c2eb9.zip
Added Genre combo to Shuffle dialog (thanks archrival for parsers)
Diffstat (limited to 'subsonic-android')
-rw-r--r--subsonic-android/res/layout/shuffle_dialog.xml10
-rw-r--r--subsonic-android/res/values/strings.xml1
-rw-r--r--subsonic-android/src/github/daneren2005/dsub/domain/Genre.java29
-rw-r--r--subsonic-android/src/github/daneren2005/dsub/fragments/SubsonicFragment.java65
-rw-r--r--subsonic-android/src/github/daneren2005/dsub/service/CachedMusicService.java20
-rw-r--r--subsonic-android/src/github/daneren2005/dsub/service/MusicService.java5
-rw-r--r--subsonic-android/src/github/daneren2005/dsub/service/OfflineMusicService.java11
-rw-r--r--subsonic-android/src/github/daneren2005/dsub/service/RESTMusicService.java39
-rw-r--r--subsonic-android/src/github/daneren2005/dsub/service/parser/GenreParser.java122
9 files changed, 300 insertions, 2 deletions
diff --git a/subsonic-android/res/layout/shuffle_dialog.xml b/subsonic-android/res/layout/shuffle_dialog.xml
index 2a21dc11..e78aba33 100644
--- a/subsonic-android/res/layout/shuffle_dialog.xml
+++ b/subsonic-android/res/layout/shuffle_dialog.xml
@@ -66,6 +66,14 @@
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginLeft="4dp"
- android:hint="@string/shuffle.genre" />
+ android:hint="@string/shuffle.genre"/>
+
+ <Button
+ android:id="@+id/genre_combo"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:layout_marginLeft="4dp"
+ android:text="@string/shuffle.genre"/>
</LinearLayout>
</LinearLayout> \ No newline at end of file
diff --git a/subsonic-android/res/values/strings.xml b/subsonic-android/res/values/strings.xml
index 62172631..01e10d6b 100644
--- a/subsonic-android/res/values/strings.xml
+++ b/subsonic-android/res/values/strings.xml
@@ -283,6 +283,7 @@
<string name="shuffle.startYear">Start Year:</string>
<string name="shuffle.endYear">End Year:</string>
<string name="shuffle.genre">Genre:</string>
+ <string name="shuffle.pick_genre">Pick a genre</string>
<string name="music_service.retry">A network error occurred. Retrying %1$d of %2$d.</string>
diff --git a/subsonic-android/src/github/daneren2005/dsub/domain/Genre.java b/subsonic-android/src/github/daneren2005/dsub/domain/Genre.java
new file mode 100644
index 00000000..8c705e31
--- /dev/null
+++ b/subsonic-android/src/github/daneren2005/dsub/domain/Genre.java
@@ -0,0 +1,29 @@
+package github.daneren2005.dsub.domain;
+
+import java.io.Serializable;
+
+public class Genre implements Serializable {
+ private String name;
+ private String index;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getIndex() {
+ return index;
+ }
+
+ public void setIndex(String index) {
+ this.index = index;
+ }
+
+ @Override
+ public String toString() {
+ return name;
+ }
+}
diff --git a/subsonic-android/src/github/daneren2005/dsub/fragments/SubsonicFragment.java b/subsonic-android/src/github/daneren2005/dsub/fragments/SubsonicFragment.java
index 35a272eb..05b78eab 100644
--- a/subsonic-android/src/github/daneren2005/dsub/fragments/SubsonicFragment.java
+++ b/subsonic-android/src/github/daneren2005/dsub/fragments/SubsonicFragment.java
@@ -35,6 +35,7 @@ import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
+import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import com.actionbarsherlock.app.SherlockFragment;
@@ -46,8 +47,10 @@ import github.daneren2005.dsub.activity.SearchActivity;
import github.daneren2005.dsub.activity.SettingsActivity;
import github.daneren2005.dsub.activity.SubsonicActivity;
import github.daneren2005.dsub.domain.Artist;
+import github.daneren2005.dsub.domain.Genre;
import github.daneren2005.dsub.domain.MusicDirectory;
import github.daneren2005.dsub.domain.Playlist;
+import github.daneren2005.dsub.domain.Version;
import github.daneren2005.dsub.service.DownloadFile;
import github.daneren2005.dsub.service.DownloadService;
import github.daneren2005.dsub.service.DownloadServiceImpl;
@@ -379,15 +382,70 @@ public class SubsonicFragment extends SherlockFragment {
final EditText startYearBox = (EditText)dialogView.findViewById(R.id.start_year);
final EditText endYearBox = (EditText)dialogView.findViewById(R.id.end_year);
final EditText genreBox = (EditText)dialogView.findViewById(R.id.genre);
+ final Button genreCombo = (Button)dialogView.findViewById(R.id.genre_combo);
final SharedPreferences prefs = Util.getPreferences(context);
final String oldStartYear = prefs.getString(Constants.PREFERENCES_KEY_SHUFFLE_START_YEAR, "");
final String oldEndYear = prefs.getString(Constants.PREFERENCES_KEY_SHUFFLE_END_YEAR, "");
final String oldGenre = prefs.getString(Constants.PREFERENCES_KEY_SHUFFLE_GENRE, "");
+
+ Version version = Util.getServerRestVersion(context);
+ Version genreVersion = new Version("1.9.0");
+ boolean _useCombo = false;
+ if(version.compareTo(genreVersion) >= 0) {
+ genreBox.setVisibility(View.GONE);
+ genreCombo.setOnClickListener(new View.OnClickListener() {
+ public void onClick(View v) {
+ new LoadingTask<List<Genre>>(context, true) {
+ @Override
+ protected List<Genre> doInBackground() throws Throwable {
+ MusicService musicService = MusicServiceFactory.getMusicService(context);
+ return musicService.getGenres(context, this);
+ }
+
+ @Override
+ protected void done(final List<Genre> genres) {
+ List<String> names = new ArrayList<String>();
+ for(Genre genre: genres) {
+ names.add(genre.getName());
+ }
+ final List<String> finalNames = names;
+
+ AlertDialog.Builder builder = new AlertDialog.Builder(context);
+ builder.setTitle(R.string.shuffle_pick_genre)
+ .setItems(names.toArray(new CharSequence[names.size()]), new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ genreCombo.setText(finalNames.get(which));
+ }
+ });
+ AlertDialog dialog = builder.create();
+ dialog.show();
+ }
+
+ @Override
+ protected void error(Throwable error) {
+ String msg;
+ if (error instanceof OfflineException || error instanceof ServerTooOldException) {
+ msg = getErrorMessage(error);
+ } else {
+ msg = context.getResources().getString(R.string.playlist_error) + " " + getErrorMessage(error);
+ }
+
+ Util.toast(context, msg, false);
+ }
+ }.execute();
+ }
+ });
+ _useCombo = true;
+ } else {
+ genreCombo.setVisibility(View.GONE);
+ }
+ final boolean useCombo = _useCombo;
startYearBox.setText(oldStartYear);
endYearBox.setText(oldEndYear);
genreBox.setText(oldGenre);
+ genreCombo.setText(oldGenre);
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle("Shuffle By")
@@ -397,7 +455,12 @@ public class SubsonicFragment extends SherlockFragment {
public void onClick(DialogInterface dialog, int id) {
Intent intent = new Intent(context, DownloadActivity.class);
intent.putExtra(Constants.INTENT_EXTRA_NAME_SHUFFLE, true);
- String genre = genreBox.getText().toString();
+ String genre;
+ if(useCombo) {
+ genre = genreCombo.getText().toString();
+ } else {
+ genre = genreBox.getText().toString();
+ }
String startYear = startYearBox.getText().toString();
String endYear = endYearBox.getText().toString();
diff --git a/subsonic-android/src/github/daneren2005/dsub/service/CachedMusicService.java b/subsonic-android/src/github/daneren2005/dsub/service/CachedMusicService.java
index 3eb4184f..71bbb867 100644
--- a/subsonic-android/src/github/daneren2005/dsub/service/CachedMusicService.java
+++ b/subsonic-android/src/github/daneren2005/dsub/service/CachedMusicService.java
@@ -26,6 +26,7 @@ import org.apache.http.HttpResponse;
import android.content.Context;
import android.graphics.Bitmap;
import github.daneren2005.dsub.domain.ChatMessage;
+import github.daneren2005.dsub.domain.Genre;
import github.daneren2005.dsub.domain.Indexes;
import github.daneren2005.dsub.domain.JukeboxStatus;
import github.daneren2005.dsub.domain.Lyrics;
@@ -56,6 +57,7 @@ public class CachedMusicService implements MusicService {
private final TimeLimitedCache<Indexes> cachedIndexes = new TimeLimitedCache<Indexes>(60 * 60, TimeUnit.SECONDS);
private final TimeLimitedCache<List<Playlist>> cachedPlaylists = new TimeLimitedCache<List<Playlist>>(3600, TimeUnit.SECONDS);
private final TimeLimitedCache<List<MusicFolder>> cachedMusicFolders = new TimeLimitedCache<List<MusicFolder>>(10 * 3600, TimeUnit.SECONDS);
+ private final TimeLimitedCache<List<Genre>> cachedGenres = new TimeLimitedCache<List<Genre>>(10 * 3600, TimeUnit.SECONDS);
private String restUrl;
public CachedMusicService(MusicService musicService) {
@@ -275,6 +277,24 @@ public class CachedMusicService implements MusicService {
public void addChatMessage(String message, Context context, ProgressListener progressListener) throws Exception {
musicService.addChatMessage(message, context, progressListener);
}
+
+ @Override
+ public List<Genre> getGenres(Context context, ProgressListener progressListener) throws Exception {
+ checkSettingsChanged(context);
+ List<Genre> result = cachedGenres.get();
+
+ if (result == null) {
+ result = musicService.getGenres(context, progressListener);
+ cachedGenres.set(result);
+ }
+
+ return result;
+ }
+
+ @Override
+ public MusicDirectory getSongsByGenre(String genre, int count, int offset, Context context, ProgressListener progressListener) throws Exception {
+ return musicService.getSongsByGenre(genre, count, offset, context, progressListener);
+ }
private void checkSettingsChanged(Context context) {
String newUrl = Util.getRestUrl(context, null);
diff --git a/subsonic-android/src/github/daneren2005/dsub/service/MusicService.java b/subsonic-android/src/github/daneren2005/dsub/service/MusicService.java
index 88391e53..31e9c23c 100644
--- a/subsonic-android/src/github/daneren2005/dsub/service/MusicService.java
+++ b/subsonic-android/src/github/daneren2005/dsub/service/MusicService.java
@@ -25,6 +25,7 @@ import org.apache.http.HttpResponse;
import android.content.Context;
import android.graphics.Bitmap;
import github.daneren2005.dsub.domain.ChatMessage;
+import github.daneren2005.dsub.domain.Genre;
import github.daneren2005.dsub.domain.Indexes;
import github.daneren2005.dsub.domain.JukeboxStatus;
import github.daneren2005.dsub.domain.Lyrics;
@@ -110,4 +111,8 @@ public interface MusicService {
List<ChatMessage> getChatMessages(Long since, Context context, ProgressListener progressListener) throws Exception;
void addChatMessage(String message, Context context, ProgressListener progressListener) throws Exception;
+
+ List<Genre> getGenres(Context context, ProgressListener progressListener) throws Exception;
+
+ public MusicDirectory getSongsByGenre(String genre, int count, int offset, Context context, ProgressListener progressListener) throws Exception;
} \ No newline at end of file
diff --git a/subsonic-android/src/github/daneren2005/dsub/service/OfflineMusicService.java b/subsonic-android/src/github/daneren2005/dsub/service/OfflineMusicService.java
index df501994..97fed19f 100644
--- a/subsonic-android/src/github/daneren2005/dsub/service/OfflineMusicService.java
+++ b/subsonic-android/src/github/daneren2005/dsub/service/OfflineMusicService.java
@@ -38,6 +38,7 @@ import android.graphics.BitmapFactory;
import android.media.MediaMetadataRetriever;
import android.util.Log;
import github.daneren2005.dsub.domain.Artist;
+import github.daneren2005.dsub.domain.Genre;
import github.daneren2005.dsub.domain.Indexes;
import github.daneren2005.dsub.domain.JukeboxStatus;
import github.daneren2005.dsub.domain.Lyrics;
@@ -480,6 +481,16 @@ public class OfflineMusicService extends RESTMusicService {
public void setStarred(String id, boolean starred, Context context, ProgressListener progressListener) throws Exception {
throw new OfflineException("Starring not available in offline mode");
}
+
+ @Override
+ public List<Genre> getGenres(Context context, ProgressListener progressListener) throws Exception {
+ throw new OfflineException("Getting Genres not available in offline mode");
+ }
+
+ @Override
+ public MusicDirectory getSongsByGenre(String genre, int count, int offset, Context context, ProgressListener progressListener) throws Exception {
+ throw new OfflineException("Getting Songs By Genre not available in offline mode");
+ }
@Override
public MusicDirectory getRandomSongs(int size, String folder, String genre, String startYear, String endYear, Context context, ProgressListener progressListener) throws Exception {
diff --git a/subsonic-android/src/github/daneren2005/dsub/service/RESTMusicService.java b/subsonic-android/src/github/daneren2005/dsub/service/RESTMusicService.java
index daa9291a..5fc66190 100644
--- a/subsonic-android/src/github/daneren2005/dsub/service/RESTMusicService.java
+++ b/subsonic-android/src/github/daneren2005/dsub/service/RESTMusicService.java
@@ -75,6 +75,7 @@ import github.daneren2005.dsub.domain.MusicDirectory.Entry;
import github.daneren2005.dsub.service.parser.AlbumListParser;
import github.daneren2005.dsub.service.parser.ChatMessageParser;
import github.daneren2005.dsub.service.parser.ErrorParser;
+import github.daneren2005.dsub.service.parser.GenreParser;
import github.daneren2005.dsub.service.parser.IndexesParser;
import github.daneren2005.dsub.service.parser.JukeboxStatusParser;
import github.daneren2005.dsub.service.parser.LicenseParser;
@@ -787,6 +788,44 @@ public class RESTMusicService implements MusicService {
Util.close(reader);
}
}
+
+ @Override
+ public List<Genre> getGenres(Context context, ProgressListener progressListener) throws Exception {
+ checkServerVersion(context, "1.9", "Genres not supported.");
+
+ Reader reader = getReader(context, progressListener, "getGenres", null);
+ try {
+ return new GenreParser(context).parse(reader, progressListener);
+ } finally {
+ Util.close(reader);
+ }
+ }
+
+ @Override
+ public MusicDirectory getSongsByGenre(String genre, int count, int offset, Context context, ProgressListener progressListener) throws Exception {
+ checkServerVersion(context, "1.9", "Genres not supported.");
+
+ HttpParams params = new BasicHttpParams();
+ HttpConnectionParams.setSoTimeout(params, SOCKET_READ_TIMEOUT_GET_RANDOM_SONGS);
+
+ List<String> parameterNames = new ArrayList<String>();
+ List<Object> parameterValues = new ArrayList<Object>();
+
+ parameterNames.add("genre");
+ parameterValues.add(genre);
+ parameterNames.add("count");
+ parameterValues.add(count);
+ parameterNames.add("offset");
+ parameterValues.add(offset);
+
+ Reader reader = getReader(context, progressListener, "getSongsByGenre", params, parameterNames, parameterValues);
+
+ try {
+ return new RandomSongsParser(context).parse(reader, progressListener);
+ } finally {
+ Util.close(reader);
+ }
+ }
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/parser/GenreParser.java b/subsonic-android/src/github/daneren2005/dsub/service/parser/GenreParser.java
new file mode 100644
index 00000000..1062d3af
--- /dev/null
+++ b/subsonic-android/src/github/daneren2005/dsub/service/parser/GenreParser.java
@@ -0,0 +1,122 @@
+/*
+ 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 2010 (C) Sindre Mehus
+ */
+package github.daneren2005.dsub.service.parser;
+
+import android.content.Context;
+import android.util.Log;
+import github.daneren2005.dsub.R;
+import github.daneren2005.dsub.domain.Genre;
+import github.daneren2005.dsub.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.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author Joshua Bahnsen
+ */
+public class GenreParser extends AbstractParser {
+ private static final String TAG = GenreParser.class.getSimpleName();
+
+ public GenreParser(Context context) {
+ super(context);
+ }
+
+ public List<Genre> parse(Reader reader, ProgressListener progressListener) throws Exception {
+ updateProgress(progressListener, R.string.parser_reading);
+
+ 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();
+ if (eventType == XmlPullParser.START_TAG) {
+ String name = getElementName();
+ if ("genre".equals(name)) {
+ genre = new Genre();
+ } else if ("error".equals(name)) {
+ handleError();
+ } else {
+ genre = null;
+ }
+ } else if (eventType == XmlPullParser.TEXT) {
+ if (genre != null) {
+ String value = getText();
+ if (genre != null) {
+ genre.setName(value);
+ genre.setIndex(value.substring(0, 1));
+ result.add(genre);
+ genre = null;
+ }
+ }
+ }
+ } while (eventType != XmlPullParser.END_DOCUMENT);
+
+ validate();
+ updateProgress(progressListener, R.string.parser_reading_done);
+
+ return result;
+ }
+}