private async Task <ICollection <AnimeStreamInfo> > GetAnimeSeriesAsync(string apiToken, CancellationToken cancellationToken)
        {
            // https://public-api.viewster.com/series?genreId=58&pageSize=25
            int pageSize  = 100;
            int pageIndex = 1;

            HashSet <AnimeStreamInfo> streams = new HashSet <AnimeStreamInfo>(new ProjectionEqualityComparer <AnimeStreamInfo, string>(stream => stream.Url));

            string baseUrl = "https://public-api.viewster.com/series?genreId=58";
            ICollection <AnimeStreamInfo> streamsFromThisRequest;

            do
            {
                string url = baseUrl + string.Format("&pageSize={0}&pageIndex={1}", pageSize, pageIndex);

                Console.WriteLine("Getting Viewster anime page {0}.", pageIndex);
                WebClientRequest request = new WebClientRequest(url);
                request.Headers.Add(new KeyValuePair <string, string>("Auth-token", apiToken));
                request.Accept = "application/json";
                string json = await _webClient.GetStringAsync(request, cancellationToken).ConfigureAwait(continueOnCapturedContext: false);

                streamsFromThisRequest = ParseAnimeJson(json);
                streams.UnionWith(streamsFromThisRequest);

                pageIndex++;
            } while (streamsFromThisRequest.Count == pageSize);

            if (streams.Count == 0)
            {
                throw new Exception("No Viewster streams found, something must be wrong.");
            }
            return(streams.ToList());
        }
예제 #2
0
        public async Task <ICollection <AnimeStreamInfo> > GetAnimeStreamInfoAsync(CancellationToken cancellationToken)
        {
            Console.WriteLine("Getting HTML for {0}", Url);
            WebClientRequest request = new WebClientRequest(Url);

            ModifyRequestBeforeSending(request);

            string responseBody = await WebClient.GetStringAsync(request, cancellationToken).ConfigureAwait(continueOnCapturedContext: false);

            HtmlDocument htmlDoc = new HtmlDocument();

            htmlDoc.LoadHtml(responseBody);
            HtmlNodeCollection matchingNodes = htmlDoc.DocumentNode.SelectNodes(XPath);

            if (matchingNodes == null || matchingNodes.Count == 0)
            {
                throw new NoMatchingHtmlException(string.Format("Could not extract information from {0}. The site's HTML format probably changed.", Url));
            }

            List <AnimeStreamInfo> streams = new List <AnimeStreamInfo>();

            foreach (HtmlNode matchingNode in matchingNodes)
            {
                AnimeStreamInfo stream = GetStreamInfoFromMatch(matchingNode);

                // Convert possibly relative url to an absolute url
                stream = new AnimeStreamInfo(stream.AnimeName, Utils.PossiblyRelativeUrlToAbsoluteUrl(stream.Url, Url), stream.Service);

                streams.Add(stream);
            }

            OnStreamsExtracted(htmlDoc, streams);

            return(streams);
        }
        private async Task <string> GetAPITokenAsync(CancellationToken cancellationToken)
        {
            WebClientRequest request = new WebClientRequest(InitialPageUrl);

            request.Accept    = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
            request.UserAgent = "animerecs.com stream update tool";

            Console.WriteLine("Getting Viewster API token.");
            using (IWebClientResult result = await _webClient.GetAsync(request, cancellationToken).ConfigureAwait(continueOnCapturedContext: false))
            {
                CookieCollection viewsterCookies = _webClient.Cookies.GetCookies(new Uri("https://www.viewster.com/"));
                if (viewsterCookies == null)
                {
                    throw new Exception("No cookie collection for Viewster somehow.");
                }
                Cookie apiTokenCookie = viewsterCookies["api_token"];

                if (apiTokenCookie == null)
                {
                    throw new Exception("Viewster api_token cookie not set on initial page request. Maybe Viewster changed their site.");
                }

                return(WebUtility.UrlDecode(apiTokenCookie.Value));
            }
        }
예제 #4
0
 public static async Task <string> GetStringAsync(this IWebClient webClient, WebClientRequest request, CancellationToken cancellationToken)
 {
     using (IWebClientResult result = await webClient.GetAsync(request, cancellationToken).ConfigureAwait(continueOnCapturedContext: false))
     {
         return(await result.ReadResponseAsStringAsync(cancellationToken).ConfigureAwait(continueOnCapturedContext: false));
     }
 }
