/*
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 github.daneren2005.dsub.service;
import java.io.File;
import java.io.Reader;
import java.io.FileReader;
import java.net.HttpURLConnection;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import java.util.Set;
import android.content.Context;
import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.util.Log;
import github.daneren2005.dsub.domain.Artist;
import github.daneren2005.dsub.domain.ArtistInfo;
import github.daneren2005.dsub.domain.ChatMessage;
import github.daneren2005.dsub.domain.Genre;
import github.daneren2005.dsub.domain.Indexes;
import github.daneren2005.dsub.domain.InternetRadioStation;
import github.daneren2005.dsub.domain.MusicDirectory.Entry;
import github.daneren2005.dsub.domain.PlayerQueue;
import github.daneren2005.dsub.domain.PodcastEpisode;
import github.daneren2005.dsub.domain.RemoteStatus;
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.SearchCritera;
import github.daneren2005.dsub.domain.SearchResult;
import github.daneren2005.dsub.domain.Share;
import github.daneren2005.dsub.domain.User;
import github.daneren2005.dsub.util.Constants;
import github.daneren2005.dsub.util.FileUtil;
import github.daneren2005.dsub.util.Pair;
import github.daneren2005.dsub.util.ProgressListener;
import github.daneren2005.dsub.util.SilentBackgroundTask;
import github.daneren2005.dsub.util.SongDBHandler;
import github.daneren2005.dsub.util.Util;
import java.io.*;
import java.util.Comparator;
import java.util.SortedSet;
/**
* @author Sindre Mehus
*/
public class OfflineMusicService implements MusicService {
private static final String TAG = OfflineMusicService.class.getSimpleName();
private static final String ERRORMSG = "Not available in offline mode";
private static final Random random = new Random();
@Override
public void ping(Context context, ProgressListener progressListener) throws Exception {
}
@Override
public boolean isLicenseValid(Context context, ProgressListener progressListener) throws Exception {
return true;
}
@Override
public Indexes getIndexes(String musicFolderId, boolean refresh, Context context, ProgressListener progressListener) throws Exception {
List<Artist> artists = new ArrayList<Artist>();
List<Entry> entries = new ArrayList<>();
File root = FileUtil.getMusicDirectory(context);
for (File file : FileUtil.listFiles(root)) {
if (file.isDirectory()) {
Artist artist = new Artist();
artist.setId(file.getPath());
artist.setIndex(file.getName().substring(0, 1));
artist.setName(file.getName());
artists.add(artist);
} else if(!file.getName().equals("albumart.jpg") && !file.getName().equals(".nomedia")) {
entries.add(createEntry(context, file));
}
}
Indexes indexes = new Indexes(0L, Collections.<Artist>emptyList(), artists, entries);
return indexes;
}
@Override
public MusicDirectory getMusicDirectory(String id, String artistName, boolean refresh, Context context, ProgressListener progressListener) throws Exception {
return getMusicDirectory(id, artistName, refresh, context, progressListener, false);
}
private MusicDirectory getMusicDirectory(String id, String artistName, boolean refresh, Context context, ProgressListener progressListener, boolean isPodcast) throws Exception {
File dir = new File(id);
MusicDirectory result = new MusicDirectory();
result.setName(dir.getName());
Set<String> names = new HashSet<String>();
for (File file : FileUtil.listMediaFiles(dir)) {
String name = getName(file);
if (name != null & !names.contains(name)) {
names.add(name);
result.addChild(createEntry(context, file, name, true, isPodcast));
}
}
result.sortChildren(Util.getPreferences(context).getBoolean(Constants.PREFERENCES_KEY_CUSTOM_SORT_ENABLED, true));
return result;
}
@Override
public MusicDirectory getArtist(String id, String name, boolean refresh, Context context, ProgressListener progressListener) throws Exception {
throw new OfflineException(ERRORMSG);
}
@Override
public MusicDirectory getAlbum(String id, String name, boolean refresh, Context context, ProgressListener progressListener) throws Exception {
throw new OfflineException(ERRORMSG);
}
private String getName(File file) {
String name = file.getName();
if (file.isDirectory()) {
return name;
}
if (name.endsWith(".partial") || name.contains(".partial.") || name.equals(Constants.ALBUM_ART_FILE)) {
return null;
}
name = name.replace(".complete", "");
return FileUtil.getBaseName(name);
}
private Entry createEntry(Context context, File file) {
return createEntry(context, file, getName(file));
}
private Entry createEntry(Context context, File file, String name) {
return createEntry(context, file, name, true);
}
private Entry createEntry(Context context, File file, String name, boolean load) {
return createEntry(context, file, name, load, false);
}
private Entry createEntry(Context context, File file, String name, boolean load, boolean isPodcast) {
Entry entry;
if(isPodcast) {
PodcastEpisode episode = new PodcastEpisode();
episode.setStatus("completed");
entry = episode;
} else {
entry = new Entry();
}
entry.setDirectory(file.isDirectory());
entry.setId(file.getPath());
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()) {
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) {
try {
entry.setTrack(Integer.parseInt(name.substring(0, index)));
title = title.substring(index + 1);
} catch(Exception e) {
// Failed parseInt, just means track filled out
}
}
if(load) {
entry.loadMetadata(file);
}
}
entry.setTitle(title);
entry.setSuffix(FileUtil.getExtension(file.getName().replace(".complete", "")));
File albumArt = FileUtil.getAlbumArtFile(context, entry);
if (albumArt.exists()) {
entry.setCoverArt(albumArt.getPath());
}
if(FileUtil.isVideoFile(file)) {
entry.setVideo(true);
}
return entry;
}
@Override
public Bitmap getCoverArt(Context context, Entry entry, int size, ProgressListener progressListener, SilentBackgroundTask task) throws Exception {
try {
return FileUtil.getAlbumArtBitmap(context, entry, size);
} catch(Exception e) {
return null;
}
}
@Override
public HttpURLConnection getDownloadInputStream(Context context, Entry song, long offset, int maxBitrate, SilentBackgroundTask task) throws Exception {
throw new OfflineException(ERRORMSG);
}
@Override
public String getMusicUrl(Context context, Entry song, int maxBitrate) throws Exception {
throw new OfflineException(ERRORMSG);
}
@Override
public List<MusicFolder> getMusicFolders(boolean refresh, Context context, ProgressListener progressListener) throws Exception {
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>();
List<Entry> albums = new ArrayList<Entry>();
List<Entry> songs = new ArrayList<Entry>();
File root = FileUtil.getMusicDirectory(context);
int closeness = 0;
for (File artistFile : FileUtil.listFiles(root)) {
String artistName = artistFile.getName();
if (artistFile.isDirectory()) {
if((closeness = matchCriteria(criteria, artistName)) > 0) {
Artist artist = new Artist();
artist.setId(artistFile.getPath());
artist.setIndex(artistFile.getName().substring(0, 1));
artist.setName(artistName);
artist.setCloseness(closeness);
artists.add(artist);
}
recursiveAlbumSearch(artistName, artistFile, criteria, context, albums, songs);
}
}
Collections.sort(artists, new Comparator<Artist>() {
public int compare(Artist lhs, Artist rhs) {
if(lhs.getCloseness() == rhs.getCloseness()) {
return 0;
}
else if(lhs.getCloseness() > rhs.getCloseness()) {
return -1;
}
else {
return 1;
}
}
});
Collections.sort(albums, new Comparator<Entry>() {
public int compare(Entry lhs, Entry rhs) {
if(lhs.getCloseness() == rhs.getCloseness()) {
return 0;
}
else if(lhs.getCloseness() > rhs.getCloseness()) {
return -1;
}
else {
return 1;
}
}
});
Collections.sort(songs, new Comparator<Entry>() {
public int compare(Entry lhs, Entry rhs) {
if(lhs.getCloseness() == rhs.getCloseness()) {
return 0;
}
else if(lhs.getCloseness() > rhs.getCloseness()) {
return -1;
}
else {
return 1;
}
}
});
// Respect counts in search criteria
int artistCount = Math.min(artists.size(), criteria.getArtistCount());
int albumCount = Math.min(albums.size(), criteria.getAlbumCount());
int songCount = Math.min(songs.size(), criteria.getSongCount());
artists = artists.subList(0, artistCount);
albums = albums.subList(0, albumCount);
songs = songs.subList(0, songCount);
return new SearchResult(artists, albums, songs);
}
@Override
public MusicDirectory getStarredList(Context context, ProgressListener progressListener) throws Exception {
throw new OfflineException(ERRORMSG);
}
private void recursiveAlbumSearch(String artistName, File file, SearchCritera criteria, Context context, List<Entry> albums, List<Entry> songs) {
int closeness;
for(File albumFile : FileUtil.listMediaFiles(file)) {
if(albumFile.isDirectory()) {
String albumName = getName(albumFile);
if((closeness = matchCriteria(criteria, albumName)) > 0) {
Entry album = createEntry(context, albumFile, albumName);
album.setArtist(artistName);
album.setCloseness(closeness);
albums.add(album);
}
for(File songFile : FileUtil.listMediaFiles(albumFile)) {
String songName = getName(songFile);
if(songName == null) {
continue;
}
if(songFile.isDirectory()) {
recursiveAlbumSearch(artistName, songFile, criteria, context, albums, songs);
}
else if((closeness = matchCriteria(criteria, songName)) > 0){
Entry song = createEntry(context, albumFile, songName);
song.setArtist(artistName);
song.setAlbum(albumName);
song.setCloseness(closeness);
songs.add(song);
}
}
}
else {
String songName = getName(albumFile);
if((closeness = matchCriteria(criteria, songName)) > 0) {
Entry song = createEntry(context, albumFile, songName);
song.setArtist(artistName);
song.setAlbum(songName);
song.setCloseness(closeness);
songs.add(song);
}
}
}
}
private int matchCriteria(SearchCritera criteria, String name) {
if (criteria.getPattern().matcher(name).matches()) {
return Util.getStringDistance(
criteria.getQuery().toLowerCase(),
name.toLowerCase());
} else {
return 0;
}
}
@Override
public List<Playlist> getPlaylists(boolean refresh, Context context, ProgressListener progressListener) throws Exception {
List<Playlist> playlists = new ArrayList<Playlist>();
File root = FileUtil.getPlaylistDirectory(context);
String lastServer = null;
boolean removeServer = true;
for (File folder : FileUtil.listFiles(root)) {
if(folder.isDirectory()) {
String server = folder.getName();
SortedSet<File> fileList = FileUtil.listFiles(folder);
for(File file: fileList) {
if(FileUtil.isPlaylistFile(file)) {
String id = file.getName();
String filename = FileUtil.getBaseName(id);
String name = server + ": " + filename;
Playlist playlist = new Playlist(server, name);
playlist.setComment(filename);
Reader reader = null;
BufferedReader buffer = null;
int songCount = 0;
try {
reader = new FileReader(file);
buffer = new BufferedReader(reader);
String line = buffer.readLine();
while( (line = buffer.readLine()) != null ){
// No matter what, end file can't have .complete in it
line = line.replace(".complete", "");
File entryFile = new File(line);
// Don't add file to playlist if it doesn't exist as cached or pinned!
File checkFile = entryFile;
if(!checkFile.exists()) {
// If normal file doens't exist, check if .complete version does
checkFile = new File(entryFile.getParent(), FileUtil.getBaseName(entryFile.getName())
+ ".complete." + FileUtil.getExtension(entryFile.getName()));
}
String entryName = getName(entryFile);
if(checkFile.exists() && entryName != null){
songCount++;
}
}
playlist.setSongCount(Integer.toString(songCount));
} catch(Exception e) {
Log.w(TAG, "Failed to count songs in playlist", e);
} finally {
Util.close(buffer);
Util.close(reader);
}
if(songCount > 0) {
playlists.add(playlist);
}
}
}
if(!server.equals(lastServer) && fileList.size() > 0) {
if(lastServer != null) {
removeServer = false;
}
lastServer = server;
}
} else {
// Delete legacy playlist files
try {
folder.delete();
} catch(Exception e) {
Log.w(TAG, "Failed to delete old playlist file: " + folder.getName());
}
}
}
if(removeServer) {
for(Playlist playlist: playlists) {
playlist.setName(playlist.getName().substring(playlist.getId().length() + 2));
}
}
return playlists;
}
@Override
public MusicDirectory getPlaylist(boolean refresh, String id, String name, Context context, ProgressListener progressListener) throws Exception {
DownloadService downloadService = DownloadService.getInstance();
if (downloadService == null) {
return new MusicDirectory();
}
Reader reader = null;
BufferedReader buffer = null;
try {
int firstIndex = name.indexOf(id);
if(firstIndex != -1) {
name = name.substring(id.length() + 2);
}
File playlistFile = FileUtil.getPlaylistFile(context, id, name);
reader = new FileReader(playlistFile);
buffer = new BufferedReader(reader);
MusicDirectory playlist = new MusicDirectory();
String line = buffer.readLine();
if(!"#EXTM3U".equals(line)) return playlist;
while( (line = buffer.readLine()) != null ){
// No matter what, end file can't have .complete in it
line = line.replace(".complete", "");
File entryFile = new File(line);
// Don't add file to playlist if it doesn't exist as cached or pinned!
File checkFile = entryFile;
if(!checkFile.exists()) {
// If normal file doens't exist, check if .complete version does
checkFile = new File(entryFile.getParent(), FileUtil.getBaseName(entryFile.getName())
+ ".complete." + FileUtil.getExtension(entryFile.getName()));
}
String entryName = getName(entryFile);
if(checkFile.exists() && entryName != null){
playlist.addChild(createEntry(context, entryFile, entryName, false));
}
}
return playlist;
} finally {
Util.close(buffer);
Util.close(reader);
}
}
@Override
public void createPlaylist(String id, String name, List<Entry> entries, Context context, ProgressListener progressListener) throws Exception {
throw new OfflineException(ERRORMSG);
}
@Override
public void deletePlaylist(String id, Context context, ProgressListener progressListener) throws Exception {
throw new OfflineException(ERRORMSG);
}
@Override
public void addToPlaylist(String id, List<Entry> toAdd, Context context, ProgressListener progressListener) throws Exception {
throw new OfflineException(ERRORMSG);
}
@Override
public void removeFromPlaylist(String id, List<Integer> toRemove, Context context, ProgressListener progressListener) throws Exception {
throw new OfflineException(ERRORMSG);
}
@Override
public void overwritePlaylist(String id, String name, int toRemove, List<Entry> toAdd, Context context, ProgressListener progressListener) throws Exception {
throw new OfflineException(ERRORMSG);
}
@Override
public void updatePlaylist(String id, String name, String comment, boolean pub, Context context, ProgressListener progressListener) throws Exception {
throw new OfflineException(ERRORMSG);
}
@Override
public Lyrics getLyrics(String artist, String title, Context context, ProgressListener progressListener) throws Exception {
throw new OfflineException(ERRORMSG);
}
@Override
public void scrobble(String id, boolean submission, Context context, ProgressListener progressListener) throws Exception {
if(!submission) {
return;
}
SharedPreferences prefs = Util.getPreferences(context);
String cacheLocn = prefs.getString(Constants.PREFERENCES_KEY_CACHE_LOCATION, null);
SharedPreferences offline = Util.getOfflineSync(context);
int scrobbles = offline.getInt(Constants.OFFLINE_SCROBBLE_COUNT, 0);
scrobbles++;
SharedPreferences.Editor offlineEditor = offline.edit();
if(id.indexOf(cacheLocn) != -1) {
Pair<Integer, String> cachedSongId = SongDBHandler.getHandler(context).getIdFromPath(id);
if(cachedSongId != null) {
offlineEditor.putString(Constants.OFFLINE_SCROBBLE_ID + scrobbles, cachedSongId.getSecond());
offlineEditor.remove(Constants.OFFLINE_SCROBBLE_SEARCH + scrobbles);
} else {
String scrobbleSearchCriteria = Util.parseOfflineIDSearch(context, id, cacheLocn);
offlineEditor.putString(Constants.OFFLINE_SCROBBLE_SEARCH + scrobbles, scrobbleSearchCriteria);
offlineEditor.remove(Constants.OFFLINE_SCROBBLE_ID + scrobbles);
}
} else {
offlineEditor.putString(Constants.OFFLINE_SCROBBLE_ID + scrobbles, id);
offlineEditor.remove(Constants.OFFLINE_SCROBBLE_SEARCH + scrobbles);
}
offlineEditor.putLong(Constants.OFFLINE_SCROBBLE_TIME + scrobbles, System.currentTimeMillis());
offlineEditor.putInt(Constants.OFFLINE_SCROBBLE_COUNT, scrobbles);
offlineEditor.commit();
}
@Override
public MusicDirectory getAlbumList(String type, int size, int offset, boolean refresh, Context context, ProgressListener progressListener) throws Exception {
throw new OfflineException(ERRORMSG);
}
@Override
public MusicDirectory getAlbumList(String type, String extra, int size, int offset, boolean refresh, Context context, ProgressListener progressListener) throws Exception {
throw new OfflineException(ERRORMSG);
}
@Override
public MusicDirectory getSongList(String type, int size, int offset, Context context, ProgressListener progressListener) throws Exception {
throw new OfflineException(ERRORMSG);
}
@Override
public MusicDirectory getRandomSongs(int size, String artistId, Context context, ProgressListener progressListener) throws Exception {
throw new OfflineException(ERRORMSG);
}
@Override
public String getVideoUrl(int maxBitrate, Context context, String id) {
return null;
}
@Override
public String getVideoStreamUrl(String format, int maxBitrate, Context context, String id) throws Exception {
throw new OfflineException(ERRORMSG);
}
@Override
public String getHlsUrl(String id, int bitRate, Context context) throws Exception {
throw new OfflineException(ERRORMSG);
}
@Override
public RemoteStatus updateJukeboxPlaylist(List<String> ids, Context context, ProgressListener progressListener) throws Exception {
throw new OfflineException(ERRORMSG);
}
@Override
public RemoteStatus skipJukebox(int index, int offsetSeconds, Context context, ProgressListener progressListener) throws Exception {
throw new OfflineException(ERRORMSG);
}
@Override
public RemoteStatus stopJukebox(Context context, ProgressListener progressListener) throws Exception {
throw new OfflineException(ERRORMSG);
}
@Override
public RemoteStatus startJukebox(Context context, ProgressListener progressListener) throws Exception {
throw new OfflineException(ERRORMSG);
}
@Override
public RemoteStatus getJukeboxStatus(Context context, ProgressListener progressListener) throws Exception {
throw new OfflineException(ERRORMSG);
}
@Override
public RemoteStatus setJukeboxGain(float gain, Context context, ProgressListener progressListener) throws Exception {
throw new OfflineException(ERRORMSG);
}
@Override
public void setStarred(List<Entry> entries, List<Entry> artists, List<Entry> albums, boolean starred, ProgressListener progressListener, Context context) throws Exception {
SharedPreferences prefs = Util.getPreferences(context);
String cacheLocn = prefs.getString(Constants.PREFERENCES_KEY_CACHE_LOCATION, null);
SharedPreferences offline = Util.getOfflineSync(context);
int stars = offline.getInt(Constants.OFFLINE_STAR_COUNT, 0);
stars++;
SharedPreferences.Editor offlineEditor = offline.edit();
String id = entries.get(0).getId();
if(id.indexOf(cacheLocn) != -1) {
String searchCriteria = Util.parseOfflineIDSearch(context, id, cacheLocn);
offlineEditor.putString(Constants.OFFLINE_STAR_SEARCH + stars, searchCriteria);
offlineEditor.remove(Constants.OFFLINE_STAR_ID + stars);
} else {
offlineEditor.putString(Constants.OFFLINE_STAR_ID + stars, id);
offlineEditor.remove(Constants.OFFLINE_STAR_SEARCH + stars);
}
offlineEditor.putBoolean(Constants.OFFLINE_STAR_SETTING + stars, starred);
offlineEditor.putInt(Constants.OFFLINE_STAR_COUNT, stars);
offlineEditor.commit();
}
@Override
public List<Share> getShares(Context context, ProgressListener progressListener) throws Exception {
throw new OfflineException(ERRORMSG);
}
@Override
public List<Share> createShare(List<String> ids, String description, Long expires, Context context, ProgressListener progressListener) throws Exception {
throw new OfflineException(ERRORMSG);
}
@Override
public void deleteShare(String id, Context context, ProgressListener progressListener) throws Exception {
throw new OfflineException(ERRORMSG);
}
@Override
public void updateShare(String id, String description, Long expires, Context context, ProgressListener progressListener) throws Exception {
throw new OfflineException(ERRORMSG);
}
@Override
public List<ChatMessage> getChatMessages(Long since, Context context, ProgressListener progressListener) throws Exception {
throw new OfflineException(ERRORMSG);
}
@Override
public void addChatMessage(String message, Context context, ProgressListener progressListener) throws Exception {
throw new OfflineException(ERRORMSG);
}
@Override
public List<Genre> getGenres(boolean refresh, Context context, ProgressListener progressListener) throws Exception {
throw new OfflineException(ERRORMSG);
}
@Override
public MusicDirectory getSongsByGenre(String genre, int count, int offset, Context context, ProgressListener progressListener) throws Exception {
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);
List<File> children = new LinkedList<File>();
listFilesRecursively(root, children);
MusicDirectory result = new MusicDirectory();
if (children.isEmpty()) {
return result;
}
for (int i = 0; i < size; i++) {
File file = children.get(random.nextInt(children.size()));
result.addChild(createEntry(context, file, getName(file)));
}
return result;
}
@Override
public String getCoverArtUrl(Context context, Entry entry) throws Exception {
throw new OfflineException(ERRORMSG);
}
@Override
public List<PodcastChannel> getPodcastChannels(boolean refresh, Context context, ProgressListener progressListener) throws Exception {
List<PodcastChannel> channels = new ArrayList<PodcastChannel>();
File dir = FileUtil.getPodcastDirectory(context);
String line;
for(File file: dir.listFiles()) {
BufferedReader br = new BufferedReader(new FileReader(file));
while ((line = br.readLine()) != null && !"".equals(line)) {
String[] parts = line.split("\t");
PodcastChannel channel = new PodcastChannel();
channel.setId(parts[0]);
channel.setName(parts[0]);
channel.setStatus("completed");
File albumArt = FileUtil.getAlbumArtFile(context, channel);
if (albumArt.exists()) {
channel.setCoverArt(albumArt.getPath());
}
if(parts.length > 1) {
channel.setUrl(parts[1]);
}
if(FileUtil.getPodcastDirectory(context, channel).exists() && !channels.contains(channel)) {
channels.add(channel);
}
}
br.close();
}
return channels;
}
@Override
public MusicDirectory getPodcastEpisodes(boolean refresh, String id, Context context, ProgressListener progressListener) throws Exception {
return getMusicDirectory(FileUtil.getPodcastDirectory(context, id).getPath(), null, false, context, progressListener, true);
}
@Override
public MusicDirectory getNewestPodcastEpisodes(boolean refresh, Context context, ProgressListener progressListener, int count) throws Exception {
throw new OfflineException(ERRORMSG);
}
@Override
public void refreshPodcasts(Context context, ProgressListener progressListener) throws Exception {
throw new OfflineException(ERRORMSG);
}
@Override
public void createPodcastChannel(String url, Context context, ProgressListener progressListener) throws Exception{
throw new OfflineException(ERRORMSG);
}
@Override
public void deletePodcastChannel(String id, Context context, ProgressListener progressListener) throws Exception{
throw new OfflineException(ERRORMSG);
}
@Override
public void downloadPodcastEpisode(String id, Context context, ProgressListener progressListener) throws Exception{
throw new OfflineException(ERRORMSG);
}
@Override
public void deletePodcastEpisode(String id, String parent, ProgressListener progressListener, Context context) throws Exception{
throw new OfflineException(ERRORMSG);
}
@Override
public void setRating(Entry entry, int rating, Context context, ProgressListener progressListener) throws Exception {
throw new OfflineException(ERRORMSG);
}
@Override
public MusicDirectory getBookmarks(boolean refresh, Context context, ProgressListener progressListener) throws Exception {
throw new OfflineException(ERRORMSG);
}
@Override
public void createBookmark(Entry entry, int position, String comment, Context context, ProgressListener progressListener) throws Exception {
throw new OfflineException(ERRORMSG);
}
@Override
public void deleteBookmark(Entry entry, Context context, ProgressListener progressListener) throws Exception {
throw new OfflineException(ERRORMSG);
}
@Override
public User getUser(boolean refresh, String username, Context context, ProgressListener progressListener) throws Exception {
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 getAvatar(String username, int size, Context context, ProgressListener progressListener, SilentBackgroundTask task) throws Exception {
throw new OfflineException(ERRORMSG);
}
@Override
public ArtistInfo getArtistInfo(String id, boolean refresh, boolean allowNetwork, 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);
}
@Override
public MusicDirectory getVideos(boolean refresh, Context context, ProgressListener progressListener) throws Exception {
throw new OfflineException(ERRORMSG);
}
@Override
public void savePlayQueue(List<Entry> songs, Entry currentPlaying, int position, Context context, ProgressListener progressListener) throws Exception {
throw new OfflineException(ERRORMSG);
}
@Override
public PlayerQueue getPlayQueue(Context context, ProgressListener progressListener) throws Exception {
throw new OfflineException(ERRORMSG);
}
@Override
public List<InternetRadioStation> getInternetRadioStations(boolean refresh, Context context, ProgressListener progressListener) throws Exception {
throw new OfflineException(ERRORMSG);
}
@Override
public int processOfflineSyncs(final Context context, final ProgressListener progressListener) throws Exception{
throw new OfflineException(ERRORMSG);
}
@Override
public void setInstance(Integer instance) throws Exception{
throw new OfflineException(ERRORMSG);
}
private void listFilesRecursively(File parent, List<File> children) {
for (File file : FileUtil.listMediaFiles(parent)) {
if (file.isFile()) {
children.add(file);
} else {
listFilesRecursively(file, children);
}
}
}
}