feat: test: Implemented initial functional version with Android Auto support

This commit is contained in:
antonio 2024-01-03 00:45:22 +01:00
parent e8c7c065e2
commit d6cc4fc028
8 changed files with 758 additions and 160 deletions

View file

@ -14,17 +14,19 @@ import com.cappielloantonio.tempo.database.dao.FavoriteDao;
import com.cappielloantonio.tempo.database.dao.QueueDao;
import com.cappielloantonio.tempo.database.dao.RecentSearchDao;
import com.cappielloantonio.tempo.database.dao.ServerDao;
import com.cappielloantonio.tempo.database.dao.SessionMediaItemDao;
import com.cappielloantonio.tempo.model.Chronology;
import com.cappielloantonio.tempo.model.Download;
import com.cappielloantonio.tempo.model.Favorite;
import com.cappielloantonio.tempo.model.Queue;
import com.cappielloantonio.tempo.model.RecentSearch;
import com.cappielloantonio.tempo.model.Server;
import com.cappielloantonio.tempo.model.SessionMediaItem;
@Database(
version = 3,
entities = {Queue.class, Server.class, RecentSearch.class, Download.class, Chronology.class, Favorite.class},
autoMigrations = {@AutoMigration(from = 2, to = 3)}
version = 8,
entities = {Queue.class, Server.class, RecentSearch.class, Download.class, Chronology.class, Favorite.class, SessionMediaItem.class},
autoMigrations = {@AutoMigration(from = 7, to = 8)}
)
@TypeConverters({DateConverters.class})
public abstract class AppDatabase extends RoomDatabase {
@ -52,4 +54,6 @@ public abstract class AppDatabase extends RoomDatabase {
public abstract ChronologyDao chronologyDao();
public abstract FavoriteDao favoriteDao();
public abstract SessionMediaItemDao sessionMediaItemDao();
}

View file

@ -0,0 +1,29 @@
package com.cappielloantonio.tempo.database.dao;
import androidx.room.Dao;
import androidx.room.Insert;
import androidx.room.OnConflictStrategy;
import androidx.room.Query;
import com.cappielloantonio.tempo.model.Queue;
import com.cappielloantonio.tempo.model.SessionMediaItem;
import java.util.List;
@Dao
public interface SessionMediaItemDao {
@Query("SELECT * FROM session_media_item WHERE id = :id")
SessionMediaItem get(String id);
@Query("SELECT * FROM session_media_item WHERE timestamp = :timestamp")
List<SessionMediaItem> get(long timestamp);
@Insert(onConflict = OnConflictStrategy.IGNORE)
void insert(SessionMediaItem sessionMediaItem);
@Insert(onConflict = OnConflictStrategy.IGNORE)
void insertAll(List<SessionMediaItem> sessionMediaItems);
@Query("DELETE FROM session_media_item")
void deleteAll();
}

View file

@ -0,0 +1,279 @@
package com.cappielloantonio.tempo.model
import android.net.Uri
import android.os.Bundle
import androidx.annotation.Keep
import androidx.media3.common.MediaItem
import androidx.media3.common.MediaItem.RequestMetadata
import androidx.media3.common.MediaMetadata
import androidx.media3.common.MimeTypes
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
import com.cappielloantonio.tempo.glide.CustomGlideRequest
import com.cappielloantonio.tempo.subsonic.models.Child
import com.cappielloantonio.tempo.subsonic.models.InternetRadioStation
import com.cappielloantonio.tempo.subsonic.models.PodcastEpisode
import com.cappielloantonio.tempo.util.Constants
import com.cappielloantonio.tempo.util.MusicUtil
import com.cappielloantonio.tempo.util.Preferences.getImageSize
import java.util.Date
@Keep
@Entity(tableName = "session_media_item")
class SessionMediaItem() {
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "index")
var index: Int = 0
@ColumnInfo(name = "id")
var id: String? = null
@ColumnInfo(name = "parent_id")
var parentId: String? = null
@ColumnInfo(name = "is_dir")
var isDir: Boolean = false
@ColumnInfo
var title: String? = null
@ColumnInfo
var album: String? = null
@ColumnInfo
var artist: String? = null
@ColumnInfo
var track: Int? = null
@ColumnInfo
var year: Int? = null
@ColumnInfo
var genre: String? = null
@ColumnInfo(name = "cover_art_id")
var coverArtId: String? = null
@ColumnInfo
var size: Long? = null
@ColumnInfo(name = "content_type")
var contentType: String? = null
@ColumnInfo
var suffix: String? = null
@ColumnInfo("transcoding_content_type")
var transcodedContentType: String? = null
@ColumnInfo(name = "transcoded_suffix")
var transcodedSuffix: String? = null
@ColumnInfo
var duration: Int? = null
@ColumnInfo("bitrate")
var bitrate: Int? = null
@ColumnInfo
var path: String? = null
@ColumnInfo(name = "is_video")
var isVideo: Boolean = false
@ColumnInfo(name = "user_rating")
var userRating: Int? = null
@ColumnInfo(name = "average_rating")
var averageRating: Double? = null
@ColumnInfo(name = "play_count")
var playCount: Long? = null
@ColumnInfo(name = "disc_number")
var discNumber: Int? = null
@ColumnInfo
var created: Date? = null
@ColumnInfo
var starred: Date? = null
@ColumnInfo(name = "album_id")
var albumId: String? = null
@ColumnInfo(name = "artist_id")
var artistId: String? = null
@ColumnInfo
var type: String? = null
@ColumnInfo(name = "bookmark_position")
var bookmarkPosition: Long? = null
@ColumnInfo(name = "original_width")
var originalWidth: Int? = null
@ColumnInfo(name = "original_height")
var originalHeight: Int? = null
@ColumnInfo(name = "stream_id")
var streamId: String? = null
@ColumnInfo(name = "stream_url")
var streamUrl: String? = null
@ColumnInfo(name = "timestamp")
var timestamp: Long? = null
constructor(child: Child) : this() {
id = child.id
parentId = child.parentId
isDir = child.isDir
title = child.title
album = child.album
artist = child.artist
track = child.track
year = child.year
genre = child.genre
coverArtId = child.coverArtId
size = child.size
contentType = child.contentType
suffix = child.suffix
transcodedContentType = child.transcodedContentType
transcodedSuffix = child.transcodedSuffix
duration = child.duration
bitrate = child.bitrate
path = child.path
isVideo = child.isVideo
userRating = child.userRating
averageRating = child.averageRating
playCount = child.playCount
discNumber = child.discNumber
created = child.created
starred = child.starred
albumId = child.albumId
artistId = child.artistId
type = Constants.MEDIA_TYPE_MUSIC
bookmarkPosition = child.bookmarkPosition
originalWidth = child.originalWidth
originalHeight = child.originalHeight
}
constructor(podcastEpisode: PodcastEpisode) : this() {
id = podcastEpisode.id
parentId = podcastEpisode.parentId
isDir = podcastEpisode.isDir
title = podcastEpisode.title
album = podcastEpisode.album
artist = podcastEpisode.artist
year = podcastEpisode.year
genre = podcastEpisode.genre
coverArtId = podcastEpisode.coverArtId
size = podcastEpisode.size
contentType = podcastEpisode.contentType
suffix = podcastEpisode.suffix
duration = podcastEpisode.duration
bitrate = podcastEpisode.bitrate
path = podcastEpisode.path
isVideo = podcastEpisode.isVideo
created = podcastEpisode.created
artistId = podcastEpisode.artistId
streamId = podcastEpisode.streamId
type = Constants.MEDIA_TYPE_PODCAST
}
constructor(internetRadioStation: InternetRadioStation) : this() {
id = internetRadioStation.id
title = internetRadioStation.name
streamUrl = internetRadioStation.streamUrl
type = Constants.MEDIA_TYPE_RADIO
}
fun getMediaItem(): MediaItem {
val uri: Uri = getStreamUri()
val artworkUri = Uri.parse(CustomGlideRequest.createUrl(coverArtId, getImageSize()))
val bundle = Bundle()
bundle.putString("id", id)
bundle.putString("parentId", parentId)
bundle.putBoolean("isDir", isDir)
bundle.putString("title", title)
bundle.putString("album", album)
bundle.putString("artist", artist)
bundle.putInt("track", track ?: 0)
bundle.putInt("year", year ?: 0)
bundle.putString("genre", genre)
bundle.putString("coverArtId", coverArtId)
bundle.putLong("size", size ?: 0)
bundle.putString("contentType", contentType)
bundle.putString("suffix", suffix)
bundle.putString("transcodedContentType", transcodedContentType)
bundle.putString("transcodedSuffix", transcodedSuffix)
bundle.putInt("duration", duration ?: 0)
bundle.putInt("bitrate", bitrate ?: 0)
bundle.putString("path", path)
bundle.putBoolean("isVideo", isVideo)
bundle.putInt("userRating", userRating ?: 0)
bundle.putDouble("averageRating", averageRating ?: .0)
bundle.putLong("playCount", playCount ?: 0)
bundle.putInt("discNumber", discNumber ?: 0)
bundle.putLong("created", created?.time ?: 0)
bundle.putLong("starred", starred?.time ?: 0)
bundle.putString("albumId", albumId)
bundle.putString("artistId", artistId)
bundle.putString("type", Constants.MEDIA_TYPE_MUSIC)
bundle.putLong("bookmarkPosition", bookmarkPosition ?: 0)
bundle.putInt("originalWidth", originalWidth ?: 0)
bundle.putInt("originalHeight", originalHeight ?: 0)
bundle.putString("uri", uri.toString())
return MediaItem.Builder()
.setMediaId(id!!)
.setMediaMetadata(
MediaMetadata.Builder()
.setTitle(MusicUtil.getReadableString(title))
.setTrackNumber(track ?: 0)
.setDiscNumber(discNumber ?: 0)
.setReleaseYear(year ?: 0)
.setAlbumTitle(MusicUtil.getReadableString(album))
.setArtist(MusicUtil.getReadableString(artist))
.setArtworkUri(artworkUri)
.setExtras(bundle)
.setIsBrowsable(false)
.setIsPlayable(true)
.build()
)
.setRequestMetadata(
RequestMetadata.Builder()
.setMediaUri(uri)
.setExtras(bundle)
.build()
)
.setMimeType(MimeTypes.BASE_TYPE_AUDIO)
.setUri(uri)
.build()
}
private fun getStreamUri(): Uri {
return when (type) {
Constants.MEDIA_TYPE_MUSIC -> {
MusicUtil.getStreamUri(id)
}
Constants.MEDIA_TYPE_PODCAST -> {
MusicUtil.getStreamUri(streamId)
}
Constants.MEDIA_TYPE_RADIO -> {
Uri.parse(streamUrl)
}
else -> {
MusicUtil.getStreamUri(id)
}
}
}
}

