diff --git a/app/src/main/java/com/dkanada/gramophone/App.java b/app/src/main/java/com/dkanada/gramophone/App.java index 718d75f0..f97f82ef 100644 --- a/app/src/main/java/com/dkanada/gramophone/App.java +++ b/app/src/main/java/com/dkanada/gramophone/App.java @@ -61,6 +61,7 @@ public class App extends Application { .addMigrations(JellyDatabase.Migration2) .addMigrations(JellyDatabase.Migration3) .addMigrations(JellyDatabase.Migration4) + .addMigrations(JellyDatabase.Migration5) .build(); } diff --git a/app/src/main/java/com/dkanada/gramophone/database/Cache.java b/app/src/main/java/com/dkanada/gramophone/database/Cache.java new file mode 100644 index 00000000..7fff9e98 --- /dev/null +++ b/app/src/main/java/com/dkanada/gramophone/database/Cache.java @@ -0,0 +1,29 @@ +package com.dkanada.gramophone.database; + +import androidx.annotation.NonNull; +import androidx.room.ColumnInfo; +import androidx.room.Entity; +import androidx.room.PrimaryKey; + +import com.dkanada.gramophone.model.Song; + +import java.util.UUID; + +@Entity(tableName = "cache") +public class Cache { + @NonNull + @PrimaryKey + public String id; + + @ColumnInfo(defaultValue = "1") + public Boolean cache; + + public Cache() { + this.id = UUID.randomUUID().toString(); + } + + public Cache(Song song) { + this.id = song.id; + this.cache = true; + } +} diff --git a/app/src/main/java/com/dkanada/gramophone/database/CacheDao.java b/app/src/main/java/com/dkanada/gramophone/database/CacheDao.java new file mode 100644 index 00000000..72d62fd1 --- /dev/null +++ b/app/src/main/java/com/dkanada/gramophone/database/CacheDao.java @@ -0,0 +1,19 @@ +package com.dkanada.gramophone.database; + +import androidx.room.Dao; +import androidx.room.Insert; +import androidx.room.OnConflictStrategy; +import androidx.room.Query; + +import com.dkanada.gramophone.model.Song; + +import java.util.List; + +@Dao +public interface CacheDao { + @Insert(onConflict = OnConflictStrategy.REPLACE) + void insertCache(Cache cache); + + @Query("SELECT * FROM songs LEFT JOIN cache USING(id) WHERE songs.id IN (:ids)") + List getSongs(List ids); +} diff --git a/app/src/main/java/com/dkanada/gramophone/database/JellyDatabase.java b/app/src/main/java/com/dkanada/gramophone/database/JellyDatabase.java index a39cc428..6742f672 100644 --- a/app/src/main/java/com/dkanada/gramophone/database/JellyDatabase.java +++ b/app/src/main/java/com/dkanada/gramophone/database/JellyDatabase.java @@ -10,14 +10,16 @@ import com.dkanada.gramophone.model.User; @androidx.room.Database( entities = { + Cache.class, Song.class, QueueSong.class, User.class }, - version = 4, + version = 5, exportSchema = false ) public abstract class JellyDatabase extends RoomDatabase { + public abstract CacheDao cacheDao(); public abstract SongDao songDao(); public abstract QueueSongDao queueSongDao(); public abstract UserDao userDao(); @@ -52,4 +54,12 @@ public abstract class JellyDatabase extends RoomDatabase { + "name TEXT, server TEXT, token TEXT)"); } }; + + public static final Migration Migration5 = new Migration(4, 5) { + @Override + public void migrate(@NonNull SupportSQLiteDatabase database) { + database.execSQL("CREATE TABLE cache (id TEXT NOT NULL PRIMARY KEY," + + "cache INTEGER NOT NULL)"); + } + }; } diff --git a/app/src/main/java/com/dkanada/gramophone/database/QueueSongDao.java b/app/src/main/java/com/dkanada/gramophone/database/QueueSongDao.java index a1a7fbbf..69796902 100644 --- a/app/src/main/java/com/dkanada/gramophone/database/QueueSongDao.java +++ b/app/src/main/java/com/dkanada/gramophone/database/QueueSongDao.java @@ -4,6 +4,7 @@ import androidx.room.Dao; import androidx.room.Insert; import androidx.room.OnConflictStrategy; import androidx.room.Query; +import androidx.room.Transaction; import com.dkanada.gramophone.App; import com.dkanada.gramophone.model.Song; @@ -22,6 +23,7 @@ public abstract class QueueSongDao { @Query("SELECT * from queueSongs WHERE queue = :queue ORDER BY `index`") public abstract List getQueueSongs(int queue); + @Transaction public List getQueue(int queue) { List queueSongs = getQueueSongs(queue); List songs = new ArrayList<>(); @@ -34,6 +36,7 @@ public abstract class QueueSongDao { return songs; } + @Transaction public void setQueue(List songs, int queue) { List queueSongs = new ArrayList<>(); for (int i = 0; i < songs.size(); i++) { diff --git a/app/src/main/java/com/dkanada/gramophone/model/Song.java b/app/src/main/java/com/dkanada/gramophone/model/Song.java index 57bcc26b..16614274 100644 --- a/app/src/main/java/com/dkanada/gramophone/model/Song.java +++ b/app/src/main/java/com/dkanada/gramophone/model/Song.java @@ -48,6 +48,8 @@ public class Song implements Parcelable { public int bitDepth; public int channels; + public boolean cache; + public Song() { this.id = UUID.randomUUID().toString(); } diff --git a/app/src/main/java/com/dkanada/gramophone/service/DownloadService.java b/app/src/main/java/com/dkanada/gramophone/service/DownloadService.java index a45e9c0b..a92d1af7 100644 --- a/app/src/main/java/com/dkanada/gramophone/service/DownloadService.java +++ b/app/src/main/java/com/dkanada/gramophone/service/DownloadService.java @@ -2,13 +2,13 @@ package com.dkanada.gramophone.service; import android.app.Service; import android.content.Intent; -import android.os.Environment; import android.os.Handler; import android.os.IBinder; import android.os.Looper; import com.dkanada.gramophone.App; import com.dkanada.gramophone.BuildConfig; +import com.dkanada.gramophone.database.Cache; import com.dkanada.gramophone.model.Song; import com.dkanada.gramophone.util.MusicUtil; @@ -50,11 +50,7 @@ public class DownloadService extends Service { try { URL url = new URL(MusicUtil.getDownloadUri(song)); URLConnection connection = url.openConnection(); - - File root = new File(App.getInstance().getCacheDir(), "music"); - String path = song.artistName + "/" + song.albumName + "/"; - String name = song.discNumber + "." + song.trackNumber + " - " + song.title + "." + song.container; - File audio = new File(root, path + name); + File audio = new File(MusicUtil.getFileUri(song)); audio.getParentFile().mkdirs(); audio.createNewFile(); @@ -64,7 +60,7 @@ public class DownloadService extends Service { connection.connect(); - byte[] data = new byte[4096]; + byte[] data = new byte[262144]; int count; while ((count = input.read(data)) != -1) { @@ -73,6 +69,8 @@ public class DownloadService extends Service { input.close(); output.close(); + + App.getDatabase().cacheDao().insertCache(new Cache(song)); } catch (Exception e) { e.printStackTrace(); } diff --git a/app/src/main/java/com/dkanada/gramophone/service/playback/LocalPlayer.java b/app/src/main/java/com/dkanada/gramophone/service/playback/LocalPlayer.java index e299eb63..1daa568b 100644 --- a/app/src/main/java/com/dkanada/gramophone/service/playback/LocalPlayer.java +++ b/app/src/main/java/com/dkanada/gramophone/service/playback/LocalPlayer.java @@ -96,15 +96,14 @@ public class LocalPlayer implements Playback { @Override public void setDataSource(Song song) { - String uri = MusicUtil.getTranscodeUri(song); MediaItem mediaItem = exoPlayer.getCurrentMediaItem(); - if (mediaItem != null && mediaItem.playbackProperties.uri.toString().equals(uri)) { + if (mediaItem != null && mediaItem.mediaId.equals(song.id)) { return; } exoPlayer.clearMediaItems(); - appendDataSource(MusicUtil.getTranscodeUri(song)); + appendDataSource(song); exoPlayer.seekTo(0, 0); } @@ -114,12 +113,19 @@ public class LocalPlayer implements Playback { exoPlayer.removeMediaItem(1); } - appendDataSource(MusicUtil.getTranscodeUri(song)); + appendDataSource(song); } - private void appendDataSource(String path) { - Uri uri = Uri.parse(path); + private void appendDataSource(Song song) { + File audio = new File(MusicUtil.getFileUri(song)); + Uri uri = Uri.fromFile(audio); + + if (!song.cache || !audio.exists()) { + uri = Uri.parse(MusicUtil.getTranscodeUri(song)); + } + MediaItem mediaItem = MediaItem.fromUri(uri); + mediaItem = mediaItem.buildUpon().setMediaId(song.id).build(); exoPlayer.addMediaItem(mediaItem); } diff --git a/app/src/main/java/com/dkanada/gramophone/service/playback/UnknownMediaSourceFactory.kt b/app/src/main/java/com/dkanada/gramophone/service/playback/UnknownMediaSourceFactory.kt index 0ba62998..69cc75d4 100644 --- a/app/src/main/java/com/dkanada/gramophone/service/playback/UnknownMediaSourceFactory.kt +++ b/app/src/main/java/com/dkanada/gramophone/service/playback/UnknownMediaSourceFactory.kt @@ -42,6 +42,10 @@ class UnknownMediaSourceFactory(dataSourceFactory: DataSource.Factory) : MediaSo } override fun createMediaSource(mediaItem: MediaItem): MediaSource { + if (mediaItem.playbackProperties?.uri.toString().contains("file://")) { + return progressiveMediaSource.createMediaSource(mediaItem) + } + val type: String? = runBlocking { httpGet(mediaItem.playbackProperties!!.uri.toString()) } diff --git a/app/src/main/java/com/dkanada/gramophone/util/MusicUtil.java b/app/src/main/java/com/dkanada/gramophone/util/MusicUtil.java index 41aefdd1..c76e9cf2 100644 --- a/app/src/main/java/com/dkanada/gramophone/util/MusicUtil.java +++ b/app/src/main/java/com/dkanada/gramophone/util/MusicUtil.java @@ -21,6 +21,7 @@ import org.jellyfin.apiclient.interaction.ApiClient; import org.jellyfin.apiclient.interaction.Response; import org.jellyfin.apiclient.model.dto.UserItemDataDto; +import java.io.File; import java.util.List; import java.util.Locale; @@ -82,6 +83,15 @@ public class MusicUtil { return builder.toString(); } + public static String getFileUri(Song song) { + File root = new File(App.getInstance().getCacheDir(), "music"); + + String path = "/" + song.artistName + "/" + song.albumName + "/"; + String name = song.discNumber + "." + song.trackNumber + " - " + song.title + "." + song.container; + + return root + path + name; + } + @NonNull public static Intent createShareSongFileIntent(@NonNull final Song song, Context context) { try { diff --git a/app/src/main/java/com/dkanada/gramophone/util/QueryUtil.java b/app/src/main/java/com/dkanada/gramophone/util/QueryUtil.java index 7f0fea0a..2da8b138 100644 --- a/app/src/main/java/com/dkanada/gramophone/util/QueryUtil.java +++ b/app/src/main/java/com/dkanada/gramophone/util/QueryUtil.java @@ -170,11 +170,14 @@ public class QueryUtil { @Override public void onResponse(ItemsResult result) { List songs = new ArrayList<>(); + List ids = new ArrayList<>(); for (BaseItemDto itemDto : result.getItems()) { songs.add(new Song(itemDto)); + ids.add(itemDto.getId()); } - callback.onLoadMedia(songs); + App.getDatabase().songDao().insertSongs(songs); + callback.onLoadMedia(App.getDatabase().cacheDao().getSongs(ids)); } @Override