aboutsummaryrefslogtreecommitdiff
path: root/Emby.Server.Implementations/LiveTv/Listings
diff options
context:
space:
mode:
authorPatrick Barron <barronpm@gmail.com>2023-12-28 15:15:03 -0500
committerPatrick Barron <barronpm@gmail.com>2024-01-09 10:16:56 -0500
commitc1a3084312fa4fb7796b83640bfe9ad2b5044afa (patch)
treeb7e81594c3782128d37f875a0ce54d0bad12c6e5 /Emby.Server.Implementations/LiveTv/Listings
parent7eba162879f6d1ff04539cac5c0d6372a955d82b (diff)
Move LiveTv to separate project
Diffstat (limited to 'Emby.Server.Implementations/LiveTv/Listings')
-rw-r--r--Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs808
-rw-r--r--Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/BroadcasterDto.cs34
-rw-r--r--Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/CaptionDto.cs22
-rw-r--r--Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/CastDto.cs46
-rw-r--r--Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ChannelDto.cs30
-rw-r--r--Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ContentRatingDto.cs22
-rw-r--r--Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/CrewDto.cs40
-rw-r--r--Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/DayDto.cs30
-rw-r--r--Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/Description1000Dto.cs22
-rw-r--r--Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/Description100Dto.cs22
-rw-r--r--Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/DescriptionsProgramDto.cs24
-rw-r--r--Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/EventDetailsDto.cs16
-rw-r--r--Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/GracenoteDto.cs22
-rw-r--r--Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/HeadendsDto.cs36
-rw-r--r--Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ImageDataDto.cs70
-rw-r--r--Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/LineupDto.cs46
-rw-r--r--Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/LineupsDto.cs36
-rw-r--r--Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/LogoDto.cs34
-rw-r--r--Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MapDto.cs58
-rw-r--r--Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MetadataDto.cs28
-rw-r--r--Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MetadataProgramsDto.cs16
-rw-r--r--Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MetadataScheduleDto.cs41
-rw-r--r--Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MovieDto.cs30
-rw-r--r--Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MultipartDto.cs22
-rw-r--r--Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ProgramDetailsDto.cs156
-rw-r--r--Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ProgramDto.cs90
-rw-r--r--Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/QualityRatingDto.cs40
-rw-r--r--Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/RatingDto.cs22
-rw-r--r--Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/RecommendationDto.cs22
-rw-r--r--Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/RequestScheduleForChannelDto.cs24
-rw-r--r--Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ShowImagesDto.cs24
-rw-r--r--Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/StationDto.cs66
-rw-r--r--Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/TitleDto.cs16
-rw-r--r--Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/TokenDto.cs47
-rw-r--r--Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs267
35 files changed, 0 insertions, 2329 deletions
diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs
deleted file mode 100644
index 5be3a7488a..0000000000
--- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs
+++ /dev/null
@@ -1,808 +0,0 @@
-#nullable disable
-
-#pragma warning disable CS1591
-
-using System;
-using System.Collections.Concurrent;
-using System.Collections.Generic;
-using System.Globalization;
-using System.Linq;
-using System.Net;
-using System.Net.Http;
-using System.Net.Http.Json;
-using System.Net.Mime;
-using System.Security.Cryptography;
-using System.Text;
-using System.Text.Json;
-using System.Threading;
-using System.Threading.Tasks;
-using Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos;
-using Jellyfin.Extensions;
-using Jellyfin.Extensions.Json;
-using MediaBrowser.Common.Net;
-using MediaBrowser.Controller.Authentication;
-using MediaBrowser.Controller.LiveTv;
-using MediaBrowser.Model.Dto;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.LiveTv;
-using Microsoft.Extensions.Logging;
-
-namespace Emby.Server.Implementations.LiveTv.Listings
-{
- public class SchedulesDirect : IListingsProvider, IDisposable
- {
- private const string ApiUrl = "https://json.schedulesdirect.org/20141201";
-
- private readonly ILogger<SchedulesDirect> _logger;
- private readonly IHttpClientFactory _httpClientFactory;
- private readonly SemaphoreSlim _tokenSemaphore = new SemaphoreSlim(1, 1);
-
- private readonly ConcurrentDictionary<string, NameValuePair> _tokens = new ConcurrentDictionary<string, NameValuePair>();
- private readonly JsonSerializerOptions _jsonOptions = JsonDefaults.Options;
- private DateTime _lastErrorResponse;
- private bool _disposed = false;
-
- public SchedulesDirect(
- ILogger<SchedulesDirect> logger,
- IHttpClientFactory httpClientFactory)
- {
- _logger = logger;
- _httpClientFactory = httpClientFactory;
- }
-
- /// <inheritdoc />
- public string Name => "Schedules Direct";
-
- /// <inheritdoc />
- public string Type => nameof(SchedulesDirect);
-
- private static List<string> GetScheduleRequestDates(DateTime startDateUtc, DateTime endDateUtc)
- {
- var dates = new List<string>();
-
- var start = new[] { startDateUtc, startDateUtc.ToLocalTime() }.Min().Date;
- var end = new[] { endDateUtc, endDateUtc.ToLocalTime() }.Max().Date;
-
- while (start <= end)
- {
- dates.Add(start.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture));
- start = start.AddDays(1);
- }
-
- return dates;
- }
-
- public async Task<IEnumerable<ProgramInfo>> GetProgramsAsync(ListingsProviderInfo info, string channelId, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken)
- {
- ArgumentException.ThrowIfNullOrEmpty(channelId);
-
- // Normalize incoming input
- channelId = channelId.Replace(".json.schedulesdirect.org", string.Empty, StringComparison.OrdinalIgnoreCase).TrimStart('I');
-
- var token = await GetToken(info, cancellationToken).ConfigureAwait(false);
-
- if (string.IsNullOrEmpty(token))
- {
- _logger.LogWarning("SchedulesDirect token is empty, returning empty program list");
-
- return Enumerable.Empty<ProgramInfo>();
- }
-
- var dates = GetScheduleRequestDates(startDateUtc, endDateUtc);
-
- _logger.LogInformation("Channel Station ID is: {ChannelID}", channelId);
- var requestList = new List<RequestScheduleForChannelDto>()
- {
- new RequestScheduleForChannelDto()
- {
- StationId = channelId,
- Date = dates
- }
- };
-
- _logger.LogDebug("Request string for schedules is: {@RequestString}", requestList);
-
- using var options = new HttpRequestMessage(HttpMethod.Post, ApiUrl + "/schedules");
- options.Content = JsonContent.Create(requestList, options: _jsonOptions);
- options.Headers.TryAddWithoutValidation("token", token);
- using var response = await Send(options, true, info, cancellationToken).ConfigureAwait(false);
- var dailySchedules = await response.Content.ReadFromJsonAsync<IReadOnlyList<DayDto>>(_jsonOptions, cancellationToken).ConfigureAwait(false);
- if (dailySchedules is null)
- {
- return Array.Empty<ProgramInfo>();
- }
-
- _logger.LogDebug("Found {ScheduleCount} programs on {ChannelID} ScheduleDirect", dailySchedules.Count, channelId);
-
- using var programRequestOptions = new HttpRequestMessage(HttpMethod.Post, ApiUrl + "/programs");
- programRequestOptions.Headers.TryAddWithoutValidation("token", token);
-
- var programIds = dailySchedules.SelectMany(d => d.Programs.Select(s => s.ProgramId)).Distinct();
- programRequestOptions.Content = JsonContent.Create(programIds, options: _jsonOptions);
-
- using var innerResponse = await Send(programRequestOptions, true, info, cancellationToken).ConfigureAwait(false);
- var programDetails = await innerResponse.Content.ReadFromJsonAsync<IReadOnlyList<ProgramDetailsDto>>(_jsonOptions, cancellationToken).ConfigureAwait(false);
- if (programDetails is null)
- {
- return Array.Empty<ProgramInfo>();
- }
-
- 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).ConfigureAwait(false);
-
- var programsInfo = new List<ProgramInfo>();
- foreach (ProgramDto schedule in dailySchedules.SelectMany(d => d.Programs))
- {
- // _logger.LogDebug("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 (string.IsNullOrEmpty(schedule.ProgramId))
- {
- continue;
- }
-
- if (images is not null)
- {
- var imageIndex = images.FindIndex(i => i.ProgramId == schedule.ProgramId[..10]);
- if (imageIndex > -1)
- {
- var programEntry = programDict[schedule.ProgramId];
-
- var allImages = images[imageIndex].Data;
- var imagesWithText = allImages.Where(i => string.Equals(i.Text, "yes", StringComparison.OrdinalIgnoreCase)).ToList();
- var imagesWithoutText = allImages.Where(i => string.Equals(i.Text, "no", StringComparison.OrdinalIgnoreCase)).ToList();
-
- const double DesiredAspect = 2.0 / 3;
-
- programEntry.PrimaryImage = GetProgramImage(ApiUrl, imagesWithText, DesiredAspect, token) ??
- GetProgramImage(ApiUrl, allImages, DesiredAspect, token);
-
- const double WideAspect = 16.0 / 9;
-
- programEntry.ThumbImage = GetProgramImage(ApiUrl, imagesWithText, WideAspect, token);
-
- // Don't supply the same image twice
- if (string.Equals(programEntry.PrimaryImage, programEntry.ThumbImage, StringComparison.Ordinal))
- {
- programEntry.ThumbImage = null;
- }
-
- programEntry.BackdropImage = GetProgramImage(ApiUrl, imagesWithoutText, WideAspect, token);
-
- // 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 static int GetSizeOrder(ImageDataDto image)
- {
- if (int.TryParse(image.Height, out int value))
- {
- return value;
- }
-
- return 0;
- }
-
- private static string GetChannelNumber(MapDto map)
- {
- var channelNumber = map.LogicalChannelNumber;
-
- if (string.IsNullOrWhiteSpace(channelNumber))
- {
- channelNumber = map.Channel;
- }
-
- if (string.IsNullOrWhiteSpace(channelNumber))
- {
- channelNumber = map.AtscMajor + "." + map.AtscMinor;
- }
-
- return channelNumber.TrimStart('0');
- }
-
- private static bool IsMovie(ProgramDetailsDto programInfo)
- {
- return string.Equals(programInfo.EntityType, "movie", StringComparison.OrdinalIgnoreCase);
- }
-
- private ProgramInfo GetProgram(string channelId, ProgramDto programInfo, ProgramDetailsDto details)
- {
- if (programInfo.AirDateTime is null)
- {
- return null;
- }
-
- var startAt = programInfo.AirDateTime.Value;
- var endAt = startAt.AddSeconds(programInfo.Duration);
- var audioType = ProgramAudio.Stereo;
-
- var programId = programInfo.ProgramId ?? string.Empty;
-
- string newID = programId + "T" + startAt.Ticks + "C" + channelId;
-
- if (programInfo.AudioProperties.Count != 0)
- {
- if (programInfo.AudioProperties.Contains("atmos", StringComparison.OrdinalIgnoreCase))
- {
- audioType = ProgramAudio.Atmos;
- }
- else if (programInfo.AudioProperties.Contains("dd 5.1", StringComparison.OrdinalIgnoreCase))
- {
- audioType = ProgramAudio.DolbyDigital;
- }
- else if (programInfo.AudioProperties.Contains("dd", StringComparison.OrdinalIgnoreCase))
- {
- audioType = ProgramAudio.DolbyDigital;
- }
- else if (programInfo.AudioProperties.Contains("stereo", StringComparison.OrdinalIgnoreCase))
- {
- audioType = ProgramAudio.Stereo;
- }
- else
- {
- audioType = ProgramAudio.Mono;
- }
- }
-
- string episodeTitle = null;
- if (details.EpisodeTitle150 is not null)
- {
- episodeTitle = details.EpisodeTitle150;
- }
-
- var info = new ProgramInfo
- {
- ChannelId = channelId,
- Id = newID,
- StartDate = startAt,
- EndDate = endAt,
- Name = details.Titles[0].Title120 ?? "Unknown",
- OfficialRating = null,
- CommunityRating = null,
- EpisodeTitle = episodeTitle,
- Audio = audioType,
- // IsNew = programInfo.@new ?? false,
- IsRepeat = programInfo.New is null,
- IsSeries = string.Equals(details.EntityType, "episode", StringComparison.OrdinalIgnoreCase),
- ImageUrl = details.PrimaryImage,
- ThumbImageUrl = details.ThumbImage,
- IsKids = string.Equals(details.Audience, "children", StringComparison.OrdinalIgnoreCase),
- IsSports = string.Equals(details.EntityType, "sports", StringComparison.OrdinalIgnoreCase),
- IsMovie = IsMovie(details),
- Etag = programInfo.Md5,
- IsLive = string.Equals(programInfo.LiveTapeDelay, "live", StringComparison.OrdinalIgnoreCase),
- IsPremiere = programInfo.Premiere || (programInfo.IsPremiereOrFinale ?? string.Empty).Contains("premiere", StringComparison.OrdinalIgnoreCase)
- };
-
- var showId = programId;
-
- if (!info.IsSeries)
- {
- // It's also a series if it starts with SH
- info.IsSeries = showId.StartsWith("SH", StringComparison.OrdinalIgnoreCase) && showId.Length >= 14;
- }
-
- // According to SchedulesDirect, these are generic, unidentified episodes
- // SH005316560000
- var hasUniqueShowId = !showId.StartsWith("SH", StringComparison.OrdinalIgnoreCase) ||
- !showId.EndsWith("0000", StringComparison.OrdinalIgnoreCase);
-
- if (!hasUniqueShowId)
- {
- showId = newID;
- }
-
- info.ShowId = showId;
-
- if (programInfo.VideoProperties is not null)
- {
- info.IsHD = programInfo.VideoProperties.Contains("hdtv", StringComparison.OrdinalIgnoreCase);
- info.Is3D = programInfo.VideoProperties.Contains("3d", StringComparison.OrdinalIgnoreCase);
- }
-
- if (details.ContentRating is not null && details.ContentRating.Count > 0)
- {
- info.OfficialRating = details.ContentRating[0].Code.Replace("TV", "TV-", StringComparison.Ordinal)
- .Replace("--", "-", StringComparison.Ordinal);
-
- var invalid = new[] { "N/A", "Approved", "Not Rated", "Passed" };
- if (invalid.Contains(info.OfficialRating, StringComparison.OrdinalIgnoreCase))
- {
- info.OfficialRating = null;
- }
- }
-
- if (details.Descriptions is not null)
- {
- if (details.Descriptions.Description1000 is not null && details.Descriptions.Description1000.Count > 0)
- {
- info.Overview = details.Descriptions.Description1000[0].Description;
- }
- else if (details.Descriptions.Description100 is not null && details.Descriptions.Description100.Count > 0)
- {
- info.Overview = details.Descriptions.Description100[0].Description;
- }
- }
-
- if (info.IsSeries)
- {
- info.SeriesId = programId.Substring(0, 10);
-
- info.SeriesProviderIds[MetadataProvider.Zap2It.ToString()] = info.SeriesId;
-
- if (details.Metadata is not null)
- {
- foreach (var metadataProgram in details.Metadata)
- {
- var gracenote = metadataProgram.Gracenote;
- if (gracenote is not null)
- {
- info.SeasonNumber = gracenote.Season;
-
- if (gracenote.Episode > 0)
- {
- info.EpisodeNumber = gracenote.Episode;
- }
-
- break;
- }
- }
- }
- }
-
- if (details.OriginalAirDate is not null)
- {
- info.OriginalAirDate = details.OriginalAirDate;
- info.ProductionYear = info.OriginalAirDate.Value.Year;
- }
-
- if (details.Movie is not null)
- {
- if (!string.IsNullOrEmpty(details.Movie.Year)
- && int.TryParse(details.Movie.Year, out int year))
- {
- info.ProductionYear = year;
- }
- }
-
- if (details.Genres is not null)
- {
- info.Genres = details.Genres.Where(g => !string.IsNullOrWhiteSpace(g)).ToList();
- info.IsNews = details.Genres.Contains("news", StringComparison.OrdinalIgnoreCase);
-
- if (info.Genres.Contains("children", StringComparison.OrdinalIgnoreCase))
- {
- info.IsKids = true;
- }
- }
-
- return info;
- }
-
- private static string GetProgramImage(string apiUrl, IEnumerable<ImageDataDto> images, double desiredAspect, string token)
- {
- var match = images
- .OrderBy(i => Math.Abs(desiredAspect - GetAspectRatio(i)))
- .ThenByDescending(i => GetSizeOrder(i))
- .FirstOrDefault();
-
- if (match is null)
- {
- return null;
- }
-
- var uri = match.Uri;
-
- if (string.IsNullOrWhiteSpace(uri))
- {
- return null;
- }
-
- if (uri.Contains("http", StringComparison.OrdinalIgnoreCase))
- {
- return uri;
- }
-
- return apiUrl + "/image/" + uri + "?token=" + token;
- }
-
- private static double GetAspectRatio(ImageDataDto i)
- {
- int width = 0;
- int height = 0;
-
- if (!string.IsNullOrWhiteSpace(i.Width))
- {
- _ = int.TryParse(i.Width, out width);
- }
-
- if (!string.IsNullOrWhiteSpace(i.Height))
- {
- _ = int.TryParse(i.Height, out height);
- }
-
- if (height == 0 || width == 0)
- {
- return 0;
- }
-
- double result = width;
- result /= height;
- return result;
- }
-
- private async Task<IReadOnlyList<ShowImagesDto>> GetImageForPrograms(
- ListingsProviderInfo info,
- IReadOnlyList<string> programIds,
- CancellationToken cancellationToken)
- {
- var token = await GetToken(info, cancellationToken).ConfigureAwait(false);
-
- if (programIds.Count == 0)
- {
- return Array.Empty<ShowImagesDto>();
- }
-
- StringBuilder str = new StringBuilder("[", 1 + (programIds.Count * 13));
- foreach (var i in programIds)
- {
- str.Append('"')
- .Append(i[..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)
- };
- message.Headers.TryAddWithoutValidation("token", token);
-
- try
- {
- using var innerResponse2 = await Send(message, true, info, cancellationToken).ConfigureAwait(false);
- return await innerResponse2.Content.ReadFromJsonAsync<IReadOnlyList<ShowImagesDto>>(_jsonOptions, cancellationToken).ConfigureAwait(false);
- }
- catch (Exception ex)
- {
- _logger.LogError(ex, "Error getting image info from schedules direct");
-
- return Array.Empty<ShowImagesDto>();
- }
- }
-
- 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);
- var root = await httpResponse.Content.ReadFromJsonAsync<IReadOnlyList<HeadendsDto>>(_jsonOptions, cancellationToken).ConfigureAwait(false);
- if (root is not null)
- {
- foreach (HeadendsDto headend in root)
- {
- foreach (LineupDto lineup in headend.Lineups)
- {
- lineups.Add(new NameIdPair
- {
- Name = string.IsNullOrWhiteSpace(lineup.Name) ? lineup.Lineup : lineup.Name,
- Id = lineup.Uri?[18..]
- });
- }
- }
- }
- else
- {
- _logger.LogInformation("No lineups available");
- }
- }
- catch (Exception ex)
- {
- _logger.LogError(ex, "Error getting headends");
- }
-
- return lineups;
- }
-
- 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.IsNullOrEmpty(password))
- {
- return null;
- }
-
- // Avoid hammering SD
- if ((DateTime.UtcNow - _lastErrorResponse).TotalMinutes < 1)
- {
- return null;
- }
-
- if (!_tokens.TryGetValue(username, out NameValuePair savedToken))
- {
- savedToken = new NameValuePair();
- _tokens.TryAdd(username, savedToken);
- }
-
- if (!string.IsNullOrEmpty(savedToken.Name)
- && long.TryParse(savedToken.Value, CultureInfo.InvariantCulture, out long 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 (HttpRequestException ex)
- {
- if (ex.StatusCode.HasValue && ex.StatusCode.Value == HttpStatusCode.BadRequest)
- {
- _tokens.Clear();
- _lastErrorResponse = DateTime.UtcNow;
- }
-
- throw;
- }
- finally
- {
- _tokenSemaphore.Release();
- }
- }
-
- private async Task<HttpResponseMessage> Send(
- HttpRequestMessage options,
- bool enableRetry,
- ListingsProviderInfo providerInfo,
- CancellationToken cancellationToken,
- HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead)
- {
- var response = await _httpClientFactory.CreateClient(NamedClient.Default)
- .SendAsync(options, completionOption, cancellationToken).ConfigureAwait(false);
- if (response.IsSuccessStatusCode)
- {
- return response;
- }
-
- // Response is automatically disposed in the calling function,
- // so dispose manually if not returning.
- response.Dispose();
- if (!enableRetry || (int)response.StatusCode >= 500)
- {
- throw new HttpRequestException(
- string.Format(CultureInfo.InvariantCulture, "Request failed: {0}", response.ReasonPhrase),
- null,
- response.StatusCode);
- }
-
- _tokens.Clear();
- options.Headers.TryAddWithoutValidation("token", await GetToken(providerInfo, cancellationToken).ConfigureAwait(false));
- return await Send(options, false, providerInfo, cancellationToken).ConfigureAwait(false);
- }
-
- private async Task<string> GetTokenInternal(
- string username,
- string password,
- CancellationToken cancellationToken)
- {
- using var options = new HttpRequestMessage(HttpMethod.Post, ApiUrl + "/token");
-#pragma warning disable CA5350 // SchedulesDirect is always SHA1.
- var hashedPasswordBytes = SHA1.HashData(Encoding.ASCII.GetBytes(password));
-#pragma warning restore CA5350
- // TODO: remove ToLower when Convert.ToHexString supports lowercase
- // Schedules Direct requires the hex to be lowercase
- string hashedPassword = Convert.ToHexString(hashedPasswordBytes).ToLowerInvariant();
- options.Content = new StringContent("{\"username\":\"" + username + "\",\"password\":\"" + hashedPassword + "\"}", Encoding.UTF8, MediaTypeNames.Application.Json);
-
- using var response = await Send(options, false, null, cancellationToken).ConfigureAwait(false);
- response.EnsureSuccessStatusCode();
- var root = await response.Content.ReadFromJsonAsync<TokenDto>(_jsonOptions, cancellationToken).ConfigureAwait(false);
- if (string.Equals(root?.Message, "OK", StringComparison.Ordinal))
- {
- _logger.LogInformation("Authenticated with Schedules Direct token: {Token}", root.Token);
- return root.Token;
- }
-
- throw new AuthenticationException("Could not authenticate with Schedules Direct Error: " + root.Message);
- }
-
- private async Task AddLineupToAccount(ListingsProviderInfo info, CancellationToken cancellationToken)
- {
- var token = await GetToken(info, cancellationToken).ConfigureAwait(false);
-
- ArgumentException.ThrowIfNullOrEmpty(token);
- ArgumentException.ThrowIfNullOrEmpty(info.ListingsId);
-
- _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<bool> HasLineup(ListingsProviderInfo info, CancellationToken cancellationToken)
- {
- ArgumentException.ThrowIfNullOrEmpty(info.ListingsId);
-
- var token = await GetToken(info, cancellationToken).ConfigureAwait(false);
-
- ArgumentException.ThrowIfNullOrEmpty(token);
-
- _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();
- var root = await httpResponse.Content.ReadFromJsonAsync<LineupsDto>(_jsonOptions, cancellationToken).ConfigureAwait(false);
- return root?.Lineups.Any(i => string.Equals(info.ListingsId, i.Lineup, StringComparison.OrdinalIgnoreCase)) ?? false;
- }
- catch (HttpRequestException ex)
- {
- // SchedulesDirect returns 400 if no lineups are configured.
- if (ex.StatusCode is HttpStatusCode.BadRequest)
- {
- return false;
- }
-
- throw;
- }
- }
-
- public async Task Validate(ListingsProviderInfo info, bool validateLogin, bool validateListings)
- {
- if (validateLogin)
- {
- ArgumentException.ThrowIfNullOrEmpty(info.Username);
- ArgumentException.ThrowIfNullOrEmpty(info.Password);
- }
-
- if (validateListings)
- {
- ArgumentException.ThrowIfNullOrEmpty(info.ListingsId);
-
- var hasLineup = await HasLineup(info, CancellationToken.None).ConfigureAwait(false);
-
- if (!hasLineup)
- {
- await AddLineupToAccount(info, CancellationToken.None).ConfigureAwait(false);
- }
- }
- }
-
- public Task<List<NameIdPair>> GetLineups(ListingsProviderInfo info, string country, string location)
- {
- return GetHeadends(info, country, location, CancellationToken.None);
- }
-
- public async Task<List<ChannelInfo>> GetChannels(ListingsProviderInfo info, CancellationToken cancellationToken)
- {
- var listingsId = info.ListingsId;
- ArgumentException.ThrowIfNullOrEmpty(listingsId);
-
- var token = await GetToken(info, cancellationToken).ConfigureAwait(false);
-
- ArgumentException.ThrowIfNullOrEmpty(token);
-
- using var options = new HttpRequestMessage(HttpMethod.Get, ApiUrl + "/lineups/" + listingsId);
- options.Headers.TryAddWithoutValidation("token", token);
-
- using var httpResponse = await Send(options, true, info, cancellationToken).ConfigureAwait(false);
- var root = await httpResponse.Content.ReadFromJsonAsync<ChannelDto>(_jsonOptions, cancellationToken).ConfigureAwait(false);
- if (root is null)
- {
- return new List<ChannelInfo>();
- }
-
- _logger.LogInformation("Found {ChannelCount} channels on the lineup on ScheduleDirect", root.Map.Count);
- _logger.LogInformation("Mapping Stations to Channel");
-
- var allStations = root.Stations;
-
- var map = root.Map;
- var list = new List<ChannelInfo>(map.Count);
- foreach (var channel in map)
- {
- var channelNumber = GetChannelNumber(channel);
-
- var stationIndex = allStations.FindIndex(item => string.Equals(item.StationId, channel.StationId, StringComparison.OrdinalIgnoreCase));
- var station = stationIndex == -1
- ? new StationDto { StationId = channel.StationId }
- : allStations[stationIndex];
-
- var channelInfo = new ChannelInfo
- {
- Id = station.StationId,
- CallSign = station.Callsign,
- Number = channelNumber,
- Name = string.IsNullOrWhiteSpace(station.Name) ? channelNumber : station.Name
- };
-
- if (station.Logo is not null)
- {
- channelInfo.ImageUrl = station.Logo.Url;
- }
-
- list.Add(channelInfo);
- }
-
- return list;
- }
-
- /// <inheritdoc />
- public void Dispose()
- {
- Dispose(true);
- GC.SuppressFinalize(this);
- }
-
- /// <summary>
- /// Releases unmanaged and optionally managed resources.
- /// </summary>
- /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
- protected virtual void Dispose(bool disposing)
- {
- if (_disposed)
- {
- return;
- }
-
- if (disposing)
- {
- _tokenSemaphore?.Dispose();
- }
-
- _disposed = true;
- }
- }
-}
diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/BroadcasterDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/BroadcasterDto.cs
deleted file mode 100644
index 95ac996e01..0000000000
--- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/BroadcasterDto.cs
+++ /dev/null
@@ -1,34 +0,0 @@
-using System.Text.Json.Serialization;
-
-namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos
-{
- /// <summary>
- /// Broadcaster dto.
- /// </summary>
- public class BroadcasterDto
- {
- /// <summary>
- /// Gets or sets the city.
- /// </summary>
- [JsonPropertyName("city")]
- public string? City { get; set; }
-
- /// <summary>
- /// Gets or sets the state.
- /// </summary>
- [JsonPropertyName("state")]
- public string? State { get; set; }
-
- /// <summary>
- /// Gets or sets the postal code.
- /// </summary>
- [JsonPropertyName("postalCode")]
- public string? Postalcode { get; set; }
-
- /// <summary>
- /// Gets or sets the country.
- /// </summary>
- [JsonPropertyName("country")]
- public string? Country { get; set; }
- }
-}
diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/CaptionDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/CaptionDto.cs
deleted file mode 100644
index f6251b9ad8..0000000000
--- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/CaptionDto.cs
+++ /dev/null
@@ -1,22 +0,0 @@
-using System.Text.Json.Serialization;
-
-namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos
-{
- /// <summary>
- /// Caption dto.
- /// </summary>
- public class CaptionDto
- {
- /// <summary>
- /// Gets or sets the content.
- /// </summary>
- [JsonPropertyName("content")]
- public string? Content { get; set; }
-
- /// <summary>
- /// Gets or sets the lang.
- /// </summary>
- [JsonPropertyName("lang")]
- public string? Lang { get; set; }
- }
-}
diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/CastDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/CastDto.cs
deleted file mode 100644
index 0b7a2c63ad..0000000000
--- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/CastDto.cs
+++ /dev/null
@@ -1,46 +0,0 @@
-using System.Text.Json.Serialization;
-
-namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos
-{
- /// <summary>
- /// Cast dto.
- /// </summary>
- public class CastDto
- {
- /// <summary>
- /// Gets or sets the billing order.
- /// </summary>
- [JsonPropertyName("billingOrder")]
- public string? BillingOrder { get; set; }
-
- /// <summary>
- /// Gets or sets the role.
- /// </summary>
- [JsonPropertyName("role")]
- public string? Role { get; set; }
-
- /// <summary>
- /// Gets or sets the name id.
- /// </summary>
- [JsonPropertyName("nameId")]
- public string? NameId { get; set; }
-
- /// <summary>
- /// Gets or sets the person id.
- /// </summary>
- [JsonPropertyName("personId")]
- public string? PersonId { get; set; }
-
- /// <summary>
- /// Gets or sets the name.
- /// </summary>
- [JsonPropertyName("name")]
- public string? Name { get; set; }
-
- /// <summary>
- /// Gets or sets the character name.
- /// </summary>
- [JsonPropertyName("characterName")]
- public string? CharacterName { get; set; }
- }
-}
diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ChannelDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ChannelDto.cs
deleted file mode 100644
index 87c327ed82..0000000000
--- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ChannelDto.cs
+++ /dev/null
@@ -1,30 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Text.Json.Serialization;
-
-namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos
-{
- /// <summary>
- /// Channel dto.
- /// </summary>
- public class ChannelDto
- {
- /// <summary>
- /// Gets or sets the list of maps.
- /// </summary>
- [JsonPropertyName("map")]
- public IReadOnlyList<MapDto> Map { get; set; } = Array.Empty<MapDto>();
-
- /// <summary>
- /// Gets or sets the list of stations.
- /// </summary>
- [JsonPropertyName("stations")]
- public IReadOnlyList<StationDto> Stations { get; set; } = Array.Empty<StationDto>();
-
- /// <summary>
- /// Gets or sets the metadata.
- /// </summary>
- [JsonPropertyName("metadata")]
- public MetadataDto? Metadata { get; set; }
- }
-}
diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ContentRatingDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ContentRatingDto.cs
deleted file mode 100644
index c19cd2e48d..0000000000
--- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ContentRatingDto.cs
+++ /dev/null
@@ -1,22 +0,0 @@
-using System.Text.Json.Serialization;
-
-namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos
-{
- /// <summary>
- /// Content rating dto.
- /// </summary>
- public class ContentRatingDto
- {
- /// <summary>
- /// Gets or sets the body.
- /// </summary>
- [JsonPropertyName("body")]
- public string? Body { get; set; }
-
- /// <summary>
- /// Gets or sets the code.
- /// </summary>
- [JsonPropertyName("code")]
- public string? Code { get; set; }
- }
-}
diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/CrewDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/CrewDto.cs
deleted file mode 100644
index f00c9accdd..0000000000
--- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/CrewDto.cs
+++ /dev/null
@@ -1,40 +0,0 @@
-using System.Text.Json.Serialization;
-
-namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos
-{
- /// <summary>
- /// Crew dto.
- /// </summary>
- public class CrewDto
- {
- /// <summary>
- /// Gets or sets the billing order.
- /// </summary>
- [JsonPropertyName("billingOrder")]
- public string? BillingOrder { get; set; }
-
- /// <summary>
- /// Gets or sets the role.
- /// </summary>
- [JsonPropertyName("role")]
- public string? Role { get; set; }
-
- /// <summary>
- /// Gets or sets the name id.
- /// </summary>
- [JsonPropertyName("nameId")]
- public string? NameId { get; set; }
-
- /// <summary>
- /// Gets or sets the person id.
- /// </summary>
- [JsonPropertyName("personId")]
- public string? PersonId { get; set; }
-
- /// <summary>
- /// Gets or sets the name.
- /// </summary>
- [JsonPropertyName("name")]
- public string? Name { get; set; }
- }
-}
diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/DayDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/DayDto.cs
deleted file mode 100644
index 1a371965cf..0000000000
--- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/DayDto.cs
+++ /dev/null
@@ -1,30 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Text.Json.Serialization;
-
-namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos
-{
- /// <summary>
- /// Day dto.
- /// </summary>
- public class DayDto
- {
- /// <summary>
- /// Gets or sets the station id.
- /// </summary>
- [JsonPropertyName("stationID")]
- public string? StationId { get; set; }
-
- /// <summary>
- /// Gets or sets the list of programs.
- /// </summary>
- [JsonPropertyName("programs")]
- public IReadOnlyList<ProgramDto> Programs { get; set; } = Array.Empty<ProgramDto>();
-
- /// <summary>
- /// Gets or sets the metadata schedule.
- /// </summary>
- [JsonPropertyName("metadata")]
- public MetadataScheduleDto? Metadata { get; set; }
- }
-}
diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/Description1000Dto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/Description1000Dto.cs
deleted file mode 100644
index ca6ae7fb13..0000000000
--- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/Description1000Dto.cs
+++ /dev/null
@@ -1,22 +0,0 @@
-using System.Text.Json.Serialization;
-
-namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos
-{
- /// <summary>
- /// Description 1_000 dto.
- /// </summary>
- public class Description1000Dto
- {
- /// <summary>
- /// Gets or sets the description language.
- /// </summary>
- [JsonPropertyName("descriptionLanguage")]
- public string? DescriptionLanguage { get; set; }
-
- /// <summary>
- /// Gets or sets the description.
- /// </summary>
- [JsonPropertyName("description")]
- public string? Description { get; set; }
- }
-}
diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/Description100Dto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/Description100Dto.cs
deleted file mode 100644
index 1577219ed2..0000000000
--- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/Description100Dto.cs
+++ /dev/null
@@ -1,22 +0,0 @@
-using System.Text.Json.Serialization;
-
-namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos
-{
- /// <summary>
- /// Description 100 dto.
- /// </summary>
- public class Description100Dto
- {
- /// <summary>
- /// Gets or sets the description language.
- /// </summary>
- [JsonPropertyName("descriptionLanguage")]
- public string? DescriptionLanguage { get; set; }
-
- /// <summary>
- /// Gets or sets the description.
- /// </summary>
- [JsonPropertyName("description")]
- public string? Description { get; set; }
- }
-}
diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/DescriptionsProgramDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/DescriptionsProgramDto.cs
deleted file mode 100644
index eaf4a340bd..0000000000
--- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/DescriptionsProgramDto.cs
+++ /dev/null
@@ -1,24 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Text.Json.Serialization;
-
-namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos
-{
- /// <summary>
- /// Descriptions program dto.
- /// </summary>
- public class DescriptionsProgramDto
- {
- /// <summary>
- /// Gets or sets the list of description 100.
- /// </summary>
- [JsonPropertyName("description100")]
- public IReadOnlyList<Description100Dto> Description100 { get; set; } = Array.Empty<Description100Dto>();
-
- /// <summary>
- /// Gets or sets the list of description1000.
- /// </summary>
- [JsonPropertyName("description1000")]
- public IReadOnlyList<Description1000Dto> Description1000 { get; set; } = Array.Empty<Description1000Dto>();
- }
-}
diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/EventDetailsDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/EventDetailsDto.cs
deleted file mode 100644
index fbdfb1f716..0000000000
--- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/EventDetailsDto.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-using System.Text.Json.Serialization;
-
-namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos
-{
- /// <summary>
- /// Event details dto.
- /// </summary>
- public class EventDetailsDto
- {
- /// <summary>
- /// Gets or sets the sub type.
- /// </summary>
- [JsonPropertyName("subType")]
- public string? SubType { get; set; }
- }
-}
diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/GracenoteDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/GracenoteDto.cs
deleted file mode 100644
index 6852d89d71..0000000000
--- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/GracenoteDto.cs
+++ /dev/null
@@ -1,22 +0,0 @@
-using System.Text.Json.Serialization;
-
-namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos
-{
- /// <summary>
- /// Gracenote dto.
- /// </summary>
- public class GracenoteDto
- {
- /// <summary>
- /// Gets or sets the season.
- /// </summary>
- [JsonPropertyName("season")]
- public int Season { get; set; }
-
- /// <summary>
- /// Gets or sets the episode.
- /// </summary>
- [JsonPropertyName("episode")]
- public int Episode { get; set; }
- }
-}
diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/HeadendsDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/HeadendsDto.cs
deleted file mode 100644
index b9844562f3..0000000000
--- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/HeadendsDto.cs
+++ /dev/null
@@ -1,36 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Text.Json.Serialization;
-
-namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos
-{
- /// <summary>
- /// Headends dto.
- /// </summary>
- public class HeadendsDto
- {
- /// <summary>
- /// Gets or sets the headend.
- /// </summary>
- [JsonPropertyName("headend")]
- public string? Headend { get; set; }
-
- /// <summary>
- /// Gets or sets the transport.
- /// </summary>
- [JsonPropertyName("transport")]
- public string? Transport { get; set; }
-
- /// <summary>
- /// Gets or sets the location.
- /// </summary>
- [JsonPropertyName("location")]
- public string? Location { get; set; }
-
- /// <summary>
- /// Gets or sets the list of lineups.
- /// </summary>
- [JsonPropertyName("lineups")]
- public IReadOnlyList<LineupDto> Lineups { get; set; } = Array.Empty<LineupDto>();
- }
-}
diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ImageDataDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ImageDataDto.cs
deleted file mode 100644
index a1ae3ca6d4..0000000000
--- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ImageDataDto.cs
+++ /dev/null
@@ -1,70 +0,0 @@
-using System.Text.Json.Serialization;
-
-namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos
-{
- /// <summary>
- /// Image data dto.
- /// </summary>
- public class ImageDataDto
- {
- /// <summary>
- /// Gets or sets the width.
- /// </summary>
- [JsonPropertyName("width")]
- public string? Width { get; set; }
-
- /// <summary>
- /// Gets or sets the height.
- /// </summary>
- [JsonPropertyName("height")]
- public string? Height { get; set; }
-
- /// <summary>
- /// Gets or sets the uri.
- /// </summary>
- [JsonPropertyName("uri")]
- public string? Uri { get; set; }
-
- /// <summary>
- /// Gets or sets the size.
- /// </summary>
- [JsonPropertyName("size")]
- public string? Size { get; set; }
-
- /// <summary>
- /// Gets or sets the aspect.
- /// </summary>
- [JsonPropertyName("aspect")]
- public string? Aspect { get; set; }
-
- /// <summary>
- /// Gets or sets the category.
- /// </summary>
- [JsonPropertyName("category")]
- public string? Category { get; set; }
-
- /// <summary>
- /// Gets or sets the text.
- /// </summary>
- [JsonPropertyName("text")]
- public string? Text { get; set; }
-
- /// <summary>
- /// Gets or sets the primary.
- /// </summary>
- [JsonPropertyName("primary")]
- public string? Primary { get; set; }
-
- /// <summary>
- /// Gets or sets the tier.
- /// </summary>
- [JsonPropertyName("tier")]
- public string? Tier { get; set; }
-
- /// <summary>
- /// Gets or sets the caption.
- /// </summary>
- [JsonPropertyName("caption")]
- public CaptionDto? Caption { get; set; }
- }
-}
diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/LineupDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/LineupDto.cs
deleted file mode 100644
index 3dc64e5d8a..0000000000
--- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/LineupDto.cs
+++ /dev/null
@@ -1,46 +0,0 @@
-using System.Text.Json.Serialization;
-
-namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos
-{
- /// <summary>
- /// The lineup dto.
- /// </summary>
- public class LineupDto
- {
- /// <summary>
- /// Gets or sets the linup.
- /// </summary>
- [JsonPropertyName("lineup")]
- public string? Lineup { get; set; }
-
- /// <summary>
- /// Gets or sets the lineup name.
- /// </summary>
- [JsonPropertyName("name")]
- public string? Name { get; set; }
-
- /// <summary>
- /// Gets or sets the transport.
- /// </summary>
- [JsonPropertyName("transport")]
- public string? Transport { get; set; }
-
- /// <summary>
- /// Gets or sets the location.
- /// </summary>
- [JsonPropertyName("location")]
- public string? Location { get; set; }
-
- /// <summary>
- /// Gets or sets the uri.
- /// </summary>
- [JsonPropertyName("uri")]
- public string? Uri { get; set; }
-
- /// <summary>
- /// Gets or sets a value indicating whether this lineup was deleted.
- /// </summary>
- [JsonPropertyName("isDeleted")]
- public bool? IsDeleted { get; set; }
- }
-}
diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/LineupsDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/LineupsDto.cs
deleted file mode 100644
index f190817813..0000000000
--- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/LineupsDto.cs
+++ /dev/null
@@ -1,36 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Text.Json.Serialization;
-
-namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos
-{
- /// <summary>
- /// Lineups dto.
- /// </summary>
- public class LineupsDto
- {
- /// <summary>
- /// Gets or sets the response code.
- /// </summary>
- [JsonPropertyName("code")]
- public int Code { get; set; }
-
- /// <summary>
- /// Gets or sets the server id.
- /// </summary>
- [JsonPropertyName("serverID")]
- public string? ServerId { get; set; }
-
- /// <summary>
- /// Gets or sets the datetime.
- /// </summary>
- [JsonPropertyName("datetime")]
- public DateTime? LineupTimestamp { get; set; }
-
- /// <summary>
- /// Gets or sets the list of lineups.
- /// </summary>
- [JsonPropertyName("lineups")]
- public IReadOnlyList<LineupDto> Lineups { get; set; } = Array.Empty<LineupDto>();
- }
-}
diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/LogoDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/LogoDto.cs
deleted file mode 100644
index fecc55e037..0000000000
--- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/LogoDto.cs
+++ /dev/null
@@ -1,34 +0,0 @@
-using System.Text.Json.Serialization;
-
-namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos
-{
- /// <summary>
- /// Logo dto.
- /// </summary>
- public class LogoDto
- {
- /// <summary>
- /// Gets or sets the url.
- /// </summary>
- [JsonPropertyName("URL")]
- public string? Url { get; set; }
-
- /// <summary>
- /// Gets or sets the height.
- /// </summary>
- [JsonPropertyName("height")]
- public int Height { get; set; }
-
- /// <summary>
- /// Gets or sets the width.
- /// </summary>
- [JsonPropertyName("width")]
- public int Width { get; set; }
-
- /// <summary>
- /// Gets or sets the md5.
- /// </summary>
- [JsonPropertyName("md5")]
- public string? Md5 { get; set; }
- }
-}
diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MapDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MapDto.cs
deleted file mode 100644
index ffd02d474b..0000000000
--- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MapDto.cs
+++ /dev/null
@@ -1,58 +0,0 @@
-using System.Text.Json.Serialization;
-
-namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos
-{
- /// <summary>
- /// Map dto.
- /// </summary>
- public class MapDto
- {
- /// <summary>
- /// Gets or sets the station id.
- /// </summary>
- [JsonPropertyName("stationID")]
- public string? StationId { get; set; }
-
- /// <summary>
- /// Gets or sets the channel.
- /// </summary>
- [JsonPropertyName("channel")]
- public string? Channel { get; set; }
-
- /// <summary>
- /// Gets or sets the provider callsign.
- /// </summary>
- [JsonPropertyName("providerCallsign")]
- public string? ProvderCallsign { get; set; }
-
- /// <summary>
- /// Gets or sets the logical channel number.
- /// </summary>
- [JsonPropertyName("logicalChannelNumber")]
- public string? LogicalChannelNumber { get; set; }
-
- /// <summary>
- /// Gets or sets the uhfvhf.
- /// </summary>
- [JsonPropertyName("uhfVhf")]
- public int UhfVhf { get; set; }
-
- /// <summary>
- /// Gets or sets the atsc major.
- /// </summary>
- [JsonPropertyName("atscMajor")]
- public int AtscMajor { get; set; }
-
- /// <summary>
- /// Gets or sets the atsc minor.
- /// </summary>
- [JsonPropertyName("atscMinor")]
- public int AtscMinor { get; set; }
-
- /// <summary>
- /// Gets or sets the match type.
- /// </summary>
- [JsonPropertyName("matchType")]
- public string? MatchType { get; set; }
- }
-}
diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MetadataDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MetadataDto.cs
deleted file mode 100644
index 40faa493c5..0000000000
--- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MetadataDto.cs
+++ /dev/null
@@ -1,28 +0,0 @@
-using System.Text.Json.Serialization;
-
-namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos
-{
- /// <summary>
- /// Metadata dto.
- /// </summary>
- public class MetadataDto
- {
- /// <summary>
- /// Gets or sets the linup.
- /// </summary>
- [JsonPropertyName("lineup")]
- public string? Lineup { get; set; }
-
- /// <summary>
- /// Gets or sets the modified timestamp.
- /// </summary>
- [JsonPropertyName("modified")]
- public string? Modified { get; set; }
-
- /// <summary>
- /// Gets or sets the transport.
- /// </summary>
- [JsonPropertyName("transport")]
- public string? Transport { get; set; }
- }
-}
diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MetadataProgramsDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MetadataProgramsDto.cs
deleted file mode 100644
index 43f2901566..0000000000
--- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MetadataProgramsDto.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-using System.Text.Json.Serialization;
-
-namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos
-{
- /// <summary>
- /// Metadata programs dto.
- /// </summary>
- public class MetadataProgramsDto
- {
- /// <summary>
- /// Gets or sets the gracenote object.
- /// </summary>
- [JsonPropertyName("Gracenote")]
- public GracenoteDto? Gracenote { get; set; }
- }
-}
diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MetadataScheduleDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MetadataScheduleDto.cs
deleted file mode 100644
index 04560ab55d..0000000000
--- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MetadataScheduleDto.cs
+++ /dev/null
@@ -1,41 +0,0 @@
-using System;
-using System.Text.Json.Serialization;
-
-namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos
-{
- /// <summary>
- /// Metadata schedule dto.
- /// </summary>
- public class MetadataScheduleDto
- {
- /// <summary>
- /// Gets or sets the modified timestamp.
- /// </summary>
- [JsonPropertyName("modified")]
- public string? Modified { get; set; }
-
- /// <summary>
- /// Gets or sets the md5.
- /// </summary>
- [JsonPropertyName("md5")]
- public string? Md5 { get; set; }
-
- /// <summary>
- /// Gets or sets the start date.
- /// </summary>
- [JsonPropertyName("startDate")]
- public DateTime? StartDate { get; set; }
-
- /// <summary>
- /// Gets or sets the end date.
- /// </summary>
- [JsonPropertyName("endDate")]
- public DateTime? EndDate { get; set; }
-
- /// <summary>
- /// Gets or sets the days count.
- /// </summary>
- [JsonPropertyName("days")]
- public int Days { get; set; }
- }
-}
diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MovieDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MovieDto.cs
deleted file mode 100644
index 31bef423b2..0000000000
--- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MovieDto.cs
+++ /dev/null
@@ -1,30 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Text.Json.Serialization;
-
-namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos
-{
- /// <summary>
- /// Movie dto.
- /// </summary>
- public class MovieDto
- {
- /// <summary>
- /// Gets or sets the year.
- /// </summary>
- [JsonPropertyName("year")]
- public string? Year { get; set; }
-
- /// <summary>
- /// Gets or sets the duration.
- /// </summary>
- [JsonPropertyName("duration")]
- public int Duration { get; set; }
-
- /// <summary>
- /// Gets or sets the list of quality rating.
- /// </summary>
- [JsonPropertyName("qualityRating")]
- public IReadOnlyList<QualityRatingDto> QualityRating { get; set; } = Array.Empty<QualityRatingDto>();
- }
-}
diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MultipartDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MultipartDto.cs
deleted file mode 100644
index e8b15dc07c..0000000000
--- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MultipartDto.cs
+++ /dev/null
@@ -1,22 +0,0 @@
-using System.Text.Json.Serialization;
-
-namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos
-{
- /// <summary>
- /// Multipart dto.
- /// </summary>
- public class MultipartDto
- {
- /// <summary>
- /// Gets or sets the part number.
- /// </summary>
- [JsonPropertyName("partNumber")]
- public int PartNumber { get; set; }
-
- /// <summary>
- /// Gets or sets the total parts.
- /// </summary>
- [JsonPropertyName("totalParts")]
- public int TotalParts { get; set; }
- }
-}
diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ProgramDetailsDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ProgramDetailsDto.cs
deleted file mode 100644
index 84c48f67f3..0000000000
--- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ProgramDetailsDto.cs
+++ /dev/null
@@ -1,156 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Text.Json.Serialization;
-
-namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos
-{
- /// <summary>
- /// Program details dto.
- /// </summary>
- public class ProgramDetailsDto
- {
- /// <summary>
- /// Gets or sets the audience.
- /// </summary>
- [JsonPropertyName("audience")]
- public string? Audience { get; set; }
-
- /// <summary>
- /// Gets or sets the program id.
- /// </summary>
- [JsonPropertyName("programID")]
- public string? ProgramId { get; set; }
-
- /// <summary>
- /// Gets or sets the list of titles.
- /// </summary>
- [JsonPropertyName("titles")]
- public IReadOnlyList<TitleDto> Titles { get; set; } = Array.Empty<TitleDto>();
-
- /// <summary>
- /// Gets or sets the event details object.
- /// </summary>
- [JsonPropertyName("eventDetails")]
- public EventDetailsDto? EventDetails { get; set; }
-
- /// <summary>
- /// Gets or sets the descriptions.
- /// </summary>
- [JsonPropertyName("descriptions")]
- public DescriptionsProgramDto? Descriptions { get; set; }
-
- /// <summary>
- /// Gets or sets the original air date.
- /// </summary>
- [JsonPropertyName("originalAirDate")]
- public DateTime? OriginalAirDate { get; set; }
-
- /// <summary>
- /// Gets or sets the list of genres.
- /// </summary>
- [JsonPropertyName("genres")]
- public IReadOnlyList<string> Genres { get; set; } = Array.Empty<string>();
-
- /// <summary>
- /// Gets or sets the episode title.
- /// </summary>
- [JsonPropertyName("episodeTitle150")]
- public string? EpisodeTitle150 { get; set; }
-
- /// <summary>
- /// Gets or sets the list of metadata.
- /// </summary>
- [JsonPropertyName("metadata")]
- public IReadOnlyList<MetadataProgramsDto> Metadata { get; set; } = Array.Empty<MetadataProgramsDto>();
-
- /// <summary>
- /// Gets or sets the list of content raitings.
- /// </summary>
- [JsonPropertyName("contentRating")]
- public IReadOnlyList<ContentRatingDto> ContentRating { get; set; } = Array.Empty<ContentRatingDto>();
-
- /// <summary>
- /// Gets or sets the list of cast.
- /// </summary>
- [JsonPropertyName("cast")]
- public IReadOnlyList<CastDto> Cast { get; set; } = Array.Empty<CastDto>();
-
- /// <summary>
- /// Gets or sets the list of crew.
- /// </summary>
- [JsonPropertyName("crew")]
- public IReadOnlyList<CrewDto> Crew { get; set; } = Array.Empty<CrewDto>();
-
- /// <summary>
- /// Gets or sets the entity type.
- /// </summary>
- [JsonPropertyName("entityType")]
- public string? EntityType { get; set; }
-
- /// <summary>
- /// Gets or sets the show type.
- /// </summary>
- [JsonPropertyName("showType")]
- public string? ShowType { get; set; }
-
- /// <summary>
- /// Gets or sets a value indicating whether there is image artwork.
- /// </summary>
- [JsonPropertyName("hasImageArtwork")]
- public bool HasImageArtwork { get; set; }
-
- /// <summary>
- /// Gets or sets the primary image.
- /// </summary>
- [JsonPropertyName("primaryImage")]
- public string? PrimaryImage { get; set; }
-
- /// <summary>
- /// Gets or sets the thumb image.
- /// </summary>
- [JsonPropertyName("thumbImage")]
- public string? ThumbImage { get; set; }
-
- /// <summary>
- /// Gets or sets the backdrop image.
- /// </summary>
- [JsonPropertyName("backdropImage")]
- public string? BackdropImage { get; set; }
-
- /// <summary>
- /// Gets or sets the banner image.
- /// </summary>
- [JsonPropertyName("bannerImage")]
- public string? BannerImage { get; set; }
-
- /// <summary>
- /// Gets or sets the image id.
- /// </summary>
- [JsonPropertyName("imageID")]
- public string? ImageId { get; set; }
-
- /// <summary>
- /// Gets or sets the md5.
- /// </summary>
- [JsonPropertyName("md5")]
- public string? Md5 { get; set; }
-
- /// <summary>
- /// Gets or sets the list of content advisory.
- /// </summary>
- [JsonPropertyName("contentAdvisory")]
- public IReadOnlyList<string> ContentAdvisory { get; set; } = Array.Empty<string>();
-
- /// <summary>
- /// Gets or sets the movie object.
- /// </summary>
- [JsonPropertyName("movie")]
- public MovieDto? Movie { get; set; }
-
- /// <summary>
- /// Gets or sets the list of recommendations.
- /// </summary>
- [JsonPropertyName("recommendations")]
- public IReadOnlyList<RecommendationDto> Recommendations { get; set; } = Array.Empty<RecommendationDto>();
- }
-}
diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ProgramDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ProgramDto.cs
deleted file mode 100644
index 60389b45bf..0000000000
--- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ProgramDto.cs
+++ /dev/null
@@ -1,90 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Text.Json.Serialization;
-
-namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos
-{
- /// <summary>
- /// Program dto.
- /// </summary>
- public class ProgramDto
- {
- /// <summary>
- /// Gets or sets the program id.
- /// </summary>
- [JsonPropertyName("programID")]
- public string? ProgramId { get; set; }
-
- /// <summary>
- /// Gets or sets the air date time.
- /// </summary>
- [JsonPropertyName("airDateTime")]
- public DateTime? AirDateTime { get; set; }
-
- /// <summary>
- /// Gets or sets the duration.
- /// </summary>
- [JsonPropertyName("duration")]
- public int Duration { get; set; }
-
- /// <summary>
- /// Gets or sets the md5.
- /// </summary>
- [JsonPropertyName("md5")]
- public string? Md5 { get; set; }
-
- /// <summary>
- /// Gets or sets the list of audio properties.
- /// </summary>
- [JsonPropertyName("audioProperties")]
- public IReadOnlyList<string> AudioProperties { get; set; } = Array.Empty<string>();
-
- /// <summary>
- /// Gets or sets the list of video properties.
- /// </summary>
- [JsonPropertyName("videoProperties")]
- public IReadOnlyList<string> VideoProperties { get; set; } = Array.Empty<string>();
-
- /// <summary>
- /// Gets or sets the list of ratings.
- /// </summary>
- [JsonPropertyName("ratings")]
- public IReadOnlyList<RatingDto> Ratings { get; set; } = Array.Empty<RatingDto>();
-
- /// <summary>
- /// Gets or sets a value indicating whether this program is new.
- /// </summary>
- [JsonPropertyName("new")]
- public bool? New { get; set; }
-
- /// <summary>
- /// Gets or sets the multipart object.
- /// </summary>
- [JsonPropertyName("multipart")]
- public MultipartDto? Multipart { get; set; }
-
- /// <summary>
- /// Gets or sets the live tape delay.
- /// </summary>
- [JsonPropertyName("liveTapeDelay")]
- public string? LiveTapeDelay { get; set; }
-
- /// <summary>
- /// Gets or sets a value indicating whether this is the premiere.
- /// </summary>
- [JsonPropertyName("premiere")]
- public bool Premiere { get; set; }
-
- /// <summary>
- /// Gets or sets a value indicating whether this is a repeat.
- /// </summary>
- [JsonPropertyName("repeat")]
- public bool Repeat { get; set; }
-
- /// <summary>
- /// Gets or sets the premiere or finale.
- /// </summary>
- [JsonPropertyName("isPremiereOrFinale")]
- public string? IsPremiereOrFinale { get; set; }
- }
-}
diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/QualityRatingDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/QualityRatingDto.cs
deleted file mode 100644
index c5ddcf7c51..0000000000
--- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/QualityRatingDto.cs
+++ /dev/null
@@ -1,40 +0,0 @@
-using System.Text.Json.Serialization;
-
-namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos
-{
- /// <summary>
- /// Quality rating dto.
- /// </summary>
- public class QualityRatingDto
- {
- /// <summary>
- /// Gets or sets the ratings body.
- /// </summary>
- [JsonPropertyName("ratingsBody")]
- public string? RatingsBody { get; set; }
-
- /// <summary>
- /// Gets or sets the rating.
- /// </summary>
- [JsonPropertyName("rating")]
- public string? Rating { get; set; }
-
- /// <summary>
- /// Gets or sets the min rating.
- /// </summary>
- [JsonPropertyName("minRating")]
- public string? MinRating { get; set; }
-
- /// <summary>
- /// Gets or sets the max rating.
- /// </summary>
- [JsonPropertyName("maxRating")]
- public string? MaxRating { get; set; }
-
- /// <summary>
- /// Gets or sets the increment.
- /// </summary>
- [JsonPropertyName("increment")]
- public string? Increment { get; set; }
- }
-}
diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/RatingDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/RatingDto.cs
deleted file mode 100644
index e04b619a4d..0000000000
--- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/RatingDto.cs
+++ /dev/null
@@ -1,22 +0,0 @@
-using System.Text.Json.Serialization;
-
-namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos
-{
- /// <summary>
- /// Rating dto.
- /// </summary>
- public class RatingDto
- {
- /// <summary>
- /// Gets or sets the body.
- /// </summary>
- [JsonPropertyName("body")]
- public string? Body { get; set; }
-
- /// <summary>
- /// Gets or sets the code.
- /// </summary>
- [JsonPropertyName("code")]
- public string? Code { get; set; }
- }
-}
diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/RecommendationDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/RecommendationDto.cs
deleted file mode 100644
index c8f79fd1c2..0000000000
--- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/RecommendationDto.cs
+++ /dev/null
@@ -1,22 +0,0 @@
-using System.Text.Json.Serialization;
-
-namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos
-{
- /// <summary>
- /// Recommendation dto.
- /// </summary>
- public class RecommendationDto
- {
- /// <summary>
- /// Gets or sets the program id.
- /// </summary>
- [JsonPropertyName("programID")]
- public string? ProgramId { get; set; }
-
- /// <summary>
- /// Gets or sets the title.
- /// </summary>
- [JsonPropertyName("title120")]
- public string? Title120 { get; set; }
- }
-}
diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/RequestScheduleForChannelDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/RequestScheduleForChannelDto.cs
deleted file mode 100644
index 0cd05709b3..0000000000
--- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/RequestScheduleForChannelDto.cs
+++ /dev/null
@@ -1,24 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Text.Json.Serialization;
-
-namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos
-{
- /// <summary>
- /// Request schedule for channel dto.
- /// </summary>
- public class RequestScheduleForChannelDto
- {
- /// <summary>
- /// Gets or sets the station id.
- /// </summary>
- [JsonPropertyName("stationID")]
- public string? StationId { get; set; }
-
- /// <summary>
- /// Gets or sets the list of dates.
- /// </summary>
- [JsonPropertyName("date")]
- public IReadOnlyList<string> Date { get; set; } = Array.Empty<string>();
- }
-}
diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ShowImagesDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ShowImagesDto.cs
deleted file mode 100644
index 84e224b71e..0000000000
--- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ShowImagesDto.cs
+++ /dev/null
@@ -1,24 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Text.Json.Serialization;
-
-namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos
-{
- /// <summary>
- /// Show image dto.
- /// </summary>
- public class ShowImagesDto
- {
- /// <summary>
- /// Gets or sets the program id.
- /// </summary>
- [JsonPropertyName("programID")]
- public string? ProgramId { get; set; }
-
- /// <summary>
- /// Gets or sets the list of data.
- /// </summary>
- [JsonPropertyName("data")]
- public IReadOnlyList<ImageDataDto> Data { get; set; } = Array.Empty<ImageDataDto>();
- }
-}
diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/StationDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/StationDto.cs
deleted file mode 100644
index d797fd49b1..0000000000
--- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/StationDto.cs
+++ /dev/null
@@ -1,66 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Text.Json.Serialization;
-
-namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos
-{
- /// <summary>
- /// Station dto.
- /// </summary>
- public class StationDto
- {
- /// <summary>
- /// Gets or sets the station id.
- /// </summary>
- [JsonPropertyName("stationID")]
- public string? StationId { get; set; }
-
- /// <summary>
- /// Gets or sets the name.
- /// </summary>
- [JsonPropertyName("name")]
- public string? Name { get; set; }
-
- /// <summary>
- /// Gets or sets the callsign.
- /// </summary>
- [JsonPropertyName("callsign")]
- public string? Callsign { get; set; }
-
- /// <summary>
- /// Gets or sets the broadcast language.
- /// </summary>
- [JsonPropertyName("broadcastLanguage")]
- public IReadOnlyList<string> BroadcastLanguage { get; set; } = Array.Empty<string>();
-
- /// <summary>
- /// Gets or sets the description language.
- /// </summary>
- [JsonPropertyName("descriptionLanguage")]
- public IReadOnlyList<string> DescriptionLanguage { get; set; } = Array.Empty<string>();
-
- /// <summary>
- /// Gets or sets the broadcaster.
- /// </summary>
- [JsonPropertyName("broadcaster")]
- public BroadcasterDto? Broadcaster { get; set; }
-
- /// <summary>
- /// Gets or sets the affiliate.
- /// </summary>
- [JsonPropertyName("affiliate")]
- public string? Affiliate { get; set; }
-
- /// <summary>
- /// Gets or sets the logo.
- /// </summary>
- [JsonPropertyName("logo")]
- public LogoDto? Logo { get; set; }
-
- /// <summary>
- /// Gets or sets a value indicating whether it is commercial free.
- /// </summary>
- [JsonPropertyName("isCommercialFree")]
- public bool? IsCommercialFree { get; set; }
- }
-}
diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/TitleDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/TitleDto.cs
deleted file mode 100644
index 61cd4a9b00..0000000000
--- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/TitleDto.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-using System.Text.Json.Serialization;
-
-namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos
-{
- /// <summary>
- /// Title dto.
- /// </summary>
- public class TitleDto
- {
- /// <summary>
- /// Gets or sets the title.
- /// </summary>
- [JsonPropertyName("title120")]
- public string? Title120 { get; set; }
- }
-}
diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/TokenDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/TokenDto.cs
deleted file mode 100644
index afb9994869..0000000000
--- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/TokenDto.cs
+++ /dev/null
@@ -1,47 +0,0 @@
-using System;
-using System.Text.Json.Serialization;
-
-namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos
-{
- /// <summary>
- /// The token dto.
- /// </summary>
- public class TokenDto
- {
- /// <summary>
- /// Gets or sets the response code.
- /// </summary>
- [JsonPropertyName("code")]
- public int Code { get; set; }
-
- /// <summary>
- /// Gets or sets the response message.
- /// </summary>
- [JsonPropertyName("message")]
- public string? Message { get; set; }
-
- /// <summary>
- /// Gets or sets the server id.
- /// </summary>
- [JsonPropertyName("serverID")]
- public string? ServerId { get; set; }
-
- /// <summary>
- /// Gets or sets the token.
- /// </summary>
- [JsonPropertyName("token")]
- public string? Token { get; set; }
-
- /// <summary>
- /// Gets or sets the current datetime.
- /// </summary>
- [JsonPropertyName("datetime")]
- public DateTime? TokenTimestamp { get; set; }
-
- /// <summary>
- /// Gets or sets the response message.
- /// </summary>
- [JsonPropertyName("response")]
- public string? Response { get; set; }
- }
-}
diff --git a/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs b/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs
deleted file mode 100644
index e60e9dcc1c..0000000000
--- a/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs
+++ /dev/null
@@ -1,267 +0,0 @@
-#nullable disable
-
-#pragma warning disable CS1591
-
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.IO;
-using System.IO.Compression;
-using System.Linq;
-using System.Net.Http;
-using System.Threading;
-using System.Threading.Tasks;
-using Jellyfin.Extensions;
-using Jellyfin.XmlTv;
-using Jellyfin.XmlTv.Entities;
-using MediaBrowser.Common.Extensions;
-using MediaBrowser.Common.Net;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.LiveTv;
-using MediaBrowser.Model.Dto;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Model.LiveTv;
-using Microsoft.Extensions.Logging;
-
-namespace Emby.Server.Implementations.LiveTv.Listings
-{
- public class XmlTvListingsProvider : IListingsProvider
- {
- private static readonly TimeSpan _maxCacheAge = TimeSpan.FromHours(1);
-
- private readonly IServerConfigurationManager _config;
- private readonly IHttpClientFactory _httpClientFactory;
- private readonly ILogger<XmlTvListingsProvider> _logger;
-
- public XmlTvListingsProvider(
- IServerConfigurationManager config,
- IHttpClientFactory httpClientFactory,
- ILogger<XmlTvListingsProvider> logger)
- {
- _config = config;
- _httpClientFactory = httpClientFactory;
- _logger = logger;
- }
-
- public string Name => "XmlTV";
-
- public string Type => "xmltv";
-
- private string GetLanguage(ListingsProviderInfo info)
- {
- if (!string.IsNullOrWhiteSpace(info.PreferredLanguage))
- {
- return info.PreferredLanguage;
- }
-
- return _config.Configuration.PreferredMetadataLanguage;
- }
-
- private async Task<string> GetXml(ListingsProviderInfo info, CancellationToken cancellationToken)
- {
- _logger.LogInformation("xmltv path: {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 cacheFile;
- }
-
- // Must check if file exists as parent directory may not exist.
- if (File.Exists(cacheFile))
- {
- File.Delete(cacheFile);
- }
- else
- {
- Directory.CreateDirectory(Path.GetDirectoryName(cacheFile));
- }
-
- if (info.Path.StartsWith("http", StringComparison.OrdinalIgnoreCase))
- {
- _logger.LogInformation("Downloading xmltv listings from {Path}", info.Path);
-
- using var response = await _httpClientFactory.CreateClient(NamedClient.Default).GetAsync(info.Path, cancellationToken).ConfigureAwait(false);
- var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false);
- await using (stream.ConfigureAwait(false))
- {
- return await UnzipIfNeededAndCopy(info.Path, stream, cacheFile, cancellationToken).ConfigureAwait(false);
- }
- }
- else
- {
- var stream = AsyncFile.OpenRead(info.Path);
- await using (stream.ConfigureAwait(false))
- {
- return await UnzipIfNeededAndCopy(info.Path, stream, cacheFile, cancellationToken).ConfigureAwait(false);
- }
- }
- }
-
- private async Task<string> UnzipIfNeededAndCopy(string originalUrl, Stream stream, string file, CancellationToken cancellationToken)
- {
- var fileStream = new FileStream(
- file,
- FileMode.CreateNew,
- FileAccess.Write,
- FileShare.None,
- IODefaults.FileStreamBufferSize,
- FileOptions.Asynchronous);
-
- await using (fileStream.ConfigureAwait(false))
- {
- if (Path.GetExtension(originalUrl.AsSpan().LeftPart('?')).Equals(".gz", StringComparison.OrdinalIgnoreCase))
- {
- try
- {
- using var reader = new GZipStream(stream, CompressionMode.Decompress);
- await reader.CopyToAsync(fileStream, cancellationToken).ConfigureAwait(false);
- }
- catch (Exception ex)
- {
- _logger.LogError(ex, "Error extracting from gz file {File}", originalUrl);
- }
- }
- else
- {
- await stream.CopyToAsync(fileStream, cancellationToken).ConfigureAwait(false);
- }
-
- return file;
- }
- }
-
- 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, 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));
- }
-
- private static ProgramInfo GetProgramInfo(XmlTvProgram program, ListingsProviderInfo info)
- {
- string episodeTitle = program.Episode.Title;
- var programCategories = program.Categories.Where(c => !string.IsNullOrWhiteSpace(c)).ToList();
-
- var programInfo = new ProgramInfo
- {
- ChannelId = program.ChannelId,
- EndDate = program.EndDate.UtcDateTime,
- EpisodeNumber = program.Episode.Episode,
- EpisodeTitle = episodeTitle,
- Genres = programCategories,
- StartDate = program.StartDate.UtcDateTime,
- Name = program.Title,
- Overview = program.Description,
- ProductionYear = program.CopyrightDate?.Year,
- SeasonNumber = program.Episode.Series,
- IsSeries = program.Episode.Series is not null,
- IsRepeat = program.IsPreviouslyShown && !program.IsNew,
- IsPremiere = program.Premiere is not null,
- IsKids = programCategories.Any(c => info.KidsCategories.Contains(c, StringComparison.OrdinalIgnoreCase)),
- IsMovie = programCategories.Any(c => info.MovieCategories.Contains(c, StringComparison.OrdinalIgnoreCase)),
- IsNews = programCategories.Any(c => info.NewsCategories.Contains(c, StringComparison.OrdinalIgnoreCase)),
- IsSports = programCategories.Any(c => info.SportsCategories.Contains(c, StringComparison.OrdinalIgnoreCase)),
- ImageUrl = string.IsNullOrEmpty(program.Icon?.Source) ? null : program.Icon.Source,
- HasImage = !string.IsNullOrEmpty(program.Icon?.Source),
- OfficialRating = string.IsNullOrEmpty(program.Rating?.Value) ? null : program.Rating.Value,
- CommunityRating = program.StarRating,
- SeriesId = program.Episode.Episode is null ? null : program.Title?.GetMD5().ToString("N", CultureInfo.InvariantCulture)
- };
-
- if (string.IsNullOrWhiteSpace(program.ProgramId))
- {
- string uniqueString = (program.Title ?? string.Empty) + (episodeTitle ?? 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", CultureInfo.InvariantCulture);
-
- // If we don't have valid episode info, assume it's a unique program, otherwise recordings might be skipped
- if (programInfo.IsSeries
- && !programInfo.IsRepeat
- && (programInfo.EpisodeNumber ?? 0) == 0)
- {
- programInfo.ShowId += programInfo.StartDate.Ticks.ToString(CultureInfo.InvariantCulture);
- }
- }
- else
- {
- programInfo.ShowId = program.ProgramId;
- }
-
- // Construct an id from the channel and start date
- programInfo.Id = string.Format(CultureInfo.InvariantCulture, "{0}_{1:O}", program.ChannelId, program.StartDate);
-
- if (programInfo.IsMovie)
- {
- programInfo.IsSeries = false;
- programInfo.EpisodeNumber = null;
- programInfo.EpisodeTitle = null;
- }
-
- return programInfo;
- }
-
- 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) && !File.Exists(info.Path))
- {
- throw new FileNotFoundException("Could not find the XmlTv file specified:", info.Path);
- }
-
- return Task.CompletedTask;
- }
-
- 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
- string path = await GetXml(info, CancellationToken.None).ConfigureAwait(false);
- _logger.LogDebug("Opening XmlTvReader for {Path}", path);
- var reader = new XmlTvReader(path, GetLanguage(info));
- IEnumerable<XmlTvChannel> results = reader.GetChannels();
-
- // Should this method be async?
- return results.Select(c => new NameIdPair() { Id = c.Id, Name = c.DisplayName }).ToList();
- }
-
- 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 = string.IsNullOrEmpty(c.Icon?.Source) ? null : c.Icon.Source,
- Number = string.IsNullOrWhiteSpace(c.Number) ? c.Id : c.Number
- }).ToList();
- }
- }
-}