public override async Task <SearchResponse> Search(SearchRequest request, ServerCallContext context) { // Check if parameters fulfill our basic requirements if (string.IsNullOrWhiteSpace(request.Query)) { return(SearchFailure("query is empty")); } // Try to extract a video id from the query and fetch information for that specific video if (ParseVideoId(request.Query, out string videoIdFromQuery)) { // Use youtube-dl to get the video information YouTubeVideoInformation videoInformation = null; try { var cancellationTokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(5)); videoInformation = await GetVideoInformationAsync(videoIdFromQuery, cancellationTokenSource.Token); } catch (OperationCanceledException) { logger.LogError($"Search: Video information lookup (id: {videoIdFromQuery}) took too long to respond (> 5 seconds)"); return(SearchFailure("remote api information fetch timeout")); } catch (Exception exception) { logger.LogInformation($"Search: Downloading video (id: {videoIdFromQuery}) information through youtube-dl has failed: {exception}"); return(SearchFailure("remote api information fetch exception")); } if (videoInformation == null) { logger.LogInformation($"Search: Video (id: {videoIdFromQuery}) information is empty"); return(SearchFailure("video not available")); } else if (videoInformation.Video == null || videoInformation.Error != null) { logger.LogInformation( $"Stream: Downloading video (id: {videoIdFromQuery}) information through youtube-dl has failed: {videoInformation.Error}"); return(SearchFailure("video not available")); } else { var response = new SearchResponse { Status = new ResponseStatus { Success = true } }; response.Items.Add(new SearchResponseItem { Id = videoInformation.Video.Id, Title = videoInformation.Video.Title, }); return(response); } } else { // Search for videos GoogleYouTubeApi.SearchResource.ListRequest searchListRequest = googleYouTubeService.Search.List("snippet"); searchListRequest.Q = request.Query; searchListRequest.MaxResults = 50; searchListRequest.Order = GoogleYouTubeApi.SearchResource.ListRequest.OrderEnum.ViewCount; searchListRequest.SafeSearch = GoogleYouTubeApi.SearchResource.ListRequest.SafeSearchEnum.None; searchListRequest.Type = "video"; searchListRequest.VideoDimension = GoogleYouTubeApi.SearchResource.ListRequest.VideoDimensionEnum.Value2d; GoogleYouTubeApi.Data.SearchListResponse searchListResponse = null; try { var cancellationTokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(5)); searchListResponse = await searchListRequest.ExecuteAsync(cancellationTokenSource.Token); } catch (OperationCanceledException) { logger.LogError($"Video search (query: {request.Query}) took too long to respond (> 5 seconds)"); return(SearchFailure("remote api search timeout")); } catch (Exception exception) { logger.LogError($"Video search (query: {request.Query}) threw an exception: {exception}"); return(SearchFailure("remote api search exception")); } // Check the search response if (searchListResponse == null) { logger.LogError($"Video search (query: {request.Query}) with invalid result"); return(SearchFailure("unknown search error")); } var response = new SearchResponse { Status = new ResponseStatus { Success = true } }; response.Items.AddRange( searchListResponse.Items.Select(item => new SearchResponseItem { Id = item.Id.VideoId, Title = item.Snippet.Title, })); return(response); } }
public override async Task <StreamResponse> Stream(StreamRequest request, ServerCallContext context) { // Check if parameters fulfill our basic requirements if (!IsVideoId(request.Id)) { return(StreamFailure("invalid video id")); } // Use youtube-dl to get the URL for the download YouTubeVideoInformation videoInformation = null; try { var cancellationTokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(5)); videoInformation = await GetVideoInformationAsync(request.Id, cancellationTokenSource.Token); } catch (OperationCanceledException) { logger.LogError($"Stream: Video information lookup (id: {request.Id}) took too long to respond (> 5 seconds)"); return(StreamFailure("remote api information fetch timeout")); } catch (Exception exception) { logger.LogInformation($"Stream: Downloading video (id: {request.Id}) information through youtube-dl has failed: {exception}"); return(StreamFailure("video information fetch exception")); } if (videoInformation == null) { logger.LogInformation($"Stream: Video (id: {request.Id}) information is empty"); return(StreamFailure("video information is empty")); } else if (videoInformation.Video == null || videoInformation.Error != null) { logger.LogInformation( $"Stream: Downloading video (id: {request.Id}) information through youtube-dl has failed: {videoInformation.Error}"); return(StreamFailure("video information fetch error")); } else { // Filter video information by supported formats and order by format id IOrderedEnumerable <YouTubeVideoFormat> videoFormats = videoInformation.Video.Formats.Where(format => supportedFormats.Contains(format.FormatId)) .OrderByDescending(format => Convert.ToInt64(format.FormatId)); // Find a responsive downloadable url foreach (YouTubeVideoFormat videoFormat in videoFormats) { if (await IsURLAvailable(videoFormat.Url)) { return(new StreamResponse { Status = new ResponseStatus { Success = true }, Url = videoFormat.Url, }); } } return(StreamFailure("video is not playable")); } }