View file

@ -9,15 +9,22 @@ import androidx.media3.common.MediaMetadata;
import androidx.media3.session.LibraryResult;
import com.cappielloantonio.tempo.App;
import com.cappielloantonio.tempo.database.AppDatabase;
import com.cappielloantonio.tempo.database.dao.SessionMediaItemDao;
import com.cappielloantonio.tempo.glide.CustomGlideRequest;
import com.cappielloantonio.tempo.model.SessionMediaItem;
import com.cappielloantonio.tempo.subsonic.base.ApiResponse;
import com.cappielloantonio.tempo.subsonic.models.AlbumID3;
import com.cappielloantonio.tempo.subsonic.models.Artist;
import com.cappielloantonio.tempo.subsonic.models.ArtistID3;
import com.cappielloantonio.tempo.subsonic.models.Child;
import com.cappielloantonio.tempo.subsonic.models.Directory;
import com.cappielloantonio.tempo.subsonic.models.Index;
import com.cappielloantonio.tempo.subsonic.models.InternetRadioStation;
import com.cappielloantonio.tempo.subsonic.models.MusicFolder;
import com.cappielloantonio.tempo.subsonic.models.Playlist;
import com.cappielloantonio.tempo.subsonic.models.PodcastEpisode;
import com.cappielloantonio.tempo.util.MappingUtil;
import com.cappielloantonio.tempo.util.MusicUtil;
import com.cappielloantonio.tempo.util.Preferences;
import com.google.common.collect.ImmutableList;
@ -25,13 +32,17 @@ import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.SettableFuture;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
public class AutomotiveRepository {
private final SessionMediaItemDao sessionMediaItemDao = AppDatabase.getInstance().sessionMediaItemDao();
public ListenableFuture<LibraryResult<ImmutableList<MediaItem>>> getAlbums(String prefix, String type, int size) {
final SettableFuture<LibraryResult<ImmutableList<MediaItem>>> listenableFuture = SettableFuture.create();
@ -86,7 +97,7 @@ public class AutomotiveRepository {
return listenableFuture;
}
public ListenableFuture<LibraryResult<ImmutableList<MediaItem>>> getStarredSongs(String prefix) {
public ListenableFuture<LibraryResult<ImmutableList<MediaItem>>> getStarredSongs() {
final SettableFuture<LibraryResult<ImmutableList<MediaItem>>> listenableFuture = SettableFuture.create();
App.getSubsonicClientInstance(false)
@ -98,29 +109,9 @@ public class AutomotiveRepository {
if (response.isSuccessful() && response.body() != null && response.body().getSubsonicResponse().getStarred2() != null && response.body().getSubsonicResponse().getStarred2().getSongs() != null) {
List<Child> songs = response.body().getSubsonicResponse().getStarred2().getSongs();
List<MediaItem> mediaItems = new ArrayList<>();
setChildrenMetadata(songs);
for (Child song : songs) {
Uri artworkUri = Uri.parse(CustomGlideRequest.createUrl(song.getCoverArtId(), Preferences.getImageSize()));
MediaMetadata mediaMetadata = new MediaMetadata.Builder()
.setTitle(song.getTitle())
.setAlbumTitle(song.getAlbum())
.setArtist(song.getArtist())
.setIsBrowsable(false)
.setIsPlayable(true)
.setMediaType(MediaMetadata.MEDIA_TYPE_MUSIC)
.setArtworkUri(artworkUri)
.build();
MediaItem mediaItem = new MediaItem.Builder()
.setMediaId(prefix + song.getId())
.setMediaMetadata(mediaMetadata)
.setUri(MusicUtil.getStreamUri(song.getId()))
.build();
mediaItems.add(mediaItem);
}
List<MediaItem> mediaItems = MappingUtil.mapMediaItems(songs);
LibraryResult<ImmutableList<MediaItem>> libraryResult = LibraryResult.ofItemList(ImmutableList.copyOf(mediaItems), null);
@ -252,7 +243,7 @@ public class AutomotiveRepository {
.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().getMusicFolders() != null) {
if (response.isSuccessful() && response.body() != null && response.body().getSubsonicResponse().getMusicFolders() != null && response.body().getSubsonicResponse().getMusicFolders().getMusicFolders() != null) {
List<MusicFolder> musicFolders = response.body().getSubsonicResponse().getMusicFolders().getMusicFolders();
List<MediaItem> mediaItems = new ArrayList<>();
@ -291,6 +282,137 @@ public class AutomotiveRepository {
return listenableFuture;
}
public ListenableFuture<LibraryResult<ImmutableList<MediaItem>>> getIndexes(String prefix, String id) {
final SettableFuture<LibraryResult<ImmutableList<MediaItem>>> listenableFuture = SettableFuture.create();
App.getSubsonicClientInstance(false)
.getBrowsingClient()
.getIndexes(id, null)
.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().getIndexes() != null) {
List<MediaItem> mediaItems = new ArrayList<>();
if (response.body().getSubsonicResponse().getIndexes().getIndices() != null) {
List<Index> indices = response.body().getSubsonicResponse().getIndexes().getIndices();
for (Index index : indices) {
if (index.getArtists() != null) {
for (Artist artist : index.getArtists()) {
MediaMetadata mediaMetadata = new MediaMetadata.Builder()
.setTitle(artist.getName())
.setIsBrowsable(true)
.setIsPlayable(false)
.setMediaType(MediaMetadata.MEDIA_TYPE_ARTIST)
.build();
MediaItem mediaItem = new MediaItem.Builder()
.setMediaId(prefix + artist.getId())
.setMediaMetadata(mediaMetadata)
.setUri("")
.build();
mediaItems.add(mediaItem);
}
}
}
}
if (response.body().getSubsonicResponse().getIndexes().getChildren() != null) {
List<Child> children = response.body().getSubsonicResponse().getIndexes().getChildren();
for (Child song : children) {
Uri artworkUri = Uri.parse(CustomGlideRequest.createUrl(song.getCoverArtId(), Preferences.getImageSize()));
MediaMetadata mediaMetadata = new MediaMetadata.Builder()
.setTitle(song.getTitle())
.setAlbumTitle(song.getAlbum())
.setArtist(song.getArtist())
.setIsBrowsable(false)
.setIsPlayable(true)
.setMediaType(MediaMetadata.MEDIA_TYPE_MUSIC)
.setArtworkUri(artworkUri)
.build();
MediaItem mediaItem = new MediaItem.Builder()
.setMediaId(prefix + song.getId())
.setMediaMetadata(mediaMetadata)
.setUri(MusicUtil.getStreamUri(song.getId()))
.build();
mediaItems.add(mediaItem);
}
setChildrenMetadata(children);
}
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>>> getDirectories(String prefix, String id) {
final SettableFuture<LibraryResult<ImmutableList<MediaItem>>> listenableFuture = SettableFuture.create();
App.getSubsonicClientInstance(false)
.getBrowsingClient()
.getMusicDirectory(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().getDirectory() != null && response.body().getSubsonicResponse().getDirectory().getChildren() != null) {
Directory directory = response.body().getSubsonicResponse().getDirectory();
List<MediaItem> mediaItems = new ArrayList<>();
for (Child child : directory.getChildren()) {
Uri artworkUri = Uri.parse(CustomGlideRequest.createUrl(child.getCoverArtId(), Preferences.getImageSize()));
MediaMetadata mediaMetadata = new MediaMetadata.Builder()
.setTitle(child.getTitle())
.setIsBrowsable(child.isDir())
.setIsPlayable(!child.isDir())
.setMediaType(MediaMetadata.MEDIA_TYPE_FOLDER_MIXED)
.setArtworkUri(artworkUri)
.build();
MediaItem mediaItem = new MediaItem.Builder()
.setMediaId(child.isDir() ? prefix + child.getId() : child.getId())
.setMediaMetadata(mediaMetadata)
.setUri(!child.isDir() ? MusicUtil.getStreamUri(child.getId()) : Uri.parse(""))
.build();
mediaItems.add(mediaItem);
}
setChildrenMetadata(directory.getChildren().stream().filter(child -> !child.isDir()).collect(Collectors.toList()));
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>>> getPlaylists(String prefix) {
final SettableFuture<LibraryResult<ImmutableList<MediaItem>>> listenableFuture = SettableFuture.create();
@ -373,6 +495,8 @@ public class AutomotiveRepository {
mediaItems.add(mediaItem);
}
setPodcastEpisodesMetadata(episodes);
LibraryResult<ImmutableList<MediaItem>> libraryResult = LibraryResult.ofItemList(ImmutableList.copyOf(mediaItems), null);
listenableFuture.set(libraryResult);
@ -422,6 +546,8 @@ public class AutomotiveRepository {
mediaItems.add(mediaItem);
}
setInternetRadioStationsMetadata(radioStations);
LibraryResult<ImmutableList<MediaItem>> libraryResult = LibraryResult.ofItemList(ImmutableList.copyOf(mediaItems), null);
listenableFuture.set(libraryResult);
@ -452,29 +578,9 @@ public class AutomotiveRepository {
List<Child> tracks = response.body().getSubsonicResponse().getAlbum().getSongs();
List<MediaItem> mediaItems = new ArrayList<>();
setChildrenMetadata(tracks);
for (Child track : tracks) {
Uri artworkUri = Uri.parse(CustomGlideRequest.createUrl(track.getCoverArtId(), Preferences.getImageSize()));
MediaMetadata mediaMetadata = new MediaMetadata.Builder()
.setTitle(track.getTitle())
.setAlbumTitle(track.getAlbum())
.setArtist(track.getArtist())
.setIsBrowsable(false)
.setIsPlayable(true)
.setMediaType(MediaMetadata.MEDIA_TYPE_MUSIC)
.setArtworkUri(artworkUri)
.build();
MediaItem mediaItem = new MediaItem.Builder()
.setMediaId(track.getId())
.setMediaMetadata(mediaMetadata)
.setUri(MusicUtil.getStreamUri(track.getId()))
.build();
mediaItems.add(mediaItem);
}
List<MediaItem> mediaItems = MappingUtil.mapMediaItems(tracks);
LibraryResult<ImmutableList<MediaItem>> libraryResult = LibraryResult.ofItemList(ImmutableList.copyOf(mediaItems), null);
@ -486,10 +592,234 @@ public class AutomotiveRepository {
@Override
public void onFailure(@NonNull Call<ApiResponse> call, @NonNull Throwable t) {
listenableFuture.setException(t);
}
});
return listenableFuture;
}
public ListenableFuture<LibraryResult<ImmutableList<MediaItem>>> getPlaylistSongs(String id) {
final SettableFuture<LibraryResult<ImmutableList<MediaItem>>> listenableFuture = SettableFuture.create();
App.getSubsonicClientInstance(false)
.getPlaylistClient()
.getPlaylist(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().getPlaylist() != null && response.body().getSubsonicResponse().getPlaylist().getEntries() != null) {
List<Child> tracks = response.body().getSubsonicResponse().getPlaylist().getEntries();
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 void setChildrenMetadata(List<Child> children) {
long timestamp = System.currentTimeMillis();
ArrayList<SessionMediaItem> sessionMediaItems = new ArrayList<>();
for (Child child : children) {
SessionMediaItem sessionMediaItem = new SessionMediaItem(child);
sessionMediaItem.setTimestamp(timestamp);
sessionMediaItems.add(sessionMediaItem);
}
InsertAllThreadSafe insertAll = new InsertAllThreadSafe(sessionMediaItemDao, sessionMediaItems);
Thread thread = new Thread(insertAll);
thread.start();
}
public void setPodcastEpisodesMetadata(List<PodcastEpisode> podcastEpisodes) {
long timestamp = System.currentTimeMillis();
ArrayList<SessionMediaItem> sessionMediaItems = new ArrayList<>();
for (PodcastEpisode podcastEpisode : podcastEpisodes) {
SessionMediaItem sessionMediaItem = new SessionMediaItem(podcastEpisode);
sessionMediaItem.setTimestamp(timestamp);
sessionMediaItems.add(sessionMediaItem);
}
InsertAllThreadSafe insertAll = new InsertAllThreadSafe(sessionMediaItemDao, sessionMediaItems);
Thread thread = new Thread(insertAll);
thread.start();
}
public void setInternetRadioStationsMetadata(List<InternetRadioStation> internetRadioStations) {
long timestamp = System.currentTimeMillis();
ArrayList<SessionMediaItem> sessionMediaItems = new ArrayList<>();
for (InternetRadioStation internetRadioStation : internetRadioStations) {
SessionMediaItem sessionMediaItem = new SessionMediaItem(internetRadioStation);
sessionMediaItem.setTimestamp(timestamp);
sessionMediaItems.add(sessionMediaItem);
}
InsertAllThreadSafe insertAll = new InsertAllThreadSafe(sessionMediaItemDao, sessionMediaItems);
Thread thread = new Thread(insertAll);
thread.start();
}
public SessionMediaItem getSessionMediaItem(String id) {
SessionMediaItem sessionMediaItem = null;
GetMediaItemThreadSafe getMediaItemThreadSafe = new GetMediaItemThreadSafe(sessionMediaItemDao, id);
Thread thread = new Thread(getMediaItemThreadSafe);
thread.start();
try {
thread.join();
sessionMediaItem = getMediaItemThreadSafe.getSessionMediaItem();
} catch (InterruptedException e) {
e.printStackTrace();
}
return sessionMediaItem;
}
public List<MediaItem> getMetadatas(long timestamp) {
List<MediaItem> mediaItems = Collections.emptyList();
GetMediaItemsThreadSafe getMediaItemsThreadSafe = new GetMediaItemsThreadSafe(sessionMediaItemDao, timestamp);
Thread thread = new Thread(getMediaItemsThreadSafe);
thread.start();
try {
thread.join();
mediaItems = getMediaItemsThreadSafe.getMediaItems();
} catch (InterruptedException e) {
e.printStackTrace();
}
return mediaItems;
}
public void deleteMetadata() {
DeleteAllThreadSafe delete = new DeleteAllThreadSafe(sessionMediaItemDao);
Thread thread = new Thread(delete);
thread.start();
}
private static class GetMediaItemThreadSafe implements Runnable {
private final SessionMediaItemDao sessionMediaItemDao;
private final String id;
private SessionMediaItem sessionMediaItem;
public GetMediaItemThreadSafe(SessionMediaItemDao sessionMediaItemDao, String id) {
this.sessionMediaItemDao = sessionMediaItemDao;
this.id = id;
}
@Override
public void run() {
sessionMediaItem = sessionMediaItemDao.get(id);
}
public SessionMediaItem getSessionMediaItem() {
return sessionMediaItem;
}
}
private static class GetMediaItemsThreadSafe implements Runnable {
private final SessionMediaItemDao sessionMediaItemDao;
private final Long timestamp;
private List<MediaItem> mediaItems = new ArrayList<>();
public GetMediaItemsThreadSafe(SessionMediaItemDao sessionMediaItemDao, Long timestamp) {
this.sessionMediaItemDao = sessionMediaItemDao;
this.timestamp = timestamp;
}
@Override
public void run() {
List<SessionMediaItem> sessionMediaItems = sessionMediaItemDao.get(timestamp);
sessionMediaItems.forEach(sessionMediaItem -> mediaItems.add(sessionMediaItem.getMediaItem()));
}
public List<MediaItem> getMediaItems() {
return mediaItems;
}
}
/* 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 final SessionMediaItemDao sessionMediaItemDao;
private final List<SessionMediaItem> sessionMediaItems;
public InsertAllThreadSafe(SessionMediaItemDao sessionMediaItemDao, List<SessionMediaItem> sessionMediaItems) {
this.sessionMediaItemDao = sessionMediaItemDao;
this.sessionMediaItems = sessionMediaItems;
}
@Override
public void run() {
sessionMediaItemDao.insertAll(sessionMediaItems);
}
}
private static class DeleteAllThreadSafe implements Runnable {
private final SessionMediaItemDao sessionMediaItemDao;
public DeleteAllThreadSafe(SessionMediaItemDao sessionMediaItemDao) {
this.sessionMediaItemDao = sessionMediaItemDao;
}
@Override
public void run() {
sessionMediaItemDao.deleteAll();
}
}
}

View file

@ -82,6 +82,8 @@ public class MappingUtil {
.setArtist(MusicUtil.getReadableString(media.getArtist()))
.setArtworkUri(artworkUri)
.setExtras(bundle)
.setIsBrowsable(false)
.setIsPlayable(true)
.build()
)
.setRequestMetadata(
@ -116,6 +118,8 @@ public class MappingUtil {
.setReleaseYear(media.getYear() != null ? media.getYear() : 0)
.setAlbumTitle(MusicUtil.getReadableString(media.getAlbum()))
.setArtist(MusicUtil.getReadableString(media.getArtist()))
.setIsBrowsable(false)
.setIsPlayable(true)
.build()
)
.setRequestMetadata(
@ -145,6 +149,8 @@ public class MappingUtil {
.setTitle(internetRadioStation.getName())
.setArtist(internetRadioStation.getStreamUrl())
.setExtras(bundle)
.setIsBrowsable(false)
.setIsPlayable(true)
.build()
)
.setRequestMetadata(
@ -193,6 +199,8 @@ public class MappingUtil {
.setArtist(MusicUtil.getReadableString(podcastEpisode.getArtist()))
.setArtworkUri(artworkUri)
.setExtras(bundle)
.setIsBrowsable(false)
.setIsPlayable(true)
.build()
)
.setRequestMetadata(
@ -201,12 +209,6 @@ public class MappingUtil {
.setExtras(bundle)
.build()
)
/* .setClippingConfiguration(
new MediaItem.ClippingConfiguration.Builder()
.setStartPositionMs(0)
.setEndPositionMs(podcastEpisode.getDuration() * 1000)
.build()
) */
.setMimeType(MimeTypes.BASE_TYPE_AUDIO)
.setUri(uri)
.build();