public YoutubeSongViewModel(YoutubeSong wrapped, Func<string> downloadPathFunc) : base(wrapped) { this.hasThumbnail = this.WhenAnyValue(x => x.Thumbnail) .Select(x => x != null) .ToProperty(this, x => x.HasThumbnail); // Wait for the opening of the context menu to download the YouTube information this.WhenAnyValue(x => x.IsContextMenuOpen) .FirstAsync(x => x) .SelectMany(_ => this.LoadContextMenu().ToObservable()) .Subscribe(); // We have to set a dummy here, so that we can connect the commands this.isDownloading = Observable.Never<bool>().ToProperty(this, x => x.IsDownloading); this.DownloadVideoCommand = ReactiveCommand.CreateAsyncTask(this.WhenAnyValue(x => x.IsDownloading).Select(x => !x), x => this.DownloadVideo((VideoInfo)x, downloadPathFunc())); this.DownloadAudioCommand = ReactiveCommand.CreateAsyncTask(this.WhenAnyValue(x => x.IsDownloading).Select(x => !x), x => this.DownloadAudio((VideoInfo)x, downloadPathFunc())); this.isDownloading = this.DownloadVideoCommand.IsExecuting .CombineLatest(this.DownloadAudioCommand.IsExecuting, (x1, x2) => x1 || x2) .ToProperty(this, x => x.IsDownloading); }
public async Task<IReadOnlyList<YoutubeSong>> GetSongsAsync(string searchTerm) { var query = new YouTubeQuery(YouTubeQuery.DefaultVideoUri) { OrderBy = "relevance", Query = searchTerm, SafeSearch = YouTubeQuery.SafeSearchValues.None }; try // The API gives no clue what can throw, wrap it all up { // NB: I have no idea where this API blocks exactly var settings = new YouTubeRequestSettings("Espera", ApiKey); var request = new YouTubeRequest(settings); Feed<Video> feed = await Task.Run(() => request.Get<Video>(query)); List<Video> entries = await Task.Run(() => feed.Entries.ToList()); var songs = new List<YoutubeSong>(); foreach (Video video in entries) { var duration = TimeSpan.FromSeconds(Int32.Parse(video.YouTubeEntry.Duration.Seconds)); string url = video.WatchPage.OriginalString .Replace("&feature=youtube_gdata_player", String.Empty) // Unnecessary long url .Replace("https://", "http://"); // Secure connections are not always easy to handle when streaming var song = new YoutubeSong(url, duration) { Title = video.Title, Description = video.Description, Rating = video.RatingAverage >= 1 ? video.RatingAverage : (double?)null, ThumbnailSource = new Uri(video.Thumbnails[0].Url), Views = video.ViewCount }; songs.Add(song); } return songs; } catch (Exception ex) { throw new NetworkSongFinderException("YoutubeSongFinder search failed", ex); } }
private static IObservable <IReadOnlyList <YoutubeSong> > RealSearch(string searchTerm) { var query = new YouTubeQuery(YouTubeQuery.DefaultVideoUri) { OrderBy = "relevance", Query = searchTerm, SafeSearch = YouTubeQuery.SafeSearchValues.None, NumberToRetrieve = RequestLimit }; // NB: I have no idea where this API blocks exactly var settings = new YouTubeRequestSettings("Espera", ApiKey); var request = new YouTubeRequest(settings); return(Observable.FromAsync(async() => { Feed <Video> feed = await Task.Run(() => request.Get <Video>(query)); List <Video> entries = await Task.Run(() => feed.Entries.ToList()); var songs = new List <YoutubeSong>(); foreach (Video video in entries) { var duration = TimeSpan.FromSeconds(Int32.Parse(video.YouTubeEntry.Duration.Seconds)); string url = video.WatchPage.OriginalString .Replace("&feature=youtube_gdata_player", String.Empty) // Unnecessary long url .Replace("https://", "http://"); // Secure connections are not always easy to handle when streaming var song = new YoutubeSong(url, duration) { Artist = video.Uploader, Title = video.Title, Description = video.Description, Rating = video.RatingAverage >= 1 ? video.RatingAverage : (double?)null, ThumbnailSource = new Uri(video.Thumbnails[0].Url), Views = video.ViewCount }; songs.Add(song); } return songs; }) // The API gives no clue what can throw, wrap it all up .Catch <IReadOnlyList <YoutubeSong>, Exception>(ex => Observable.Throw <IReadOnlyList <YoutubeSong> >(new NetworkSongFinderException("YoutubeSongFinder search failed", ex)))); }
public async Task NullUriThrowsArgumentNullException() { const string youtubePath = "http://youtube.com?v=yadda"; var song = new YoutubeSong(youtubePath, TimeSpan.FromMinutes(1)); var songFinder = Substitute.For<IYoutubeSongFinder>(); songFinder.ResolveYoutubeSongFromUrl(Arg.Any<Uri>()).Returns(Task.FromResult(song)); using (var library = new LibraryBuilder().WithPlaylist().Build()) { Guid accessToken = library.LocalAccessControl.RegisterLocalAccessToken(); var playlist = library.Playlists.First(); library.SwitchToPlaylist(playlist, accessToken); var fixture = new DirectYoutubeViewModel(library, accessToken, songFinder); await Helpers.ThrowsAsync<ArgumentNullException>(() => fixture.AddDirectYoutubeUrlToPlaylist(null, null)); } }
public void SmokeTest() { var song1 = new YoutubeSong("www.youtube.com?watch=abcde", TimeSpan.Zero) { Title = "A" }; var song2 = new YoutubeSong("www.youtube.com?watch=abcdef", TimeSpan.Zero) { Title = "B" }; var songs = (IReadOnlyList<YoutubeSong>)new[] { song1, song2 }.ToList(); var songFinder = Substitute.For<IYoutubeSongFinder>(); songFinder.GetSongsAsync(Arg.Any<string>()).Returns(Observable.Return(songs)); using (var library = Helpers.CreateLibrary()) { Guid token = library.LocalAccessControl.RegisterLocalAccessToken(); var vm = new YoutubeViewModel(library, new ViewSettings(), new CoreSettings(), token, songFinder); Assert.Equal(songs, vm.SelectableSongs.Select(x => x.Model).ToList()); Assert.Equal(songs.First(), vm.SelectableSongs.First().Model); Assert.False(vm.IsSearching); } }
public async Task SmokeTest() { const string youtubePath = "http://youtube.com?v=yadda"; var song = new YoutubeSong(youtubePath, TimeSpan.FromMinutes(1)); var songFinder = Substitute.For<IYoutubeSongFinder>(); songFinder.ResolveYoutubeSongFromUrl(Arg.Any<Uri>()).Returns(Task.FromResult(song)); using (var library = new LibraryBuilder().WithPlaylist().Build()) { Guid accessToken = library.LocalAccessControl.RegisterLocalAccessToken(); var playlist = library.Playlists.First(); library.SwitchToPlaylist(playlist, accessToken); var fixture = new DirectYoutubeViewModel(library, accessToken, songFinder); await fixture.AddDirectYoutubeUrlToPlaylist(new Uri(youtubePath), null); Assert.Equal(1, playlist.Count()); } }
public YoutubeSongViewModel(YoutubeSong wrapped) : base(wrapped) { }