// Kyoo - A portable and vast media library solution. // Copyright (c) Kyoo. // // See AUTHORS.md and LICENSE file in the project root for full license information. // // Kyoo is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // any later version. // // Kyoo is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Kyoo. If not, see . using System; using System.Collections.Generic; using System.Text.RegularExpressions; using JetBrains.Annotations; using Kyoo.Abstractions.Controllers; using Kyoo.Abstractions.Models.Attributes; namespace Kyoo.Abstractions.Models { /// /// A class to represent a single show's episode. /// public class Episode : IResource, IMetadata, IThumbnails { /// public int ID { get; set; } /// [Computed] public string Slug { get { if (ShowSlug != null || Show != null) return GetSlug(ShowSlug ?? Show.Slug, SeasonNumber, EpisodeNumber, AbsoluteNumber); return ShowID != 0 ? GetSlug(ShowID.ToString(), SeasonNumber, EpisodeNumber, AbsoluteNumber) : null; } [UsedImplicitly] [NotNull] private set { if (value == null) throw new ArgumentNullException(nameof(value)); Match match = Regex.Match(value, @"(?.+)-s(?\d+)e(?\d+)"); if (match.Success) { ShowSlug = match.Groups["show"].Value; SeasonNumber = int.Parse(match.Groups["season"].Value); EpisodeNumber = int.Parse(match.Groups["episode"].Value); } else { match = Regex.Match(value, @"(?.+)-(?\d+)"); if (match.Success) { ShowSlug = match.Groups["show"].Value; AbsoluteNumber = int.Parse(match.Groups["absolute"].Value); } else ShowSlug = value; SeasonNumber = null; EpisodeNumber = null; } } } /// /// The slug of the Show that contain this episode. If this is not set, this episode is ill-formed. /// [SerializeIgnore] public string ShowSlug { private get; set; } /// /// The ID of the Show containing this episode. /// [SerializeIgnore] public int ShowID { get; set; } /// /// The show that contains this episode. This must be explicitly loaded via a call to . /// [LoadableRelation(nameof(ShowID))] public Show Show { get; set; } /// /// The ID of the Season containing this episode. /// [SerializeIgnore] public int? SeasonID { get; set; } /// /// The season that contains this episode. /// This must be explicitly loaded via a call to . /// /// /// This can be null if the season is unknown and the episode is only identified /// by it's . /// [LoadableRelation(nameof(SeasonID))] public Season Season { get; set; } /// /// The season in witch this episode is in. /// public int? SeasonNumber { get; set; } /// /// The number of this episode in it's season. /// public int? EpisodeNumber { get; set; } /// /// The absolute number of this episode. It's an episode number that is not reset to 1 after a new season. /// public int? AbsoluteNumber { get; set; } /// /// The path of the video file for this episode. Any format supported by a is allowed. /// [SerializeIgnore] public string Path { get; set; } /// public Dictionary Images { get; set; } /// /// The path of this episode's thumbnail. /// By default, the http path for the thumbnail is returned from the public API. /// This can be disabled using the internal query flag. /// [SerializeAs("{HOST}/api/episodes/{Slug}/thumbnail")] [Obsolete("Use Images instead of this, this is only kept for the API response.")] public string Thumb => Images?.GetValueOrDefault(Models.Images.Thumbnail); /// /// The title of this episode. /// public string Title { get; set; } /// /// The overview of this episode. /// public string Overview { get; set; } /// /// The release date of this episode. It can be null if unknown. /// public DateTime? ReleaseDate { get; set; } /// [EditableRelation] [LoadableRelation] public ICollection ExternalIDs { get; set; } /// /// The list of tracks this episode has. This lists video, audio and subtitles available. /// [EditableRelation] [LoadableRelation] public ICollection Tracks { get; set; } /// /// Get the slug of an episode. /// /// The slug of the show. It can't be null. /// /// The season in which the episode is. /// If this is a movie or if the episode should be referred by it's absolute number, set this to null. /// /// /// The number of the episode in it's season. /// If this is a movie or if the episode should be referred by it's absolute number, set this to null. /// /// /// The absolute number of this show. /// If you don't know it or this is a movie, use null /// /// The slug corresponding to the given arguments /// The given show slug was null. public static string GetSlug([NotNull] string showSlug, int? seasonNumber, int? episodeNumber, int? absoluteNumber = null) { if (showSlug == null) throw new ArgumentNullException(nameof(showSlug)); return seasonNumber switch { null when absoluteNumber == null => showSlug, null => $"{showSlug}-{absoluteNumber}", _ => $"{showSlug}-s{seasonNumber}e{episodeNumber}" }; } } }