mirror of
https://github.com/jellyfin/jellyfin.git
synced 2025-07-09 03:04:24 -04:00
Report manager implementation
This commit is contained in:
parent
67ad98786f
commit
b2b262c06a
@ -84,10 +84,28 @@
|
|||||||
<Compile Include="Playback\MediaInfoService.cs" />
|
<Compile Include="Playback\MediaInfoService.cs" />
|
||||||
<Compile Include="Playback\TranscodingThrottler.cs" />
|
<Compile Include="Playback\TranscodingThrottler.cs" />
|
||||||
<Compile Include="PlaylistService.cs" />
|
<Compile Include="PlaylistService.cs" />
|
||||||
<Compile Include="Reports\ReportFieldType.cs" />
|
<Compile Include="Reports\Common\HeaderMetadata.cs" />
|
||||||
<Compile Include="Reports\ReportResult.cs" />
|
<Compile Include="Reports\Common\ItemViewType.cs" />
|
||||||
<Compile Include="Reports\ReportsService.cs" />
|
<Compile Include="Reports\Common\ReportBuilderBase.cs" />
|
||||||
|
<Compile Include="Reports\Common\ReportExportType.cs" />
|
||||||
|
<Compile Include="Reports\Common\ReportFieldType.cs" />
|
||||||
|
<Compile Include="Reports\Common\ReportHeaderIdType.cs" />
|
||||||
|
<Compile Include="Reports\Common\ReportHelper.cs" />
|
||||||
|
<Compile Include="Reports\Common\ReportViewType.cs" />
|
||||||
|
<Compile Include="Reports\Data\ReportBuilder.cs" />
|
||||||
|
<Compile Include="Reports\Data\ReportExport.cs" />
|
||||||
|
<Compile Include="Reports\Data\ReportGroup.cs" />
|
||||||
|
<Compile Include="Reports\Data\ReportHeader.cs" />
|
||||||
|
<Compile Include="Reports\Data\ReportItem.cs" />
|
||||||
|
<Compile Include="Reports\Data\ReportOptions.cs" />
|
||||||
|
<Compile Include="Reports\Data\ReportResult.cs" />
|
||||||
|
<Compile Include="Reports\Data\ReportRow.cs" />
|
||||||
<Compile Include="Reports\ReportRequests.cs" />
|
<Compile Include="Reports\ReportRequests.cs" />
|
||||||
|
<Compile Include="Reports\ReportsService.cs" />
|
||||||
|
<Compile Include="Reports\Stat\ReportStatBuilder.cs" />
|
||||||
|
<Compile Include="Reports\Stat\ReportStatGroup.cs" />
|
||||||
|
<Compile Include="Reports\Stat\ReportStatItem.cs" />
|
||||||
|
<Compile Include="Reports\Stat\ReportStatResult.cs" />
|
||||||
<Compile Include="StartupWizardService.cs" />
|
<Compile Include="StartupWizardService.cs" />
|
||||||
<Compile Include="Subtitles\SubtitleService.cs" />
|
<Compile Include="Subtitles\SubtitleService.cs" />
|
||||||
<Compile Include="Movies\CollectionService.cs" />
|
<Compile Include="Movies\CollectionService.cs" />
|
||||||
|
47
MediaBrowser.Api/Reports/Common/HeaderMetadata.cs
Normal file
47
MediaBrowser.Api/Reports/Common/HeaderMetadata.cs
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Api.Reports
|
||||||
|
{
|
||||||
|
public enum HeaderMetadata
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
Name,
|
||||||
|
PremiereDate,
|
||||||
|
DateAdded,
|
||||||
|
ReleaseDate,
|
||||||
|
Runtime,
|
||||||
|
PlayCount,
|
||||||
|
Season,
|
||||||
|
SeasonNumber,
|
||||||
|
Series,
|
||||||
|
Network,
|
||||||
|
Year,
|
||||||
|
ParentalRating,
|
||||||
|
CommunityRating,
|
||||||
|
Trailers,
|
||||||
|
Specials,
|
||||||
|
GameSystem,
|
||||||
|
Players,
|
||||||
|
AlbumArtist,
|
||||||
|
Album,
|
||||||
|
Disc,
|
||||||
|
Track,
|
||||||
|
Audio,
|
||||||
|
EmbeddedImage,
|
||||||
|
Video,
|
||||||
|
Resolution,
|
||||||
|
Subtitles,
|
||||||
|
Genres,
|
||||||
|
Countries,
|
||||||
|
StatusImage,
|
||||||
|
Tracks,
|
||||||
|
EpisodeSeries,
|
||||||
|
EpisodeSeason,
|
||||||
|
AudioAlbumArtist,
|
||||||
|
MusicArtist,
|
||||||
|
AudioAlbum,
|
||||||
|
Status
|
||||||
|
}
|
||||||
|
}
|
20
MediaBrowser.Api/Reports/Common/ItemViewType.cs
Normal file
20
MediaBrowser.Api/Reports/Common/ItemViewType.cs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Api.Reports
|
||||||
|
{
|
||||||
|
public enum ItemViewType
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
Detail,
|
||||||
|
Edit,
|
||||||
|
List,
|
||||||
|
ItemByNameDetails,
|
||||||
|
StatusImage,
|
||||||
|
EmbeddedImage,
|
||||||
|
SubtitleImage,
|
||||||
|
TrailersImage,
|
||||||
|
SpecialsImage
|
||||||
|
}
|
||||||
|
}
|
229
MediaBrowser.Api/Reports/Common/ReportBuilderBase.cs
Normal file
229
MediaBrowser.Api/Reports/Common/ReportBuilderBase.cs
Normal file
@ -0,0 +1,229 @@
|
|||||||
|
using MediaBrowser.Controller.Entities;
|
||||||
|
using MediaBrowser.Controller.Entities.Audio;
|
||||||
|
using MediaBrowser.Controller.Entities.TV;
|
||||||
|
using MediaBrowser.Controller.Library;
|
||||||
|
using MediaBrowser.Model.Channels;
|
||||||
|
using MediaBrowser.Model.Dto;
|
||||||
|
using MediaBrowser.Model.Entities;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Api.Reports
|
||||||
|
{
|
||||||
|
/// <summary> A report builder base. </summary>
|
||||||
|
public class ReportBuilderBase
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the MediaBrowser.Api.Reports.ReportBuilderBase class. </summary>
|
||||||
|
/// <param name="libraryManager"> Manager for library. </param>
|
||||||
|
public ReportBuilderBase(ILibraryManager libraryManager)
|
||||||
|
{
|
||||||
|
_libraryManager = libraryManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary> Manager for library. </summary>
|
||||||
|
protected readonly ILibraryManager _libraryManager;
|
||||||
|
|
||||||
|
/// <summary> Gets audio stream. </summary>
|
||||||
|
/// <param name="item"> The item. </param>
|
||||||
|
/// <returns> The audio stream. </returns>
|
||||||
|
protected string GetAudioStream(BaseItem item)
|
||||||
|
{
|
||||||
|
var stream = GetStream(item, MediaStreamType.Audio);
|
||||||
|
if (stream != null)
|
||||||
|
return stream.Codec.ToUpper() == "DCA" ? stream.Profile : stream.Codec.
|
||||||
|
ToUpper();
|
||||||
|
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary> Gets an episode. </summary>
|
||||||
|
/// <param name="item"> The item. </param>
|
||||||
|
/// <returns> The episode. </returns>
|
||||||
|
protected string GetEpisode(BaseItem item)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (item.GetClientTypeName() == ChannelMediaContentType.Episode.ToString() && item.ParentIndexNumber != null)
|
||||||
|
return "Season " + item.ParentIndexNumber;
|
||||||
|
else
|
||||||
|
return item.Name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary> Gets a genre. </summary>
|
||||||
|
/// <param name="name"> The name. </param>
|
||||||
|
/// <returns> The genre. </returns>
|
||||||
|
protected Genre GetGenre(string name)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(name))
|
||||||
|
return null;
|
||||||
|
return _libraryManager.GetGenre(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary> Gets genre identifier. </summary>
|
||||||
|
/// <param name="name"> The name. </param>
|
||||||
|
/// <returns> The genre identifier. </returns>
|
||||||
|
protected string GetGenreID(string name)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(name))
|
||||||
|
return string.Empty;
|
||||||
|
return string.Format("{0:N}",
|
||||||
|
GetGenre(name).Id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary> Gets list as string. </summary>
|
||||||
|
/// <param name="items"> The items. </param>
|
||||||
|
/// <returns> The list as string. </returns>
|
||||||
|
protected string GetListAsString(List<string> items)
|
||||||
|
{
|
||||||
|
return String.Join("; ", items);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary> Gets media source information. </summary>
|
||||||
|
/// <param name="item"> The item. </param>
|
||||||
|
/// <returns> The media source information. </returns>
|
||||||
|
protected MediaSourceInfo GetMediaSourceInfo(BaseItem item)
|
||||||
|
{
|
||||||
|
var mediaSource = item as IHasMediaSources;
|
||||||
|
if (mediaSource != null)
|
||||||
|
return mediaSource.GetMediaSources(false).FirstOrDefault(n => n.Type == MediaSourceType.Default);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary> Gets an object. </summary>
|
||||||
|
/// <typeparam name="T"> Generic type parameter. </typeparam>
|
||||||
|
/// <typeparam name="R"> Type of the r. </typeparam>
|
||||||
|
/// <param name="item"> The item. </param>
|
||||||
|
/// <param name="function"> The function. </param>
|
||||||
|
/// <param name="defaultValue"> The default value. </param>
|
||||||
|
/// <returns> The object. </returns>
|
||||||
|
protected R GetObject<T, R>(BaseItem item, Func<T, R> function, R defaultValue = default(R)) where T : class
|
||||||
|
{
|
||||||
|
var value = item as T;
|
||||||
|
if (value != null && function != null)
|
||||||
|
return function(value);
|
||||||
|
else
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary> Gets a person. </summary>
|
||||||
|
/// <param name="name"> The name. </param>
|
||||||
|
/// <returns> The person. </returns>
|
||||||
|
protected Person GetPerson(string name)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(name))
|
||||||
|
return null;
|
||||||
|
return _libraryManager.GetPerson(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary> Gets person identifier. </summary>
|
||||||
|
/// <param name="name"> The name. </param>
|
||||||
|
/// <returns> The person identifier. </returns>
|
||||||
|
protected string GetPersonID(string name)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(name))
|
||||||
|
return string.Empty;
|
||||||
|
return string.Format("{0:N}",
|
||||||
|
GetPerson(name).Id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary> Gets runtime date time. </summary>
|
||||||
|
/// <param name="runtime"> The runtime. </param>
|
||||||
|
/// <returns> The runtime date time. </returns>
|
||||||
|
protected DateTime? GetRuntimeDateTime(long? runtime)
|
||||||
|
{
|
||||||
|
if (runtime.HasValue)
|
||||||
|
return new DateTime(runtime.Value);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary> Gets series production year. </summary>
|
||||||
|
/// <param name="item"> The item. </param>
|
||||||
|
/// <returns> The series production year. </returns>
|
||||||
|
protected string GetSeriesProductionYear(BaseItem item)
|
||||||
|
{
|
||||||
|
|
||||||
|
string productionYear = item.ProductionYear.ToString();
|
||||||
|
var series = item as Series;
|
||||||
|
if (series == null)
|
||||||
|
{
|
||||||
|
if (item.ProductionYear == null || item.ProductionYear == 0)
|
||||||
|
return string.Empty;
|
||||||
|
return productionYear;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (series.Status == SeriesStatus.Continuing)
|
||||||
|
return productionYear += "-Present";
|
||||||
|
|
||||||
|
if (series.EndDate != null && series.EndDate.Value.Year != series.ProductionYear)
|
||||||
|
return productionYear += "-" + series.EndDate.Value.Year;
|
||||||
|
|
||||||
|
return productionYear;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary> Gets a stream. </summary>
|
||||||
|
/// <param name="item"> The item. </param>
|
||||||
|
/// <param name="streamType"> Type of the stream. </param>
|
||||||
|
/// <returns> The stream. </returns>
|
||||||
|
protected MediaStream GetStream(BaseItem item, MediaStreamType streamType)
|
||||||
|
{
|
||||||
|
var itemInfo = GetMediaSourceInfo(item);
|
||||||
|
if (itemInfo != null)
|
||||||
|
return itemInfo.MediaStreams.FirstOrDefault(n => n.Type == streamType);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary> Gets a studio. </summary>
|
||||||
|
/// <param name="name"> The name. </param>
|
||||||
|
/// <returns> The studio. </returns>
|
||||||
|
protected Studio GetStudio(string name)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(name))
|
||||||
|
return null;
|
||||||
|
return _libraryManager.GetStudio(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary> Gets studio identifier. </summary>
|
||||||
|
/// <param name="name"> The name. </param>
|
||||||
|
/// <returns> The studio identifier. </returns>
|
||||||
|
protected string GetStudioID(string name)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(name))
|
||||||
|
return string.Empty;
|
||||||
|
return string.Format("{0:N}",
|
||||||
|
GetStudio(name).Id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary> Gets video resolution. </summary>
|
||||||
|
/// <param name="item"> The item. </param>
|
||||||
|
/// <returns> The video resolution. </returns>
|
||||||
|
protected string GetVideoResolution(BaseItem item)
|
||||||
|
{
|
||||||
|
var stream = GetStream(item,
|
||||||
|
MediaStreamType.Video);
|
||||||
|
if (stream != null && stream.Width != null)
|
||||||
|
return string.Format("{0} * {1}",
|
||||||
|
stream.Width,
|
||||||
|
(stream.Height != null ? stream.Height.ToString() : "-"));
|
||||||
|
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary> Gets video stream. </summary>
|
||||||
|
/// <param name="item"> The item. </param>
|
||||||
|
/// <returns> The video stream. </returns>
|
||||||
|
protected string GetVideoStream(BaseItem item)
|
||||||
|
{
|
||||||
|
var stream = GetStream(item, MediaStreamType.Video);
|
||||||
|
if (stream != null)
|
||||||
|
return stream.Codec.ToUpper();
|
||||||
|
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
12
MediaBrowser.Api/Reports/Common/ReportExportType.cs
Normal file
12
MediaBrowser.Api/Reports/Common/ReportExportType.cs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Api.Reports
|
||||||
|
{
|
||||||
|
public enum ReportExportType
|
||||||
|
{
|
||||||
|
CSV,
|
||||||
|
Excel
|
||||||
|
}
|
||||||
|
}
|
18
MediaBrowser.Api/Reports/Common/ReportFieldType.cs
Normal file
18
MediaBrowser.Api/Reports/Common/ReportFieldType.cs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Api.Reports
|
||||||
|
{
|
||||||
|
public enum ReportFieldType
|
||||||
|
{
|
||||||
|
String,
|
||||||
|
Boolean,
|
||||||
|
Date,
|
||||||
|
Time,
|
||||||
|
DateTime,
|
||||||
|
Int,
|
||||||
|
Image,
|
||||||
|
Object
|
||||||
|
}
|
||||||
|
}
|
12
MediaBrowser.Api/Reports/Common/ReportHeaderIdType.cs
Normal file
12
MediaBrowser.Api/Reports/Common/ReportHeaderIdType.cs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Api.Reports
|
||||||
|
{
|
||||||
|
public enum ReportHeaderIdType
|
||||||
|
{
|
||||||
|
Row,
|
||||||
|
Item
|
||||||
|
}
|
||||||
|
}
|
99
MediaBrowser.Api/Reports/Common/ReportHelper.cs
Normal file
99
MediaBrowser.Api/Reports/Common/ReportHelper.cs
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
using MediaBrowser.Controller.Entities;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Api.Reports
|
||||||
|
{
|
||||||
|
public class ReportHelper
|
||||||
|
{
|
||||||
|
/// <summary> Gets java script localized string. </summary>
|
||||||
|
/// <param name="phrase"> The phrase. </param>
|
||||||
|
/// <returns> The java script localized string. </returns>
|
||||||
|
public static string GetJavaScriptLocalizedString(string phrase)
|
||||||
|
{
|
||||||
|
var dictionary = BaseItem.LocalizationManager.GetJavaScriptLocalizationDictionary(BaseItem.ConfigurationManager.Configuration.UICulture);
|
||||||
|
|
||||||
|
string value;
|
||||||
|
|
||||||
|
if (dictionary.TryGetValue(phrase, out value))
|
||||||
|
{
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return phrase;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary> Gets server localized string. </summary>
|
||||||
|
/// <param name="phrase"> The phrase. </param>
|
||||||
|
/// <returns> The server localized string. </returns>
|
||||||
|
public static string GetServerLocalizedString(string phrase)
|
||||||
|
{
|
||||||
|
return BaseItem.LocalizationManager.GetLocalizedString(phrase, BaseItem.ConfigurationManager.Configuration.UICulture);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary> Gets row type. </summary>
|
||||||
|
/// <param name="rowType"> The type. </param>
|
||||||
|
/// <returns> The row type. </returns>
|
||||||
|
public static ReportViewType GetRowType(string rowType)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(rowType))
|
||||||
|
return ReportViewType.BaseItem;
|
||||||
|
|
||||||
|
ReportViewType rType;
|
||||||
|
|
||||||
|
if (!Enum.TryParse<ReportViewType>(rowType, out rType))
|
||||||
|
return ReportViewType.BaseItem;
|
||||||
|
|
||||||
|
return rType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary> Gets header metadata type. </summary>
|
||||||
|
/// <param name="header"> The header. </param>
|
||||||
|
/// <returns> The header metadata type. </returns>
|
||||||
|
public static HeaderMetadata GetHeaderMetadataType(string header)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(header))
|
||||||
|
return HeaderMetadata.None;
|
||||||
|
|
||||||
|
HeaderMetadata rType;
|
||||||
|
|
||||||
|
if (!Enum.TryParse<HeaderMetadata>(header, out rType))
|
||||||
|
return HeaderMetadata.None;
|
||||||
|
|
||||||
|
return rType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary> Convert field to string. </summary>
|
||||||
|
/// <typeparam name="T"> Generic type parameter. </typeparam>
|
||||||
|
/// <param name="value"> The value. </param>
|
||||||
|
/// <param name="fieldType"> Type of the field. </param>
|
||||||
|
/// <returns> The field converted to string. </returns>
|
||||||
|
public static string ConvertToString<T>(T value, ReportFieldType fieldType)
|
||||||
|
{
|
||||||
|
if (value == null)
|
||||||
|
return "";
|
||||||
|
switch (fieldType)
|
||||||
|
{
|
||||||
|
case ReportFieldType.String:
|
||||||
|
return value.ToString();
|
||||||
|
case ReportFieldType.Boolean:
|
||||||
|
return value.ToString();
|
||||||
|
case ReportFieldType.Date:
|
||||||
|
return string.Format("{0:d}", value);
|
||||||
|
case ReportFieldType.Time:
|
||||||
|
return string.Format("{0:t}", value);
|
||||||
|
case ReportFieldType.DateTime:
|
||||||
|
return string.Format("{0:d}", value);
|
||||||
|
case ReportFieldType.Int:
|
||||||
|
return string.Format("", value);
|
||||||
|
default:
|
||||||
|
if (value is Guid)
|
||||||
|
return string.Format("{0:N}", value);
|
||||||
|
return value.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
25
MediaBrowser.Api/Reports/Common/ReportViewType.cs
Normal file
25
MediaBrowser.Api/Reports/Common/ReportViewType.cs
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Api.Reports
|
||||||
|
{
|
||||||
|
public enum ReportViewType
|
||||||
|
{
|
||||||
|
MusicArtist,
|
||||||
|
MusicAlbum,
|
||||||
|
Book,
|
||||||
|
BoxSet,
|
||||||
|
Episode,
|
||||||
|
Game,
|
||||||
|
Video,
|
||||||
|
Movie,
|
||||||
|
MusicVideo,
|
||||||
|
Trailer,
|
||||||
|
Season,
|
||||||
|
Series,
|
||||||
|
Audio,
|
||||||
|
BaseItem,
|
||||||
|
Artist
|
||||||
|
}
|
||||||
|
}
|
589
MediaBrowser.Api/Reports/Data/ReportBuilder.cs
Normal file
589
MediaBrowser.Api/Reports/Data/ReportBuilder.cs
Normal file
@ -0,0 +1,589 @@
|
|||||||
|
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
|
||||||
|
{
|
||||||
|
/// <summary> A report builder. </summary>
|
||||||
|
/// <seealso cref="T:MediaBrowser.Api.Reports.ReportBuilderBase"/>
|
||||||
|
public class ReportBuilder : ReportBuilderBase
|
||||||
|
{
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the MediaBrowser.Api.Reports.ReportBuilder class. </summary>
|
||||||
|
/// <param name="libraryManager"> Manager for library. </param>
|
||||||
|
public ReportBuilder(ILibraryManager libraryManager)
|
||||||
|
: base(libraryManager)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
private Func<bool, string> GetBoolString = s => s == true ? "x" : "";
|
||||||
|
|
||||||
|
public ReportResult GetReportResult(BaseItem[] items, ReportViewType reportRowType, BaseReportRequest request)
|
||||||
|
{
|
||||||
|
List<HeaderMetadata> headersMetadata = this.GetFilteredReportHeaderMetadata(reportRowType, request);
|
||||||
|
|
||||||
|
var headers = GetReportHeaders(reportRowType, headersMetadata);
|
||||||
|
var rows = GetReportRows(items, headersMetadata);
|
||||||
|
|
||||||
|
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 { Genre = g.Trim(), Rows = x })
|
||||||
|
.GroupBy(x => x.Genre)
|
||||||
|
.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;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<ReportHeader> GetReportHeaders(ReportViewType reportRowType, BaseReportRequest request)
|
||||||
|
{
|
||||||
|
List<ReportHeader> headersMetadata = this.GetReportHeaders(reportRowType);
|
||||||
|
if (request != null && !string.IsNullOrEmpty(request.ReportColumns))
|
||||||
|
{
|
||||||
|
List<HeaderMetadata> headersMetadataFiltered = this.GetFilteredReportHeaderMetadata(reportRowType, request);
|
||||||
|
foreach (ReportHeader reportHeader in headersMetadata)
|
||||||
|
{
|
||||||
|
if (!headersMetadataFiltered.Contains(reportHeader.FieldName))
|
||||||
|
{
|
||||||
|
reportHeader.Visible = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return headersMetadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<ReportHeader> GetReportHeaders(ReportViewType reportRowType, List<HeaderMetadata> headersMetadata = null)
|
||||||
|
{
|
||||||
|
if (headersMetadata == null)
|
||||||
|
headersMetadata = this.GetDefaultReportHeaderMetadata(reportRowType);
|
||||||
|
|
||||||
|
List<ReportOptions<BaseItem>> options = new List<ReportOptions<BaseItem>>();
|
||||||
|
foreach (HeaderMetadata header in headersMetadata)
|
||||||
|
{
|
||||||
|
options.Add(GetReportOption(header));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
List<ReportHeader> headers = new List<ReportHeader>();
|
||||||
|
foreach (ReportOptions<BaseItem> option in options)
|
||||||
|
{
|
||||||
|
headers.Add(option.Header);
|
||||||
|
}
|
||||||
|
return headers;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<ReportRow> GetReportRows(IEnumerable<BaseItem> items, List<HeaderMetadata> headersMetadata)
|
||||||
|
{
|
||||||
|
List<ReportOptions<BaseItem>> options = new List<ReportOptions<BaseItem>>();
|
||||||
|
foreach (HeaderMetadata header in headersMetadata)
|
||||||
|
{
|
||||||
|
options.Add(GetReportOption(header));
|
||||||
|
}
|
||||||
|
|
||||||
|
var rows = new List<ReportRow>();
|
||||||
|
|
||||||
|
foreach (BaseItem item in items)
|
||||||
|
{
|
||||||
|
ReportRow rRow = GetRow(item);
|
||||||
|
foreach (ReportOptions<BaseItem> option in options)
|
||||||
|
{
|
||||||
|
object itemColumn = option.Column != null ? option.Column(item, rRow) : "";
|
||||||
|
object itemId = option.ItemID != null ? option.ItemID(item) : "";
|
||||||
|
ReportItem rItem = new ReportItem
|
||||||
|
{
|
||||||
|
Name = ReportHelper.ConvertToString(itemColumn, option.Header.HeaderFieldType),
|
||||||
|
Id = ReportHelper.ConvertToString(itemId, ReportFieldType.Object)
|
||||||
|
};
|
||||||
|
rRow.Columns.Add(rItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
rows.Add(rRow);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rows;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary> Gets a row. </summary>
|
||||||
|
/// <param name="item"> The item. </param>
|
||||||
|
/// <returns> The row. </returns>
|
||||||
|
private ReportRow GetRow(BaseItem item)
|
||||||
|
{
|
||||||
|
var hasTrailers = item as IHasTrailers;
|
||||||
|
var hasSpecialFeatures = item as IHasSpecialFeatures;
|
||||||
|
var video = item as Video;
|
||||||
|
ReportRow rRow = new ReportRow
|
||||||
|
{
|
||||||
|
Id = item.Id.ToString("N"),
|
||||||
|
HasLockData = item.IsLocked,
|
||||||
|
IsUnidentified = item.IsUnidentified,
|
||||||
|
HasLocalTrailer = hasTrailers != null ? hasTrailers.GetTrailerIds().Count() > 0 : false,
|
||||||
|
HasImageTagsPrimary = (item.ImageInfos != null && item.ImageInfos.Count(n => n.Type == ImageType.Primary) > 0),
|
||||||
|
HasImageTagsBackdrop = (item.ImageInfos != null && item.ImageInfos.Count(n => n.Type == ImageType.Backdrop) > 0),
|
||||||
|
HasImageTagsLogo = (item.ImageInfos != null && item.ImageInfos.Count(n => n.Type == ImageType.Logo) > 0),
|
||||||
|
HasSpecials = hasSpecialFeatures != null ? hasSpecialFeatures.SpecialFeatureIds.Count > 0 : false,
|
||||||
|
HasSubtitles = video != null ? video.HasSubtitles : false,
|
||||||
|
RowType = ReportHelper.GetRowType(item.GetClientTypeName())
|
||||||
|
};
|
||||||
|
return rRow;
|
||||||
|
}
|
||||||
|
public List<HeaderMetadata> GetFilteredReportHeaderMetadata(ReportViewType reportRowType, BaseReportRequest request)
|
||||||
|
{
|
||||||
|
if (request != null && !string.IsNullOrEmpty(request.ReportColumns))
|
||||||
|
{
|
||||||
|
var s = request.ReportColumns.Split('|').Select(x => ReportHelper.GetHeaderMetadataType(x)).Where(x => x != HeaderMetadata.None);
|
||||||
|
return s.ToList();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return this.GetDefaultReportHeaderMetadata(reportRowType);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<HeaderMetadata> GetDefaultReportHeaderMetadata(ReportViewType reportRowType)
|
||||||
|
{
|
||||||
|
switch (reportRowType)
|
||||||
|
{
|
||||||
|
case ReportViewType.Season:
|
||||||
|
return new List<HeaderMetadata>
|
||||||
|
{
|
||||||
|
HeaderMetadata.StatusImage,
|
||||||
|
HeaderMetadata.Series,
|
||||||
|
HeaderMetadata.Season,
|
||||||
|
HeaderMetadata.SeasonNumber,
|
||||||
|
HeaderMetadata.DateAdded,
|
||||||
|
HeaderMetadata.Year,
|
||||||
|
HeaderMetadata.Genres
|
||||||
|
};
|
||||||
|
|
||||||
|
case ReportViewType.Series:
|
||||||
|
return new List<HeaderMetadata>
|
||||||
|
{
|
||||||
|
HeaderMetadata.StatusImage,
|
||||||
|
HeaderMetadata.Name,
|
||||||
|
HeaderMetadata.Network,
|
||||||
|
HeaderMetadata.DateAdded,
|
||||||
|
HeaderMetadata.Year,
|
||||||
|
HeaderMetadata.Genres,
|
||||||
|
HeaderMetadata.ParentalRating,
|
||||||
|
HeaderMetadata.CommunityRating,
|
||||||
|
HeaderMetadata.Runtime,
|
||||||
|
HeaderMetadata.Trailers,
|
||||||
|
HeaderMetadata.Specials
|
||||||
|
};
|
||||||
|
|
||||||
|
case ReportViewType.MusicAlbum:
|
||||||
|
return new List<HeaderMetadata>
|
||||||
|
{
|
||||||
|
HeaderMetadata.StatusImage,
|
||||||
|
HeaderMetadata.Name,
|
||||||
|
HeaderMetadata.AlbumArtist,
|
||||||
|
HeaderMetadata.DateAdded,
|
||||||
|
HeaderMetadata.ReleaseDate,
|
||||||
|
HeaderMetadata.Tracks,
|
||||||
|
HeaderMetadata.Year,
|
||||||
|
HeaderMetadata.Genres
|
||||||
|
};
|
||||||
|
|
||||||
|
case ReportViewType.MusicArtist:
|
||||||
|
return new List<HeaderMetadata>
|
||||||
|
{
|
||||||
|
HeaderMetadata.StatusImage,
|
||||||
|
HeaderMetadata.MusicArtist,
|
||||||
|
HeaderMetadata.Countries,
|
||||||
|
HeaderMetadata.DateAdded,
|
||||||
|
HeaderMetadata.Year,
|
||||||
|
HeaderMetadata.Genres
|
||||||
|
};
|
||||||
|
|
||||||
|
case ReportViewType.Game:
|
||||||
|
return new List<HeaderMetadata>
|
||||||
|
{
|
||||||
|
HeaderMetadata.StatusImage,
|
||||||
|
HeaderMetadata.Name,
|
||||||
|
HeaderMetadata.GameSystem,
|
||||||
|
HeaderMetadata.DateAdded,
|
||||||
|
HeaderMetadata.ReleaseDate,
|
||||||
|
HeaderMetadata.ParentalRating,
|
||||||
|
HeaderMetadata.CommunityRating,
|
||||||
|
HeaderMetadata.Players,
|
||||||
|
HeaderMetadata.Year,
|
||||||
|
HeaderMetadata.Genres,
|
||||||
|
HeaderMetadata.Trailers
|
||||||
|
};
|
||||||
|
|
||||||
|
case ReportViewType.Movie:
|
||||||
|
return new List<HeaderMetadata>
|
||||||
|
{
|
||||||
|
HeaderMetadata.StatusImage,
|
||||||
|
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 ReportViewType.Book:
|
||||||
|
return new List<HeaderMetadata>
|
||||||
|
{
|
||||||
|
HeaderMetadata.StatusImage,
|
||||||
|
HeaderMetadata.Name,
|
||||||
|
HeaderMetadata.DateAdded,
|
||||||
|
HeaderMetadata.ReleaseDate,
|
||||||
|
HeaderMetadata.Year,
|
||||||
|
HeaderMetadata.Genres,
|
||||||
|
HeaderMetadata.ParentalRating,
|
||||||
|
HeaderMetadata.CommunityRating
|
||||||
|
};
|
||||||
|
|
||||||
|
case ReportViewType.BoxSet:
|
||||||
|
return new List<HeaderMetadata>
|
||||||
|
{
|
||||||
|
HeaderMetadata.StatusImage,
|
||||||
|
HeaderMetadata.Name,
|
||||||
|
HeaderMetadata.DateAdded,
|
||||||
|
HeaderMetadata.ReleaseDate,
|
||||||
|
HeaderMetadata.Year,
|
||||||
|
HeaderMetadata.Genres,
|
||||||
|
HeaderMetadata.ParentalRating,
|
||||||
|
HeaderMetadata.CommunityRating,
|
||||||
|
HeaderMetadata.Trailers
|
||||||
|
};
|
||||||
|
|
||||||
|
case ReportViewType.Audio:
|
||||||
|
return new List<HeaderMetadata>
|
||||||
|
{
|
||||||
|
HeaderMetadata.StatusImage,
|
||||||
|
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 ReportViewType.Episode:
|
||||||
|
return new List<HeaderMetadata>
|
||||||
|
{
|
||||||
|
HeaderMetadata.StatusImage,
|
||||||
|
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 ReportViewType.Video:
|
||||||
|
case ReportViewType.MusicVideo:
|
||||||
|
case ReportViewType.Trailer:
|
||||||
|
case ReportViewType.BaseItem:
|
||||||
|
default:
|
||||||
|
return new List<HeaderMetadata>
|
||||||
|
{
|
||||||
|
HeaderMetadata.StatusImage,
|
||||||
|
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
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary> Gets report option. </summary>
|
||||||
|
/// <param name="header"> The header. </param>
|
||||||
|
/// <param name="sortField"> The sort field. </param>
|
||||||
|
/// <returns> The report option. </returns>
|
||||||
|
private ReportOptions<BaseItem> GetReportOption(HeaderMetadata header, string sortField = "")
|
||||||
|
{
|
||||||
|
ReportHeader reportHeader = new ReportHeader
|
||||||
|
{
|
||||||
|
HeaderFieldType = ReportFieldType.String,
|
||||||
|
SortField = sortField,
|
||||||
|
Type = "",
|
||||||
|
ItemViewType = ItemViewType.None
|
||||||
|
};
|
||||||
|
|
||||||
|
Func<BaseItem, ReportRow, object> column = null;
|
||||||
|
Func<BaseItem, object> itemId = null;
|
||||||
|
HeaderMetadata internalHeader = header;
|
||||||
|
|
||||||
|
switch (header)
|
||||||
|
{
|
||||||
|
case HeaderMetadata.StatusImage:
|
||||||
|
reportHeader.ItemViewType = ItemViewType.StatusImage;
|
||||||
|
internalHeader = HeaderMetadata.Status;
|
||||||
|
reportHeader.CanGroup = false;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HeaderMetadata.Name:
|
||||||
|
column = (i, r) => i.Name;
|
||||||
|
reportHeader.ItemViewType = ItemViewType.Detail;
|
||||||
|
reportHeader.SortField = "SortName";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HeaderMetadata.DateAdded:
|
||||||
|
column = (i, r) => i.DateCreated;
|
||||||
|
reportHeader.SortField = "DateCreated,SortName";
|
||||||
|
reportHeader.HeaderFieldType = ReportFieldType.DateTime;
|
||||||
|
reportHeader.Type = "";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HeaderMetadata.PremiereDate:
|
||||||
|
case HeaderMetadata.ReleaseDate:
|
||||||
|
column = (i, r) => i.PremiereDate;
|
||||||
|
reportHeader.HeaderFieldType = ReportFieldType.DateTime;
|
||||||
|
reportHeader.SortField = "ProductionYear,PremiereDate,SortName";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HeaderMetadata.Runtime:
|
||||||
|
column = (i, r) => this.GetRuntimeDateTime(i.RunTimeTicks);
|
||||||
|
reportHeader.HeaderFieldType = ReportFieldType.Time;
|
||||||
|
reportHeader.SortField = "Runtime,SortName";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HeaderMetadata.PlayCount:
|
||||||
|
reportHeader.HeaderFieldType = ReportFieldType.Int;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HeaderMetadata.Season:
|
||||||
|
column = (i, r) => this.GetEpisode(i);
|
||||||
|
reportHeader.ItemViewType = ItemViewType.Detail;
|
||||||
|
reportHeader.SortField = "SortName";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HeaderMetadata.SeasonNumber:
|
||||||
|
column = (i, r) => i.IndexNumber;
|
||||||
|
reportHeader.SortField = "IndexNumber";
|
||||||
|
reportHeader.HeaderFieldType = ReportFieldType.Int;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HeaderMetadata.Series:
|
||||||
|
column = (i, r) => this.GetObject<IHasSeries, string>(i, (x) => x.SeriesName);
|
||||||
|
reportHeader.ItemViewType = ItemViewType.Detail;
|
||||||
|
reportHeader.SortField = "SeriesSortName,SortName";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HeaderMetadata.EpisodeSeries:
|
||||||
|
column = (i, r) => this.GetObject<IHasSeries, string>(i, (x) => x.SeriesName);
|
||||||
|
reportHeader.ItemViewType = ItemViewType.Detail;
|
||||||
|
itemId = (i) =>
|
||||||
|
{
|
||||||
|
Series series = this.GetObject<Episode, Series>(i, (x) => x.Series);
|
||||||
|
if (series == null)
|
||||||
|
return string.Empty;
|
||||||
|
return series.Id;
|
||||||
|
};
|
||||||
|
reportHeader.SortField = "SeriesSortName,SortName";
|
||||||
|
internalHeader = HeaderMetadata.Series;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HeaderMetadata.EpisodeSeason:
|
||||||
|
column = (i, r) => this.GetObject<IHasSeries, string>(i, (x) => x.SeriesName);
|
||||||
|
reportHeader.ItemViewType = ItemViewType.Detail;
|
||||||
|
itemId = (i) =>
|
||||||
|
{
|
||||||
|
Season season = this.GetObject<Episode, Season>(i, (x) => x.Season);
|
||||||
|
if (season == null)
|
||||||
|
return string.Empty;
|
||||||
|
return season.Id;
|
||||||
|
};
|
||||||
|
reportHeader.SortField = "SortName";
|
||||||
|
internalHeader = HeaderMetadata.Season;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HeaderMetadata.Network:
|
||||||
|
column = (i, r) => this.GetListAsString(i.Studios);
|
||||||
|
itemId = (i) => this.GetStudioID(i.Studios.FirstOrDefault());
|
||||||
|
reportHeader.ItemViewType = ItemViewType.ItemByNameDetails;
|
||||||
|
reportHeader.SortField = "Studio,SortName";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HeaderMetadata.Year:
|
||||||
|
column = (i, r) => this.GetSeriesProductionYear(i);
|
||||||
|
reportHeader.SortField = "ProductionYear,PremiereDate,SortName";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HeaderMetadata.ParentalRating:
|
||||||
|
column = (i, r) => i.OfficialRating;
|
||||||
|
reportHeader.SortField = "OfficialRating,SortName";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HeaderMetadata.CommunityRating:
|
||||||
|
column = (i, r) => i.CommunityRating;
|
||||||
|
reportHeader.SortField = "CommunityRating,SortName";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HeaderMetadata.Trailers:
|
||||||
|
column = (i, r) => this.GetBoolString(r.HasLocalTrailer);
|
||||||
|
reportHeader.ItemViewType = ItemViewType.TrailersImage;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HeaderMetadata.Specials:
|
||||||
|
column = (i, r) => this.GetBoolString(r.HasSpecials);
|
||||||
|
reportHeader.ItemViewType = ItemViewType.SpecialsImage;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HeaderMetadata.GameSystem:
|
||||||
|
column = (i, r) => this.GetObject<Game, string>(i, (x) => x.GameSystem);
|
||||||
|
reportHeader.SortField = "GameSystem,SortName";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HeaderMetadata.Players:
|
||||||
|
column = (i, r) => this.GetObject<Game, int?>(i, (x) => x.PlayersSupported);
|
||||||
|
reportHeader.SortField = "Players,GameSystem,SortName";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HeaderMetadata.AlbumArtist:
|
||||||
|
column = (i, r) => this.GetObject<MusicAlbum, string>(i, (x) => x.AlbumArtist);
|
||||||
|
itemId = (i) => this.GetPersonID(this.GetObject<MusicAlbum, string>(i, (x) => x.AlbumArtist));
|
||||||
|
reportHeader.ItemViewType = ItemViewType.Detail;
|
||||||
|
reportHeader.SortField = "AlbumArtist,Album,SortName";
|
||||||
|
|
||||||
|
break;
|
||||||
|
case HeaderMetadata.MusicArtist:
|
||||||
|
column = (i, r) => this.GetObject<MusicArtist, string>(i, (x) => x.GetLookupInfo().Name);
|
||||||
|
reportHeader.ItemViewType = ItemViewType.Detail;
|
||||||
|
reportHeader.SortField = "AlbumArtist,Album,SortName";
|
||||||
|
internalHeader = HeaderMetadata.AlbumArtist;
|
||||||
|
break;
|
||||||
|
case HeaderMetadata.AudioAlbumArtist:
|
||||||
|
column = (i, r) => this.GetListAsString(this.GetObject<Audio, List<string>>(i, (x) => x.AlbumArtists));
|
||||||
|
reportHeader.SortField = "AlbumArtist,Album,SortName";
|
||||||
|
internalHeader = HeaderMetadata.AlbumArtist;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HeaderMetadata.AudioAlbum:
|
||||||
|
column = (i, r) => this.GetObject<Audio, string>(i, (x) => x.Album);
|
||||||
|
reportHeader.SortField = "Album,SortName";
|
||||||
|
internalHeader = HeaderMetadata.Album;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HeaderMetadata.Countries:
|
||||||
|
column = (i, r) => this.GetListAsString(this.GetObject<IHasProductionLocations, List<string>>(i, (x) => x.ProductionLocations));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HeaderMetadata.Disc:
|
||||||
|
column = (i, r) => i.ParentIndexNumber;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HeaderMetadata.Track:
|
||||||
|
column = (i, r) => i.IndexNumber;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HeaderMetadata.Tracks:
|
||||||
|
column = (i, r) => this.GetObject<MusicAlbum, List<Audio>>(i, (x) => x.Tracks.ToList(), new List<Audio>()).Count();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HeaderMetadata.Audio:
|
||||||
|
column = (i, r) => this.GetAudioStream(i);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HeaderMetadata.EmbeddedImage:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HeaderMetadata.Video:
|
||||||
|
column = (i, r) => this.GetVideoStream(i);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HeaderMetadata.Resolution:
|
||||||
|
column = (i, r) => this.GetVideoResolution(i);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HeaderMetadata.Subtitles:
|
||||||
|
column = (i, r) => this.GetBoolString(r.HasSubtitles);
|
||||||
|
reportHeader.ItemViewType = ItemViewType.SubtitleImage;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HeaderMetadata.Genres:
|
||||||
|
column = (i, r) => this.GetListAsString(i.Genres);
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
string headerName = "";
|
||||||
|
if (internalHeader != HeaderMetadata.None)
|
||||||
|
{
|
||||||
|
string localHeader = "Header" + internalHeader.ToString();
|
||||||
|
headerName = internalHeader != HeaderMetadata.None ? ReportHelper.GetJavaScriptLocalizedString(localHeader) : "";
|
||||||
|
if (string.Compare(localHeader, headerName, StringComparison.CurrentCultureIgnoreCase) == 0)
|
||||||
|
headerName = ReportHelper.GetServerLocalizedString(localHeader);
|
||||||
|
}
|
||||||
|
|
||||||
|
reportHeader.Name = headerName;
|
||||||
|
reportHeader.FieldName = header;
|
||||||
|
ReportOptions<BaseItem> option = new ReportOptions<BaseItem>()
|
||||||
|
{
|
||||||
|
Header = reportHeader,
|
||||||
|
Column = column,
|
||||||
|
ItemID = itemId
|
||||||
|
};
|
||||||
|
return option;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
210
MediaBrowser.Api/Reports/Data/ReportExport.cs
Normal file
210
MediaBrowser.Api/Reports/Data/ReportExport.cs
Normal file
@ -0,0 +1,210 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Api.Reports
|
||||||
|
{
|
||||||
|
/// <summary> A report export. </summary>
|
||||||
|
public class ReportExport
|
||||||
|
{
|
||||||
|
/// <summary> Export to CSV. </summary>
|
||||||
|
/// <param name="reportResult"> The report result. </param>
|
||||||
|
/// <returns> A string. </returns>
|
||||||
|
public string ExportToCsv(ReportResult reportResult)
|
||||||
|
{
|
||||||
|
StringBuilder returnValue = new StringBuilder();
|
||||||
|
|
||||||
|
returnValue.AppendLine(string.Join(";", reportResult.Headers.Select(s => s.Name.Replace(',', ' ')).ToArray()));
|
||||||
|
|
||||||
|
if (reportResult.IsGrouped)
|
||||||
|
foreach (ReportGroup group in reportResult.Groups)
|
||||||
|
{
|
||||||
|
foreach (ReportRow row in reportResult.Rows)
|
||||||
|
{
|
||||||
|
returnValue.AppendLine(string.Join(";", row.Columns.Select(s => s.Name.Replace(',', ' ')).ToArray()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
foreach (ReportRow row in reportResult.Rows)
|
||||||
|
{
|
||||||
|
returnValue.AppendLine(string.Join(";", row.Columns.Select(s => s.Name.Replace(',', ' ')).ToArray()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return returnValue.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary> Export to excel. </summary>
|
||||||
|
/// <param name="reportResult"> The report result. </param>
|
||||||
|
/// <returns> A string. </returns>
|
||||||
|
public string ExportToExcel(ReportResult reportResult)
|
||||||
|
{
|
||||||
|
|
||||||
|
string style = @"<style type='text/css'>
|
||||||
|
BODY {
|
||||||
|
font-family: Arial;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
TABLE {
|
||||||
|
font-family: Arial;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
A {
|
||||||
|
font-family: Arial;
|
||||||
|
color: #144A86;
|
||||||
|
font-size: 12px;
|
||||||
|
cursor: pointer;
|
||||||
|
text-decoration: none;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
DIV {
|
||||||
|
font-family: Arial;
|
||||||
|
font-size: 12px;
|
||||||
|
margin-bottom: 0px;
|
||||||
|
}
|
||||||
|
P, LI, DIV {
|
||||||
|
font-size: 12px;
|
||||||
|
margin-bottom: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
P, UL {
|
||||||
|
font-size: 12px;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
margin-top: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
H1 {
|
||||||
|
font-size: 18pt;
|
||||||
|
}
|
||||||
|
|
||||||
|
H2 {
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 14pt;
|
||||||
|
COLOR: #C0C0C0;
|
||||||
|
}
|
||||||
|
|
||||||
|
H3 {
|
||||||
|
font-weight: normal;
|
||||||
|
font-size: 14pt;
|
||||||
|
text-indent: +1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
H4 {
|
||||||
|
font-size: 10pt;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
H5 {
|
||||||
|
font-size: 10pt;
|
||||||
|
font-weight: normal;
|
||||||
|
background: #A9A9A9;
|
||||||
|
COLOR: white;
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
|
||||||
|
H6 {
|
||||||
|
padding: 2 1 2 5;
|
||||||
|
font-size: 11px;
|
||||||
|
font-weight: bold;
|
||||||
|
text-decoration: none;
|
||||||
|
margin-bottom: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
UL {
|
||||||
|
line-height: 1.5em;
|
||||||
|
list-style-type: disc;
|
||||||
|
}
|
||||||
|
|
||||||
|
OL {
|
||||||
|
line-height: 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
LI {
|
||||||
|
line-height: 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
A IMG {
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.gridtable {
|
||||||
|
color: #333333;
|
||||||
|
border-width: 0.1pt;
|
||||||
|
border-color: #666666;
|
||||||
|
border-collapse: collapse;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.gridtable th {
|
||||||
|
border-width: 0.1pt;
|
||||||
|
padding: 8px;
|
||||||
|
border-style: solid;
|
||||||
|
border-color: #666666;
|
||||||
|
background-color: #dedede;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.gridtable td {
|
||||||
|
border-width: 0.1pt;
|
||||||
|
padding: 8px;
|
||||||
|
border-style: solid;
|
||||||
|
border-color: #666666;
|
||||||
|
background-color: #ffffff;
|
||||||
|
}
|
||||||
|
</style>";
|
||||||
|
|
||||||
|
string Html = @"<!DOCTYPE html>
|
||||||
|
<html xmlns='http://www.w3.org/1999/xhtml'>
|
||||||
|
<head>
|
||||||
|
<meta http-equiv='X-UA-Compatible' content='IE=8, IE=9, IE=10' />
|
||||||
|
<meta charset='utf-8'>
|
||||||
|
<title>Emby Export</title>";
|
||||||
|
Html += "\n" + style + "\n";
|
||||||
|
Html += "</head>\n";
|
||||||
|
Html += "<body>\n";
|
||||||
|
|
||||||
|
StringBuilder returnValue = new StringBuilder();
|
||||||
|
returnValue.AppendLine("<table class='gridtable'>");
|
||||||
|
returnValue.AppendLine("<tr>");
|
||||||
|
returnValue.AppendLine(string.Join("", reportResult.Headers.Select(s => string.Format("<th>{0}</th>", s.Name)).ToArray()));
|
||||||
|
returnValue.AppendLine("</tr>");
|
||||||
|
if (reportResult.IsGrouped)
|
||||||
|
foreach (ReportGroup group in reportResult.Groups)
|
||||||
|
{
|
||||||
|
returnValue.AppendLine("<tr style='background-color: rgb(51, 51, 51);'>");
|
||||||
|
returnValue.AppendLine("<th scope='rowgroup' colspan='" + reportResult.Headers.Count + "'>" + (string.IsNullOrEmpty(group.Name) ? " " : group.Name) + "</th>");
|
||||||
|
returnValue.AppendLine("</tr>");
|
||||||
|
foreach (ReportRow row in group.Rows)
|
||||||
|
{
|
||||||
|
ExportToExcelRow(reportResult, returnValue, row);
|
||||||
|
}
|
||||||
|
returnValue.AppendLine("<tr style='background-color: white;'>");
|
||||||
|
returnValue.AppendLine("<th scope='rowgroup' colspan='" + reportResult.Headers.Count + "'>" + " " + "</th>");
|
||||||
|
returnValue.AppendLine("</tr>");
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
foreach (ReportRow row in reportResult.Rows)
|
||||||
|
{
|
||||||
|
ExportToExcelRow(reportResult, returnValue, row);
|
||||||
|
}
|
||||||
|
returnValue.AppendLine("</table>");
|
||||||
|
|
||||||
|
Html += returnValue.ToString();
|
||||||
|
Html += "</body>";
|
||||||
|
Html += "</html>";
|
||||||
|
return Html;
|
||||||
|
}
|
||||||
|
private static void ExportToExcelRow(ReportResult reportResult,
|
||||||
|
StringBuilder returnValue,
|
||||||
|
ReportRow row)
|
||||||
|
{
|
||||||
|
returnValue.AppendLine("<tr>");
|
||||||
|
returnValue.AppendLine(string.Join("", row.Columns.Select(s => string.Format("<td>{0}</td>", s.Name)).ToArray()));
|
||||||
|
returnValue.AppendLine("</tr>");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
44
MediaBrowser.Api/Reports/Data/ReportGroup.cs
Normal file
44
MediaBrowser.Api/Reports/Data/ReportGroup.cs
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Api.Reports
|
||||||
|
{
|
||||||
|
|
||||||
|
/// <summary> A report group. </summary>
|
||||||
|
public class ReportGroup
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the MediaBrowser.Api.Reports.ReportGroup class. </summary>
|
||||||
|
public ReportGroup()
|
||||||
|
{
|
||||||
|
Rows = new List<ReportRow>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the MediaBrowser.Api.Reports.ReportGroup class. </summary>
|
||||||
|
/// <param name="rows"> The rows. </param>
|
||||||
|
public ReportGroup(List<ReportRow> rows)
|
||||||
|
{
|
||||||
|
Rows = rows;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary> Gets or sets the name. </summary>
|
||||||
|
/// <value> The name. </value>
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
/// <summary> Gets or sets the rows. </summary>
|
||||||
|
/// <value> The rows. </value>
|
||||||
|
public List<ReportRow> Rows { get; set; }
|
||||||
|
|
||||||
|
/// <summary> Returns a string that represents the current object. </summary>
|
||||||
|
/// <returns> A string that represents the current object. </returns>
|
||||||
|
/// <seealso cref="M:System.Object.ToString()"/>
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return Name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
54
MediaBrowser.Api/Reports/Data/ReportHeader.cs
Normal file
54
MediaBrowser.Api/Reports/Data/ReportHeader.cs
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
using MediaBrowser.Controller.Entities;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Api.Reports
|
||||||
|
{
|
||||||
|
/// <summary> A report header. </summary>
|
||||||
|
public class ReportHeader
|
||||||
|
{
|
||||||
|
/// <summary> Initializes a new instance of the ReportHeader class. </summary>
|
||||||
|
public ReportHeader()
|
||||||
|
{
|
||||||
|
ItemViewType = ItemViewType.None;
|
||||||
|
Visible = true;
|
||||||
|
CanGroup = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary> Gets or sets the type of the header field. </summary>
|
||||||
|
/// <value> The type of the header field. </value>
|
||||||
|
public ReportFieldType HeaderFieldType { get; set; }
|
||||||
|
|
||||||
|
/// <summary> Gets or sets the name of the header. </summary>
|
||||||
|
/// <value> The name of the header. </value>
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
/// <summary> Gets or sets the name of the field. </summary>
|
||||||
|
/// <value> The name of the field. </value>
|
||||||
|
public HeaderMetadata FieldName { get; set; }
|
||||||
|
|
||||||
|
/// <summary> Gets or sets the sort field. </summary>
|
||||||
|
/// <value> The sort field. </value>
|
||||||
|
public string SortField { get; set; }
|
||||||
|
|
||||||
|
/// <summary> Gets or sets the type. </summary>
|
||||||
|
/// <value> The type. </value>
|
||||||
|
public string Type { get; set; }
|
||||||
|
|
||||||
|
/// <summary> Gets or sets the type of the item view. </summary>
|
||||||
|
/// <value> The type of the item view. </value>
|
||||||
|
public ItemViewType ItemViewType { get; set; }
|
||||||
|
|
||||||
|
/// <summary> Gets or sets a value indicating whether this object is visible. </summary>
|
||||||
|
/// <value> true if visible, false if not. </value>
|
||||||
|
public bool Visible { get; set; }
|
||||||
|
|
||||||
|
/// <summary> Gets or sets a value indicating whether we can group. </summary>
|
||||||
|
/// <value> true if we can group, false if not. </value>
|
||||||
|
public bool CanGroup { get; set; }
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
34
MediaBrowser.Api/Reports/Data/ReportItem.cs
Normal file
34
MediaBrowser.Api/Reports/Data/ReportItem.cs
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Api.Reports
|
||||||
|
{
|
||||||
|
/// <summary> A report item. </summary>
|
||||||
|
public class ReportItem
|
||||||
|
{
|
||||||
|
/// <summary> Gets or sets the identifier. </summary>
|
||||||
|
/// <value> The identifier. </value>
|
||||||
|
public string Id { get; set; }
|
||||||
|
|
||||||
|
/// <summary> Gets or sets the name. </summary>
|
||||||
|
/// <value> The name. </value>
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
public string Image { get; set; }
|
||||||
|
|
||||||
|
/// <summary> Gets or sets the custom tag. </summary>
|
||||||
|
/// <value> The custom tag. </value>
|
||||||
|
public string CustomTag { get; set; }
|
||||||
|
|
||||||
|
/// <summary> Returns a string that represents the current object. </summary>
|
||||||
|
/// <returns> A string that represents the current object. </returns>
|
||||||
|
/// <seealso cref="M:System.Object.ToString()"/>
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return Name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
52
MediaBrowser.Api/Reports/Data/ReportOptions.cs
Normal file
52
MediaBrowser.Api/Reports/Data/ReportOptions.cs
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
using MediaBrowser.Controller.Entities;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Api.Reports
|
||||||
|
{
|
||||||
|
/// <summary> A report options. </summary>
|
||||||
|
internal class ReportOptions<I>
|
||||||
|
{
|
||||||
|
/// <summary> Initializes a new instance of the ReportOptions class. </summary>
|
||||||
|
public ReportOptions()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary> Initializes a new instance of the ReportOptions class. </summary>
|
||||||
|
/// <param name="header"> . </param>
|
||||||
|
/// <param name="row"> . </param>
|
||||||
|
public ReportOptions(ReportHeader header, Func<I, ReportRow, object> column)
|
||||||
|
{
|
||||||
|
Header = header;
|
||||||
|
Column = column;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the ReportOptions class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="header"></param>
|
||||||
|
/// <param name="column"></param>
|
||||||
|
/// <param name="itemID"></param>
|
||||||
|
public ReportOptions(ReportHeader header, Func<I, ReportRow, object> column, Func<I, object> itemID)
|
||||||
|
{
|
||||||
|
Header = header;
|
||||||
|
Column = column;
|
||||||
|
ItemID = itemID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary> Gets or sets the header. </summary>
|
||||||
|
/// <value> The header. </value>
|
||||||
|
public ReportHeader Header { get; set; }
|
||||||
|
|
||||||
|
/// <summary> Gets or sets the column. </summary>
|
||||||
|
/// <value> The column. </value>
|
||||||
|
public Func<I, ReportRow, object> Column { get; set; }
|
||||||
|
|
||||||
|
/// <summary> Gets or sets the identifier of the item. </summary>
|
||||||
|
/// <value> The identifier of the item. </value>
|
||||||
|
public Func<I, object> ItemID { get; set; }
|
||||||
|
}
|
||||||
|
}
|
53
MediaBrowser.Api/Reports/Data/ReportResult.cs
Normal file
53
MediaBrowser.Api/Reports/Data/ReportResult.cs
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Api.Reports
|
||||||
|
{
|
||||||
|
|
||||||
|
/// <summary> Encapsulates the result of a report. </summary>
|
||||||
|
public class ReportResult
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the MediaBrowser.Api.Reports.ReportResult class. </summary>
|
||||||
|
public ReportResult()
|
||||||
|
{
|
||||||
|
Rows = new List<ReportRow>();
|
||||||
|
Headers = new List<ReportHeader>();
|
||||||
|
Groups = new List<ReportGroup>();
|
||||||
|
TotalRecordCount = 0;
|
||||||
|
IsGrouped = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the MediaBrowser.Api.Reports.ReportResult class. </summary>
|
||||||
|
/// <param name="headers"> The headers. </param>
|
||||||
|
/// <param name="rows"> The rows. </param>
|
||||||
|
public ReportResult(List<ReportHeader> headers, List<ReportRow> rows)
|
||||||
|
{
|
||||||
|
Rows = rows;
|
||||||
|
Headers = headers;
|
||||||
|
TotalRecordCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary> Gets or sets the rows. </summary>
|
||||||
|
/// <value> The rows. </value>
|
||||||
|
public List<ReportRow> Rows { get; set; }
|
||||||
|
|
||||||
|
/// <summary> Gets or sets the headers. </summary>
|
||||||
|
/// <value> The headers. </value>
|
||||||
|
public List<ReportHeader> Headers { get; set; }
|
||||||
|
|
||||||
|
/// <summary> Gets or sets the groups. </summary>
|
||||||
|
/// <value> The groups. </value>
|
||||||
|
public List<ReportGroup> Groups { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary> Gets or sets the number of total records. </summary>
|
||||||
|
/// <value> The total number of record count. </value>
|
||||||
|
public int TotalRecordCount { get; set; }
|
||||||
|
|
||||||
|
/// <summary> Gets or sets the is grouped. </summary>
|
||||||
|
/// <value> The is grouped. </value>
|
||||||
|
public bool IsGrouped { get; set; }
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
71
MediaBrowser.Api/Reports/Data/ReportRow.cs
Normal file
71
MediaBrowser.Api/Reports/Data/ReportRow.cs
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Api.Reports
|
||||||
|
{
|
||||||
|
public class ReportRow
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the ReportRow class.
|
||||||
|
/// </summary>
|
||||||
|
public ReportRow()
|
||||||
|
{
|
||||||
|
Columns = new List<ReportItem>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary> Gets or sets the identifier. </summary>
|
||||||
|
/// <value> The identifier. </value>
|
||||||
|
public string Id { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value indicating whether this object has backdrop image. </summary>
|
||||||
|
/// <value> true if this object has backdrop image, false if not. </value>
|
||||||
|
public bool HasImageTagsBackdrop { get; set; }
|
||||||
|
|
||||||
|
/// <summary> Gets or sets a value indicating whether this object has image tags. </summary>
|
||||||
|
/// <value> true if this object has image tags, false if not. </value>
|
||||||
|
public bool HasImageTagsPrimary { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value indicating whether this object has image tags logo. </summary>
|
||||||
|
/// <value> true if this object has image tags logo, false if not. </value>
|
||||||
|
public bool HasImageTagsLogo { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value indicating whether this object has local trailer. </summary>
|
||||||
|
/// <value> true if this object has local trailer, false if not. </value>
|
||||||
|
public bool HasLocalTrailer { get; set; }
|
||||||
|
|
||||||
|
/// <summary> Gets or sets a value indicating whether this object has lock data. </summary>
|
||||||
|
/// <value> true if this object has lock data, false if not. </value>
|
||||||
|
public bool HasLockData { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value indicating whether this object has embedded image. </summary>
|
||||||
|
/// <value> true if this object has embedded image, false if not. </value>
|
||||||
|
public bool HasEmbeddedImage { get; set; }
|
||||||
|
|
||||||
|
/// <summary> Gets or sets a value indicating whether this object has subtitles. </summary>
|
||||||
|
/// <value> true if this object has subtitles, false if not. </value>
|
||||||
|
public bool HasSubtitles { get; set; }
|
||||||
|
|
||||||
|
/// <summary> Gets or sets a value indicating whether this object has specials. </summary>
|
||||||
|
/// <value> true if this object has specials, false if not. </value>
|
||||||
|
public bool HasSpecials { get; set; }
|
||||||
|
|
||||||
|
/// <summary> Gets or sets a value indicating whether this object is unidentified. </summary>
|
||||||
|
/// <value> true if this object is unidentified, false if not. </value>
|
||||||
|
public bool IsUnidentified { get; set; }
|
||||||
|
|
||||||
|
/// <summary> Gets or sets the columns. </summary>
|
||||||
|
/// <value> The columns. </value>
|
||||||
|
public List<ReportItem> Columns { get; set; }
|
||||||
|
|
||||||
|
/// <summary> Gets or sets the type. </summary>
|
||||||
|
/// <value> The type. </value>
|
||||||
|
public ReportViewType RowType { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -1,9 +0,0 @@
|
|||||||
|
|
||||||
namespace MediaBrowser.Api.Reports
|
|
||||||
{
|
|
||||||
public enum ReportFieldType
|
|
||||||
{
|
|
||||||
String,
|
|
||||||
Boolean
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,33 +1,45 @@
|
|||||||
using ServiceStack;
|
using MediaBrowser.Api.UserLibrary;
|
||||||
|
using MediaBrowser.Controller.Net;
|
||||||
|
using ServiceStack;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace MediaBrowser.Api.Reports
|
namespace MediaBrowser.Api.Reports
|
||||||
{
|
{
|
||||||
public class BaseReportRequest : IReturn<ReportResult>
|
public class BaseReportRequest : GetItems
|
||||||
{
|
{
|
||||||
/// <summary>
|
public bool HasQueryLimit { get; set; }
|
||||||
/// Specify this to localize the search to a specific item or folder. Omit to use the root.
|
public string GroupBy { get; set; }
|
||||||
/// </summary>
|
|
||||||
/// <value>The parent id.</value>
|
|
||||||
[ApiMember(Name = "ParentId", Description = "Specify this to localize the search to a specific item or folder. Omit to use the root", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
|
||||||
public string ParentId { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
public string ReportColumns { get; set; }
|
||||||
/// Skips over a given number of items within the results. Use for paging.
|
}
|
||||||
/// </summary>
|
|
||||||
/// <value>The start index.</value>
|
|
||||||
[ApiMember(Name = "StartIndex", Description = "Optional. The record index to start at. All items with a lower index will be dropped from the results.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
|
|
||||||
public int? StartIndex { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
[Route("/Reports/Items", "GET", Summary = "Gets reports based on library items")]
|
||||||
/// The maximum number of items to return
|
public class GetItemReport : BaseReportRequest, IReturn<ReportResult>
|
||||||
/// </summary>
|
{
|
||||||
/// <value>The limit.</value>
|
|
||||||
[ApiMember(Name = "Limit", Description = "Optional. The maximum number of records to return", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
|
}
|
||||||
public int? Limit { get; set; }
|
|
||||||
}
|
[Route("/Reports/Headers", "GET", Summary = "Gets reports headers based on library items")]
|
||||||
|
public class GetReportHeaders : BaseReportRequest, IReturn<List<ReportHeader>>
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
[Route("/Reports/Statistics", "GET", Summary = "Gets reports statistics based on library items")]
|
||||||
|
public class GetReportStatistics : BaseReportRequest, IReturn<ReportStatResult>
|
||||||
|
{
|
||||||
|
public int? TopItems { get; set; }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
[Route("/Reports/Items/Download", "GET", Summary = "Downloads report")]
|
||||||
|
public class GetReportDownload : BaseReportRequest
|
||||||
|
{
|
||||||
|
public GetReportDownload()
|
||||||
|
{
|
||||||
|
ExportType = ReportExportType.CSV;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ReportExportType ExportType { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
[Route("/Reports/Items", "GET", Summary = "Gets reports based on library items")]
|
|
||||||
public class GetItemReport : BaseReportRequest
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,16 +0,0 @@
|
|||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace MediaBrowser.Api.Reports
|
|
||||||
{
|
|
||||||
public class ReportResult
|
|
||||||
{
|
|
||||||
public List<List<string>> Rows { get; set; }
|
|
||||||
public List<ReportFieldType> Columns { get; set; }
|
|
||||||
|
|
||||||
public ReportResult()
|
|
||||||
{
|
|
||||||
Rows = new List<List<string>>();
|
|
||||||
Columns = new List<ReportFieldType>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
214
MediaBrowser.Api/Reports/Stat/ReportStatBuilder.cs
Normal file
214
MediaBrowser.Api/Reports/Stat/ReportStatBuilder.cs
Normal file
@ -0,0 +1,214 @@
|
|||||||
|
using MediaBrowser.Controller.Entities;
|
||||||
|
using MediaBrowser.Controller.Library;
|
||||||
|
using MediaBrowser.Model.Entities;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Api.Reports
|
||||||
|
{
|
||||||
|
/// <summary> A report stat builder. </summary>
|
||||||
|
/// <seealso cref="T:MediaBrowser.Api.Reports.ReportBuilderBase"/>
|
||||||
|
public class ReportStatBuilder : ReportBuilderBase
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the MediaBrowser.Api.Reports.ReportStatBuilder class. </summary>
|
||||||
|
/// <param name="libraryManager"> Manager for library. </param>
|
||||||
|
public ReportStatBuilder(ILibraryManager libraryManager)
|
||||||
|
: base(libraryManager)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary> Gets report stat result. </summary>
|
||||||
|
/// <param name="items"> The items. </param>
|
||||||
|
/// <param name="reportRowType"> Type of the report row. </param>
|
||||||
|
/// <param name="topItem"> The top item. </param>
|
||||||
|
/// <returns> The report stat result. </returns>
|
||||||
|
public ReportStatResult GetReportStatResult(BaseItem[] items, ReportViewType reportRowType, int topItem = 5)
|
||||||
|
{
|
||||||
|
ReportStatResult result = new ReportStatResult();
|
||||||
|
result = this.GetResultGenres(result, items, topItem);
|
||||||
|
result = this.GetResultStudios(result, items, topItem);
|
||||||
|
result = this.GetResultPersons(result, items, topItem);
|
||||||
|
result = this.GetResultProductionYears(result, items, topItem);
|
||||||
|
result = this.GetResulProductionLocations(result, items, topItem);
|
||||||
|
result = this.GetResultCommunityRatings(result, items, topItem);
|
||||||
|
result = this.GetResultParentalRatings(result, items, topItem);
|
||||||
|
|
||||||
|
switch (reportRowType)
|
||||||
|
{
|
||||||
|
case ReportViewType.Season:
|
||||||
|
case ReportViewType.Series:
|
||||||
|
case ReportViewType.MusicAlbum:
|
||||||
|
case ReportViewType.MusicArtist:
|
||||||
|
case ReportViewType.Game:
|
||||||
|
break;
|
||||||
|
case ReportViewType.Movie:
|
||||||
|
case ReportViewType.BoxSet:
|
||||||
|
|
||||||
|
break;
|
||||||
|
case ReportViewType.Book:
|
||||||
|
case ReportViewType.Episode:
|
||||||
|
case ReportViewType.Video:
|
||||||
|
case ReportViewType.MusicVideo:
|
||||||
|
case ReportViewType.Trailer:
|
||||||
|
case ReportViewType.Audio:
|
||||||
|
case ReportViewType.BaseItem:
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
result.Groups = result.Groups.OrderByDescending(n => n.Items.Count()).ToList();
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ReportStatResult GetResultGenres(ReportStatResult result, BaseItem[] items, int topItem = 5)
|
||||||
|
{
|
||||||
|
this.GetGroups(result, ReportHelper.GetServerLocalizedString("HeaderGenres"), topItem,
|
||||||
|
items.SelectMany(x => x.Genres)
|
||||||
|
.GroupBy(x => x)
|
||||||
|
.OrderByDescending(x => x.Count())
|
||||||
|
.Take(topItem)
|
||||||
|
.Select(x => new ReportStatItem
|
||||||
|
{
|
||||||
|
Name = x.Key,
|
||||||
|
Value = x.Count().ToString(),
|
||||||
|
Id = GetGenreID(x.Key)
|
||||||
|
}));
|
||||||
|
return result;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private ReportStatResult GetResultStudios(ReportStatResult result, BaseItem[] items, int topItem = 5)
|
||||||
|
{
|
||||||
|
this.GetGroups(result, ReportHelper.GetServerLocalizedString("HeaderStudios"), topItem,
|
||||||
|
items.SelectMany(x => x.Studios)
|
||||||
|
.GroupBy(x => x)
|
||||||
|
.OrderByDescending(x => x.Count())
|
||||||
|
.Take(topItem)
|
||||||
|
.Select(x => new ReportStatItem
|
||||||
|
{
|
||||||
|
Name = x.Key,
|
||||||
|
Value = x.Count().ToString(),
|
||||||
|
Id = GetStudioID(x.Key)
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private ReportStatResult GetResultPersons(ReportStatResult result, BaseItem[] items, int topItem = 5)
|
||||||
|
{
|
||||||
|
List<string> t = new List<string> { PersonType.Actor, PersonType.Composer, PersonType.Director, PersonType.GuestStar, PersonType.Producer, PersonType.Writer, "Artist", "AlbumArtist" };
|
||||||
|
foreach (var item in t)
|
||||||
|
{
|
||||||
|
this.GetGroups(result, ReportHelper.GetServerLocalizedString("Option" + item), topItem,
|
||||||
|
items.SelectMany(x => x.People)
|
||||||
|
.Where(n => n.Type == item)
|
||||||
|
.GroupBy(x => x.Name)
|
||||||
|
.OrderByDescending(x => x.Count())
|
||||||
|
.Take(topItem)
|
||||||
|
.Select(x => new ReportStatItem
|
||||||
|
{
|
||||||
|
Name = x.Key,
|
||||||
|
Value = x.Count().ToString(),
|
||||||
|
Id = GetPersonID(x.Key)
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ReportStatResult GetResultCommunityRatings(ReportStatResult result, BaseItem[] items, int topItem = 5)
|
||||||
|
{
|
||||||
|
this.GetGroups(result, ReportHelper.GetServerLocalizedString("LabelCommunityRating"), topItem,
|
||||||
|
items.Where(x => x.CommunityRating != null && x.CommunityRating > 0)
|
||||||
|
.GroupBy(x => x.CommunityRating)
|
||||||
|
.OrderByDescending(x => x.Count())
|
||||||
|
.Take(topItem)
|
||||||
|
.Select(x => new ReportStatItem
|
||||||
|
{
|
||||||
|
Name = x.Key.ToString(),
|
||||||
|
Value = x.Count().ToString()
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ReportStatResult GetResultParentalRatings(ReportStatResult result, BaseItem[] items, int topItem = 5)
|
||||||
|
{
|
||||||
|
this.GetGroups(result, ReportHelper.GetServerLocalizedString("HeaderParentalRatings"), topItem,
|
||||||
|
items.Where(x => x.OfficialRating != null)
|
||||||
|
.GroupBy(x => x.OfficialRating)
|
||||||
|
.OrderByDescending(x => x.Count())
|
||||||
|
.Take(topItem)
|
||||||
|
.Select(x => new ReportStatItem
|
||||||
|
{
|
||||||
|
Name = x.Key.ToString(),
|
||||||
|
Value = x.Count().ToString()
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private ReportStatResult GetResultProductionYears(ReportStatResult result, BaseItem[] items, int topItem = 5)
|
||||||
|
{
|
||||||
|
this.GetGroups(result, ReportHelper.GetServerLocalizedString("HeaderYears"), topItem,
|
||||||
|
items.Where(x => x.ProductionYear != null && x.ProductionYear > 0)
|
||||||
|
.GroupBy(x => x.ProductionYear)
|
||||||
|
.OrderByDescending(x => x.Count())
|
||||||
|
.Take(topItem)
|
||||||
|
.Select(x => new ReportStatItem
|
||||||
|
{
|
||||||
|
Name = x.Key.ToString(),
|
||||||
|
Value = x.Count().ToString()
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ReportStatResult GetResulProductionLocations(ReportStatResult result, BaseItem[] items, int topItem = 5)
|
||||||
|
{
|
||||||
|
this.GetGroups(result, ReportHelper.GetServerLocalizedString("HeaderCountries"), topItem,
|
||||||
|
items.OfType<IHasProductionLocations>()
|
||||||
|
.Where(x => x.ProductionLocations != null)
|
||||||
|
.SelectMany(x => x.ProductionLocations)
|
||||||
|
.GroupBy(x => x)
|
||||||
|
.OrderByDescending(x => x.Count())
|
||||||
|
.Take(topItem)
|
||||||
|
.Select(x => new ReportStatItem
|
||||||
|
{
|
||||||
|
Name = x.Key.ToString(),
|
||||||
|
Value = x.Count().ToString()
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary> Gets the groups. </summary>
|
||||||
|
/// <param name="result"> The result. </param>
|
||||||
|
/// <param name="header"> The header. </param>
|
||||||
|
/// <param name="topItem"> The top item. </param>
|
||||||
|
/// <param name="top"> The top. </param>
|
||||||
|
private void GetGroups(ReportStatResult result, string header, int topItem, IEnumerable<ReportStatItem> top)
|
||||||
|
{
|
||||||
|
if (top.Count() > 0)
|
||||||
|
{
|
||||||
|
var group = new ReportStatGroup { Header = ReportStatGroup.FormatedHeader(header, topItem) };
|
||||||
|
group.Items.AddRange(top);
|
||||||
|
result.Groups.Add(group);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
37
MediaBrowser.Api/Reports/Stat/ReportStatGroup.cs
Normal file
37
MediaBrowser.Api/Reports/Stat/ReportStatGroup.cs
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Api.Reports
|
||||||
|
{
|
||||||
|
/// <summary> A report stat group. </summary>
|
||||||
|
public class ReportStatGroup
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the MediaBrowser.Api.Reports.ReportStatGroup class. </summary>
|
||||||
|
public ReportStatGroup()
|
||||||
|
{
|
||||||
|
Items = new List<ReportStatItem>();
|
||||||
|
TotalRecordCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary> Gets or sets the header. </summary>
|
||||||
|
/// <value> The header. </value>
|
||||||
|
public string Header { get; set; }
|
||||||
|
|
||||||
|
/// <summary> Gets or sets the items. </summary>
|
||||||
|
/// <value> The items. </value>
|
||||||
|
public List<ReportStatItem> Items { get; set; }
|
||||||
|
|
||||||
|
/// <summary> Gets or sets the number of total records. </summary>
|
||||||
|
/// <value> The total number of record count. </value>
|
||||||
|
public int TotalRecordCount { get; set; }
|
||||||
|
|
||||||
|
internal static string FormatedHeader(string header, int topItem)
|
||||||
|
{
|
||||||
|
return string.Format("Top {0} {1}", topItem, header);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
29
MediaBrowser.Api/Reports/Stat/ReportStatItem.cs
Normal file
29
MediaBrowser.Api/Reports/Stat/ReportStatItem.cs
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Api.Reports
|
||||||
|
{
|
||||||
|
/// <summary> A report stat item. </summary>
|
||||||
|
public class ReportStatItem
|
||||||
|
{
|
||||||
|
/// <summary> Gets or sets the name. </summary>
|
||||||
|
/// <value> The name. </value>
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
/// <summary> Gets or sets the image. </summary>
|
||||||
|
/// <value> The image. </value>
|
||||||
|
public string Image { get; set; }
|
||||||
|
|
||||||
|
/// <summary> Gets or sets the value. </summary>
|
||||||
|
/// <value> The value. </value>
|
||||||
|
public string Value { get; set; }
|
||||||
|
|
||||||
|
/// <summary> Gets or sets the identifier. </summary>
|
||||||
|
/// <value> The identifier. </value>
|
||||||
|
public string Id { get; set; }
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
28
MediaBrowser.Api/Reports/Stat/ReportStatResult.cs
Normal file
28
MediaBrowser.Api/Reports/Stat/ReportStatResult.cs
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Api.Reports
|
||||||
|
{
|
||||||
|
/// <summary> Encapsulates the result of a report stat. </summary>
|
||||||
|
public class ReportStatResult
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the MediaBrowser.Api.Reports.ReportStatResult class. </summary>
|
||||||
|
public ReportStatResult()
|
||||||
|
{
|
||||||
|
Groups = new List<ReportStatGroup>();
|
||||||
|
TotalRecordCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary> Gets or sets the groups. </summary>
|
||||||
|
/// <value> The groups. </value>
|
||||||
|
public List<ReportStatGroup> Groups { get; set; }
|
||||||
|
|
||||||
|
/// <summary> Gets or sets the number of total records. </summary>
|
||||||
|
/// <value> The total number of record count. </value>
|
||||||
|
public int TotalRecordCount { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -14,199 +14,199 @@ using WebMarkupMin.Core.Settings;
|
|||||||
|
|
||||||
namespace MediaBrowser.WebDashboard.Api
|
namespace MediaBrowser.WebDashboard.Api
|
||||||
{
|
{
|
||||||
public class PackageCreator
|
public class PackageCreator
|
||||||
{
|
{
|
||||||
private readonly IFileSystem _fileSystem;
|
private readonly IFileSystem _fileSystem;
|
||||||
private readonly ILocalizationManager _localization;
|
private readonly ILocalizationManager _localization;
|
||||||
private readonly ILogger _logger;
|
private readonly ILogger _logger;
|
||||||
private readonly IServerConfigurationManager _config;
|
private readonly IServerConfigurationManager _config;
|
||||||
private readonly IJsonSerializer _jsonSerializer;
|
private readonly IJsonSerializer _jsonSerializer;
|
||||||
|
|
||||||
public PackageCreator(IFileSystem fileSystem, ILocalizationManager localization, ILogger logger, IServerConfigurationManager config, IJsonSerializer jsonSerializer)
|
public PackageCreator(IFileSystem fileSystem, ILocalizationManager localization, ILogger logger, IServerConfigurationManager config, IJsonSerializer jsonSerializer)
|
||||||
{
|
{
|
||||||
_fileSystem = fileSystem;
|
_fileSystem = fileSystem;
|
||||||
_localization = localization;
|
_localization = localization;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_config = config;
|
_config = config;
|
||||||
_jsonSerializer = jsonSerializer;
|
_jsonSerializer = jsonSerializer;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<Stream> GetResource(string path,
|
public async Task<Stream> GetResource(string path,
|
||||||
string localizationCulture,
|
string localizationCulture,
|
||||||
string appVersion, bool enableMinification)
|
string appVersion, bool enableMinification)
|
||||||
{
|
{
|
||||||
var isHtml = IsHtml(path);
|
var isHtml = IsHtml(path);
|
||||||
|
|
||||||
Stream resourceStream;
|
Stream resourceStream;
|
||||||
|
|
||||||
if (path.Equals("scripts/all.js", StringComparison.OrdinalIgnoreCase))
|
if (path.Equals("scripts/all.js", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
resourceStream = await GetAllJavascript(localizationCulture, appVersion, enableMinification).ConfigureAwait(false);
|
resourceStream = await GetAllJavascript(localizationCulture, appVersion, enableMinification).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
else if (path.Equals("css/all.css", StringComparison.OrdinalIgnoreCase))
|
else if (path.Equals("css/all.css", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
resourceStream = await GetAllCss(enableMinification).ConfigureAwait(false);
|
resourceStream = await GetAllCss(enableMinification).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
resourceStream = GetRawResourceStream(path);
|
resourceStream = GetRawResourceStream(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (resourceStream != null)
|
if (resourceStream != null)
|
||||||
{
|
{
|
||||||
// Don't apply any caching for html pages
|
// Don't apply any caching for html pages
|
||||||
// jQuery ajax doesn't seem to handle if-modified-since correctly
|
// jQuery ajax doesn't seem to handle if-modified-since correctly
|
||||||
if (isHtml)
|
if (isHtml)
|
||||||
{
|
{
|
||||||
resourceStream = await ModifyHtml(resourceStream, localizationCulture, enableMinification).ConfigureAwait(false);
|
resourceStream = await ModifyHtml(resourceStream, localizationCulture, enableMinification).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return resourceStream;
|
return resourceStream;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Determines whether the specified path is HTML.
|
/// Determines whether the specified path is HTML.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="path">The path.</param>
|
/// <param name="path">The path.</param>
|
||||||
/// <returns><c>true</c> if the specified path is HTML; otherwise, <c>false</c>.</returns>
|
/// <returns><c>true</c> if the specified path is HTML; otherwise, <c>false</c>.</returns>
|
||||||
private bool IsHtml(string path)
|
private bool IsHtml(string path)
|
||||||
{
|
{
|
||||||
return Path.GetExtension(path).EndsWith("html", StringComparison.OrdinalIgnoreCase);
|
return Path.GetExtension(path).EndsWith("html", StringComparison.OrdinalIgnoreCase);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the dashboard UI path.
|
/// Gets the dashboard UI path.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The dashboard UI path.</value>
|
/// <value>The dashboard UI path.</value>
|
||||||
public string DashboardUIPath
|
public string DashboardUIPath
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (!string.IsNullOrEmpty(_config.Configuration.DashboardSourcePath))
|
if (!string.IsNullOrEmpty(_config.Configuration.DashboardSourcePath))
|
||||||
{
|
{
|
||||||
return _config.Configuration.DashboardSourcePath;
|
return _config.Configuration.DashboardSourcePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Path.Combine(_config.ApplicationPaths.ApplicationResourcesPath, "dashboard-ui");
|
return Path.Combine(_config.ApplicationPaths.ApplicationResourcesPath, "dashboard-ui");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the dashboard resource path.
|
/// Gets the dashboard resource path.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="virtualPath">The virtual path.</param>
|
/// <param name="virtualPath">The virtual path.</param>
|
||||||
/// <returns>System.String.</returns>
|
/// <returns>System.String.</returns>
|
||||||
private string GetDashboardResourcePath(string virtualPath)
|
private string GetDashboardResourcePath(string virtualPath)
|
||||||
{
|
{
|
||||||
return Path.Combine(DashboardUIPath, virtualPath.Replace('/', Path.DirectorySeparatorChar));
|
return Path.Combine(DashboardUIPath, virtualPath.Replace('/', Path.DirectorySeparatorChar));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Modifies the HTML by adding common meta tags, css and js.
|
/// Modifies the HTML by adding common meta tags, css and js.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="sourceStream">The source stream.</param>
|
/// <param name="sourceStream">The source stream.</param>
|
||||||
/// <param name="localizationCulture">The localization culture.</param>
|
/// <param name="localizationCulture">The localization culture.</param>
|
||||||
/// <param name="enableMinification">if set to <c>true</c> [enable minification].</param>
|
/// <param name="enableMinification">if set to <c>true</c> [enable minification].</param>
|
||||||
/// <returns>Task{Stream}.</returns>
|
/// <returns>Task{Stream}.</returns>
|
||||||
public async Task<Stream> ModifyHtml(Stream sourceStream, string localizationCulture, bool enableMinification)
|
public async Task<Stream> ModifyHtml(Stream sourceStream, string localizationCulture, bool enableMinification)
|
||||||
{
|
{
|
||||||
using (sourceStream)
|
using (sourceStream)
|
||||||
{
|
{
|
||||||
string html;
|
string html;
|
||||||
|
|
||||||
using (var memoryStream = new MemoryStream())
|
using (var memoryStream = new MemoryStream())
|
||||||
{
|
{
|
||||||
await sourceStream.CopyToAsync(memoryStream).ConfigureAwait(false);
|
await sourceStream.CopyToAsync(memoryStream).ConfigureAwait(false);
|
||||||
|
|
||||||
html = Encoding.UTF8.GetString(memoryStream.ToArray());
|
html = Encoding.UTF8.GetString(memoryStream.ToArray());
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(localizationCulture))
|
if (!string.IsNullOrWhiteSpace(localizationCulture))
|
||||||
{
|
{
|
||||||
var lang = localizationCulture.Split('-').FirstOrDefault();
|
var lang = localizationCulture.Split('-').FirstOrDefault();
|
||||||
|
|
||||||
html = _localization.LocalizeDocument(html, localizationCulture, GetLocalizationToken);
|
html = _localization.LocalizeDocument(html, localizationCulture, GetLocalizationToken);
|
||||||
|
|
||||||
html = html.Replace("<html>", "<html lang=\"" + lang + "\">");
|
html = html.Replace("<html>", "<html lang=\"" + lang + "\">");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (enableMinification)
|
if (enableMinification)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var minifier = new HtmlMinifier(new HtmlMinificationSettings());
|
var minifier = new HtmlMinifier(new HtmlMinificationSettings());
|
||||||
var result = minifier.Minify(html, false);
|
var result = minifier.Minify(html, false);
|
||||||
|
|
||||||
if (result.Errors.Count > 0)
|
if (result.Errors.Count > 0)
|
||||||
{
|
{
|
||||||
_logger.Error("Error minifying html: " + result.Errors[0].Message);
|
_logger.Error("Error minifying html: " + result.Errors[0].Message);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
html = result.MinifiedContent;
|
html = result.MinifiedContent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
_logger.ErrorException("Error minifying html", ex);
|
_logger.ErrorException("Error minifying html", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var version = GetType().Assembly.GetName().Version;
|
var version = GetType().Assembly.GetName().Version;
|
||||||
|
|
||||||
html = html.Replace("<head>", "<head>" + GetMetaTags() + GetCommonCss(version) + GetCommonJavascript(version));
|
html = html.Replace("<head>", "<head>" + GetMetaTags() + GetCommonCss(version) + GetCommonJavascript(version));
|
||||||
|
|
||||||
var bytes = Encoding.UTF8.GetBytes(html);
|
var bytes = Encoding.UTF8.GetBytes(html);
|
||||||
|
|
||||||
return new MemoryStream(bytes);
|
return new MemoryStream(bytes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetLocalizationToken(string phrase)
|
private string GetLocalizationToken(string phrase)
|
||||||
{
|
{
|
||||||
return "${" + phrase + "}";
|
return "${" + phrase + "}";
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the meta tags.
|
/// Gets the meta tags.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>System.String.</returns>
|
/// <returns>System.String.</returns>
|
||||||
private static string GetMetaTags()
|
private static string GetMetaTags()
|
||||||
{
|
{
|
||||||
var sb = new StringBuilder();
|
var sb = new StringBuilder();
|
||||||
|
|
||||||
sb.Append("<meta http-equiv=\"X-UA-Compatibility\" content=\"IE=Edge\">");
|
sb.Append("<meta http-equiv=\"X-UA-Compatibility\" content=\"IE=Edge\">");
|
||||||
sb.Append("<meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">");
|
sb.Append("<meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">");
|
||||||
//sb.Append("<meta name=\"apple-mobile-web-app-capable\" content=\"yes\">");
|
//sb.Append("<meta name=\"apple-mobile-web-app-capable\" content=\"yes\">");
|
||||||
sb.Append("<meta name=\"mobile-web-app-capable\" content=\"yes\">");
|
sb.Append("<meta name=\"mobile-web-app-capable\" content=\"yes\">");
|
||||||
sb.Append("<meta name=\"application-name\" content=\"Emby\">");
|
sb.Append("<meta name=\"application-name\" content=\"Emby\">");
|
||||||
//sb.Append("<meta name=\"apple-mobile-web-app-status-bar-style\" content=\"black-translucent\">");
|
//sb.Append("<meta name=\"apple-mobile-web-app-status-bar-style\" content=\"black-translucent\">");
|
||||||
|
|
||||||
sb.Append("<meta name=\"robots\" content=\"noindex, nofollow, noarchive\" />");
|
sb.Append("<meta name=\"robots\" content=\"noindex, nofollow, noarchive\" />");
|
||||||
|
|
||||||
// http://developer.apple.com/library/ios/#DOCUMENTATION/AppleApplications/Reference/SafariWebContent/ConfiguringWebApplications/ConfiguringWebApplications.html
|
// http://developer.apple.com/library/ios/#DOCUMENTATION/AppleApplications/Reference/SafariWebContent/ConfiguringWebApplications/ConfiguringWebApplications.html
|
||||||
sb.Append("<link rel=\"apple-touch-icon\" href=\"css/images/touchicon.png\" />");
|
sb.Append("<link rel=\"apple-touch-icon\" href=\"css/images/touchicon.png\" />");
|
||||||
sb.Append("<link rel=\"apple-touch-icon\" sizes=\"72x72\" href=\"css/images/touchicon72.png\" />");
|
sb.Append("<link rel=\"apple-touch-icon\" sizes=\"72x72\" href=\"css/images/touchicon72.png\" />");
|
||||||
sb.Append("<link rel=\"apple-touch-icon\" sizes=\"114x114\" href=\"css/images/touchicon114.png\" />");
|
sb.Append("<link rel=\"apple-touch-icon\" sizes=\"114x114\" href=\"css/images/touchicon114.png\" />");
|
||||||
sb.Append("<link rel=\"apple-touch-startup-image\" href=\"css/images/iossplash.png\" />");
|
sb.Append("<link rel=\"apple-touch-startup-image\" href=\"css/images/iossplash.png\" />");
|
||||||
sb.Append("<link rel=\"shortcut icon\" href=\"css/images/favicon.ico\" />");
|
sb.Append("<link rel=\"shortcut icon\" href=\"css/images/favicon.ico\" />");
|
||||||
sb.Append("<meta name=\"msapplication-TileImage\" content=\"css/images/touchicon144.png\">");
|
sb.Append("<meta name=\"msapplication-TileImage\" content=\"css/images/touchicon144.png\">");
|
||||||
sb.Append("<meta name=\"msapplication-TileColor\" content=\"#23456B\">");
|
sb.Append("<meta name=\"msapplication-TileColor\" content=\"#23456B\">");
|
||||||
|
|
||||||
return sb.ToString();
|
return sb.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the common CSS.
|
/// Gets the common CSS.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="version">The version.</param>
|
/// <param name="version">The version.</param>
|
||||||
/// <returns>System.String.</returns>
|
/// <returns>System.String.</returns>
|
||||||
private string GetCommonCss(Version version)
|
private string GetCommonCss(Version version)
|
||||||
{
|
{
|
||||||
var versionString = "?v=" + version;
|
var versionString = "?v=" + version;
|
||||||
|
|
||||||
var files = new[]
|
var files = new[]
|
||||||
{
|
{
|
||||||
"thirdparty/jquerymobile-1.4.5/jquery.mobile-1.4.5.min.css",
|
"thirdparty/jquerymobile-1.4.5/jquery.mobile-1.4.5.min.css",
|
||||||
"thirdparty/swipebox-master/css/swipebox.min.css" + versionString,
|
"thirdparty/swipebox-master/css/swipebox.min.css" + versionString,
|
||||||
@ -215,68 +215,68 @@ namespace MediaBrowser.WebDashboard.Api
|
|||||||
"css/all.css" + versionString
|
"css/all.css" + versionString
|
||||||
};
|
};
|
||||||
|
|
||||||
var tags = files.Select(s => string.Format("<link rel=\"stylesheet\" href=\"{0}\" />", s)).ToArray();
|
var tags = files.Select(s => string.Format("<link rel=\"stylesheet\" href=\"{0}\" />", s)).ToArray();
|
||||||
|
|
||||||
return string.Join(string.Empty, tags);
|
return string.Join(string.Empty, tags);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the common javascript.
|
/// Gets the common javascript.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="version">The version.</param>
|
/// <param name="version">The version.</param>
|
||||||
/// <returns>System.String.</returns>
|
/// <returns>System.String.</returns>
|
||||||
private string GetCommonJavascript(Version version)
|
private string GetCommonJavascript(Version version)
|
||||||
{
|
{
|
||||||
var builder = new StringBuilder();
|
var builder = new StringBuilder();
|
||||||
|
|
||||||
var versionString = "?v=" + version;
|
var versionString = "?v=" + version;
|
||||||
|
|
||||||
var files = new[]
|
var files = new[]
|
||||||
{
|
{
|
||||||
"scripts/all.js" + versionString,
|
"scripts/all.js" + versionString,
|
||||||
"thirdparty/swipebox-master/js/jquery.swipebox.min.js" + versionString
|
"thirdparty/swipebox-master/js/jquery.swipebox.min.js" + versionString
|
||||||
};
|
};
|
||||||
|
|
||||||
var tags = files.Select(s => string.Format("<script src=\"{0}\"></script>", s)).ToArray();
|
var tags = files.Select(s => string.Format("<script src=\"{0}\"></script>", s)).ToArray();
|
||||||
|
|
||||||
builder.Append(string.Join(string.Empty, tags));
|
builder.Append(string.Join(string.Empty, tags));
|
||||||
|
|
||||||
return builder.ToString();
|
return builder.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a stream containing all concatenated javascript
|
/// Gets a stream containing all concatenated javascript
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>Task{Stream}.</returns>
|
/// <returns>Task{Stream}.</returns>
|
||||||
private async Task<Stream> GetAllJavascript(string culture, string version, bool enableMinification)
|
private async Task<Stream> GetAllJavascript(string culture, string version, bool enableMinification)
|
||||||
{
|
{
|
||||||
var memoryStream = new MemoryStream();
|
var memoryStream = new MemoryStream();
|
||||||
var newLineBytes = Encoding.UTF8.GetBytes(Environment.NewLine);
|
var newLineBytes = Encoding.UTF8.GetBytes(Environment.NewLine);
|
||||||
|
|
||||||
// jQuery + jQuery mobile
|
// jQuery + jQuery mobile
|
||||||
await AppendResource(memoryStream, "thirdparty/jquery-2.1.1.min.js", newLineBytes).ConfigureAwait(false);
|
await AppendResource(memoryStream, "thirdparty/jquery-2.1.1.min.js", newLineBytes).ConfigureAwait(false);
|
||||||
await AppendResource(memoryStream, "thirdparty/jquerymobile-1.4.5/jquery.mobile-1.4.5.min.js", newLineBytes).ConfigureAwait(false);
|
await AppendResource(memoryStream, "thirdparty/jquerymobile-1.4.5/jquery.mobile-1.4.5.min.js", newLineBytes).ConfigureAwait(false);
|
||||||
|
|
||||||
await AppendResource(memoryStream, "thirdparty/jquery.unveil-custom.js", newLineBytes).ConfigureAwait(false);
|
await AppendResource(memoryStream, "thirdparty/jquery.unveil-custom.js", newLineBytes).ConfigureAwait(false);
|
||||||
|
|
||||||
await AppendResource(memoryStream, "thirdparty/cast_sender.js", newLineBytes).ConfigureAwait(false);
|
await AppendResource(memoryStream, "thirdparty/cast_sender.js", newLineBytes).ConfigureAwait(false);
|
||||||
await AppendResource(memoryStream, "thirdparty/browser.js", newLineBytes).ConfigureAwait(false);
|
await AppendResource(memoryStream, "thirdparty/browser.js", newLineBytes).ConfigureAwait(false);
|
||||||
|
|
||||||
await AppendResource(memoryStream, "thirdparty/jstree3.0.8/jstree.js", newLineBytes).ConfigureAwait(false);
|
await AppendResource(memoryStream, "thirdparty/jstree3.0.8/jstree.js", newLineBytes).ConfigureAwait(false);
|
||||||
|
|
||||||
await AppendLocalization(memoryStream, culture).ConfigureAwait(false);
|
await AppendLocalization(memoryStream, culture).ConfigureAwait(false);
|
||||||
await memoryStream.WriteAsync(newLineBytes, 0, newLineBytes.Length).ConfigureAwait(false);
|
await memoryStream.WriteAsync(newLineBytes, 0, newLineBytes.Length).ConfigureAwait(false);
|
||||||
|
|
||||||
// Write the version string for the dashboard comparison function
|
// Write the version string for the dashboard comparison function
|
||||||
var versionString = string.Format("window.dashboardVersion='{0}';", version);
|
var versionString = string.Format("window.dashboardVersion='{0}';", version);
|
||||||
var versionBytes = Encoding.UTF8.GetBytes(versionString);
|
var versionBytes = Encoding.UTF8.GetBytes(versionString);
|
||||||
|
|
||||||
await memoryStream.WriteAsync(versionBytes, 0, versionBytes.Length).ConfigureAwait(false);
|
await memoryStream.WriteAsync(versionBytes, 0, versionBytes.Length).ConfigureAwait(false);
|
||||||
await memoryStream.WriteAsync(newLineBytes, 0, newLineBytes.Length).ConfigureAwait(false);
|
await memoryStream.WriteAsync(newLineBytes, 0, newLineBytes.Length).ConfigureAwait(false);
|
||||||
|
|
||||||
var builder = new StringBuilder();
|
var builder = new StringBuilder();
|
||||||
|
|
||||||
foreach (var file in new[]
|
foreach (var file in new[]
|
||||||
{
|
{
|
||||||
"thirdparty/apiclient/logger.js",
|
"thirdparty/apiclient/logger.js",
|
||||||
"thirdparty/apiclient/md5.js",
|
"thirdparty/apiclient/md5.js",
|
||||||
@ -293,65 +293,65 @@ namespace MediaBrowser.WebDashboard.Api
|
|||||||
"thirdparty/apiclient/serverdiscovery.js",
|
"thirdparty/apiclient/serverdiscovery.js",
|
||||||
"thirdparty/apiclient/connectionmanager.js"
|
"thirdparty/apiclient/connectionmanager.js"
|
||||||
})
|
})
|
||||||
{
|
{
|
||||||
using (var fs = _fileSystem.GetFileStream(GetDashboardResourcePath(file), FileMode.Open, FileAccess.Read, FileShare.ReadWrite, true))
|
using (var fs = _fileSystem.GetFileStream(GetDashboardResourcePath(file), FileMode.Open, FileAccess.Read, FileShare.ReadWrite, true))
|
||||||
{
|
{
|
||||||
using (var streamReader = new StreamReader(fs))
|
using (var streamReader = new StreamReader(fs))
|
||||||
{
|
{
|
||||||
var text = await streamReader.ReadToEndAsync().ConfigureAwait(false);
|
var text = await streamReader.ReadToEndAsync().ConfigureAwait(false);
|
||||||
builder.Append(text);
|
builder.Append(text);
|
||||||
builder.Append(Environment.NewLine);
|
builder.Append(Environment.NewLine);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var file in GetScriptFiles())
|
foreach (var file in GetScriptFiles())
|
||||||
{
|
{
|
||||||
var path = GetDashboardResourcePath("scripts/" + file);
|
var path = GetDashboardResourcePath("scripts/" + file);
|
||||||
|
|
||||||
using (var fs = _fileSystem.GetFileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, true))
|
using (var fs = _fileSystem.GetFileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, true))
|
||||||
{
|
{
|
||||||
using (var streamReader = new StreamReader(fs))
|
using (var streamReader = new StreamReader(fs))
|
||||||
{
|
{
|
||||||
var text = await streamReader.ReadToEndAsync().ConfigureAwait(false);
|
var text = await streamReader.ReadToEndAsync().ConfigureAwait(false);
|
||||||
builder.Append(text);
|
builder.Append(text);
|
||||||
builder.Append(Environment.NewLine);
|
builder.Append(Environment.NewLine);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var js = builder.ToString();
|
var js = builder.ToString();
|
||||||
|
|
||||||
if (enableMinification)
|
if (enableMinification)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var result = new CrockfordJsMinifier().Minify(js, false, Encoding.UTF8);
|
var result = new CrockfordJsMinifier().Minify(js, false, Encoding.UTF8);
|
||||||
|
|
||||||
if (result.Errors.Count > 0)
|
if (result.Errors.Count > 0)
|
||||||
{
|
{
|
||||||
_logger.Error("Error minifying javascript: " + result.Errors[0].Message);
|
_logger.Error("Error minifying javascript: " + result.Errors[0].Message);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
js = result.MinifiedContent;
|
js = result.MinifiedContent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
_logger.ErrorException("Error minifying javascript", ex);
|
_logger.ErrorException("Error minifying javascript", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var bytes = Encoding.UTF8.GetBytes(js);
|
var bytes = Encoding.UTF8.GetBytes(js);
|
||||||
await memoryStream.WriteAsync(bytes, 0, bytes.Length).ConfigureAwait(false);
|
await memoryStream.WriteAsync(bytes, 0, bytes.Length).ConfigureAwait(false);
|
||||||
|
|
||||||
memoryStream.Position = 0;
|
memoryStream.Position = 0;
|
||||||
return memoryStream;
|
return memoryStream;
|
||||||
}
|
}
|
||||||
private IEnumerable<string> GetScriptFiles()
|
private IEnumerable<string> GetScriptFiles()
|
||||||
{
|
{
|
||||||
return new[]
|
return new[]
|
||||||
{
|
{
|
||||||
"extensions.js",
|
"extensions.js",
|
||||||
"site.js",
|
"site.js",
|
||||||
@ -422,7 +422,7 @@ namespace MediaBrowser.WebDashboard.Api
|
|||||||
"itemlistpage.js",
|
"itemlistpage.js",
|
||||||
"kids.js",
|
"kids.js",
|
||||||
"librarypathmapping.js",
|
"librarypathmapping.js",
|
||||||
"reports.js",
|
"reportmanager.js",
|
||||||
"librarysettings.js",
|
"librarysettings.js",
|
||||||
"livetvchannel.js",
|
"livetvchannel.js",
|
||||||
"livetvchannels.js",
|
"livetvchannels.js",
|
||||||
@ -510,48 +510,48 @@ namespace MediaBrowser.WebDashboard.Api
|
|||||||
"wizardsettings.js",
|
"wizardsettings.js",
|
||||||
"wizarduserpage.js"
|
"wizarduserpage.js"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task AppendLocalization(Stream stream, string culture)
|
private async Task AppendLocalization(Stream stream, string culture)
|
||||||
{
|
{
|
||||||
var js = "window.localizationGlossary=" + _jsonSerializer.SerializeToString(_localization.GetJavaScriptLocalizationDictionary(culture));
|
var js = "window.localizationGlossary=" + _jsonSerializer.SerializeToString(_localization.GetJavaScriptLocalizationDictionary(culture));
|
||||||
|
|
||||||
var bytes = Encoding.UTF8.GetBytes(js);
|
var bytes = Encoding.UTF8.GetBytes(js);
|
||||||
await stream.WriteAsync(bytes, 0, bytes.Length).ConfigureAwait(false);
|
await stream.WriteAsync(bytes, 0, bytes.Length).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Appends the resource.
|
/// Appends the resource.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="outputStream">The output stream.</param>
|
/// <param name="outputStream">The output stream.</param>
|
||||||
/// <param name="path">The path.</param>
|
/// <param name="path">The path.</param>
|
||||||
/// <param name="newLineBytes">The new line bytes.</param>
|
/// <param name="newLineBytes">The new line bytes.</param>
|
||||||
/// <returns>Task.</returns>
|
/// <returns>Task.</returns>
|
||||||
private async Task AppendResource(Stream outputStream, string path, byte[] newLineBytes)
|
private async Task AppendResource(Stream outputStream, string path, byte[] newLineBytes)
|
||||||
{
|
{
|
||||||
path = GetDashboardResourcePath(path);
|
path = GetDashboardResourcePath(path);
|
||||||
|
|
||||||
using (var fs = _fileSystem.GetFileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, true))
|
using (var fs = _fileSystem.GetFileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, true))
|
||||||
{
|
{
|
||||||
using (var streamReader = new StreamReader(fs))
|
using (var streamReader = new StreamReader(fs))
|
||||||
{
|
{
|
||||||
var text = await streamReader.ReadToEndAsync().ConfigureAwait(false);
|
var text = await streamReader.ReadToEndAsync().ConfigureAwait(false);
|
||||||
var bytes = Encoding.UTF8.GetBytes(text);
|
var bytes = Encoding.UTF8.GetBytes(text);
|
||||||
await outputStream.WriteAsync(bytes, 0, bytes.Length).ConfigureAwait(false);
|
await outputStream.WriteAsync(bytes, 0, bytes.Length).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await outputStream.WriteAsync(newLineBytes, 0, newLineBytes.Length).ConfigureAwait(false);
|
await outputStream.WriteAsync(newLineBytes, 0, newLineBytes.Length).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets all CSS.
|
/// Gets all CSS.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>Task{Stream}.</returns>
|
/// <returns>Task{Stream}.</returns>
|
||||||
private async Task<Stream> GetAllCss(bool enableMinification)
|
private async Task<Stream> GetAllCss(bool enableMinification)
|
||||||
{
|
{
|
||||||
var files = new[]
|
var files = new[]
|
||||||
{
|
{
|
||||||
"site.css",
|
"site.css",
|
||||||
"chromecast.css",
|
"chromecast.css",
|
||||||
@ -574,61 +574,61 @@ namespace MediaBrowser.WebDashboard.Api
|
|||||||
"materialize.css"
|
"materialize.css"
|
||||||
};
|
};
|
||||||
|
|
||||||
var builder = new StringBuilder();
|
var builder = new StringBuilder();
|
||||||
|
|
||||||
foreach (var file in files)
|
foreach (var file in files)
|
||||||
{
|
{
|
||||||
var path = GetDashboardResourcePath("css/" + file);
|
var path = GetDashboardResourcePath("css/" + file);
|
||||||
|
|
||||||
using (var fs = _fileSystem.GetFileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, true))
|
using (var fs = _fileSystem.GetFileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, true))
|
||||||
{
|
{
|
||||||
using (var streamReader = new StreamReader(fs))
|
using (var streamReader = new StreamReader(fs))
|
||||||
{
|
{
|
||||||
var text = await streamReader.ReadToEndAsync().ConfigureAwait(false);
|
var text = await streamReader.ReadToEndAsync().ConfigureAwait(false);
|
||||||
builder.Append(text);
|
builder.Append(text);
|
||||||
builder.Append(Environment.NewLine);
|
builder.Append(Environment.NewLine);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var css = builder.ToString();
|
var css = builder.ToString();
|
||||||
|
|
||||||
if (enableMinification)
|
if (enableMinification)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var result = new KristensenCssMinifier().Minify(builder.ToString(), false, Encoding.UTF8);
|
var result = new KristensenCssMinifier().Minify(builder.ToString(), false, Encoding.UTF8);
|
||||||
|
|
||||||
if (result.Errors.Count > 0)
|
if (result.Errors.Count > 0)
|
||||||
{
|
{
|
||||||
_logger.Error("Error minifying css: " + result.Errors[0].Message);
|
_logger.Error("Error minifying css: " + result.Errors[0].Message);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
css = result.MinifiedContent;
|
css = result.MinifiedContent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
_logger.ErrorException("Error minifying css", ex);
|
_logger.ErrorException("Error minifying css", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var memoryStream = new MemoryStream(Encoding.UTF8.GetBytes(css));
|
var memoryStream = new MemoryStream(Encoding.UTF8.GetBytes(css));
|
||||||
|
|
||||||
memoryStream.Position = 0;
|
memoryStream.Position = 0;
|
||||||
return memoryStream;
|
return memoryStream;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the raw resource stream.
|
/// Gets the raw resource stream.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="path">The path.</param>
|
/// <param name="path">The path.</param>
|
||||||
/// <returns>Task{Stream}.</returns>
|
/// <returns>Task{Stream}.</returns>
|
||||||
private Stream GetRawResourceStream(string path)
|
private Stream GetRawResourceStream(string path)
|
||||||
{
|
{
|
||||||
return _fileSystem.GetFileStream(GetDashboardResourcePath(path), FileMode.Open, FileAccess.Read, FileShare.ReadWrite, true);
|
return _fileSystem.GetFileStream(GetDashboardResourcePath(path), FileMode.Open, FileAccess.Read, FileShare.ReadWrite, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -132,6 +132,9 @@
|
|||||||
<Content Include="dashboard-ui\mysyncjob.html">
|
<Content Include="dashboard-ui\mysyncjob.html">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
|
<Content Include="dashboard-ui\ReportManager.html">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
<Content Include="dashboard-ui\scripts\dashboardhosting.js">
|
<Content Include="dashboard-ui\scripts\dashboardhosting.js">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
@ -147,6 +150,9 @@
|
|||||||
<Content Include="dashboard-ui\scripts\livetvitems.js">
|
<Content Include="dashboard-ui\scripts\livetvitems.js">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
|
<Content Include="dashboard-ui\scripts\reportmanager.js">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
<Content Include="dashboard-ui\scripts\selectserver.js">
|
<Content Include="dashboard-ui\scripts\selectserver.js">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user