From 96d6c306e75533423137a31b3cff378f7f916d8d Mon Sep 17 00:00:00 2001 From: Tom Date: Tue, 4 Jun 2013 20:02:56 +0100 Subject: Added Offline Scrobbling functionality: FileUtil: new function to return name of offline scrobbles file CachedMusicService: added code to scrobble() that appends to offline scrobbles file a search query made from song path and the millis time of that song play RESTMusicService: override scrobble function that also takes time in millis of scrobble RESTMusicService: new function to look for offline scrobbleis file and process it by using searchNew to get the song id using the cached query (needs putting on a thread) RESTMusicServer: Added call to processOfflineScrobbles in checkLicence --- .../dsub/service/OfflineMusicService.java | 23 +++++++- .../daneren2005/dsub/service/RESTMusicService.java | 67 +++++++++++++++++++++- .../github/daneren2005/dsub/util/Constants.java | 2 + .../src/github/daneren2005/dsub/util/FileUtil.java | 5 ++ .../src/github/daneren2005/dsub/util/Util.java | 4 +- 5 files changed, 96 insertions(+), 5 deletions(-) diff --git a/subsonic-android/src/github/daneren2005/dsub/service/OfflineMusicService.java b/subsonic-android/src/github/daneren2005/dsub/service/OfflineMusicService.java index 9af58b16..83c7f960 100644 --- a/subsonic-android/src/github/daneren2005/dsub/service/OfflineMusicService.java +++ b/subsonic-android/src/github/daneren2005/dsub/service/OfflineMusicService.java @@ -36,6 +36,7 @@ import android.content.SharedPreferences; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.media.MediaMetadataRetriever; +import android.os.Environment; import android.util.Log; import github.daneren2005.dsub.domain.Artist; import github.daneren2005.dsub.domain.Genre; @@ -429,7 +430,27 @@ public class OfflineMusicService extends RESTMusicService { @Override public void scrobble(String id, boolean submission, Context context, ProgressListener progressListener) throws Exception { - throw new OfflineException("Scrobbling not available in offline mode"); + + if(!submission) + 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", ""); + scrobbleSearchCriteria = scrobbleSearchCriteria.replace("/", " ").replace("-", "\\-").replace(".", "\\."); + + BufferedWriter bw = new BufferedWriter(new FileWriter(offlineScrobblesFile)); + bw.write(scrobbleSearchCriteria + "," + System.currentTimeMillis()); + bw.newLine(); + bw.flush(); + bw.close(); } @Override diff --git a/subsonic-android/src/github/daneren2005/dsub/service/RESTMusicService.java b/subsonic-android/src/github/daneren2005/dsub/service/RESTMusicService.java index f4f64046..be0763e7 100644 --- a/subsonic-android/src/github/daneren2005/dsub/service/RESTMusicService.java +++ b/subsonic-android/src/github/daneren2005/dsub/service/RESTMusicService.java @@ -163,6 +163,54 @@ public class RESTMusicService implements MusicService { return org.apache.http.conn.ssl.SSLSocketFactory.getSocketFactory(); } } + + public void processOfflineScrobbles(final Context context, final ProgressListener progressListener){ + 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(); + + //TODO make a prompt: "Found " + lines.size() + " offline scrobbles. Scrobble? Ignore? Clear File?" + for(int i = 0; i < lines.size(); i++){ + line = lines.get(i); + String filename = line.substring(0, line.lastIndexOf(',')); + + Log.i(TAG, "Searching for id of file" + filename); + try{ + long time = Long.parseLong(line.substring(line.lastIndexOf(',')+1)); + SearchCritera critera = new SearchCritera(filename, 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, "Scrobbling " + result.getSongs().get(0).getId() + " with time " + time); + scrobble(result.getSongs().get(0).getId(), true, time, context, progressListener); + } + } + catch(Exception e){ + Log.e(TAG, e.toString()); + BufferedWriter bw = new BufferedWriter(new FileWriter(offlineScrobblesFile)); + bw.write(line); + bw.newLine(); + bw.flush(); + bw.close(); + } + } + } + catch(FileNotFoundException fnfe){ + //ignore, we dont care + } + catch(Exception e){ + Log.e(TAG, e.toString()); + } + } @Override public void ping(Context context, ProgressListener progressListener) throws Exception { @@ -176,7 +224,11 @@ public class RESTMusicService implements MusicService { @Override public boolean isLicenseValid(Context context, ProgressListener progressListener) throws Exception { - Reader reader = getReader(context, progressListener, "getLicense", null); + + //TODO run on a thread + processOfflineScrobbles(context, progressListener); + + Reader reader = getReader(context, progressListener, "getLicense", null); try { ServerInfo serverInfo = new LicenseParser(context).parse(reader); return serverInfo.isLicenseValid(); @@ -186,6 +238,7 @@ public class RESTMusicService implements MusicService { } public List getMusicFolders(boolean refresh, Context context, ProgressListener progressListener) throws Exception { + List cachedMusicFolders = readCachedMusicFolders(context); if (cachedMusicFolders != null && !refresh) { return cachedMusicFolders; @@ -464,8 +517,18 @@ public class RESTMusicService implements MusicService { @Override public void scrobble(String id, boolean submission, Context context, ProgressListener progressListener) throws Exception { + scrobble(id, submission, 0, context, progressListener); + } + + public void scrobble(String id, boolean submission, long time, Context context, ProgressListener progressListener) throws Exception { checkServerVersion(context, "1.5", "Scrobbling not supported."); - Reader reader = getReader(context, progressListener, "scrobble", null, Arrays.asList("id", "submission"), Arrays.asList(id, submission)); + Reader reader; + if(time > 0){ + checkServerVersion(context, "1.8", "Scrobbling with a time not supported."); + reader = getReader(context, progressListener, "scrobble", null, Arrays.asList("id", "submission", "time"), Arrays.asList(id, submission, time)); + } + else + reader = getReader(context, progressListener, "scrobble", null, Arrays.asList("id", "submission"), Arrays.asList(id, submission)); try { new ErrorParser(context).parse(reader); } finally { diff --git a/subsonic-android/src/github/daneren2005/dsub/util/Constants.java b/subsonic-android/src/github/daneren2005/dsub/util/Constants.java index 5de13e73..af5f7e08 100644 --- a/subsonic-android/src/github/daneren2005/dsub/util/Constants.java +++ b/subsonic-android/src/github/daneren2005/dsub/util/Constants.java @@ -125,6 +125,8 @@ 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 7ead874c..ca06b55f 100644 --- a/subsonic-android/src/github/daneren2005/dsub/util/FileUtil.java +++ b/subsonic-android/src/github/daneren2005/dsub/util/FileUtil.java @@ -149,6 +149,11 @@ 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 a8918923..9d785212 100644 --- a/subsonic-android/src/github/daneren2005/dsub/util/Util.java +++ b/subsonic-android/src/github/daneren2005/dsub/util/Util.java @@ -147,9 +147,9 @@ public final class Util { } public static boolean isScrobblingEnabled(Context context) { - if (isOffline(context)) { + /*if (isOffline(context)) { return false; - } + }*/ SharedPreferences prefs = getPreferences(context); return prefs.getBoolean(Constants.PREFERENCES_KEY_SCROBBLE, false); } -- cgit v1.2.3