From 8dd5b6136e8ae5dd41a9004617238f87a8d27281 Mon Sep 17 00:00:00 2001 From: Scott Jackson Date: Fri, 14 Jun 2013 20:33:58 -0700 Subject: Convert offline scrobbling to SharedPreference, add support for offline mode with online added songs --- subsonic-android/res/values/strings.xml | 3 +- .../daneren2005/dsub/fragments/MainFragment.java | 28 ++++++---- .../dsub/service/CachedMusicService.java | 11 ++-- .../daneren2005/dsub/service/MusicService.java | 4 +- .../dsub/service/OfflineMusicService.java | 59 +++++++++++----------- .../daneren2005/dsub/service/RESTMusicService.java | 59 ++++++++-------------- .../github/daneren2005/dsub/util/Constants.java | 8 ++- .../src/github/daneren2005/dsub/util/FileUtil.java | 5 -- .../src/github/daneren2005/dsub/util/Util.java | 8 +++ 9 files changed, 89 insertions(+), 96 deletions(-) diff --git a/subsonic-android/res/values/strings.xml b/subsonic-android/res/values/strings.xml index f3126ae0..224247fb 100644 --- a/subsonic-android/res/values/strings.xml +++ b/subsonic-android/res/values/strings.xml @@ -117,7 +117,8 @@ Offline scrobbles file found. Process offline scrobbles file? - Successfully scrobbled songs + Successfully scrobbled %1$d songs + Successfully scrobbled %1$d of %2$d songs. Try the rest on a different server. Failed to scrobble songs No genres found diff --git a/subsonic-android/src/github/daneren2005/dsub/fragments/MainFragment.java b/subsonic-android/src/github/daneren2005/dsub/fragments/MainFragment.java index 645f2ae2..45d6eb49 100644 --- a/subsonic-android/src/github/daneren2005/dsub/fragments/MainFragment.java +++ b/subsonic-android/src/github/daneren2005/dsub/fragments/MainFragment.java @@ -4,6 +4,7 @@ import android.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; +import android.content.SharedPreferences; import android.net.Uri; import android.os.Bundle; import android.os.StatFs; @@ -204,9 +205,9 @@ public class MainFragment extends SubsonicFragment { context.getPagerAdapter().invalidate(); if(isOffline) { - MusicService musicService = MusicServiceFactory.getMusicService(context); - if(musicService.hasOfflineScrobbles()){ - showOfflineScrobblesDialog(); + int count = Util.offlineScrobblesCount(context); + if(count > 0){ + showOfflineScrobblesDialog(count); } } } @@ -227,7 +228,7 @@ public class MainFragment extends SubsonicFragment { } } - private void showOfflineScrobblesDialog() { + private void showOfflineScrobblesDialog(final int count) { AlertDialog.Builder builder = new AlertDialog.Builder(context); builder.setIcon(android.R.drawable.ic_dialog_info) .setTitle(R.string.offline_scrobbles_dialog_title) @@ -235,17 +236,20 @@ public class MainFragment extends SubsonicFragment { .setPositiveButton(R.string.common_ok, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int i) { - new SilentBackgroundTask(context) { + new SilentBackgroundTask(context) { @Override - protected Void doInBackground() throws Throwable { + protected Integer doInBackground() throws Throwable { MusicService musicService = MusicServiceFactory.getMusicService(context); - musicService.processOfflineScrobbles(context, null); - return null; + return musicService.processOfflineScrobbles(context, null); } @Override - protected void done(Void result) { - Util.toast(context, R.string.offline_scrobbles_success); + protected void done(Integer result) { + if(result == count) { + Util.toast(context, context.getResources().getString(R.string.offline_scrobbles_success, result)); + } else { + Util.toast(context, context.getResources().getString(R.string.offline_scrobbles_partial, result, count)); + } } @Override @@ -264,7 +268,9 @@ public class MainFragment extends SubsonicFragment { @Override public void onClick(DialogInterface dialogInterface, int i) { dialogInterface.dismiss(); - FileUtil.getOfflineScrobblesFile().delete(); + SharedPreferences.Editor offline = Util.getOfflineSync(context).edit(); + offline.putInt(Constants.OFFLINE_SCROBBLE_COUNT, 0); + offline.commit(); } }); diff --git a/subsonic-android/src/github/daneren2005/dsub/service/CachedMusicService.java b/subsonic-android/src/github/daneren2005/dsub/service/CachedMusicService.java index 218949c4..59e81c3b 100644 --- a/subsonic-android/src/github/daneren2005/dsub/service/CachedMusicService.java +++ b/subsonic-android/src/github/daneren2005/dsub/service/CachedMusicService.java @@ -303,14 +303,9 @@ public class CachedMusicService implements MusicService { } @Override - public boolean hasOfflineScrobbles(){ - return musicService.hasOfflineScrobbles(); - } - - @Override - public void processOfflineScrobbles(final Context context, final ProgressListener progressListener) throws Exception{ - musicService.processOfflineScrobbles(context, progressListener); - } + public int processOfflineScrobbles(final Context context, final ProgressListener progressListener) throws Exception{ + return musicService.processOfflineScrobbles(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 2787b75b..1689835f 100644 --- a/subsonic-android/src/github/daneren2005/dsub/service/MusicService.java +++ b/subsonic-android/src/github/daneren2005/dsub/service/MusicService.java @@ -118,7 +118,5 @@ public interface MusicService { public MusicDirectory getSongsByGenre(String genre, int count, int offset, Context context, ProgressListener progressListener) throws Exception; - boolean hasOfflineScrobbles(); - - void processOfflineScrobbles(final Context context, final ProgressListener progressListener) throws Exception; + int processOfflineScrobbles(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 a9d18c5c..bda112ff 100644 --- a/subsonic-android/src/github/daneren2005/dsub/service/OfflineMusicService.java +++ b/subsonic-android/src/github/daneren2005/dsub/service/OfflineMusicService.java @@ -431,36 +431,42 @@ public class OfflineMusicService extends RESTMusicService { @Override public void scrobble(String id, boolean submission, Context context, ProgressListener progressListener) throws Exception { if(!submission) { - return; + return; } SharedPreferences prefs = Util.getPreferences(context); String cacheLocn = prefs.getString(Constants.PREFERENCES_KEY_CACHE_LOCATION, null); - File offlineScrobblesFile = FileUtil.getOfflineScrobblesFile(); - - String scrobbleSearchCriteria = id.replace(cacheLocn, ""); - if(scrobbleSearchCriteria.startsWith("/")) { - scrobbleSearchCriteria = scrobbleSearchCriteria.substring(1); - } - - scrobbleSearchCriteria = scrobbleSearchCriteria.replace(".complete", "").replace(".partial", ""); - int index = scrobbleSearchCriteria.lastIndexOf("."); - scrobbleSearchCriteria = index == -1 ? scrobbleSearchCriteria : scrobbleSearchCriteria.substring(0, index); - String[] details = scrobbleSearchCriteria.split("/"); + 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) { + String scrobbleSearchCriteria = id.replace(cacheLocn, ""); + if(scrobbleSearchCriteria.startsWith("/")) { + scrobbleSearchCriteria = scrobbleSearchCriteria.substring(1); + } - //last.fm only uses artist and track title so broaden the search by just using those. doesn't matter if it find the track on a different album - String artist = "artist:\"" + details[0] + "\""; - String title = details[details.length - 1]; - title = "title:\"" + title.substring(title.indexOf('-') + 1) + "\""; + scrobbleSearchCriteria = scrobbleSearchCriteria.replace(".complete", "").replace(".partial", ""); + int index = scrobbleSearchCriteria.lastIndexOf("."); + scrobbleSearchCriteria = index == -1 ? scrobbleSearchCriteria : scrobbleSearchCriteria.substring(0, index); + String[] details = scrobbleSearchCriteria.split("/"); - scrobbleSearchCriteria = artist + " AND " + title; + //last.fm only uses artist and track title so broaden the search by just using those. doesn't matter if it find the track on a different album + String artist = "artist:\"" + details[0] + "\""; + String title = details[details.length - 1]; + title = "title:\"" + title.substring(title.indexOf('-') + 1) + "\""; - BufferedWriter bw = new BufferedWriter(new FileWriter(offlineScrobblesFile, true)); - bw.write(scrobbleSearchCriteria + "," + System.currentTimeMillis()); - bw.newLine(); - bw.flush(); - bw.close(); + scrobbleSearchCriteria = artist + " AND " + title; + offlineEditor.putString(Constants.OFFLINE_SCROBBLE_SEARCH + scrobbles, scrobbleSearchCriteria); + } else { + offlineEditor.putString(Constants.OFFLINE_SCROBBLE_ID + scrobbles, id); + } + + offlineEditor.putLong(Constants.OFFLINE_SCROBBLE_TIME + scrobbles, System.currentTimeMillis()); + offlineEditor.putInt(Constants.OFFLINE_SCROBBLE_COUNT, scrobbles); + offlineEditor.commit(); } @Override @@ -543,13 +549,8 @@ public class OfflineMusicService extends RESTMusicService { } @Override - public boolean hasOfflineScrobbles(){ - return false; - } - - @Override - public void processOfflineScrobbles(final Context context, final ProgressListener progressListener) throws Exception{ - throw new OfflineException("Offline scrobble cached can not be processes while in offline mode"); + public int processOfflineScrobbles(final Context context, final ProgressListener progressListener) throws Exception{ + throw new OfflineException("Offline scrobble cached can not be processes while in offline mode"); } private void listFilesRecursively(File parent, List children) { diff --git a/subsonic-android/src/github/daneren2005/dsub/service/RESTMusicService.java b/subsonic-android/src/github/daneren2005/dsub/service/RESTMusicService.java index 8a84cd21..53eccf71 100644 --- a/subsonic-android/src/github/daneren2005/dsub/service/RESTMusicService.java +++ b/subsonic-android/src/github/daneren2005/dsub/service/RESTMusicService.java @@ -869,35 +869,23 @@ public class RESTMusicService implements MusicService { } @Override - public boolean hasOfflineScrobbles(){ - return FileUtil.getOfflineScrobblesFile().exists(); - } - - @Override - public void processOfflineScrobbles(final Context context, final ProgressListener progressListener) throws Exception{ - File offlineScrobblesFile = FileUtil.getOfflineScrobblesFile(); - try{ - - BufferedReader br = new BufferedReader(new FileReader(offlineScrobblesFile)); - String line; - - ArrayList lines = new ArrayList(); - while ((line = br.readLine()) != null) { - lines.add(line); - } - br.close(); - offlineScrobblesFile.delete(); - - for(int i = 0; i < lines.size(); i++){ - line = lines.get(i); - String filename = line.substring(0, line.lastIndexOf(',')); - + public int processOfflineScrobbles(final Context context, final ProgressListener progressListener) throws Exception{ + SharedPreferences offline = Util.getOfflineSync(context); + SharedPreferences.Editor offlineEditor = offline.edit(); + int count = offline.getInt(Constants.OFFLINE_SCROBBLE_COUNT, 0); + int retry = 0; + for(int i = 1; i <= count; i++) { + String id = offline.getString(Constants.OFFLINE_SCROBBLE_ID + i, null); + long time = offline.getLong(Constants.OFFLINE_SCROBBLE_TIME + i, 0); + if(id != null) { + scrobble(id, true, time, context, progressListener); + } else { + String search = offline.getString(Constants.OFFLINE_SCROBBLE_SEARCH + i, ""); try{ - long time = Long.parseLong(line.substring(line.lastIndexOf(',')+1)); - SearchCritera critera = new SearchCritera(filename, 0, 0, 1); + SearchCritera critera = new SearchCritera(search, 0, 0, 1); SearchResult result = searchNew(critera, context, progressListener); if(result.getSongs().size() == 1){ - Log.i(TAG, "Query '" + filename + "' returned song " + result.getSongs().get(0).getTitle() + " by " + result.getSongs().get(0).getArtist() + " with id " + result.getSongs().get(0).getId()); + Log.i(TAG, "Query '" + search + "' returned song " + result.getSongs().get(0).getTitle() + " by " + result.getSongs().get(0).getArtist() + " with id " + result.getSongs().get(0).getId()); Log.i(TAG, "Scrobbling " + result.getSongs().get(0).getId() + " with time " + time); scrobble(result.getSongs().get(0).getId(), true, time, context, progressListener); } @@ -907,20 +895,17 @@ public class RESTMusicService implements MusicService { } catch(Exception e){ Log.e(TAG, e.toString()); - BufferedWriter bw = new BufferedWriter(new FileWriter(offlineScrobblesFile, true)); - bw.write(line); - bw.newLine(); - bw.flush(); - bw.close(); + retry++; + offlineEditor.putString(Constants.OFFLINE_SCROBBLE_SEARCH + retry, search); + offlineEditor.putLong(Constants.OFFLINE_SCROBBLE_TIME + retry, time); } } } - catch(FileNotFoundException fnfe){ - //ignore, we dont care - } - catch(Exception e){ - Log.e(TAG, e.toString()); - } + + offlineEditor.putInt(Constants.OFFLINE_SCROBBLE_COUNT, retry); + offlineEditor.commit(); + + return count - retry; } private Reader getReader(Context context, ProgressListener progressListener, String method, HttpParams requestParams) throws Exception { diff --git a/subsonic-android/src/github/daneren2005/dsub/util/Constants.java b/subsonic-android/src/github/daneren2005/dsub/util/Constants.java index d6aa4541..5714b1f1 100644 --- a/subsonic-android/src/github/daneren2005/dsub/util/Constants.java +++ b/subsonic-android/src/github/daneren2005/dsub/util/Constants.java @@ -109,6 +109,11 @@ public final class Constants { public static final String PREFERENCES_KEY_CHAT_ENABLED = "chatEnabled"; public static final String PREFERENCES_KEY_VIDEO_PLAYER = "videoPlayer"; + public static final String OFFLINE_SCROBBLE_COUNT = "scrobbleCount"; + public static final String OFFLINE_SCROBBLE_ID = "scrobbleID"; + public static final String OFFLINE_SCROBBLE_SEARCH = "scrobbleTitle"; + public static final String OFFLINE_SCROBBLE_TIME = "scrobbleTime"; + public static final String CACHE_KEY_IGNORE = "ignoreArticles"; public static final String MAIN_BACK_STACK = "backStackIds"; @@ -118,6 +123,7 @@ public final class Constants { // Name of the preferences file. public static final String PREFERENCES_FILE_NAME = "github.daneren2005.dsub_preferences"; + public static final String OFFLINE_SYNC_NAME = "github.daneren2005.dsub.offline"; // Number of free trial days for non-licensed servers. public static final int FREE_TRIAL_DAYS = 30; @@ -126,8 +132,6 @@ public final class Constants { public static final String DONATION_URL = "http://subsonic.org/pages/android-donation.jsp"; public static final String ALBUM_ART_FILE = "albumart.jpg"; - - public static final String OFFLINE_SCROBBLES_FILE = "offline_scrobbles.log"; private Constants() { } diff --git a/subsonic-android/src/github/daneren2005/dsub/util/FileUtil.java b/subsonic-android/src/github/daneren2005/dsub/util/FileUtil.java index ca06b55f..7ead874c 100644 --- a/subsonic-android/src/github/daneren2005/dsub/util/FileUtil.java +++ b/subsonic-android/src/github/daneren2005/dsub/util/FileUtil.java @@ -149,11 +149,6 @@ public class FileUtil { } return dir; } - - public static File getOfflineScrobblesFile(){ - File offlineScrobblesFile = new File(getSubsonicDirectory(), fileSystemSafe(Constants.OFFLINE_SCROBBLES_FILE)); - return offlineScrobblesFile; - } public static void createDirectoryForParent(File file) { File dir = file.getParentFile(); diff --git a/subsonic-android/src/github/daneren2005/dsub/util/Util.java b/subsonic-android/src/github/daneren2005/dsub/util/Util.java index 269b05d3..76bf6a04 100644 --- a/subsonic-android/src/github/daneren2005/dsub/util/Util.java +++ b/subsonic-android/src/github/daneren2005/dsub/util/Util.java @@ -332,6 +332,14 @@ public final class Util { public static SharedPreferences getPreferences(Context context) { return context.getSharedPreferences(Constants.PREFERENCES_FILE_NAME, 0); } + public static SharedPreferences getOfflineSync(Context context) { + return context.getSharedPreferences(Constants.OFFLINE_SYNC_NAME, 0); + } + + public static int offlineScrobblesCount(Context context) { + SharedPreferences offline = getOfflineSync(context); + return offline.getInt(Constants.OFFLINE_SCROBBLE_COUNT, 0); + } public static String getContentType(HttpEntity entity) { if (entity == null || entity.getContentType() == null) { -- cgit v1.2.3