feat: Implemented search functionality for Android Auto, "Made for You" section, starred songs, albums, artists, podcasts, and radio

This commit is contained in:
antonio 2024-01-03 12:23:46 +01:00
parent d6cc4fc028
commit 68512b7e12
4 changed files with 243 additions and 111 deletions

View file

@ -7,6 +7,7 @@ import androidx.media3.common.MediaItem
import androidx.media3.common.MediaItem.RequestMetadata import androidx.media3.common.MediaItem.RequestMetadata
import androidx.media3.common.MediaMetadata import androidx.media3.common.MediaMetadata
import androidx.media3.common.MimeTypes import androidx.media3.common.MimeTypes
import androidx.media3.common.util.UnstableApi
import androidx.room.ColumnInfo import androidx.room.ColumnInfo
import androidx.room.Entity import androidx.room.Entity
import androidx.room.PrimaryKey import androidx.room.PrimaryKey
@ -19,6 +20,7 @@ import com.cappielloantonio.tempo.util.MusicUtil
import com.cappielloantonio.tempo.util.Preferences.getImageSize import com.cappielloantonio.tempo.util.Preferences.getImageSize
import java.util.Date import java.util.Date
@UnstableApi
@Keep @Keep
@Entity(tableName = "session_media_item") @Entity(tableName = "session_media_item")
class SessionMediaItem() { class SessionMediaItem() {

View file

@ -4,8 +4,10 @@ package com.cappielloantonio.tempo.repository;
import android.net.Uri; import android.net.Uri;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.OptIn;
import androidx.media3.common.MediaItem; import androidx.media3.common.MediaItem;
import androidx.media3.common.MediaMetadata; import androidx.media3.common.MediaMetadata;
import androidx.media3.common.util.UnstableApi;
import androidx.media3.session.LibraryResult; import androidx.media3.session.LibraryResult;
import com.cappielloantonio.tempo.App; import com.cappielloantonio.tempo.App;
@ -183,7 +185,7 @@ public class AutomotiveRepository {
return listenableFuture; return listenableFuture;
} }
public ListenableFuture<LibraryResult<ImmutableList<MediaItem>>> getStarredArtists(String prefix, boolean playFromThere) { public ListenableFuture<LibraryResult<ImmutableList<MediaItem>>> getStarredArtists(String prefix) {
final SettableFuture<LibraryResult<ImmutableList<MediaItem>>> listenableFuture = SettableFuture.create(); final SettableFuture<LibraryResult<ImmutableList<MediaItem>>> listenableFuture = SettableFuture.create();
App.getSubsonicClientInstance(false) App.getSubsonicClientInstance(false)
@ -195,6 +197,8 @@ public class AutomotiveRepository {
if (response.isSuccessful() && response.body() != null && response.body().getSubsonicResponse().getStarred2() != null && response.body().getSubsonicResponse().getStarred2().getArtists() != null) { if (response.isSuccessful() && response.body() != null && response.body().getSubsonicResponse().getStarred2() != null && response.body().getSubsonicResponse().getStarred2().getArtists() != null) {
List<ArtistID3> artists = response.body().getSubsonicResponse().getStarred2().getArtists(); List<ArtistID3> artists = response.body().getSubsonicResponse().getStarred2().getArtists();
Collections.shuffle(artists);
List<MediaItem> mediaItems = new ArrayList<>(); List<MediaItem> mediaItems = new ArrayList<>();
for (ArtistID3 artist : artists) { for (ArtistID3 artist : artists) {
@ -202,8 +206,8 @@ public class AutomotiveRepository {
MediaMetadata mediaMetadata = new MediaMetadata.Builder() MediaMetadata mediaMetadata = new MediaMetadata.Builder()
.setTitle(artist.getName()) .setTitle(artist.getName())
.setIsBrowsable(!playFromThere) .setIsBrowsable(true)
.setIsPlayable(playFromThere) .setIsPlayable(false)
.setMediaType(MediaMetadata.MEDIA_TYPE_PLAYLIST) .setMediaType(MediaMetadata.MEDIA_TYPE_PLAYLIST)
.setArtworkUri(artworkUri) .setArtworkUri(artworkUri)
.build(); .build();
@ -461,7 +465,7 @@ public class AutomotiveRepository {
return listenableFuture; return listenableFuture;
} }
public ListenableFuture<LibraryResult<ImmutableList<MediaItem>>> getNewestPodcastEpisodes(String prefix, int count) { public ListenableFuture<LibraryResult<ImmutableList<MediaItem>>> getNewestPodcastEpisodes(int count) {
final SettableFuture<LibraryResult<ImmutableList<MediaItem>>> listenableFuture = SettableFuture.create(); final SettableFuture<LibraryResult<ImmutableList<MediaItem>>> listenableFuture = SettableFuture.create();
App.getSubsonicClientInstance(false) App.getSubsonicClientInstance(false)
@ -487,7 +491,7 @@ public class AutomotiveRepository {
.build(); .build();
MediaItem mediaItem = new MediaItem.Builder() MediaItem mediaItem = new MediaItem.Builder()
.setMediaId(prefix + episode.getId()) .setMediaId(episode.getId())
.setMediaMetadata(mediaMetadata) .setMediaMetadata(mediaMetadata)
.setUri(MusicUtil.getStreamUri(episode.getStreamId())) .setUri(MusicUtil.getStreamUri(episode.getStreamId()))
.build(); .build();
@ -514,7 +518,7 @@ public class AutomotiveRepository {
return listenableFuture; return listenableFuture;
} }
public ListenableFuture<LibraryResult<ImmutableList<MediaItem>>> getInternetRadioStations(String prefix) { public ListenableFuture<LibraryResult<ImmutableList<MediaItem>>> getInternetRadioStations() {
final SettableFuture<LibraryResult<ImmutableList<MediaItem>>> listenableFuture = SettableFuture.create(); final SettableFuture<LibraryResult<ImmutableList<MediaItem>>> listenableFuture = SettableFuture.create();
App.getSubsonicClientInstance(false) App.getSubsonicClientInstance(false)
@ -538,7 +542,7 @@ public class AutomotiveRepository {
.build(); .build();
MediaItem mediaItem = new MediaItem.Builder() MediaItem mediaItem = new MediaItem.Builder()
.setMediaId(prefix + radioStation.getId()) .setMediaId(radioStation.getId())
.setMediaMetadata(mediaMetadata) .setMediaMetadata(mediaMetadata)
.setUri(radioStation.getStreamUrl()) .setUri(radioStation.getStreamUrl())
.build(); .build();
@ -575,7 +579,6 @@ public class AutomotiveRepository {
@Override @Override
public void onResponse(@NonNull Call<ApiResponse> call, @NonNull Response<ApiResponse> response) { public void onResponse(@NonNull Call<ApiResponse> call, @NonNull Response<ApiResponse> response) {
if (response.isSuccessful() && response.body() != null && response.body().getSubsonicResponse().getAlbum() != null && response.body().getSubsonicResponse().getAlbum().getSongs() != null) { if (response.isSuccessful() && response.body() != null && response.body().getSubsonicResponse().getAlbum() != null && response.body().getSubsonicResponse().getAlbum().getSongs() != null) {
List<Child> tracks = response.body().getSubsonicResponse().getAlbum().getSongs(); List<Child> tracks = response.body().getSubsonicResponse().getAlbum().getSongs();
setChildrenMetadata(tracks); setChildrenMetadata(tracks);
@ -599,6 +602,58 @@ public class AutomotiveRepository {
return listenableFuture; return listenableFuture;
} }
public ListenableFuture<LibraryResult<ImmutableList<MediaItem>>> getArtistAlbum(String prefix, String id) {
final SettableFuture<LibraryResult<ImmutableList<MediaItem>>> listenableFuture = SettableFuture.create();
App.getSubsonicClientInstance(false)
.getBrowsingClient()
.getArtist(id)
.enqueue(new Callback<ApiResponse>() {
@Override
public void onResponse(@NonNull Call<ApiResponse> call, @NonNull Response<ApiResponse> response) {
if (response.isSuccessful() && response.body() != null && response.body().getSubsonicResponse().getArtist() != null && response.body().getSubsonicResponse().getArtist().getAlbums() != null) {
List<AlbumID3> albums = response.body().getSubsonicResponse().getArtist().getAlbums();
List<MediaItem> mediaItems = new ArrayList<>();
for (AlbumID3 album : albums) {
Uri artworkUri = Uri.parse(CustomGlideRequest.createUrl(album.getCoverArtId(), Preferences.getImageSize()));
MediaMetadata mediaMetadata = new MediaMetadata.Builder()
.setTitle(album.getName())
.setAlbumTitle(album.getName())
.setArtist(album.getArtist())
.setGenre(album.getGenre())
.setIsBrowsable(true)
.setIsPlayable(false)
.setMediaType(MediaMetadata.MEDIA_TYPE_ALBUM)
.setArtworkUri(artworkUri)
.build();
MediaItem mediaItem = new MediaItem.Builder()
.setMediaId(prefix + album.getId())
.setMediaMetadata(mediaMetadata)
.setUri("")
.build();
mediaItems.add(mediaItem);
}
LibraryResult<ImmutableList<MediaItem>> libraryResult = LibraryResult.ofItemList(ImmutableList.copyOf(mediaItems), null);
listenableFuture.set(libraryResult);
}
}
@Override
public void onFailure(@NonNull Call<ApiResponse> call, @NonNull Throwable t) {
listenableFuture.setException(t);
}
});
return listenableFuture;
}
public ListenableFuture<LibraryResult<ImmutableList<MediaItem>>> getPlaylistSongs(String id) { public ListenableFuture<LibraryResult<ImmutableList<MediaItem>>> getPlaylistSongs(String id) {
final SettableFuture<LibraryResult<ImmutableList<MediaItem>>> listenableFuture = SettableFuture.create(); final SettableFuture<LibraryResult<ImmutableList<MediaItem>>> listenableFuture = SettableFuture.create();
@ -630,6 +685,118 @@ public class AutomotiveRepository {
return listenableFuture; return listenableFuture;
} }
public ListenableFuture<LibraryResult<ImmutableList<MediaItem>>> getMadeForYou(String id, int count) {
final SettableFuture<LibraryResult<ImmutableList<MediaItem>>> listenableFuture = SettableFuture.create();
App.getSubsonicClientInstance(false)
.getBrowsingClient()
.getSimilarSongs2(id, count)
.enqueue(new Callback<ApiResponse>() {
@Override
public void onResponse(@NonNull Call<ApiResponse> call, @NonNull Response<ApiResponse> response) {
if (response.isSuccessful() && response.body() != null && response.body().getSubsonicResponse().getSimilarSongs2() != null && response.body().getSubsonicResponse().getSimilarSongs2().getSongs() != null) {
List<Child> tracks = response.body().getSubsonicResponse().getSimilarSongs2().getSongs();
setChildrenMetadata(tracks);
List<MediaItem> mediaItems = MappingUtil.mapMediaItems(tracks);
LibraryResult<ImmutableList<MediaItem>> libraryResult = LibraryResult.ofItemList(ImmutableList.copyOf(mediaItems), null);
listenableFuture.set(libraryResult);
}
}
@Override
public void onFailure(@NonNull Call<ApiResponse> call, @NonNull Throwable t) {
listenableFuture.setException(t);
}
});
return listenableFuture;
}
public ListenableFuture<LibraryResult<ImmutableList<MediaItem>>> search(String query, String albumPrefix, String artistPrefix) {
final SettableFuture<LibraryResult<ImmutableList<MediaItem>>> listenableFuture = SettableFuture.create();
App.getSubsonicClientInstance(false)
.getSearchingClient()
.search3(query, 20, 20, 20)
.enqueue(new Callback<ApiResponse>() {
@Override
public void onResponse(@NonNull Call<ApiResponse> call, @NonNull Response<ApiResponse> response) {
if (response.isSuccessful() && response.body() != null && response.body().getSubsonicResponse().getSearchResult3() != null) {
List<MediaItem> mediaItems = new ArrayList<>();
if (response.body().getSubsonicResponse().getSearchResult3().getArtists() != null) {
for (ArtistID3 artist : response.body().getSubsonicResponse().getSearchResult3().getArtists()) {
Uri artworkUri = Uri.parse(CustomGlideRequest.createUrl(artist.getCoverArtId(), Preferences.getImageSize()));
MediaMetadata mediaMetadata = new MediaMetadata.Builder()
.setTitle(artist.getName())
.setIsBrowsable(true)
.setIsPlayable(false)
.setMediaType(MediaMetadata.MEDIA_TYPE_PLAYLIST)
.setArtworkUri(artworkUri)
.build();
MediaItem mediaItem = new MediaItem.Builder()
.setMediaId(artistPrefix + artist.getId())
.setMediaMetadata(mediaMetadata)
.setUri("")
.build();
mediaItems.add(mediaItem);
}
}
if (response.body().getSubsonicResponse().getSearchResult3().getAlbums() != null) {
for (AlbumID3 album : response.body().getSubsonicResponse().getSearchResult3().getAlbums()) {
Uri artworkUri = Uri.parse(CustomGlideRequest.createUrl(album.getCoverArtId(), Preferences.getImageSize()));
MediaMetadata mediaMetadata = new MediaMetadata.Builder()
.setTitle(album.getName())
.setAlbumTitle(album.getName())
.setArtist(album.getArtist())
.setGenre(album.getGenre())
.setIsBrowsable(true)
.setIsPlayable(false)
.setMediaType(MediaMetadata.MEDIA_TYPE_ALBUM)
.setArtworkUri(artworkUri)
.build();
MediaItem mediaItem = new MediaItem.Builder()
.setMediaId(albumPrefix + album.getId())
.setMediaMetadata(mediaMetadata)
.setUri("")
.build();
mediaItems.add(mediaItem);
}
}
if (response.body().getSubsonicResponse().getSearchResult3().getSongs() != null) {
List<Child> tracks = response.body().getSubsonicResponse().getSearchResult3().getSongs();
setChildrenMetadata(tracks);
mediaItems.addAll(MappingUtil.mapMediaItems(tracks));
}
LibraryResult<ImmutableList<MediaItem>> libraryResult = LibraryResult.ofItemList(ImmutableList.copyOf(mediaItems), null);
listenableFuture.set(libraryResult);
}
}
@Override
public void onFailure(@NonNull Call<ApiResponse> call, @NonNull Throwable t) {
listenableFuture.setException(t);
}
});
return listenableFuture;
}
@OptIn(markerClass = UnstableApi.class)
public void setChildrenMetadata(List<Child> children) { public void setChildrenMetadata(List<Child> children) {
long timestamp = System.currentTimeMillis(); long timestamp = System.currentTimeMillis();
ArrayList<SessionMediaItem> sessionMediaItems = new ArrayList<>(); ArrayList<SessionMediaItem> sessionMediaItems = new ArrayList<>();
@ -645,6 +812,7 @@ public class AutomotiveRepository {
thread.start(); thread.start();
} }
@OptIn(markerClass = UnstableApi.class)
public void setPodcastEpisodesMetadata(List<PodcastEpisode> podcastEpisodes) { public void setPodcastEpisodesMetadata(List<PodcastEpisode> podcastEpisodes) {
long timestamp = System.currentTimeMillis(); long timestamp = System.currentTimeMillis();
ArrayList<SessionMediaItem> sessionMediaItems = new ArrayList<>(); ArrayList<SessionMediaItem> sessionMediaItems = new ArrayList<>();
@ -660,6 +828,7 @@ public class AutomotiveRepository {
thread.start(); thread.start();
} }
@OptIn(markerClass = UnstableApi.class)
public void setInternetRadioStationsMetadata(List<InternetRadioStation> internetRadioStations) { public void setInternetRadioStationsMetadata(List<InternetRadioStation> internetRadioStations) {
long timestamp = System.currentTimeMillis(); long timestamp = System.currentTimeMillis();
ArrayList<SessionMediaItem> sessionMediaItems = new ArrayList<>(); ArrayList<SessionMediaItem> sessionMediaItems = new ArrayList<>();
@ -736,11 +905,11 @@ public class AutomotiveRepository {
} }
} }
@OptIn(markerClass = UnstableApi.class)
private static class GetMediaItemsThreadSafe implements Runnable { private static class GetMediaItemsThreadSafe implements Runnable {
private final SessionMediaItemDao sessionMediaItemDao; private final SessionMediaItemDao sessionMediaItemDao;
private final Long timestamp; private final Long timestamp;
private final List<MediaItem> mediaItems = new ArrayList<>();
private List<MediaItem> mediaItems = new ArrayList<>();
public GetMediaItemsThreadSafe(SessionMediaItemDao sessionMediaItemDao, Long timestamp) { public GetMediaItemsThreadSafe(SessionMediaItemDao sessionMediaItemDao, Long timestamp) {
this.sessionMediaItemDao = sessionMediaItemDao; this.sessionMediaItemDao = sessionMediaItemDao;
@ -758,43 +927,6 @@ public class AutomotiveRepository {
} }
} }
/* private static class InsertThreadSafe implements Runnable {
private final SessionMediaItemDao sessionMediaItemDao;
private final List<Child> children;
private final List<PodcastEpisode> podcastEpisodes;
private final List<InternetRadioStation> internetRadioStations;
private final long timestamp;
public InsertThreadSafe(SessionMediaItemDao sessionMediaItemDao, List<Child> children, List<PodcastEpisode> podcastEpisodes, List<InternetRadioStation> internetRadioStations, long timestamp) {
this.sessionMediaItemDao = sessionMediaItemDao;
this.children = children;
this.podcastEpisodes = podcastEpisodes;
this.internetRadioStations = internetRadioStations;
this.timestamp = timestamp;
}
@Override
public void run() {
if (children != null) {
SessionMediaItem sessionMediaItem = new SessionMediaItem(children);
sessionMediaItem.setTimestamp(timestamp);
sessionMediaItemDao.insert(sessionMediaItem);
}
if (podcastEpisodes != null) {
SessionMediaItem sessionMediaItem = new SessionMediaItem(podcastEpisodes);
sessionMediaItem.setTimestamp(timestamp);
sessionMediaItemDao.insert(sessionMediaItem);
}
if (internetRadioStations != null) {
SessionMediaItem sessionMediaItem = new SessionMediaItem(internetRadioStations);
sessionMediaItem.setTimestamp(timestamp);
sessionMediaItemDao.insert(sessionMediaItem);
}
}
} */
private static class InsertAllThreadSafe implements Runnable { private static class InsertAllThreadSafe implements Runnable {
private final SessionMediaItemDao sessionMediaItemDao; private final SessionMediaItemDao sessionMediaItemDao;
private final List<SessionMediaItem> sessionMediaItems; private final List<SessionMediaItem> sessionMediaItems;

View file

@ -1,20 +1,15 @@
package com.cappielloantonio.tempo.service package com.cappielloantonio.tempo.service
import android.content.Context
import android.net.Uri import android.net.Uri
import android.util.Log
import androidx.media3.common.MediaItem import androidx.media3.common.MediaItem
import androidx.media3.common.MediaItem.SubtitleConfiguration import androidx.media3.common.MediaItem.SubtitleConfiguration
import androidx.media3.common.MediaMetadata import androidx.media3.common.MediaMetadata
import androidx.media3.session.LibraryResult import androidx.media3.session.LibraryResult
import androidx.media3.session.MediaLibraryService
import com.cappielloantonio.tempo.model.SessionMediaItem
import com.cappielloantonio.tempo.repository.AutomotiveRepository import com.cappielloantonio.tempo.repository.AutomotiveRepository
import com.google.common.collect.ImmutableList import com.google.common.collect.ImmutableList
import com.google.common.util.concurrent.Futures import com.google.common.util.concurrent.Futures
import com.google.common.util.concurrent.ListenableFuture import com.google.common.util.concurrent.ListenableFuture
import com.google.common.util.concurrent.SettableFuture import com.google.common.util.concurrent.SettableFuture
import java.lang.Exception
object MediaBrowserTree { object MediaBrowserTree {
@ -36,7 +31,6 @@ object MediaBrowserTree {
private const val MOST_PLAYED_ID = "[mostPlayedID]" private const val MOST_PLAYED_ID = "[mostPlayedID]"
private const val LAST_PLAYED_ID = "[lastPlayedID]" private const val LAST_PLAYED_ID = "[lastPlayedID]"
private const val RECENTLY_ADDED_ID = "[recentlyAddedID]" private const val RECENTLY_ADDED_ID = "[recentlyAddedID]"
private const val BEST_OF_ID = "[bestOfID]"
private const val MADE_FOR_YOU_ID = "[madeForYouID]" private const val MADE_FOR_YOU_ID = "[madeForYouID]"
private const val STARRED_TRACKS_ID = "[starredTracksID]" private const val STARRED_TRACKS_ID = "[starredTracksID]"
private const val STARRED_ALBUMS_ID = "[starredAlbumsID]" private const val STARRED_ALBUMS_ID = "[starredAlbumsID]"
@ -51,7 +45,9 @@ object MediaBrowserTree {
// Second level OTHER_ID // Second level OTHER_ID
private const val PODCAST_ID = "[podcastID]" private const val PODCAST_ID = "[podcastID]"
private const val RADIO_ID = "[radioID]" private const val RADIO_ID = "[radioID]"
private const val DOWNLOAD_ID = "[downloadID]"
private const val ALBUM_ID = "[albumID]"
private const val ARTIST_ID = "[artistID]"
private class MediaItemNode(val item: MediaItem) { private class MediaItemNode(val item: MediaItem) {
private val children: MutableList<MediaItem> = ArrayList() private val children: MutableList<MediaItem> = ArrayList()
@ -103,7 +99,7 @@ object MediaBrowserTree {
.build() .build()
} }
fun initialize(context: Context, automotiveRepository: AutomotiveRepository) { fun initialize(automotiveRepository: AutomotiveRepository) {
this.automotiveRepository = automotiveRepository this.automotiveRepository = automotiveRepository
if (isInitialized) return if (isInitialized) return
@ -197,17 +193,6 @@ object MediaBrowserTree {
) )
) )
treeNodes[BEST_OF_ID] =
MediaItemNode(
buildMediaItem(
title = "Best of",
mediaId = BEST_OF_ID,
isPlayable = false,
isBrowsable = true,
mediaType = MediaMetadata.MEDIA_TYPE_FOLDER_PLAYLISTS
)
)
treeNodes[MADE_FOR_YOU_ID] = treeNodes[MADE_FOR_YOU_ID] =
MediaItemNode( MediaItemNode(
buildMediaItem( buildMediaItem(
@ -255,11 +240,10 @@ object MediaBrowserTree {
treeNodes[HOME_ID]!!.addChild(MOST_PLAYED_ID) treeNodes[HOME_ID]!!.addChild(MOST_PLAYED_ID)
treeNodes[HOME_ID]!!.addChild(LAST_PLAYED_ID) treeNodes[HOME_ID]!!.addChild(LAST_PLAYED_ID)
treeNodes[HOME_ID]!!.addChild(RECENTLY_ADDED_ID) treeNodes[HOME_ID]!!.addChild(RECENTLY_ADDED_ID)
treeNodes[HOME_ID]!!.addChild(BEST_OF_ID)
treeNodes[HOME_ID]!!.addChild(MADE_FOR_YOU_ID) treeNodes[HOME_ID]!!.addChild(MADE_FOR_YOU_ID)
// treeNodes[HOME_ID]!!.addChild(STARRED_TRACKS_ID) treeNodes[HOME_ID]!!.addChild(STARRED_TRACKS_ID)
// treeNodes[HOME_ID]!!.addChild(STARRED_ALBUMS_ID) treeNodes[HOME_ID]!!.addChild(STARRED_ALBUMS_ID)
// treeNodes[HOME_ID]!!.addChild(STARRED_ARTISTS_ID) treeNodes[HOME_ID]!!.addChild(STARRED_ARTISTS_ID)
// Second level LIBRARY_ID // Second level LIBRARY_ID
@ -312,20 +296,8 @@ object MediaBrowserTree {
) )
) )
treeNodes[DOWNLOAD_ID] =
MediaItemNode(
buildMediaItem(
title = "Downloads",
mediaId = DOWNLOAD_ID,
isPlayable = false,
isBrowsable = true,
mediaType = MediaMetadata.MEDIA_TYPE_FOLDER_RADIO_STATIONS
)
)
treeNodes[OTHER_ID]!!.addChild(PODCAST_ID) treeNodes[OTHER_ID]!!.addChild(PODCAST_ID)
treeNodes[OTHER_ID]!!.addChild(RADIO_ID) treeNodes[OTHER_ID]!!.addChild(RADIO_ID)
// treeNodes[OTHER_ID]!!.addChild(DOWNLOAD_ID)
} }
fun getRootItem(): MediaItem { fun getRootItem(): MediaItem {
@ -333,8 +305,7 @@ object MediaBrowserTree {
} }
fun getChildren( fun getChildren(
id: String, id: String
params: MediaLibraryService.LibraryParams?
): ListenableFuture<LibraryResult<ImmutableList<MediaItem>>> { ): ListenableFuture<LibraryResult<ImmutableList<MediaItem>>> {
return when (id) { return when (id) {
ROOT_ID -> treeNodes[ROOT_ID]?.getChildren()!! ROOT_ID -> treeNodes[ROOT_ID]?.getChildren()!!
@ -345,17 +316,14 @@ object MediaBrowserTree {
MOST_PLAYED_ID -> automotiveRepository.getAlbums(id, "frequent", 100) MOST_PLAYED_ID -> automotiveRepository.getAlbums(id, "frequent", 100)
LAST_PLAYED_ID -> automotiveRepository.getAlbums(id, "recent", 100) LAST_PLAYED_ID -> automotiveRepository.getAlbums(id, "recent", 100)
RECENTLY_ADDED_ID -> automotiveRepository.getAlbums(id, "newest", 100) RECENTLY_ADDED_ID -> automotiveRepository.getAlbums(id, "newest", 100)
BEST_OF_ID -> automotiveRepository.getStarredArtists(id, true) MADE_FOR_YOU_ID -> automotiveRepository.getStarredArtists(id)
MADE_FOR_YOU_ID -> automotiveRepository.getStarredArtists(id, true)
STARRED_TRACKS_ID -> automotiveRepository.starredSongs STARRED_TRACKS_ID -> automotiveRepository.starredSongs
STARRED_ALBUMS_ID -> automotiveRepository.getStarredAlbums(id) STARRED_ALBUMS_ID -> automotiveRepository.getStarredAlbums(id)
STARRED_ARTISTS_ID -> automotiveRepository.getStarredArtists(id, false) STARRED_ARTISTS_ID -> automotiveRepository.getStarredArtists(id)
FOLDER_ID -> automotiveRepository.getMusicFolders(id) FOLDER_ID -> automotiveRepository.getMusicFolders(id)
PLAYLIST_ID -> automotiveRepository.getPlaylists(id) PLAYLIST_ID -> automotiveRepository.getPlaylists(id)
PODCAST_ID -> automotiveRepository.getNewestPodcastEpisodes(id, 100) PODCAST_ID -> automotiveRepository.getNewestPodcastEpisodes(100)
RADIO_ID -> automotiveRepository.getInternetRadioStations(id) RADIO_ID -> automotiveRepository.internetRadioStations
DOWNLOAD_ID -> Futures.immediateFuture(null)
else -> { else -> {
if (id.startsWith(MOST_PLAYED_ID)) { if (id.startsWith(MOST_PLAYED_ID)) {
@ -382,12 +350,30 @@ object MediaBrowserTree {
) )
} }
if (id.startsWith(BEST_OF_ID)) { if (id.startsWith(MADE_FOR_YOU_ID)) {
return automotiveRepository.getMadeForYou(
id.removePrefix(
MADE_FOR_YOU_ID
),
20
)
} }
if (id.startsWith(MADE_FOR_YOU_ID)) { if (id.startsWith(STARRED_ALBUMS_ID)) {
return automotiveRepository.getAlbumTracks(
id.removePrefix(
STARRED_ALBUMS_ID
)
)
}
if (id.startsWith(STARRED_ARTISTS_ID)) {
return automotiveRepository.getArtistAlbum(
STARRED_ALBUMS_ID,
id.removePrefix(
STARRED_ARTISTS_ID
)
)
} }
if (id.startsWith(FOLDER_ID)) { if (id.startsWith(FOLDER_ID)) {
@ -425,12 +411,21 @@ object MediaBrowserTree {
) )
} }
if (id.startsWith(PODCAST_ID)) { if (id.startsWith(ALBUM_ID)) {
return automotiveRepository.getAlbumTracks(
id.removePrefix(
ALBUM_ID
)
)
} }
if (id.startsWith(RADIO_ID)) { if (id.startsWith(ARTIST_ID)) {
return automotiveRepository.getArtistAlbum(
ALBUM_ID,
id.removePrefix(
ARTIST_ID
)
)
} }
return Futures.immediateFuture(LibraryResult.ofError(LibraryResult.RESULT_ERROR_BAD_VALUE)) return Futures.immediateFuture(LibraryResult.ofError(LibraryResult.RESULT_ERROR_BAD_VALUE))
@ -461,4 +456,12 @@ object MediaBrowserTree {
return updatedMediaItems return updatedMediaItems
} }
fun search(query: String): ListenableFuture<LibraryResult<ImmutableList<MediaItem>>> {
return automotiveRepository.search(
query,
ALBUM_ID,
ARTIST_ID
)
}
} }

View file

@ -22,10 +22,9 @@ open class MediaLibrarySessionCallback(
automotiveRepository: AutomotiveRepository automotiveRepository: AutomotiveRepository
) : ) :
MediaLibraryService.MediaLibrarySession.Callback { MediaLibraryService.MediaLibrarySession.Callback {
private val TAG = "MediaLibraryServiceCall"
init { init {
MediaBrowserTree.initialize(context, automotiveRepository) MediaBrowserTree.initialize(automotiveRepository)
} }
private val customLayoutCommandButtons: List<CommandButton> = listOf( private val customLayoutCommandButtons: List<CommandButton> = listOf(
@ -118,7 +117,7 @@ open class MediaLibrarySessionCallback(
pageSize: Int, pageSize: Int,
params: MediaLibraryService.LibraryParams? params: MediaLibraryService.LibraryParams?
): ListenableFuture<LibraryResult<ImmutableList<MediaItem>>> { ): ListenableFuture<LibraryResult<ImmutableList<MediaItem>>> {
return MediaBrowserTree.getChildren(parentId, params) return MediaBrowserTree.getChildren(parentId)
} }
override fun onAddMediaItems( override fun onAddMediaItems(
@ -133,17 +132,17 @@ open class MediaLibrarySessionCallback(
) )
} }
/* override fun onSearch( override fun onSearch(
session: MediaLibraryService.MediaLibrarySession, session: MediaLibraryService.MediaLibrarySession,
browser: MediaSession.ControllerInfo, browser: MediaSession.ControllerInfo,
query: String, query: String,
params: MediaLibraryService.LibraryParams? params: MediaLibraryService.LibraryParams?
): ListenableFuture<LibraryResult<Void>> { ): ListenableFuture<LibraryResult<Void>> {
session.notifySearchResultChanged(browser, query, MediaBrowserTree.search(query).size, params) session.notifySearchResultChanged(browser, query, 60, params)
return Futures.immediateFuture(LibraryResult.ofVoid()) return Futures.immediateFuture(LibraryResult.ofVoid())
} */ }
/* override fun onGetSearchResult( override fun onGetSearchResult(
session: MediaLibraryService.MediaLibrarySession, session: MediaLibraryService.MediaLibrarySession,
browser: MediaSession.ControllerInfo, browser: MediaSession.ControllerInfo,
query: String, query: String,
@ -151,12 +150,8 @@ open class MediaLibrarySessionCallback(
pageSize: Int, pageSize: Int,
params: MediaLibraryService.LibraryParams? params: MediaLibraryService.LibraryParams?
): ListenableFuture<LibraryResult<ImmutableList<MediaItem>>> { ): ListenableFuture<LibraryResult<ImmutableList<MediaItem>>> {
return Futures.immediateFuture( return MediaBrowserTree.search(query)
LibraryResult.ofItemList( }
MediaBrowserTree.search(query), params
)
)
} */
companion object { companion object {
private const val CUSTOM_COMMAND_TOGGLE_SHUFFLE_MODE_ON = private const val CUSTOM_COMMAND_TOGGLE_SHUFFLE_MODE_ON =