예제 #5
0
        private async Task <IWebClientResult> DoRequestAsync(WebClientRequest request, HttpMethod method, CancellationToken cancellationToken)
        {
            using (HttpRequestMessage translatedRequest = TranslateRequest(request, method))
            {
                HttpResponseMessage response = await _client.SendAsync(translatedRequest, HttpCompletionOption.ResponseContentRead, cancellationToken).ConfigureAwait(continueOnCapturedContext: false);

                try
                {
                    if (!response.IsSuccessStatusCode)
                    {
                        throw new Exception(string.Format("Request to {0} failed with status code {1}.", request.URL, response.StatusCode));
                    }
                }
                catch (Exception)
                {
                    response.Dispose();
                    throw;
                }

                return(new WebClientResult(response));
            }
        }
예제 #6
0
        private HttpRequestMessage TranslateRequest(WebClientRequest request, HttpMethod method)
        {
            HttpRequestMessage translatedRequest = new HttpRequestMessage(method, request.URL);

            if (request.UserAgent != null)
            {
                if (!translatedRequest.Headers.TryAddWithoutValidation("User-Agent", request.UserAgent))
                {
                    throw new Exception("Failed adding user agent string to request.");
                }
            }

            if (request.Accept != null)
            {
                if (!translatedRequest.Headers.TryAddWithoutValidation("Accept", request.Accept))
                {
                    throw new Exception("Failed adding Accept header to request.");
                }
            }

            if (request.Headers != null)
            {
                foreach (KeyValuePair <string, string> header in request.Headers)
                {
                    if (!translatedRequest.Headers.TryAddWithoutValidation(header.Key, header.Value))
                    {
                        throw new Exception(string.Format("Failed adding {0} header with value {1} to request.", header.Key, header.Value));
                    }
                }
            }

            if (method == HttpMethod.Post && request.PostParameters != null && request.PostParameters.Count > 0)
            {
                FormUrlEncodedContent encodedContent = new FormUrlEncodedContent(request.PostParameters);
                translatedRequest.Content = encodedContent;
            }

            return(translatedRequest);
        }
예제 #7
0
 /// <summary>
 /// Subclasses can add headers here.
 /// </summary>
 protected virtual void ModifyRequestBeforeSending(WebClientRequest request)
 {
 }
예제 #8
0
 /// <summary>
 /// Not currently supported.
 /// </summary>
 /// <param name="request"></param>
 /// <param name="cancellationToken"></param>
 /// <returns></returns>
 public Task <IWebClientResult> PostAsync(WebClientRequest request, CancellationToken cancellationToken)
 {
     throw new NotImplementedException();
 }
예제 #9
0
 private IWebClientResult GetSync(WebClientRequest request)
 {
     _driver.Navigate().GoToUrl(request.URL);
     return(new StringWebClientResult(_driver.PageSource));
 }
예제 #10
0
 /// <summary>
 /// Does not currently honor any of the properties of <paramref name="request"/> other than the URL.
 /// Does not currently honor the cancellation token.
 /// </summary>
 /// <param name="request"></param>
 /// <param name="cancellationToken"></param>
 /// <returns></returns>
 public Task <IWebClientResult> GetAsync(WebClientRequest request, CancellationToken cancellationToken)
 {
     // Selenium's Chrome Driver support has no async support. So do the request on a separate thread.
     return(Task.Factory.StartNew(() => GetSync(request), cancellationToken, TaskCreationOptions.LongRunning, TaskScheduler.Default));
 }
예제 #11
0
 protected override void ModifyRequestBeforeSending(WebClientRequest request)
 {
     // Hidive returns a 403 forbidden if we don't use a browser's user agent.
     request.UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:57.0) Gecko/20100101 Firefox/57.0";
 }
예제 #12
0
 public Task <IWebClientResult> GetAsync(WebClientRequest request, CancellationToken cancellationToken)
 {
     return(DoRequestAsync(request, HttpMethod.Get, cancellationToken));
 }
예제 #13
0
 internal WebPageStreamInfoSource(string url, IWebClient webClient)
 {
     Request   = new WebClientRequest(url);
     WebClient = webClient;
 }