| | | 1 | | #nullable disable |
| | | 2 | | |
| | | 3 | | #pragma warning disable CS1591 |
| | | 4 | | |
| | | 5 | | using System; |
| | | 6 | | using System.Collections.Generic; |
| | | 7 | | using System.Globalization; |
| | | 8 | | using System.Linq; |
| | | 9 | | using System.Text.Json.Serialization; |
| | | 10 | | using System.Threading; |
| | | 11 | | using Jellyfin.Data.Enums; |
| | | 12 | | using Jellyfin.Database.Implementations.Entities; |
| | | 13 | | using Jellyfin.Extensions; |
| | | 14 | | using MediaBrowser.Common; |
| | | 15 | | using MediaBrowser.Controller.Dto; |
| | | 16 | | using MediaBrowser.Controller.Providers; |
| | | 17 | | using MediaBrowser.Model.Querying; |
| | | 18 | | |
| | | 19 | | namespace MediaBrowser.Controller.Entities.TV |
| | | 20 | | { |
| | | 21 | | /// <summary> |
| | | 22 | | /// Class Season. |
| | | 23 | | /// </summary> |
| | | 24 | | [RequiresSourceSerialisation] |
| | | 25 | | public class Season : Folder, IHasSeries, IHasLookupInfo<SeasonInfo> |
| | | 26 | | { |
| | | 27 | | [JsonIgnore] |
| | 0 | 28 | | public override bool SupportsAddingToPlaylist => true; |
| | | 29 | | |
| | | 30 | | [JsonIgnore] |
| | 0 | 31 | | public override bool IsPreSorted => true; |
| | | 32 | | |
| | | 33 | | [JsonIgnore] |
| | 0 | 34 | | public override bool SupportsDateLastMediaAdded => false; |
| | | 35 | | |
| | | 36 | | [JsonIgnore] |
| | 0 | 37 | | public override bool SupportsPeople => true; |
| | | 38 | | |
| | | 39 | | [JsonIgnore] |
| | 0 | 40 | | public override bool SupportsInheritedParentImages => true; |
| | | 41 | | |
| | | 42 | | [JsonIgnore] |
| | 0 | 43 | | public override Guid DisplayParentId => SeriesId; |
| | | 44 | | |
| | | 45 | | /// <summary> |
| | | 46 | | /// Gets this Episode's Series Instance. |
| | | 47 | | /// </summary> |
| | | 48 | | /// <value>The series.</value> |
| | | 49 | | [JsonIgnore] |
| | | 50 | | public Series Series |
| | | 51 | | { |
| | | 52 | | get |
| | | 53 | | { |
| | 0 | 54 | | var seriesId = SeriesId; |
| | 0 | 55 | | if (seriesId.IsEmpty()) |
| | | 56 | | { |
| | 0 | 57 | | seriesId = FindSeriesId(); |
| | | 58 | | } |
| | | 59 | | |
| | 0 | 60 | | return seriesId.IsEmpty() ? null : (LibraryManager.GetItemById(seriesId) as Series); |
| | | 61 | | } |
| | | 62 | | } |
| | | 63 | | |
| | | 64 | | [JsonIgnore] |
| | | 65 | | public string SeriesPath |
| | | 66 | | { |
| | | 67 | | get |
| | | 68 | | { |
| | 0 | 69 | | var series = Series; |
| | | 70 | | |
| | 0 | 71 | | if (series is not null) |
| | | 72 | | { |
| | 0 | 73 | | return series.Path; |
| | | 74 | | } |
| | | 75 | | |
| | 0 | 76 | | return System.IO.Path.GetDirectoryName(Path); |
| | | 77 | | } |
| | | 78 | | } |
| | | 79 | | |
| | | 80 | | [JsonIgnore] |
| | | 81 | | public string SeriesPresentationUniqueKey { get; set; } |
| | | 82 | | |
| | | 83 | | [JsonIgnore] |
| | | 84 | | public string SeriesName { get; set; } |
| | | 85 | | |
| | | 86 | | [JsonIgnore] |
| | | 87 | | public Guid SeriesId { get; set; } |
| | | 88 | | |
| | | 89 | | public override double GetDefaultPrimaryImageAspectRatio() |
| | | 90 | | { |
| | 0 | 91 | | double value = 2; |
| | 0 | 92 | | value /= 3; |
| | | 93 | | |
| | 0 | 94 | | return value; |
| | | 95 | | } |
| | | 96 | | |
| | | 97 | | public string FindSeriesSortName() |
| | | 98 | | { |
| | 0 | 99 | | var series = Series; |
| | 0 | 100 | | return series is null ? SeriesName : series.SortName; |
| | | 101 | | } |
| | | 102 | | |
| | | 103 | | public override List<string> GetUserDataKeys() |
| | | 104 | | { |
| | 0 | 105 | | var list = base.GetUserDataKeys(); |
| | | 106 | | |
| | 0 | 107 | | var series = Series; |
| | 0 | 108 | | if (series is not null) |
| | | 109 | | { |
| | 0 | 110 | | var newList = series.GetUserDataKeys(); |
| | 0 | 111 | | var suffix = (IndexNumber ?? 0).ToString("000", CultureInfo.InvariantCulture); |
| | 0 | 112 | | for (int i = 0; i < newList.Count; i++) |
| | | 113 | | { |
| | 0 | 114 | | newList[i] = newList[i] + suffix; |
| | | 115 | | } |
| | | 116 | | |
| | 0 | 117 | | newList.AddRange(list); |
| | 0 | 118 | | list = newList; |
| | | 119 | | } |
| | | 120 | | |
| | 0 | 121 | | return list; |
| | | 122 | | } |
| | | 123 | | |
| | | 124 | | public override int GetChildCount(User user) |
| | | 125 | | { |
| | 0 | 126 | | var result = GetChildren(user, true, null).Count; |
| | | 127 | | |
| | 0 | 128 | | return result; |
| | | 129 | | } |
| | | 130 | | |
| | | 131 | | public override string CreatePresentationUniqueKey() |
| | | 132 | | { |
| | 0 | 133 | | if (IndexNumber.HasValue) |
| | | 134 | | { |
| | 0 | 135 | | var series = Series; |
| | 0 | 136 | | if (series is not null) |
| | | 137 | | { |
| | 0 | 138 | | return series.PresentationUniqueKey + "-" + IndexNumber.Value.ToString("000", CultureInfo.InvariantC |
| | | 139 | | } |
| | | 140 | | } |
| | | 141 | | |
| | 0 | 142 | | return base.CreatePresentationUniqueKey(); |
| | | 143 | | } |
| | | 144 | | |
| | | 145 | | /// <summary> |
| | | 146 | | /// Creates the name of the sort. |
| | | 147 | | /// </summary> |
| | | 148 | | /// <returns>System.String.</returns> |
| | | 149 | | protected override string CreateSortName() |
| | | 150 | | { |
| | 0 | 151 | | return IndexNumber is not null ? IndexNumber.Value.ToString("0000", CultureInfo.InvariantCulture) : Name; |
| | | 152 | | } |
| | | 153 | | |
| | | 154 | | protected override QueryResult<BaseItem> GetItemsInternal(InternalItemsQuery query) |
| | | 155 | | { |
| | 0 | 156 | | if (SourceType == SourceType.Channel) |
| | | 157 | | { |
| | | 158 | | try |
| | | 159 | | { |
| | 0 | 160 | | query.Parent = this; |
| | 0 | 161 | | query.ChannelIds = new[] { ChannelId }; |
| | 0 | 162 | | return ChannelManager.GetChannelItemsInternal(query, new Progress<double>(), CancellationToken.None) |
| | | 163 | | } |
| | 0 | 164 | | catch |
| | | 165 | | { |
| | | 166 | | // Already logged at lower levels |
| | 0 | 167 | | return new QueryResult<BaseItem>(); |
| | | 168 | | } |
| | | 169 | | } |
| | | 170 | | |
| | 0 | 171 | | if (query.User is null) |
| | | 172 | | { |
| | 0 | 173 | | return base.GetItemsInternal(query); |
| | | 174 | | } |
| | | 175 | | |
| | 0 | 176 | | var user = query.User; |
| | | 177 | | |
| | 0 | 178 | | Func<BaseItem, bool> filter = i => UserViewBuilder.Filter(i, user, query, UserDataManager, LibraryManager); |
| | | 179 | | |
| | 0 | 180 | | var items = GetEpisodes(user, query.DtoOptions, true).Where(filter); |
| | | 181 | | |
| | 0 | 182 | | return PostFilterAndSort(items, query); |
| | 0 | 183 | | } |
| | | 184 | | |
| | | 185 | | /// <summary> |
| | | 186 | | /// Gets the episodes. |
| | | 187 | | /// </summary> |
| | | 188 | | /// <param name="user">The user.</param> |
| | | 189 | | /// <param name="options">The options to use.</param> |
| | | 190 | | /// <param name="shouldIncludeMissingEpisodes">If missing episodes should be included.</param> |
| | | 191 | | /// <returns>Set of episodes.</returns> |
| | | 192 | | public List<BaseItem> GetEpisodes(User user, DtoOptions options, bool shouldIncludeMissingEpisodes) |
| | | 193 | | { |
| | 0 | 194 | | return GetEpisodes(Series, user, options, shouldIncludeMissingEpisodes); |
| | | 195 | | } |
| | | 196 | | |
| | | 197 | | public List<BaseItem> GetEpisodes(Series series, User user, DtoOptions options, bool shouldIncludeMissingEpisode |
| | | 198 | | { |
| | 0 | 199 | | return GetEpisodes(series, user, null, options, shouldIncludeMissingEpisodes); |
| | | 200 | | } |
| | | 201 | | |
| | | 202 | | public List<BaseItem> GetEpisodes(Series series, User user, IEnumerable<Episode> allSeriesEpisodes, DtoOptions o |
| | | 203 | | { |
| | 0 | 204 | | return series.GetSeasonEpisodes(this, user, allSeriesEpisodes, options, shouldIncludeMissingEpisodes); |
| | | 205 | | } |
| | | 206 | | |
| | | 207 | | public List<BaseItem> GetEpisodes() |
| | | 208 | | { |
| | 0 | 209 | | return Series.GetSeasonEpisodes(this, null, null, new DtoOptions(true), true); |
| | | 210 | | } |
| | | 211 | | |
| | | 212 | | public override List<BaseItem> GetChildren(User user, bool includeLinkedChildren, InternalItemsQuery query) |
| | | 213 | | { |
| | 0 | 214 | | return GetEpisodes(user, new DtoOptions(true), true); |
| | | 215 | | } |
| | | 216 | | |
| | | 217 | | protected override bool GetBlockUnratedValue(User user) |
| | | 218 | | { |
| | | 219 | | // Don't block. Let either the entire series rating or episode rating determine it |
| | 0 | 220 | | return false; |
| | | 221 | | } |
| | | 222 | | |
| | | 223 | | public override UnratedItem GetBlockUnratedType() |
| | | 224 | | { |
| | 0 | 225 | | return UnratedItem.Series; |
| | | 226 | | } |
| | | 227 | | |
| | | 228 | | public string FindSeriesPresentationUniqueKey() |
| | | 229 | | { |
| | 0 | 230 | | var series = Series; |
| | 0 | 231 | | return series is null ? null : series.PresentationUniqueKey; |
| | | 232 | | } |
| | | 233 | | |
| | | 234 | | public string FindSeriesName() |
| | | 235 | | { |
| | 0 | 236 | | var series = Series; |
| | 0 | 237 | | return series is null ? SeriesName : series.Name; |
| | | 238 | | } |
| | | 239 | | |
| | | 240 | | public Guid FindSeriesId() |
| | | 241 | | { |
| | 0 | 242 | | var series = FindParent<Series>(); |
| | 0 | 243 | | return series?.Id ?? Guid.Empty; |
| | | 244 | | } |
| | | 245 | | |
| | | 246 | | /// <summary> |
| | | 247 | | /// Gets the lookup information. |
| | | 248 | | /// </summary> |
| | | 249 | | /// <returns>SeasonInfo.</returns> |
| | | 250 | | public SeasonInfo GetLookupInfo() |
| | | 251 | | { |
| | 0 | 252 | | var id = GetItemLookupInfo<SeasonInfo>(); |
| | | 253 | | |
| | 0 | 254 | | var series = Series; |
| | | 255 | | |
| | 0 | 256 | | if (series is not null) |
| | | 257 | | { |
| | 0 | 258 | | id.SeriesProviderIds = series.ProviderIds; |
| | 0 | 259 | | id.SeriesDisplayOrder = series.DisplayOrder; |
| | | 260 | | } |
| | | 261 | | |
| | 0 | 262 | | return id; |
| | | 263 | | } |
| | | 264 | | |
| | | 265 | | /// <summary> |
| | | 266 | | /// This is called before any metadata refresh and returns true or false indicating if changes were made. |
| | | 267 | | /// </summary> |
| | | 268 | | /// <param name="replaceAllMetadata"><c>true</c> to replace metadata, <c>false</c> to not.</param> |
| | | 269 | | /// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns> |
| | | 270 | | public override bool BeforeMetadataRefresh(bool replaceAllMetadata) |
| | | 271 | | { |
| | 0 | 272 | | var hasChanges = base.BeforeMetadataRefresh(replaceAllMetadata); |
| | | 273 | | |
| | 0 | 274 | | if (!IndexNumber.HasValue && !string.IsNullOrEmpty(Path)) |
| | | 275 | | { |
| | 0 | 276 | | IndexNumber ??= LibraryManager.GetSeasonNumberFromPath(Path, ParentId); |
| | | 277 | | |
| | | 278 | | // If a change was made record it |
| | 0 | 279 | | if (IndexNumber.HasValue) |
| | | 280 | | { |
| | 0 | 281 | | hasChanges = true; |
| | | 282 | | } |
| | | 283 | | } |
| | | 284 | | |
| | 0 | 285 | | return hasChanges; |
| | | 286 | | } |
| | | 287 | | } |
| | | 288 | | } |