diff --git a/.idea/compiler.xml b/.idea/compiler.xml index 5a367df9..920a0f89 100644 --- a/.idea/compiler.xml +++ b/.idea/compiler.xml @@ -34,8 +34,6 @@ - - diff --git a/src/com/thejoshwa/ultrasonic/androidapp/service/DownloadFile.java b/src/com/thejoshwa/ultrasonic/androidapp/service/DownloadFile.java index 6d2bfd0d..1c1bbf8e 100644 --- a/src/com/thejoshwa/ultrasonic/androidapp/service/DownloadFile.java +++ b/src/com/thejoshwa/ultrasonic/androidapp/service/DownloadFile.java @@ -37,6 +37,7 @@ import com.thejoshwa.ultrasonic.androidapp.util.CacheCleaner; import org.apache.http.HttpResponse; import org.apache.http.HttpStatus; +import org.apache.http.Header; /** * @author Sindre Mehus @@ -59,6 +60,7 @@ public class DownloadFile { private volatile boolean isPlaying = false; private volatile boolean saveWhenDone = false; private volatile boolean completeWhenDone = false; + private Integer contentLength = null; public DownloadFile(Context context, MusicDirectory.Entry song, boolean save) { this.context = context; @@ -91,6 +93,10 @@ public class DownloadFile { return song.getBitRate() == null ? 160 : song.getBitRate(); } + public Integer getContentLength() { + return contentLength; + } + public synchronized void download() { FileUtil.createDirectoryForParent(saveFile); failed = false; @@ -281,6 +287,17 @@ 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; diff --git a/src/com/thejoshwa/ultrasonic/androidapp/service/DownloadServiceImpl.java b/src/com/thejoshwa/ultrasonic/androidapp/service/DownloadServiceImpl.java index c7c3bd46..5f4d1be5 100644 --- a/src/com/thejoshwa/ultrasonic/androidapp/service/DownloadServiceImpl.java +++ b/src/com/thejoshwa/ultrasonic/androidapp/service/DownloadServiceImpl.java @@ -191,21 +191,6 @@ public class DownloadServiceImpl extends Service implements DownloadService { audioManager = (AudioManager) this.getSystemService(Context.AUDIO_SERVICE); - if (mediaPlayer != null) { - mediaPlayer.release(); - } - - mediaPlayer = new MediaPlayer(); - mediaPlayer.setWakeMode(this, PowerManager.PARTIAL_WAKE_LOCK); - mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); - mediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() { - @Override - public boolean onError(MediaPlayer mediaPlayer, int what, int more) { - handleError(new Exception("MediaPlayer error: " + what + " (" + more + ")")); - return false; - } - }); - notification.flags |= Notification.FLAG_NO_CLEAR | Notification.FLAG_ONGOING_EVENT; notification.contentView = new RemoteViews(this.getPackageName(), R.layout.notification); Util.linkButtons(this, notification.contentView, false); @@ -251,6 +236,8 @@ public class DownloadServiceImpl extends Service implements DownloadService { @Override public void onDestroy() { super.onDestroy(); + + instance = null; lifecycleSupport.onDestroy(); mediaPlayer.release(); @@ -287,7 +274,6 @@ public class DownloadServiceImpl extends Service implements DownloadService { audioManager.unregisterRemoteControlClient(remoteControlClient); notification = null; - instance = null; } public static DownloadService getInstance() { @@ -321,14 +307,21 @@ public class DownloadServiceImpl extends Service implements DownloadService { DownloadFile downloadFile = new DownloadFile(this, song, save); downloadList.add(getCurrentPlayingIndex() + offset, downloadFile); offset++; - } + } 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++; } @@ -357,6 +350,8 @@ public class DownloadServiceImpl extends Service implements DownloadService { DownloadFile downloadFile = new DownloadFile(this, song, save); backgroundDownloadList.add(downloadFile); } + + revision++; checkDownloads(); lifecycleSupport.serializeDownloadQueue(); @@ -373,6 +368,10 @@ public class DownloadServiceImpl extends Service implements DownloadService { download(songs, false, false, false, false, newPlaylist); if (currentPlayingIndex != -1) { + while (mediaPlayer == null) { + Util.sleepQuietly(50L); + } + play(currentPlayingIndex, autoPlayStart); if (currentPlaying != null) { @@ -607,6 +606,14 @@ public class DownloadServiceImpl extends Service implements DownloadService { } synchronized void setNextPlaying() { + boolean gaplessPlayback = Util.getGaplessPlaybackPreference(DownloadServiceImpl.this); + + if (!gaplessPlayback) { + nextPlaying = null; + nextPlayerState = IDLE; + return; + } + int index = getCurrentPlayingIndex(); if (index != -1) { switch (getRepeatMode()) { @@ -1312,9 +1319,7 @@ public class DownloadServiceImpl extends Service implements DownloadService { try { setNextPlayerState(PREPARED); - boolean gaplessPlayback = Util.getGaplessPlaybackPreference(DownloadServiceImpl.this); - - if (gaplessPlayback && Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN && (playerState == PlayerState.STARTED || playerState == PlayerState.PAUSED)) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN && (playerState == PlayerState.STARTED || playerState == PlayerState.PAUSED)) { mediaPlayer.setNextMediaPlayer(nextMediaPlayer); nextSetup = true; } @@ -1506,7 +1511,8 @@ public class DownloadServiceImpl extends Service implements DownloadService { DownloadFile downloadFile = backgroundDownloadList.get(i); if (downloadFile.isWorkDone() && (!downloadFile.shouldSave() || downloadFile.isSaved())) { // Don't need to keep list like active song list - backgroundDownloadList.remove(downloadFile); + backgroundDownloadList.remove(i); + revision++; i--; } else { currentDownloading = downloadFile; diff --git a/src/com/thejoshwa/ultrasonic/androidapp/service/DownloadServiceLifecycleSupport.java b/src/com/thejoshwa/ultrasonic/androidapp/service/DownloadServiceLifecycleSupport.java index 4cedd826..baef4dde 100644 --- a/src/com/thejoshwa/ultrasonic/androidapp/service/DownloadServiceLifecycleSupport.java +++ b/src/com/thejoshwa/ultrasonic/androidapp/service/DownloadServiceLifecycleSupport.java @@ -24,6 +24,7 @@ import java.util.List; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.locks.ReentrantLock; import android.content.BroadcastReceiver; @@ -56,6 +57,7 @@ public class DownloadServiceLifecycleSupport { private PhoneStateListener phoneStateListener; private boolean externalStorageAvailable= true; private ReentrantLock lock = new ReentrantLock(); + private final AtomicBoolean setup = new AtomicBoolean(false); /** * This receiver manages the intent that could come from other applications. @@ -186,6 +188,10 @@ public class DownloadServiceLifecycleSupport { } public void serializeDownloadQueue() { + if(!setup.get()) { + return; + } + new SerializeTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } @@ -307,6 +313,7 @@ public class DownloadServiceLifecycleSupport { try { lock.lock(); deserializeDownloadQueueNow(); + setup.set(true); } finally { lock.unlock(); } diff --git a/src/com/thejoshwa/ultrasonic/androidapp/service/OfflineMusicService.java b/src/com/thejoshwa/ultrasonic/androidapp/service/OfflineMusicService.java index 2ffeaaca..1f2558b4 100644 --- a/src/com/thejoshwa/ultrasonic/androidapp/service/OfflineMusicService.java +++ b/src/com/thejoshwa/ultrasonic/androidapp/service/OfflineMusicService.java @@ -30,6 +30,7 @@ import java.util.LinkedList; import java.util.List; import java.util.Random; import java.util.Set; +import java.util.SortedSet; import java.util.concurrent.TimeUnit; import android.content.Context; @@ -47,6 +48,7 @@ import com.thejoshwa.ultrasonic.androidapp.domain.Playlist; import com.thejoshwa.ultrasonic.androidapp.domain.SearchCriteria; import com.thejoshwa.ultrasonic.androidapp.domain.SearchResult; import com.thejoshwa.ultrasonic.androidapp.util.Constants; +import com.thejoshwa.ultrasonic.androidapp.util.EntryByDiscAndTrackComparator; import com.thejoshwa.ultrasonic.androidapp.util.FileUtil; import com.thejoshwa.ultrasonic.androidapp.util.ProgressListener; import com.thejoshwa.ultrasonic.androidapp.util.Util; @@ -62,64 +64,89 @@ public class OfflineMusicService extends RESTMusicService { return true; } - @Override - public Indexes getIndexes(String musicFolderId, boolean refresh, Context context, ProgressListener progressListener) throws Exception { - List artists = 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.setName(file.getName()); - - String artistIndex = ""; - - try { - artistIndex = file.getName().substring(0, 1); - } - catch (Exception ignored) { } - - artist.setIndex(artistIndex); - - artists.add(artist); - } - } - return new Indexes(0L, Collections.emptyList(), artists); - } + @Override + public Indexes getIndexes(String musicFolderId, boolean refresh, Context context, ProgressListener progressListener) throws Exception { + List artists = 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); + } + } - @Override - public MusicDirectory getMusicDirectory(String id, String artistName, boolean refresh, Context context, ProgressListener progressListener) throws Exception { - File dir = new File(id); - MusicDirectory result = new MusicDirectory(); - result.setName(dir.getName()); + String ignoredArticlesString = "The El La Los Las Le Les"; + final String[] ignoredArticles = ignoredArticlesString.split(" "); - Set names = new HashSet(); + Collections.sort(artists, new Comparator() { + public int compare(Artist lhsArtist, Artist rhsArtist) { + String lhs = lhsArtist.getName().toLowerCase(); + String rhs = rhsArtist.getName().toLowerCase(); - 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)); - } - } - return result; - } + char lhs1 = lhs.charAt(0); + char rhs1 = rhs.charAt(0); - private String getName(File file) { - String name = file.getName(); - if (file.isDirectory()) { - return name; - } + if(Character.isDigit(lhs1) && !Character.isDigit(rhs1)) { + return 1; + } else if(Character.isDigit(rhs1) && !Character.isDigit(lhs1)) { + return -1; + } - if (name.endsWith(".partial") || name.contains(".partial.") || name.equals(Constants.ALBUM_ART_FILE)) { - return null; - } + for(String article: ignoredArticles) { + int index = lhs.indexOf(article.toLowerCase() + " "); + if(index == 0) { + lhs = lhs.substring(article.length() + 1); + } + index = rhs.indexOf(article.toLowerCase() + " "); + if(index == 0) { + rhs = rhs.substring(article.length() + 1); + } + } - name = name.replace(".complete", ""); - return FileUtil.getBaseName(name); - } + return lhs.compareTo(rhs); + } + }); - private MusicDirectory.Entry createEntry(Context context, File file, String name) { + return new Indexes(0L, Collections.emptyList(), artists); + } + + @Override + public MusicDirectory getMusicDirectory(String id, String artistName, boolean refresh, Context context, ProgressListener progressListener) throws Exception { + File dir = new File(id); + MusicDirectory result = new MusicDirectory(); + result.setName(dir.getName()); + + Set names = new HashSet(); + + 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)); + } + } + + return result; + } + + 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 MusicDirectory.Entry createEntry(Context context, File file, String name) { MusicDirectory.Entry entry = new MusicDirectory.Entry(); entry.setIsDirectory(file.isDirectory()); entry.setId(file.getPath()); @@ -277,18 +304,17 @@ public class OfflineMusicService extends RESTMusicService { throw new OfflineException("Music folders not available in offline mode"); } - @Override - public SearchResult search(SearchCriteria criteria, Context context, ProgressListener progressListener) throws Exception { + @Override + public SearchResult search(SearchCriteria criteria, Context context, ProgressListener progressListener) throws Exception { List artists = new ArrayList(); List albums = new ArrayList(); List songs = new ArrayList(); - File root = FileUtil.getMusicDirectory(context); - int closeness; - - for (File artistFile : FileUtil.listFiles(root)) { + 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) { + if (artistFile.isDirectory()) { + if((closeness = matchCriteria(criteria, artistName)) > 0) { Artist artist = new Artist(); artist.setId(artistFile.getPath()); artist.setIndex(artistFile.getName().substring(0, 1)); @@ -296,11 +322,11 @@ public class OfflineMusicService extends RESTMusicService { artist.setCloseness(closeness); artists.add(artist); } - + recursiveAlbumSearch(artistName, artistFile, criteria, context, albums, songs); - } - } - + } + } + Collections.sort(artists, new Comparator() { public int compare(Artist lhs, Artist rhs) { if(lhs.getCloseness() == rhs.getCloseness()) { @@ -340,10 +366,10 @@ public class OfflineMusicService extends RESTMusicService { } } }); - + return new SearchResult(artists, albums, songs); - } - + } + private void recursiveAlbumSearch(String artistName, File file, SearchCriteria criteria, Context context, List albums, List songs) { int closeness; for(File albumFile : FileUtil.listMediaFiles(file)) { @@ -382,11 +408,12 @@ public class OfflineMusicService extends RESTMusicService { } } } + private int matchCriteria(SearchCriteria criteria, String name) { String query = criteria.getQuery().toLowerCase(); String[] queryParts = query.split(" "); String[] nameParts = name.toLowerCase().split(" "); - + int closeness = 0; for(String queryPart : queryParts) { for(String namePart : nameParts) { @@ -395,50 +422,76 @@ public class OfflineMusicService extends RESTMusicService { } } } - + return closeness; } - @Override - public List getPlaylists(boolean refresh, Context context, ProgressListener progressListener) throws Exception { - List playlists = new ArrayList(); - File root = FileUtil.getPlaylistDirectory(); - for (File file : FileUtil.listFiles(root)) { - if(FileUtil.isPlaylistFile(file)) { - String id = file.getName(); - String filename = FileUtil.getBaseName(id); - Playlist playlist = new Playlist(id, filename); - playlists.add(playlist); + @Override + public List getPlaylists(boolean refresh, Context context, ProgressListener progressListener) throws Exception { + List playlists = new ArrayList(); + File root = FileUtil.getPlaylistDirectory(); + String lastServer = null; + boolean removeServer = true; + for (File folder : FileUtil.listFiles(root)) { + if(folder.isDirectory()) { + String server = folder.getName(); + SortedSet fileList = FileUtil.listFiles(folder); + for(File file: fileList) { + if(FileUtil.isPlaylistFile(file)) { + String id = file.getName(); + String filename = server + ": " + FileUtil.getBaseName(id); + Playlist playlist = new Playlist(server, filename); + playlists.add(playlist); + } + } + + if(!server.equals(lastServer) && fileList.size() > 0) { + if(lastServer != null) { + removeServer = false; + } + lastServer = server; + } } else { // Delete legacy playlist files try { - file.delete(); + folder.delete(); } catch(Exception e) { - Log.w(TAG, "Failed to delete old playlist file: " + file.getName()); + Log.w(TAG, "Failed to delete old playlist file: " + folder.getName()); } } - } - return playlists; - } + } - @Override - public MusicDirectory getPlaylist(String id, String name, Context context, ProgressListener progressListener) throws Exception { + if(removeServer) { + for(Playlist playlist: playlists) { + playlist.setName(playlist.getName().substring(playlist.getId().length() + 2)); + } + } + return playlists; + } + + @Override + public MusicDirectory getPlaylist(String id, String name, Context context, ProgressListener progressListener) throws Exception { DownloadService downloadService = DownloadServiceImpl.getInstance(); - if (downloadService == null) { - return new MusicDirectory(); - } - - Reader reader = null; + if (downloadService == null) { + return new MusicDirectory(); + } + + Reader reader = null; BufferedReader buffer = null; try { - File playlistFile = FileUtil.getPlaylistFile(name); + int firstIndex = name.indexOf(id); + if(firstIndex != -1) { + name = name.substring(id.length() + 2); + } + + File playlistFile = FileUtil.getPlaylistFile(id, name); reader = new FileReader(playlistFile); buffer = new BufferedReader(reader); - + MusicDirectory playlist = new MusicDirectory(); String line = buffer.readLine(); - if(!"#EXTM3U".equals(line)) return playlist; - + if(!"#EXTM3U".equals(line)) return playlist; + while( (line = buffer.readLine()) != null ){ File entryFile = new File(line); String entryName = getName(entryFile); @@ -446,13 +499,13 @@ public class OfflineMusicService extends RESTMusicService { playlist.addChild(createEntry(context, entryFile, entryName)); } } - + return playlist; } finally { Util.close(buffer); Util.close(reader); } - } + } @Override public void createPlaylist(String id, String name, List entries, Context context, ProgressListener progressListener) throws Exception { @@ -568,13 +621,13 @@ public class OfflineMusicService extends RESTMusicService { throw new OfflineException("Getting Genres not available in offline mode"); } - private void listFilesRecursively(File parent, List children) { - for (File file : FileUtil.listMediaFiles(parent)) { - if (file.isFile()) { - children.add(file); - } else { - listFilesRecursively(file, children); - } - } - } + private void listFilesRecursively(File parent, List children) { + for (File file : FileUtil.listMediaFiles(parent)) { + if (file.isFile()) { + children.add(file); + } else { + listFilesRecursively(file, children); + } + } + } } diff --git a/src/com/thejoshwa/ultrasonic/androidapp/service/RESTMusicService.java b/src/com/thejoshwa/ultrasonic/androidapp/service/RESTMusicService.java index 0e3f4a22..18b2a017 100644 --- a/src/com/thejoshwa/ultrasonic/androidapp/service/RESTMusicService.java +++ b/src/com/thejoshwa/ultrasonic/androidapp/service/RESTMusicService.java @@ -469,16 +469,16 @@ public class RESTMusicService implements MusicService { } } - @Override - public MusicDirectory getPlaylist(String id, String name, Context context, ProgressListener progressListener) throws Exception { - HttpParams params = new BasicHttpParams(); - HttpConnectionParams.setSoTimeout(params, SOCKET_READ_TIMEOUT_GET_PLAYLIST); + @Override + public MusicDirectory getPlaylist(String id, String name, Context context, ProgressListener progressListener) throws Exception { + HttpParams params = new BasicHttpParams(); + HttpConnectionParams.setSoTimeout(params, SOCKET_READ_TIMEOUT_GET_PLAYLIST); - Reader reader = getReader(context, progressListener, "getPlaylist", params, "id", id); - try { + Reader reader = getReader(context, progressListener, "getPlaylist", params, "id", id); + try { MusicDirectory playlist = new PlaylistParser(context).parse(reader, progressListener); - - File playlistFile = FileUtil.getPlaylistFile(name); + + File playlistFile = FileUtil.getPlaylistFile(Util.getServerName(context), name); FileWriter fw = new FileWriter(playlistFile); BufferedWriter bw = new BufferedWriter(fw); try { @@ -488,7 +488,7 @@ public class RESTMusicService implements MusicService { if(! new File(filePath).exists()){ String ext = FileUtil.getExtension(filePath); String base = FileUtil.getBaseName(filePath); - filePath = base + ".complete." + ext; + filePath = base + ".complete." + ext; } fw.write(filePath + "\n"); } @@ -498,67 +498,63 @@ public class RESTMusicService implements MusicService { bw.close(); fw.close(); } - + return playlist; - } finally { - Util.close(reader); - } - } - - @Override - public List getPlaylists(boolean refresh, Context context, ProgressListener progressListener) throws Exception { - Reader reader = getReader(context, progressListener, "getPlaylists", null); - try { - return new PlaylistsParser(context).parse(reader, progressListener); - } finally { - Util.close(reader); - } - } + } finally { + Util.close(reader); + } + } - @Override - public void createPlaylist(String id, String name, List entries, Context context, ProgressListener progressListener) throws Exception { - checkServerVersion(context, "1.2", "Creating playlist not supported."); - - List parameterNames = new LinkedList(); - List parameterValues = new LinkedList(); + @Override + public List getPlaylists(boolean refresh, Context context, ProgressListener progressListener) throws Exception { + Reader reader = getReader(context, progressListener, "getPlaylists", null); + try { + return new PlaylistsParser(context).parse(reader, progressListener); + } finally { + Util.close(reader); + } + } - if (id != null) { - parameterNames.add("playlistId"); - parameterValues.add(id); - } - if (name != null) { - parameterNames.add("name"); - parameterValues.add(name); - } - for (MusicDirectory.Entry entry : entries) { - parameterNames.add("songId"); - parameterValues.add(entry.getId()); - } + @Override + public void createPlaylist(String id, String name, List entries, Context context, ProgressListener progressListener) throws Exception { + List parameterNames = new LinkedList(); + List parameterValues = new LinkedList(); + + if (id != null) { + parameterNames.add("playlistId"); + parameterValues.add(id); + } + if (name != null) { + parameterNames.add("name"); + parameterValues.add(name); + } + for (MusicDirectory.Entry entry : entries) { + parameterNames.add("songId"); + parameterValues.add(entry.getId()); + } + + Reader reader = getReader(context, progressListener, "createPlaylist", null, parameterNames, parameterValues); + try { + new ErrorParser(context).parse(reader); + } finally { + Util.close(reader); + } + } - Reader reader = getReader(context, progressListener, "createPlaylist", null, parameterNames, parameterValues); - try { - new ErrorParser(context).parse(reader); - } finally { - Util.close(reader); - } - } - @Override public void deletePlaylist(String id, Context context, ProgressListener progressListener) throws Exception { - checkServerVersion(context, "1.2", "Deleting playlist not supported."); - Reader reader = getReader(context, progressListener, "deletePlaylist", null, "id", id); try { - new ErrorParser(context).parse(reader); - } finally { - Util.close(reader); - } + new ErrorParser(context).parse(reader); + } finally { + Util.close(reader); + } } - + @Override public void updatePlaylist(String id, List toAdd, Context context, ProgressListener progressListener) throws Exception { checkServerVersion(context, "1.8", "Updating playlist not supported."); - + List names = new ArrayList(); List values = new ArrayList(); names.add("playlistId"); @@ -568,17 +564,16 @@ public class RESTMusicService implements MusicService { values.add(song.getId()); } Reader reader = getReader(context, progressListener, "updatePlaylist", null, names, values); - try { - new ErrorParser(context).parse(reader); - } finally { - Util.close(reader); - } + try { + new ErrorParser(context).parse(reader); + } finally { + Util.close(reader); + } } - + @Override public void removeFromPlaylist(String id, List toRemove, Context context, ProgressListener progressListener) throws Exception { - checkServerVersion(context, "1.8", "Removing from playlist not supported."); - + checkServerVersion(context, "1.8", "Updating playlists is not supported."); List names = new ArrayList(); List values = new ArrayList(); names.add("playlistId"); @@ -588,16 +583,16 @@ public class RESTMusicService implements MusicService { values.add(song); } Reader reader = getReader(context, progressListener, "updatePlaylist", null, names, values); - try { - new ErrorParser(context).parse(reader); - } finally { - Util.close(reader); - } + try { + new ErrorParser(context).parse(reader); + } finally { + Util.close(reader); + } } - + @Override public void updatePlaylist(String id, String name, String comment, boolean pub, Context context, ProgressListener progressListener) throws Exception { - checkServerVersion(context, "1.8", "Updating playlist not supported."); + checkServerVersion(context, "1.8", "Updating playlists is not supported."); Reader reader = getReader(context, progressListener, "updatePlaylist", null, Arrays.asList("playlistId", "name", "comment", "public"), Arrays.asList(id, name, comment, pub)); try { new ErrorParser(context).parse(reader); @@ -606,7 +601,7 @@ public class RESTMusicService implements MusicService { } } - @Override + @Override public Lyrics getLyrics(String artist, String title, Context context, ProgressListener progressListener) throws Exception { checkServerVersion(context, "1.2", "Lyrics not supported."); diff --git a/src/com/thejoshwa/ultrasonic/androidapp/util/CacheCleaner.java b/src/com/thejoshwa/ultrasonic/androidapp/util/CacheCleaner.java index 9d8aff91..d79720c5 100644 --- a/src/com/thejoshwa/ultrasonic/androidapp/util/CacheCleaner.java +++ b/src/com/thejoshwa/ultrasonic/androidapp/util/CacheCleaner.java @@ -165,7 +165,7 @@ public class CacheCleaner { undeletable.add(FileUtil.getMusicDirectory(context)); return undeletable; } - + private class BackgroundCleanup extends AsyncTask { @Override protected Void doInBackground(Void... params) { @@ -188,11 +188,11 @@ public class CacheCleaner { } catch (RuntimeException x) { Log.e(TAG, "Error in cache cleaning.", x); } - + return null; } } - + private class BackgroundSpaceCleanup extends AsyncTask { @Override protected Void doInBackground(Void... params) { @@ -205,7 +205,7 @@ public class CacheCleaner { List files = new ArrayList(); List dirs = new ArrayList(); findCandidatesForDeletion(FileUtil.getMusicDirectory(context), files, dirs); - + long bytesToDelete = getMinimumDelete(files); if(bytesToDelete > 0L) { sortByAscendingModificationTime(files); @@ -215,28 +215,29 @@ public class CacheCleaner { } catch (RuntimeException x) { Log.e(TAG, "Error in cache cleaning.", x); } - + return null; } } - + private class BackgroundPlaylistsCleanup extends AsyncTask, Void, Void> { @Override protected Void doInBackground(List... params) { try { - SortedSet playlistFiles = FileUtil.listFiles(FileUtil.getPlaylistDirectory()); + String server = Util.getServerName(context); + SortedSet playlistFiles = FileUtil.listFiles(FileUtil.getPlaylistDirectory(server)); List playlists = params[0]; for (Playlist playlist : playlists) { - playlistFiles.remove(FileUtil.getPlaylistFile(playlist.getName())); + playlistFiles.remove(FileUtil.getPlaylistFile(server, playlist.getName())); + } + + for(File playlist : playlistFiles) { + playlist.delete(); } - - for (File playlist : playlistFiles) { - playlist.delete(); - } } catch (RuntimeException x) { Log.e(TAG, "Error in playlist cache cleaning.", x); } - + return null; } } diff --git a/src/com/thejoshwa/ultrasonic/androidapp/util/FileUtil.java b/src/com/thejoshwa/ultrasonic/androidapp/util/FileUtil.java index 1db6009f..014e7b73 100644 --- a/src/com/thejoshwa/ultrasonic/androidapp/util/FileUtil.java +++ b/src/com/thejoshwa/ultrasonic/androidapp/util/FileUtil.java @@ -52,40 +52,46 @@ public class FileUtil { private static final List PLAYLIST_FILE_EXTENSIONS = Arrays.asList("m3u"); private static final File DEFAULT_MUSIC_DIR = createDirectory("music"); - public static File getSongFile(Context context, MusicDirectory.Entry song) { - File dir = getAlbumDirectory(context, song); + public static File getSongFile(Context context, MusicDirectory.Entry song) { + File dir = getAlbumDirectory(context, song); - StringBuilder fileName = new StringBuilder(); - Integer track = song.getTrack(); - if (track != null) { - if (track < 10) { - fileName.append("0"); - } - fileName.append(track).append("-"); - } + StringBuilder fileName = new StringBuilder(); + Integer track = song.getTrack(); + if (track != null) { + if (track < 10) { + fileName.append("0"); + } + fileName.append(track).append("-"); + } - fileName.append(fileSystemSafe(song.getTitle())).append("."); + fileName.append(fileSystemSafe(song.getTitle())).append("."); - if (song.getTranscodedSuffix() != null) { - fileName.append(song.getTranscodedSuffix()); - } else { - fileName.append(song.getSuffix()); - } + if (song.getTranscodedSuffix() != null) { + fileName.append(song.getTranscodedSuffix()); + } else { + fileName.append(song.getSuffix()); + } - return new File(dir, fileName.toString()); - } + return new File(dir, fileName.toString()); + } - public static File getPlaylistFile(String name) { - File playlistDir = getPlaylistDirectory(); + public static File getPlaylistFile(String server, String name) { + File playlistDir = getPlaylistDirectory(server); return new File(playlistDir, fileSystemSafe(name) + ".m3u"); } - public static File getPlaylistDirectory() { + public static File getPlaylistDirectory() { File playlistDir = new File(getUltraSonicDirectory(), "playlists"); ensureDirectoryExistsAndIsReadWritable(playlistDir); return playlistDir; } - + + public static File getPlaylistDirectory(String server) { + File playlistDir = new File(getPlaylistDirectory(), server); + ensureDirectoryExistsAndIsReadWritable(playlistDir); + return playlistDir; + } + public static File getAlbumArtFile(Context context, MusicDirectory.Entry entry) { File albumDir = getAlbumDirectory(context, entry); return getAlbumArtFile(albumDir); diff --git a/src/com/thejoshwa/ultrasonic/androidapp/util/StreamProxy.java b/src/com/thejoshwa/ultrasonic/androidapp/util/StreamProxy.java index 277c54f4..a710f945 100644 --- a/src/com/thejoshwa/ultrasonic/androidapp/util/StreamProxy.java +++ b/src/com/thejoshwa/ultrasonic/androidapp/util/StreamProxy.java @@ -157,12 +157,22 @@ 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/src/com/thejoshwa/ultrasonic/androidapp/util/Util.java b/src/com/thejoshwa/ultrasonic/androidapp/util/Util.java index 45c7d7d8..d59ad79a 100644 --- a/src/com/thejoshwa/ultrasonic/androidapp/util/Util.java +++ b/src/com/thejoshwa/ultrasonic/androidapp/util/Util.java @@ -189,6 +189,17 @@ public class Util extends DownloadActivity { return settings.getInt(Constants.PREFERENCES_KEY_ACTIVE_SERVERS, 3); } + public static String getServerName(Context context) { + int instance = getActiveServer(context); + + if (instance == 0) { + return context.getResources().getString(R.string.main_offline); + } + + SharedPreferences preferences = getPreferences(context); + return preferences.getString(Constants.PREFERENCES_KEY_SERVER_NAME + instance, null); + } + public static String getServerName(Context context, int instance) { if (instance == 0) { return context.getResources().getString(R.string.main_offline);