diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index b8660be..3c6e2e1 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -45,6 +45,15 @@
+
+
+
+
+
+
+
diff --git a/app/src/main/java/com/github/apognu/otter/Otter.kt b/app/src/main/java/com/github/apognu/otter/Otter.kt
index 2edeb0b..81af4ac 100644
--- a/app/src/main/java/com/github/apognu/otter/Otter.kt
+++ b/app/src/main/java/com/github/apognu/otter/Otter.kt
@@ -6,6 +6,9 @@ import com.github.apognu.otter.utils.Cache
import com.github.apognu.otter.utils.Command
import com.github.apognu.otter.utils.Event
import com.github.apognu.otter.utils.Request
+import com.google.android.exoplayer2.database.ExoDatabaseProvider
+import com.google.android.exoplayer2.upstream.cache.LeastRecentlyUsedCacheEvictor
+import com.google.android.exoplayer2.upstream.cache.SimpleCache
import com.preference.PowerPreference
import kotlinx.coroutines.channels.BroadcastChannel
import kotlinx.coroutines.channels.Channel
@@ -27,6 +30,9 @@ class Otter : Application() {
val requestBus: BroadcastChannel = BroadcastChannel(10)
val progressBus: BroadcastChannel> = ConflatedBroadcastChannel()
+ var exoCache: SimpleCache? = null
+ var exoDatabase: ExoDatabaseProvider? = null
+
override fun onCreate() {
super.onCreate()
@@ -35,6 +41,15 @@ class Otter : Application() {
Thread.setDefaultUncaughtExceptionHandler(CrashReportHandler())
instance = this
+ exoDatabase = ExoDatabaseProvider(this)
+
+ PowerPreference.getDefaultFile().getInt("media_cache_size", 1).toLong().also {
+ exoCache = SimpleCache(
+ cacheDir.resolve("media"),
+ LeastRecentlyUsedCacheEvictor(it * 1024 * 1024 * 1024),
+ exoDatabase
+ )
+ }
when (PowerPreference.getDefaultFile().getString("night_mode")) {
"on" -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
diff --git a/app/src/main/java/com/github/apognu/otter/activities/MainActivity.kt b/app/src/main/java/com/github/apognu/otter/activities/MainActivity.kt
index f471156..2913230 100644
--- a/app/src/main/java/com/github/apognu/otter/activities/MainActivity.kt
+++ b/app/src/main/java/com/github/apognu/otter/activities/MainActivity.kt
@@ -22,6 +22,7 @@ import androidx.fragment.app.FragmentManager
import com.github.apognu.otter.R
import com.github.apognu.otter.fragments.*
import com.github.apognu.otter.playback.MediaControlsManager
+import com.github.apognu.otter.playback.PinService
import com.github.apognu.otter.playback.PlayerService
import com.github.apognu.otter.repositories.FavoritedRepository
import com.github.apognu.otter.repositories.FavoritesRepository
diff --git a/app/src/main/java/com/github/apognu/otter/adapters/TracksAdapter.kt b/app/src/main/java/com/github/apognu/otter/adapters/TracksAdapter.kt
index c43b48c..1969c9b 100644
--- a/app/src/main/java/com/github/apognu/otter/adapters/TracksAdapter.kt
+++ b/app/src/main/java/com/github/apognu/otter/adapters/TracksAdapter.kt
@@ -105,6 +105,7 @@ class TracksAdapter(private val context: Context?, private val favoriteListener:
when (it.itemId) {
R.id.track_add_to_queue -> CommandBus.send(Command.AddToQueue(listOf(track)))
R.id.track_play_next -> CommandBus.send(Command.PlayNext(track))
+ R.id.track_pin -> CommandBus.send(Command.PinTrack(track))
R.id.queue_remove -> CommandBus.send(Command.RemoveFromQueue(track))
}
diff --git a/app/src/main/java/com/github/apognu/otter/playback/PinService.kt b/app/src/main/java/com/github/apognu/otter/playback/PinService.kt
new file mode 100644
index 0000000..3568423
--- /dev/null
+++ b/app/src/main/java/com/github/apognu/otter/playback/PinService.kt
@@ -0,0 +1,29 @@
+package com.github.apognu.otter.playback
+
+import android.app.Notification
+import com.github.apognu.otter.Otter
+import com.github.apognu.otter.R
+import com.github.apognu.otter.utils.AppContext
+import com.google.android.exoplayer2.offline.*
+import com.google.android.exoplayer2.scheduler.Scheduler
+import com.google.android.exoplayer2.ui.DownloadNotificationHelper
+
+class PinService : DownloadService(AppContext.NOTIFICATION_DOWNLOADS) {
+ private val manager by lazy {
+ val database = Otter.get().exoDatabase
+ val cache = Otter.get().exoCache
+ val helper = DownloaderConstructorHelper(cache, QueueManager.factory(this))
+
+ DownloadManager(this, DefaultDownloadIndex(database), DefaultDownloaderFactory(helper))
+ }
+
+ override fun getDownloadManager() = manager
+
+ override fun getScheduler(): Scheduler? = null
+
+ override fun getForegroundNotification(downloads: MutableList?): Notification {
+ return DownloadNotificationHelper(this, AppContext.NOTIFICATION_CHANNEL_DOWNLOADS).buildProgressNotification(R.drawable.ottershape, null, null, downloads)
+ }
+
+ fun getDownloads() = manager.downloadIndex.getDownloads()
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/github/apognu/otter/playback/PlayerService.kt b/app/src/main/java/com/github/apognu/otter/playback/PlayerService.kt
index 44dd550..568d6dc 100644
--- a/app/src/main/java/com/github/apognu/otter/playback/PlayerService.kt
+++ b/app/src/main/java/com/github/apognu/otter/playback/PlayerService.kt
@@ -8,14 +8,19 @@ import android.content.IntentFilter
import android.media.AudioAttributes
import android.media.AudioFocusRequest
import android.media.AudioManager
+import android.net.Uri
import android.os.Build
import android.os.IBinder
import android.support.v4.media.session.MediaSessionCompat
import android.view.KeyEvent
+import com.github.apognu.otter.Otter
import com.github.apognu.otter.R
import com.github.apognu.otter.utils.*
import com.google.android.exoplayer2.*
import com.google.android.exoplayer2.ext.mediasession.MediaSessionConnector
+import com.google.android.exoplayer2.offline.DownloadRequest
+import com.google.android.exoplayer2.offline.DownloadService
+import com.google.android.exoplayer2.offline.DownloadService.sendAddDownload
import com.google.android.exoplayer2.source.TrackGroupArray
import com.google.android.exoplayer2.trackselection.TrackSelectionArray
import kotlinx.coroutines.Dispatchers.IO
@@ -25,6 +30,7 @@ import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
+import java.util.*
class PlayerService : Service() {
private lateinit var queue: QueueManager
@@ -186,6 +192,16 @@ class PlayerService : Service() {
}
is Command.SetRepeatMode -> player.repeatMode = message.mode
+
+ is Command.PinTrack -> {
+ message.track.bestUpload()?.let { upload ->
+ val url = mustNormalizeUrl(upload.listen_url)
+
+ DownloadRequest(url, DownloadRequest.TYPE_PROGRESSIVE, Uri.parse(url), Collections.emptyList(), null, null).also {
+ DownloadService.sendAddDownload(this@PlayerService, PinService::class.java, it, false)
+ }
+ }
+ }
}
if (player.playWhenReady) {
@@ -246,7 +262,7 @@ class PlayerService : Service() {
state(false)
player.release()
- queue.cache.release()
+ Otter.get().exoCache?.release()
stopForeground(true)
stopSelf()
diff --git a/app/src/main/java/com/github/apognu/otter/playback/QueueManager.kt b/app/src/main/java/com/github/apognu/otter/playback/QueueManager.kt
index 066f602..dbd6cd8 100644
--- a/app/src/main/java/com/github/apognu/otter/playback/QueueManager.kt
+++ b/app/src/main/java/com/github/apognu/otter/playback/QueueManager.kt
@@ -2,6 +2,7 @@ package com.github.apognu.otter.playback
import android.content.Context
import android.net.Uri
+import com.github.apognu.otter.Otter
import com.github.apognu.otter.R
import com.github.apognu.otter.utils.*
import com.github.kittinunf.fuel.gson.gsonDeserializerOf
@@ -9,31 +10,34 @@ import com.google.android.exoplayer2.source.ConcatenatingMediaSource
import com.google.android.exoplayer2.source.ProgressiveMediaSource
import com.google.android.exoplayer2.upstream.DefaultHttpDataSourceFactory
import com.google.android.exoplayer2.upstream.cache.CacheDataSourceFactory
-import com.google.android.exoplayer2.upstream.cache.LeastRecentlyUsedCacheEvictor
-import com.google.android.exoplayer2.upstream.cache.SimpleCache
import com.google.android.exoplayer2.util.Util
import com.google.gson.Gson
-import com.preference.PowerPreference
class QueueManager(val context: Context) {
- var cache: SimpleCache
var metadata: MutableList