From 1068fde7bfe3e258f07eb425610da8ea0d10b19e Mon Sep 17 00:00:00 2001 From: Scott Jackson Date: Wed, 26 Jun 2013 22:07:05 -0700 Subject: Start of podcast support --- .../drawable-hdpi-v4/list_item_more_saved.9.png | Bin 0 -> 5919 bytes subsonic-android/res/layout/select_podcasts.xml | 30 +++++ subsonic-android/res/menu/select_podcasts.xml | 18 +++ subsonic-android/res/values/strings.xml | 3 + .../daneren2005/dsub/domain/PodcastChannel.java | 72 +++++++++++ .../daneren2005/dsub/domain/PodcastEpisode.java | 62 +++++++++ .../dsub/fragments/SelectDirectoryFragment.java | 38 +++++- .../dsub/fragments/SelectPodcastsFragment.java | 140 +++++++++++++++++++++ .../dsub/service/CachedMusicService.java | 20 +++ .../daneren2005/dsub/service/MusicService.java | 8 +- .../dsub/service/OfflineMusicService.java | 12 ++ .../daneren2005/dsub/service/RESTMusicService.java | 22 ++++ .../dsub/service/parser/PodcastChannelParser.java | 70 +++++++++++ .../dsub/service/parser/PodcastEntryParser.java | 79 ++++++++++++ .../github/daneren2005/dsub/util/Constants.java | 3 + .../dsub/view/PodcastChannelAdapter.java | 59 +++++++++ .../daneren2005/dsub/view/PodcastChannelView.java | 53 ++++++++ .../src/github/daneren2005/dsub/view/SongView.java | 7 +- 18 files changed, 689 insertions(+), 7 deletions(-) create mode 100644 subsonic-android/res/drawable-hdpi-v4/list_item_more_saved.9.png create mode 100644 subsonic-android/res/layout/select_podcasts.xml create mode 100644 subsonic-android/res/menu/select_podcasts.xml create mode 100644 subsonic-android/src/github/daneren2005/dsub/domain/PodcastChannel.java create mode 100644 subsonic-android/src/github/daneren2005/dsub/domain/PodcastEpisode.java create mode 100644 subsonic-android/src/github/daneren2005/dsub/fragments/SelectPodcastsFragment.java create mode 100644 subsonic-android/src/github/daneren2005/dsub/service/parser/PodcastChannelParser.java create mode 100644 subsonic-android/src/github/daneren2005/dsub/service/parser/PodcastEntryParser.java create mode 100644 subsonic-android/src/github/daneren2005/dsub/view/PodcastChannelAdapter.java create mode 100644 subsonic-android/src/github/daneren2005/dsub/view/PodcastChannelView.java (limited to 'subsonic-android') diff --git a/subsonic-android/res/drawable-hdpi-v4/list_item_more_saved.9.png b/subsonic-android/res/drawable-hdpi-v4/list_item_more_saved.9.png new file mode 100644 index 00000000..f3805bfb Binary files /dev/null and b/subsonic-android/res/drawable-hdpi-v4/list_item_more_saved.9.png differ diff --git a/subsonic-android/res/layout/select_podcasts.xml b/subsonic-android/res/layout/select_podcasts.xml new file mode 100644 index 00000000..3fda5799 --- /dev/null +++ b/subsonic-android/res/layout/select_podcasts.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + diff --git a/subsonic-android/res/menu/select_podcasts.xml b/subsonic-android/res/menu/select_podcasts.xml new file mode 100644 index 00000000..e0f9a718 --- /dev/null +++ b/subsonic-android/res/menu/select_podcasts.xml @@ -0,0 +1,18 @@ + + + + + + + + \ No newline at end of file diff --git a/subsonic-android/res/values/strings.xml b/subsonic-android/res/values/strings.xml index 150933fd..d7c0d089 100644 --- a/subsonic-android/res/values/strings.xml +++ b/subsonic-android/res/values/strings.xml @@ -27,6 +27,7 @@ Search Playlists Playing + Podcasts Chat Welcome! @@ -129,6 +130,8 @@ No genres found Blank + No podcasts found + No saved playlists on server Playlist is empty diff --git a/subsonic-android/src/github/daneren2005/dsub/domain/PodcastChannel.java b/subsonic-android/src/github/daneren2005/dsub/domain/PodcastChannel.java new file mode 100644 index 00000000..6cb3944f --- /dev/null +++ b/subsonic-android/src/github/daneren2005/dsub/domain/PodcastChannel.java @@ -0,0 +1,72 @@ +/* + 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 . + + Copyright 2009 (C) Sindre Mehus + */ +package github.daneren2005.dsub.domain; + +import java.io.Serializable; + +/** + * + * @author Scott + */ +public class PodcastChannel implements Serializable { + private String id; + private String name; + private String url; + private String description; + private String status; + + public PodcastChannel() { + + } + + public String getId() { + return id; + } + public void setId(String id) { + this.id = id; + } + + public String getName() { + return name; + } + public void setName(String name) { + this.name = name; + } + + public String getUrl() { + return url; + } + public void setUrl(String url) { + this.url = url; + } + + public String getDescription() { + return description; + } + public void setDescription(String description) { + this.description = description; + } + + public String getStatus() { + return status; + } + public void setStatus(String status) { + this.status = status; + } +} diff --git a/subsonic-android/src/github/daneren2005/dsub/domain/PodcastEpisode.java b/subsonic-android/src/github/daneren2005/dsub/domain/PodcastEpisode.java new file mode 100644 index 00000000..d85e8325 --- /dev/null +++ b/subsonic-android/src/github/daneren2005/dsub/domain/PodcastEpisode.java @@ -0,0 +1,62 @@ +/* + 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 . + + Copyright 2009 (C) Sindre Mehus + */ +package github.daneren2005.dsub.domain; + +/** + * + * @author Scott + */ +public class PodcastEpisode extends MusicDirectory.Entry { + private String episodeId; + private String description; + private String date; + private String status; + + public PodcastEpisode() { + setDirectory(false); + } + + public String getEpisodeId() { + return episodeId; + } + public void setEpisodeId(String episodeId) { + this.episodeId = episodeId; + } + + public String getDescription() { + return description; + } + public void setDescription(String description) { + this.description = description; + } + + public String getDate() { + return date; + } + public void setDate(String date) { + this.date = date; + } + + public String getStatus() { + return status; + } + public void setStatus(String status) { + this.status = status; + } +} diff --git a/subsonic-android/src/github/daneren2005/dsub/fragments/SelectDirectoryFragment.java b/subsonic-android/src/github/daneren2005/dsub/fragments/SelectDirectoryFragment.java index 82b6c481..5b007e6f 100644 --- a/subsonic-android/src/github/daneren2005/dsub/fragments/SelectDirectoryFragment.java +++ b/subsonic-android/src/github/daneren2005/dsub/fragments/SelectDirectoryFragment.java @@ -54,6 +54,9 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter String name; String playlistId; String playlistName; + String podcastId; + String podcastName; + String podcastDescription; String albumListType; String albumListExtra; int albumListSize; @@ -100,6 +103,9 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter name = args.getString(Constants.INTENT_EXTRA_NAME_NAME); playlistId = args.getString(Constants.INTENT_EXTRA_NAME_PLAYLIST_ID); playlistName = args.getString(Constants.INTENT_EXTRA_NAME_PLAYLIST_NAME); + podcastId = args.getString(Constants.INTENT_EXTRA_NAME_PODCAST_ID); + podcastName = args.getString(Constants.INTENT_EXTRA_NAME_PODCAST_NAME); + podcastDescription = args.getString(Constants.INTENT_EXTRA_NAME_PODCAST_DESCRIPTION); albumListType = args.getString(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TYPE); albumListExtra = args.getString(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_EXTRA); albumListSize = args.getInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, 0); @@ -267,6 +273,8 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter emptyView.setVisibility(View.INVISIBLE); if (playlistId != null) { getPlaylist(playlistId, playlistName); + } else if(podcastId != null) { + getPodcast(podcastId, podcastName); } else if (albumListType != null) { getAlbumList(albumListType, albumListSize); } else { @@ -295,6 +303,17 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter } }.execute(); } + + private void getPodcast(final String podcastId, final String podcastName) { + setTitle(podcastName); + + new LoadTask() { + @Override + protected MusicDirectory load(MusicService service) throws Exception { + return service.getPodcastEpisodes(podcastId, context, this); + } + }.execute(); + } private void getAlbumList(final String albumListType, final int size) { showHeader = false; @@ -648,6 +667,9 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter TextView titleView = (TextView) header.findViewById(R.id.select_album_title); if(playlistName != null) { titleView.setText(playlistName); + } else if(podcastName != null) { + titleView.setText(podcastName); + titleView.setPadding(0, 6, 4, 8); } else if(name != null) { titleView.setText(name); } @@ -673,16 +695,24 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter if (artists.size() == 1) { artistView.setText(artists.iterator().next()); artistView.setVisibility(View.VISIBLE); + } else if(podcastDescription != null) { + artistView.setText(podcastDescription); + artistView.setSingleLine(false); + artistView.setLines(5); } else { artistView.setVisibility(View.GONE); } TextView songCountView = (TextView) header.findViewById(R.id.select_album_song_count); - String s = context.getResources().getQuantityString(R.plurals.select_album_n_songs, songCount, songCount); - songCountView.setText(s.toUpperCase()); - TextView songLengthView = (TextView) header.findViewById(R.id.select_album_song_length); - songLengthView.setText(Util.formatDuration(totalDuration)); + if(podcastDescription == null) { + String s = context.getResources().getQuantityString(R.plurals.select_album_n_songs, songCount, songCount); + songCountView.setText(s.toUpperCase()); + songLengthView.setText(Util.formatDuration(totalDuration)); + } else { + songCountView.setVisibility(View.GONE); + songLengthView.setVisibility(View.GONE); + } if(add) { return header; diff --git a/subsonic-android/src/github/daneren2005/dsub/fragments/SelectPodcastsFragment.java b/subsonic-android/src/github/daneren2005/dsub/fragments/SelectPodcastsFragment.java new file mode 100644 index 00000000..923eac87 --- /dev/null +++ b/subsonic-android/src/github/daneren2005/dsub/fragments/SelectPodcastsFragment.java @@ -0,0 +1,140 @@ +/* + 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 . + + Copyright 2010 (C) Sindre Mehus + */ +package github.daneren2005.dsub.fragments; + +import android.os.Bundle; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.ListView; +import com.actionbarsherlock.view.Menu; +import com.actionbarsherlock.view.MenuItem; +import com.actionbarsherlock.view.MenuInflater; +import github.daneren2005.dsub.R; +import github.daneren2005.dsub.domain.PodcastChannel; +import github.daneren2005.dsub.service.MusicService; +import github.daneren2005.dsub.service.MusicServiceFactory; +import github.daneren2005.dsub.util.BackgroundTask; +import github.daneren2005.dsub.util.Constants; +import github.daneren2005.dsub.util.TabBackgroundTask; +import github.daneren2005.dsub.view.PodcastChannelAdapter; +import java.util.ArrayList; +import java.util.List; + +/** + * + * @author Scott + */ +public class SelectPodcastsFragment extends SubsonicFragment implements AdapterView.OnItemClickListener { + private static final String TAG = SelectPodcastsFragment.class.getSimpleName(); + private ListView podcastListView; + private View emptyView; + + @Override + public void onCreate(Bundle bundle) { + super.onCreate(bundle); + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) { + rootView = inflater.inflate(R.layout.select_podcasts, container, false); + + podcastListView = (ListView)rootView.findViewById(R.id.select_podcasts_list); + podcastListView.setOnItemClickListener(this); + emptyView = rootView.findViewById(R.id.select_podcasts_empty); + refresh(); + + return rootView; + } + + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater menuInflater) { + menuInflater.inflate(R.menu.select_podcasts, menu); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + if(super.onOptionsItemSelected(item)) { + return true; + } + + return false; + } + + @Override + public void setPrimaryFragment(boolean primary) { + super.setPrimaryFragment(primary); + if(rootView != null) { + if(primary) { + ((ViewGroup)rootView).getChildAt(0).setVisibility(View.VISIBLE); + } else { + ((ViewGroup)rootView).getChildAt(0).setVisibility(View.GONE); + } + } + } + + @Override + protected void refresh(final boolean refresh) { + setTitle(R.string.button_bar_podcasts); + + BackgroundTask> task = new TabBackgroundTask>(this) { + @Override + protected List doInBackground() throws Throwable { + MusicService musicService = MusicServiceFactory.getMusicService(context); + + List channels = new ArrayList(); + + try { + channels = musicService.getPodcastChannels(refresh, context, this); + } catch (Exception x) { + Log.e(TAG, "Failed to load podcasts", x); + } + + return channels; + } + + @Override + protected void done(List result) { + emptyView.setVisibility(result == null || result.isEmpty() ? View.VISIBLE : View.GONE); + + if (result != null) { + podcastListView.setAdapter(new PodcastChannelAdapter(context, result)); + } + + } + }; + task.execute(); + } + + @Override + public void onItemClick(AdapterView parent, View view, int position, long id) { + PodcastChannel channel = (PodcastChannel) parent.getItemAtPosition(position); + + SubsonicFragment fragment = new SelectDirectoryFragment(); + Bundle args = new Bundle(); + args.putString(Constants.INTENT_EXTRA_NAME_PODCAST_ID, channel.getId()); + args.putString(Constants.INTENT_EXTRA_NAME_PODCAST_NAME, channel.getName()); + args.putString(Constants.INTENT_EXTRA_NAME_PODCAST_DESCRIPTION, channel.getDescription()); + fragment.setArguments(args); + + replaceFragment(fragment, R.id.select_podcasts_layout); + } +} diff --git a/subsonic-android/src/github/daneren2005/dsub/service/CachedMusicService.java b/subsonic-android/src/github/daneren2005/dsub/service/CachedMusicService.java index a6d6e8f8..e06f3372 100644 --- a/subsonic-android/src/github/daneren2005/dsub/service/CachedMusicService.java +++ b/subsonic-android/src/github/daneren2005/dsub/service/CachedMusicService.java @@ -33,6 +33,8 @@ import github.daneren2005.dsub.domain.Lyrics; import github.daneren2005.dsub.domain.MusicDirectory; import github.daneren2005.dsub.domain.MusicFolder; import github.daneren2005.dsub.domain.Playlist; +import github.daneren2005.dsub.domain.PodcastChannel; +import github.daneren2005.dsub.domain.PodcastEpisode; import github.daneren2005.dsub.domain.SearchCritera; import github.daneren2005.dsub.domain.SearchResult; import github.daneren2005.dsub.domain.Share; @@ -59,6 +61,7 @@ public class CachedMusicService implements MusicService { private final TimeLimitedCache> cachedPlaylists = new TimeLimitedCache>(3600, TimeUnit.SECONDS); private final TimeLimitedCache> cachedMusicFolders = new TimeLimitedCache>(10 * 3600, TimeUnit.SECONDS); private final TimeLimitedCache> cachedGenres = new TimeLimitedCache>(10 * 3600, TimeUnit.SECONDS); + private final TimeLimitedCache> cachedPodcastChannels = new TimeLimitedCache>(10 * 3600, TimeUnit.SECONDS); private String restUrl; public CachedMusicService(MusicService musicService) { @@ -302,6 +305,23 @@ public class CachedMusicService implements MusicService { return musicService.getSongsByGenre(genre, count, offset, context, progressListener); } + @Override + public List getPodcastChannels(boolean refresh, Context context, ProgressListener progressListener) throws Exception { + List result = refresh ? null : cachedPodcastChannels.get(); + + if (result == null) { + result = musicService.getPodcastChannels(refresh, context, progressListener); + cachedPodcastChannels.set(result); + } + + return result; + } + + @Override + public MusicDirectory getPodcastEpisodes(String id, Context context, ProgressListener progressListener) throws Exception { + return musicService.getPodcastEpisodes(id, context, progressListener); + } + @Override public int processOfflineSyncs(final Context context, final ProgressListener progressListener) throws Exception{ return musicService.processOfflineSyncs(context, progressListener); diff --git a/subsonic-android/src/github/daneren2005/dsub/service/MusicService.java b/subsonic-android/src/github/daneren2005/dsub/service/MusicService.java index c6efffc3..57deff8f 100644 --- a/subsonic-android/src/github/daneren2005/dsub/service/MusicService.java +++ b/subsonic-android/src/github/daneren2005/dsub/service/MusicService.java @@ -32,6 +32,8 @@ import github.daneren2005.dsub.domain.Lyrics; import github.daneren2005.dsub.domain.MusicDirectory; import github.daneren2005.dsub.domain.MusicFolder; import github.daneren2005.dsub.domain.Playlist; +import github.daneren2005.dsub.domain.PodcastChannel; +import github.daneren2005.dsub.domain.PodcastEpisode; import github.daneren2005.dsub.domain.SearchCritera; import github.daneren2005.dsub.domain.SearchResult; import github.daneren2005.dsub.domain.Share; @@ -116,7 +118,11 @@ public interface MusicService { List getGenres(boolean refresh, Context context, ProgressListener progressListener) throws Exception; - public MusicDirectory getSongsByGenre(String genre, int count, int offset, Context context, ProgressListener progressListener) throws Exception; + MusicDirectory getSongsByGenre(String genre, int count, int offset, Context context, ProgressListener progressListener) throws Exception; + + List getPodcastChannels(boolean refresh, Context context, ProgressListener progressListener) throws Exception; + + MusicDirectory getPodcastEpisodes(String id, Context context, ProgressListener progressListener) throws Exception; int processOfflineSyncs(final Context context, final 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 ba194562..ea45b626 100644 --- a/subsonic-android/src/github/daneren2005/dsub/service/OfflineMusicService.java +++ b/subsonic-android/src/github/daneren2005/dsub/service/OfflineMusicService.java @@ -42,6 +42,8 @@ import github.daneren2005.dsub.domain.Lyrics; import github.daneren2005.dsub.domain.MusicDirectory; import github.daneren2005.dsub.domain.MusicFolder; import github.daneren2005.dsub.domain.Playlist; +import github.daneren2005.dsub.domain.PodcastChannel; +import github.daneren2005.dsub.domain.PodcastEpisode; import github.daneren2005.dsub.domain.SearchCritera; import github.daneren2005.dsub.domain.SearchResult; import github.daneren2005.dsub.util.Constants; @@ -595,6 +597,16 @@ public class OfflineMusicService extends RESTMusicService { return result; } + + @Override + public List getPodcastChannels(boolean refresh, Context context, ProgressListener progressListener) throws Exception { + throw new OfflineException("Getting Podcasts not available in offline mode"); + } + + @Override + public MusicDirectory getPodcastEpisodes(String id, Context context, ProgressListener progressListener) throws Exception { + throw new OfflineException("Getting Podcasts not available in offline mode"); + } @Override public int processOfflineSyncs(final Context context, final 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 ac564f29..ffa8e676 100644 --- a/subsonic-android/src/github/daneren2005/dsub/service/RESTMusicService.java +++ b/subsonic-android/src/github/daneren2005/dsub/service/RESTMusicService.java @@ -84,6 +84,8 @@ import github.daneren2005.dsub.service.parser.MusicDirectoryParser; import github.daneren2005.dsub.service.parser.MusicFoldersParser; import github.daneren2005.dsub.service.parser.PlaylistParser; import github.daneren2005.dsub.service.parser.PlaylistsParser; +import github.daneren2005.dsub.service.parser.PodcastChannelParser; +import github.daneren2005.dsub.service.parser.PodcastEntryParser; import github.daneren2005.dsub.service.parser.RandomSongsParser; import github.daneren2005.dsub.service.parser.SearchResult2Parser; import github.daneren2005.dsub.service.parser.SearchResultParser; @@ -884,6 +886,26 @@ public class RESTMusicService implements MusicService { } } + @Override + public List getPodcastChannels(boolean refresh, Context context, ProgressListener progressListener) throws Exception { + Reader reader = getReader(context, progressListener, "getPodcasts", null, Arrays.asList("includeEpisodes"), Arrays.asList("false")); + try { + return new PodcastChannelParser(context).parse(reader, progressListener); + } finally { + Util.close(reader); + } + } + + @Override + public MusicDirectory getPodcastEpisodes(String id, Context context, ProgressListener progressListener) throws Exception { + Reader reader = getReader(context, progressListener, "getPodcasts", null, Arrays.asList("id"), Arrays.asList(id)); + try { + return new PodcastEntryParser(context).parse(reader, progressListener); + } finally { + Util.close(reader); + } + } + @Override public int processOfflineSyncs(final Context context, final ProgressListener progressListener) throws Exception{ return processOfflineScrobbles(context, progressListener) + processOfflineStars(context, progressListener); diff --git a/subsonic-android/src/github/daneren2005/dsub/service/parser/PodcastChannelParser.java b/subsonic-android/src/github/daneren2005/dsub/service/parser/PodcastChannelParser.java new file mode 100644 index 00000000..4fc49290 --- /dev/null +++ b/subsonic-android/src/github/daneren2005/dsub/service/parser/PodcastChannelParser.java @@ -0,0 +1,70 @@ +/* + 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 . + + Copyright 2009 (C) Sindre Mehus + */ +package github.daneren2005.dsub.service.parser; + +import android.content.Context; +import github.daneren2005.dsub.R; +import github.daneren2005.dsub.domain.PodcastChannel; +import github.daneren2005.dsub.util.ProgressListener; +import java.io.Reader; +import java.util.ArrayList; +import java.util.List; +import org.xmlpull.v1.XmlPullParser; + +/** + * + * @author Scott + */ +public class PodcastChannelParser extends AbstractParser { + public PodcastChannelParser(Context context) { + super(context); + } + + public List parse(Reader reader, ProgressListener progressListener) throws Exception { + updateProgress(progressListener, R.string.parser_reading); + init(reader); + + List channels = new ArrayList(); + int eventType; + do { + eventType = nextParseEvent(); + if (eventType == XmlPullParser.START_TAG) { + String name = getElementName(); + if ("channel".equals(name)) { + PodcastChannel channel = new PodcastChannel(); + channel.setId(get("id")); + channel.setUrl(get("url")); + channel.setName(get("title")); + channel.setDescription(get("description")); + channel.setStatus(get("status")); + + if("error".equals(channel.getStatus())) { + channel.setStatus(get("errorMessage")); + } + channels.add(channel); + } else if ("error".equals(name)) { + handleError(); + } + } + } while (eventType != XmlPullParser.END_DOCUMENT); + + validate(); + return channels; + } +} diff --git a/subsonic-android/src/github/daneren2005/dsub/service/parser/PodcastEntryParser.java b/subsonic-android/src/github/daneren2005/dsub/service/parser/PodcastEntryParser.java new file mode 100644 index 00000000..efc36a7e --- /dev/null +++ b/subsonic-android/src/github/daneren2005/dsub/service/parser/PodcastEntryParser.java @@ -0,0 +1,79 @@ +/* + 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 . + + Copyright 2009 (C) Sindre Mehus + */ +package github.daneren2005.dsub.service.parser; + +import android.content.Context; +import github.daneren2005.dsub.R; +import github.daneren2005.dsub.domain.MusicDirectory; +import github.daneren2005.dsub.domain.PodcastEpisode; +import github.daneren2005.dsub.util.ProgressListener; +import java.io.Reader; +import java.util.ArrayList; +import java.util.List; +import org.xmlpull.v1.XmlPullParser; + +/** + * + * @author Scott + */ +public class PodcastEntryParser extends AbstractParser { + public PodcastEntryParser(Context context) { + super(context); + } + + public MusicDirectory parse(Reader reader, ProgressListener progressListener) throws Exception { + updateProgress(progressListener, R.string.parser_reading); + init(reader); + + MusicDirectory episodes = new MusicDirectory(); + int eventType; + do { + eventType = nextParseEvent(); + if (eventType == XmlPullParser.START_TAG) { + String name = getElementName(); + if ("channel".equals(name)) { + episodes.setId(get("id")); + episodes.setName(get("title")); + } + else if ("episode".equals(name)) { + PodcastEpisode episode = new PodcastEpisode(); + episode.setEpisodeId(get("id")); + episode.setId(get("streamId")); + episode.setTitle(get("title")); + episode.setDescription(get("description")); + episode.setDate(get("publishDate")); + episode.setStatus(get("status")); + episode.setCoverArt(get("coverArt")); + episode.setSize(getLong("size")); + episode.setContentType(get("contentType")); + episode.setSuffix(get("suffix")); + episode.setDuration(getInteger("duration")); + episode.setBitRate(getInteger("bitRate")); + episode.setPath(get("path")); + episodes.addChild(episode); + } else if ("error".equals(name)) { + handleError(); + } + } + } while (eventType != XmlPullParser.END_DOCUMENT); + + validate(); + return episodes; + } +} diff --git a/subsonic-android/src/github/daneren2005/dsub/util/Constants.java b/subsonic-android/src/github/daneren2005/dsub/util/Constants.java index 2d7edbab..a5168a9a 100644 --- a/subsonic-android/src/github/daneren2005/dsub/util/Constants.java +++ b/subsonic-android/src/github/daneren2005/dsub/util/Constants.java @@ -55,6 +55,9 @@ public final class Constants { public static final String INTENT_EXTRA_NAME_EXIT = "subsonic.exit" ; public static final String INTENT_EXTRA_NAME_DOWNLOAD = "subsonic.download"; public static final String INTENT_EXTRA_VIEW_ALBUM = "subsonic.view_album"; + public static final String INTENT_EXTRA_NAME_PODCAST_ID = "subsonic.podcast.id"; + public static final String INTENT_EXTRA_NAME_PODCAST_NAME = "subsonic.podcast.name"; + public static final String INTENT_EXTRA_NAME_PODCAST_DESCRIPTION = "subsonic.podcast.description"; // Notification IDs. public static final int NOTIFICATION_ID_PLAYING = 100; diff --git a/subsonic-android/src/github/daneren2005/dsub/view/PodcastChannelAdapter.java b/subsonic-android/src/github/daneren2005/dsub/view/PodcastChannelAdapter.java new file mode 100644 index 00000000..6b7af991 --- /dev/null +++ b/subsonic-android/src/github/daneren2005/dsub/view/PodcastChannelAdapter.java @@ -0,0 +1,59 @@ +/* + 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 . + + Copyright 2010 (C) Sindre Mehus + */ +package github.daneren2005.dsub.view; + +import android.widget.ArrayAdapter; +import android.widget.SectionIndexer; +import android.content.Context; +import android.view.View; +import android.view.ViewGroup; +import github.daneren2005.dsub.R; +import github.daneren2005.dsub.domain.PodcastChannel; + +import java.util.List; +import java.util.Set; +import java.util.LinkedHashSet; +import java.util.ArrayList; + +/** + * @author Sindre Mehus +*/ +public class PodcastChannelAdapter extends ArrayAdapter{ + private Context activity; + private List podcasts; + + public PodcastChannelAdapter(Context context, List podcasts) { + super(context, android.R.layout.simple_list_item_1, podcasts); + this.activity = context; + this.podcasts = podcasts; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + PodcastChannel podcast = podcasts.get(position); + PodcastChannelView view; + if (convertView != null && convertView instanceof PodcastChannelView) { + view = (PodcastChannelView) convertView; + } else { + view = new PodcastChannelView(activity); + } + view.setPodcastChannel(podcast); + return view; + } +} diff --git a/subsonic-android/src/github/daneren2005/dsub/view/PodcastChannelView.java b/subsonic-android/src/github/daneren2005/dsub/view/PodcastChannelView.java new file mode 100644 index 00000000..62e67a9a --- /dev/null +++ b/subsonic-android/src/github/daneren2005/dsub/view/PodcastChannelView.java @@ -0,0 +1,53 @@ +/* + 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 . + + Copyright 2009 (C) Sindre Mehus + */ +package github.daneren2005.dsub.view; + +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.ImageButton; +import android.widget.ImageView; +import android.widget.TextView; +import github.daneren2005.dsub.R; +import github.daneren2005.dsub.domain.PodcastChannel; + +public class PodcastChannelView extends UpdateView { + private static final String TAG = PodcastChannelView.class.getSimpleName(); + + private TextView titleView; + private ImageButton starButton; + private ImageView moreButton; + + public PodcastChannelView(Context context) { + super(context); + LayoutInflater.from(context).inflate(R.layout.artist_list_item, this, true); + + titleView = (TextView) findViewById(R.id.artist_name); + starButton = (ImageButton) findViewById(R.id.artist_star); + moreButton = (ImageView) findViewById(R.id.artist_more); + moreButton.setClickable(false); + } + + public void setPodcastChannel(PodcastChannel podcastChannel) { + titleView.setText(podcastChannel.getName()); + + starButton.setVisibility(View.GONE); + starButton.setFocusable(false); + } +} diff --git a/subsonic-android/src/github/daneren2005/dsub/view/SongView.java b/subsonic-android/src/github/daneren2005/dsub/view/SongView.java index 64a1d911..6f594048 100644 --- a/subsonic-android/src/github/daneren2005/dsub/view/SongView.java +++ b/subsonic-android/src/github/daneren2005/dsub/view/SongView.java @@ -87,7 +87,10 @@ public class SongView extends UpdateView implements Checkable { } if(!song.isVideo()) { - artist.append(song.getArtist()).append(" (") + if(song.getArtist() != null) { + artist.append(song.getArtist()); + } + artist.append(" (") .append(String.format(getContext().getString(R.string.song_details_all), bitRate == null ? "" : bitRate, fileFormat)) .append(")"); } else { @@ -101,7 +104,7 @@ public class SongView extends UpdateView implements Checkable { } titleTextView.setText(title); - artistTextView.setText(artist); + artistTextView.setText(artist); durationTextView.setText(Util.formatDuration(song.getDuration())); checkedTextView.setVisibility(checkable && !song.isVideo() ? View.VISIBLE : View.GONE); starButton.setVisibility(!song.isStarred() ? View.GONE : View.VISIBLE); -- cgit v1.2.3