aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorScott Jackson <daneren2005@gmail.com>2015-12-12 15:56:56 -0800
committerScott Jackson <daneren2005@gmail.com>2015-12-12 15:56:56 -0800
commit024fc7231f8fe78b9daf27b5c0e1421005355dd9 (patch)
tree556fd6d5bca70969db4a0f7693d8057162e5fdbe
parent546cd362c88850999ddb7274eb51fdd7759c5547 (diff)
parent26873c657849a1351618950a1533fd59b3422ba8 (diff)
downloaddsub-024fc7231f8fe78b9daf27b5c0e1421005355dd9.tar.gz
dsub-024fc7231f8fe78b9daf27b5c0e1421005355dd9.tar.bz2
dsub-024fc7231f8fe78b9daf27b5c0e1421005355dd9.zip
Merge branch 'played'
-rw-r--r--app/src/main/java/github/daneren2005/dsub/domain/MusicDirectory.java9
-rw-r--r--app/src/main/java/github/daneren2005/dsub/fragments/SubsonicFragment.java11
-rw-r--r--app/src/main/java/github/daneren2005/dsub/service/CachedMusicService.java12
-rw-r--r--app/src/main/java/github/daneren2005/dsub/service/DownloadFile.java7
-rw-r--r--app/src/main/java/github/daneren2005/dsub/service/OfflineMusicService.java14
-rw-r--r--app/src/main/java/github/daneren2005/dsub/service/RESTMusicService.java18
-rw-r--r--app/src/main/java/github/daneren2005/dsub/service/Scrobbler.java41
-rw-r--r--app/src/main/java/github/daneren2005/dsub/util/SongDBHandler.java238
-rw-r--r--app/src/main/java/github/daneren2005/dsub/util/Util.java19
-rw-r--r--app/src/main/res/values/strings.xml1
10 files changed, 344 insertions, 26 deletions
diff --git a/app/src/main/java/github/daneren2005/dsub/domain/MusicDirectory.java b/app/src/main/java/github/daneren2005/dsub/domain/MusicDirectory.java
index 42c97b9e..6dc56bb3 100644
--- a/app/src/main/java/github/daneren2005/dsub/domain/MusicDirectory.java
+++ b/app/src/main/java/github/daneren2005/dsub/domain/MusicDirectory.java
@@ -107,6 +107,15 @@ public class MusicDirectory implements Serializable {
}
return result;
}
+ public List<Entry> getSongs() {
+ List<Entry> result = new ArrayList<Entry>();
+ for (Entry child : children) {
+ if (child != null && !child.isDirectory() && !child.isVideo()) {
+ result.add(child);
+ }
+ }
+ return result;
+ }
public int getChildrenSize() {
return children.size();
diff --git a/app/src/main/java/github/daneren2005/dsub/fragments/SubsonicFragment.java b/app/src/main/java/github/daneren2005/dsub/fragments/SubsonicFragment.java
index 6d25bc0b..88c8363b 100644
--- a/app/src/main/java/github/daneren2005/dsub/fragments/SubsonicFragment.java
+++ b/app/src/main/java/github/daneren2005/dsub/fragments/SubsonicFragment.java
@@ -77,6 +77,7 @@ import github.daneren2005.dsub.util.MenuUtil;
import github.daneren2005.dsub.util.ProgressListener;
import github.daneren2005.dsub.util.SilentBackgroundTask;
import github.daneren2005.dsub.util.LoadingTask;
+import github.daneren2005.dsub.util.SongDBHandler;
import github.daneren2005.dsub.util.UpdateHelper;
import github.daneren2005.dsub.util.UserUtil;
import github.daneren2005.dsub.util.Util;
@@ -1293,6 +1294,16 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR
headers.add(R.string.details_starred);
details.add(Util.formatBoolean(context, song.isStarred()));
+ try {
+ Long[] dates = SongDBHandler.getHandler(context).getLastPlayed(song);
+ if(dates != null && dates[0] != null && dates[0] > 0) {
+ headers.add(R.string.details_last_played);
+ details.add(Util.formatDate(dates[0]));
+ }
+ } catch(Exception e) {
+ Log.e(TAG, "Failed to get last played", e);
+ }
+
if(song instanceof PodcastEpisode) {
headers.add(R.string.details_description);
details.add(song.getAlbum());
diff --git a/app/src/main/java/github/daneren2005/dsub/service/CachedMusicService.java b/app/src/main/java/github/daneren2005/dsub/service/CachedMusicService.java
index 68ca36a7..c0851009 100644
--- a/app/src/main/java/github/daneren2005/dsub/service/CachedMusicService.java
+++ b/app/src/main/java/github/daneren2005/dsub/service/CachedMusicService.java
@@ -53,6 +53,7 @@ import github.daneren2005.dsub.domain.Share;
import github.daneren2005.dsub.domain.User;
import github.daneren2005.dsub.util.SilentBackgroundTask;
import github.daneren2005.dsub.util.ProgressListener;
+import github.daneren2005.dsub.util.SongDBHandler;
import github.daneren2005.dsub.util.SyncUtil;
import github.daneren2005.dsub.util.TimeLimitedCache;
import github.daneren2005.dsub.util.FileUtil;
@@ -171,6 +172,7 @@ public class CachedMusicService implements MusicService {
protected Void doInBackground() throws Throwable {
Util.sleepQuietly(2000L);
MusicDirectory refreshed = musicService.getMusicDirectory(id, name, true, context, null);
+ updateAllSongs(context, refreshed);
cached.updateDifferences(context, musicService.getInstance(context), refreshed);
FileUtil.serialize(context, refreshed, getCacheName(context, "directory", id));
return null;
@@ -193,6 +195,7 @@ public class CachedMusicService implements MusicService {
if(dir == null) {
dir = musicService.getMusicDirectory(id, name, refresh, context, progressListener);
+ updateAllSongs(context, dir);
FileUtil.serialize(context, dir, getCacheName(context, "directory", id));
// If a cached copy exists to check against, look for removes
@@ -231,6 +234,7 @@ public class CachedMusicService implements MusicService {
if(dir == null) {
dir = musicService.getAlbum(id, name, refresh, context, progressListener);
+ updateAllSongs(context, dir);
FileUtil.serialize(context, dir, getCacheName(context, "album", id));
// If a cached copy exists to check against, look for removes
@@ -254,6 +258,7 @@ public class CachedMusicService implements MusicService {
}
if(dir == null) {
dir = musicService.getPlaylist(refresh, id, name, context, progressListener);
+ updateAllSongs(context, dir);
FileUtil.serialize(context, dir, getCacheName(context, "playlist", id));
File playlistFile = FileUtil.getPlaylistFile(context, Util.getServerName(context, musicService.getInstance(context)), dir.getName());
@@ -1500,6 +1505,13 @@ public class CachedMusicService implements MusicService {
}
}
+ protected void updateAllSongs(Context context, MusicDirectory dir) {
+ List<Entry> songs = dir.getSongs();
+ if(!songs.isEmpty()) {
+ SongDBHandler.getHandler(context).addSongs(musicService.getInstance(context), songs);
+ }
+ }
+
private void checkSettingsChanged(Context context) {
int instance = musicService.getInstance(context);
String newUrl = musicService.getRestUrl(context, null, false);
diff --git a/app/src/main/java/github/daneren2005/dsub/service/DownloadFile.java b/app/src/main/java/github/daneren2005/dsub/service/DownloadFile.java
index 505e4a6d..3febfaea 100644
--- a/app/src/main/java/github/daneren2005/dsub/service/DownloadFile.java
+++ b/app/src/main/java/github/daneren2005/dsub/service/DownloadFile.java
@@ -85,6 +85,10 @@ public class DownloadFile implements BufferFile {
return song;
}
+ public Context getContext() {
+ return context;
+ }
+
/**
* Returns the effective bit rate.
*/
@@ -206,6 +210,9 @@ public class DownloadFile implements BufferFile {
return saveFile;
}
+ public File getSaveFile() {
+ return saveFile;
+ }
public File getPartialFile() {
return partialFile;
diff --git a/app/src/main/java/github/daneren2005/dsub/service/OfflineMusicService.java b/app/src/main/java/github/daneren2005/dsub/service/OfflineMusicService.java
index c8253c91..11a723ce 100644
--- a/app/src/main/java/github/daneren2005/dsub/service/OfflineMusicService.java
+++ b/app/src/main/java/github/daneren2005/dsub/service/OfflineMusicService.java
@@ -56,8 +56,10 @@ 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;
@@ -556,9 +558,15 @@ public class OfflineMusicService implements MusicService {
SharedPreferences.Editor offlineEditor = offline.edit();
if(id.indexOf(cacheLocn) != -1) {
- String scrobbleSearchCriteria = Util.parseOfflineIDSearch(context, id, cacheLocn);
- offlineEditor.putString(Constants.OFFLINE_SCROBBLE_SEARCH + scrobbles, scrobbleSearchCriteria);
- offlineEditor.remove(Constants.OFFLINE_SCROBBLE_ID + scrobbles);
+ 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);
diff --git a/app/src/main/java/github/daneren2005/dsub/service/RESTMusicService.java b/app/src/main/java/github/daneren2005/dsub/service/RESTMusicService.java
index 9ec77897..9af512e3 100644
--- a/app/src/main/java/github/daneren2005/dsub/service/RESTMusicService.java
+++ b/app/src/main/java/github/daneren2005/dsub/service/RESTMusicService.java
@@ -69,6 +69,7 @@ import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Looper;
import android.util.Log;
+
import github.daneren2005.dsub.R;
import github.daneren2005.dsub.domain.*;
import github.daneren2005.dsub.service.parser.AlbumListParser;
@@ -99,10 +100,12 @@ import github.daneren2005.dsub.service.parser.VideosParser;
import github.daneren2005.dsub.service.ssl.SSLSocketFactory;
import github.daneren2005.dsub.service.ssl.TrustSelfSignedStrategy;
import github.daneren2005.dsub.util.BackgroundTask;
+import github.daneren2005.dsub.util.Pair;
import github.daneren2005.dsub.util.SilentBackgroundTask;
import github.daneren2005.dsub.util.Constants;
import github.daneren2005.dsub.util.FileUtil;
import github.daneren2005.dsub.util.ProgressListener;
+import github.daneren2005.dsub.util.SongDBHandler;
import github.daneren2005.dsub.util.Util;
import java.io.*;
import java.util.zip.GZIPInputStream;
@@ -1796,11 +1799,16 @@ public class RESTMusicService implements MusicService {
SharedPreferences prefs = Util.getPreferences(context);
String cacheLocn = prefs.getString(Constants.PREFERENCES_KEY_CACHE_LOCATION, null);
if(cacheLocn != null && id.indexOf(cacheLocn) != -1) {
- String searchCriteria = Util.parseOfflineIDSearch(context, id, cacheLocn);
- SearchCritera critera = new SearchCritera(searchCriteria, 0, 0, 1);
- SearchResult result = searchNew(critera, context, progressListener);
- if(result.getSongs().size() == 1){
- id = result.getSongs().get(0).getId();
+ Pair<Integer, String> cachedSongId = SongDBHandler.getHandler(context).getIdFromPath(Util.getRestUrlHash(context, getInstance(context)), id);
+ if(cachedSongId != null) {
+ id = cachedSongId.getSecond();
+ } else {
+ String searchCriteria = Util.parseOfflineIDSearch(context, id, cacheLocn);
+ SearchCritera critera = new SearchCritera(searchCriteria, 0, 0, 1);
+ SearchResult result = searchNew(critera, context, progressListener);
+ if (result.getSongs().size() == 1) {
+ id = result.getSongs().get(0).getId();
+ }
}
}
diff --git a/app/src/main/java/github/daneren2005/dsub/service/Scrobbler.java b/app/src/main/java/github/daneren2005/dsub/service/Scrobbler.java
index 1f8538c9..1d9fecef 100644
--- a/app/src/main/java/github/daneren2005/dsub/service/Scrobbler.java
+++ b/app/src/main/java/github/daneren2005/dsub/service/Scrobbler.java
@@ -5,6 +5,7 @@ import android.util.Log;
import github.daneren2005.dsub.domain.PodcastEpisode;
import github.daneren2005.dsub.util.SilentBackgroundTask;
+import github.daneren2005.dsub.util.SongDBHandler;
import github.daneren2005.dsub.util.Util;
/**
@@ -32,28 +33,11 @@ public class Scrobbler {
}
public void scrobble(final Context context, final DownloadFile song, final boolean submission) {
- if (song == null || !Util.isScrobblingEnabled(context)) {
- return;
- }
-
- // Ignore if online with no network access
- if(!Util.isOffline(context) && !Util.isNetworkConnected(context)) {
- return;
- }
-
- // Ignore podcasts
- if(song.getSong() instanceof PodcastEpisode) {
- return;
- }
-
- // Ignore songs which are under 30 seconds per Last.FM guidelines
- Integer duration = song.getSong().getDuration();
- if(duration != null && duration > 0 && duration < 30) {
+ if(song == null) {
return;
}
final String id = song.getSong().getId();
-
// Avoid duplicate registrations.
if (submission && id.equals(lastSubmission)) {
return;
@@ -71,6 +55,27 @@ public class Scrobbler {
new SilentBackgroundTask<Void>(context) {
@Override
protected Void doInBackground() {
+ SongDBHandler.getHandler(context).setSongPlayed(song, submission);
+
+ // Scrobbling disabled
+ if (!Util.isScrobblingEnabled(context)) {
+ return null;
+ }
+ // Ignore if online with no network access
+ else if(!Util.isOffline(context) && !Util.isNetworkConnected(context)) {
+ return null;
+ }
+ // Ignore podcasts
+ else if(song.getSong() instanceof PodcastEpisode) {
+ return null;
+ }
+
+ // Ignore songs which are under 30 seconds per Last.FM guidelines
+ Integer duration = song.getSong().getDuration();
+ if(duration != null && duration > 0 && duration < 30) {
+ return null;
+ }
+
MusicService service = MusicServiceFactory.getMusicService(context);
try {
service.scrobble(id, submission, context, null);
diff --git a/app/src/main/java/github/daneren2005/dsub/util/SongDBHandler.java b/app/src/main/java/github/daneren2005/dsub/util/SongDBHandler.java
new file mode 100644
index 00000000..08f6f461
--- /dev/null
+++ b/app/src/main/java/github/daneren2005/dsub/util/SongDBHandler.java
@@ -0,0 +1,238 @@
+/*
+ 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 2015 (C) Scott Jackson
+*/
+
+package github.daneren2005.dsub.util;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import github.daneren2005.dsub.domain.MusicDirectory;
+import github.daneren2005.dsub.service.DownloadFile;
+
+public class SongDBHandler extends SQLiteOpenHelper {
+ private static final String TAG = SongDBHandler.class.getSimpleName();
+ private static SongDBHandler dbHandler;
+
+ private static final int DATABASE_VERSION = 2;
+ public static final String DATABASE_NAME = "SongsDB";
+
+ public static final String TABLE_SONGS = "RegisteredSongs";
+ public static final String SONGS_ID = "id";
+ public static final String SONGS_SERVER_KEY = "serverKey";
+ public static final String SONGS_SERVER_ID = "serverId";
+ public static final String SONGS_COMPLETE_PATH = "completePath";
+ public static final String SONGS_LAST_PLAYED = "lastPlayed";
+ public static final String SONGS_LAST_COMPLETED = "lastCompleted";
+
+ private Context context;
+
+ private SongDBHandler(Context context) {
+ super(context, DATABASE_NAME, null, DATABASE_VERSION);
+ this.context = context;
+ }
+
+ @Override
+ public void onCreate(SQLiteDatabase db) {
+ db.execSQL("CREATE TABLE " + TABLE_SONGS + " ( " +
+ SONGS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
+ SONGS_SERVER_KEY + " INTEGER NOT NULL, " +
+ SONGS_SERVER_ID + " TEXT NOT NULL, " +
+ SONGS_COMPLETE_PATH + " TEXT NOT NULL, " +
+ SONGS_LAST_PLAYED + " INTEGER, " +
+ SONGS_LAST_COMPLETED + " INTEGER, " +
+ "UNIQUE(" + SONGS_SERVER_KEY + ", " + SONGS_SERVER_ID + "))");
+ }
+
+ @Override
+ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+ db.execSQL("DROP TABLE IF EXISTS " + TABLE_SONGS);
+ this.onCreate(db);
+ }
+
+ public synchronized void addSong(DownloadFile downloadFile) {
+ addSong(Util.getMostRecentActiveServer(context), downloadFile);
+ }
+ public synchronized void addSong(int instance, DownloadFile downloadFile) {
+ SQLiteDatabase db = this.getWritableDatabase();
+ addSong(db, instance, downloadFile);
+ db.close();
+ }
+ protected synchronized void addSong(SQLiteDatabase db, DownloadFile downloadFile) {
+ addSong(db, Util.getMostRecentActiveServer(context), downloadFile);
+ }
+ protected synchronized void addSong(SQLiteDatabase db, int instance, DownloadFile downloadFile) {
+ addSong(db, instance, downloadFile.getSong().getId(), downloadFile.getSaveFile().getAbsolutePath());
+ }
+
+ protected synchronized void addSong(SQLiteDatabase db, String id, String absolutePath) {
+ addSong(db, Util.getMostRecentActiveServer(context), id, absolutePath);
+ }
+ protected synchronized void addSong(SQLiteDatabase db, int instance, String id, String absolutePath) {
+ addSongImpl(db, Util.getRestUrlHash(context, instance), id, absolutePath);
+ }
+ protected synchronized void addSongImpl(SQLiteDatabase db, int serverKey, String id, String absolutePath) {
+ ContentValues values = new ContentValues();
+ values.put(SONGS_SERVER_KEY, serverKey);
+ values.put(SONGS_SERVER_ID, id);
+ values.put(SONGS_COMPLETE_PATH, absolutePath);
+
+ db.insertWithOnConflict(TABLE_SONGS, null, values, SQLiteDatabase.CONFLICT_IGNORE);
+ }
+
+ public synchronized void addSongs(int instance, List<MusicDirectory.Entry> entries) {
+ SQLiteDatabase db = this.getWritableDatabase();
+
+ List<Pair<String, String>> pairs = new ArrayList<>();
+ for(MusicDirectory.Entry entry: entries) {
+ pairs.add(new Pair<>(entry.getId(), FileUtil.getSongFile(context, entry).getAbsolutePath()));
+ }
+ addSongs(db, instance, pairs);
+
+ db.close();
+ }
+ public synchronized void addSongs(SQLiteDatabase db, int instance, List<Pair<String, String>> entries) {
+ addSongsImpl(db, Util.getRestUrlHash(context, instance), entries);
+ }
+ protected synchronized void addSongsImpl(SQLiteDatabase db, int serverKey, List<Pair<String, String>> entries) {
+ db.beginTransaction();
+ try {
+ for (Pair<String, String> entry : entries) {
+ ContentValues values = new ContentValues();
+ values.put(SONGS_SERVER_KEY, serverKey);
+ values.put(SONGS_SERVER_ID, entry.getFirst());
+ values.put(SONGS_COMPLETE_PATH, entry.getSecond());
+
+ db.insertWithOnConflict(TABLE_SONGS, null, values, SQLiteDatabase.CONFLICT_IGNORE);
+ }
+
+ db.setTransactionSuccessful();
+ } catch(Exception e) {}
+
+ db.endTransaction();
+ }
+
+ public synchronized void setSongPlayed(DownloadFile downloadFile, boolean submission) {
+ // TODO: In case of offline want to update all matches
+ Pair<Integer, String> pair = getOnlineSongId(downloadFile);
+ if(pair == null) {
+ return;
+ }
+ int serverKey = pair.getFirst();
+ String id = pair.getSecond();
+
+ // Open and make sure song is in db
+ SQLiteDatabase db = this.getWritableDatabase();
+ addSongImpl(db, serverKey, id, downloadFile.getSaveFile().getAbsolutePath());
+
+ // Update song's last played
+ ContentValues values = new ContentValues();
+ values.put(submission ? SONGS_LAST_COMPLETED : SONGS_LAST_PLAYED, System.currentTimeMillis());
+ db.update(TABLE_SONGS, values, SONGS_SERVER_KEY + " = ? AND " + SONGS_SERVER_ID + " = ?", new String[]{Integer.toString(serverKey), id});
+ db.close();
+ }
+
+ public synchronized Long[] getLastPlayed(MusicDirectory.Entry entry) {
+ return getLastPlayed(getOnlineSongId(entry));
+ }
+ protected synchronized Long[] getLastPlayed(Pair<Integer, String> pair) {
+ return getLastPlayed(pair.getFirst(), pair.getSecond());
+ }
+ public synchronized Long[] getLastPlayed(int serverKey, String id) {
+ SQLiteDatabase db = this.getReadableDatabase();
+
+ String[] columns = {SONGS_LAST_PLAYED, SONGS_LAST_COMPLETED};
+ Cursor cursor = db.query(TABLE_SONGS, columns, SONGS_SERVER_KEY + " = ? AND " + SONGS_SERVER_ID + " = ?", new String[]{Integer.toString(serverKey), id}, null, null, null, null);
+
+ try {
+ cursor.moveToFirst();
+
+ Long[] dates = new Long[2];
+ dates[0] = cursor.getLong(0);
+ dates[1] = cursor.getLong(1);
+ return dates;
+ } catch(Exception e) {}
+
+ return null;
+ }
+
+ public synchronized Pair<Integer, String> getOnlineSongId(MusicDirectory.Entry entry) {
+ return getOnlineSongId(new DownloadFile(context, entry, true));
+ }
+ public synchronized Pair<Integer, String> getOnlineSongId(DownloadFile downloadFile) {
+ return getOnlineSongId(Util.getRestUrlHash(context), downloadFile.getSong().getId(), downloadFile.getSaveFile().getAbsolutePath(), Util.isOffline(context) ? false : true);
+ }
+
+ public synchronized Pair<Integer, String> getOnlineSongId(int serverKey, MusicDirectory.Entry entry) {
+ return getOnlineSongId(serverKey, new DownloadFile(context, entry, true));
+ }
+ public synchronized Pair<Integer, String> getOnlineSongId(int serverKey, DownloadFile downloadFile) {
+ return getOnlineSongId(serverKey, downloadFile.getSong().getId(), downloadFile.getSaveFile().getAbsolutePath(), true);
+ }
+ public synchronized Pair<Integer, String> getOnlineSongId(int serverKey, String id, String savePath, boolean requireServerKey) {
+ SharedPreferences prefs = Util.getPreferences(context);
+ String cacheLocn = prefs.getString(Constants.PREFERENCES_KEY_CACHE_LOCATION, null);
+ if(cacheLocn != null && id.indexOf(cacheLocn) != -1) {
+ if(requireServerKey) {
+ return getIdFromPath(serverKey, savePath);
+ } else {
+ return getIdFromPath(savePath);
+ }
+ } else {
+ return new Pair<>(serverKey, id);
+ }
+ }
+
+ public synchronized Pair<Integer, String> getIdFromPath(String path) {
+ SQLiteDatabase db = this.getReadableDatabase();
+
+ String[] columns = {SONGS_SERVER_KEY, SONGS_SERVER_ID};
+ Cursor cursor = db.query(TABLE_SONGS, columns, SONGS_COMPLETE_PATH + " = ?", new String[] { path }, null, null, SONGS_LAST_PLAYED + " DESC", null);
+
+ try {
+ cursor.moveToFirst();
+ return new Pair(cursor.getInt(0), cursor.getString(1));
+ } catch(Exception e) {}
+
+ return null;
+ }
+ public synchronized Pair<Integer, String> getIdFromPath(int serverKey, String path) {
+ SQLiteDatabase db = this.getReadableDatabase();
+
+ String[] columns = {SONGS_SERVER_KEY, SONGS_SERVER_ID};
+ Cursor cursor = db.query(TABLE_SONGS, columns, SONGS_SERVER_KEY + " = ? AND " + SONGS_COMPLETE_PATH + " = ?", new String[] {Integer.toString(serverKey), path }, null, null, null, null);
+
+ try {
+ cursor.moveToFirst();
+ return new Pair(cursor.getInt(0), cursor.getString(1));
+ } catch(Exception e) {}
+
+ return null;
+ }
+
+ public static SongDBHandler getHandler(Context context) {
+ if(dbHandler == null) {
+ dbHandler = new SongDBHandler(context);
+ }
+
+ return dbHandler;
+ }
+}
diff --git a/app/src/main/java/github/daneren2005/dsub/util/Util.java b/app/src/main/java/github/daneren2005/dsub/util/Util.java
index 490e922b..bf4af20d 100644
--- a/app/src/main/java/github/daneren2005/dsub/util/Util.java
+++ b/app/src/main/java/github/daneren2005/dsub/util/Util.java
@@ -176,6 +176,10 @@ public final class Util {
// Don't allow the SERVER_INSTANCE to ever be 0
return prefs.getBoolean(Constants.PREFERENCES_KEY_OFFLINE, false) ? 0 : Math.max(1, prefs.getInt(Constants.PREFERENCES_KEY_SERVER_INSTANCE, 1));
}
+ public static int getMostRecentActiveServer(Context context) {
+ SharedPreferences prefs = getPreferences(context);
+ return Math.max(1, prefs.getInt(Constants.PREFERENCES_KEY_SERVER_INSTANCE, 1));
+ }
public static int getServerCount(Context context) {
SharedPreferences prefs = getPreferences(context);
@@ -450,6 +454,18 @@ public final class Util {
return builder.toString();
}
+ public static int getRestUrlHash(Context context) {
+ return getRestUrlHash(context, Util.getMostRecentActiveServer(context));
+ }
+ public static int getRestUrlHash(Context context, int instance) {
+ StringBuilder builder = new StringBuilder();
+
+ SharedPreferences prefs = Util.getPreferences(context);
+ builder.append(prefs.getString(Constants.PREFERENCES_KEY_SERVER_URL + instance, null));
+ builder.append(prefs.getString(Constants.PREFERENCES_KEY_USERNAME + instance, null));
+
+ return builder.toString().hashCode();
+ }
public static String replaceInternalUrl(Context context, String url) {
// Only change to internal when using https
@@ -908,6 +924,9 @@ public final class Util {
}
}
}
+ public static String formatDate(long millis) {
+ return formatDate(new Date(millis));
+ }
public static String formatBoolean(Context context, boolean value) {
return context.getResources().getString(value ? R.string.common_true : R.string.common_false);
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 303a8e0e..3acbff3e 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -642,6 +642,7 @@
<string name="details.position">Position</string>
<string name="details.updated">Updated</string>
<string name="details.starred">Starred</string>
+ <string name="details.last_played">Last Played</string>
<plurals name="select_album_n_songs">
<item quantity="zero">No songs</item>