From 47e24a2cf77e6c3fe50eb5398fa56950a047ed7b Mon Sep 17 00:00:00 2001 From: Cody Robibero Date: Fri, 3 Sep 2021 12:35:52 -0600 Subject: [PATCH] Add SchedulesDirect json tests --- .../LiveTv/Listings/SchedulesDirect.cs | 62 ++--- .../SchedulesDirectDtos/ImageDataDto.cs | 2 +- .../Listings/SchedulesDirectDtos/LineupDto.cs | 6 + .../SchedulesDirectDtos/LineupsDto.cs | 2 +- .../Listings/SchedulesDirectDtos/MapDto.cs | 12 + .../MetadataProgramsDto.cs | 2 +- .../SchedulesDirectDtos/ProgramDetailsDto.cs | 2 +- .../SchedulesDirectDtos/ProgramDto.cs | 2 +- .../Listings/SchedulesDirectDtos/TokenDto.cs | 6 + ...llyfin.Server.Implementations.Tests.csproj | 3 + .../SchedulesDirectDeserializeTests.cs | 245 ++++++++++++++++++ .../TestData/headends_response.json | 113 ++++++++ .../TestData/lineup_response.json | 18 ++ .../TestData/lineups_response.json | 40 +++ .../TestData/metadata_programs_response.json | 51 ++++ .../TestData/programs_response.json | 245 ++++++++++++++++++ .../TestData/schedules_request.json | 16 ++ .../TestData/schedules_response.json | 35 +++ .../TestData/token_live_response.json | 7 + .../TestData/token_offline_response.json | 8 + 20 files changed, 841 insertions(+), 36 deletions(-) create mode 100644 tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/SchedulesDirectDeserializeTests.cs create mode 100644 tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/headends_response.json create mode 100644 tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/lineup_response.json create mode 100644 tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/lineups_response.json create mode 100644 tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/metadata_programs_response.json create mode 100644 tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/programs_response.json create mode 100644 tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/schedules_request.json create mode 100644 tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/schedules_response.json create mode 100644 tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/token_live_response.json create mode 100644 tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/token_offline_response.json diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs index 41c3bafa06..e8562b8c57 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs @@ -9,12 +9,14 @@ using System.Globalization; using System.Linq; using System.Net; using System.Net.Http; +using System.Net.Http.Json; using System.Net.Mime; 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.LiveTv; @@ -110,19 +112,19 @@ namespace Emby.Server.Implementations.LiveTv.Listings options.Headers.TryAddWithoutValidation("token", token); using var response = await Send(options, true, info, cancellationToken).ConfigureAwait(false); await using var responseStream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); - var dailySchedules = await JsonSerializer.DeserializeAsync>(responseStream, _jsonOptions, cancellationToken).ConfigureAwait(false); - _logger.LogDebug("Found {ScheduleCount} programs on {ChannelID} ScheduleDirect", dailySchedules.Count, channelId); + var dailySchedules = await JsonSerializer.DeserializeAsync>(responseStream, _jsonOptions, cancellationToken).ConfigureAwait(false); + _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 = new StringContent("[\"" + string.Join("\", \"", programIds) + "\"]", Encoding.UTF8, MediaTypeNames.Application.Json); + programRequestOptions.Content = new StringContent(JsonSerializer.Serialize(programIds), Encoding.UTF8, MediaTypeNames.Application.Json); using var innerResponse = await Send(programRequestOptions, true, info, cancellationToken).ConfigureAwait(false); await using var innerResponseStream = await innerResponse.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); - var programDetails = await JsonSerializer.DeserializeAsync>(innerResponseStream, _jsonOptions, cancellationToken).ConfigureAwait(false); - var programDict = programDetails.ToDictionary(p => p.ProgramId, y => y); + var programDetails = await JsonSerializer.DeserializeAsync>(innerResponseStream, _jsonOptions, cancellationToken).ConfigureAwait(false); + var programDict = programDetails!.ToDictionary(p => p.ProgramId, y => y); var programIdsWithImages = programDetails .Where(p => p.HasImageArtwork).Select(p => p.ProgramId) @@ -138,6 +140,11 @@ namespace Emby.Server.Implementations.LiveTv.Listings // schedule.ProgramId + " which says it has images? " + // programDict[schedule.ProgramId].hasImageArtwork); + if (string.IsNullOrEmpty(schedule.ProgramId)) + { + continue; + } + if (images != null) { var imageIndex = images.FindIndex(i => i.ProgramId == schedule.ProgramId[..10]); @@ -145,7 +152,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings { var programEntry = programDict[schedule.ProgramId]; - var allImages = images[imageIndex].Data ?? new List(); + var allImages = images[imageIndex].Data; var imagesWithText = allImages.Where(i => string.Equals(i.Text, "yes", StringComparison.OrdinalIgnoreCase)); var imagesWithoutText = allImages.Where(i => string.Equals(i.Text, "no", StringComparison.OrdinalIgnoreCase)); @@ -213,7 +220,12 @@ namespace Emby.Server.Implementations.LiveTv.Listings private ProgramInfo GetProgram(string channelId, ProgramDto programInfo, ProgramDetailsDto details) { - var startAt = GetDate(programInfo.AirDateTime); + if (programInfo.AirDateTime == null) + { + return null; + } + + var startAt = programInfo.AirDateTime.Value; var endAt = startAt.AddSeconds(programInfo.Duration); var audioType = ProgramAudio.Stereo; @@ -351,9 +363,9 @@ namespace Emby.Server.Implementations.LiveTv.Listings } } - if (!string.IsNullOrWhiteSpace(details.OriginalAirDate)) + if (details.OriginalAirDate != null) { - info.OriginalAirDate = DateTime.Parse(details.OriginalAirDate, CultureInfo.InvariantCulture); + info.OriginalAirDate = details.OriginalAirDate; info.ProductionYear = info.OriginalAirDate.Value.Year; } @@ -380,18 +392,6 @@ namespace Emby.Server.Implementations.LiveTv.Listings return info; } - private static DateTime GetDate(string value) - { - var date = DateTime.ParseExact(value, "yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'", CultureInfo.InvariantCulture); - - if (date.Kind != DateTimeKind.Utc) - { - date = DateTime.SpecifyKind(date, DateTimeKind.Utc); - } - - return date; - } - private string GetProgramImage(string apiUrl, IEnumerable images, bool returnDefaultImage, double desiredAspect) { var match = images @@ -445,14 +445,14 @@ namespace Emby.Server.Implementations.LiveTv.Listings return result; } - private async Task> GetImageForPrograms( + private async Task> GetImageForPrograms( ListingsProviderInfo info, IReadOnlyList programIds, CancellationToken cancellationToken) { if (programIds.Count == 0) { - return new List(); + return Array.Empty(); } StringBuilder str = new StringBuilder("[", 1 + (programIds.Count * 13)); @@ -476,13 +476,13 @@ namespace Emby.Server.Implementations.LiveTv.Listings { 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>(response, _jsonOptions, cancellationToken).ConfigureAwait(false); + return await JsonSerializer.DeserializeAsync>(response, _jsonOptions, cancellationToken).ConfigureAwait(false); } catch (Exception ex) { _logger.LogError(ex, "Error getting image info from schedules direct"); - return new List(); + return Array.Empty(); } } @@ -505,7 +505,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings using var httpResponse = await Send(options, false, info, cancellationToken).ConfigureAwait(false); await using var response = await httpResponse.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); - var root = await JsonSerializer.DeserializeAsync>(response, _jsonOptions, cancellationToken).ConfigureAwait(false); + var root = await JsonSerializer.DeserializeAsync>(response, _jsonOptions, cancellationToken).ConfigureAwait(false); if (root != null) { @@ -647,7 +647,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings response.EnsureSuccessStatusCode(); await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); var root = await JsonSerializer.DeserializeAsync(stream, _jsonOptions, cancellationToken).ConfigureAwait(false); - if (string.Equals(root.Message, "OK", StringComparison.Ordinal)) + if (string.Equals(root?.Message, "OK", StringComparison.Ordinal)) { _logger.LogInformation("Authenticated with Schedules Direct token: {Token}", root.Token); return root.Token; @@ -704,12 +704,12 @@ namespace Emby.Server.Implementations.LiveTv.Listings using var response = httpResponse.Content; var root = await JsonSerializer.DeserializeAsync(stream, _jsonOptions, cancellationToken).ConfigureAwait(false); - return root.Lineups.Any(i => string.Equals(info.ListingsId, i.Lineup, StringComparison.OrdinalIgnoreCase)); + 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.HasValue && ex.StatusCode.Value == HttpStatusCode.BadRequest) + if (ex.StatusCode is HttpStatusCode.BadRequest) { return false; } @@ -775,10 +775,10 @@ namespace Emby.Server.Implementations.LiveTv.Listings using var httpResponse = await Send(options, true, info, cancellationToken).ConfigureAwait(false); await using var stream = await httpResponse.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); var root = await JsonSerializer.DeserializeAsync(stream, _jsonOptions, cancellationToken).ConfigureAwait(false); - _logger.LogInformation("Found {ChannelCount} channels on the lineup on ScheduleDirect", root.Map.Count); + _logger.LogInformation("Found {ChannelCount} channels on the lineup on ScheduleDirect", root!.Map.Count); _logger.LogInformation("Mapping Stations to Channel"); - var allStations = root.Stations ?? new List(); + var allStations = root.Stations; var map = root.Map; var list = new List(map.Count); diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ImageDataDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ImageDataDto.cs index 7e554ff1ce..a1ae3ca6d4 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ImageDataDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ImageDataDto.cs @@ -35,7 +35,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the aspect. /// [JsonPropertyName("aspect")] - public string? aspect { get; set; } + public string? Aspect { get; set; } /// /// Gets or sets the category. diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/LineupDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/LineupDto.cs index 676e745258..3dc64e5d8a 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/LineupDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/LineupDto.cs @@ -36,5 +36,11 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// [JsonPropertyName("uri")] public string? Uri { get; set; } + + /// + /// Gets or sets a value indicating whether this lineup was deleted. + /// + [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 index b0ee0ac8eb..a635c59870 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/LineupsDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/LineupsDto.cs @@ -25,7 +25,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the datetime. /// [JsonPropertyName("datetime")] - public string? Datetime { get; set; } + public DateTime? Datetime { get; set; } /// /// Gets or sets the list of lineups. diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MapDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MapDto.cs index cc1841c176..2420307b4f 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MapDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MapDto.cs @@ -19,6 +19,12 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos [JsonPropertyName("channel")] public string? Channel { get; set; } + /// + /// Gets or sets the provider callsign. + /// + [JsonPropertyName("providerCallsign")] + public string? ProvderCallsign { get; set; } + /// /// Gets or sets the logical channel number. /// @@ -42,5 +48,11 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// [JsonPropertyName("atscMinor")] public int AtscMinor { get; set; } + + /// + /// Gets or sets the match type. + /// + [JsonPropertyName("matchType")] + public string? MatchType { get;set; } } } diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MetadataProgramsDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MetadataProgramsDto.cs index 843ef9091d..43f2901566 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MetadataProgramsDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/MetadataProgramsDto.cs @@ -10,7 +10,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// /// Gets or sets the gracenote object. /// - [JsonPropertyName("gracenote")] + [JsonPropertyName("Gracenote")] public GracenoteDto? Gracenote { get; set; } } } diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ProgramDetailsDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ProgramDetailsDto.cs index bfaed1e081..84c48f67f3 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ProgramDetailsDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ProgramDetailsDto.cs @@ -43,7 +43,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the original air date. /// [JsonPropertyName("originalAirDate")] - public string? OriginalAirDate { get; set; } + public DateTime? OriginalAirDate { get; set; } /// /// Gets or sets the list of genres. diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ProgramDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ProgramDto.cs index ff039c1cf1..60389b45bf 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ProgramDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/ProgramDto.cs @@ -19,7 +19,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// Gets or sets the air date time. /// [JsonPropertyName("airDateTime")] - public string? AirDateTime { get; set; } + public DateTime? AirDateTime { get; set; } /// /// Gets or sets the duration. diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/TokenDto.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/TokenDto.cs index fb5ed95ac9..561f79c5af 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/TokenDto.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirectDtos/TokenDto.cs @@ -37,5 +37,11 @@ namespace Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos /// [JsonPropertyName("datetime")] public DateTime? DateTime { get; set; } + + /// + /// Gets or sets the response message. + /// + [JsonPropertyName("response")] + public string? Response { get; set; } } } diff --git a/tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj b/tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj index 9b6ab7bdf5..e02e357ca0 100644 --- a/tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj +++ b/tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj @@ -16,6 +16,9 @@ PreserveNewest + + PreserveNewest + diff --git a/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/SchedulesDirectDeserializeTests.cs b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/SchedulesDirectDeserializeTests.cs new file mode 100644 index 0000000000..84ac3ea477 --- /dev/null +++ b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/SchedulesDirectDeserializeTests.cs @@ -0,0 +1,245 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text.Json; +using Emby.Server.Implementations.LiveTv.Listings.SchedulesDirectDtos; +using Jellyfin.Extensions.Json; +using Xunit; + +namespace Jellyfin.Server.Implementations.Tests.LiveTv.SchedulesDirect +{ + public class SchedulesDirectDeserializeTests + { + private readonly JsonSerializerOptions _jsonOptions; + + public SchedulesDirectDeserializeTests() + { + _jsonOptions = JsonDefaults.Options; + } + + /// + /// /token reponse. + /// + [Fact] + public void Deserialize_Token_Response_Live_Success() + { + var bytes = File.ReadAllBytes("LiveTv/SchedulesDirect/TestData/token_live_response.json"); + var tokenDto = JsonSerializer.Deserialize(bytes); + + Assert.NotNull(tokenDto); + Assert.Equal(0, tokenDto!.Code); + Assert.Equal("OK", tokenDto.Message); + Assert.Equal("AWS-SD-web.1", tokenDto.ServerId); + Assert.Equal(new DateTime(2016, 08, 23, 13, 55, 25, DateTimeKind.Utc), tokenDto.DateTime); + Assert.Equal("f3fca79989cafe7dead71beefedc812b", tokenDto.Token); + } + + /// + /// /token response. + /// + [Fact] + public void Deserialize_Token_Response_Offline_Success() + { + var bytes = File.ReadAllBytes("LiveTv/SchedulesDirect/TestData/token_offline_response.json"); + var tokenDto = JsonSerializer.Deserialize(bytes); + + Assert.NotNull(tokenDto); + Assert.Equal(3_000, tokenDto!.Code); + Assert.Equal("Server offline for maintenance.", tokenDto.Message); + Assert.Equal("20141201.web.1", tokenDto.ServerId); + Assert.Equal(new DateTime(2015, 04, 23, 00, 03, 32, DateTimeKind.Utc), tokenDto.DateTime); + Assert.Equal("CAFEDEADBEEFCAFEDEADBEEFCAFEDEADBEEFCAFE", tokenDto.Token); + Assert.Equal("SERVICE_OFFLINE", tokenDto.Response); + } + + /// + /// /schedules request. + /// + [Fact] + public void Serialize_Schedule_Request_Success() + { + var expectedString = File.ReadAllText("LiveTv/SchedulesDirect/TestData/schedules_request.json").Trim(); + + var requestObject = new RequestScheduleForChannelDto[] + { + new RequestScheduleForChannelDto + { + StationId = "20454", + Date = new[] + { + "2015-03-13", + "2015-03-17" + } + }, + new RequestScheduleForChannelDto + { + StationId = "10021", + Date = new[] + { + "2015-03-12", + "2015-03-13" + } + } + }; + + var jsonOptions = new JsonSerializerOptions(_jsonOptions) + { + WriteIndented = true + }; + + var requestString = JsonSerializer.Serialize(requestObject, jsonOptions); + Assert.Equal(expectedString, requestString); + } + + /// + /// /schedules response. + /// + [Fact] + public void Deserialize_Schedule_Response_Success() + { + var bytes = File.ReadAllBytes("LiveTv/SchedulesDirect/TestData/schedules_response.json"); + var days = JsonSerializer.Deserialize>(bytes); + + Assert.NotNull(days); + Assert.Equal(1, days!.Count); + + var dayDto = days[0]; + Assert.Equal("20454", dayDto.StationId); + Assert.Equal(2, dayDto.Programs.Count); + + Assert.Equal("SH005371070000", dayDto.Programs[0].ProgramId); + Assert.Equal(new DateTime(2015, 03, 03, 00, 00, 00, DateTimeKind.Utc), dayDto.Programs[0].AirDateTime); + Assert.Equal(1_800, dayDto.Programs[0].Duration); + Assert.Equal("Sy8HEMBPcuiAx3FBukUhKQ", dayDto.Programs[0].Md5); + Assert.True(dayDto.Programs[0].New); + Assert.Equal(2, dayDto.Programs[0].AudioProperties.Count); + Assert.Equal("stereo", dayDto.Programs[0].AudioProperties[0]); + Assert.Equal("cc", dayDto.Programs[0].AudioProperties[1]); + Assert.Equal(1, dayDto.Programs[0].VideoProperties.Count); + Assert.Equal("hdtv", dayDto.Programs[0].VideoProperties[0]); + } + + /// + /// /programs response. + /// + [Fact] + public void Deserialize_Program_Response_Success() + { + var bytes = File.ReadAllBytes("LiveTv/SchedulesDirect/TestData/programs_response.json"); + var programDtos = JsonSerializer.Deserialize>(bytes); + + Assert.NotNull(programDtos); + Assert.Equal(2, programDtos!.Count); + Assert.Equal("EP000000060003", programDtos[0].ProgramId); + Assert.Equal(1, programDtos[0].Titles.Count); + Assert.Equal("'Allo 'Allo!", programDtos[0].Titles[0].Title120); + Assert.Equal("Series", programDtos[0].EventDetails?.SubType); + Assert.Equal("en", programDtos[0].Descriptions?.Description1000[0].DescriptionLanguage); + Assert.Equal("A disguised British Intelligence officer is sent to help the airmen.", programDtos[0].Descriptions?.Description1000[0].Description); + Assert.Equal(new DateTime(1985, 11, 04), programDtos[0].OriginalAirDate); + Assert.Equal(1, programDtos[0].Genres.Count); + Assert.Equal("Sitcom", programDtos[0].Genres[0]); + Assert.Equal("The Poloceman Cometh", programDtos[0].EpisodeTitle150); + Assert.Equal(2, programDtos[0].Metadata[0].Gracenote?.Season); + Assert.Equal(3, programDtos[0].Metadata[0].Gracenote?.Episode); + Assert.Equal(13, programDtos[0].Cast.Count); + Assert.Equal("383774", programDtos[0].Cast[0].PersonId); + Assert.Equal("392649", programDtos[0].Cast[0].NameId); + Assert.Equal("Gorden Kaye", programDtos[0].Cast[0].Name); + Assert.Equal("Actor", programDtos[0].Cast[0].Role); + Assert.Equal("01", programDtos[0].Cast[0].BillingOrder); + Assert.Equal(3, programDtos[0].Crew.Count); + Assert.Equal("354407", programDtos[0].Crew[0].PersonId); + Assert.Equal("363281", programDtos[0].Crew[0].NameId); + Assert.Equal("David Croft", programDtos[0].Crew[0].Name); + Assert.Equal("Director", programDtos[0].Crew[0].Role); + Assert.Equal("01", programDtos[0].Crew[0].BillingOrder); + } + + /// + /// /metadata/programs response. + /// + [Fact] + public void Deserialize_Metadata_Programs_Response_Success() + { + var bytes = File.ReadAllBytes("LiveTv/SchedulesDirect/TestData/metadata_programs_response.json"); + var showImagesDtos = JsonSerializer.Deserialize>(bytes); + + Assert.NotNull(showImagesDtos); + Assert.Equal(1, showImagesDtos!.Count); + Assert.Equal("SH00712240", showImagesDtos[0].ProgramId); + Assert.Equal(4, showImagesDtos[0].Data.Count); + Assert.Equal("135", showImagesDtos[0].Data[0].Width); + Assert.Equal("180", showImagesDtos[0].Data[0].Height); + Assert.Equal("assets/p282288_b_v2_aa.jpg", showImagesDtos[0].Data[0].Uri); + Assert.Equal("Sm", showImagesDtos[0].Data[0].Size); + Assert.Equal("3x4", showImagesDtos[0].Data[0].Aspect); + Assert.Equal("Banner-L3", showImagesDtos[0].Data[0].Category); + Assert.Equal("yes", showImagesDtos[0].Data[0].Text); + Assert.Equal("true", showImagesDtos[0].Data[0].Primary); + Assert.Equal("Series", showImagesDtos[0].Data[0].Tier); + } + + /// + /// /headends response. + /// + [Fact] + public void Deserialize_Headends_Response_Success() + { + var bytes = File.ReadAllBytes("LiveTv/SchedulesDirect/TestData/headends_response.json"); + var headendsDtos = JsonSerializer.Deserialize>(bytes); + + Assert.NotNull(headendsDtos); + Assert.Equal(8, headendsDtos!.Count); + Assert.Equal("CA00053", headendsDtos[0].Headend); + Assert.Equal("Cable", headendsDtos[0].Transport); + Assert.Equal("Beverly Hills", headendsDtos[0].Location); + Assert.Equal(2, headendsDtos[0].Lineups.Count); + Assert.Equal("Time Warner Cable - Cable", headendsDtos[0].Lineups[0].Name); + Assert.Equal("USA-CA00053-DEFAULT", headendsDtos[0].Lineups[0].Lineup); + Assert.Equal("/20141201/lineups/USA-CA00053-DEFAULT", headendsDtos[0].Lineups[0].Uri); + } + + /// + /// /lineups response. + /// + [Fact] + public void Deserialize_Lineups_Response_Success() + { + var bytes = File.ReadAllBytes("LiveTv/SchedulesDirect/TestData/lineups_response.json"); + var lineupsDto = JsonSerializer.Deserialize(bytes); + + Assert.NotNull(lineupsDto); + Assert.Equal(0, lineupsDto!.Code); + Assert.Equal("20141201.web.1", lineupsDto.ServerId); + Assert.Equal(new DateTime(2015, 04, 17, 14, 22, 17, DateTimeKind.Utc), lineupsDto.Datetime); + Assert.Equal(5, lineupsDto.Lineups.Count); + Assert.Equal("GBR-0001317-DEFAULT", lineupsDto.Lineups[0].Lineup); + Assert.Equal("Freeview - Carlton - LWT (Southeast)", lineupsDto.Lineups[0].Name); + Assert.Equal("DVB-T", lineupsDto.Lineups[0].Transport); + Assert.Equal("London", lineupsDto.Lineups[0].Location); + Assert.Equal("/20141201/lineups/GBR-0001317-DEFAULT", lineupsDto.Lineups[0].Uri); + + Assert.Equal("DELETED LINEUP", lineupsDto.Lineups[4].Name); + Assert.True(lineupsDto.Lineups[4].IsDeleted); + } + + /// + /// /lineup/:id response. + /// + [Fact] + public void Deserialize_Lineup_Response_Success() + { + var bytes = File.ReadAllBytes("LiveTv/SchedulesDirect/TestData/lineup_response.json"); + var channelDto = JsonSerializer.Deserialize(bytes); + + Assert.NotNull(channelDto); + Assert.Equal(2, channelDto!.Map.Count); + Assert.Equal("24326", channelDto.Map[0].StationId); + Assert.Equal("001", channelDto.Map[0].Channel); + Assert.Equal("BBC ONE South", channelDto.Map[0].ProvderCallsign); + Assert.Equal("1", channelDto.Map[0].LogicalChannelNumber); + Assert.Equal("providerCallsign", channelDto.Map[0].MatchType); + } + } +} diff --git a/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/headends_response.json b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/headends_response.json new file mode 100644 index 0000000000..a1a96cf87a --- /dev/null +++ b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/headends_response.json @@ -0,0 +1,113 @@ +[ + { + "headend": "CA00053", + "transport": "Cable", + "location": "Beverly Hills", + "lineups": [ + { + "name": "Time Warner Cable - Cable", + "lineup": "USA-CA00053-DEFAULT", + "uri": "/20141201/lineups/USA-CA00053-DEFAULT" + }, + { + "name": "Time Warner Cable - Digital", + "lineup": "USA-CA00053-X", + "uri": "/20141201/lineups/USA-CA00053-X" + } + ] + }, + { + "headend": "CA61222", + "transport": "Cable", + "location": "Beverly Hills", + "lineups": [ + { + "name": "Mulholland Estates - Cable", + "lineup": "USA-CA61222-DEFAULT", + "uri": "/20141201/lineups/USA-CA61222-DEFAULT" + } + ] + }, + { + "headend": "CA66511", + "transport": "Cable", + "location": "Los Angeles", + "lineups": [ + { + "name": "AT&T U-verse TV - Digital", + "lineup": "USA-CA66511-X", + "uri": "/20141201/lineups/USA-CA66511-X" + } + ] + }, + { + "headend": "CA67309", + "transport": "Cable", + "location": "Westchester", + "lineups": [ + { + "name": "Time Warner Cable Sherman Oaks - Cable", + "lineup": "USA-CA67309-DEFAULT", + "uri": "/20141201/lineups/USA-CA67309-DEFAULT" + }, + { + "name": "Time Warner Cable Sherman Oaks - Digital", + "lineup": "USA-CA67309-X", + "uri": "/20141201/lineups/USA-CA67309-X" + } + ] + }, + { + "headend": "CA67310", + "transport": "Cable", + "location": "Eagle Rock", + "lineups": [ + { + "name": "Time Warner Cable City of Los Angeles - Cable", + "lineup": "USA-CA67310-DEFAULT", + "uri": "/20141201/lineups/USA-CA67310-DEFAULT" + }, + { + "name": "Time Warner Cable City of Los Angeles - Digital", + "lineup": "USA-CA67310-X", + "uri": "/20141201/lineups/USA-CA67310-X" + } + ] + }, + { + "headend": "DISH803", + "transport": "Satellite", + "location": "Los Angeles", + "lineups": [ + { + "name": "DISH Los Angeles - Satellite", + "lineup": "USA-DISH803-DEFAULT", + "uri": "/20141201/lineups/USA-DISH803-DEFAULT" + } + ] + }, + { + "headend": "DITV803", + "transport": "Satellite", + "location": "Los Angeles", + "lineups": [ + { + "name": "DIRECTV Los Angeles - Satellite", + "lineup": "USA-DITV803-DEFAULT", + "uri": "/20141201/lineups/USA-DITV803-DEFAULT" + } + ] + }, + { + "headend": "90210", + "transport": "Antenna", + "location": "90210", + "lineups": [ + { + "name": "Antenna", + "lineup": "USA-OTA-90210", + "uri": "/20141201/lineups/USA-OTA-90210" + } + ] + } +] diff --git a/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/lineup_response.json b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/lineup_response.json new file mode 100644 index 0000000000..5c5e36e301 --- /dev/null +++ b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/lineup_response.json @@ -0,0 +1,18 @@ +{ + "map": [ + { + "stationID": "24326", + "channel": "001", + "providerCallsign": "BBC ONE South", + "logicalChannelNumber": "1", + "matchType": "providerCallsign" + }, + { + "stationID": "17154", + "channel": "002", + "providerCallsign": "BBC TWO", + "logicalChannelNumber": "2", + "matchType": "providerCallsign" + } + ] +} diff --git a/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/lineups_response.json b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/lineups_response.json new file mode 100644 index 0000000000..257b682eef --- /dev/null +++ b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/lineups_response.json @@ -0,0 +1,40 @@ +{ + "code": 0, + "serverID": "20141201.web.1", + "datetime": "2015-04-17T14:22:17Z", + "lineups": [ + { + "lineup": "GBR-0001317-DEFAULT", + "name": "Freeview - Carlton - LWT (Southeast)", + "transport": "DVB-T", + "location": "London", + "uri": "/20141201/lineups/GBR-0001317-DEFAULT" + }, + { + "lineup": "USA-IL57303-X", + "name": "Comcast Waukegan/Lake Forest Area - Digital", + "transport": "Cable", + "location": "Lake Forest", + "uri": "/20141201/lineups/USA-IL57303-X" + }, + { + "lineup": "USA-NY67791-X", + "name": "Verizon Fios Queens - Digital", + "transport": "Cable", + "location": "Fresh Meadows", + "uri": "/20141201/lineups/USA-NY67791-X" + }, + { + "lineup": "USA-OTA-60030", + "name": "Local Over the Air Broadcast", + "transport": "Antenna", + "location": "60030", + "uri": "/20141201/lineups/USA-OTA-60030" + }, + { + "lineup": "USA-WI61859-DEFAULT", + "name": "DELETED LINEUP", + "isDeleted": true + } + ] +} diff --git a/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/metadata_programs_response.json b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/metadata_programs_response.json new file mode 100644 index 0000000000..b75e777b48 --- /dev/null +++ b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/metadata_programs_response.json @@ -0,0 +1,51 @@ +[ + { + "programID": "SH00712240", + "data": [ + { + "width": "135", + "height": "180", + "uri": "assets/p282288_b_v2_aa.jpg", + "size": "Sm", + "aspect": "3x4", + "category": "Banner-L3", + "text": "yes", + "primary": "true", + "tier": "Series" + }, + { + "width": "720", + "height": "540", + "uri": "assets/p282288_b_h6_aa.jpg", + "size": "Lg", + "aspect": "4x3", + "category": "Banner-L3", + "text": "yes", + "primary": "true", + "tier": "Series" + }, + { + "width": "960", + "height": "1440", + "uri": "assets/p282288_b_v8_aa.jpg", + "size": "Ms", + "aspect": "2x3", + "category": "Banner-L3", + "text": "yes", + "primary": "true", + "tier": "Series" + }, + { + "width": "180", + "height": "135", + "uri": "assets/p282288_b_h5_aa.jpg", + "size": "Sm", + "aspect": "4x3", + "category": "Banner-L3", + "text": "yes", + "primary": "true", + "tier": "Series" + } + ] + } +] diff --git a/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/programs_response.json b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/programs_response.json new file mode 100644 index 0000000000..154c02f973 --- /dev/null +++ b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/programs_response.json @@ -0,0 +1,245 @@ +[ + { + "programID": "EP000000060003", + "titles": [{ + "title120": "'Allo 'Allo!" + }], + "eventDetails": { + "subType": "Series" + }, + "descriptions": { + "description1000": [{ + "descriptionLanguage": "en", + "description": "A disguised British Intelligence officer is sent to help the airmen." + }] + }, + "originalAirDate": "1985-11-04", + "genres": ["Sitcom"], + "episodeTitle150": "The Poloceman Cometh", + "metadata": [{ + "Gracenote": { + "season": 2, + "episode": 3 + } + }], + "cast": [{ + "personId": "383774", + "nameId": "392649", + "name": "Gorden Kaye", + "role": "Actor", + "billingOrder": "01" + }, { + "personId": "246840", + "nameId": "250387", + "name": "Carmen Silvera", + "role": "Actor", + "billingOrder": "02" + }, { + "personId": "376955", + "nameId": "385830", + "name": "Rose Hill", + "role": "Actor", + "billingOrder": "03" + }, { + "personId": "259773", + "nameId": "263340", + "name": "Vicki Michelle", + "role": "Actor", + "billingOrder": "04" + }, { + "personId": "353113", + "nameId": "361987", + "name": "Kirsten Cooke", + "role": "Actor", + "billingOrder": "05" + }, { + "personId": "77787", + "nameId": "77787", + "name": "Richard Marner", + "role": "Actor", + "billingOrder": "06" + }, { + "personId": "230921", + "nameId": "234193", + "name": "Guy Siner", + "role": "Actor", + "billingOrder": "07" + }, { + "personId": "374934", + "nameId": "383809", + "name": "Kim Hartman", + "role": "Actor", + "billingOrder": "08" + }, { + "personId": "369151", + "nameId": "378026", + "name": "Richard Gibson", + "role": "Actor", + "billingOrder": "09" + }, { + "personId": "343690", + "nameId": "352564", + "name": "Arthur Bostrom", + "role": "Actor", + "billingOrder": "10" + }, { + "personId": "352557", + "nameId": "361431", + "name": "John D. Collins", + "role": "Actor", + "billingOrder": "11" + }, { + "personId": "605275", + "nameId": "627734", + "name": "Nicholas Frankau", + "role": "Actor", + "billingOrder": "12" + }, { + "personId": "373394", + "nameId": "382269", + "name": "Jack Haig", + "role": "Actor", + "billingOrder": "13" + }], + "crew": [{ + "personId": "354407", + "nameId": "363281", + "name": "David Croft", + "role": "Director", + "billingOrder": "01" + }, { + "personId": "354407", + "nameId": "363281", + "name": "David Croft", + "role": "Writer", + "billingOrder": "02" + }, { + "personId": "105145", + "nameId": "105145", + "name": "Jeremy Lloyd", + "role": "Writer", + "billingOrder": "03" + }], + "showType": "Series", + "hasImageArtwork": true, + "md5": "Jo5NKxoo44xRvBCAq8QT2A" + }, + { + "programID": "EP000000510142", + "titles": [{ + "title120": "A Different World" + }], + "eventDetails": { + "subType": "Series" + }, + "descriptions": { + "description1000": [{ + "descriptionLanguage": "en", + "description": "Whitley and Dwayne tell new students about their honeymoon in Los Angeles." + }] + }, + "originalAirDate": "1992-09-24", + "genres": ["Sitcom"], + "episodeTitle150": "Honeymoon in L.A.", + "metadata": [{ + "Gracenote": { + "season": 6, + "episode": 1 + } + }], + "cast": [{ + "personId": "700", + "nameId": "700", + "name": "Jasmine Guy", + "role": "Actor", + "billingOrder": "01" + }, { + "personId": "729", + "nameId": "729", + "name": "Kadeem Hardison", + "role": "Actor", + "billingOrder": "02" + }, { + "personId": "120", + "nameId": "120", + "name": "Darryl M. Bell", + "role": "Actor", + "billingOrder": "03" + }, { + "personId": "1729", + "nameId": "1729", + "name": "Cree Summer", + "role": "Actor", + "billingOrder": "04" + }, { + "personId": "217", + "nameId": "217", + "name": "Charnele Brown", + "role": "Actor", + "billingOrder": "05" + }, { + "personId": "1811", + "nameId": "1811", + "name": "Glynn Turman", + "role": "Actor", + "billingOrder": "06" + }, { + "personId": "1232", + "nameId": "1232", + "name": "Lou Myers", + "role": "Actor", + "billingOrder": "07" + }, { + "personId": "1363", + "nameId": "1363", + "name": "Jada Pinkett", + "role": "Guest Star", + "billingOrder": "08" + }, { + "personId": "222967", + "nameId": "225536", + "name": "Ajai Sanders", + "role": "Guest Star", + "billingOrder": "09" + }, { + "personId": "181744", + "nameId": "183292", + "name": "Karen Malina White", + "role": "Guest Star", + "billingOrder": "10" + }, { + "personId": "305017", + "nameId": "318897", + "name": "Patrick Y. Malone", + "role": "Guest Star", + "billingOrder": "11" + }, { + "personId": "9841", + "nameId": "9841", + "name": "Bumper Robinson", + "role": "Guest Star", + "billingOrder": "12" + }, { + "personId": "426422", + "nameId": "435297", + "name": "Sister Souljah", + "role": "Guest Star", + "billingOrder": "13" + }, { + "personId": "25", + "nameId": "25", + "name": "Debbie Allen", + "role": "Guest Star", + "billingOrder": "14" + }, { + "personId": "668", + "nameId": "668", + "name": "Gilbert Gottfried", + "role": "Guest Star", + "billingOrder": "15" + }], + "showType": "Series", + "hasImageArtwork": true, + "md5": "P5kz0QmCeYxIA+yL0H4DWw" + } +] diff --git a/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/schedules_request.json b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/schedules_request.json new file mode 100644 index 0000000000..72248921ae --- /dev/null +++ b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/schedules_request.json @@ -0,0 +1,16 @@ +[ + { + "stationID": "20454", + "date": [ + "2015-03-13", + "2015-03-17" + ] + }, + { + "stationID": "10021", + "date": [ + "2015-03-12", + "2015-03-13" + ] + } +] diff --git a/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/schedules_response.json b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/schedules_response.json new file mode 100644 index 0000000000..f474f3aff2 --- /dev/null +++ b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/schedules_response.json @@ -0,0 +1,35 @@ +[ + { + "stationID": "20454", + "programs": [ + { + "programID": "SH005371070000", + "airDateTime": "2015-03-03T00:00:00Z", + "duration": 1800, + "md5": "Sy8HEMBPcuiAx3FBukUhKQ", + "new": true, + "audioProperties": [ + "stereo", + "cc" + ], + "videoProperties": [ + "hdtv" + ] + }, + { + "programID": "EP000014577244", + "airDateTime": "2015-03-03T00:30:00Z", + "duration": 1800, + "md5": "25DNXVXO192JI7Y9vSW9lQ", + "new": true, + "audioProperties": [ + "stereo", + "cc" + ], + "videoProperties": [ + "hdtv" + ] + } + ] + } +] diff --git a/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/token_live_response.json b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/token_live_response.json new file mode 100644 index 0000000000..73b0a54c4e --- /dev/null +++ b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/token_live_response.json @@ -0,0 +1,7 @@ +{ + "code": 0, + "message": "OK", + "serverID": "AWS-SD-web.1", + "datetime": "2016-08-23T13:55:25Z", + "token": "f3fca79989cafe7dead71beefedc812b" +} diff --git a/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/token_offline_response.json b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/token_offline_response.json new file mode 100644 index 0000000000..b630c24041 --- /dev/null +++ b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/SchedulesDirect/TestData/token_offline_response.json @@ -0,0 +1,8 @@ +{ + "response": "SERVICE_OFFLINE", + "code": 3000, + "serverID": "20141201.web.1", + "message": "Server offline for maintenance.", + "datetime": "2015-04-23T00:03:32Z", + "token": "CAFEDEADBEEFCAFEDEADBEEFCAFEDEADBEEFCAFE" +}