private string GetLanguage(ListingsProviderInfo info) { if (!string.IsNullOrWhiteSpace(info.PreferredLanguage)) { return(info.PreferredLanguage); } return(_config.Configuration.PreferredMetadataLanguage); }
public Task Validate(ListingsProviderInfo info, bool validateLogin, bool validateListings) { // Assume all urls are valid. check files for existence if (!info.Path.StartsWith("http", StringComparison.OrdinalIgnoreCase) && !_fileSystem.FileExists(info.Path)) { throw new FileNotFoundException("Could not find the XmlTv file specified:", info.Path); } return(Task.FromResult(true)); }
public async Task <List <NameIdPair> > GetLineups(ListingsProviderInfo info, string country, string location) { // In theory this should never be called because there is always only one lineup var channels = await GetChannels(info, CancellationToken.None); return(channels.Select(i => new NameIdPair { Name = i.Name, Id = i.Id }).ToList()); }
public async Task <List <NameIdPair> > GetHeadends(ListingsProviderInfo info, string country, string location, CancellationToken cancellationToken) { var token = await GetToken(info, cancellationToken); var lineups = new List <NameIdPair>(); if (string.IsNullOrWhiteSpace(token)) { return(lineups); } var options = new HttpRequestOptions() { Url = ApiUrl + "/headends?country=" + country + "&postalcode=" + location, UserAgent = UserAgent, CancellationToken = cancellationToken, LogErrorResponseBody = true }; options.RequestHeaders["token"] = token; try { using (Stream responce = await Get(options, false, info).ConfigureAwait(false)) { var root = _jsonSerializer.DeserializeFromStream <List <ScheduleDirect.Headends> >(responce); if (root != null) { foreach (ScheduleDirect.Headends headend in root) { foreach (ScheduleDirect.Lineup lineup in headend.lineups) { lineups.Add(new NameIdPair { Name = string.IsNullOrWhiteSpace(lineup.name) ? lineup.lineup : lineup.name, Id = lineup.uri.Substring(18) }); } } } else { _logger.Info("No lineups available"); } } } catch (Exception ex) { _logger.Error("Error getting headends", ex); } return(lineups); }
private async Task <List <ScheduleDirect.ShowImages> > GetImageForPrograms( ListingsProviderInfo info, List <string> programIds, CancellationToken cancellationToken) { if (programIds.Count == 0) { return(new List <ScheduleDirect.ShowImages>()); } var imageIdString = "["; foreach (var i in programIds) { var imageId = i.Substring(0, 10); if (!imageIdString.Contains(imageId)) { imageIdString += "\"" + imageId + "\","; } } imageIdString = imageIdString.TrimEnd(',') + "]"; var httpOptions = new HttpRequestOptions() { Url = ApiUrl + "/metadata/programs", UserAgent = UserAgent, CancellationToken = cancellationToken, RequestContent = imageIdString, LogErrorResponseBody = true, // The data can be large so give it some extra time TimeoutMs = 60000 }; try { using (var innerResponse2 = await Post(httpOptions, true, info).ConfigureAwait(false)) { return(_jsonSerializer.DeserializeFromStream <List <ScheduleDirect.ShowImages> >( innerResponse2.Content)); } } catch (Exception ex) { _logger.ErrorException("Error getting image info from schedules direct", ex); return(new List <ScheduleDirect.ShowImages>()); } }
public async Task <List <NameIdPair> > GetLineups(ListingsProviderInfo info, string country, string location) { // In theory this should never be called because there is always only one lineup var path = await GetXml(info.Path, CancellationToken.None).ConfigureAwait(false); var reader = new XmlTvReader(path, GetLanguage()); var results = reader.GetChannels(); // Should this method be async? return(results.Select(c => new NameIdPair() { Id = c.Id, Name = c.DisplayName }).ToList()); }
private bool IsListingProviderEnabledForTuner(ListingsProviderInfo info, string tunerHostId) { if (info.EnableAllTuners) { return(true); } if (string.IsNullOrWhiteSpace(tunerHostId)) { throw new ArgumentNullException("tunerHostId"); } return(info.EnabledTuners.Contains(tunerHostId, StringComparer.OrdinalIgnoreCase)); }
public async Task <List <NameIdPair> > GetHeadends(ListingsProviderInfo info, string country, string location, CancellationToken cancellationToken) { var token = await GetToken(info, cancellationToken).ConfigureAwait(false); var lineups = new List <NameIdPair>(); if (string.IsNullOrWhiteSpace(token)) { return(lineups); } using var options = new HttpRequestMessage(HttpMethod.Get, ApiUrl + "/headends?country=" + country + "&postalcode=" + location); options.Headers.TryAddWithoutValidation("token", token); try { using var httpResponse = await Send(options, false, info, cancellationToken).ConfigureAwait(false); await using var response = await httpResponse.Content.ReadAsStreamAsync().ConfigureAwait(false); var root = await _jsonSerializer.DeserializeFromStreamAsync <List <ScheduleDirect.Headends> >(response).ConfigureAwait(false); if (root != null) { foreach (ScheduleDirect.Headends headend in root) { foreach (ScheduleDirect.Lineup lineup in headend.lineups) { lineups.Add(new NameIdPair { Name = string.IsNullOrWhiteSpace(lineup.name) ? lineup.lineup : lineup.name, Id = lineup.uri.Substring(18) }); } } } else { _logger.LogInformation("No lineups available"); } } catch (Exception ex) { _logger.LogError(ex, "Error getting headends"); } return(lineups); }
public async Task <IEnumerable <ProgramInfo> > GetProgramsAsync(ListingsProviderInfo info, string channelNumber, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken) { channelNumber = NormalizeNumber(channelNumber); var url = "https://data.emby.media/service/listings?id=" + info.ListingsId; // Normalize startDateUtc = startDateUtc.Date; endDateUtc = startDateUtc.AddDays(7); url += "&start=" + startDateUtc.ToString("s", CultureInfo.InvariantCulture) + "Z"; url += "&end=" + endDateUtc.ToString("s", CultureInfo.InvariantCulture) + "Z"; var response = await GetResponse <ListingInfo[]>(url).ConfigureAwait(false); return(response.Where(i => IncludeInResults(i, channelNumber)).Select(GetProgramInfo).OrderBy(i => i.StartDate)); }
public async Task <IEnumerable <ProgramInfo> > GetProgramsAsync(ListingsProviderInfo info, string channelId, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken) { if (string.IsNullOrWhiteSpace(channelId)) { throw new ArgumentNullException(nameof(channelId)); } _logger.LogDebug("Getting xmltv programs for channel {Id}", channelId); string path = await GetXml(info.Path, cancellationToken).ConfigureAwait(false); _logger.LogDebug("Opening XmlTvReader for {Path}", path); var reader = new XmlTvReader(path, GetLanguage(info)); return(reader.GetProgrammes(channelId, startDateUtc, endDateUtc, cancellationToken) .Select(p => GetProgramInfo(p, info))); }
public async Task <List <ChannelInfo> > GetChannels(ListingsProviderInfo info, CancellationToken cancellationToken) { // In theory this should never be called because there is always only one lineup var path = await GetXml(info.Path, cancellationToken).ConfigureAwait(false); var reader = new XmlTvReader(path, GetLanguage()); var results = reader.GetChannels(); // Should this method be async? return(results.Select(c => new ChannelInfo() { Id = c.Id, Name = c.DisplayName, ImageUrl = c.Icon != null && !String.IsNullOrEmpty(c.Icon.Source) ? c.Icon.Source : null, Number = c.Id }).ToList()); }
private async Task <bool> HasLineup(ListingsProviderInfo info, CancellationToken cancellationToken) { if (string.IsNullOrWhiteSpace(info.ListingsId)) { throw new ArgumentException("Listings Id required"); } var token = await GetToken(info, cancellationToken); if (string.IsNullOrWhiteSpace(token)) { throw new Exception("token required"); } _logger.Info("Headends on account "); var options = new HttpRequestOptions() { Url = ApiUrl + "/lineups", UserAgent = UserAgent, CancellationToken = cancellationToken, LogErrorResponseBody = true }; options.RequestHeaders["token"] = token; try { using (var response = await Get(options, false, null).ConfigureAwait(false)) { var root = _jsonSerializer.DeserializeFromStream <ScheduleDirect.Lineups>(response); return(root.lineups.Any(i => string.Equals(info.ListingsId, i.lineup, StringComparison.OrdinalIgnoreCase))); } } catch (HttpException ex) { // Apparently we're supposed to swallow this if (ex.StatusCode.HasValue && ex.StatusCode.Value == HttpStatusCode.BadRequest) { return(false); } throw; } }
public async Task <IEnumerable <ProgramInfo> > GetProgramsAsync(ListingsProviderInfo info, string channelNumber, string channelName, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken) { if (!await EmbyTV.EmbyTVRegistration.Instance.EnableXmlTv().ConfigureAwait(false)) { var length = endDateUtc - startDateUtc; if (length.TotalDays > 1) { endDateUtc = startDateUtc.AddDays(1); } } var path = await GetXml(info.Path, cancellationToken).ConfigureAwait(false); var reader = new XmlTvReader(path, GetLanguage(), null); var results = reader.GetProgrammes(channelNumber, startDateUtc, endDateUtc, cancellationToken); return(results.Select(p => new ProgramInfo() { ChannelId = p.ChannelId, EndDate = GetDate(p.EndDate), EpisodeNumber = p.Episode == null ? null : p.Episode.Episode, EpisodeTitle = p.Episode == null ? null : p.Episode.Title, Genres = p.Categories, Id = String.Format("{0}_{1:O}", p.ChannelId, p.StartDate), // Construct an id from the channel and start date, StartDate = GetDate(p.StartDate), Name = p.Title, Overview = p.Description, ShortOverview = p.Description, ProductionYear = !p.CopyrightDate.HasValue ? (int?)null : p.CopyrightDate.Value.Year, SeasonNumber = p.Episode == null ? null : p.Episode.Series, IsSeries = p.Episode != null, IsRepeat = p.IsRepeat, IsPremiere = p.Premiere != null, IsKids = p.Categories.Any(c => info.KidsCategories.Contains(c, StringComparer.InvariantCultureIgnoreCase)), IsMovie = p.Categories.Any(c => info.MovieCategories.Contains(c, StringComparer.InvariantCultureIgnoreCase)), IsNews = p.Categories.Any(c => info.NewsCategories.Contains(c, StringComparer.InvariantCultureIgnoreCase)), IsSports = p.Categories.Any(c => info.SportsCategories.Contains(c, StringComparer.InvariantCultureIgnoreCase)), ImageUrl = p.Icon != null && !String.IsNullOrEmpty(p.Icon.Source) ? p.Icon.Source : null, HasImage = p.Icon != null && !String.IsNullOrEmpty(p.Icon.Source), OfficialRating = p.Rating != null && !String.IsNullOrEmpty(p.Rating.Value) ? p.Rating.Value : null, CommunityRating = p.StarRating.HasValue ? p.StarRating.Value : (float?)null, SeriesId = p.Episode != null ? p.Title.GetMD5().ToString("N") : null })); }
private async Task <List <ScheduleDirect.ShowImages> > GetImageForPrograms( ListingsProviderInfo info, List <string> programIds, CancellationToken cancellationToken) { if (programIds.Count == 0) { return(new List <ScheduleDirect.ShowImages>()); } var imageIdString = "["; foreach (var i in programIds) { var imageId = i.Substring(0, 10); if (!imageIdString.Contains(imageId, StringComparison.Ordinal)) { imageIdString += "\"" + imageId + "\","; } } imageIdString = imageIdString.TrimEnd(',') + "]"; using var message = new HttpRequestMessage(HttpMethod.Post, ApiUrl + "/metadata/programs") { Content = new StringContent(imageIdString, Encoding.UTF8, MediaTypeNames.Application.Json) }; try { using var innerResponse2 = await Send(message, true, info, cancellationToken).ConfigureAwait(false); await using var response = await innerResponse2.Content.ReadAsStreamAsync().ConfigureAwait(false); return(await _jsonSerializer.DeserializeFromStreamAsync <List <ScheduleDirect.ShowImages> >( response).ConfigureAwait(false)); } catch (Exception ex) { _logger.LogError(ex, "Error getting image info from schedules direct"); return(new List <ScheduleDirect.ShowImages>()); } }
public async Task <List <ChannelInfo> > GetChannels(ListingsProviderInfo info, CancellationToken cancellationToken) { // In theory this should never be called because there is always only one lineup string path = await GetXml(info, cancellationToken).ConfigureAwait(false); _logger.LogDebug("Opening XmlTvReader for {Path}", path); var reader = new XmlTvReader(path, GetLanguage(info)); var results = reader.GetChannels(); // Should this method be async? return(results.Select(c => new ChannelInfo { Id = c.Id, Name = c.DisplayName, ImageUrl = c.Icon != null && !string.IsNullOrEmpty(c.Icon.Source) ? c.Icon.Source : null, Number = string.IsNullOrWhiteSpace(c.Number) ? c.Id : c.Number }).ToList()); }
private async Task <IReadOnlyList <ShowImagesDto> > GetImageForPrograms( ListingsProviderInfo info, IReadOnlyList <string> programIds, CancellationToken cancellationToken) { if (programIds.Count == 0) { return(Array.Empty <ShowImagesDto>()); } StringBuilder str = new StringBuilder("[", 1 + (programIds.Count * 13)); foreach (ReadOnlySpan <char> i in programIds) { str.Append('"') .Append(i.Slice(0, 10)) .Append("\","); } // Remove last , str.Length--; str.Append(']'); using var message = new HttpRequestMessage(HttpMethod.Post, ApiUrl + "/metadata/programs") { Content = new StringContent(str.ToString(), Encoding.UTF8, MediaTypeNames.Application.Json) }; try { using var innerResponse2 = await Send(message, true, info, cancellationToken).ConfigureAwait(false); await using var response = await innerResponse2.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); return(await JsonSerializer.DeserializeAsync <IReadOnlyList <ShowImagesDto> >(response, _jsonOptions, cancellationToken).ConfigureAwait(false)); } catch (Exception ex) { _logger.LogError(ex, "Error getting image info from schedules direct"); return(Array.Empty <ShowImagesDto>()); } }
public async Task <IEnumerable <ProgramInfo> > GetProgramsAsync(ListingsProviderInfo info, string channelNumber, string channelName, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken) { if (!await EmbyTV.EmbyTVRegistration.Instance.EnableXmlTv().ConfigureAwait(false)) { var length = endDateUtc - startDateUtc; if (length.TotalDays > 1) { endDateUtc = startDateUtc.AddDays(1); } } var path = await GetXml(info.Path, cancellationToken).ConfigureAwait(false); var reader = new XmlTvReader(path, GetLanguage()); var results = reader.GetProgrammes(channelNumber, startDateUtc, endDateUtc, cancellationToken); return(results.Select(p => GetProgramInfo(p, info))); }
private async Task <bool> HasLineup(ListingsProviderInfo info, CancellationToken cancellationToken) { if (string.IsNullOrEmpty(info.ListingsId)) { throw new ArgumentException("Listings Id required"); } var token = await GetToken(info, cancellationToken).ConfigureAwait(false); if (string.IsNullOrEmpty(token)) { throw new Exception("token required"); } _logger.LogInformation("Headends on account "); using var options = new HttpRequestMessage(HttpMethod.Get, ApiUrl + "/lineups"); options.Headers.TryAddWithoutValidation("token", token); try { using var httpResponse = await Send(options, false, null, cancellationToken).ConfigureAwait(false); httpResponse.EnsureSuccessStatusCode(); await using var stream = await httpResponse.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); using var response = httpResponse.Content; var root = await JsonSerializer.DeserializeAsync <ScheduleDirect.Lineups>(stream, _jsonOptions, cancellationToken).ConfigureAwait(false); return(root.lineups.Any(i => string.Equals(info.ListingsId, i.lineup, StringComparison.OrdinalIgnoreCase))); } catch (HttpRequestException ex) { // SchedulesDirect returns 400 if no lineups are configured. if (ex.StatusCode.HasValue && ex.StatusCode.Value == HttpStatusCode.BadRequest) { return(false); } throw; } }
private ProgramInfo GetProgramInfo(XmlTvProgram p, ListingsProviderInfo info) { var episodeTitle = p.Episode == null ? null : p.Episode.Title; var programInfo = new ProgramInfo { ChannelId = p.ChannelId, EndDate = GetDate(p.EndDate), EpisodeNumber = p.Episode == null ? null : p.Episode.Episode, EpisodeTitle = episodeTitle, Genres = p.Categories, Id = String.Format("{0}_{1:O}", p.ChannelId, p.StartDate), // Construct an id from the channel and start date, StartDate = GetDate(p.StartDate), Name = p.Title, Overview = p.Description, ShortOverview = p.Description, ProductionYear = !p.CopyrightDate.HasValue ? (int?)null : p.CopyrightDate.Value.Year, SeasonNumber = p.Episode == null ? null : p.Episode.Series, IsSeries = p.Episode != null, IsRepeat = p.IsPreviouslyShown && !p.IsNew, IsPremiere = p.Premiere != null, IsKids = p.Categories.Any(c => info.KidsCategories.Contains(c, StringComparer.OrdinalIgnoreCase)), IsMovie = p.Categories.Any(c => info.MovieCategories.Contains(c, StringComparer.OrdinalIgnoreCase)), IsNews = p.Categories.Any(c => info.NewsCategories.Contains(c, StringComparer.OrdinalIgnoreCase)), IsSports = p.Categories.Any(c => info.SportsCategories.Contains(c, StringComparer.OrdinalIgnoreCase)), ImageUrl = p.Icon != null && !String.IsNullOrEmpty(p.Icon.Source) ? p.Icon.Source : null, HasImage = p.Icon != null && !String.IsNullOrEmpty(p.Icon.Source), OfficialRating = p.Rating != null && !String.IsNullOrEmpty(p.Rating.Value) ? p.Rating.Value : null, CommunityRating = p.StarRating.HasValue ? p.StarRating.Value : (float?)null, SeriesId = p.Episode != null?p.Title.GetMD5().ToString("N") : null, ShowId = ((p.Title ?? string.Empty) + (episodeTitle ?? string.Empty)).GetMD5().ToString("N") }; if (programInfo.IsMovie) { programInfo.IsSeries = false; programInfo.EpisodeNumber = null; programInfo.EpisodeTitle = null; } return(programInfo); }
private async Task AddLineupToAccount(ListingsProviderInfo info, CancellationToken cancellationToken) { var token = await GetToken(info, cancellationToken).ConfigureAwait(false); if (string.IsNullOrEmpty(token)) { throw new ArgumentException("Authentication required."); } if (string.IsNullOrEmpty(info.ListingsId)) { throw new ArgumentException("Listings Id required"); } _logger.LogInformation("Adding new LineUp "); using var options = new HttpRequestMessage(HttpMethod.Put, ApiUrl + "/lineups/" + info.ListingsId); options.Headers.TryAddWithoutValidation("token", token); using var response = await _httpClientFactory.CreateClient(NamedClient.Default).SendAsync(options, HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); }
private async Task <string> GetXml(ListingsProviderInfo info, string path, CancellationToken cancellationToken) { _logger.Info("xmltv path: {0}", path); if (!path.StartsWith("http", StringComparison.OrdinalIgnoreCase)) { return(UnzipIfNeeded(path, path)); } var cacheFilename = DateTime.UtcNow.DayOfYear.ToString(CultureInfo.InvariantCulture) + "-" + DateTime.UtcNow.Hour.ToString(CultureInfo.InvariantCulture) + ".xml"; var cacheFile = Path.Combine(_config.ApplicationPaths.CachePath, "xmltv", cacheFilename); if (_fileSystem.FileExists(cacheFile)) { return(UnzipIfNeeded(path, cacheFile)); } _logger.Info("Downloading xmltv listings from {0}", path); var tempFile = await _httpClient.GetTempFile(new HttpRequestOptions { CancellationToken = cancellationToken, Url = path, Progress = new SimpleProgress <Double>(), DecompressionMethod = CompressionMethod.Gzip, // It's going to come back gzipped regardless of this value // So we need to make sure the decompression method is set to gzip EnableHttpCompression = true, UserAgent = string.IsNullOrEmpty(info.UserAgent) ? "Emby/3.0" : info.UserAgent }).ConfigureAwait(false); _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(cacheFile)); _fileSystem.CopyFile(tempFile, cacheFile, true); return(UnzipIfNeeded(path, cacheFile)); }
public async Task AddMetadata(ListingsProviderInfo info, List <ChannelInfo> channels, CancellationToken cancellationToken) { // Add the channel image url var path = await GetXml(info.Path, cancellationToken).ConfigureAwait(false); var reader = new XmlTvReader(path, GetLanguage()); var results = reader.GetChannels().ToList(); if (channels != null) { foreach (var c in channels) { var channelNumber = info.GetMappedChannel(c.Number); var match = results.FirstOrDefault(r => string.Equals(r.Id, channelNumber, StringComparison.OrdinalIgnoreCase)); if (match != null && match.Icon != null && !String.IsNullOrEmpty(match.Icon.Source)) { c.ImageUrl = match.Icon.Source; } } } }
private async Task <string> GetXml(ListingsProviderInfo info, CancellationToken cancellationToken) { _logger.LogInformation("xmltv path: {Path}", info.Path); if (!info.Path.StartsWith("http", StringComparison.OrdinalIgnoreCase)) { return(UnzipIfNeeded(info.Path, info.Path)); } string cacheFilename = info.Id + ".xml"; string cacheFile = Path.Combine(_config.ApplicationPaths.CachePath, "xmltv", cacheFilename); if (File.Exists(cacheFile) && File.GetLastWriteTimeUtc(cacheFile) >= DateTime.UtcNow.Subtract(_maxCacheAge)) { return(UnzipIfNeeded(info.Path, cacheFile)); } // Must check if file exists as parent directory may not exist. if (File.Exists(cacheFile)) { File.Delete(cacheFile); } _logger.LogInformation("Downloading xmltv listings from {Path}", info.Path); Directory.CreateDirectory(Path.GetDirectoryName(cacheFile)); using var response = await _httpClientFactory.CreateClient(NamedClient.Default).GetAsync(info.Path, cancellationToken).ConfigureAwait(false); await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); await using (var fileStream = new FileStream(cacheFile, FileMode.CreateNew, FileAccess.Write, FileShare.None, IODefaults.CopyToBufferSize, FileOptions.Asynchronous)) { await stream.CopyToAsync(fileStream, cancellationToken).ConfigureAwait(false); } return(UnzipIfNeeded(info.Path, cacheFile)); }
private async Task <List <ScheduleDirect.ShowImages> > GetImageForPrograms( ListingsProviderInfo info, List <string> programIds, CancellationToken cancellationToken) { var imageIdString = "["; foreach (var i in programIds) { if (!imageIdString.Contains(i.Substring(0, 10))) { imageIdString += "\"" + i.Substring(0, 10) + "\","; } } imageIdString = imageIdString.TrimEnd(',') + "]"; var httpOptions = new HttpRequestOptions() { Url = ApiUrl + "/metadata/programs", UserAgent = UserAgent, CancellationToken = cancellationToken, RequestContent = imageIdString, LogErrorResponseBody = true, // The data can be large so give it some extra time TimeoutMs = 60000 }; List <ScheduleDirect.ShowImages> images; using (var innerResponse2 = await Post(httpOptions, true, info).ConfigureAwait(false)) { images = _jsonSerializer.DeserializeFromStream <List <ScheduleDirect.ShowImages> >( innerResponse2.Content); } return(images); }
public async Task AddMetadata(ListingsProviderInfo info, List <ChannelInfo> channels, CancellationToken cancellationToken) { var response = await GetResponse <LineupDetailResponse>("https://data.emby.media/service/lineups?id=" + info.ListingsId).ConfigureAwait(false); foreach (var channel in channels) { var station = response.stations.FirstOrDefault(i => { var itemNumber = NormalizeNumber(channel.Number); if (string.Equals(itemNumber, NormalizeNumber(i.number), StringComparison.OrdinalIgnoreCase)) { return(true); } var channelNumber = i.channelNumber.ToString(CultureInfo.InvariantCulture); if (i.subChannelNumber > 0) { channelNumber += "." + i.subChannelNumber.ToString(CultureInfo.InvariantCulture); } return(string.Equals(channelNumber, itemNumber, StringComparison.OrdinalIgnoreCase)); }); if (station != null) { //channel.Name = station.name; if (!string.IsNullOrWhiteSpace(station.logoFilename)) { channel.HasImage = true; channel.ImageUrl = "http://cdn.tvpassport.com/image/station/100x100/" + station.logoFilename; } } } }
public async Task <List <ChannelInfo> > GetChannels(ListingsProviderInfo info, CancellationToken cancellationToken) { var listingsId = info.ListingsId; if (string.IsNullOrWhiteSpace(listingsId)) { throw new Exception("ListingsId required"); } var token = await GetToken(info, cancellationToken); if (string.IsNullOrWhiteSpace(token)) { throw new Exception("token required"); } var httpOptions = new HttpRequestOptions() { Url = ApiUrl + "/lineups/" + listingsId, UserAgent = UserAgent, CancellationToken = cancellationToken, LogErrorResponseBody = true, // The data can be large so give it some extra time TimeoutMs = 60000 }; httpOptions.RequestHeaders["token"] = token; var list = new List <ChannelInfo>(); using (var response = await Get(httpOptions, true, info).ConfigureAwait(false)) { var root = _jsonSerializer.DeserializeFromStream <ScheduleDirect.Channel>(response); _logger.Info("Found " + root.map.Count + " channels on the lineup on ScheduleDirect"); _logger.Info("Mapping Stations to Channel"); var allStations = root.stations ?? new List <ScheduleDirect.Station>(); foreach (ScheduleDirect.Map map in root.map) { var channelNumber = GetChannelNumber(map); var station = allStations.FirstOrDefault(item => string.Equals(item.stationID, map.stationID, StringComparison.OrdinalIgnoreCase)); if (station == null) { station = new ScheduleDirect.Station { stationID = map.stationID }; } var name = channelNumber; var channelInfo = new ChannelInfo { Number = channelNumber, Name = name }; if (station != null) { if (!string.IsNullOrWhiteSpace(station.name)) { channelInfo.Name = station.name; } channelInfo.Id = station.stationID; channelInfo.CallSign = station.callsign; if (station.logo != null) { channelInfo.ImageUrl = station.logo.URL; channelInfo.HasImage = true; } } list.Add(channelInfo); } } return(list); }
public Task <List <NameIdPair> > GetLineups(ListingsProviderInfo info, string country, string location) { return(GetHeadends(info, country, location, CancellationToken.None)); }
public async Task <IEnumerable <ProgramInfo> > GetProgramsAsync(ListingsProviderInfo info, string channelId, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken) { if (string.IsNullOrWhiteSpace(channelId)) { throw new ArgumentNullException("channelId"); } // Normalize incoming input channelId = channelId.Replace(".json.schedulesdirect.org", string.Empty, StringComparison.OrdinalIgnoreCase).TrimStart('I'); List <ProgramInfo> programsInfo = new List <ProgramInfo>(); var token = await GetToken(info, cancellationToken).ConfigureAwait(false); if (string.IsNullOrWhiteSpace(token)) { _logger.Warn("SchedulesDirect token is empty, returning empty program list"); return(programsInfo); } if (string.IsNullOrWhiteSpace(info.ListingsId)) { _logger.Warn("ListingsId is null, returning empty program list"); return(programsInfo); } var dates = GetScheduleRequestDates(startDateUtc, endDateUtc); string stationID = channelId; _logger.Info("Channel Station ID is: " + stationID); List <ScheduleDirect.RequestScheduleForChannel> requestList = new List <ScheduleDirect.RequestScheduleForChannel>() { new ScheduleDirect.RequestScheduleForChannel() { stationID = stationID, date = dates } }; var requestString = _jsonSerializer.SerializeToString(requestList); _logger.Debug("Request string for schedules is: " + requestString); var httpOptions = new HttpRequestOptions() { Url = ApiUrl + "/schedules", UserAgent = UserAgent, CancellationToken = cancellationToken, // The data can be large so give it some extra time TimeoutMs = 60000, LogErrorResponseBody = true }; httpOptions.RequestHeaders["token"] = token; httpOptions.RequestContent = requestString; using (var response = await Post(httpOptions, true, info).ConfigureAwait(false)) { StreamReader reader = new StreamReader(response.Content); string responseString = reader.ReadToEnd(); var dailySchedules = _jsonSerializer.DeserializeFromString <List <ScheduleDirect.Day> >(responseString); _logger.Debug("Found " + dailySchedules.Count + " programs on " + stationID + " ScheduleDirect"); httpOptions = new HttpRequestOptions() { Url = ApiUrl + "/programs", UserAgent = UserAgent, CancellationToken = cancellationToken, LogErrorResponseBody = true, // The data can be large so give it some extra time TimeoutMs = 60000 }; httpOptions.RequestHeaders["token"] = token; List <string> programsID = new List <string>(); programsID = dailySchedules.SelectMany(d => d.programs.Select(s => s.programID)).Distinct().ToList(); var requestBody = "[\"" + string.Join("\", \"", programsID) + "\"]"; httpOptions.RequestContent = requestBody; using (var innerResponse = await Post(httpOptions, true, info).ConfigureAwait(false)) { StreamReader innerReader = new StreamReader(innerResponse.Content); responseString = innerReader.ReadToEnd(); var programDetails = _jsonSerializer.DeserializeFromString <List <ScheduleDirect.ProgramDetails> >( responseString); var programDict = programDetails.ToDictionary(p => p.programID, y => y); var programIdsWithImages = programDetails.Where(p => p.hasImageArtwork).Select(p => p.programID) .ToList(); var images = await GetImageForPrograms(info, programIdsWithImages, cancellationToken); var schedules = dailySchedules.SelectMany(d => d.programs); foreach (ScheduleDirect.Program schedule in schedules) { //_logger.Debug("Proccesing Schedule for statio ID " + stationID + // " which corresponds to channel " + channelNumber + " and program id " + // schedule.programID + " which says it has images? " + // programDict[schedule.programID].hasImageArtwork); if (images != null) { var imageIndex = images.FindIndex(i => i.programID == schedule.programID.Substring(0, 10)); if (imageIndex > -1) { var programEntry = programDict[schedule.programID]; var data = images[imageIndex].data ?? new List <ScheduleDirect.ImageData>(); data = data.OrderByDescending(GetSizeOrder).ToList(); programEntry.primaryImage = GetProgramImage(ApiUrl, data, "Logo", true, 600); //programEntry.thumbImage = GetProgramImage(ApiUrl, data, "Iconic", false); //programEntry.bannerImage = GetProgramImage(ApiUrl, data, "Banner", false) ?? // GetProgramImage(ApiUrl, data, "Banner-L1", false) ?? // GetProgramImage(ApiUrl, data, "Banner-LO", false) ?? // GetProgramImage(ApiUrl, data, "Banner-LOT", false); } } programsInfo.Add(GetProgram(channelId, schedule, programDict[schedule.programID])); } } } return(programsInfo); }
private async Task <string> GetToken(ListingsProviderInfo info, CancellationToken cancellationToken) { var username = info.Username; // Reset the token if there's no username if (string.IsNullOrWhiteSpace(username)) { return(null); } var password = info.Password; if (string.IsNullOrWhiteSpace(password)) { return(null); } // Avoid hammering SD if ((DateTime.UtcNow - _lastErrorResponse).TotalMinutes < 1) { return(null); } NameValuePair savedToken = null; if (!_tokens.TryGetValue(username, out savedToken)) { savedToken = new NameValuePair(); _tokens.TryAdd(username, savedToken); } if (!string.IsNullOrWhiteSpace(savedToken.Name) && !string.IsNullOrWhiteSpace(savedToken.Value)) { long ticks; if (long.TryParse(savedToken.Value, NumberStyles.Any, CultureInfo.InvariantCulture, out ticks)) { // If it's under 24 hours old we can still use it if (DateTime.UtcNow.Ticks - ticks < TimeSpan.FromHours(20).Ticks) { return(savedToken.Name); } } } await _tokenSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false); try { var result = await GetTokenInternal(username, password, cancellationToken).ConfigureAwait(false); savedToken.Name = result; savedToken.Value = DateTime.UtcNow.Ticks.ToString(CultureInfo.InvariantCulture); return(result); } catch (HttpException ex) { if (ex.StatusCode.HasValue) { if ((int)ex.StatusCode.Value == 400) { _tokens.Clear(); _lastErrorResponse = DateTime.UtcNow; } } throw; } finally { _tokenSemaphore.Release(); } }
private ProgramInfo GetProgramInfo(XmlTvProgram p, ListingsProviderInfo info) { var episodeTitle = p.Episode == null ? null : p.Episode.Title; var programInfo = new ProgramInfo { ChannelId = p.ChannelId, EndDate = GetDate(p.EndDate), EpisodeNumber = p.Episode == null ? null : p.Episode.Episode, EpisodeTitle = episodeTitle, Genres = p.Categories, StartDate = GetDate(p.StartDate), Name = p.Title, Overview = p.Description, ProductionYear = !p.CopyrightDate.HasValue ? (int?)null : p.CopyrightDate.Value.Year, SeasonNumber = p.Episode == null ? null : p.Episode.Series, IsSeries = p.Episode != null, IsRepeat = p.IsPreviouslyShown && !p.IsNew, IsPremiere = p.Premiere != null, IsKids = p.Categories.Any(c => info.KidsCategories.Contains(c, StringComparer.OrdinalIgnoreCase)), IsMovie = p.Categories.Any(c => info.MovieCategories.Contains(c, StringComparer.OrdinalIgnoreCase)), IsNews = p.Categories.Any(c => info.NewsCategories.Contains(c, StringComparer.OrdinalIgnoreCase)), IsSports = p.Categories.Any(c => info.SportsCategories.Contains(c, StringComparer.OrdinalIgnoreCase)), ImageUrl = p.Icon != null && !String.IsNullOrEmpty(p.Icon.Source) ? p.Icon.Source : null, HasImage = p.Icon != null && !String.IsNullOrEmpty(p.Icon.Source), OfficialRating = p.Rating != null && !String.IsNullOrEmpty(p.Rating.Value) ? p.Rating.Value : null, CommunityRating = p.StarRating.HasValue ? p.StarRating.Value : (float?)null, SeriesId = p.Episode != null?p.Title.GetMD5().ToString("N") : null }; if (!string.IsNullOrWhiteSpace(p.ProgramId)) { programInfo.ShowId = p.ProgramId; } else { var uniqueString = (p.Title ?? string.Empty) + (episodeTitle ?? string.Empty) + (p.IceTvEpisodeNumber ?? string.Empty); if (programInfo.SeasonNumber.HasValue) { uniqueString = "-" + programInfo.SeasonNumber.Value.ToString(CultureInfo.InvariantCulture); } if (programInfo.EpisodeNumber.HasValue) { uniqueString = "-" + programInfo.EpisodeNumber.Value.ToString(CultureInfo.InvariantCulture); } programInfo.ShowId = uniqueString.GetMD5().ToString("N"); // If we don't have valid episode info, assume it's a unique program, otherwise recordings might be skipped if (programInfo.IsSeries && !programInfo.IsRepeat) { if ((programInfo.EpisodeNumber ?? 0) == 0) { programInfo.ShowId = programInfo.ShowId + programInfo.StartDate.Ticks.ToString(CultureInfo.InvariantCulture); } } } // Construct an id from the channel and start date programInfo.Id = String.Format("{0}_{1:O}", p.ChannelId, p.StartDate); if (programInfo.IsMovie) { programInfo.IsSeries = false; programInfo.EpisodeNumber = null; programInfo.EpisodeTitle = null; } return(programInfo); }