From 502ccca61b802d7df2d3f6e4bae22ed3b1483805 Mon Sep 17 00:00:00 2001 From: sunmisc Date: Thu, 5 Sep 2024 20:15:24 +0300 Subject: [PATCH] updated --- .../vk/music/e/MusicCatalogConfiguration.java | 98 +++++++ .../hooks/music/MusicBottomSheetHook.java | 9 +- .../hooks/music/MusicCacheFilesHook.java | 2 +- .../hooks/music/PlaylistFormatterHook.java | 2 +- .../music/injectors/CatalogJsonInjector.java | 2 +- .../music/injectors/PlaylistInjector.java | 10 +- .../music/injectors/ShuffleInjector.java | 5 +- .../music/injectors/TracklistInjector.java | 64 ++--- .../lite/downloaders/AudioDownloader.java | 2 +- .../vtosters/lite/music/LastFMScrobbler.java | 2 +- .../lite/music/cache/db/Constants.java | 5 + .../lite/music/cache/db/Database.java | 4 +- .../music/cache/{ => db}/DatabaseAccess.java | 2 +- .../lite/music/cache/db/LazyDatabase.java | 41 +++ .../music/cache/db/old/OldMusicCacheDb.java | 4 +- .../cache/{ => delegate}/MusicCacheImpl.java | 37 ++- .../delegate/PlaylistCacheDbDelegate.java | 25 +- .../music/cache/helpers/PlaylistHelper.java | 39 ++- .../music/cache/helpers/TracklistHelper.java | 38 +-- .../cache/{db => playlists}/MusicCacheDb.java | 5 +- .../cache/{db => playlists}/SqlPlaylist.java | 36 ++- .../cache/{db => playlists}/SqlPlaylists.java | 13 +- .../music/downloader/CachedDownloader.java | 8 +- .../music/downloader/TrackDownloader.java | 5 +- .../playlist/ParallelDownloadPlaylist.java | 30 +-- .../lite/music/interfaces/IPlaylists.java | 5 +- .../lite/ui/fragments/MusicFragment.java | 26 +- .../lite/utils/lazy/CachingSupplier.java | 73 ++++++ .../ru/vtosters/lite/utils/lazy/Lazy.java | 7 + .../music/e/MusicCatalogConfiguration.smali | 244 ------------------ 30 files changed, 412 insertions(+), 431 deletions(-) create mode 100644 app/src/main/java/com/vk/music/e/MusicCatalogConfiguration.java rename app/src/main/java/ru/vtosters/lite/music/cache/{ => db}/DatabaseAccess.java (84%) create mode 100644 app/src/main/java/ru/vtosters/lite/music/cache/db/LazyDatabase.java rename app/src/main/java/ru/vtosters/lite/music/cache/{ => delegate}/MusicCacheImpl.java (75%) rename app/src/main/java/ru/vtosters/lite/music/cache/{db => playlists}/MusicCacheDb.java (97%) rename app/src/main/java/ru/vtosters/lite/music/cache/{db => playlists}/SqlPlaylist.java (83%) rename app/src/main/java/ru/vtosters/lite/music/cache/{db => playlists}/SqlPlaylists.java (94%) create mode 100644 app/src/main/java/ru/vtosters/lite/utils/lazy/CachingSupplier.java create mode 100644 app/src/main/java/ru/vtosters/lite/utils/lazy/Lazy.java delete mode 100644 smali/smali_classes3/com/vk/music/e/MusicCatalogConfiguration.smali diff --git a/app/src/main/java/com/vk/music/e/MusicCatalogConfiguration.java b/app/src/main/java/com/vk/music/e/MusicCatalogConfiguration.java new file mode 100644 index 000000000..3c3b112b4 --- /dev/null +++ b/app/src/main/java/com/vk/music/e/MusicCatalogConfiguration.java @@ -0,0 +1,98 @@ +package com.vk.music.e; + +import android.os.Bundle; + +import com.vk.catalog2.core.CatalogEntryPointParams; +import com.vk.catalog2.core.VkCatalogConfiguration; +import com.vk.catalog2.core.api.dto.CatalogCatalog; +import com.vk.catalog2.core.api.dto.CatalogDataType; +import com.vk.catalog2.core.api.dto.CatalogResponse; +import com.vk.catalog2.core.api.dto.CatalogViewType; +import com.vk.catalog2.core.api.music.CatalogGetAudio; +import com.vk.catalog2.core.blocks.UIBlock; +import com.vk.catalog2.core.blocks.UIBlockButtons; +import com.vk.catalog2.core.holders.common.CatalogViewHolder; +import com.vk.catalog2.core.holders.music.MusicActionButtonVh; +import com.vk.catalog2.core.ui.j.CatalogRecyclerGridOffsetsItemDecorator; +import com.vk.catalog2.core.ui.j.CatalogRecyclerHorizontalOffsetsItemDecorator; +import com.vk.catalog2.core.ui.j.CatalogRecyclerVerticalOffsetsItemDecorator; + +import io.reactivex.Observable; +import ru.vtosters.hooks.music.injectors.TracklistInjector; + +public final class MusicCatalogConfiguration extends VkCatalogConfiguration { + + private final String url; + + public MusicCatalogConfiguration(int i, String str, String str2) { + super(i, str); + this.url = str2; + } + + public MusicCatalogConfiguration(Bundle paramBundle) { + this(paramBundle.getInt("owner_id"), paramBundle.getString("ref"), paramBundle.getString("url")); + } + @Override + public CatalogRecyclerHorizontalOffsetsItemDecorator c() { + return super.c(); + } + @Override + public CatalogRecyclerGridOffsetsItemDecorator f() { + return super.f(); + } + @Override + public CatalogRecyclerVerticalOffsetsItemDecorator i() { + return super.i(); + } + + + @Override + public CatalogViewHolder a(CatalogDataType var1, CatalogViewType var2, + UIBlock var3, CatalogEntryPointParams var4) { + if (var3 instanceof UIBlockButtons && var3.z1() == CatalogViewType.BUTTONS_HORIZONTAL && + ((UIBlockButtons)var3).B1().size() != 1) { + CatalogViewHolder var6; + if (com.vk.music.e.c.$EnumSwitchMapping$1[(var1).ordinal()] != 1) { + var6 = super.a(var1, var2, var3, var4); + } else { + int var5 = com.vk.music.e.c.$EnumSwitchMapping$0[(var2).ordinal()]; + if (var5 != 1) { + if (var5 != 2) { + var6 = super.a(var1, var2, var3, var4); + } else { + var6 = new MusicActionButtonVh( + com.vtosters.lite.R.drawable.ic_shuffle_outline_28, + com.vtosters.lite.R.layout.catalog_action_horizontal_list_music, + com.vtosters.lite.R.string.audio_shuffle_all, + var4.k() + ); + } + } else { + var6 = new MusicActionButtonVh(com.vtosters.lite.R.drawable.ic_play_28, + com.vtosters.lite.R.layout.catalog_action_horizontal_list_music, + com.vtosters.lite.R.string.music_artist_listen_all_btn, + var4.k()); + } + } + + return var6; + } else { + return super.a(var1, var2, var3, var4); + } + } + + + @Override + public Bundle e() { + Bundle e = super.e(); + e.putString("url", this.url); + return e; + } + @Override + public Observable> a(int paramInt, String paramString) { + + return TracklistInjector.eligibleForOfflineCaching() + ? TracklistInjector.createOfflineRx(j()) + : new CatalogGetAudio(j(), paramInt, paramString, this.url).m(); + } +} \ No newline at end of file diff --git a/app/src/main/java/ru/vtosters/hooks/music/MusicBottomSheetHook.java b/app/src/main/java/ru/vtosters/hooks/music/MusicBottomSheetHook.java index fdcc2c263..a4a709335 100644 --- a/app/src/main/java/ru/vtosters/hooks/music/MusicBottomSheetHook.java +++ b/app/src/main/java/ru/vtosters/hooks/music/MusicBottomSheetHook.java @@ -8,7 +8,7 @@ import com.vk.music.common.MusicPlaybackLaunchContext; import com.vtosters.lite.R; import ru.vtosters.lite.downloaders.AudioDownloader; -import ru.vtosters.lite.music.cache.MusicCacheImpl; +import ru.vtosters.lite.music.cache.delegate.MusicCacheImpl; import ru.vtosters.lite.music.cache.delegate.PlaylistCacheDbDelegate; import ru.vtosters.lite.utils.AndroidUtils; import ru.vtosters.lite.utils.music.VKXUtils; @@ -97,7 +97,10 @@ public static ArrayList hook(ArrayList actions, Playli return actions; } - public static boolean injectOnClick(int actionId, MusicTrack track, MusicPlaybackLaunchContext context, Playlist playlist) { // musictrack inj + public static boolean injectOnClick(int actionId, MusicTrack track, + MusicPlaybackLaunchContext context, + + Playlist playlist) { // musictrack inj if (actionId == R.id.play_in_vkx) return tryPlayInVKX(track, context, playlist); @@ -122,7 +125,7 @@ public static boolean injectOnClick(int actionId, MusicTrack track, MusicPlaybac } if (actionId == R.id.remove_from_cache) { - MusicCacheImpl.removeTrack(asId(track)); + MusicCacheImpl.removeTrack(playlist.b, playlist.a, asId(track)); AndroidUtils.sendToast(AndroidUtils.getString("audio_deleted_from_cache")); return true; } else if (actionId == R.id.add_to_cache) { diff --git a/app/src/main/java/ru/vtosters/hooks/music/MusicCacheFilesHook.java b/app/src/main/java/ru/vtosters/hooks/music/MusicCacheFilesHook.java index cc550f604..f015e59e9 100644 --- a/app/src/main/java/ru/vtosters/hooks/music/MusicCacheFilesHook.java +++ b/app/src/main/java/ru/vtosters/hooks/music/MusicCacheFilesHook.java @@ -1,6 +1,6 @@ package ru.vtosters.hooks.music; -import ru.vtosters.lite.music.cache.MusicCacheImpl; +import ru.vtosters.lite.music.cache.delegate.MusicCacheImpl; import ru.vtosters.lite.utils.music.MusicCacheStorageUtils; import java.io.File; diff --git a/app/src/main/java/ru/vtosters/hooks/music/PlaylistFormatterHook.java b/app/src/main/java/ru/vtosters/hooks/music/PlaylistFormatterHook.java index 774f878ef..93f1056b2 100644 --- a/app/src/main/java/ru/vtosters/hooks/music/PlaylistFormatterHook.java +++ b/app/src/main/java/ru/vtosters/hooks/music/PlaylistFormatterHook.java @@ -12,7 +12,7 @@ public class PlaylistFormatterHook { // basically we replace the author name with subtitle // because for some reason VK decided to merge title and subtitle into one field in 5.56 public static String getOwnerText(Context context, Playlist playlist) { - if (playlist.h != null && playlist.h.length() > 0) { + if (playlist.h != null && !playlist.h.isEmpty()) { return playlist.h; } String string = context.getString(com.vk.music.m.i.music_my_playlist); diff --git a/app/src/main/java/ru/vtosters/hooks/music/injectors/CatalogJsonInjector.java b/app/src/main/java/ru/vtosters/hooks/music/injectors/CatalogJsonInjector.java index 80cb8f497..efab1b51e 100644 --- a/app/src/main/java/ru/vtosters/hooks/music/injectors/CatalogJsonInjector.java +++ b/app/src/main/java/ru/vtosters/hooks/music/injectors/CatalogJsonInjector.java @@ -10,7 +10,7 @@ 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.music.cache.delegate.MusicCacheImpl; import ru.vtosters.lite.music.cache.helpers.PlaylistHelper; import ru.vtosters.lite.utils.AccountManagerUtils; import ru.vtosters.lite.utils.AndroidUtils; 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 58a1638ce..d234eaf3b 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 @@ -13,9 +13,8 @@ import org.json.JSONException; import org.json.JSONObject; import ru.vtosters.lite.downloaders.AudioDownloader; -import ru.vtosters.lite.music.cache.MusicCacheImpl; +import ru.vtosters.lite.music.cache.delegate.MusicCacheImpl; import ru.vtosters.lite.music.cache.helpers.PlaylistHelper; -import ru.vtosters.lite.music.cache.helpers.TracklistHelper; import ru.vtosters.lite.utils.AccountManagerUtils; import java.util.ArrayList; @@ -37,7 +36,8 @@ private static boolean isCacheEmpty() { } private static boolean isVirtualPlaylist(String accessKey) { - return accessKey != null && (accessKey.equals("cache") || accessKey.equals("cacheAlbum")); + return accessKey != null && (accessKey.equals("cache") || + accessKey.equals("cacheAlbum")); } private static boolean isAlbumVirtualPlaylist(String accessKey) { @@ -101,10 +101,6 @@ private static Observable handleMusicCacheImpl(int id, int o // Main method to inject the playlist public static Observable injectGetPlaylist(AudioGetPlaylist audioGetPlaylist) { - if (isCacheEmpty()) { - return null; - } - Map requestArgs = audioGetPlaylist.b(); String id = requestArgs.get("id"); String ownerId = requestArgs.get("owner_id"); diff --git a/app/src/main/java/ru/vtosters/hooks/music/injectors/ShuffleInjector.java b/app/src/main/java/ru/vtosters/hooks/music/injectors/ShuffleInjector.java index 32d506aca..5b273a400 100644 --- a/app/src/main/java/ru/vtosters/hooks/music/injectors/ShuffleInjector.java +++ b/app/src/main/java/ru/vtosters/hooks/music/injectors/ShuffleInjector.java @@ -5,6 +5,7 @@ import com.vk.music.model.PlayerModelImpl; import ru.vtosters.lite.music.cache.helpers.TracklistHelper; +import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -18,7 +19,9 @@ public static void shuffleTracks(PlayerModelImpl playerModelImpl) { } private static List getShuffledList() { - List shuffled = TracklistHelper.getMyCachedMusicTracks(); + List shuffled = new ArrayList<>( + TracklistHelper.getTracks() + ); Collections.shuffle(shuffled); return shuffled; } diff --git a/app/src/main/java/ru/vtosters/hooks/music/injectors/TracklistInjector.java b/app/src/main/java/ru/vtosters/hooks/music/injectors/TracklistInjector.java index d151eb6cb..b56c6fc41 100644 --- a/app/src/main/java/ru/vtosters/hooks/music/injectors/TracklistInjector.java +++ b/app/src/main/java/ru/vtosters/hooks/music/injectors/TracklistInjector.java @@ -3,7 +3,9 @@ import android.util.Log; import bruhcollective.itaysonlab.libvkx.client.LibVKXClient; import com.vk.catalog2.core.CatalogParser; +import com.vk.catalog2.core.api.dto.CatalogCatalog; import com.vk.catalog2.core.api.dto.CatalogResponse; +import com.vk.core.concurrent.VkExecutors; import com.vk.dto.music.MusicTrack; import com.vtosters.lite.R; import io.reactivex.Observable; @@ -11,7 +13,9 @@ import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; -import ru.vtosters.lite.music.cache.MusicCacheImpl; + +import io.reactivex.schedulers.AndroidSchedulers; +import ru.vtosters.lite.music.cache.delegate.MusicCacheImpl; import ru.vtosters.lite.music.cache.delegate.PlaylistCacheDbDelegate; import ru.vtosters.lite.music.cache.helpers.PlaylistHelper; import ru.vtosters.lite.music.cache.helpers.TracklistHelper; @@ -19,9 +23,9 @@ import ru.vtosters.lite.utils.AndroidUtils; import ru.vtosters.lite.utils.NetworkUtils; -import java.util.ArrayList; import java.util.List; import java.util.UUID; +import java.util.stream.Collectors; import static ru.vtosters.lite.music.cache.helpers.PlaylistHelper.*; @@ -31,41 +35,32 @@ public static boolean eligibleForOfflineCaching() { return !NetworkUtils.isNetworkConnected(); } - public static Observable createOfflineRx(CatalogParser parser) { + public static Observable> + createOfflineRx(CatalogParser parser) { Log.d("TracklistInjector", "createOfflineRx"); - return Observable.a((ObservableOnSubscribe) observableEmitter -> { + return Observable.a((ObservableOnSubscribe) observer -> { if (LibVKXClient.isIntegrationEnabled()) { - LibVKXClient.getInstance().runOnService((service) -> { + LibVKXClient.getInstance().runOnService(service -> { try { - try { - Log.d("TracklistInjector", "Using vkx cache catalog"); - observableEmitter.b(parser.c(new JSONObject(service.getCacheCatalog()))); - } catch (Exception e) { - e.fillInStackTrace(); - List tracks = new ArrayList<>(); - List cache = service.getCache(); - - for (String json : cache) { - Log.d("TracklistInjector", "added " + json); - tracks.add(new MusicTrack(new JSONObject(json))); - } - - Log.d("TracklistInjector", "Using own cache catalog from vkx"); - observableEmitter.b(parser.c(createVirtualCatalog(tracks))); - } + Log.d("TracklistInjector", "Using vkx cache catalog"); + observer.b(parser.c(new JSONObject(service.getCacheCatalog()))); } catch (Exception e) { e.fillInStackTrace(); } }); - } else { - if (MusicCacheImpl.isEmpty()) { - observableEmitter.b(parser.c(getEmptyCatalog())); - } else { - observableEmitter.b(parser.c(createVirtualCatalog(TracklistHelper.getMyCachedMusicTracks()))); - } } - }); + observer.b(parser.c( + createVirtualCatalog( + MusicCacheImpl.getPlaylistSongs( + AccountManagerUtils.getUserId(), + -1, + // todo: + 0, Integer.MAX_VALUE + ) + )) + ); + }).b(VkExecutors.x.m()).a(AndroidSchedulers.a()); } private static JSONObject getEmptyCatalog() throws JSONException { @@ -151,6 +146,7 @@ private static JSONObject getShuffleButton() throws JSONException { public static void injectIntoExistingCatalog(JSONObject catalogNode) { try { + System.out.println("kasdkakdakdk ak "+catalogNode.toString()); JSONObject catalog = catalogNode.getJSONObject("catalog"); JSONArray sectionsNode = catalog.getJSONArray("sections"); JSONObject firstSection = sectionsNode.getJSONObject(0); @@ -231,7 +227,12 @@ public static JSONObject createVirtualCatalog(List tracks) throws JS .put("id", getRandomId()) .put("data_type", "music_audios") .put("url", "synth:cache:list") - .put("audios_ids", TracklistHelper.tracksToIds(tracks)); + .put("audio_count", "4") + .put("audios_ids", new JSONArray( + tracks.stream() + .map(MusicTrack::y1) + .collect(Collectors.toList())) + ); var layout = new JSONObject() .put("name", "list") @@ -243,7 +244,7 @@ public static JSONObject createVirtualCatalog(List tracks) throws JS if (MusicCacheImpl.hasPlaylist()) { blocks.put(getCatalogHeader("Кешированные плейлисты")) - .put(getCatalogPlaylist()); + .put(getCatalogPlaylist0()); } if (!PlaylistCacheDbDelegate.isPlaylistEmpty( @@ -262,8 +263,7 @@ public static JSONObject createVirtualCatalog(List tracks) throws JS .put("url", "synth:cache") .put("blocks", blocks); - var sections = new JSONArray() - .put(section); + var sections = new JSONArray().put(section); var catalog = new JSONObject() .put("sections", sections) 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 f7cbde694..399f1d195 100644 --- a/app/src/main/java/ru/vtosters/lite/downloaders/AudioDownloader.java +++ b/app/src/main/java/ru/vtosters/lite/downloaders/AudioDownloader.java @@ -12,7 +12,7 @@ import ru.vtosters.hooks.music.MusicCacheFilesHook; import ru.vtosters.hooks.other.Preferences; import ru.vtosters.lite.concurrent.VTExecutors; -import ru.vtosters.lite.music.cache.MusicCacheImpl; +import ru.vtosters.lite.music.cache.delegate.MusicCacheImpl; import ru.vtosters.lite.music.cache.delegate.PlaylistCacheDbDelegate; import ru.vtosters.lite.music.cache.helpers.PlaylistHelper; import ru.vtosters.lite.music.callback.MusicCallbackBuilder; diff --git a/app/src/main/java/ru/vtosters/lite/music/LastFMScrobbler.java b/app/src/main/java/ru/vtosters/lite/music/LastFMScrobbler.java index e22dc01c5..f79a769c8 100644 --- a/app/src/main/java/ru/vtosters/lite/music/LastFMScrobbler.java +++ b/app/src/main/java/ru/vtosters/lite/music/LastFMScrobbler.java @@ -13,7 +13,7 @@ import ru.vtosters.hooks.other.Preferences; import ru.vtosters.lite.di.singleton.VtOkHttpClient; import ru.vtosters.lite.downloaders.AudioDownloader; -import ru.vtosters.lite.music.cache.MusicCacheImpl; +import ru.vtosters.lite.music.cache.delegate.MusicCacheImpl; import ru.vtosters.lite.utils.AccountManagerUtils; import ru.vtosters.lite.utils.AndroidUtils; import ru.vtosters.lite.utils.music.MusicTrackUtils; 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 8790fb4df..258e210d7 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 @@ -63,6 +63,11 @@ public interface Constants { + "REFERENCES " + TABLE_MUSICS + "(" + TRACK_ID + ") " + "ON DELETE CASCADE" + ")"; + String DELETE_DEAD = "DELETE FROM " + TABLE_MUSICS + + " WHERE "+TRACK_ID+" NOT IN (" + + " SELECT " + TABLE_PLAYLIST_TRACKS + "." + TRACK_ID + + " FROM " + TABLE_PLAYLIST_TRACKS + + ");"; String DROP_MUSICS = "DROP TABLE IF EXISTS " + TABLE_MUSICS; String DROP_PLAYLIST = "DROP TABLE IF EXISTS " + TABLE_PLAYLIST; 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 79009c2f7..23eff8e2b 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 @@ -7,10 +7,11 @@ 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.cache.playlists.MusicCacheDb; +import ru.vtosters.lite.music.cache.playlists.SqlPlaylists; import ru.vtosters.lite.music.interfaces.IPlaylist; import ru.vtosters.lite.utils.AccountManagerUtils; import ru.vtosters.lite.utils.AndroidUtils; @@ -34,7 +35,6 @@ 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 diff --git a/app/src/main/java/ru/vtosters/lite/music/cache/DatabaseAccess.java b/app/src/main/java/ru/vtosters/lite/music/cache/db/DatabaseAccess.java similarity index 84% rename from app/src/main/java/ru/vtosters/lite/music/cache/DatabaseAccess.java rename to app/src/main/java/ru/vtosters/lite/music/cache/db/DatabaseAccess.java index adcd843fd..f53031893 100644 --- a/app/src/main/java/ru/vtosters/lite/music/cache/DatabaseAccess.java +++ b/app/src/main/java/ru/vtosters/lite/music/cache/db/DatabaseAccess.java @@ -1,4 +1,4 @@ -package ru.vtosters.lite.music.cache; +package ru.vtosters.lite.music.cache.db; import android.database.sqlite.SQLiteDatabase; diff --git a/app/src/main/java/ru/vtosters/lite/music/cache/db/LazyDatabase.java b/app/src/main/java/ru/vtosters/lite/music/cache/db/LazyDatabase.java new file mode 100644 index 000000000..ff901268f --- /dev/null +++ b/app/src/main/java/ru/vtosters/lite/music/cache/db/LazyDatabase.java @@ -0,0 +1,41 @@ +package ru.vtosters.lite.music.cache.db; + +import android.database.sqlite.SQLiteDatabase; + +import java.io.IOException; + +import ru.vtosters.lite.utils.lazy.CachingSupplier; +import ru.vtosters.lite.utils.lazy.Lazy; + + +public final class LazyDatabase implements DatabaseAccess { + + private final DatabaseAccess origin; + private final Lazy readable, writable; + + + public LazyDatabase(DatabaseAccess origin) { + this.origin = origin; + this.readable = new CachingSupplier<>( + origin::getReadableDatabase + ); + this.writable = new CachingSupplier<>( + origin::getWritableDatabase + ); + } + + @Override + public SQLiteDatabase getReadableDatabase() { + return readable.get(); + } + + @Override + public SQLiteDatabase getWritableDatabase() { + return writable.get(); + } + + @Override + public void close() throws IOException { + origin.close(); + } +} 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 8517d86bf..8e8142402 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 @@ -8,8 +8,7 @@ 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; @@ -19,7 +18,6 @@ import java.net.URLDecoder; import java.util.ArrayList; import java.util.List; -import java.util.Optional; /** *

Note: the {@link AutoCloseable} interface was diff --git a/app/src/main/java/ru/vtosters/lite/music/cache/MusicCacheImpl.java b/app/src/main/java/ru/vtosters/lite/music/cache/delegate/MusicCacheImpl.java similarity index 75% rename from app/src/main/java/ru/vtosters/lite/music/cache/MusicCacheImpl.java rename to app/src/main/java/ru/vtosters/lite/music/cache/delegate/MusicCacheImpl.java index 278fd4871..052937001 100644 --- a/app/src/main/java/ru/vtosters/lite/music/cache/MusicCacheImpl.java +++ b/app/src/main/java/ru/vtosters/lite/music/cache/delegate/MusicCacheImpl.java @@ -1,7 +1,6 @@ -package ru.vtosters.lite.music.cache; +package ru.vtosters.lite.music.cache.delegate; import android.content.Context; -import android.database.sqlite.SQLiteDatabase; import android.os.RemoteException; import bruhcollective.itaysonlab.libvkx.ILibVkxService; import bruhcollective.itaysonlab.libvkx.client.LibVKXClient; @@ -10,9 +9,10 @@ import com.vk.dto.music.Playlist; import ru.vtosters.lite.music.cache.db.Constants; 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.cache.delegate.PlaylistCacheDbDelegate; +import ru.vtosters.lite.music.cache.db.DatabaseAccess; +import ru.vtosters.lite.music.cache.db.LazyDatabase; +import ru.vtosters.lite.music.cache.playlists.MusicCacheDb; +import ru.vtosters.lite.music.cache.playlists.SqlPlaylists; import ru.vtosters.lite.music.interfaces.IPlaylist; import ru.vtosters.lite.music.interfaces.IPlaylists; import ru.vtosters.lite.utils.AccountManagerUtils; @@ -25,11 +25,25 @@ @SuppressWarnings("forRemoval") public class MusicCacheImpl { - private static final Database connection = - new Database(); + static final DatabaseAccess connection = + new LazyDatabase( + new Database() + ); + static final MusicCacheDb musics = new MusicCacheDb(connection); + static final IPlaylists playlists = new SqlPlaylists(connection); - private static final MusicCacheDb musics = new MusicCacheDb(connection); - private static final IPlaylists playlists = new SqlPlaylists(connection); + + public static void removeTrack(int owner_id, int playlist_id, + String trackId) { + playlists.playlist(owner_id, playlist_id) + .ifPresent(iPlaylist -> { + iPlaylist.removeTrack(trackId); + + if (!musics.getTrackById(trackId).isPresent()) { + MusicCacheStorageUtils.removeTrackDirById(trackId); + } + }); + } public static void removeTrack(String trackId) { @@ -60,11 +74,6 @@ public static Optional getTrackById(String trackId) { } - public static List getPlaylists() { - return PlaylistCacheDbDelegate.getAllPlaylists(); - } - - public static boolean hasPlaylist() { return !PlaylistCacheDbDelegate.isPlaylistsDbEmpty(); // has playlists or not } 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 a4537976b..a3b3ec4ca 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,11 +1,13 @@ package ru.vtosters.lite.music.cache.delegate; +import static ru.vtosters.lite.music.cache.delegate.MusicCacheImpl.playlists; + 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; -import ru.vtosters.lite.music.cache.db.SqlPlaylists; +import ru.vtosters.lite.music.cache.playlists.SqlPlaylists; import ru.vtosters.lite.music.interfaces.IPlaylist; import java.util.List; @@ -14,57 +16,54 @@ @SuppressWarnings("forRemoval") public class PlaylistCacheDbDelegate { - public static final Database connection = new Database(); public static IPlaylist getOrCreatePlaylist(Playlist playlist) { - return new SqlPlaylists(connection).insertIfAbsent(playlist); + return playlists.insertIfAbsent(playlist); } public static void deletePlaylist(int id, int ownerId) { - new SqlPlaylists(connection).deletePlaylist(ownerId, id); + playlists.deletePlaylist(ownerId, id); } public static long getTracksCountInPlaylist(int ownerId, int id) { - return new SqlPlaylists(connection).playlist(ownerId, id) + return playlists.playlist(ownerId, id) .map(IPlaylist::count) .orElse(0); } public static boolean isPlaylistsDbEmpty() { - return new SqlPlaylists(connection).isEmpty(); + return playlists.isEmpty(); } public static void removeAllPlaylists() { - new SqlPlaylists(connection).deleteAll(); + playlists.deleteAll(); } public static List getAllPlaylistIds() { - return new SqlPlaylists(connection).playlists() - .stream() + return playlists.playlists() .map(x -> x.ownerId() + "_" + x.id()) .collect(Collectors.toList()); } public static boolean isCachedPlaylist(int ownerId, int id) { - return new SqlPlaylists(connection).playlist(ownerId, id).isPresent(); + return playlists.playlist(ownerId, id).isPresent(); } public static List getAllPlaylists() { - return new SqlPlaylists(connection).playlists() - .stream() + return playlists.playlists() .map(IPlaylist::toPlaylist) .collect(Collectors.toList()); } public static boolean isPlaylistEmpty(int ownerId, int id) { - return new SqlPlaylists(connection).playlist(ownerId, id) + return playlists.playlist(ownerId, id) .map(IPlaylist::isEmpty) .orElse(true); } 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 4bfdad48f..22a0c4544 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 @@ -6,11 +6,10 @@ import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; -import ru.vtosters.lite.music.cache.MusicCacheImpl; + import ru.vtosters.lite.music.cache.delegate.PlaylistCacheDbDelegate; import ru.vtosters.lite.utils.AccountManagerUtils; import ru.vtosters.lite.utils.AndroidUtils; -import ru.vtosters.lite.utils.NetworkUtils; import ru.vtosters.lite.utils.music.PlaylistUtils; public class PlaylistHelper { @@ -29,15 +28,13 @@ public static JSONArray addCachedPlaylists(JSONArray jsonArray) { jsonArray.put(getCachedSongsPlaylist()); // TODO remove or do something } - if (MusicCacheImpl.hasPlaylist()) { - for (Playlist playlist : MusicCacheImpl.getPlaylists()) { - jsonArray.put(generatePlaylist(playlist.a, - playlist.b, playlist.C, playlist.g, playlist.B, - playlist.O, - PlaylistUtils.getThumb(playlist))); + for (Playlist playlist : PlaylistCacheDbDelegate.getAllPlaylists()) { + jsonArray.put(generatePlaylist(playlist.a, + playlist.b, playlist.C, playlist.g, playlist.B, + playlist.O, + PlaylistUtils.getThumb(playlist))); - Log.d("PlaylistHelper", "Playlist cache added: " + playlist.a + " " + playlist.b + " " + playlist.C + " " + playlist.g + " " + playlist.B); - } + Log.d("PlaylistHelper", "Playlist cache added: " + playlist.a + " " + playlist.b + " " + playlist.C + " " + playlist.g + " " + playlist.B); } } catch (JSONException e) { e.fillInStackTrace(); @@ -116,6 +113,18 @@ public static JSONArray getCachedPlaylistsIds() { return arr; } + public static JSONArray getCachedPlaylistsIds0() { + JSONArray arr = new JSONArray(); + + for (String playlist : PlaylistCacheDbDelegate.getAllPlaylistIds()) { + if (playlist.equals(AccountManagerUtils.getUserId()+"_-1")) { + continue; + } + arr.put(playlist); + } + + return arr; + } public static JSONObject getCatalogPlaylist() throws JSONException { return new JSONObject() @@ -127,6 +136,16 @@ public static JSONObject getCatalogPlaylist() throws JSONException { .put("owner_id", AccountManagerUtils.getUserId())) .put("playlists_ids", getCachedPlaylistsIds()); } + public static JSONObject getCatalogPlaylist0() throws JSONException { + return new JSONObject() + .put("id", "cache") + .put("data_type", "music_playlists") + .put("layout", new JSONObject() + .put("name", "large_slider") + .put("is_editable", 0) + .put("owner_id", AccountManagerUtils.getUserId())) + .put("playlists_ids", getCachedPlaylistsIds0()); + } public static JSONObject getCatalogHeader(String text) throws JSONException { return new JSONObject() 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 7ba31d074..5ff3dd5a2 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 @@ -9,16 +9,14 @@ 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.music.cache.delegate.MusicCacheImpl; import ru.vtosters.lite.utils.AccountManagerUtils; import ru.vtosters.lite.utils.music.MusicCacheStorageUtils; import java.io.File; import java.net.MalformedURLException; -import java.util.ArrayList; import java.util.Collections; import java.util.List; -import java.util.Optional; public class TracklistHelper { public static List getTracks() { @@ -36,27 +34,6 @@ public static List getTracks() { } } - public static List getMyCachedMusicTracks() { - return getTracks(); - } - - public static List getTracksWithThumbnails(List tracks) { - List tracksWithThumbnails = new ArrayList<>(); - - for (MusicTrack track : tracks) { - try { - JSONObject json = track.J(); - File folder = MusicCacheStorageUtils.getThumbDirById(LibVKXClient.asId(track)); - addCachedThumbnails(json, folder); - tracksWithThumbnails.add(new MusicTrack(json)); - } catch (JSONException | MalformedURLException e) { - Log.d("TracklistHelper", e.getMessage()); - } - } - - return tracksWithThumbnails; - } - private static void addCachedThumbnails(JSONObject target, File thumbnailsDir) throws JSONException, MalformedURLException { var sizes = new JSONArray(); var files = thumbnailsDir.listFiles(); @@ -76,19 +53,6 @@ private static void addCachedThumbnails(JSONObject target, File thumbnailsDir) t } } - public static Optional getTrack(String id) { - return MusicCacheImpl.getTrackById(id); - } - - public static JSONArray tracksToIds(List tracks) { - JSONArray arr = new JSONArray(); - - for (MusicTrack track : tracks) { - arr.put(track.y1()); - } - - return arr; - } public static JSONArray tracksToJsons(List tracks) { JSONArray arr = new JSONArray(); 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/playlists/MusicCacheDb.java similarity index 97% rename from app/src/main/java/ru/vtosters/lite/music/cache/db/MusicCacheDb.java rename to app/src/main/java/ru/vtosters/lite/music/cache/playlists/MusicCacheDb.java index 6be00ad53..469c12264 100644 --- a/app/src/main/java/ru/vtosters/lite/music/cache/db/MusicCacheDb.java +++ b/app/src/main/java/ru/vtosters/lite/music/cache/playlists/MusicCacheDb.java @@ -1,4 +1,4 @@ -package ru.vtosters.lite.music.cache.db; +package ru.vtosters.lite.music.cache.playlists; import android.content.ContentValues; import android.database.Cursor; @@ -11,7 +11,8 @@ import com.vk.dto.music.Thumb; import org.json.JSONObject; -import ru.vtosters.lite.music.cache.DatabaseAccess; +import ru.vtosters.lite.music.cache.db.DatabaseAccess; +import ru.vtosters.lite.music.cache.db.Constants; import ru.vtosters.lite.utils.AndroidUtils; import ru.vtosters.lite.utils.music.MusicCacheStorageUtils; import ru.vtosters.lite.utils.music.MusicTrackUtils; 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/playlists/SqlPlaylist.java similarity index 83% rename from app/src/main/java/ru/vtosters/lite/music/cache/db/SqlPlaylist.java rename to app/src/main/java/ru/vtosters/lite/music/cache/playlists/SqlPlaylist.java index 1ae3a2e82..734f65a89 100644 --- a/app/src/main/java/ru/vtosters/lite/music/cache/db/SqlPlaylist.java +++ b/app/src/main/java/ru/vtosters/lite/music/cache/playlists/SqlPlaylist.java @@ -1,18 +1,18 @@ -package ru.vtosters.lite.music.cache.db; +package ru.vtosters.lite.music.cache.playlists; import android.annotation.SuppressLint; 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.db.DatabaseAccess; +import ru.vtosters.lite.music.cache.delegate.MusicCacheImpl; +import ru.vtosters.lite.music.cache.db.Constants; import ru.vtosters.lite.music.cache.helpers.PlaylistHelper; -import ru.vtosters.lite.music.cache.helpers.TracklistHelper; import ru.vtosters.lite.music.interfaces.IPlaylist; import java.util.ArrayList; @@ -44,7 +44,6 @@ 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); @@ -57,13 +56,24 @@ public void addTrack(String trackId) { @Override public void removeTrack(String trackId) { - sqlite.getReadableDatabase().delete(Constants.TABLE_PLAYLIST_TRACKS, - selection() + " AND " + Constants.TRACK_ID + " = ?", - new String[]{ - Integer.toString(id), - Integer.toString(ownerId), - trackId, - }); + + SQLiteDatabase writable = sqlite.getWritableDatabase(); + + // writable.beginTransaction(); + try { + writable.delete(Constants.TABLE_PLAYLIST_TRACKS, + selection() + " AND " + Constants.TRACK_ID + " = ?", + new String[]{ + Integer.toString(ownerId), + Integer.toString(id), + trackId, + }); + // skip dead + // todo: check + writable.execSQL(Constants.DELETE_DEAD); + } finally { + // writable.endTransaction(); + } } @Override @@ -78,7 +88,7 @@ public List tracks(int offset, int count) { while (cursor.moveToNext()) { @SuppressLint("Range") String trackId = cursor.getString(0); - TracklistHelper.getTrack(trackId).ifPresent(track -> { + MusicCacheImpl.getTrackById(trackId).ifPresent(track -> { tracks.add(track); Log.d("Playlist", "add " + trackId + " to playlist " + ownerId + "_" + id); 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/playlists/SqlPlaylists.java similarity index 94% rename from app/src/main/java/ru/vtosters/lite/music/cache/db/SqlPlaylists.java rename to app/src/main/java/ru/vtosters/lite/music/cache/playlists/SqlPlaylists.java index 74189af23..8a278d6b4 100644 --- a/app/src/main/java/ru/vtosters/lite/music/cache/db/SqlPlaylists.java +++ b/app/src/main/java/ru/vtosters/lite/music/cache/playlists/SqlPlaylists.java @@ -1,22 +1,22 @@ -package ru.vtosters.lite.music.cache.db; +package ru.vtosters.lite.music.cache.playlists; 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.cache.db.DatabaseAccess; +import ru.vtosters.lite.music.cache.db.Constants; import ru.vtosters.lite.music.interfaces.IPlaylist; import ru.vtosters.lite.music.interfaces.IPlaylists; import ru.vtosters.lite.utils.music.MusicCacheStorageUtils; import ru.vtosters.lite.utils.music.PlaylistUtils; import java.util.*; +import java.util.stream.Stream; public final class SqlPlaylists implements IPlaylists { @@ -107,7 +107,7 @@ public Map playlists(int ownerId) { } @Override - public List playlists() { + public Stream playlists() { try (Cursor cur = database.getReadableDatabase() .query(Constants.TABLE_PLAYLIST, new String[]{Constants.OWNER_ID, Constants.PLAYLIST_ID}, @@ -123,13 +123,12 @@ public List playlists() { list.add(new SqlPlaylist(ownerId, id, database)); } - return Collections.unmodifiableList(list); + return list.stream(); } } @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); 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 a51ee20c1..74539d6aa 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,18 +1,12 @@ 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.cache.playlists.MusicCacheDb; 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; 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 698330810..78a13478e 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 @@ -3,9 +3,8 @@ import android.util.Log; import bruhcollective.itaysonlab.libvkx.client.LibVKXClient; 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.cache.delegate.MusicCacheImpl; import ru.vtosters.lite.music.interfaces.Callback; import ru.vtosters.lite.music.interfaces.IPlaylist; import ru.vtosters.lite.utils.IOUtils; 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 65b715e00..bbf60ad55 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,7 +1,5 @@ package ru.vtosters.lite.music.downloader.playlist; -import android.database.sqlite.SQLiteDatabase; - import com.vk.dto.music.MusicTrack; import com.vk.dto.music.Playlist; @@ -12,11 +10,10 @@ import java.util.concurrent.atomic.AtomicInteger; import bruhcollective.itaysonlab.libvkx.client.LibVKXClient; -import java8.util.concurrent.CompletableFuture; import ru.vtosters.lite.concurrent.VTExecutors; 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.cache.playlists.MusicCacheDb; +import ru.vtosters.lite.music.cache.playlists.SqlPlaylists; import ru.vtosters.lite.music.downloader.Mp3Downloader; import ru.vtosters.lite.music.downloader.ThumbnailTrackDownloader; import ru.vtosters.lite.music.interfaces.Callback; @@ -77,16 +74,19 @@ public void download(List content) throws Exception { // fork content.forEach(track -> { - futures.add(CompletableFuture.supplyAsync(() -> { - try { - origin.download(track); - thumbnail.download(track); - callback.onProgress(indicator.incrementAndGet()); - return track; - } catch (Exception e) { - throw new RuntimeException(e); - } - }, VTExecutors.getMusicDownloadExecutor())); + Future f = VTExecutors + .getMusicDownloadExecutor() + .submit(() -> { + try { + origin.download(track); + thumbnail.download(track); + callback.onProgress(indicator.incrementAndGet()); + return track; + } catch (Exception e) { + throw new RuntimeException(e); + } + }); + futures.add(f); }); // join try (Database database = new Database()) { 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 9d0f113ec..4b61e1b5b 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 @@ -5,6 +5,7 @@ import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.stream.Stream; public interface IPlaylists { @@ -18,7 +19,7 @@ public interface IPlaylists { Map playlists(int ownerId); - List playlists(); + Stream playlists(); default void deleteAll() { @@ -26,7 +27,7 @@ default void deleteAll() { } default boolean isEmpty() { - return playlists().isEmpty(); + return !playlists().findAny().isPresent(); } diff --git a/app/src/main/java/ru/vtosters/lite/ui/fragments/MusicFragment.java b/app/src/main/java/ru/vtosters/lite/ui/fragments/MusicFragment.java index 9be84d63e..8aa0869d3 100644 --- a/app/src/main/java/ru/vtosters/lite/ui/fragments/MusicFragment.java +++ b/app/src/main/java/ru/vtosters/lite/ui/fragments/MusicFragment.java @@ -17,7 +17,7 @@ import ru.vtosters.hooks.other.ThemesUtils; import ru.vtosters.lite.downloaders.AudioDownloader; import ru.vtosters.lite.music.LastFMScrobbler; -import ru.vtosters.lite.music.cache.MusicCacheImpl; +import ru.vtosters.lite.music.cache.delegate.MusicCacheImpl; import ru.vtosters.lite.music.cache.delegate.PlaylistCacheDbDelegate; import ru.vtosters.lite.ui.PreferenceFragmentUtils; import ru.vtosters.lite.utils.AccountManagerUtils; @@ -68,12 +68,14 @@ public void onCreate(Bundle bundle) { } ); - if (MusicCacheImpl.hasPlaylist()) { + List playlists = PlaylistCacheDbDelegate.getAllPlaylists(); + int n = playlists.size(); + if (n > 0) { PreferenceFragmentUtils.addPreference( getPreferenceScreen(), "cached_playlists", "Кешированные плейлисты", - String.format("Скачано плейлистов: %d", MusicCacheImpl.getPlaylists().size()), + String.format("Скачано плейлистов: %d", n), null, preference -> { cachedPlaylistsDialog(requireContext()); @@ -434,19 +436,23 @@ private void logout(Context ctx) { @SuppressLint("DefaultLocale") private void cachedPlaylistsDialog(Context ctx) { List playlists = PlaylistCacheDbDelegate.getAllPlaylists(); - String[] playlistNames = new String[playlists.size()]; - - for (int i = 0; i < playlists.size(); i++) { - playlistNames[i] = playlists.get(i).g; // Assuming Playlist class has a getTitle() method - } - + CharSequence[] playlistNames = playlists + .stream() + .map(x -> x.g) + .toArray(String[]::new); VkAlertDialog.Builder builder = new VkAlertDialog.Builder(ctx); builder.setTitle("Скачанные плейлисты"); builder.setItems(playlistNames, (dialog, which) -> { Playlist playlist = playlists.get(which); PlaylistCacheDbDelegate.deletePlaylist(playlist.a, playlist.b); AndroidUtils.sendToast("Плейлист удален"); - findPreference("cached_playlists").setSummary(String.format("Скачано плейлистов: %d", MusicCacheImpl.getPlaylists().size())); + findPreference("cached_playlists") + .setSummary( + String.format( + "Скачано плейлистов: %d", + playlistNames.length + ) + ); }); builder.show(); diff --git a/app/src/main/java/ru/vtosters/lite/utils/lazy/CachingSupplier.java b/app/src/main/java/ru/vtosters/lite/utils/lazy/CachingSupplier.java new file mode 100644 index 000000000..8d2d89a42 --- /dev/null +++ b/app/src/main/java/ru/vtosters/lite/utils/lazy/CachingSupplier.java @@ -0,0 +1,73 @@ +package ru.vtosters.lite.utils.lazy; + +import java.util.Objects; +import java.util.concurrent.locks.ReentrantLock; +import java.util.function.Supplier; + +/* + * This not very nice solution is due to footprint, at the moment jvm bloats + * the footprint object a lot, this is a very delicate property - + * one step to the left, one step to the right and the size of the object is + * significantly larger than expected. + * I'm focusing on the latest jdk versions, as soon as one of + * the projects compresses objects (e.g. Valhalla, Liliput project) + * the code will be rewritten. + * + * There is also an idea to write my own lightweight version of locking + * on waiting for the first writer, but this idea may not be so promising + */ +public final class CachingSupplier implements Lazy { + private volatile Lazy outcome; + + public CachingSupplier(final Supplier scalar) { + final class Sync extends ReentrantLock implements Lazy { + @Override + public E get() { + lock(); + try { + if (completed()) + return CachingSupplier.this.get(); + final E val = scalar.get(); + outcome = new Lazy<>() { + @Override + public E get() { return val; } + @Override + public boolean completed() { return true; } + @Override + public String toString() { return Objects.toString(val); } + }; + return val; + } finally { + unlock(); + } + } + + @Override + public boolean completed() { + final Lazy lazy = outcome; + return lazy != this && lazy.completed(); + } + @Override + public String toString() { + return "uninitialized"; + } + } + this.outcome = new Sync(); + } + + + @Override + public E get() { + return outcome.get(); + } + + @Override + public boolean completed() { + return outcome.completed(); + } + + @Override + public String toString() { + return outcome.toString(); + } +} \ No newline at end of file diff --git a/app/src/main/java/ru/vtosters/lite/utils/lazy/Lazy.java b/app/src/main/java/ru/vtosters/lite/utils/lazy/Lazy.java new file mode 100644 index 000000000..c926d6282 --- /dev/null +++ b/app/src/main/java/ru/vtosters/lite/utils/lazy/Lazy.java @@ -0,0 +1,7 @@ +package ru.vtosters.lite.utils.lazy; + +import java.util.function.Supplier; + +public interface Lazy extends Supplier { + boolean completed(); +} diff --git a/smali/smali_classes3/com/vk/music/e/MusicCatalogConfiguration.smali b/smali/smali_classes3/com/vk/music/e/MusicCatalogConfiguration.smali deleted file mode 100644 index 66e4786d6..000000000 --- a/smali/smali_classes3/com/vk/music/e/MusicCatalogConfiguration.smali +++ /dev/null @@ -1,244 +0,0 @@ -.class public final Lcom/vk/music/e/MusicCatalogConfiguration; -.super Lcom/vk/catalog2/core/VkCatalogConfiguration; -.source "MusicCatalogConfiguration.kt" - - -# instance fields -.field private final c:Ljava/lang/String; - - -# direct methods -.method public constructor (ILjava/lang/String;Ljava/lang/String;)V - .locals 0 - - .line 1 - invoke-direct {p0, p1, p2}, Lcom/vk/catalog2/core/VkCatalogConfiguration;->(ILjava/lang/String;)V - - iput-object p3, p0, Lcom/vk/music/e/MusicCatalogConfiguration;->c:Ljava/lang/String; - - return-void -.end method - -.method public constructor (Landroid/os/Bundle;)V - .locals 3 - - const-string v0, "owner_id" - - .line 2 - invoke-virtual {p1, v0}, Landroid/os/Bundle;->getInt(Ljava/lang/String;)I - - move-result v0 - - const-string v1, "ref" - - .line 3 - invoke-virtual {p1, v1}, Landroid/os/Bundle;->getString(Ljava/lang/String;)Ljava/lang/String; - - move-result-object v1 - - const-string v2, "url" - - .line 4 - invoke-virtual {p1, v2}, Landroid/os/Bundle;->getString(Ljava/lang/String;)Ljava/lang/String; - - move-result-object p1 - - .line 5 - invoke-direct {p0, v0, v1, p1}, Lcom/vk/music/e/MusicCatalogConfiguration;->(ILjava/lang/String;Ljava/lang/String;)V - - return-void -.end method - - -# virtual methods -.method public a(ILjava/lang/String;)Lio/reactivex/Observable; - .locals 3 - .annotation system Ldalvik/annotation/Signature; - value = { - "(I", - "Ljava/lang/String;", - ")", - "Lio/reactivex/Observable<", - "Lcom/vk/catalog2/core/api/dto/CatalogResponse<", - "Lcom/vk/catalog2/core/api/dto/CatalogCatalog;", - ">;>;" - } - .end annotation - - invoke-static {}, Lru/vtosters/hooks/music/injectors/TracklistInjector;->eligibleForOfflineCaching()Z - - move-result v0 - - if-eqz v0, :cond_custom - - invoke-virtual {p0}, Lcom/vk/catalog2/core/VkCatalogConfiguration;->j()Lcom/vk/catalog2/core/CatalogParser; - - move-result-object v0 - - invoke-static {v0}, Lru/vtosters/hooks/music/injectors/TracklistInjector;->createOfflineRx(Lcom/vk/catalog2/core/CatalogParser;)Lio/reactivex/Observable; - - move-result-object v0 - - return-object v0 - - :cond_custom - .line 1 - new-instance v0, Lcom/vk/catalog2/core/api/music/CatalogGetAudio; - - invoke-virtual {p0}, Lcom/vk/catalog2/core/VkCatalogConfiguration;->j()Lcom/vk/catalog2/core/CatalogParser; - - move-result-object v1 - - iget-object v2, p0, Lcom/vk/music/e/MusicCatalogConfiguration;->c:Ljava/lang/String; - - invoke-direct {v0, v1, p1, p2, v2}, Lcom/vk/catalog2/core/api/music/CatalogGetAudio;->(Lcom/vk/catalog2/core/CatalogParser;ILjava/lang/String;Ljava/lang/String;)V - - const/4 p1, 0x0 - - const/4 p2, 0x1 - - invoke-static {v0, p1, p2, p1}, Lcom/vk/api/base/ApiRequest;->d(Lcom/vk/api/base/ApiRequest;Lcom/vk/api/base/ApiThreadHolder;ILjava/lang/Object;)Lio/reactivex/Observable; - - move-result-object p1 - - return-object p1 -.end method - -.method public a(Lcom/vk/catalog2/core/api/dto/CatalogDataType;Lcom/vk/catalog2/core/api/dto/CatalogViewType;Lcom/vk/catalog2/core/blocks/UIBlock;Lcom/vk/catalog2/core/CatalogEntryPointParams;)Lcom/vk/catalog2/core/holders/common/CatalogViewHolder; - .locals 3 - - .line 2 - instance-of v0, p3, Lcom/vk/catalog2/core/blocks/UIBlockButtons; - - if-eqz v0, :cond_3 - - invoke-virtual {p3}, Lcom/vk/catalog2/core/blocks/UIBlock;->z1()Lcom/vk/catalog2/core/api/dto/CatalogViewType; - - move-result-object v0 - - sget-object v1, Lcom/vk/catalog2/core/api/dto/CatalogViewType;->BUTTONS_HORIZONTAL:Lcom/vk/catalog2/core/api/dto/CatalogViewType; - - if-ne v0, v1, :cond_3 - - move-object v0, p3 - - check-cast v0, Lcom/vk/catalog2/core/blocks/UIBlockButtons; - - invoke-virtual {v0}, Lcom/vk/catalog2/core/blocks/UIBlockButtons;->B1()Ljava/util/ArrayList; - - move-result-object v0 - - invoke-virtual {v0}, Ljava/util/ArrayList;->size()I - - move-result v0 - - const/4 v1, 0x1 - - if-eq v0, v1, :cond_3 - - .line 3 - sget-object v0, Lcom/vk/music/e/c;->$EnumSwitchMapping$1:[I - - invoke-virtual {p1}, Ljava/lang/Enum;->ordinal()I - - move-result v2 - - aget v0, v0, v2 - - if-eq v0, v1, :cond_0 - - .line 4 - invoke-super {p0, p1, p2, p3, p4}, Lcom/vk/catalog2/core/VkCatalogConfiguration;->a(Lcom/vk/catalog2/core/api/dto/CatalogDataType;Lcom/vk/catalog2/core/api/dto/CatalogViewType;Lcom/vk/catalog2/core/blocks/UIBlock;Lcom/vk/catalog2/core/CatalogEntryPointParams;)Lcom/vk/catalog2/core/holders/common/CatalogViewHolder; - - move-result-object p1 - - goto :goto_0 - - .line 5 - :cond_0 - sget-object v0, Lcom/vk/music/e/c;->$EnumSwitchMapping$0:[I - - invoke-virtual {p2}, Ljava/lang/Enum;->ordinal()I - - move-result v2 - - aget v0, v0, v2 - - const v2, 0x7f0d00bd - - if-eq v0, v1, :cond_2 - - const/4 v1, 0x2 - - if-eq v0, v1, :cond_1 - - .line 6 - invoke-super {p0, p1, p2, p3, p4}, Lcom/vk/catalog2/core/VkCatalogConfiguration;->a(Lcom/vk/catalog2/core/api/dto/CatalogDataType;Lcom/vk/catalog2/core/api/dto/CatalogViewType;Lcom/vk/catalog2/core/blocks/UIBlock;Lcom/vk/catalog2/core/CatalogEntryPointParams;)Lcom/vk/catalog2/core/holders/common/CatalogViewHolder; - - move-result-object p1 - - goto :goto_0 - - .line 7 - :cond_1 - new-instance p1, Lcom/vk/catalog2/core/holders/music/MusicActionButtonVh; - - const p2, 0x7f080770 - - const p3, 0x7f120136 - - .line 8 - invoke-virtual {p4}, Lcom/vk/catalog2/core/CatalogEntryPointParams;->k()Lcom/vk/music/player/PlayerModel; - - move-result-object p4 - - .line 9 - invoke-direct {p1, p2, v2, p3, p4}, Lcom/vk/catalog2/core/holders/music/MusicActionButtonVh;->(IIILcom/vk/music/player/PlayerModel;)V - - goto :goto_0 - - .line 10 - :cond_2 - new-instance p1, Lcom/vk/catalog2/core/holders/music/MusicActionButtonVh; - - const p2, 0x7f0806cc - - const p3, 0x7f12078f - - .line 11 - invoke-virtual {p4}, Lcom/vk/catalog2/core/CatalogEntryPointParams;->k()Lcom/vk/music/player/PlayerModel; - - move-result-object p4 - - .line 12 - invoke-direct {p1, p2, v2, p3, p4}, Lcom/vk/catalog2/core/holders/music/MusicActionButtonVh;->(IIILcom/vk/music/player/PlayerModel;)V - - :goto_0 - return-object p1 - - .line 13 - :cond_3 - invoke-super {p0, p1, p2, p3, p4}, Lcom/vk/catalog2/core/VkCatalogConfiguration;->a(Lcom/vk/catalog2/core/api/dto/CatalogDataType;Lcom/vk/catalog2/core/api/dto/CatalogViewType;Lcom/vk/catalog2/core/blocks/UIBlock;Lcom/vk/catalog2/core/CatalogEntryPointParams;)Lcom/vk/catalog2/core/holders/common/CatalogViewHolder; - - move-result-object p1 - - return-object p1 -.end method - -.method public e()Landroid/os/Bundle; - .locals 3 - - .line 1 - invoke-super {p0}, Lcom/vk/catalog2/core/VkCatalogConfiguration;->e()Landroid/os/Bundle; - - move-result-object v0 - - .line 2 - iget-object v1, p0, Lcom/vk/music/e/MusicCatalogConfiguration;->c:Ljava/lang/String; - - const-string v2, "url" - - invoke-virtual {v0, v2, v1}, Landroid/os/Bundle;->putString(Ljava/lang/String;Ljava/lang/String;)V - - return-object v0 -.end method