diff --git a/app/src/main/java/ru/vtosters/hooks/music/injectors/PlaylistInjector.java b/app/src/main/java/ru/vtosters/hooks/music/injectors/PlaylistInjector.java index b9553eeaf..58a1638ce 100644 --- a/app/src/main/java/ru/vtosters/hooks/music/injectors/PlaylistInjector.java +++ b/app/src/main/java/ru/vtosters/hooks/music/injectors/PlaylistInjector.java @@ -45,7 +45,8 @@ private static boolean isAlbumVirtualPlaylist(String accessKey) { } private static boolean isOwnCachePlaylist(String ownerId, String id) { - return Objects.equals(ownerId, String.valueOf(AccountManagerUtils.getUserId())) && Objects.equals(id, "-1"); + return Objects.equals(ownerId, String.valueOf(AccountManagerUtils.getUserId())) + && Objects.equals(id, "-1"); } private static int[] getCountAndOffset(Map requestArgs) { @@ -87,11 +88,11 @@ private static Observable handleMusicCacheImpl(int id, int o return Observable.c(() -> { AudioGetPlaylist.c response = new AudioGetPlaylist.c(); + response.c = new ArrayList<>(MusicCacheImpl.getPlaylistSongs(ownerId, id, offset, count)); + if (isOwnCachePlaylist) { - response.c = (ArrayList) TracklistHelper.getMyCachedMusicTracks(); response.b = PlaylistHelper.createCachedPlaylistMetadata(); } else { - response.c = new ArrayList<>(MusicCacheImpl.getPlaylistSongs(ownerId, id, offset, count)); response.b = MusicCacheImpl.getPlaylist(id, ownerId); } return response; diff --git a/app/src/main/java/ru/vtosters/lite/downloaders/AudioDownloader.java b/app/src/main/java/ru/vtosters/lite/downloaders/AudioDownloader.java index 76546e3d9..f7cbde694 100644 --- a/app/src/main/java/ru/vtosters/lite/downloaders/AudioDownloader.java +++ b/app/src/main/java/ru/vtosters/lite/downloaders/AudioDownloader.java @@ -53,7 +53,7 @@ public static void downloadPlaylist(Playlist playlist) { int notificationId = playlistName.hashCode(); NotificationCompat.Builder notification = MusicNotificationBuilder.buildPlaylistDownloadNotification(playlistName, notificationId); - downloadPlaylist(tracks, playlistName, downloadPath, notification, notificationId); + downloadPlaylist(tracks, downloadPath, notification, notificationId); }); } @@ -107,7 +107,7 @@ public static void downloadAllAudios() { String downloadPath = getDownloadPath(playlistName); if (!tracks.isEmpty()) { - downloadPlaylist(tracks, playlistName, downloadPath, notification, notificationId); + downloadPlaylist(tracks, downloadPath, notification, notificationId); } }); } @@ -124,17 +124,18 @@ private static void downloadM3U8(MusicTrack track, boolean cache) { Callback cb = MusicCallbackBuilder.buildOneTrackCallback(tempId, notification); if (cache) { - TrackDownloader.cacheTrack(track, cb, PlaylistHelper.createCachedPlaylistMetadata()); + Playlist playlist = PlaylistHelper.createCachedPlaylistMetadata(); + TrackDownloader.cacheTrack(track, cb, + PlaylistCacheDbDelegate.getOrCreatePlaylist(playlist)); } else { TrackDownloader.downloadTrack(track, downloadPath, cb); } }); } - private static void downloadPlaylist(List tracks, String playlistName, String downloadPath, NotificationCompat.Builder notification, int notificationId) { + private static void downloadPlaylist(List tracks, String downloadPath, NotificationCompat.Builder notification, int notificationId) { PlaylistDownloader.downloadPlaylist( tracks, - playlistName, downloadPath, MusicCallbackBuilder.buildPlaylistCallback(tracks.size(), notification, notificationId) ); @@ -151,7 +152,7 @@ public void onProgress(int progress) { @Override public void onSuccess() { - PlaylistCacheDbDelegate.addPlaylist(playlist); + PlaylistCacheDbDelegate.getOrCreatePlaylist(playlist); Log.d("Playlist", "adding to cache with thumbs " + playlist.v1()); } @@ -161,7 +162,7 @@ public void onFailure(Throwable e) { } }).download(playlist); } else { - PlaylistCacheDbDelegate.addPlaylist(playlist); + PlaylistCacheDbDelegate.getOrCreatePlaylist(playlist); Log.d("Playlist", "adding to cache without thumbs " + playlist.a); } diff --git a/app/src/main/java/ru/vtosters/lite/music/cache/DatabaseAccess.java b/app/src/main/java/ru/vtosters/lite/music/cache/DatabaseAccess.java new file mode 100644 index 000000000..adcd843fd --- /dev/null +++ b/app/src/main/java/ru/vtosters/lite/music/cache/DatabaseAccess.java @@ -0,0 +1,12 @@ +package ru.vtosters.lite.music.cache; + +import android.database.sqlite.SQLiteDatabase; + +import java.io.Closeable; + +public interface DatabaseAccess extends Closeable { + + SQLiteDatabase getReadableDatabase(); + + SQLiteDatabase getWritableDatabase(); +} diff --git a/app/src/main/java/ru/vtosters/lite/music/cache/MusicCacheImpl.java b/app/src/main/java/ru/vtosters/lite/music/cache/MusicCacheImpl.java index c93b8f373..278fd4871 100644 --- a/app/src/main/java/ru/vtosters/lite/music/cache/MusicCacheImpl.java +++ b/app/src/main/java/ru/vtosters/lite/music/cache/MusicCacheImpl.java @@ -1,6 +1,7 @@ package ru.vtosters.lite.music.cache; import android.content.Context; +import android.database.sqlite.SQLiteDatabase; import android.os.RemoteException; import bruhcollective.itaysonlab.libvkx.ILibVkxService; import bruhcollective.itaysonlab.libvkx.client.LibVKXClient; @@ -24,7 +25,8 @@ @SuppressWarnings("forRemoval") public class MusicCacheImpl { - private static final Database connection = new Database(); + private static final Database connection = + new Database(); private static final MusicCacheDb musics = new MusicCacheDb(connection); private static final IPlaylists playlists = new SqlPlaylists(connection); @@ -35,13 +37,6 @@ public static void removeTrack(String trackId) { MusicCacheStorageUtils.removeTrackDirById(trackId); } - public static List getAllOwnTracks() { - return playlists - .playlist(AccountManagerUtils.getUserId(), -1) - .map(IPlaylist::tracks) - .orElse(List.of()); - } - public static List getPlaylistSongs(int owner_id, int playlist_id, diff --git a/app/src/main/java/ru/vtosters/lite/music/cache/db/Constants.java b/app/src/main/java/ru/vtosters/lite/music/cache/db/Constants.java index 925ee78eb..8790fb4df 100644 --- a/app/src/main/java/ru/vtosters/lite/music/cache/db/Constants.java +++ b/app/src/main/java/ru/vtosters/lite/music/cache/db/Constants.java @@ -55,8 +55,6 @@ public interface Constants { + PLAYLIST_ID + " INTEGER NOT NULL," + TRACK_ID + " TEXT NOT NULL," - + "PRIMARY KEY (" + OWNER_ID + ", " + PLAYLIST_ID + ", " + TRACK_ID + ")," - + "FOREIGN KEY (" + OWNER_ID + ", " + PLAYLIST_ID + ") " + "REFERENCES " + TABLE_PLAYLIST + "(" + OWNER_ID + ", " + PLAYLIST_ID + ") " + "ON DELETE CASCADE," diff --git a/app/src/main/java/ru/vtosters/lite/music/cache/db/Database.java b/app/src/main/java/ru/vtosters/lite/music/cache/db/Database.java index 66c48d147..79009c2f7 100644 --- a/app/src/main/java/ru/vtosters/lite/music/cache/db/Database.java +++ b/app/src/main/java/ru/vtosters/lite/music/cache/db/Database.java @@ -6,19 +6,25 @@ import androidx.annotation.Nullable; import com.vk.dto.music.MusicTrack; import com.vk.dto.music.Playlist; + +import ru.vtosters.lite.music.cache.DatabaseAccess; import ru.vtosters.lite.music.cache.db.old.OldMusicCacheDb; import ru.vtosters.lite.music.cache.db.old.OldPlaylistCacheDb; +import ru.vtosters.lite.music.cache.helpers.PlaylistHelper; +import ru.vtosters.lite.music.interfaces.IPlaylist; +import ru.vtosters.lite.utils.AccountManagerUtils; import ru.vtosters.lite.utils.AndroidUtils; - -import java.util.HashMap; import java.util.List; import java.util.Map; -public final class Database extends SQLiteOpenHelper implements AutoCloseable { +public final class Database extends SQLiteOpenHelper implements DatabaseAccess { + + public Database() { this(AndroidUtils.getGlobalContext()); } + public Database(@Nullable Context context) { super(context, Constants.DB_NAME, null, Constants.DV_VERSION); } @@ -28,50 +34,53 @@ public void onCreate(SQLiteDatabase db) { db.execSQL(Constants.CREATE_TABLE_MUSICS); db.execSQL(Constants.CREATE_TABLE_PLAYLISTS); db.execSQL(Constants.CREATE_TABLE_PLAYLIST_TRACKS); + } @Override public void onUpgrade(SQLiteDatabase db, int prev, int current) { if (prev < current) { - migrateMusics(); - migratePlaylists(); - } - } - - private void migrateMusics() { - try (OldMusicCacheDb old = new OldMusicCacheDb(AndroidUtils.getGlobalContext())) { - MusicCacheDb musics = new MusicCacheDb(this); + DatabaseAccess access = new DatabaseAccess() { + @Override public void close() { db.close(); } - SQLiteDatabase write = old.getWritableDatabase(); - List tracks = old.getAllTracks(); + @Override public SQLiteDatabase getReadableDatabase() { + return db; + } - write.execSQL(OldMusicCacheDb.Constants.DROP_QUERY); + @Override public SQLiteDatabase getWritableDatabase() { + return db; + } + }; + try (OldMusicCacheDb musics = new OldMusicCacheDb()) { + List tracks = musics.getAllTracks(); - tracks.forEach(musics::addTrack); - } - } + OldPlaylistCacheDb oldPlaylistCacheDb = new OldPlaylistCacheDb(db); - private void migratePlaylists() { - try (OldPlaylistCacheDb old = new OldPlaylistCacheDb(AndroidUtils.getGlobalContext())) { - Map> map = new HashMap<>(); + List main = oldPlaylistCacheDb + .getTracksInPlaylist( + AccountManagerUtils.getUserId()+"_-1"); + Map> map = oldPlaylistCacheDb.playlistListMap(); - SQLiteDatabase write = old.getWritableDatabase(); + oldPlaylistCacheDb.onDelete(); - old.getAllPlaylists().forEach(playlist -> { - map.put(playlist, old.getTracksInPlaylist(playlist.v1())); - }); - write.execSQL(OldPlaylistCacheDb.Constants.DROP_QUERY); + onCreate(db); - SqlPlaylists playlists = new SqlPlaylists(this); + MusicCacheDb musicCacheDb = new MusicCacheDb(access); - map.forEach((playlist, tracks) -> { - playlists.addPlaylist(playlist); + tracks.forEach(musicCacheDb::addTrack); - playlists.playlist(playlist.b, playlist.a).ifPresent(newPlaylist -> { - tracks.forEach(track -> newPlaylist.addTrack(track.y1())); + SqlPlaylists playlists = new SqlPlaylists(access); + map.forEach((playlist, musicTracks) -> { + IPlaylist iPlaylist = playlists.insertIfAbsent(playlist); + musicTracks.forEach(iPlaylist::addTrack); }); - }); + IPlaylist cached = playlists.insertIfAbsent(PlaylistHelper + .createCachedPlaylistMetadata()); + + + main.forEach(cached::addTrack); + } } } } \ No newline at end of file diff --git a/app/src/main/java/ru/vtosters/lite/music/cache/db/MusicCacheDb.java b/app/src/main/java/ru/vtosters/lite/music/cache/db/MusicCacheDb.java index 1261755ac..6be00ad53 100644 --- a/app/src/main/java/ru/vtosters/lite/music/cache/db/MusicCacheDb.java +++ b/app/src/main/java/ru/vtosters/lite/music/cache/db/MusicCacheDb.java @@ -10,6 +10,8 @@ import com.vk.dto.music.MusicTrack; import com.vk.dto.music.Thumb; import org.json.JSONObject; + +import ru.vtosters.lite.music.cache.DatabaseAccess; import ru.vtosters.lite.utils.AndroidUtils; import ru.vtosters.lite.utils.music.MusicCacheStorageUtils; import ru.vtosters.lite.utils.music.MusicTrackUtils; @@ -24,9 +26,9 @@ */ public class MusicCacheDb { - private final SQLiteOpenHelper sqlite; + private final DatabaseAccess sqlite; - public MusicCacheDb(SQLiteOpenHelper sqlite) { + public MusicCacheDb(DatabaseAccess sqlite) { this.sqlite = sqlite; } @@ -119,8 +121,7 @@ public void deleteTrack(String trackId) { } public Optional getTrackById(String trackId) { - SQLiteDatabase db = sqlite.getReadableDatabase(); - try (Cursor cursor = db.query(Constants.TABLE_MUSICS, + try (Cursor cursor = sqlite.getReadableDatabase().query(Constants.TABLE_MUSICS, null, Constants.TRACK_ID + " = ?", new String[]{trackId}, @@ -134,35 +135,13 @@ public Optional getTrackById(String trackId) { public boolean isDatabaseEmpty() { SQLiteDatabase db = sqlite.getReadableDatabase(); - if (db == null) { - return true; // or throw an exception, depending on your use case - } - - Cursor cursor = db.rawQuery("SELECT name FROM sqlite_master WHERE type='table' AND name=?", new String[]{Constants.TABLE_MUSICS}); - - if (cursor == null || !cursor.moveToFirst()) { - db.close(); - Log.d("MusicCacheDb", "Database is empty and can be null"); - return true; // Table does not exist, so the database is considered empty - } - cursor.close(); - - cursor = db.rawQuery("SELECT EXISTS(SELECT 1 FROM " + Constants.TABLE_MUSICS + " LIMIT 1)", null); - - if (cursor == null) { - db.close(); - Log.d("MusicCacheDb", "Database is empty"); - return true; // or throw an exception, depending on your use case - } - - boolean isEmpty = true; - if (cursor.moveToFirst()) { - isEmpty = cursor.getInt(0) == 0; + try (Cursor cursor = db.query( + Constants.TABLE_MUSICS, + null, null, + null, null, + null, null)) { + return cursor == null || !cursor.moveToNext(); } - - cursor.close(); - db.close(); - return isEmpty; } } \ No newline at end of file diff --git a/app/src/main/java/ru/vtosters/lite/music/cache/db/SqlPlaylist.java b/app/src/main/java/ru/vtosters/lite/music/cache/db/SqlPlaylist.java index 12f7ef1a7..1ae3a2e82 100644 --- a/app/src/main/java/ru/vtosters/lite/music/cache/db/SqlPlaylist.java +++ b/app/src/main/java/ru/vtosters/lite/music/cache/db/SqlPlaylist.java @@ -4,10 +4,13 @@ import android.content.ContentValues; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteOpenHelper; import android.util.Log; import com.vk.dto.music.MusicTrack; import com.vk.dto.music.Playlist; import org.json.JSONObject; + +import ru.vtosters.lite.music.cache.DatabaseAccess; import ru.vtosters.lite.music.cache.helpers.PlaylistHelper; import ru.vtosters.lite.music.cache.helpers.TracklistHelper; import ru.vtosters.lite.music.interfaces.IPlaylist; @@ -19,9 +22,9 @@ public final class SqlPlaylist implements IPlaylist { private final int ownerId, id; - private final Database sqlite; + private final DatabaseAccess sqlite; - public SqlPlaylist(int ownerId, int id, Database sqlite) { + public SqlPlaylist(int ownerId, int id, DatabaseAccess sqlite) { this.ownerId = ownerId; this.id = id; this.sqlite = sqlite; @@ -41,6 +44,7 @@ public int ownerId() { public void addTrack(String trackId) { ContentValues values = new ContentValues(); + System.clearProperty(ownerId + " " + id); values.put(Constants.OWNER_ID, ownerId); values.put(Constants.PLAYLIST_ID, id); values.put(Constants.TRACK_ID, trackId); @@ -53,20 +57,18 @@ public void addTrack(String trackId) { @Override public void removeTrack(String trackId) { - sqlite.getWritableDatabase() - .delete(Constants.TABLE_PLAYLIST_TRACKS, - selection() + " AND " + Constants.TRACK_ID + " = ?", - new String[]{ - Integer.toString(id), - Integer.toString(ownerId), - trackId, - }); + sqlite.getReadableDatabase().delete(Constants.TABLE_PLAYLIST_TRACKS, + selection() + " AND " + Constants.TRACK_ID + " = ?", + new String[]{ + Integer.toString(id), + Integer.toString(ownerId), + trackId, + }); } @Override public List tracks(int offset, int count) { - SQLiteDatabase db = sqlite.getReadableDatabase(); - try (Cursor cursor = db.query( + try (Cursor cursor = sqlite.getReadableDatabase().query( Constants.TABLE_PLAYLIST_TRACKS, new String[]{Constants.TRACK_ID}, selection(), compositeKey(), @@ -88,19 +90,17 @@ public List tracks(int offset, int count) { @Override public int count() { - try (Cursor cursor = sqlite.getReadableDatabase() - .query(Constants.TABLE_PLAYLIST_TRACKS, - new String[]{"COUNT(*)"}, - selection(), compositeKey(), - null, null, null)) { + try (Cursor cursor = sqlite.getReadableDatabase().query(Constants.TABLE_PLAYLIST_TRACKS, + new String[]{"COUNT(*)"}, + selection(), compositeKey(), + null, null, null)) { return cursor.moveToFirst() ? cursor.getInt(0) : 0; } } @Override public boolean isEmpty() { - SQLiteDatabase db = sqlite.getReadableDatabase(); - try (Cursor cursor = db.query( + try (Cursor cursor = sqlite.getReadableDatabase().query( Constants.TABLE_PLAYLIST_TRACKS, null, selection(), compositeKey(), @@ -113,16 +113,15 @@ public boolean isEmpty() { @Override @SuppressLint("Range") public Playlist toPlaylist() { - try (Cursor cur = sqlite.getReadableDatabase() - .query(Constants.TABLE_PLAYLIST, - new String[]{ - Constants.PLAYLIST_IS_EXPLICIT, - Constants.PLAYLIST_TITLE, - Constants.PLAYLIST_DESCRIPTION, - Constants.PLAYLIST_PHOTO, - }, - selection(), compositeKey(), - null, null, null)) { + try (Cursor cur = sqlite.getReadableDatabase().query(Constants.TABLE_PLAYLIST, + new String[]{ + Constants.PLAYLIST_IS_EXPLICIT, + Constants.PLAYLIST_TITLE, + Constants.PLAYLIST_DESCRIPTION, + Constants.PLAYLIST_PHOTO, + }, + selection(), compositeKey(), + null, null, null)) { if (!cur.moveToFirst()) { throw new IllegalStateException(); } diff --git a/app/src/main/java/ru/vtosters/lite/music/cache/db/SqlPlaylists.java b/app/src/main/java/ru/vtosters/lite/music/cache/db/SqlPlaylists.java index 21e4f7fd4..74189af23 100644 --- a/app/src/main/java/ru/vtosters/lite/music/cache/db/SqlPlaylists.java +++ b/app/src/main/java/ru/vtosters/lite/music/cache/db/SqlPlaylists.java @@ -2,11 +2,15 @@ import android.content.ContentValues; import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteOpenHelper; import android.net.Uri; import android.util.Log; import com.vk.dto.music.Playlist; import org.json.JSONException; import org.json.JSONObject; + +import ru.vtosters.lite.music.cache.DatabaseAccess; import ru.vtosters.lite.music.interfaces.IPlaylist; import ru.vtosters.lite.music.interfaces.IPlaylists; import ru.vtosters.lite.utils.music.MusicCacheStorageUtils; @@ -16,9 +20,9 @@ public final class SqlPlaylists implements IPlaylists { - private final Database database; + private final DatabaseAccess database; - public SqlPlaylists(Database database) { + public SqlPlaylists(DatabaseAccess database) { this.database = database; } @@ -125,6 +129,7 @@ public List playlists() { @Override public void addPlaylist(Playlist playlist) { + System.out.println("CREATE PLAYLIST!!!! " + playlist.b + " " + playlist.a); ContentValues values = new ContentValues(); values.put(Constants.OWNER_ID, playlist.b); values.put(Constants.PLAYLIST_ID, playlist.a); @@ -133,7 +138,11 @@ public void addPlaylist(Playlist playlist) { values.put(Constants.PLAYLIST_DESCRIPTION, playlist.B); values.put(Constants.PLAYLIST_PHOTO, String.valueOf(generatePhotoJSON(playlist))); - database.getWritableDatabase().insert(Constants.TABLE_PLAYLIST, null, values); + try { + database.getWritableDatabase().insert( + Constants.TABLE_PLAYLIST, null, values); + // todo: + } catch (Exception ignored) { } } @Override diff --git a/app/src/main/java/ru/vtosters/lite/music/cache/db/old/OldMusicCacheDb.java b/app/src/main/java/ru/vtosters/lite/music/cache/db/old/OldMusicCacheDb.java index 05ae8ef88..8517d86bf 100644 --- a/app/src/main/java/ru/vtosters/lite/music/cache/db/old/OldMusicCacheDb.java +++ b/app/src/main/java/ru/vtosters/lite/music/cache/db/old/OldMusicCacheDb.java @@ -1,6 +1,5 @@ package ru.vtosters.lite.music.cache.db.old; -import android.content.Context; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; @@ -9,6 +8,9 @@ import com.vk.dto.music.MusicTrack; import com.vk.dto.music.Thumb; import org.json.JSONObject; +import ru.vtosters.lite.music.cache.db.Database; +import ru.vtosters.lite.music.cache.db.MusicCacheDb; +import ru.vtosters.lite.utils.AndroidUtils; import ru.vtosters.lite.utils.music.MusicCacheStorageUtils; import java.io.File; @@ -17,6 +19,7 @@ import java.net.URLDecoder; import java.util.ArrayList; import java.util.List; +import java.util.Optional; /** *

Note: the {@link AutoCloseable} interface was @@ -24,10 +27,15 @@ */ @SuppressWarnings("forRemoval") public class OldMusicCacheDb extends SQLiteOpenHelper { - public OldMusicCacheDb(Context context) { - super(context, Constants.DB_NAME, null, Constants.DV_VERSION); + + + + public OldMusicCacheDb() { + super(AndroidUtils.getGlobalContext(), + Constants.DB_NAME, null, Constants.DV_VERSION); } + private static MusicTrack fromCursor(Cursor cur) { try { int trackIdIndex = cur.getColumnIndex(Constants.COLUMN_TRACK_ID); @@ -92,16 +100,15 @@ private static MusicTrack fromCursor(Cursor cur) { return null; } - @Override + public void onCreate(SQLiteDatabase db) { db.execSQL(Constants.CREATE_QUERY); } - - @Override - public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { - + public void onDelete() { + getWritableDatabase().execSQL(Constants.DROP_QUERY); } + public List getAllTracks() { Cursor cursor = getReadableDatabase() .query(Constants.TABLE_NAME, @@ -125,9 +132,15 @@ private List getTracksWithCursor(Cursor cur) { return res; } + + @Override + public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { + + } + @Retention(RetentionPolicy.SOURCE) - public @interface Constants { - int DV_VERSION = 0x3; + private @interface Constants { + int DV_VERSION = 0x4; String DB_NAME = "vt_lite_cache.db"; String TABLE_NAME = "tracks"; //columns diff --git a/app/src/main/java/ru/vtosters/lite/music/cache/db/old/OldPlaylistCacheDb.java b/app/src/main/java/ru/vtosters/lite/music/cache/db/old/OldPlaylistCacheDb.java index 6b51e4f03..bb872160e 100644 --- a/app/src/main/java/ru/vtosters/lite/music/cache/db/old/OldPlaylistCacheDb.java +++ b/app/src/main/java/ru/vtosters/lite/music/cache/db/old/OldPlaylistCacheDb.java @@ -16,24 +16,31 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; @SuppressWarnings("forRemoval") -public class OldPlaylistCacheDb extends SQLiteOpenHelper { - public OldPlaylistCacheDb(Context context) { - super(context, Constants.DB_NAME, null, Constants.DV_VERSION); - } +public class OldPlaylistCacheDb { + + private final SQLiteDatabase database; - private static Playlist fromCursor(Cursor cur) throws JSONException { - @SuppressLint("Range") + public OldPlaylistCacheDb(SQLiteDatabase database) { + this.database = database; + } + @SuppressLint("Range") + private Playlist fromCursor(Cursor cur) throws JSONException { String photoString = cur.getString(cur.getColumnIndex(Constants.COLUMN_PHOTO)); JSONObject photo = new JSONObject(photoString); - @SuppressLint("Range") + int id = cur.getInt(cur.getColumnIndex(Constants.COLUMN_ID)); + int ownerId = cur.getInt(cur.getColumnIndex(Constants.COLUMN_OWNER_ID)); + + JSONObject playlist = PlaylistHelper.generatePlaylist( - cur.getInt(cur.getColumnIndex(Constants.COLUMN_ID)), - cur.getInt(cur.getColumnIndex(Constants.COLUMN_OWNER_ID)), + id, + ownerId, Boolean.parseBoolean(cur.getString(cur.getColumnIndex(Constants.COLUMN_IS_EXPLICIT))), cur.getString(cur.getColumnIndex(Constants.COLUMN_TITLE)), cur.getString(cur.getColumnIndex(Constants.COLUMN_DESCRIPTION)), @@ -45,41 +52,49 @@ private static Playlist fromCursor(Cursor cur) throws JSONException { return Playlist.U.a(playlist); } - @Override - public void onCreate(SQLiteDatabase db) { - db.execSQL(Constants.CREATE_QUERY); - db.execSQL(Constants.CREATE_PLAYLIST_TRACKS_QUERY); - } - @Override - public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { - db.execSQL(Constants.DROP_QUERY); - onCreate(db); + public void onDelete() { + database.execSQL(Constants.DROP_QUERY); + database.execSQL(Constants.DROP_QUERY_TRACKS); } public List getAllPlaylists() { - Cursor cursor = getReadableDatabase().query(Constants.TABLE_NAME, null, null, null, null, null, null); - List playlists = getPlaylistsWithCursor(cursor); - cursor.close(); - return playlists; + Cursor cursor = database.query(Constants.TABLE_NAME, + null, null, null, + null, null, null); + return getPlaylistsWithCursor(cursor); } private List getPlaylistsWithCursor(Cursor cur) { List playlists = new ArrayList<>(); - while (cur.moveToNext()) { - try { - playlists.add(fromCursor(cur)); - } catch (JSONException e) { - Log.d("Playlist", "could not parse playlist"); + if (cur != null) { + while (cur.moveToNext()) { + try { + playlists.add(fromCursor(cur)); + } catch (JSONException e) { + Log.d("Playlist", "could not parse playlist"); + } } + cur.close(); } return playlists; } + public Map> + playlistListMap() { + Map> playlists = new HashMap<>(); + getAllPlaylists().forEach(playlist -> { + + List tracksIds = getTracksInPlaylist(playlist.v1()); - public List getTracksInPlaylist(String playlistId) { - SQLiteDatabase db = getReadableDatabase(); - Cursor cursor = db.query( + playlists.put(playlist, tracksIds); + }); + return playlists; + + } + + public List getTracksInPlaylist(String playlistId) { + Cursor cursor = database.query( Constants.TABLE_PLAYLIST_TRACKS, new String[]{Constants.COLUMN_TRACK_ID}, Constants.COLUMN_PLAYLIST_ID + " = ?", @@ -87,26 +102,25 @@ public List getTracksInPlaylist(String playlistId) { null, null, null ); - List tracks = new ArrayList<>(); - while (cursor.moveToNext()) { - @SuppressLint("Range") - String trackId = cursor.getString(cursor.getColumnIndex(Constants.COLUMN_TRACK_ID)); - TracklistHelper.getTrack(trackId).ifPresent(tracks::add); + List tracks = new ArrayList<>(); + if (cursor != null) { + try (cursor) { + while (cursor.moveToNext()) { + @SuppressLint("Range") + String trackId = cursor.getString( + cursor.getColumnIndex(Constants.COLUMN_TRACK_ID)); + tracks.add(trackId); + } + } } - - cursor.close(); return tracks; } - @Override - public void onConfigure(SQLiteDatabase db) { - super.onConfigure(db); - db.setForeignKeyConstraintsEnabled(true); - } + @Retention(RetentionPolicy.SOURCE) - public @interface Constants { + private @interface Constants { int DV_VERSION = 0x2; String DB_NAME = "vt_lite_cache_playlists.db"; String TABLE_NAME = "playlists"; @@ -141,5 +155,6 @@ public void onConfigure(SQLiteDatabase db) { + ")"; String DROP_QUERY = "drop table if exists " + TABLE_NAME; + String DROP_QUERY_TRACKS = "drop table if exists " + TABLE_PLAYLIST_TRACKS; } } \ No newline at end of file diff --git a/app/src/main/java/ru/vtosters/lite/music/cache/delegate/PlaylistCacheDbDelegate.java b/app/src/main/java/ru/vtosters/lite/music/cache/delegate/PlaylistCacheDbDelegate.java index 3682a5825..a4537976b 100644 --- a/app/src/main/java/ru/vtosters/lite/music/cache/delegate/PlaylistCacheDbDelegate.java +++ b/app/src/main/java/ru/vtosters/lite/music/cache/delegate/PlaylistCacheDbDelegate.java @@ -1,6 +1,7 @@ package ru.vtosters.lite.music.cache.delegate; import android.content.Context; + import com.vk.dto.music.Playlist; import ru.vtosters.lite.music.cache.db.Constants; import ru.vtosters.lite.music.cache.db.Database; @@ -13,76 +14,59 @@ @SuppressWarnings("forRemoval") public class PlaylistCacheDbDelegate { + public static final Database connection = new Database(); - public static void addPlaylist(Playlist playlist) { - try (Database db = new Database()) { - new SqlPlaylists(db).addPlaylist(playlist); - } + public static IPlaylist getOrCreatePlaylist(Playlist playlist) { + return new SqlPlaylists(connection).insertIfAbsent(playlist); } public static void deletePlaylist(int id, int ownerId) { - - try (Database db = new Database()) { - new SqlPlaylists(db).deletePlaylist(ownerId, id); - } + new SqlPlaylists(connection).deletePlaylist(ownerId, id); } public static long getTracksCountInPlaylist(int ownerId, int id) { - try (Database db = new Database()) { - return new SqlPlaylists(db).playlist(ownerId, id) - .map(IPlaylist::count) - .orElse(0); - } + + return new SqlPlaylists(connection).playlist(ownerId, id) + .map(IPlaylist::count) + .orElse(0); } public static boolean isPlaylistsDbEmpty() { - try (Database db = new Database()) { - return new SqlPlaylists(db).isEmpty(); - } + return new SqlPlaylists(connection).isEmpty(); } public static void removeAllPlaylists() { - try (Database db = new Database()) { - new SqlPlaylists(db).deleteAll(); - } + new SqlPlaylists(connection).deleteAll(); } public static List getAllPlaylistIds() { - try (Database db = new Database()) { - return new SqlPlaylists(db).playlists() - .stream() - .map(x -> x.ownerId() + "_" + x.id()) - .collect(Collectors.toList()); - } + return new SqlPlaylists(connection).playlists() + .stream() + .map(x -> x.ownerId() + "_" + x.id()) + .collect(Collectors.toList()); } public static boolean isCachedPlaylist(int ownerId, int id) { - try (Database db = new Database()) { - return new SqlPlaylists(db).playlist(ownerId, id).isPresent(); - } + return new SqlPlaylists(connection).playlist(ownerId, id).isPresent(); } public static List getAllPlaylists() { - try (Database db = new Database()) { - return new SqlPlaylists(db).playlists() - .stream() - .map(IPlaylist::toPlaylist) - .collect(Collectors.toList()); - } + return new SqlPlaylists(connection).playlists() + .stream() + .map(IPlaylist::toPlaylist) + .collect(Collectors.toList()); } public static boolean isPlaylistEmpty(int ownerId, int id) { - try (Database db = new Database()) { - return new SqlPlaylists(db).playlist(ownerId, id) - .map(IPlaylist::isEmpty) - .orElse(true); - } + return new SqlPlaylists(connection).playlist(ownerId, id) + .map(IPlaylist::isEmpty) + .orElse(true); } public static void drop(Context context) { diff --git a/app/src/main/java/ru/vtosters/lite/music/cache/helpers/PlaylistHelper.java b/app/src/main/java/ru/vtosters/lite/music/cache/helpers/PlaylistHelper.java index 981013f37..8a454805e 100644 --- a/app/src/main/java/ru/vtosters/lite/music/cache/helpers/PlaylistHelper.java +++ b/app/src/main/java/ru/vtosters/lite/music/cache/helpers/PlaylistHelper.java @@ -19,7 +19,7 @@ public static Playlist createCachedPlaylistMetadata() { try { return new Playlist(getCachedSongsPlaylist()); } catch (JSONException e) { - return null; + throw new RuntimeException(e); } } @@ -111,12 +111,6 @@ public static JSONObject getCachedSongsPlaylist() throws JSONException { public static JSONArray getCachedPlaylistsIds() { JSONArray arr = new JSONArray(); - if (NetworkUtils.isNetworkConnected() && - !PlaylistCacheDbDelegate.isPlaylistEmpty( - AccountManagerUtils.getUserId(), -1)) { - arr.put(AccountManagerUtils.getUserId() + "_-1"); - } - for (String playlist : PlaylistCacheDbDelegate.getAllPlaylistIds()) { arr.put(playlist); } diff --git a/app/src/main/java/ru/vtosters/lite/music/cache/helpers/TracklistHelper.java b/app/src/main/java/ru/vtosters/lite/music/cache/helpers/TracklistHelper.java index fa730052d..2392e06d1 100644 --- a/app/src/main/java/ru/vtosters/lite/music/cache/helpers/TracklistHelper.java +++ b/app/src/main/java/ru/vtosters/lite/music/cache/helpers/TracklistHelper.java @@ -3,11 +3,14 @@ import android.util.Log; import bruhcollective.itaysonlab.libvkx.client.LibVKXClient; import com.vk.dto.music.MusicTrack; +import com.vk.dto.music.Playlist; + import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import ru.vtosters.hooks.other.Preferences; import ru.vtosters.lite.music.cache.MusicCacheImpl; +import ru.vtosters.lite.utils.AccountManagerUtils; import ru.vtosters.lite.utils.music.MusicCacheStorageUtils; import java.io.File; @@ -19,17 +22,22 @@ public class TracklistHelper { public static List getTracks() { - List tracks = MusicCacheImpl.getAllOwnTracks(); + Playlist playlist = MusicCacheImpl + .getPlaylist(AccountManagerUtils.getUserId(), -1); - if (!Preferences.getBoolValue("invertCachedTracks", false)) { - Collections.reverse(tracks); - } - return tracks; + if (playlist != null) { + List tracks = playlist.R; + if (!Preferences.getBoolValue("invertCachedTracks", false)) { + Collections.reverse(tracks); + } + return tracks; + } + return List.of(); } public static List getMyCachedMusicTracks() { - return getTracksWithThumbnails(getTracks()); + return getTracks(); } public static List getTracksWithThumbnails(List tracks) { diff --git a/app/src/main/java/ru/vtosters/lite/music/downloader/CachedDownloader.java b/app/src/main/java/ru/vtosters/lite/music/downloader/CachedDownloader.java index 550fd909a..a51ee20c1 100644 --- a/app/src/main/java/ru/vtosters/lite/music/downloader/CachedDownloader.java +++ b/app/src/main/java/ru/vtosters/lite/music/downloader/CachedDownloader.java @@ -1,23 +1,30 @@ package ru.vtosters.lite.music.downloader; +import android.database.sqlite.SQLiteDatabase; + import com.vk.dto.music.MusicTrack; import com.vk.dto.music.Playlist; + +import ru.vtosters.lite.music.cache.DatabaseAccess; import ru.vtosters.lite.music.cache.db.Database; import ru.vtosters.lite.music.cache.db.MusicCacheDb; import ru.vtosters.lite.music.cache.db.SqlPlaylists; import ru.vtosters.lite.music.interfaces.Callback; import ru.vtosters.lite.music.interfaces.IDownloader; +import ru.vtosters.lite.music.interfaces.IPlaylist; +import ru.vtosters.lite.music.interfaces.IPlaylists; import java.io.File; import java.io.IOException; public final class CachedDownloader implements IDownloader { + private final File to; - private final Playlist playlist; + private final IPlaylist playlist; private final Callback callback; public CachedDownloader(File to, - Playlist playlist, + IPlaylist playlist, Callback callback) { this.to = to; this.playlist = playlist; @@ -37,9 +44,8 @@ public void onSuccess() { try (Database database = new Database()) { new ThumbnailTrackDownloader().download(track); new MusicCacheDb(database).addTrack(track); - new SqlPlaylists(database) - .playlist(playlist.b, playlist.a) - .ifPresent(playlist -> playlist.addTrack(track.y1())); + playlist.addTrack(track.y1()); + callback.onSuccess(); } catch (IOException e) { callback.onFailure(e); diff --git a/app/src/main/java/ru/vtosters/lite/music/downloader/PlaylistDownloader.java b/app/src/main/java/ru/vtosters/lite/music/downloader/PlaylistDownloader.java index 48ebe7ea6..165ed9427 100644 --- a/app/src/main/java/ru/vtosters/lite/music/downloader/PlaylistDownloader.java +++ b/app/src/main/java/ru/vtosters/lite/music/downloader/PlaylistDownloader.java @@ -3,14 +3,18 @@ import android.util.Log; import com.vk.dto.music.MusicTrack; import com.vk.dto.music.Playlist; + +import ru.vtosters.lite.music.cache.delegate.PlaylistCacheDbDelegate; import ru.vtosters.lite.music.interfaces.Callback; +import ru.vtosters.lite.music.interfaces.IPlaylist; import java.io.File; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; public class PlaylistDownloader { - public static void downloadPlaylist(List playlist, String playlistName, String path, Callback callback) { + public static void downloadPlaylist(List playlist, + String path, Callback callback) { var outDir = new File(path); if (!outDir.exists()) if (outDir.mkdirs()) Log.v("PlaylistDownloader", "Directory created"); @@ -20,10 +24,12 @@ public static void downloadPlaylist(List playlist, String playlistNa playlist.forEach(track -> TrackDownloader.downloadTrack(track, path, delegate)); } - public static void cachePlaylist(List playlist, Callback callback, Playlist playlistId) { + public static void cachePlaylist(List playlist, + Callback callback, Playlist playlistId) { Callback delegate = new ProgressCallback(callback); - playlist.forEach(track -> TrackDownloader.cacheTrack(track, delegate, playlistId)); + IPlaylist play = PlaylistCacheDbDelegate.getOrCreatePlaylist(playlistId); + playlist.forEach(track -> TrackDownloader.cacheTrack(track, delegate, play)); } public static final class ProgressCallback implements Callback { diff --git a/app/src/main/java/ru/vtosters/lite/music/downloader/TrackDownloader.java b/app/src/main/java/ru/vtosters/lite/music/downloader/TrackDownloader.java index 26e43d8b2..698330810 100644 --- a/app/src/main/java/ru/vtosters/lite/music/downloader/TrackDownloader.java +++ b/app/src/main/java/ru/vtosters/lite/music/downloader/TrackDownloader.java @@ -5,7 +5,9 @@ import com.vk.dto.music.MusicTrack; import com.vk.dto.music.Playlist; import ru.vtosters.lite.music.cache.MusicCacheImpl; +import ru.vtosters.lite.music.cache.db.Database; import ru.vtosters.lite.music.interfaces.Callback; +import ru.vtosters.lite.music.interfaces.IPlaylist; import ru.vtosters.lite.utils.IOUtils; import ru.vtosters.lite.utils.music.MusicCacheStorageUtils; import ru.vtosters.lite.utils.music.MusicTrackUtils; @@ -34,7 +36,7 @@ public static void downloadTrack(MusicTrack track, String path, Callback callbac ).download(track); } - public static void cacheTrack(MusicTrack track, Callback callback, Playlist playlist) { + public static void cacheTrack(MusicTrack track, Callback callback, IPlaylist playlist) { if (MusicCacheImpl.isCachedTrack(LibVKXClient.asId(track))) { return; } diff --git a/app/src/main/java/ru/vtosters/lite/music/downloader/playlist/ParallelDownloadPlaylist.java b/app/src/main/java/ru/vtosters/lite/music/downloader/playlist/ParallelDownloadPlaylist.java index 2ca99fd06..65b715e00 100644 --- a/app/src/main/java/ru/vtosters/lite/music/downloader/playlist/ParallelDownloadPlaylist.java +++ b/app/src/main/java/ru/vtosters/lite/music/downloader/playlist/ParallelDownloadPlaylist.java @@ -1,5 +1,7 @@ package ru.vtosters.lite.music.downloader.playlist; +import android.database.sqlite.SQLiteDatabase; + import com.vk.dto.music.MusicTrack; import com.vk.dto.music.Playlist; diff --git a/app/src/main/java/ru/vtosters/lite/music/interfaces/IPlaylists.java b/app/src/main/java/ru/vtosters/lite/music/interfaces/IPlaylists.java index 72dc906d0..9d0f113ec 100644 --- a/app/src/main/java/ru/vtosters/lite/music/interfaces/IPlaylists.java +++ b/app/src/main/java/ru/vtosters/lite/music/interfaces/IPlaylists.java @@ -30,6 +30,14 @@ default boolean isEmpty() { } + default IPlaylist insertIfAbsent(Playlist playlist) { + + return playlist(playlist.b, playlist.a).orElseGet(() -> { + addPlaylist(playlist); + + return insertIfAbsent(playlist); + }); + } default Optional playlist(int ownerId, int id) { return Optional.ofNullable(playlists(ownerId).get(id)); }