Skip to content

Commit

Permalink
download: add likedAutoDownloads
Browse files Browse the repository at this point in the history
  • Loading branch information
mattcarter11 committed Dec 5, 2024
1 parent 0ea17c8 commit 427b231
Show file tree
Hide file tree
Showing 20 changed files with 117 additions and 26 deletions.
2 changes: 1 addition & 1 deletion app/src/main/java/com/dd3boh/outertune/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -361,7 +361,7 @@ class MainActivity : ComponentActivity() {
val (lookupYtmArtists) = rememberPreference(LookupYtmArtistsKey, defaultValue = true)
val (autoScan) = rememberPreference(AutomaticScannerKey, defaultValue = true)
LaunchedEffect(Unit) {
downloadUtil.resumeDownloadsOnStart(this@MainActivity)
downloadUtil.resumeDownloadsOnStart()

CoroutineScope(Dispatchers.IO).launch {
// Check if the permissions for local media access
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ val SlimNavBarKey = booleanPreferencesKey("slimNavBar")
*/
const val SYSTEM_DEFAULT = "SYSTEM_DEFAULT"
val YtmSyncKey = booleanPreferencesKey("ytmSync")
val LikedAutoDownloadKey = stringPreferencesKey("likedAutoDownloadKey")
val ContentLanguageKey = stringPreferencesKey("contentLanguage")
val ContentCountryKey = stringPreferencesKey("contentCountry")
val ProxyEnabledKey = booleanPreferencesKey("proxyEnabled")
Expand Down Expand Up @@ -202,6 +203,10 @@ enum class SearchSource {
LOCAL, ONLINE
}

enum class LikedAutodownloadMode {
OFF, ON, WIFI_ONLY
}

val VisitorDataKey = stringPreferencesKey("visitorData")
val InnerTubeCookieKey = stringPreferencesKey("innerTubeCookie")
val AccountNameKey = stringPreferencesKey("accountName")
Expand Down
3 changes: 3 additions & 0 deletions app/src/main/java/com/dd3boh/outertune/db/daos/SongsDao.kt
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ interface SongsDao {
@Query("SELECT count from playCount WHERE song = :songId AND year = :year AND month = :month")
fun getPlayCountByMonth(songId: String?, year: Int, month: Int): Flow<Int>

@Query("SELECT * FROM song WHERE liked AND dateDownload IS NULL")
fun likedSongsNotDownloaded(): Flow<List<Song>>

// region Songs Sort
@Query("SELECT * FROM song WHERE inLibrary IS NOT NULL ORDER BY rowId")
fun songsByRowIdAsc(): Flow<List<Song>>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package com.dd3boh.outertune.extensions
import android.content.Context
import com.dd3boh.outertune.constants.InnerTubeCookieKey
import com.dd3boh.outertune.constants.YtmSyncKey
import com.dd3boh.outertune.constants.LikedAutoDownloadKey
import com.dd3boh.outertune.constants.LikedAutodownloadMode
import com.dd3boh.outertune.utils.dataStore
import com.dd3boh.outertune.utils.get
import com.zionhuang.innertube.utils.parseCookieString
Expand All @@ -14,4 +16,8 @@ fun Context.isSyncEnabled(): Boolean {
val cookie = dataStore[InnerTubeCookieKey] ?: ""
ytmSync && "SAPISID" in parseCookieString(cookie)
}
}

fun Context.getLikeAutoDownload(): LikedAutodownloadMode {
return dataStore[LikedAutoDownloadKey].toEnum(LikedAutodownloadMode.OFF)
}
49 changes: 41 additions & 8 deletions app/src/main/java/com/dd3boh/outertune/playback/DownloadUtil.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.dd3boh.outertune.playback

import android.content.Context
import android.net.ConnectivityManager
import android.net.NetworkCapabilities
import androidx.core.content.getSystemService
import androidx.core.net.toUri
import androidx.media3.common.PlaybackException
Expand All @@ -16,8 +17,10 @@ import androidx.media3.exoplayer.offline.DownloadRequest
import androidx.media3.exoplayer.offline.DownloadService
import com.dd3boh.outertune.constants.AudioQuality
import com.dd3boh.outertune.constants.AudioQualityKey
import com.dd3boh.outertune.constants.LikedAutodownloadMode
import com.dd3boh.outertune.db.MusicDatabase
import com.dd3boh.outertune.db.entities.FormatEntity
import com.dd3boh.outertune.db.entities.SongEntity
import com.dd3boh.outertune.di.DownloadCache
import com.dd3boh.outertune.models.MediaMetadata
import com.dd3boh.outertune.utils.enumPreference
Expand All @@ -38,10 +41,11 @@ import java.time.ZoneOffset
import java.util.concurrent.Executor
import javax.inject.Inject
import javax.inject.Singleton
import com.dd3boh.outertune.extensions.getLikeAutoDownload

@Singleton
class DownloadUtil @Inject constructor(
@ApplicationContext context: Context,
@ApplicationContext private val context: Context,
val database: MusicDatabase,
val databaseProvider: DatabaseProvider,
@DownloadCache val downloadCache: SimpleCache,
Expand Down Expand Up @@ -123,17 +127,25 @@ class DownloadUtil @Inject constructor(
}
val downloads = MutableStateFlow<Map<String, Download>>(emptyMap())


fun getDownload(songId: String): Flow<Download?> = downloads.map { it[songId] }

fun download(songs: List<MediaMetadata>) {
songs.forEach { song -> downloadSong(song.id, song.title) }
}

fun download(song: MediaMetadata){
downloadSong(song.id, song.title)
}

fun download(songs: List<MediaMetadata>, context: Context) {
songs.forEach { song -> download(song, context) }
fun download(song: SongEntity){
downloadSong(song.id, song.title)
}

fun download(song: MediaMetadata, context: Context){
val downloadRequest = DownloadRequest.Builder(song.id, song.id.toUri())
.setCustomCacheKey(song.id)
.setData(song.title.toByteArray())
private fun downloadSong(id: String, title: String){
val downloadRequest = DownloadRequest.Builder(id, id.toUri())
.setCustomCacheKey(id)
.setData(title.toByteArray())
.build()
DownloadService.sendAddDownload(
context,
Expand All @@ -142,13 +154,34 @@ class DownloadUtil @Inject constructor(
false)
}

fun resumeDownloadsOnStart(context: Context){
fun resumeDownloadsOnStart(){
DownloadService.sendResumeDownloads(
context,
ExoDownloadService::class.java,
false)
}

fun autoDownloadIfLiked(songs: List<SongEntity>){
songs.forEach { song -> autoDownloadIfLiked(song) }
}

fun autoDownloadIfLiked(song: SongEntity){
if (!song.liked || song.dateDownload != null){
return
}

val isWifiConnected = connectivityManager.getNetworkCapabilities(connectivityManager.activeNetwork)
?.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) ?: false

if (
context.getLikeAutoDownload() == LikedAutodownloadMode.ON
|| (context.getLikeAutoDownload() == LikedAutodownloadMode.WIFI_ONLY && isWifiConnected)
)
{
download(song)
}
}

init {
val result = mutableMapOf<String, Download>()
val cursor = downloadManager.downloadIndex.getDownloads()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,9 @@ class MusicService : MediaLibraryService(),
@Inject
lateinit var database: MusicDatabase

@Inject
lateinit var downloadUtil: DownloadUtil

@Inject
lateinit var lyricsHelper: LyricsHelper

Expand Down Expand Up @@ -574,7 +577,9 @@ class MusicService : MediaLibraryService(),
fun toggleLike() {
database.query {
currentSong.value?.let {
update(it.song.toggleLike())
val song = it.song.toggleLike()
update(song)
downloadUtil.autoDownloadIfLiked(song)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,7 @@ fun AlbumMenu(
val _songs = songs
.filterNot { it.song.isLocal }
.map{ it.toMediaMetadata() }
downloadUtil.download(_songs, context)
downloadUtil.download(_songs)
},
onRemoveDownload = {
songs.forEach { song ->
Expand Down
10 changes: 6 additions & 4 deletions app/src/main/java/com/dd3boh/outertune/ui/menu/PlayerMenu.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ package com.dd3boh.outertune.ui.menu
import android.content.Intent
import android.text.format.Formatter
import android.widget.Toast
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Arrangement
Expand Down Expand Up @@ -117,7 +115,6 @@ fun PlayerMenu(
val playerVolume = playerConnection.service.playerVolume.collectAsState()
val currentFormat by playerConnection.currentFormat.collectAsState(initial = null)
val currentPlayCount by playerConnection.currentPlayCount.collectAsState(initial = null)
val activityResultLauncher = rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) { }
val librarySong by database.song(mediaMetadata.id).collectAsState(initial = null)
val coroutineScope = rememberCoroutineScope()

Expand All @@ -127,6 +124,12 @@ fun PlayerMenu(
mutableStateOf(false)
}

LaunchedEffect(librarySong?.song?.liked) {
librarySong?.let {
downloadUtil.autoDownloadIfLiked(it.song)
}
}

AddToQueueDialog(
isVisible = showChooseQueueDialog,
onAdd = { queueName ->
Expand Down Expand Up @@ -411,7 +414,6 @@ fun PlayerMenu(
database.transaction {
insert(mediaMetadata)
}
downloadUtil.download(mediaMetadata, context)
},
onRemoveDownload = {
DownloadService.sendRemoveDownload(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,7 @@ fun PlaylistMenu(
state = downloadState,
onDownload = {
val _songs = songs.filterNot { it.song.isLocal }.map{ it.toMediaMetadata() }
downloadUtil.download(_songs, context)
downloadUtil.download(_songs)
},
onRemoveDownload = {
showRemoveDownloadDialog = true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,9 @@ fun SelectionMediaMetadataMenu(
}
} else {
selection.forEach { song ->
update(song.toSongEntity().copy(liked = true))
val likedSong = song.toSongEntity().copy(liked = true)
update(likedSong)
downloadUtil.autoDownloadIfLiked(likedSong)
}
}
}
Expand All @@ -264,7 +266,7 @@ fun SelectionMediaMetadataMenu(
state = downloadState,
onDownload = {
val songs = selection.filterNot { it.isLocal }
downloadUtil.download(songs, context)
downloadUtil.download(songs)
},
onRemoveDownload = {
showRemoveDownloadDialog = true
Expand Down
7 changes: 6 additions & 1 deletion app/src/main/java/com/dd3boh/outertune/ui/menu/SongMenu.kt
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
Expand Down Expand Up @@ -100,6 +101,10 @@ fun SongMenu(
mutableStateOf(false)
}

LaunchedEffect(song.song.liked) {
downloadUtil.autoDownloadIfLiked(song.song)
}

if (showEditDialog) {
TextFieldDialog(
icon = { Icon(imageVector = Icons.Rounded.Edit, contentDescription = null) },
Expand Down Expand Up @@ -289,7 +294,7 @@ fun SongMenu(
DownloadGridMenu(
state = download?.state,
onDownload = {
downloadUtil.download(song.toMediaMetadata(), context)
downloadUtil.download(song.toMediaMetadata())
},
onRemoveDownload = {
DownloadService.sendRemoveDownload(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ fun YouTubeAlbumMenu(
state = downloadState,
onDownload = {
val _songs = album?.songs?.map{ it.toMediaMetadata() } ?: emptyList()
downloadUtil.download(_songs, context)
downloadUtil.download(_songs)
},
onRemoveDownload = {
album?.songs?.forEach { song ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -335,7 +335,7 @@ fun YouTubePlaylistMenu(
state = downloadState,
onDownload = {
val _songs = songs.map{ it.toMediaMetadata() }
downloadUtil.download(_songs, context)
downloadUtil.download(_songs)
},
onRemoveDownload = {
showRemoveDownloadDialog = true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
Expand Down Expand Up @@ -99,6 +100,12 @@ fun YouTubeSongMenu(
mutableStateOf(false)
}

LaunchedEffect(librarySong?.song?.liked) {
librarySong?.let {
downloadUtil.autoDownloadIfLiked(it.song)
}
}

AddToQueueDialog(
isVisible = showChooseQueueDialog,
onAdd = { queueName ->
Expand Down Expand Up @@ -258,7 +265,7 @@ fun YouTubeSongMenu(
database.transaction {
insert(song.toMediaMetadata())
}
downloadUtil.download(song.toMediaMetadata(), context)
downloadUtil.download(song.toMediaMetadata())
},
onRemoveDownload = {
DownloadService.sendRemoveDownload(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,7 @@ fun AlbumScreen(
IconButton(
onClick = {
val songs = albumWithSongsLocal.songs.map{ it.toMediaMetadata() }
downloadUtil.download(songs, context)
downloadUtil.download(songs)
}
) {
Icon(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -382,7 +382,7 @@ fun AutoPlaylistScreen(
IconButton(
onClick = {
val _songs = songs.map{ it.toMediaMetadata() }
downloadUtil.download(_songs, context)
downloadUtil.download(_songs)
}
) {
Icon(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -387,7 +387,7 @@ fun OnlinePlaylistScreen(
syncUtils.syncPlaylist(playlist.id, dbPlaylist!!.id)
}
val _songs = songs.map{ it.toMediaMetadata() }
downloadUtil.download(_songs, context)
downloadUtil.download(_songs)
}
) {
Icon(
Expand Down
Loading

0 comments on commit 427b231

Please sign in to comment.