| | | 1 | | using System; |
| | | 2 | | using System.Collections.Generic; |
| | | 3 | | using System.ComponentModel.DataAnnotations; |
| | | 4 | | using System.Linq; |
| | | 5 | | using Jellyfin.Api.Attributes; |
| | | 6 | | using Jellyfin.Api.Extensions; |
| | | 7 | | using Jellyfin.Api.Helpers; |
| | | 8 | | using Jellyfin.Api.ModelBinders; |
| | | 9 | | using Jellyfin.Data.Enums; |
| | | 10 | | using Jellyfin.Database.Implementations.Enums; |
| | | 11 | | using Jellyfin.Extensions; |
| | | 12 | | using MediaBrowser.Controller.Dto; |
| | | 13 | | using MediaBrowser.Controller.Entities; |
| | | 14 | | using MediaBrowser.Controller.Entities.TV; |
| | | 15 | | using MediaBrowser.Controller.Library; |
| | | 16 | | using MediaBrowser.Controller.TV; |
| | | 17 | | using MediaBrowser.Model.Dto; |
| | | 18 | | using MediaBrowser.Model.Entities; |
| | | 19 | | using MediaBrowser.Model.Querying; |
| | | 20 | | using Microsoft.AspNetCore.Authorization; |
| | | 21 | | using Microsoft.AspNetCore.Http; |
| | | 22 | | using Microsoft.AspNetCore.Mvc; |
| | | 23 | | |
| | | 24 | | namespace Jellyfin.Api.Controllers; |
| | | 25 | | |
| | | 26 | | /// <summary> |
| | | 27 | | /// The tv shows controller. |
| | | 28 | | /// </summary> |
| | | 29 | | [Route("Shows")] |
| | | 30 | | [Authorize] |
| | | 31 | | public class TvShowsController : BaseJellyfinApiController |
| | | 32 | | { |
| | | 33 | | private readonly IUserManager _userManager; |
| | | 34 | | private readonly ILibraryManager _libraryManager; |
| | | 35 | | private readonly IDtoService _dtoService; |
| | | 36 | | private readonly ITVSeriesManager _tvSeriesManager; |
| | | 37 | | |
| | | 38 | | /// <summary> |
| | | 39 | | /// Initializes a new instance of the <see cref="TvShowsController"/> class. |
| | | 40 | | /// </summary> |
| | | 41 | | /// <param name="userManager">Instance of the <see cref="IUserManager"/> interface.</param> |
| | | 42 | | /// <param name="libraryManager">Instance of the <see cref="ILibraryManager"/> interface.</param> |
| | | 43 | | /// <param name="dtoService">Instance of the <see cref="IDtoService"/> interface.</param> |
| | | 44 | | /// <param name="tvSeriesManager">Instance of the <see cref="ITVSeriesManager"/> interface.</param> |
| | 0 | 45 | | public TvShowsController( |
| | 0 | 46 | | IUserManager userManager, |
| | 0 | 47 | | ILibraryManager libraryManager, |
| | 0 | 48 | | IDtoService dtoService, |
| | 0 | 49 | | ITVSeriesManager tvSeriesManager) |
| | | 50 | | { |
| | 0 | 51 | | _userManager = userManager; |
| | 0 | 52 | | _libraryManager = libraryManager; |
| | 0 | 53 | | _dtoService = dtoService; |
| | 0 | 54 | | _tvSeriesManager = tvSeriesManager; |
| | 0 | 55 | | } |
| | | 56 | | |
| | | 57 | | /// <summary> |
| | | 58 | | /// Gets a list of next up episodes. |
| | | 59 | | /// </summary> |
| | | 60 | | /// <param name="userId">The user id of the user to get the next up episodes for.</param> |
| | | 61 | | /// <param name="startIndex">Optional. The record index to start at. All items with a lower index will be dropped fr |
| | | 62 | | /// <param name="limit">Optional. The maximum number of records to return.</param> |
| | | 63 | | /// <param name="fields">Optional. Specify additional fields of information to return in the output.</param> |
| | | 64 | | /// <param name="seriesId">Optional. Filter by series id.</param> |
| | | 65 | | /// <param name="parentId">Optional. Specify this to localize the search to a specific item or folder. Omit to use t |
| | | 66 | | /// <param name="enableImages">Optional. Include image information in output.</param> |
| | | 67 | | /// <param name="imageTypeLimit">Optional. The max number of images to return, per image type.</param> |
| | | 68 | | /// <param name="enableImageTypes">Optional. The image types to include in the output.</param> |
| | | 69 | | /// <param name="enableUserData">Optional. Include user data.</param> |
| | | 70 | | /// <param name="nextUpDateCutoff">Optional. Starting date of shows to show in Next Up section.</param> |
| | | 71 | | /// <param name="enableTotalRecordCount">Whether to enable the total records count. Defaults to true.</param> |
| | | 72 | | /// <param name="disableFirstEpisode">Whether to disable sending the first episode in a series as next up.</param> |
| | | 73 | | /// <param name="enableResumable">Whether to include resumable episodes in next up results.</param> |
| | | 74 | | /// <param name="enableRewatching">Whether to include watched episodes in next up results.</param> |
| | | 75 | | /// <returns>A <see cref="QueryResult{BaseItemDto}"/> with the next up episodes.</returns> |
| | | 76 | | [HttpGet("NextUp")] |
| | | 77 | | [ProducesResponseType(StatusCodes.Status200OK)] |
| | | 78 | | public ActionResult<QueryResult<BaseItemDto>> GetNextUp( |
| | | 79 | | [FromQuery] Guid? userId, |
| | | 80 | | [FromQuery] int? startIndex, |
| | | 81 | | [FromQuery] int? limit, |
| | | 82 | | [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ItemFields[] fields, |
| | | 83 | | [FromQuery] Guid? seriesId, |
| | | 84 | | [FromQuery] Guid? parentId, |
| | | 85 | | [FromQuery] bool? enableImages, |
| | | 86 | | [FromQuery] int? imageTypeLimit, |
| | | 87 | | [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ImageType[] enableImageTypes, |
| | | 88 | | [FromQuery] bool? enableUserData, |
| | | 89 | | [FromQuery] DateTime? nextUpDateCutoff, |
| | | 90 | | [FromQuery] bool enableTotalRecordCount = true, |
| | | 91 | | [FromQuery][ParameterObsolete] bool disableFirstEpisode = false, |
| | | 92 | | [FromQuery] bool enableResumable = true, |
| | | 93 | | [FromQuery] bool enableRewatching = false) |
| | | 94 | | { |
| | 0 | 95 | | var user = _userManager.GetUserById(RequestHelpers.GetUserId(User, userId)); |
| | 0 | 96 | | if (user is null) |
| | | 97 | | { |
| | 0 | 98 | | return NotFound(); |
| | | 99 | | } |
| | | 100 | | |
| | 0 | 101 | | var options = new DtoOptions { Fields = fields } |
| | 0 | 102 | | .AddClientFields(User) |
| | 0 | 103 | | .AddAdditionalDtoOptions(enableImages, enableUserData, imageTypeLimit, enableImageTypes); |
| | | 104 | | |
| | 0 | 105 | | var result = _tvSeriesManager.GetNextUp( |
| | 0 | 106 | | new NextUpQuery |
| | 0 | 107 | | { |
| | 0 | 108 | | Limit = limit, |
| | 0 | 109 | | ParentId = parentId, |
| | 0 | 110 | | SeriesId = seriesId, |
| | 0 | 111 | | StartIndex = startIndex, |
| | 0 | 112 | | User = user, |
| | 0 | 113 | | EnableTotalRecordCount = enableTotalRecordCount, |
| | 0 | 114 | | NextUpDateCutoff = nextUpDateCutoff ?? DateTime.MinValue, |
| | 0 | 115 | | EnableResumable = enableResumable, |
| | 0 | 116 | | EnableRewatching = enableRewatching |
| | 0 | 117 | | }, |
| | 0 | 118 | | options); |
| | | 119 | | |
| | 0 | 120 | | var returnItems = _dtoService.GetBaseItemDtos(result.Items, options, user); |
| | | 121 | | |
| | 0 | 122 | | return new QueryResult<BaseItemDto>( |
| | 0 | 123 | | startIndex, |
| | 0 | 124 | | result.TotalRecordCount, |
| | 0 | 125 | | returnItems); |
| | | 126 | | } |
| | | 127 | | |
| | | 128 | | /// <summary> |
| | | 129 | | /// Gets a list of upcoming episodes. |
| | | 130 | | /// </summary> |
| | | 131 | | /// <param name="userId">The user id of the user to get the upcoming episodes for.</param> |
| | | 132 | | /// <param name="startIndex">Optional. The record index to start at. All items with a lower index will be dropped fr |
| | | 133 | | /// <param name="limit">Optional. The maximum number of records to return.</param> |
| | | 134 | | /// <param name="fields">Optional. Specify additional fields of information to return in the output.</param> |
| | | 135 | | /// <param name="parentId">Optional. Specify this to localize the search to a specific item or folder. Omit to use t |
| | | 136 | | /// <param name="enableImages">Optional. Include image information in output.</param> |
| | | 137 | | /// <param name="imageTypeLimit">Optional. The max number of images to return, per image type.</param> |
| | | 138 | | /// <param name="enableImageTypes">Optional. The image types to include in the output.</param> |
| | | 139 | | /// <param name="enableUserData">Optional. Include user data.</param> |
| | | 140 | | /// <returns>A <see cref="QueryResult{BaseItemDto}"/> with the upcoming episodes.</returns> |
| | | 141 | | [HttpGet("Upcoming")] |
| | | 142 | | [ProducesResponseType(StatusCodes.Status200OK)] |
| | | 143 | | public ActionResult<QueryResult<BaseItemDto>> GetUpcomingEpisodes( |
| | | 144 | | [FromQuery] Guid? userId, |
| | | 145 | | [FromQuery] int? startIndex, |
| | | 146 | | [FromQuery] int? limit, |
| | | 147 | | [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ItemFields[] fields, |
| | | 148 | | [FromQuery] Guid? parentId, |
| | | 149 | | [FromQuery] bool? enableImages, |
| | | 150 | | [FromQuery] int? imageTypeLimit, |
| | | 151 | | [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ImageType[] enableImageTypes, |
| | | 152 | | [FromQuery] bool? enableUserData) |
| | | 153 | | { |
| | 0 | 154 | | userId = RequestHelpers.GetUserId(User, userId); |
| | 0 | 155 | | var user = userId.IsNullOrEmpty() |
| | 0 | 156 | | ? null |
| | 0 | 157 | | : _userManager.GetUserById(userId.Value); |
| | | 158 | | |
| | 0 | 159 | | var minPremiereDate = DateTime.UtcNow.Date.AddDays(-1); |
| | | 160 | | |
| | 0 | 161 | | var parentIdGuid = parentId ?? Guid.Empty; |
| | | 162 | | |
| | 0 | 163 | | var options = new DtoOptions { Fields = fields } |
| | 0 | 164 | | .AddClientFields(User) |
| | 0 | 165 | | .AddAdditionalDtoOptions(enableImages, enableUserData, imageTypeLimit, enableImageTypes); |
| | | 166 | | |
| | 0 | 167 | | var itemsResult = _libraryManager.GetItemList(new InternalItemsQuery(user) |
| | 0 | 168 | | { |
| | 0 | 169 | | IncludeItemTypes = new[] { BaseItemKind.Episode }, |
| | 0 | 170 | | OrderBy = new[] { (ItemSortBy.PremiereDate, SortOrder.Ascending), (ItemSortBy.SortName, SortOrder.Ascending) |
| | 0 | 171 | | MinPremiereDate = minPremiereDate, |
| | 0 | 172 | | StartIndex = startIndex, |
| | 0 | 173 | | Limit = limit, |
| | 0 | 174 | | ParentId = parentIdGuid, |
| | 0 | 175 | | Recursive = true, |
| | 0 | 176 | | DtoOptions = options |
| | 0 | 177 | | }); |
| | | 178 | | |
| | 0 | 179 | | var returnItems = _dtoService.GetBaseItemDtos(itemsResult, options, user); |
| | | 180 | | |
| | 0 | 181 | | return new QueryResult<BaseItemDto>( |
| | 0 | 182 | | startIndex, |
| | 0 | 183 | | itemsResult.Count, |
| | 0 | 184 | | returnItems); |
| | | 185 | | } |
| | | 186 | | |
| | | 187 | | /// <summary> |
| | | 188 | | /// Gets episodes for a tv season. |
| | | 189 | | /// </summary> |
| | | 190 | | /// <param name="seriesId">The series id.</param> |
| | | 191 | | /// <param name="userId">The user id.</param> |
| | | 192 | | /// <param name="fields">Optional. Specify additional fields of information to return in the output. This allows mul |
| | | 193 | | /// <param name="season">Optional filter by season number.</param> |
| | | 194 | | /// <param name="seasonId">Optional. Filter by season id.</param> |
| | | 195 | | /// <param name="isMissing">Optional. Filter by items that are missing episodes or not.</param> |
| | | 196 | | /// <param name="adjacentTo">Optional. Return items that are siblings of a supplied item.</param> |
| | | 197 | | /// <param name="startItemId">Optional. Skip through the list until a given item is found.</param> |
| | | 198 | | /// <param name="startIndex">Optional. The record index to start at. All items with a lower index will be dropped fr |
| | | 199 | | /// <param name="limit">Optional. The maximum number of records to return.</param> |
| | | 200 | | /// <param name="enableImages">Optional, include image information in output.</param> |
| | | 201 | | /// <param name="imageTypeLimit">Optional, the max number of images to return, per image type.</param> |
| | | 202 | | /// <param name="enableImageTypes">Optional. The image types to include in the output.</param> |
| | | 203 | | /// <param name="enableUserData">Optional. Include user data.</param> |
| | | 204 | | /// <param name="sortBy">Optional. Specify one or more sort orders, comma delimited. Options: Album, AlbumArtist, Ar |
| | | 205 | | /// <returns>A <see cref="QueryResult{BaseItemDto}"/> with the episodes on success or a <see cref="NotFoundResult"/> |
| | | 206 | | [HttpGet("{seriesId}/Episodes")] |
| | | 207 | | [ProducesResponseType(StatusCodes.Status200OK)] |
| | | 208 | | [ProducesResponseType(StatusCodes.Status404NotFound)] |
| | | 209 | | public ActionResult<QueryResult<BaseItemDto>> GetEpisodes( |
| | | 210 | | [FromRoute, Required] Guid seriesId, |
| | | 211 | | [FromQuery] Guid? userId, |
| | | 212 | | [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ItemFields[] fields, |
| | | 213 | | [FromQuery] int? season, |
| | | 214 | | [FromQuery] Guid? seasonId, |
| | | 215 | | [FromQuery] bool? isMissing, |
| | | 216 | | [FromQuery] Guid? adjacentTo, |
| | | 217 | | [FromQuery] Guid? startItemId, |
| | | 218 | | [FromQuery] int? startIndex, |
| | | 219 | | [FromQuery] int? limit, |
| | | 220 | | [FromQuery] bool? enableImages, |
| | | 221 | | [FromQuery] int? imageTypeLimit, |
| | | 222 | | [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ImageType[] enableImageTypes, |
| | | 223 | | [FromQuery] bool? enableUserData, |
| | | 224 | | [FromQuery] ItemSortBy? sortBy) |
| | | 225 | | { |
| | 0 | 226 | | userId = RequestHelpers.GetUserId(User, userId); |
| | 0 | 227 | | var user = userId.IsNullOrEmpty() |
| | 0 | 228 | | ? null |
| | 0 | 229 | | : _userManager.GetUserById(userId.Value); |
| | | 230 | | |
| | | 231 | | List<BaseItem> episodes; |
| | | 232 | | |
| | 0 | 233 | | var dtoOptions = new DtoOptions { Fields = fields } |
| | 0 | 234 | | .AddClientFields(User) |
| | 0 | 235 | | .AddAdditionalDtoOptions(enableImages, enableUserData, imageTypeLimit, enableImageTypes); |
| | 0 | 236 | | var shouldIncludeMissingEpisodes = (user is not null && user.DisplayMissingEpisodes) || User.GetIsApiKey(); |
| | | 237 | | |
| | 0 | 238 | | if (seasonId.HasValue) // Season id was supplied. Get episodes by season id. |
| | | 239 | | { |
| | 0 | 240 | | var item = _libraryManager.GetItemById<BaseItem>(seasonId.Value); |
| | 0 | 241 | | if (item is not Season seasonItem) |
| | | 242 | | { |
| | 0 | 243 | | return NotFound("No season exists with Id " + seasonId); |
| | | 244 | | } |
| | | 245 | | |
| | 0 | 246 | | episodes = seasonItem.GetEpisodes(user, dtoOptions, shouldIncludeMissingEpisodes); |
| | | 247 | | } |
| | 0 | 248 | | else if (season.HasValue) // Season number was supplied. Get episodes by season number |
| | | 249 | | { |
| | 0 | 250 | | var series = _libraryManager.GetItemById<Series>(seriesId); |
| | 0 | 251 | | if (series is null) |
| | | 252 | | { |
| | 0 | 253 | | return NotFound("Series not found"); |
| | | 254 | | } |
| | | 255 | | |
| | 0 | 256 | | var seasonItem = series |
| | 0 | 257 | | .GetSeasons(user, dtoOptions) |
| | 0 | 258 | | .FirstOrDefault(i => i.IndexNumber == season.Value); |
| | | 259 | | |
| | 0 | 260 | | episodes = seasonItem is null ? |
| | 0 | 261 | | new List<BaseItem>() |
| | 0 | 262 | | : ((Season)seasonItem).GetEpisodes(user, dtoOptions, shouldIncludeMissingEpisodes); |
| | | 263 | | } |
| | | 264 | | else // No season number or season id was supplied. Returning all episodes. |
| | | 265 | | { |
| | 0 | 266 | | if (_libraryManager.GetItemById<BaseItem>(seriesId) is not Series series) |
| | | 267 | | { |
| | 0 | 268 | | return NotFound("Series not found"); |
| | | 269 | | } |
| | | 270 | | |
| | 0 | 271 | | episodes = series.GetEpisodes(user, dtoOptions, shouldIncludeMissingEpisodes).ToList(); |
| | | 272 | | } |
| | | 273 | | |
| | | 274 | | // Filter after the fact in case the ui doesn't want them |
| | 0 | 275 | | if (isMissing.HasValue) |
| | | 276 | | { |
| | 0 | 277 | | var val = isMissing.Value; |
| | 0 | 278 | | episodes = episodes |
| | 0 | 279 | | .Where(i => ((Episode)i).IsMissingEpisode == val) |
| | 0 | 280 | | .ToList(); |
| | | 281 | | } |
| | | 282 | | |
| | 0 | 283 | | if (startItemId.HasValue) |
| | | 284 | | { |
| | 0 | 285 | | episodes = episodes |
| | 0 | 286 | | .SkipWhile(i => !startItemId.Value.Equals(i.Id)) |
| | 0 | 287 | | .ToList(); |
| | | 288 | | } |
| | | 289 | | |
| | | 290 | | // This must be the last filter |
| | 0 | 291 | | if (!adjacentTo.IsNullOrEmpty()) |
| | | 292 | | { |
| | 0 | 293 | | episodes = UserViewBuilder.FilterForAdjacency(episodes, adjacentTo.Value).ToList(); |
| | | 294 | | } |
| | | 295 | | |
| | 0 | 296 | | if (sortBy == ItemSortBy.Random) |
| | | 297 | | { |
| | 0 | 298 | | episodes.Shuffle(); |
| | | 299 | | } |
| | | 300 | | |
| | 0 | 301 | | var returnItems = episodes; |
| | | 302 | | |
| | 0 | 303 | | if (startIndex.HasValue || limit.HasValue) |
| | | 304 | | { |
| | 0 | 305 | | returnItems = ApplyPaging(episodes, startIndex, limit).ToList(); |
| | | 306 | | } |
| | | 307 | | |
| | 0 | 308 | | var dtos = _dtoService.GetBaseItemDtos(returnItems, dtoOptions, user); |
| | | 309 | | |
| | 0 | 310 | | return new QueryResult<BaseItemDto>( |
| | 0 | 311 | | startIndex, |
| | 0 | 312 | | episodes.Count, |
| | 0 | 313 | | dtos); |
| | | 314 | | } |
| | | 315 | | |
| | | 316 | | /// <summary> |
| | | 317 | | /// Gets seasons for a tv series. |
| | | 318 | | /// </summary> |
| | | 319 | | /// <param name="seriesId">The series id.</param> |
| | | 320 | | /// <param name="userId">The user id.</param> |
| | | 321 | | /// <param name="fields">Optional. Specify additional fields of information to return in the output. This allows mul |
| | | 322 | | /// <param name="isSpecialSeason">Optional. Filter by special season.</param> |
| | | 323 | | /// <param name="isMissing">Optional. Filter by items that are missing episodes or not.</param> |
| | | 324 | | /// <param name="adjacentTo">Optional. Return items that are siblings of a supplied item.</param> |
| | | 325 | | /// <param name="enableImages">Optional. Include image information in output.</param> |
| | | 326 | | /// <param name="imageTypeLimit">Optional. The max number of images to return, per image type.</param> |
| | | 327 | | /// <param name="enableImageTypes">Optional. The image types to include in the output.</param> |
| | | 328 | | /// <param name="enableUserData">Optional. Include user data.</param> |
| | | 329 | | /// <returns>A <see cref="QueryResult{BaseItemDto}"/> on success or a <see cref="NotFoundResult"/> if the series was |
| | | 330 | | [HttpGet("{seriesId}/Seasons")] |
| | | 331 | | [ProducesResponseType(StatusCodes.Status200OK)] |
| | | 332 | | [ProducesResponseType(StatusCodes.Status404NotFound)] |
| | | 333 | | public ActionResult<QueryResult<BaseItemDto>> GetSeasons( |
| | | 334 | | [FromRoute, Required] Guid seriesId, |
| | | 335 | | [FromQuery] Guid? userId, |
| | | 336 | | [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ItemFields[] fields, |
| | | 337 | | [FromQuery] bool? isSpecialSeason, |
| | | 338 | | [FromQuery] bool? isMissing, |
| | | 339 | | [FromQuery] Guid? adjacentTo, |
| | | 340 | | [FromQuery] bool? enableImages, |
| | | 341 | | [FromQuery] int? imageTypeLimit, |
| | | 342 | | [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ImageType[] enableImageTypes, |
| | | 343 | | [FromQuery] bool? enableUserData) |
| | | 344 | | { |
| | 0 | 345 | | userId = RequestHelpers.GetUserId(User, userId); |
| | 0 | 346 | | var user = userId.IsNullOrEmpty() |
| | 0 | 347 | | ? null |
| | 0 | 348 | | : _userManager.GetUserById(userId.Value); |
| | 0 | 349 | | var item = _libraryManager.GetItemById<Series>(seriesId, user); |
| | 0 | 350 | | if (item is null) |
| | | 351 | | { |
| | 0 | 352 | | return NotFound(); |
| | | 353 | | } |
| | | 354 | | |
| | 0 | 355 | | var seasons = item.GetItemList(new InternalItemsQuery(user) |
| | 0 | 356 | | { |
| | 0 | 357 | | IsMissing = isMissing, |
| | 0 | 358 | | IsSpecialSeason = isSpecialSeason, |
| | 0 | 359 | | AdjacentTo = adjacentTo |
| | 0 | 360 | | }); |
| | | 361 | | |
| | 0 | 362 | | var dtoOptions = new DtoOptions { Fields = fields } |
| | 0 | 363 | | .AddClientFields(User) |
| | 0 | 364 | | .AddAdditionalDtoOptions(enableImages, enableUserData, imageTypeLimit, enableImageTypes); |
| | | 365 | | |
| | 0 | 366 | | var returnItems = _dtoService.GetBaseItemDtos(seasons, dtoOptions, user); |
| | | 367 | | |
| | 0 | 368 | | return new QueryResult<BaseItemDto>(returnItems); |
| | | 369 | | } |
| | | 370 | | |
| | | 371 | | /// <summary> |
| | | 372 | | /// Applies the paging. |
| | | 373 | | /// </summary> |
| | | 374 | | /// <param name="items">The items.</param> |
| | | 375 | | /// <param name="startIndex">The start index.</param> |
| | | 376 | | /// <param name="limit">The limit.</param> |
| | | 377 | | /// <returns>IEnumerable{BaseItem}.</returns> |
| | | 378 | | private IEnumerable<BaseItem> ApplyPaging(IEnumerable<BaseItem> items, int? startIndex, int? limit) |
| | | 379 | | { |
| | | 380 | | // Start at |
| | 0 | 381 | | if (startIndex.HasValue) |
| | | 382 | | { |
| | 0 | 383 | | items = items.Skip(startIndex.Value); |
| | | 384 | | } |
| | | 385 | | |
| | | 386 | | // Return limit |
| | 0 | 387 | | if (limit.HasValue) |
| | | 388 | | { |
| | 0 | 389 | | items = items.Take(limit.Value); |
| | | 390 | | } |
| | | 391 | | |
| | 0 | 392 | | return items; |
| | | 393 | | } |
| | | 394 | | } |