diff --git a/MainPage.xaml.cs b/MainPage.xaml.cs index 4605aea..201176f 100644 --- a/MainPage.xaml.cs +++ b/MainPage.xaml.cs @@ -2,6 +2,7 @@ using System.Linq; using System.Text.RegularExpressions; using System.Threading; +using System.Threading.Tasks; using Windows.UI.Core; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; @@ -23,6 +24,7 @@ public sealed partial class MainPage : Page public MainPage() { this.search = new Search(); + this.search.FinishedFetchingResults += PresentResults; this.InitializeComponent(); this.NavigationCacheMode = NavigationCacheMode.Enabled; } @@ -53,7 +55,7 @@ private void HandlePlayButton(object sender, RoutedEventArgs eventArgs) if (list != null && list.Count > 0) { - SetAsMediaURL(list.ElementAt(0).VideoId); + SetAsMediaURL(list.ElementAt(0).MediaUrl); PrepareToPlay(); } else @@ -266,6 +268,7 @@ await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { LoadingRing.IsActive = true; + inputBox.IsSuggestionListOpen = false; ErrorMessage.Visibility = Visibility.Collapsed; } ); @@ -296,36 +299,60 @@ private async void inputBox_TextChanged(AutoSuggestBox sender, AutoSuggestBoxTex SetAsMediaURL(inputBox.Text); PrepareToPlay(); } + else + { + await DoSearch(); + } } else { - if (this.inLoadingState == false) - { - this.inLoadingState = true; - RunUIUpdateByMethod(WeakLoading); - } - - try - { - await this.search.ByTerm(inputBox.Text); - } - catch - { - InLoadingState(false); - - ShowErrorMessage("Search is not available now, please use links."); - return; - } + await DoSearch(); + } + } + } - if (this.inLoadingState == true) - { - InLoadingState(false); - } + /// + /// Does the search using the text available on inputBox. + /// + /// + private async Task DoSearch() + { + if (this.inLoadingState == false) + { + this.inLoadingState = true; + RunUIUpdateByMethod(WeakLoading); + } - sender.ItemsSource = this.search.Retreive(); - inputBox.IsSuggestionListOpen = true; + try + { + await this.search.ByTerm(inputBox.Text); + } + catch (Exception ex) + { + if (!(ex is NotSupportedException)) + { + InLoadingState(false); + ShowErrorMessage("Search is not available now, please use links."); } + + } + } + + /// + /// Presents the results on AutoSuggestBox when the results are ready. + /// This function is triggered by the Search's FinishedFetchingResults event. + /// + /// + /// + public void PresentResults(Object sender, EventArgs e) + { + if (this.inLoadingState == true) + { + InLoadingState(false); } + + inputBox.ItemsSource = this.search.Retreive(); + inputBox.IsSuggestionListOpen = true; } /// @@ -339,7 +366,7 @@ private void inputBox_QuerySubmitted(AutoSuggestBox sender, AutoSuggestBoxQueryS { InLoadingState(true); ListItem chosenItem = (ListItem)args.ChosenSuggestion; - SetAsMediaURL("https://www.youtube.com/watch?v=" + chosenItem.VideoId); + SetAsMediaURL(chosenItem.MediaUrl); PrepareVideoUI(); } diff --git a/Package.appxmanifest b/Package.appxmanifest index 79b4e31..f82293f 100644 --- a/Package.appxmanifest +++ b/Package.appxmanifest @@ -10,7 +10,7 @@ + Version="1.4.1.0" /> diff --git a/Search/ListItems.cs b/Search/ListItems.cs index 81fc805..4ed4c48 100644 --- a/Search/ListItems.cs +++ b/Search/ListItems.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using System.Collections.ObjectModel; namespace YoutubeGameBarWidget.Search { @@ -19,19 +14,19 @@ public class ListItem { public string VideoTitle { get; set; } public string ChannelTitle { get; set; } - public string VideoId { get; set; } + public string MediaUrl { get; set; } /// /// A list item object. /// /// The video title of the item. /// The channel title of the item. - /// The video ID of the item. - public ListItem(string videoTitle, string channelTitle, string videoId) + /// The Media URL of the item. + public ListItem(string videoTitle, string channelTitle, string mediaUrl) { this.VideoTitle = videoTitle; this.ChannelTitle = channelTitle; - this.VideoId = videoId; + this.MediaUrl = mediaUrl; } } } diff --git a/Search/Search.cs b/Search/Search.cs index d800891..e251818 100644 --- a/Search/Search.cs +++ b/Search/Search.cs @@ -1,64 +1,76 @@ -using Google.Apis.Services; -using Google.Apis.YouTube.v3; -using Google.Apis.YouTube.v3.Data; -using System; +using System; +using System.Net; using System.Threading.Tasks; +using Windows.Data.Json; namespace YoutubeGameBarWidget.Search { /// - /// Implements a Data Retriever using Google's Youtube API. + /// Implements a Data Retriever using Youtube GameBar Search Server's service. /// - /// For more details, see: https://developers.google.com/youtube/v3/docs/search/list + /// For more API details, see: https://github.com/MarconiGRF/YoutubeGameBarSearchServer /// class Search { - private YouTubeService _youtubeService; - private SearchResource.ListRequest _listRequest; - private SearchListResponse _listResponse; + private WebClient client; + private string ytgbssEndPoint; public ListItems parsedResults; + public event EventHandler FinishedFetchingResults; /// - /// A simple constructor setting the common parameters for every request. + /// The FinishedFetchingResults event method manager. + /// + /// + protected virtual void OnFinishedFetchingResults(EventArgs e) + { + EventHandler handler = FinishedFetchingResults; + handler?.Invoke(this, e); + } + + /// + /// A simple constructor setting the common parameters for every search request. /// public Search() { - _youtubeService = new YouTubeService(new BaseClientService.Initializer() - { - ApiKey = Environment.GetEnvironmentVariable("YT_DATA_API_KEY"), - ApplicationName = "YoutubeGameBarWidget" - }); + this.ytgbssEndPoint = "http://" + + Environment.GetEnvironmentVariable("YTGBSS_ADDRESS") + ":" + + Environment.GetEnvironmentVariable("YTGBSS_PORT") + "/search/"; - this._listRequest = this._youtubeService.Search.List("snippet"); - _listRequest.Type = "video"; - _listRequest.MaxResults = 5; - _listRequest.SafeSearch = SearchResource.ListRequest.SafeSearchEnum.None; + this.client = new WebClient(); + this.client.Headers.Add(HttpRequestHeader.ContentType, "application/json"); + this.client.DownloadStringCompleted += new DownloadStringCompletedEventHandler(ParseResults); } /// - /// Performs a search request on Data API by the given term, parsing the response into a ListItems object. + /// Performs a search (GET) request on YTGBSS by the given term, raising events when the raw data is ready. /// - /// The term to compose the request. - /// - public async Task ByTerm(string term) + /// The term to compose the request. + /// 0 + public async Task ByTerm(string givenTerm) { - this._listRequest.Q = term; - this._listResponse = await _listRequest.ExecuteAsync(); + this.client.DownloadStringAsync(new Uri(ytgbssEndPoint + givenTerm)); + } + /// + /// Parses the raw data into a ListItems object, raising FinishedFetchingResults event when finished. + /// + /// + /// + private void ParseResults(Object sender, DownloadStringCompletedEventArgs e) + { this.parsedResults = new ListItems(); - foreach (SearchResult resultItem in this._listResponse.Items) + + JsonArray jArray = JsonArray.Parse((string)e.Result); + foreach (JsonValue jValue in jArray) { - switch (resultItem.Id.Kind) - { - case "youtube#video": - this.parsedResults.Add(new ListItem( - resultItem.Snippet.Title, - resultItem.Snippet.ChannelTitle, - resultItem.Id.VideoId) - ); - break; - } + JsonObject jObject = jValue.GetObject(); + this.parsedResults.Add(new ListItem( + jObject.GetNamedString("videoTitle"), + jObject.GetNamedString("channelTitle"), + jObject.GetNamedString("mediaUrl"))); } + + this.OnFinishedFetchingResults(EventArgs.Empty); } ///