/* * TrackCollectionModel.kt * Copyright (C) 2009-2021 Ultrasonic developers * * Distributed under terms of the GNU GPLv3 license. */ package org.moire.ultrasonic.fragment import android.app.Application import android.os.Bundle import androidx.lifecycle.MutableLiveData import java.util.LinkedList import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import org.moire.ultrasonic.R import org.moire.ultrasonic.domain.MusicDirectory import org.moire.ultrasonic.service.MusicService import org.moire.ultrasonic.service.MusicServiceFactory import org.moire.ultrasonic.util.Settings import org.moire.ultrasonic.util.Util /* * Model for retrieving different collections of tracks from the API * TODO: Refactor this model to extend the GenericListModel */ class TrackCollectionModel(application: Application) : GenericListModel(application) { private val allSongsId = "-1" val currentDirectory: MutableLiveData = MutableLiveData() val songsForGenre: MutableLiveData = MutableLiveData() suspend fun getMusicFolders(refresh: Boolean) { withContext(Dispatchers.IO) { if (!isOffline()) { val musicService = MusicServiceFactory.getMusicService() musicFolders.postValue(musicService.getMusicFolders(refresh)) } } } suspend fun getMusicDirectory( refresh: Boolean, id: String, name: String?, parentId: String? ) { withContext(Dispatchers.IO) { val service = MusicServiceFactory.getMusicService() var root = MusicDirectory() if (allSongsId == id && parentId != null) { val musicDirectory = service.getMusicDirectory( parentId, name, refresh ) val songs: MutableList = LinkedList() getSongsRecursively(musicDirectory, songs) for (song in songs) { if (!song.isDirectory) { root.addChild(song) } } } else { val musicDirectory = service.getMusicDirectory(id, name, refresh) if (Settings.shouldShowAllSongsByArtist && musicDirectory.findChild(allSongsId) == null && hasOnlyFolders(musicDirectory) ) { val allSongs = MusicDirectory.Entry(allSongsId) allSongs.isDirectory = true allSongs.artist = name allSongs.parent = id allSongs.title = String.format( context.resources.getString(R.string.select_album_all_songs), name ) root.addChild(allSongs) root.addAll(musicDirectory.getChildren()) } else { root = musicDirectory } } currentDirectory.postValue(root) } } // Given a Music directory "songs" it recursively adds all children to "songs" private fun getSongsRecursively( parent: MusicDirectory, songs: MutableList ) { val service = MusicServiceFactory.getMusicService() for (song in parent.getChildren(includeDirs = false, includeFiles = true)) { if (!song.isVideo && !song.isDirectory) { songs.add(song) } } for ((id1, _, _, title) in parent.getChildren(true, includeFiles = false)) { var root: MusicDirectory if (allSongsId != id1) { root = service.getMusicDirectory(id1, title, false) getSongsRecursively(root, songs) } } } /* * TODO: This method should be moved to AlbumListModel, * since it displays a list of albums by a specified artist. */ suspend fun getArtist(refresh: Boolean, id: String, name: String?) { withContext(Dispatchers.IO) { val service = MusicServiceFactory.getMusicService() var root = MusicDirectory() val musicDirectory = service.getArtist(id, name, refresh) if (Settings.shouldShowAllSongsByArtist && musicDirectory.findChild(allSongsId) == null && hasOnlyFolders(musicDirectory) ) { val allSongs = MusicDirectory.Entry(allSongsId) allSongs.isDirectory = true allSongs.artist = name allSongs.parent = id allSongs.title = String.format( context.resources.getString(R.string.select_album_all_songs), name ) root.addFirst(allSongs) root.addAll(musicDirectory.getChildren()) } else { root = musicDirectory } currentDirectory.postValue(root) } } suspend fun getAlbum(refresh: Boolean, id: String, name: String?, parentId: String?) { withContext(Dispatchers.IO) { val service = MusicServiceFactory.getMusicService() val musicDirectory: MusicDirectory if (allSongsId == id && parentId != null) { val root = MusicDirectory() val songs: MutableCollection = LinkedList() val artist = service.getArtist(parentId, "", false) for ((id1) in artist.getChildren()) { if (allSongsId != id1) { val albumDirectory = service.getAlbum( id1, "", false ) for (song in albumDirectory.getChildren()) { if (!song.isVideo) { songs.add(song) } } } } for (song in songs) { if (!song.isDirectory) { root.addChild(song) } } musicDirectory = root } else { musicDirectory = service.getAlbum(id, name, refresh) } currentDirectory.postValue(musicDirectory) } } suspend fun getSongsForGenre(genre: String, count: Int, offset: Int) { withContext(Dispatchers.IO) { val service = MusicServiceFactory.getMusicService() val musicDirectory = service.getSongsByGenre(genre, count, offset) songsForGenre.postValue(musicDirectory) } } suspend fun getStarred() { withContext(Dispatchers.IO) { val service = MusicServiceFactory.getMusicService() val musicDirectory: MusicDirectory if (Settings.shouldUseId3Tags) { musicDirectory = Util.getSongsFromSearchResult(service.getStarred2()) } else { musicDirectory = Util.getSongsFromSearchResult(service.getStarred()) } currentDirectory.postValue(musicDirectory) } } suspend fun getVideos(refresh: Boolean) { showHeader = false withContext(Dispatchers.IO) { val service = MusicServiceFactory.getMusicService() currentDirectory.postValue(service.getVideos(refresh)) } } suspend fun getRandom(size: Int) { withContext(Dispatchers.IO) { val service = MusicServiceFactory.getMusicService() val musicDirectory = service.getRandomSongs(size) currentListIsSortable = false currentDirectory.postValue(musicDirectory) } } suspend fun getPlaylist(playlistId: String, playlistName: String) { withContext(Dispatchers.IO) { val service = MusicServiceFactory.getMusicService() val musicDirectory = service.getPlaylist(playlistId, playlistName) currentDirectory.postValue(musicDirectory) } } suspend fun getPodcastEpisodes(podcastChannelId: String) { withContext(Dispatchers.IO) { val service = MusicServiceFactory.getMusicService() val musicDirectory = service.getPodcastEpisodes(podcastChannelId) currentDirectory.postValue(musicDirectory) } } suspend fun getShare(shareId: String) { withContext(Dispatchers.IO) { val service = MusicServiceFactory.getMusicService() val musicDirectory = MusicDirectory() val shares = service.getShares(true) for (share in shares) { if (share.id == shareId) { for (entry in share.getEntries()) { musicDirectory.addChild(entry) } break } } currentDirectory.postValue(musicDirectory) } } // Returns true if the directory contains only folders private fun hasOnlyFolders(musicDirectory: MusicDirectory) = musicDirectory.getChildren(includeDirs = true, includeFiles = false).size == musicDirectory.getChildren(includeDirs = true, includeFiles = true).size override fun load( isOffline: Boolean, useId3Tags: Boolean, musicService: MusicService, refresh: Boolean, args: Bundle ) { // See To_Do at the top } }