using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Entities.Movies;
using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Localization;
using MediaBrowser.Model.Channels;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Querying;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
namespace MediaBrowser.Api.Reports
{
/// A report builder.
///
public class ReportBuilder : ReportBuilderBase
{
#region [Constructors]
///
/// Initializes a new instance of the MediaBrowser.Api.Reports.ReportBuilder class.
/// Manager for library.
public ReportBuilder(ILibraryManager libraryManager)
: base(libraryManager)
{
}
#endregion
#region [Public Methods]
/// Gets report result.
/// The items.
/// The request.
/// The report result.
public ReportResult GetResult(BaseItem[] items, IReportsQuery request)
{
ReportIncludeItemTypes reportRowType = ReportHelper.GetRowType(request.IncludeItemTypes);
ReportDisplayType displayType = ReportHelper.GetReportDisplayType(request.DisplayType);
List> options = this.GetReportOptions(request,
() => this.GetDefaultHeaderMetadata(reportRowType),
(hm) => this.GetOption(hm)).Where(x => this.DisplayTypeVisible(x.Header.DisplayType, displayType)).ToList();
var headers = GetHeaders(options);
var rows = GetReportRows(items, options);
ReportResult result = new ReportResult { Headers = headers };
HeaderMetadata groupBy = ReportHelper.GetHeaderMetadataType(request.GroupBy);
int i = headers.FindIndex(x => x.FieldName == groupBy);
if (groupBy != HeaderMetadata.None && i >= 0)
{
var rowsGroup = rows.SelectMany(x => x.Columns[i].Name.Split(';'), (x, g) => new { Group = g.Trim(), Rows = x })
.GroupBy(x => x.Group)
.OrderBy(x => x.Key)
.Select(x => new ReportGroup { Name = x.Key, Rows = x.Select(r => r.Rows).ToList() });
result.Groups = rowsGroup.ToList();
result.IsGrouped = true;
}
else
{
result.Rows = rows;
result.IsGrouped = false;
}
return result;
}
#endregion
#region [Protected Internal Methods]
/// Gets the headers.
/// Type of the header.
/// The request.
/// The headers.
///
protected internal override List GetHeaders(H request)
{
ReportIncludeItemTypes reportRowType = ReportHelper.GetRowType(request.IncludeItemTypes);
return this.GetHeaders(request, () => this.GetDefaultHeaderMetadata(reportRowType), (hm) => this.GetOption(hm));
}
#endregion
#region [Private Methods]
/// Gets default report header metadata.
/// Type of the report row.
/// The default report header metadata.
private List GetDefaultHeaderMetadata(ReportIncludeItemTypes reportIncludeItemTypes)
{
switch (reportIncludeItemTypes)
{
case ReportIncludeItemTypes.Season:
return new List
{
HeaderMetadata.Status,
HeaderMetadata.Locked,
HeaderMetadata.ImagePrimary,
HeaderMetadata.ImageBackdrop,
HeaderMetadata.ImageLogo,
HeaderMetadata.Series,
HeaderMetadata.Season,
HeaderMetadata.SeasonNumber,
HeaderMetadata.DateAdded,
HeaderMetadata.Year,
HeaderMetadata.Genres
};
case ReportIncludeItemTypes.Series:
return new List
{
HeaderMetadata.Status,
HeaderMetadata.Locked,
HeaderMetadata.ImagePrimary,
HeaderMetadata.ImageBackdrop,
HeaderMetadata.ImageLogo,
HeaderMetadata.Name,
HeaderMetadata.Network,
HeaderMetadata.DateAdded,
HeaderMetadata.Year,
HeaderMetadata.Genres,
HeaderMetadata.ParentalRating,
HeaderMetadata.CommunityRating,
HeaderMetadata.Runtime,
HeaderMetadata.Trailers,
HeaderMetadata.Specials
};
case ReportIncludeItemTypes.MusicAlbum:
return new List
{
HeaderMetadata.Status,
HeaderMetadata.Locked,
HeaderMetadata.ImagePrimary,
HeaderMetadata.ImageBackdrop,
HeaderMetadata.ImageLogo,
HeaderMetadata.Name,
HeaderMetadata.AlbumArtist,
HeaderMetadata.DateAdded,
HeaderMetadata.ReleaseDate,
HeaderMetadata.Tracks,
HeaderMetadata.Year,
HeaderMetadata.Genres
};
case ReportIncludeItemTypes.MusicArtist:
return new List
{
HeaderMetadata.Status,
HeaderMetadata.Locked,
HeaderMetadata.ImagePrimary,
HeaderMetadata.ImageBackdrop,
HeaderMetadata.ImageLogo,
HeaderMetadata.MusicArtist,
HeaderMetadata.Countries,
HeaderMetadata.DateAdded,
HeaderMetadata.Year,
HeaderMetadata.Genres
};
case ReportIncludeItemTypes.Game:
return new List
{
HeaderMetadata.Status,
HeaderMetadata.Locked,
HeaderMetadata.ImagePrimary,
HeaderMetadata.ImageBackdrop,
HeaderMetadata.ImageLogo,
HeaderMetadata.Name,
HeaderMetadata.GameSystem,
HeaderMetadata.DateAdded,
HeaderMetadata.ReleaseDate,
HeaderMetadata.ParentalRating,
HeaderMetadata.CommunityRating,
HeaderMetadata.Players,
HeaderMetadata.Year,
HeaderMetadata.Genres,
HeaderMetadata.Trailers
};
case ReportIncludeItemTypes.Movie:
return new List
{
HeaderMetadata.Status,
HeaderMetadata.Locked,
HeaderMetadata.ImagePrimary,
HeaderMetadata.ImageBackdrop,
HeaderMetadata.ImageLogo,
HeaderMetadata.Name,
HeaderMetadata.DateAdded,
HeaderMetadata.ReleaseDate,
HeaderMetadata.Year,
HeaderMetadata.Genres,
HeaderMetadata.ParentalRating,
HeaderMetadata.CommunityRating,
HeaderMetadata.Runtime,
HeaderMetadata.Video,
HeaderMetadata.Resolution,
HeaderMetadata.Audio,
HeaderMetadata.Subtitles,
HeaderMetadata.Trailers,
HeaderMetadata.Specials
};
case ReportIncludeItemTypes.Book:
return new List
{
HeaderMetadata.Status,
HeaderMetadata.Locked,
HeaderMetadata.ImagePrimary,
HeaderMetadata.ImageBackdrop,
HeaderMetadata.ImageLogo,
HeaderMetadata.Name,
HeaderMetadata.DateAdded,
HeaderMetadata.ReleaseDate,
HeaderMetadata.Year,
HeaderMetadata.Genres,
HeaderMetadata.ParentalRating,
HeaderMetadata.CommunityRating
};
case ReportIncludeItemTypes.BoxSet:
return new List
{
HeaderMetadata.Status,
HeaderMetadata.Locked,
HeaderMetadata.ImagePrimary,
HeaderMetadata.ImageBackdrop,
HeaderMetadata.ImageLogo,
HeaderMetadata.Name,
HeaderMetadata.DateAdded,
HeaderMetadata.ReleaseDate,
HeaderMetadata.Year,
HeaderMetadata.Genres,
HeaderMetadata.ParentalRating,
HeaderMetadata.CommunityRating,
HeaderMetadata.Trailers
};
case ReportIncludeItemTypes.Audio:
return new List
{
HeaderMetadata.Status,
HeaderMetadata.Locked,
HeaderMetadata.ImagePrimary,
HeaderMetadata.ImageBackdrop,
HeaderMetadata.ImageLogo,
HeaderMetadata.Name,
HeaderMetadata.AudioAlbumArtist,
HeaderMetadata.AudioAlbum,
HeaderMetadata.Disc,
HeaderMetadata.Track,
HeaderMetadata.DateAdded,
HeaderMetadata.ReleaseDate,
HeaderMetadata.Year,
HeaderMetadata.Genres,
HeaderMetadata.ParentalRating,
HeaderMetadata.CommunityRating,
HeaderMetadata.Runtime,
HeaderMetadata.Audio
};
case ReportIncludeItemTypes.Episode:
return new List
{
HeaderMetadata.Status,
HeaderMetadata.Locked,
HeaderMetadata.ImagePrimary,
HeaderMetadata.ImageBackdrop,
HeaderMetadata.ImageLogo,
HeaderMetadata.Name,
HeaderMetadata.EpisodeSeries,
HeaderMetadata.Season,
HeaderMetadata.DateAdded,
HeaderMetadata.ReleaseDate,
HeaderMetadata.Year,
HeaderMetadata.Genres,
HeaderMetadata.ParentalRating,
HeaderMetadata.CommunityRating,
HeaderMetadata.Runtime,
HeaderMetadata.Video,
HeaderMetadata.Resolution,
HeaderMetadata.Audio,
HeaderMetadata.Subtitles,
HeaderMetadata.Trailers,
HeaderMetadata.Specials
};
case ReportIncludeItemTypes.Video:
case ReportIncludeItemTypes.MusicVideo:
case ReportIncludeItemTypes.Trailer:
case ReportIncludeItemTypes.BaseItem:
default:
return new List
{
HeaderMetadata.Status,
HeaderMetadata.Locked,
HeaderMetadata.ImagePrimary,
HeaderMetadata.ImageBackdrop,
HeaderMetadata.ImageLogo,
HeaderMetadata.ImagePrimary,
HeaderMetadata.ImageBackdrop,
HeaderMetadata.ImageLogo,
HeaderMetadata.Name,
HeaderMetadata.DateAdded,
HeaderMetadata.ReleaseDate,
HeaderMetadata.Year,
HeaderMetadata.Genres,
HeaderMetadata.ParentalRating,
HeaderMetadata.CommunityRating,
HeaderMetadata.Runtime,
HeaderMetadata.Video,
HeaderMetadata.Resolution,
HeaderMetadata.Audio,
HeaderMetadata.Subtitles,
HeaderMetadata.Trailers,
HeaderMetadata.Specials
};
}
}
/// Gets report option.
/// The header.
/// The sort field.
/// The report option.
private ReportOptions GetOption(HeaderMetadata header, string sortField = "")
{
HeaderMetadata internalHeader = header;
ReportOptions option = new ReportOptions()
{
Header = new ReportHeader
{
HeaderFieldType = ReportFieldType.String,
SortField = sortField,
Type = "",
ItemViewType = ItemViewType.None
}
};
switch (header)
{
case HeaderMetadata.Status:
option.Header.ItemViewType = ItemViewType.StatusImage;
internalHeader = HeaderMetadata.Status;
option.Header.CanGroup = false;
option.Header.DisplayType = ReportDisplayType.Screen;
break;
case HeaderMetadata.Locked:
option.Column = (i, r) => this.GetBoolString(r.HasLockData);
option.Header.ItemViewType = ItemViewType.LockDataImage;
option.Header.CanGroup = false;
option.Header.DisplayType = ReportDisplayType.Export;
break;
case HeaderMetadata.ImagePrimary:
option.Column = (i, r) => this.GetBoolString(r.HasImageTagsPrimary);
option.Header.ItemViewType = ItemViewType.TagsPrimaryImage;
option.Header.CanGroup = false;
option.Header.DisplayType = ReportDisplayType.Export;
break;
case HeaderMetadata.ImageBackdrop:
option.Column = (i, r) => this.GetBoolString(r.HasImageTagsBackdrop);
option.Header.ItemViewType = ItemViewType.TagsBackdropImage;
option.Header.CanGroup = false;
option.Header.DisplayType = ReportDisplayType.Export;
break;
case HeaderMetadata.ImageLogo:
option.Column = (i, r) => this.GetBoolString(r.HasImageTagsLogo);
option.Header.ItemViewType = ItemViewType.TagsLogoImage;
option.Header.CanGroup = false;
option.Header.DisplayType = ReportDisplayType.Export;
break;
case HeaderMetadata.Name:
option.Column = (i, r) => i.Name;
option.Header.ItemViewType = ItemViewType.Detail;
option.Header.SortField = "SortName";
break;
case HeaderMetadata.DateAdded:
option.Column = (i, r) => i.DateCreated;
option.Header.SortField = "DateCreated,SortName";
option.Header.HeaderFieldType = ReportFieldType.DateTime;
option.Header.Type = "";
break;
case HeaderMetadata.PremiereDate:
case HeaderMetadata.ReleaseDate:
option.Column = (i, r) => i.PremiereDate;
option.Header.HeaderFieldType = ReportFieldType.DateTime;
option.Header.SortField = "ProductionYear,PremiereDate,SortName";
break;
case HeaderMetadata.Runtime:
option.Column = (i, r) => this.GetRuntimeDateTime(i.RunTimeTicks);
option.Header.HeaderFieldType = ReportFieldType.Minutes;
option.Header.SortField = "Runtime,SortName";
break;
case HeaderMetadata.PlayCount:
option.Header.HeaderFieldType = ReportFieldType.Int;
break;
case HeaderMetadata.Season:
option.Column = (i, r) => this.GetEpisode(i);
option.Header.ItemViewType = ItemViewType.Detail;
option.Header.SortField = "SortName";
break;
case HeaderMetadata.SeasonNumber:
option.Column = (i, r) => this.GetObject(i, (x) => x.IndexNumber == null ? "" : x.IndexNumber.ToString());
option.Header.SortField = "IndexNumber";
option.Header.HeaderFieldType = ReportFieldType.Int;
break;
case HeaderMetadata.Series:
option.Column = (i, r) => this.GetObject(i, (x) => x.SeriesName);
option.Header.ItemViewType = ItemViewType.Detail;
option.Header.SortField = "SeriesSortName,SortName";
break;
case HeaderMetadata.EpisodeSeries:
option.Column = (i, r) => this.GetObject(i, (x) => x.SeriesName);
option.Header.ItemViewType = ItemViewType.Detail;
option.ItemID = (i) =>
{
Series series = this.GetObject(i, (x) => x.Series);
if (series == null)
return string.Empty;
return series.Id;
};
option.Header.SortField = "SeriesSortName,SortName";
internalHeader = HeaderMetadata.Series;
break;
case HeaderMetadata.EpisodeSeason:
option.Column = (i, r) => this.GetObject(i, (x) => x.SeriesName);
option.Header.ItemViewType = ItemViewType.Detail;
option.ItemID = (i) =>
{
Season season = this.GetObject(i, (x) => x.Season);
if (season == null)
return string.Empty;
return season.Id;
};
option.Header.SortField = "SortName";
internalHeader = HeaderMetadata.Season;
break;
case HeaderMetadata.Network:
option.Column = (i, r) => this.GetListAsString(i.Studios);
option.ItemID = (i) => this.GetStudioID(i.Studios.FirstOrDefault());
option.Header.ItemViewType = ItemViewType.ItemByNameDetails;
option.Header.SortField = "Studio,SortName";
break;
case HeaderMetadata.Year:
option.Column = (i, r) => this.GetSeriesProductionYear(i);
option.Header.SortField = "ProductionYear,PremiereDate,SortName";
break;
case HeaderMetadata.ParentalRating:
option.Column = (i, r) => i.OfficialRating;
option.Header.SortField = "OfficialRating,SortName";
break;
case HeaderMetadata.CommunityRating:
option.Column = (i, r) => i.CommunityRating;
option.Header.SortField = "CommunityRating,SortName";
break;
case HeaderMetadata.Trailers:
option.Column = (i, r) => this.GetBoolString(r.HasLocalTrailer);
option.Header.ItemViewType = ItemViewType.TrailersImage;
break;
case HeaderMetadata.Specials:
option.Column = (i, r) => this.GetBoolString(r.HasSpecials);
option.Header.ItemViewType = ItemViewType.SpecialsImage;
break;
case HeaderMetadata.GameSystem:
option.Column = (i, r) => this.GetObject(i, (x) => x.GameSystem);
option.Header.SortField = "GameSystem,SortName";
break;
case HeaderMetadata.Players:
option.Column = (i, r) => this.GetObject(i, (x) => x.PlayersSupported);
option.Header.SortField = "Players,GameSystem,SortName";
break;
case HeaderMetadata.AlbumArtist:
option.Column = (i, r) => this.GetObject(i, (x) => x.AlbumArtist);
option.ItemID = (i) => this.GetPersonID(this.GetObject(i, (x) => x.AlbumArtist));
option.Header.ItemViewType = ItemViewType.Detail;
option.Header.SortField = "AlbumArtist,Album,SortName";
break;
case HeaderMetadata.MusicArtist:
option.Column = (i, r) => this.GetObject(i, (x) => x.GetLookupInfo().Name);
option.Header.ItemViewType = ItemViewType.Detail;
option.Header.SortField = "AlbumArtist,Album,SortName";
internalHeader = HeaderMetadata.AlbumArtist;
break;
case HeaderMetadata.AudioAlbumArtist:
option.Column = (i, r) => this.GetListAsString(this.GetObject