/// <summary> /// Attempts to play a model of type BaseTrack. This method handles playback and loading /// feedback to the user. If an error occured, the user will see a message dialog. /// </summary> /// <typeparam name="TSource">A base track source.</typeparam> /// <param name="model">SoundByte collection of a base track source.</param> /// <param name="startingTrack">The track to start first (can be null)</param> /// <param name="shuffle">Should the playlist be shuffled.</param> public static async Task PlayAllTracksAsync <TSource>(SoundByteCollection <TSource> model, BaseTrack startingTrack = null, bool shuffle = false) where TSource : ISource { if (model.Count == 0) { return; } // Attempt to create the playlist var result = await SimpleIoc.Default.GetInstance <IPlaybackService>().InitializePlaylistAsync(model.Source, model, model.Token); if (result.Success == false) { await NavigationService.Current.CallMessageDialogAsync(result.Message, "Could not build playlist."); return; } // Start playback if (shuffle) { await SimpleIoc.Default.GetInstance <IPlaybackService>().StartRandomTrackAsync(); } else { await SimpleIoc.Default.GetInstance <IPlaybackService>().StartTrackAsync(startingTrack); } }
public ContentGroup(ISource source, string title, bool isAuthenticatedFeed, List <ContentButton> buttons, Action <ContentGroup>?onClickAction = null, Action <Media.Media>?onItemClickCommand = null) { Collection = new SoundByteCollection <ISource>(source); Title = title; IsAuthenticatedFeed = isAuthenticatedFeed; Buttons = buttons; if (onClickAction != null) { // Bind to the custom click event OnViewAllClickCommand = new MvxCommand(() => onClickAction?.Invoke(this)); } else { // Nothing was passed through, use the default navigation OnViewAllClickCommand = new MvxAsyncCommand(async() => { var navigationService = Mvx.IoCProvider.Resolve <IMvxNavigationService>(); await navigationService.Navigate <GenericListViewModel, GenericListViewModel.Holder>(new GenericListViewModel.Holder(Collection, Title)); }); } OnItemClickCommand = onItemClickCommand == null ? new MvxCommand <Media.Media>(async item => await ItemInvokeHelper.InvokeItem(Collection, item)) : new MvxCommand <Media.Media>(onItemClickCommand); }
public static async Task InvokeItem <T>(SoundByteCollection <T> collection, Media item) where T : ISource { var provider = Mvx.IoCProvider.Resolve <IMusicProviderService>().MusicProviders.FirstOrDefault(x => x.Identifier == item.MusicProviderId); if (provider == null) { await Mvx.IoCProvider.Resolve <IDialogService>().ShowErrorMessageAsync("Cannot open item", $"You need the music provider ({item.MusicProviderId}) in order to interact with this item"); return; } // Loop through all the item types switch (item.MediaType) { case MediaType.Unknown: break; case MediaType.Track: case MediaType.PodcastEpisode: // Build the queue var result = await Mvx.IoCProvider.Resolve <IPlaybackService>().InitializeAsync(collection.Source, collection, collection.Token); if (!result.Success) { await Mvx.IoCProvider.Resolve <IDialogService>().ShowErrorMessageAsync("Could not build playback queue", result.Message); return; } // Play the song await Mvx.IoCProvider.Resolve <IPlaybackService>().StartMediaAsync(item); break; // Navigate to the user detail view case MediaType.User: await Mvx.IoCProvider.Resolve <IMvxNavigationService>().Navigate <UserDetailViewModel, User>((User)item); break; // Navigate to the playlist detail view case MediaType.Playlist: await Mvx.IoCProvider.Resolve <IMvxNavigationService>().Navigate <PlaylistDetailViewModel, Playlist>((Playlist)item); break; // Navigate to the podcast detail view case MediaType.PodcastShow: await Mvx.IoCProvider.Resolve <IMvxNavigationService>().Navigate <PodcastDetailViewModel, PodcastShow>((PodcastShow)item); break; } }
public ContentGroup(ISource source, string title, List<ContentButton> buttons, Action<ContentGroup> onClickAction, Action<BaseSoundByteItem> onItemClickCommand = null) { Collection = new SoundByteCollection<ISource>(source); Title = title; Buttons = buttons; if (onClickAction != null) OnViewAllClickCommand = new DelegateCommand<ContentGroup>(onClickAction); if (onItemClickCommand != null) OnItemClickCommand = new DelegateCommand<BaseSoundByteItem>(onItemClickCommand); }
public static async Task ShuffleTracksAsync <TSource>(SoundByteCollection <TSource, BaseTrack> model) where TSource : ISource <BaseTrack> { model.IsLoading = true; var startPlayback = await PlaybackService.Instance.StartModelMediaPlaybackAsync(model, true); if (!startPlayback.Success) { await new MessageDialog(startPlayback.Message, "Error playing shuffled tracks.").ShowAsync(); } model.IsLoading = false; }
private async void OnSearchTrackClickCommand(BaseSoundByteItem item) { // Create the related track collection var relatedTrackCollection = new SoundByteCollection <RelatedTrackSource>(); relatedTrackCollection.Source.Service = item.Track.ServiceType; relatedTrackCollection.Source.TrackId = item.Track.TrackId; // Add this track as an initial track relatedTrackCollection.Add(item); // Play the tracks await BaseViewModel.PlayAllTracksAsync(relatedTrackCollection, item.Track); }
/// <summary> /// Helper method for PlayAllTracksAsync to play shuffled tracks. See /// PlayAllTracksAsync for more information /// </summary> /// <typeparam name="TSource">A base track source.</typeparam> /// <param name="model">SoundByte collection of a base track source.</param> public static async Task ShufflePlayAllTracksAsync <TSource>(SoundByteCollection <TSource> model) where TSource : ISource { await PlayAllTracksAsync(model, null, true); }
public async Task HandleProtocolAsync(string path) { LoggingService.Log(LoggingService.LogType.Debug, "Performing protocol work using path of " + path); if (!string.IsNullOrEmpty(path)) { try { if (path == "playUserLikes" || path == "shufflePlayUserLikes") { if (SoundByteV3Service.Current.IsServiceConnected(ServiceType.SoundCloud)) { // Navigate to the now playing screen RootFrame.Navigate(typeof(NowPlayingView)); // Get and load the user liked items var userLikes = new SoundByteCollection <LikeSoundCloudSource, BaseTrack>(); userLikes.Source.User = SoundByteV3Service.Current.GetConnectedUser(ServiceType.SoundCloud); // Loop through loading all the likes while (userLikes.HasMoreItems) { await userLikes.LoadMoreItemsAsync(50); } // Play the list of items await PlaybackService.Instance.StartModelMediaPlaybackAsync(userLikes, path == "shufflePlayUserLikes"); return; } } if (path == "playUserStream") { if (SoundByteV3Service.Current.IsServiceConnected(ServiceType.SoundCloud)) { // Navigate to the now playing screen RootFrame.Navigate(typeof(NowPlayingView)); // Get and load the user liked items var userStream = new SoundByteCollection <StreamSoundCloudSource, GroupedItem>(); // Counter so we don't get an insane amount of items var i = 0; // Grab all the users stream / 5 items while (userStream.HasMoreItems && i <= 5) { i++; await userStream.LoadMoreItemsAsync(50); } // Play the list of items await PlaybackService.Instance.StartPlaylistMediaPlaybackAsync( userStream.Where(x => x.Track != null).Select(x => x.Track).ToList()); return; } } var parser = DeepLinkParser.Create(path); var section = parser.Root.Split('/')[0].ToLower(); var page = parser.Root.Split('/')[1].ToLower(); await App.SetLoadingAsync(true); if (section == "core") { switch (page) { case "track": BaseTrack track = null; switch (parser["service"]) { case "soundcloud": track = (await SoundByteV3Service.Current.GetAsync <SoundCloudTrack>(ServiceType.SoundCloud, $"/tracks/{parser["id"]}")).ToBaseTrack(); break; case "youtube": break; case "fanburst": track = (await SoundByteV3Service.Current.GetAsync <FanburstTrack>(ServiceType.Fanburst, $"/videos/{parser["id"]}")).ToBaseTrack(); break; } if (track != null) { var startPlayback = await PlaybackService.Instance.StartPlaylistMediaPlaybackAsync(new List <BaseTrack> { track }); if (!startPlayback.Success) { await new MessageDialog(startPlayback.Message, "Error playing track.").ShowAsync(); } } break; case "playlist": var playlist = await SoundByteV3Service.Current.GetAsync <SoundCloudPlaylist>(ServiceType.SoundCloud, $"/playlists/{parser["id"]}"); App.NavigateTo(typeof(PlaylistView), playlist.ToBasePlaylist()); return; case "user": var user = await SoundByteV3Service.Current.GetAsync <SoundCloudUser>(ServiceType.SoundCloud, $"/users/{parser["id"]}"); App.NavigateTo(typeof(UserView), user.ToBaseUser()); return; case "changelog": App.NavigateTo(typeof(WhatsNewView)); return; } } } catch (Exception) { await new MessageDialog("The specified protocol is not correct. App will now launch as normal.") .ShowAsync(); } await App.SetLoadingAsync(false); } RootFrame.Navigate(SoundByteV3Service.Current.IsServiceConnected(ServiceType.SoundCloud) ? typeof(SoundCloudStreamView) : typeof(ExploreView)); }
public async Task HandleProtocolAsync(string path) { LoggingService.Log(LoggingService.LogType.Debug, "Performing protocol work using path of " + path); if (!string.IsNullOrEmpty(path)) { try { if (path == "playUserLikes" || path == "shufflePlayUserLikes") { if (SoundByteService.Current.IsServiceConnected(ServiceType.SoundCloud)) { // Navigate to the now playing screen RootFrame.Navigate(typeof(NowPlayingView)); // Get and load the user liked items var userLikes = new SoundByteCollection <SoundCloudLikeSource, BaseTrack>(); userLikes.Source.User = SoundByteService.Current.GetConnectedUser(ServiceType.SoundCloud); // Loop through loading all the likes while (userLikes.HasMoreItems) { await userLikes.LoadMoreItemsAsync(50); } // Play the list of items await BaseViewModel.PlayAllTracksAsync(userLikes, null, path == "shufflePlayUserLikes"); return; } } if (path == "playUserStream") { if (SoundByteService.Current.IsServiceConnected(ServiceType.SoundCloud)) { // Navigate to the now playing screen RootFrame.Navigate(typeof(NowPlayingView)); // Get and load the user liked items var userStream = new SoundByteCollection <SoundCloudStreamSource, GroupedItem>(); // Counter so we don't get an insane amount of items var i = 0; // Grab all the users stream / 5 items while (userStream.HasMoreItems && i <= 5) { i++; await userStream.LoadMoreItemsAsync(50); } // Play the list of items var result = await PlaybackService.Instance.InitilizePlaylistAsync <DummyTrackSource>( userStream.Where(x => x.Track != null).Select(x => x.Track).ToList()); if (result.Success) { await PlaybackService.Instance.StartTrackAsync(); } return; } } var parser = DeepLinkParser.Create(path); var section = parser.Root?.Split('/')[0]?.ToLower(); await App.SetLoadingAsync(true); if (section == "core") { var page = parser.Root?.Split('/')[1]?.ToLower(); switch (page) { case "track": BaseTrack track = null; switch (parser["service"]) { case "soundcloud": track = (await SoundByteService.Current.GetAsync <SoundCloudTrack>(ServiceType.SoundCloud, $"/tracks/{parser["id"]}")).Response.ToBaseTrack(); break; case "youtube": break; case "fanburst": track = (await SoundByteService.Current.GetAsync <FanburstTrack>(ServiceType.Fanburst, $"/videos/{parser["id"]}")).Response.ToBaseTrack(); break; } if (track != null) { var startPlayback = await PlaybackService.Instance.InitilizePlaylistAsync <DummyTrackSource>(new List <BaseTrack> { track }); if (startPlayback.Success) { await PlaybackService.Instance.StartTrackAsync(); } else { await NavigationService.Current.CallMessageDialogAsync(startPlayback.Message, "Error playing track."); } } break; case "playlist": var playlist = await SoundByteService.Current.GetAsync <SoundCloudPlaylist>(ServiceType.SoundCloud, $"/playlists/{parser["id"]}"); App.NavigateTo(typeof(PlaylistView), playlist.Response.ToBasePlaylist()); return; case "user": var user = await SoundByteService.Current.GetAsync <SoundCloudUser>(ServiceType.SoundCloud, $"/users/{parser["id"]}"); App.NavigateTo(typeof(UserView), user.Response.ToBaseUser()); return; case "changelog": await NavigationService.Current.CallDialogAsync <WhatsNewDialog>(); break; } } else if (section == "rs" || section == "remote-subsystem") { try { await App.SetLoadingAsync(true); parser.TryGetValue("d", out var data); parser.TryGetValue("t", out var timespan); var result = App.RoamingService.DecodeActivityParameters(data); // Get the current track object BaseTrack currentTrack = null; var tracks = new List <BaseTrack>(); switch (result.CurrentTrack.Service) { case ServiceType.Fanburst: break; case ServiceType.SoundCloud: case ServiceType.SoundCloudV2: currentTrack = (await SoundByteService.Current.GetAsync <SoundCloudTrack>(ServiceType.SoundCloud, $"/tracks/{result.CurrentTrack.TrackId}")).Response.ToBaseTrack(); break; case ServiceType.YouTube: currentTrack = (await SoundByteService.Current.GetAsync <YouTubeVideoHolder>(ServiceType.YouTube, "videos", new Dictionary <string, string> { { "part", "snippet,contentDetails" }, { "id", result.CurrentTrack.TrackId } })).Response.Tracks.FirstOrDefault()?.ToBaseTrack(); break; case ServiceType.ITunesPodcast: // TODO: THIS break; } //TODO: List has to be put back into wanted order. var soundCloudIds = string.Join(',', result.Tracks.Where(x => x.Service == ServiceType.SoundCloud || x.Service == ServiceType.SoundCloudV2).Select(x => x.TrackId)); var fanburstIds = string.Join(',', result.Tracks.Where(x => x.Service == ServiceType.Fanburst).Select(x => x.TrackId)); var youTubeIds = string.Join(',', result.Tracks.Where(x => x.Service == ServiceType.YouTube).Select(x => x.TrackId)); // SoundCloud tracks tracks.AddRange((await SoundByteService.Current.GetAsync <List <SoundCloudTrack> >(ServiceType.SoundCloud, $"/tracks?ids={soundCloudIds}")).Response.Select(x => x.ToBaseTrack())); // YouTube Tracks tracks.AddRange((await SoundByteService.Current.GetAsync <YouTubeVideoHolder>(ServiceType.YouTube, "videos", new Dictionary <string, string> { { "part", "snippet,contentDetails" }, { "id", youTubeIds } })).Response.Tracks.Select(x => x.ToBaseTrack())); var startPlayback = await PlaybackService.Instance.InitilizePlaylistAsync(result.Source, tracks); if (startPlayback.Success) { TimeSpan?timeSpan = null; if (!string.IsNullOrEmpty(timespan)) { timeSpan = TimeSpan.FromMilliseconds(double.Parse(timespan)); } await PlaybackService.Instance.StartTrackAsync(currentTrack, timeSpan); } else { await NavigationService.Current.CallMessageDialogAsync(startPlayback.Message, "The remote protocol subsystem failed."); } await App.SetLoadingAsync(false); } catch (Exception e) { await App.SetLoadingAsync(false); await NavigationService.Current.CallMessageDialogAsync(e.Message, "The remote protocol subsystem failed."); } } } catch (Exception ex) { await NavigationService.Current.CallMessageDialogAsync( "The specified protocol is not correct. App will now launch as normal.\n\n" + ex.Message); } await App.SetLoadingAsync(false); } if (DeviceHelper.IsMobile) { RootFrame.Navigate(typeof(MobileView)); } else { RootFrame.Navigate(typeof(ExploreView)); } }