aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.Controller/Entities
diff options
context:
space:
mode:
authorLuke <luke.pulverenti@gmail.com>2017-08-13 16:21:10 -0400
committerGitHub <noreply@github.com>2017-08-13 16:21:10 -0400
commitdc578f3742b474bd85d556299a6b2763f4d9acda (patch)
treecc4a8d1de140ece77160349e51a64857656ab373 /MediaBrowser.Controller/Entities
parentf6ed934a7e32bf10c3a141773d713bf3b19e784f (diff)
parent7f200f057d33e3ef52b1b1b1bf1767577295317e (diff)
Merge pull request #2815 from MediaBrowser/beta
Beta
Diffstat (limited to 'MediaBrowser.Controller/Entities')
-rw-r--r--MediaBrowser.Controller/Entities/AggregateFolder.cs16
-rw-r--r--MediaBrowser.Controller/Entities/Audio/Audio.cs28
-rw-r--r--MediaBrowser.Controller/Entities/Audio/IHasAlbumArtist.cs2
-rw-r--r--MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs4
-rw-r--r--MediaBrowser.Controller/Entities/Audio/MusicArtist.cs2
-rw-r--r--MediaBrowser.Controller/Entities/BaseItem.cs187
-rw-r--r--MediaBrowser.Controller/Entities/CollectionFolder.cs15
-rw-r--r--MediaBrowser.Controller/Entities/Extensions.cs23
-rw-r--r--MediaBrowser.Controller/Entities/Folder.cs78
-rw-r--r--MediaBrowser.Controller/Entities/Game.cs29
-rw-r--r--MediaBrowser.Controller/Entities/IHasId.cs9
-rw-r--r--MediaBrowser.Controller/Entities/IHasImages.cs264
-rw-r--r--MediaBrowser.Controller/Entities/IHasMediaSources.cs4
-rw-r--r--MediaBrowser.Controller/Entities/IHasMetadata.cs257
-rw-r--r--MediaBrowser.Controller/Entities/IHasSpecialFeatures.cs3
-rw-r--r--MediaBrowser.Controller/Entities/IHasTrailers.cs6
-rw-r--r--MediaBrowser.Controller/Entities/IHasUserData.cs7
-rw-r--r--MediaBrowser.Controller/Entities/InternalItemsQuery.cs6
-rw-r--r--MediaBrowser.Controller/Entities/KeywordExtensions.cs21
-rw-r--r--MediaBrowser.Controller/Entities/Movies/BoxSet.cs25
-rw-r--r--MediaBrowser.Controller/Entities/Movies/Movie.cs33
-rw-r--r--MediaBrowser.Controller/Entities/MusicVideo.cs12
-rw-r--r--MediaBrowser.Controller/Entities/TV/Episode.cs21
-rw-r--r--MediaBrowser.Controller/Entities/TV/Series.cs99
-rw-r--r--MediaBrowser.Controller/Entities/TagExtensions.cs18
-rw-r--r--MediaBrowser.Controller/Entities/Trailer.cs5
-rw-r--r--MediaBrowser.Controller/Entities/UserView.cs8
-rw-r--r--MediaBrowser.Controller/Entities/UserViewBuilder.cs33
-rw-r--r--MediaBrowser.Controller/Entities/Video.cs125
29 files changed, 636 insertions, 704 deletions
diff --git a/MediaBrowser.Controller/Entities/AggregateFolder.cs b/MediaBrowser.Controller/Entities/AggregateFolder.cs
index e8ebbdb70..f88522f78 100644
--- a/MediaBrowser.Controller/Entities/AggregateFolder.cs
+++ b/MediaBrowser.Controller/Entities/AggregateFolder.cs
@@ -23,18 +23,6 @@ namespace MediaBrowser.Controller.Entities
PhysicalLocationsList = new List<string>();
}
- /// <summary>
- /// We don't support manual shortcuts
- /// </summary>
- [IgnoreDataMember]
- protected override bool SupportsShortcutChildren
- {
- get
- {
- return false;
- }
- }
-
[IgnoreDataMember]
public override bool IsPhysicalRoot
{
@@ -80,9 +68,9 @@ namespace MediaBrowser.Controller.Entities
public List<string> PhysicalLocationsList { get; set; }
- protected override IEnumerable<FileSystemMetadata> GetFileSystemChildren(IDirectoryService directoryService)
+ protected override FileSystemMetadata[] GetFileSystemChildren(IDirectoryService directoryService)
{
- return CreateResolveArgs(directoryService, true).FileSystemChildren;
+ return CreateResolveArgs(directoryService, true).FileSystemChildren.ToArray();
}
private List<Guid> _childrenIds = null;
diff --git a/MediaBrowser.Controller/Entities/Audio/Audio.cs b/MediaBrowser.Controller/Entities/Audio/Audio.cs
index 873ac3104..0781dc35b 100644
--- a/MediaBrowser.Controller/Entities/Audio/Audio.cs
+++ b/MediaBrowser.Controller/Entities/Audio/Audio.cs
@@ -9,6 +9,7 @@ using System.Globalization;
using System.Linq;
using System.Threading;
using MediaBrowser.Common.Extensions;
+using MediaBrowser.Controller.Persistence;
using MediaBrowser.Model.Serialization;
namespace MediaBrowser.Controller.Entities.Audio
@@ -27,9 +28,11 @@ namespace MediaBrowser.Controller.Entities.Audio
/// Gets or sets the artist.
/// </summary>
/// <value>The artist.</value>
+ [IgnoreDataMember]
public List<string> Artists { get; set; }
- public List<string> AlbumArtists { get; set; }
+ [IgnoreDataMember]
+ public string[] AlbumArtists { get; set; }
[IgnoreDataMember]
public override bool EnableRefreshOnDateModifiedChange
@@ -40,7 +43,7 @@ namespace MediaBrowser.Controller.Entities.Audio
public Audio()
{
Artists = new List<string>();
- AlbumArtists = new List<string>();
+ AlbumArtists = EmptyStringArray;
}
public override double? GetDefaultPrimaryImageAspectRatio()
@@ -193,6 +196,23 @@ namespace MediaBrowser.Controller.Entities.Audio
return base.GetBlockUnratedType();
}
+ public List<MediaStream> GetMediaStreams()
+ {
+ return MediaSourceManager.GetMediaStreams(new MediaStreamQuery
+ {
+ ItemId = Id
+ });
+ }
+
+ public List<MediaStream> GetMediaStreams(MediaStreamType type)
+ {
+ return MediaSourceManager.GetMediaStreams(new MediaStreamQuery
+ {
+ ItemId = Id,
+ Type = type
+ });
+ }
+
public SongInfo GetLookupInfo()
{
var info = GetItemLookupInfo<SongInfo>();
@@ -204,7 +224,7 @@ namespace MediaBrowser.Controller.Entities.Audio
return info;
}
- public virtual IEnumerable<MediaSourceInfo> GetMediaSources(bool enablePathSubstitution)
+ public virtual List<MediaSourceInfo> GetMediaSources(bool enablePathSubstitution)
{
if (SourceType == SourceType.Channel)
{
@@ -248,7 +268,7 @@ namespace MediaBrowser.Controller.Entities.Audio
{
Id = i.Id.ToString("N"),
Protocol = locationType == LocationType.Remote ? MediaProtocol.Http : MediaProtocol.File,
- MediaStreams = MediaSourceManager.GetMediaStreams(i.Id).ToList(),
+ MediaStreams = MediaSourceManager.GetMediaStreams(i.Id),
Name = i.Name,
Path = enablePathSubstituion ? GetMappedPath(i, i.Path, locationType) : i.Path,
RunTimeTicks = i.RunTimeTicks,
diff --git a/MediaBrowser.Controller/Entities/Audio/IHasAlbumArtist.cs b/MediaBrowser.Controller/Entities/Audio/IHasAlbumArtist.cs
index a7c914664..6900699e5 100644
--- a/MediaBrowser.Controller/Entities/Audio/IHasAlbumArtist.cs
+++ b/MediaBrowser.Controller/Entities/Audio/IHasAlbumArtist.cs
@@ -5,7 +5,7 @@ namespace MediaBrowser.Controller.Entities.Audio
{
public interface IHasAlbumArtist
{
- List<string> AlbumArtists { get; set; }
+ string[] AlbumArtists { get; set; }
}
public interface IHasArtist
diff --git a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs
index 516ab5053..c35e81826 100644
--- a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs
+++ b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs
@@ -19,13 +19,13 @@ namespace MediaBrowser.Controller.Entities.Audio
/// </summary>
public class MusicAlbum : Folder, IHasAlbumArtist, IHasArtist, IHasMusicGenres, IHasLookupInfo<AlbumInfo>, IMetadataContainer
{
- public List<string> AlbumArtists { get; set; }
+ public string[] AlbumArtists { get; set; }
public List<string> Artists { get; set; }
public MusicAlbum()
{
Artists = new List<string>();
- AlbumArtists = new List<string>();
+ AlbumArtists = EmptyStringArray;
}
[IgnoreDataMember]
diff --git a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs
index 7a37b2e02..559806ac4 100644
--- a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs
+++ b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs
@@ -212,7 +212,7 @@ namespace MediaBrowser.Controller.Entities.Audio
public async Task RefreshAllMetadata(MetadataRefreshOptions refreshOptions, IProgress<double> progress, CancellationToken cancellationToken)
{
- var items = GetRecursiveChildren().ToList();
+ var items = GetRecursiveChildren();
var songs = items.OfType<Audio>().ToList();
diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs
index b4a3d89ea..8cc90db7d 100644
--- a/MediaBrowser.Controller/Entities/BaseItem.cs
+++ b/MediaBrowser.Controller/Entities/BaseItem.cs
@@ -39,21 +39,26 @@ namespace MediaBrowser.Controller.Entities
/// <summary>
/// Class BaseItem
/// </summary>
- public abstract class BaseItem : IHasProviderIds, IHasImages, IHasUserData, IHasMetadata, IHasLookupInfo<ItemLookupInfo>
+ public abstract class BaseItem : IHasMetadata, IHasLookupInfo<ItemLookupInfo>
{
+ protected static Guid[] EmptyGuidArray = new Guid[] { };
+ protected static MetadataFields[] EmptyMetadataFieldsArray = new MetadataFields[] { };
+ protected static string[] EmptyStringArray = new string[] { };
+ protected static MediaUrl[] EmptyMediaUrlArray = new MediaUrl[] { };
+ protected static ItemImageInfo[] EmptyItemImageInfoArray = new ItemImageInfo[] { };
+ public static readonly LinkedChild[] EmptyLinkedChildArray = new LinkedChild[] { };
+
protected BaseItem()
{
- ThemeSongIds = new List<Guid>();
- ThemeVideoIds = new List<Guid>();
- Keywords = new List<string>();
- Tags = new List<string>();
+ ThemeSongIds = EmptyGuidArray;
+ ThemeVideoIds = EmptyGuidArray;
+ Tags = EmptyStringArray;
Genres = new List<string>();
- Studios = new List<string>();
+ Studios = EmptyStringArray;
ProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
- LockedFields = new List<MetadataFields>();
- ImageInfos = new List<ItemImageInfo>();
- InheritedTags = new List<string>();
- ProductionLocations = new List<string>();
+ LockedFields = EmptyMetadataFieldsArray;
+ ImageInfos = EmptyItemImageInfoArray;
+ ProductionLocations = EmptyStringArray;
}
public static readonly char[] SlugReplaceChars = { '?', '/', '&' };
@@ -74,8 +79,10 @@ namespace MediaBrowser.Controller.Entities
public static string ThemeSongFilename = "theme";
public static string ThemeVideosFolderName = "backdrops";
- public List<Guid> ThemeSongIds { get; set; }
- public List<Guid> ThemeVideoIds { get; set; }
+ [IgnoreDataMember]
+ public Guid[] ThemeSongIds { get; set; }
+ [IgnoreDataMember]
+ public Guid[] ThemeVideoIds { get; set; }
[IgnoreDataMember]
public string PreferredMetadataCountryCode { get; set; }
@@ -88,7 +95,8 @@ namespace MediaBrowser.Controller.Entities
[IgnoreDataMember]
public string Tagline { get; set; }
- public List<ItemImageInfo> ImageInfos { get; set; }
+ [IgnoreDataMember]
+ public ItemImageInfo[] ImageInfos { get; set; }
[IgnoreDataMember]
public bool IsVirtualItem { get; set; }
@@ -130,12 +138,6 @@ namespace MediaBrowser.Controller.Entities
public bool IsInMixedFolder { get; set; }
[IgnoreDataMember]
- protected virtual bool SupportsIsInMixedFolderDetection
- {
- get { return false; }
- }
-
- [IgnoreDataMember]
public virtual bool SupportsPlayedStatus
{
get
@@ -153,16 +155,6 @@ namespace MediaBrowser.Controller.Entities
}
}
- public bool DetectIsInMixedFolder()
- {
- if (SupportsIsInMixedFolderDetection)
- {
-
- }
-
- return IsInMixedFolder;
- }
-
[IgnoreDataMember]
public virtual bool SupportsRemoteImageDownloading
{
@@ -214,7 +206,9 @@ namespace MediaBrowser.Controller.Entities
get { return PremiereDate.HasValue && PremiereDate.Value.ToLocalTime().Date >= DateTime.Now.Date; }
}
+ [IgnoreDataMember]
public int? TotalBitrate { get; set; }
+ [IgnoreDataMember]
public ExtraType? ExtraType { get; set; }
[IgnoreDataMember]
@@ -560,7 +554,7 @@ namespace MediaBrowser.Controller.Entities
/// </summary>
/// <value>The locked fields.</value>
[IgnoreDataMember]
- public List<MetadataFields> LockedFields { get; set; }
+ public MetadataFields[] LockedFields { get; set; }
/// <summary>
/// Gets the type of the media.
@@ -820,13 +814,6 @@ namespace MediaBrowser.Controller.Entities
public DateTime? EndDate { get; set; }
/// <summary>
- /// Gets or sets the display type of the media.
- /// </summary>
- /// <value>The display type of the media.</value>
- [IgnoreDataMember]
- public string DisplayMediaType { get; set; }
-
- /// <summary>
/// Gets or sets the official rating.
/// </summary>
/// <value>The official rating.</value>
@@ -836,9 +823,6 @@ namespace MediaBrowser.Controller.Entities
[IgnoreDataMember]
public int InheritedParentalRatingValue { get; set; }
- [IgnoreDataMember]
- public List<string> InheritedTags { get; set; }
-
/// <summary>
/// Gets or sets the critic rating.
/// </summary>
@@ -865,7 +849,7 @@ namespace MediaBrowser.Controller.Entities
/// </summary>
/// <value>The studios.</value>
[IgnoreDataMember]
- public List<string> Studios { get; set; }
+ public string[] Studios { get; set; }
/// <summary>
/// Gets or sets the genres.
@@ -879,10 +863,10 @@ namespace MediaBrowser.Controller.Entities
/// </summary>
/// <value>The tags.</value>
[IgnoreDataMember]
- public List<string> Tags { get; set; }
+ public string[] Tags { get; set; }
- public List<string> Keywords { get; set; }
- public List<string> ProductionLocations { get; set; }
+ [IgnoreDataMember]
+ public string[] ProductionLocations { get; set; }
/// <summary>
/// Gets or sets the home page URL.
@@ -991,11 +975,11 @@ namespace MediaBrowser.Controller.Entities
/// Loads the theme songs.
/// </summary>
/// <returns>List{Audio.Audio}.</returns>
- private static IEnumerable<Audio.Audio> LoadThemeSongs(List<FileSystemMetadata> fileSystemChildren, IDirectoryService directoryService)
+ private static Audio.Audio[] LoadThemeSongs(List<FileSystemMetadata> fileSystemChildren, IDirectoryService directoryService)
{
var files = fileSystemChildren.Where(i => i.IsDirectory)
.Where(i => string.Equals(i.Name, ThemeSongsFolderName, StringComparison.OrdinalIgnoreCase))
- .SelectMany(i => directoryService.GetFiles(i.FullName))
+ .SelectMany(i => FileSystem.GetFiles(i.FullName))
.ToList();
// Support plex/xbmc convention
@@ -1020,18 +1004,18 @@ namespace MediaBrowser.Controller.Entities
return audio;
// Sort them so that the list can be easily compared for changes
- }).OrderBy(i => i.Path).ToList();
+ }).OrderBy(i => i.Path).ToArray();
}
/// <summary>
/// Loads the video backdrops.
/// </summary>
/// <returns>List{Video}.</returns>
- private static IEnumerable<Video> LoadThemeVideos(IEnumerable<FileSystemMetadata> fileSystemChildren, IDirectoryService directoryService)
+ private static Video[] LoadThemeVideos(IEnumerable<FileSystemMetadata> fileSystemChildren, IDirectoryService directoryService)
{
var files = fileSystemChildren.Where(i => i.IsDirectory)
.Where(i => string.Equals(i.Name, ThemeVideosFolderName, StringComparison.OrdinalIgnoreCase))
- .SelectMany(i => directoryService.GetFiles(i.FullName));
+ .SelectMany(i => FileSystem.GetFiles(i.FullName));
return LibraryManager.ResolvePaths(files, directoryService, null, new LibraryOptions())
.OfType<Video>()
@@ -1050,7 +1034,7 @@ namespace MediaBrowser.Controller.Entities
return item;
// Sort them so that the list can be easily compared for changes
- }).OrderBy(i => i.Path).ToList();
+ }).OrderBy(i => i.Path).ToArray();
}
public Task RefreshMetadata(CancellationToken cancellationToken)
@@ -1158,7 +1142,7 @@ namespace MediaBrowser.Controller.Entities
{
if (SupportsThemeMedia)
{
- if (!DetectIsInMixedFolder())
+ if (!IsInMixedFolder)
{
themeSongsChanged = await RefreshThemeSongs(this, options, fileSystemChildren, cancellationToken).ConfigureAwait(false);
@@ -1176,7 +1160,7 @@ namespace MediaBrowser.Controller.Entities
return themeSongsChanged || themeVideosChanged || localTrailersChanged;
}
- protected virtual IEnumerable<FileSystemMetadata> GetFileSystemChildren(IDirectoryService directoryService)
+ protected virtual FileSystemMetadata[] GetFileSystemChildren(IDirectoryService directoryService)
{
var path = ContainingFolderPath;
@@ -1187,7 +1171,7 @@ namespace MediaBrowser.Controller.Entities
{
var newItems = LibraryManager.FindTrailers(this, fileSystemChildren, options.DirectoryService).ToList();
- var newItemIds = newItems.Select(i => i.Id).ToList();
+ var newItemIds = newItems.Select(i => i.Id).ToArray();
var itemsChanged = !item.LocalTrailerIds.SequenceEqual(newItemIds);
@@ -1202,9 +1186,9 @@ namespace MediaBrowser.Controller.Entities
private async Task<bool> RefreshThemeVideos(BaseItem item, MetadataRefreshOptions options, IEnumerable<FileSystemMetadata> fileSystemChildren, CancellationToken cancellationToken)
{
- var newThemeVideos = LoadThemeVideos(fileSystemChildren, options.DirectoryService).ToList();
+ var newThemeVideos = LoadThemeVideos(fileSystemChildren, options.DirectoryService);
- var newThemeVideoIds = newThemeVideos.Select(i => i.Id).ToList();
+ var newThemeVideoIds = newThemeVideos.Select(i => i.Id).ToArray(newThemeVideos.Length);
var themeVideosChanged = !item.ThemeVideoIds.SequenceEqual(newThemeVideoIds);
@@ -1233,8 +1217,8 @@ namespace MediaBrowser.Controller.Entities
/// </summary>
private async Task<bool> RefreshThemeSongs(BaseItem item, MetadataRefreshOptions options, List<FileSystemMetadata> fileSystemChildren, CancellationToken cancellationToken)
{
- var newThemeSongs = LoadThemeSongs(fileSystemChildren, options.DirectoryService).ToList();
- var newThemeSongIds = newThemeSongs.Select(i => i.Id).ToList();
+ var newThemeSongs = LoadThemeSongs(fileSystemChildren, options.DirectoryService);
+ var newThemeSongIds = newThemeSongs.Select(i => i.Id).ToArray(newThemeSongs.Length);
var themeSongsChanged = !item.ThemeSongIds.SequenceEqual(newThemeSongIds);
@@ -1313,12 +1297,9 @@ namespace MediaBrowser.Controller.Entities
{
var current = this;
- if (!SupportsIsInMixedFolderDetection)
+ if (current.IsInMixedFolder != newItem.IsInMixedFolder)
{
- if (current.IsInMixedFolder != newItem.IsInMixedFolder)
- {
- return false;
- }
+ return false;
}
return true;
@@ -1739,12 +1720,28 @@ namespace MediaBrowser.Controller.Entities
throw new ArgumentNullException("name");
}
- if (!Studios.Contains(name, StringComparer.OrdinalIgnoreCase))
+ var current = Studios;
+
+ if (!current.Contains(name, StringComparer.OrdinalIgnoreCase))
{
- Studios.Add(name);
+ if (current.Length == 0)
+ {
+ Studios = new[] { name };
+ }
+ else
+ {
+ var list = current.ToArray(current.Length + 1);
+ list[list.Length - 1] = name;
+ Studios = list;
+ }
}
}
+ public void SetStudios(IEnumerable<string> names)
+ {
+ Studios = names.Distinct().ToArray();
+ }
+
/// <summary>
/// Adds a genre to the item
/// </summary>
@@ -1864,10 +1861,18 @@ namespace MediaBrowser.Controller.Entities
if (existingImage != null)
{
- ImageInfos.Remove(existingImage);
+ existingImage.Path = image.Path;
+ existingImage.DateModified = image.DateModified;
+ existingImage.IsPlaceholder = image.IsPlaceholder;
}
- ImageInfos.Add(image);
+ else
+ {
+ var currentCount = ImageInfos.Length;
+ var newList = ImageInfos.ToArray(currentCount + 1);
+ newList[currentCount] = image;
+ ImageInfos = newList;
+ }
}
public void SetImagePath(ImageType type, int index, FileSystemMetadata file)
@@ -1881,7 +1886,10 @@ namespace MediaBrowser.Controller.Entities
if (image == null)
{
- ImageInfos.Add(GetImageInfo(file, type));
+ var currentCount = ImageInfos.Length;
+ var newList = ImageInfos.ToArray(currentCount + 1);
+ newList[currentCount] = GetImageInfo(file, type);
+ ImageInfos = newList;
}
else
{
@@ -1922,7 +1930,12 @@ namespace MediaBrowser.Controller.Entities
public void RemoveImage(ItemImageInfo image)
{
- ImageInfos.Remove(image);
+ RemoveImages(new List<ItemImageInfo> { image });
+ }
+
+ public void RemoveImages(List<ItemImageInfo> deletedImages)
+ {
+ ImageInfos = ImageInfos.Except(deletedImages).ToArray();
}
public virtual Task UpdateToRepository(ItemUpdateType updateReason, CancellationToken cancellationToken)
@@ -1939,7 +1952,7 @@ namespace MediaBrowser.Controller.Entities
.Where(i => i.IsLocalFile)
.Select(i => FileSystem.GetDirectoryName(i.Path))
.Distinct(StringComparer.OrdinalIgnoreCase)
- .SelectMany(directoryService.GetFilePaths)
+ .SelectMany(i => FileSystem.GetFilePaths(i))
.ToList();
var deletedImages = ImageInfos
@@ -1948,7 +1961,7 @@ namespace MediaBrowser.Controller.Entities
if (deletedImages.Count > 0)
{
- ImageInfos = ImageInfos.Except(deletedImages).ToList();
+ ImageInfos = ImageInfos.Except(deletedImages).ToArray();
}
return deletedImages.Count > 0;
@@ -2068,10 +2081,25 @@ namespace MediaBrowser.Controller.Entities
.Where(i => i.IsLocalFile && !newImagePaths.Contains(i.Path, StringComparer.OrdinalIgnoreCase) && !FileSystem.FileExists(i.Path))
.ToList();
- ImageInfos = ImageInfos.Except(deleted).ToList();
+ if (deleted.Count > 0)
+ {
+ ImageInfos = ImageInfos.Except(deleted).ToArray();
+ }
}
- ImageInfos.AddRange(newImageList.Select(i => GetImageInfo(i, imageType)));
+ if (newImageList.Count > 0)
+ {
+ var currentCount = ImageInfos.Length;
+ var newList = ImageInfos.ToArray(currentCount + newImageList.Count);
+
+ foreach (var image in newImageList)
+ {
+ newList[currentCount] = GetImageInfo(image, imageType);
+ currentCount++;
+ }
+
+ ImageInfos = newList;
+ }
return newImageList.Count > 0;
}
@@ -2112,7 +2140,7 @@ namespace MediaBrowser.Controller.Entities
var extensions = new[] { ".nfo", ".xml", ".srt" }.ToList();
extensions.AddRange(SupportedImageExtensionsList);
- return FileSystem.GetFiles(FileSystem.GetDirectoryName(Path), extensions.ToArray(), false, false)
+ return FileSystem.GetFiles(FileSystem.GetDirectoryName(Path), extensions.ToArray(extensions.Count), false, false)
.Where(i => System.IO.Path.GetFileNameWithoutExtension(i.FullName).StartsWith(filename, StringComparison.OrdinalIgnoreCase))
.ToList();
}
@@ -2272,17 +2300,12 @@ namespace MediaBrowser.Controller.Entities
if (!item.Studios.SequenceEqual(ownedItem.Studios, StringComparer.Ordinal))
{
newOptions.ForceSave = true;
- ownedItem.Studios = item.Studios.ToList();
+ ownedItem.Studios = item.Studios;
}
if (!item.ProductionLocations.SequenceEqual(ownedItem.ProductionLocations, StringComparer.Ordinal))
{
newOptions.ForceSave = true;
- ownedItem.ProductionLocations = item.ProductionLocations.ToList();
- }
- if (!item.Keywords.SequenceEqual(ownedItem.Keywords, StringComparer.Ordinal))
- {
- newOptions.ForceSave = true;
- ownedItem.Keywords = item.Keywords.ToList();
+ ownedItem.ProductionLocations = item.ProductionLocations;
}
if (item.CommunityRating != ownedItem.CommunityRating)
{
@@ -2341,7 +2364,9 @@ namespace MediaBrowser.Controller.Entities
public string GetEtag(User user)
{
- return string.Join("|", GetEtagValues(user).ToArray()).GetMD5().ToString("N");
+ var list = GetEtagValues(user);
+
+ return string.Join("|", list.ToArray(list.Count)).GetMD5().ToString("N");
}
protected virtual List<string> GetEtagValues(User user)
diff --git a/MediaBrowser.Controller/Entities/CollectionFolder.cs b/MediaBrowser.Controller/Entities/CollectionFolder.cs
index d88b7da34..d02e469d4 100644
--- a/MediaBrowser.Controller/Entities/CollectionFolder.cs
+++ b/MediaBrowser.Controller/Entities/CollectionFolder.cs
@@ -32,15 +32,6 @@ namespace MediaBrowser.Controller.Entities
}
[IgnoreDataMember]
- protected override bool SupportsShortcutChildren
- {
- get
- {
- return true;
- }
- }
-
- [IgnoreDataMember]
public override bool SupportsPlayedStatus
{
get
@@ -165,9 +156,9 @@ namespace MediaBrowser.Controller.Entities
public List<string> PhysicalLocationsList { get; set; }
public List<Guid> PhysicalFolderIds { get; set; }
- protected override IEnumerable<FileSystemMetadata> GetFileSystemChildren(IDirectoryService directoryService)
+ protected override FileSystemMetadata[] GetFileSystemChildren(IDirectoryService directoryService)
{
- return CreateResolveArgs(directoryService, true).FileSystemChildren;
+ return CreateResolveArgs(directoryService, true).FileSystemChildren.ToArray();
}
private bool _requiresRefresh;
@@ -249,7 +240,7 @@ namespace MediaBrowser.Controller.Entities
var changed = !linkedChildren.SequenceEqual(LinkedChildren, new LinkedChildComparer(FileSystem));
- LinkedChildren = linkedChildren;
+ LinkedChildren = linkedChildren.ToArray(linkedChildren.Count);
var folderIds = PhysicalFolderIds.ToList();
var newFolderIds = physicalFolders.Select(i => i.Id).ToList();
diff --git a/MediaBrowser.Controller/Entities/Extensions.cs b/MediaBrowser.Controller/Entities/Extensions.cs
index 5e792a03a..36855a86c 100644
--- a/MediaBrowser.Controller/Entities/Extensions.cs
+++ b/MediaBrowser.Controller/Entities/Extensions.cs
@@ -1,6 +1,7 @@
using MediaBrowser.Model.Entities;
using System;
using System.Linq;
+using MediaBrowser.Model.Extensions;
namespace MediaBrowser.Controller.Entities
{
@@ -12,11 +13,7 @@ namespace MediaBrowser.Controller.Entities
/// <summary>
/// Adds the trailer URL.
/// </summary>
- /// <param name="item">The item.</param>
- /// <param name="url">The URL.</param>
- /// <param name="isDirectLink">if set to <c>true</c> [is direct link].</param>
- /// <exception cref="System.ArgumentNullException">url</exception>
- public static void AddTrailerUrl(this IHasTrailers item, string url, bool isDirectLink)
+ public static void AddTrailerUrl(this IHasTrailers item, string url)
{
if (string.IsNullOrWhiteSpace(url))
{
@@ -27,10 +24,22 @@ namespace MediaBrowser.Controller.Entities
if (current == null)
{
- item.RemoteTrailers.Add(new MediaUrl
+ var mediaUrl = new MediaUrl
{
Url = url
- });
+ };
+
+ if (item.RemoteTrailers.Length == 0)
+ {
+ item.RemoteTrailers = new[] { mediaUrl };
+ }
+ else
+ {
+ var list = item.RemoteTrailers.ToArray(item.RemoteTrailers.Length + 1);
+ list[list.Length - 1] = mediaUrl;
+
+ item.RemoteTrailers = list;
+ }
}
}
}
diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs
index 5d74cf218..46ae9230b 100644
--- a/MediaBrowser.Controller/Entities/Folder.cs
+++ b/MediaBrowser.Controller/Entities/Folder.cs
@@ -20,6 +20,7 @@ using MediaBrowser.Controller.IO;
using MediaBrowser.Model.Channels;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Serialization;
+using MediaBrowser.Model.Extensions;
namespace MediaBrowser.Controller.Entities
{
@@ -37,14 +38,14 @@ namespace MediaBrowser.Controller.Entities
/// <value><c>true</c> if this instance is root; otherwise, <c>false</c>.</value>
public bool IsRoot { get; set; }
- public virtual List<LinkedChild> LinkedChildren { get; set; }
+ public LinkedChild[] LinkedChildren { get; set; }
[IgnoreDataMember]
public DateTime? DateLastMediaAdded { get; set; }
public Folder()
{
- LinkedChildren = new List<LinkedChild>();
+ LinkedChildren = EmptyLinkedChildArray;
}
[IgnoreDataMember]
@@ -706,7 +707,7 @@ namespace MediaBrowser.Controller.Entities
public virtual int GetChildCount(User user)
{
- if (LinkedChildren.Count > 0)
+ if (LinkedChildren.Length > 0)
{
if (!(this is ICollectionFolder))
{
@@ -791,7 +792,7 @@ namespace MediaBrowser.Controller.Entities
query.StartIndex = null;
query.Limit = null;
- var itemsList = LibraryManager.GetItemList(query);
+ IEnumerable<BaseItem> itemsList = LibraryManager.GetItemList(query);
var user = query.User;
if (user != null)
@@ -843,7 +844,7 @@ namespace MediaBrowser.Controller.Entities
private bool RequiresPostFiltering(InternalItemsQuery query)
{
- if (LinkedChildren.Count > 0)
+ if (LinkedChildren.Length > 0)
{
if (!(this is ICollectionFolder))
{
@@ -921,12 +922,6 @@ namespace MediaBrowser.Controller.Entities
return true;
}
- if (query.AirDays.Length > 0)
- {
- Logger.Debug("Query requires post-filtering due to AirDays");
- return true;
- }
-
if (query.SeriesStatuses.Length > 0)
{
Logger.Debug("Query requires post-filtering due to SeriesStatuses");
@@ -970,6 +965,27 @@ namespace MediaBrowser.Controller.Entities
return GetItemsInternal(query);
}
+ public BaseItem[] GetItemList(InternalItemsQuery query)
+ {
+ query.EnableTotalRecordCount = false;
+
+ if (query.ItemIds.Length > 0)
+ {
+ var result = LibraryManager.GetItemList(query);
+
+ if (query.SortBy.Length == 0)
+ {
+ var ids = query.ItemIds.ToList();
+
+ // Try to preserve order
+ return result.OrderBy(i => ids.IndexOf(i.Id.ToString("N"))).ToArray();
+ }
+ return result.ToArray(result.Count);
+ }
+
+ return GetItemsInternal(query).Items;
+ }
+
protected virtual QueryResult<BaseItem> GetItemsInternal(InternalItemsQuery query)
{
if (SourceType == SourceType.Channel)
@@ -1203,7 +1219,7 @@ namespace MediaBrowser.Controller.Entities
return GetLinkedChildren();
}
- if (LinkedChildren.Count == 0)
+ if (LinkedChildren.Length == 0)
{
return new List<BaseItem>();
}
@@ -1292,14 +1308,9 @@ namespace MediaBrowser.Controller.Entities
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
protected virtual bool RefreshLinkedChildren(IEnumerable<FileSystemMetadata> fileSystemChildren)
{
- var currentManualLinks = LinkedChildren.Where(i => i.Type == LinkedChildType.Manual).ToList();
- var currentShortcutLinks = LinkedChildren.Where(i => i.Type == LinkedChildType.Shortcut).ToList();
-
- List<LinkedChild> newShortcutLinks;
-
if (SupportsShortcutChildren)
{
- newShortcutLinks = fileSystemChildren
+ var newShortcutLinks = fileSystemChildren
.Where(i => !i.IsDirectory && FileSystem.IsShortcut(i.FullName))
.Select(i =>
{
@@ -1330,16 +1341,17 @@ namespace MediaBrowser.Controller.Entities
})
.Where(i => i != null)
.ToList();
- }
- else { newShortcutLinks = new List<LinkedChild>(); }
- if (!newShortcutLinks.SequenceEqual(currentShortcutLinks, new LinkedChildComparer(FileSystem)))
- {
- Logger.Info("Shortcut links have changed for {0}", Path);
+ var currentShortcutLinks = LinkedChildren.Where(i => i.Type == LinkedChildType.Shortcut).ToList();
- newShortcutLinks.AddRange(currentManualLinks);
- LinkedChildren = newShortcutLinks;
- return true;
+ if (!newShortcutLinks.SequenceEqual(currentShortcutLinks, new LinkedChildComparer(FileSystem)))
+ {
+ Logger.Info("Shortcut links have changed for {0}", Path);
+
+ newShortcutLinks.AddRange(LinkedChildren.Where(i => i.Type == LinkedChildType.Manual));
+ LinkedChildren = newShortcutLinks.ToArray(newShortcutLinks.Count);
+ return true;
+ }
}
foreach (var child in LinkedChildren)
@@ -1370,15 +1382,15 @@ namespace MediaBrowser.Controller.Entities
EnableTotalRecordCount = false
};
- if (!user.Configuration.DisplayMissingEpisodes || !user.Configuration.DisplayUnairedEpisodes)
+ if (!user.Configuration.DisplayMissingEpisodes)
{
query.IsVirtualItem = false;
}
- var itemsResult = GetItems(query);
+ var itemsResult = GetItemList(query);
// Sweep through recursively and update status
- var tasks = itemsResult.Items.Select(c => c.MarkPlayed(user, datePlayed, resetPosition));
+ var tasks = itemsResult.Select(c => c.MarkPlayed(user, datePlayed, resetPosition));
await Task.WhenAll(tasks).ConfigureAwait(false);
}
@@ -1390,7 +1402,7 @@ namespace MediaBrowser.Controller.Entities
/// <returns>Task.</returns>
public override async Task MarkUnplayed(User user)
{
- var itemsResult = GetItems(new InternalItemsQuery
+ var itemsResult = GetItemList(new InternalItemsQuery
{
User = user,
Recursive = true,
@@ -1400,14 +1412,14 @@ namespace MediaBrowser.Controller.Entities
});
// Sweep through recursively and update status
- var tasks = itemsResult.Items.Select(c => c.MarkUnplayed(user));
+ var tasks = itemsResult.Select(c => c.MarkUnplayed(user));
await Task.WhenAll(tasks).ConfigureAwait(false);
}
public override bool IsPlayed(User user)
{
- var itemsResult = GetItems(new InternalItemsQuery(user)
+ var itemsResult = GetItemList(new InternalItemsQuery(user)
{
Recursive = true,
IsFolder = false,
@@ -1416,7 +1428,7 @@ namespace MediaBrowser.Controller.Entities
});
- return itemsResult.Items
+ return itemsResult
.All(i => i.IsPlayed(user));
}
diff --git a/MediaBrowser.Controller/Entities/Game.cs b/MediaBrowser.Controller/Entities/Game.cs
index baefc9dfa..eb2638ee4 100644
--- a/MediaBrowser.Controller/Entities/Game.cs
+++ b/MediaBrowser.Controller/Entities/Game.cs
@@ -13,14 +13,14 @@ namespace MediaBrowser.Controller.Entities
{
public Game()
{
- MultiPartGameFiles = new List<string>();
- RemoteTrailers = new List<MediaUrl>();
- LocalTrailerIds = new List<Guid>();
- RemoteTrailerIds = new List<Guid>();
+ MultiPartGameFiles = EmptyStringArray;
+ RemoteTrailers = EmptyMediaUrlArray;
+ LocalTrailerIds = EmptyGuidArray;
+ RemoteTrailerIds = EmptyGuidArray;
}
- public List<Guid> LocalTrailerIds { get; set; }
- public List<Guid> RemoteTrailerIds { get; set; }
+ public Guid[] LocalTrailerIds { get; set; }
+ public Guid[] RemoteTrailerIds { get; set; }
public override bool CanDownload()
{
@@ -45,7 +45,7 @@ namespace MediaBrowser.Controller.Entities
/// Gets or sets the remote trailers.
/// </summary>
/// <value>The remote trailers.</value>
- public List<MediaUrl> RemoteTrailers { get; set; }
+ public MediaUrl[] RemoteTrailers { get; set; }
/// <summary>
/// Gets the type of the media.
@@ -84,7 +84,7 @@ namespace MediaBrowser.Controller.Entities
/// <summary>
/// Holds the paths to the game files in the event this is a multipart game
/// </summary>
- public List<string> MultiPartGameFiles { get; set; }
+ public string[] MultiPartGameFiles { get; set; }
public override List<string> GetUserDataKeys()
{
@@ -100,7 +100,7 @@ namespace MediaBrowser.Controller.Entities
public override IEnumerable<FileSystemMetadata> GetDeletePaths()
{
- if (!DetectIsInMixedFolder())
+ if (!IsInMixedFolder)
{
return new[] {
new FileSystemMetadata
@@ -127,16 +127,5 @@ namespace MediaBrowser.Controller.Entities
return id;
}
-
- /// <summary>
- /// Gets the trailer ids.
- /// </summary>
- /// <returns>List&lt;Guid&gt;.</returns>
- public List<Guid> GetTrailerIds()
- {
- var list = LocalTrailerIds.ToList();
- list.AddRange(RemoteTrailerIds);
- return list;
- }
}
}
diff --git a/MediaBrowser.Controller/Entities/IHasId.cs b/MediaBrowser.Controller/Entities/IHasId.cs
deleted file mode 100644
index 9698adf7a..000000000
--- a/MediaBrowser.Controller/Entities/IHasId.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-using System;
-
-namespace MediaBrowser.Controller.Entities
-{
- public interface IHasId
- {
- Guid Id { get; }
- }
-}
diff --git a/MediaBrowser.Controller/Entities/IHasImages.cs b/MediaBrowser.Controller/Entities/IHasImages.cs
deleted file mode 100644
index e2b3c0777..000000000
--- a/MediaBrowser.Controller/Entities/IHasImages.cs
+++ /dev/null
@@ -1,264 +0,0 @@
-using MediaBrowser.Controller.Providers;
-using MediaBrowser.Model.Entities;
-using System.Collections.Generic;
-using System.Threading;
-using System.Threading.Tasks;
-
-using MediaBrowser.Controller.IO;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Model.IO;
-
-namespace MediaBrowser.Controller.Entities
-{
- public interface IHasImages : IHasProviderIds, IHasId
- {
- /// <summary>
- /// Gets the name.
- /// </summary>
- /// <value>The name.</value>
- string Name { get; set; }
-
- /// <summary>
- /// Gets the path.
- /// </summary>
- /// <value>The path.</value>
- string Path { get; set; }
-
- /// <summary>
- /// Gets the file name without extension.
- /// </summary>
- /// <value>The file name without extension.</value>
- string FileNameWithoutExtension { get; }
-
- /// <summary>
- /// Gets the type of the location.
- /// </summary>
- /// <value>The type of the location.</value>
- LocationType LocationType { get; }
-
- /// <summary>
- /// Gets the locked fields.
- /// </summary>
- /// <value>The locked fields.</value>
- List<MetadataFields> LockedFields { get; }
-
- /// <summary>
- /// Gets the images.
- /// </summary>
- /// <param name="imageType">Type of the image.</param>
- /// <returns>IEnumerable{ItemImageInfo}.</returns>
- IEnumerable<ItemImageInfo> GetImages(ImageType imageType);
-
- /// <summary>
- /// Gets the image path.
- /// </summary>
- /// <param name="imageType">Type of the image.</param>
- /// <param name="imageIndex">Index of the image.</param>
- /// <returns>System.String.</returns>
- string GetImagePath(ImageType imageType, int imageIndex);
-
- /// <summary>
- /// Gets the image information.
- /// </summary>
- /// <param name="imageType">Type of the image.</param>
- /// <param name="imageIndex">Index of the image.</param>
- /// <returns>ItemImageInfo.</returns>
- ItemImageInfo GetImageInfo(ImageType imageType, int imageIndex);
-
- /// <summary>
- /// Sets the image.
- /// </summary>
- /// <param name="type">The type.</param>
- /// <param name="index">The index.</param>
- /// <param name="file">The file.</param>
- void SetImagePath(ImageType type, int index, FileSystemMetadata file);
-
- /// <summary>
- /// Determines whether the specified type has image.
- /// </summary>
- /// <param name="type">The type.</param>
- /// <param name="imageIndex">Index of the image.</param>
- /// <returns><c>true</c> if the specified type has image; otherwise, <c>false</c>.</returns>
- bool HasImage(ImageType type, int imageIndex);
-
- /// <summary>
- /// Allowses the multiple images.
- /// </summary>
- /// <param name="type">The type.</param>
- /// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
- bool AllowsMultipleImages(ImageType type);
-
- /// <summary>
- /// Swaps the images.
- /// </summary>
- /// <param name="type">The type.</param>
- /// <param name="index1">The index1.</param>
- /// <param name="index2">The index2.</param>
- /// <returns>Task.</returns>
- Task SwapImages(ImageType type, int index1, int index2);
-
- /// <summary>
- /// Gets the display type of the media.
- /// </summary>
- /// <value>The display type of the media.</value>
- string DisplayMediaType { get; set; }
-
- /// <summary>
- /// Gets or sets the primary image path.
- /// </summary>
- /// <value>The primary image path.</value>
- string PrimaryImagePath { get; }
-
- /// <summary>
- /// Gets the preferred metadata language.
- /// </summary>
- /// <returns>System.String.</returns>
- string GetPreferredMetadataLanguage();
-
- /// <summary>
- /// Validates the images and returns true or false indicating if any were removed.
- /// </summary>
- bool ValidateImages(IDirectoryService directoryService);
-
- /// <summary>
- /// Gets a value indicating whether this instance is owned item.
- /// </summary>
- /// <value><c>true</c> if this instance is owned item; otherwise, <c>false</c>.</value>
- bool IsOwnedItem { get; }
-
- /// <summary>
- /// Gets the containing folder path.
- /// </summary>
- /// <value>The containing folder path.</value>
- string ContainingFolderPath { get; }
-
- /// <summary>
- /// Adds the images.
- /// </summary>
- /// <param name="imageType">Type of the image.</param>
- /// <param name="images">The images.</param>
- /// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
- bool AddImages(ImageType imageType, List<FileSystemMetadata> images);
-
- /// <summary>
- /// Determines whether [is save local metadata enabled].
- /// </summary>
- /// <returns><c>true</c> if [is save local metadata enabled]; otherwise, <c>false</c>.</returns>
- bool IsSaveLocalMetadataEnabled();
-
- /// <summary>
- /// Gets a value indicating whether [supports local metadata].
- /// </summary>
- /// <value><c>true</c> if [supports local metadata]; otherwise, <c>false</c>.</value>
- bool SupportsLocalMetadata { get; }
-
- bool DetectIsInMixedFolder();
-
- /// <summary>
- /// Gets a value indicating whether this instance is locked.
- /// </summary>
- /// <value><c>true</c> if this instance is locked; otherwise, <c>false</c>.</value>
- bool IsLocked { get; }
-
- /// <summary>
- /// Gets a value indicating whether [supports remote image downloading].
- /// </summary>
- /// <value><c>true</c> if [supports remote image downloading]; otherwise, <c>false</c>.</value>
- bool SupportsRemoteImageDownloading { get; }
-
- /// <summary>
- /// Gets the internal metadata path.
- /// </summary>
- /// <returns>System.String.</returns>
- string GetInternalMetadataPath();
-
- /// <summary>
- /// Gets a value indicating whether [always scan internal metadata path].
- /// </summary>
- /// <value><c>true</c> if [always scan internal metadata path]; otherwise, <c>false</c>.</value>
- bool AlwaysScanInternalMetadataPath { get; }
-
- /// <summary>
- /// Determines whether [is internet metadata enabled].
- /// </summary>
- /// <returns><c>true</c> if [is internet metadata enabled]; otherwise, <c>false</c>.</returns>
- bool IsInternetMetadataEnabled();
-
- /// <summary>
- /// Removes the image.
- /// </summary>
- /// <param name="image">The image.</param>
- void RemoveImage(ItemImageInfo image);
-
- /// <summary>
- /// Updates to repository.
- /// </summary>
- /// <param name="updateReason">The update reason.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- Task UpdateToRepository(ItemUpdateType updateReason, CancellationToken cancellationToken);
-
- /// <summary>
- /// Sets the image.
- /// </summary>
- /// <param name="image">The image.</param>
- /// <param name="index">The index.</param>
- void SetImage(ItemImageInfo image, int index);
-
- double? GetDefaultPrimaryImageAspectRatio();
-
- int? ProductionYear { get; set; }
- }
-
- public static class HasImagesExtensions
- {
- /// <summary>
- /// Gets the image path.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="imageType">Type of the image.</param>
- /// <returns>System.String.</returns>
- public static string GetImagePath(this IHasImages item, ImageType imageType)
- {
- return item.GetImagePath(imageType, 0);
- }
-
- public static bool HasImage(this IHasImages item, ImageType imageType)
- {
- return item.HasImage(imageType, 0);
- }
-
- /// <summary>
- /// Sets the image path.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="imageType">Type of the image.</param>
- /// <param name="file">The file.</param>
- public static void SetImagePath(this IHasImages item, ImageType imageType, FileSystemMetadata file)
- {
- item.SetImagePath(imageType, 0, file);
- }
-
- /// <summary>
- /// Sets the image path.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="imageType">Type of the image.</param>
- /// <param name="file">The file.</param>
- public static void SetImagePath(this IHasImages item, ImageType imageType, string file)
- {
- if (file.StartsWith("http", System.StringComparison.OrdinalIgnoreCase))
- {
- item.SetImage(new ItemImageInfo
- {
- Path = file,
- Type = imageType
- }, 0);
- }
- else
- {
- item.SetImagePath(imageType, BaseItem.FileSystem.GetFileInfo(file));
- }
- }
- }
-}
diff --git a/MediaBrowser.Controller/Entities/IHasMediaSources.cs b/MediaBrowser.Controller/Entities/IHasMediaSources.cs
index 832b9f6c1..bf4acdfbd 100644
--- a/MediaBrowser.Controller/Entities/IHasMediaSources.cs
+++ b/MediaBrowser.Controller/Entities/IHasMediaSources.cs
@@ -1,5 +1,6 @@
using MediaBrowser.Model.Dto;
using System.Collections.Generic;
+using MediaBrowser.Model.Entities;
namespace MediaBrowser.Controller.Entities
{
@@ -10,6 +11,7 @@ namespace MediaBrowser.Controller.Entities
/// </summary>
/// <param name="enablePathSubstitution">if set to <c>true</c> [enable path substitution].</param>
/// <returns>Task{IEnumerable{MediaSourceInfo}}.</returns>
- IEnumerable<MediaSourceInfo> GetMediaSources(bool enablePathSubstitution);
+ List<MediaSourceInfo> GetMediaSources(bool enablePathSubstitution);
+ List<MediaStream> GetMediaStreams();
}
}
diff --git a/MediaBrowser.Controller/Entities/IHasMetadata.cs b/MediaBrowser.Controller/Entities/IHasMetadata.cs
index 62c67336c..59d9bd9f9 100644
--- a/MediaBrowser.Controller/Entities/IHasMetadata.cs
+++ b/MediaBrowser.Controller/Entities/IHasMetadata.cs
@@ -1,12 +1,18 @@
using System;
using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
+using MediaBrowser.Controller.Library;
+using MediaBrowser.Controller.Providers;
+using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.IO;
namespace MediaBrowser.Controller.Entities
{
/// <summary>
/// Interface IHasMetadata
/// </summary>
- public interface IHasMetadata : IHasImages
+ public interface IHasMetadata : IHasProviderIds, IHasUserData
{
/// <summary>
/// Gets the preferred metadata country code.
@@ -64,6 +70,253 @@ namespace MediaBrowser.Controller.Entities
int? GetInheritedParentalRatingValue();
int InheritedParentalRatingValue { get; set; }
List<string> GetInheritedTags();
- List<string> InheritedTags { get; set; }
+ long? RunTimeTicks { get; set; }
+
+ /// <summary>
+ /// Gets the name.
+ /// </summary>
+ /// <value>The name.</value>
+ string Name { get; set; }
+
+ /// <summary>
+ /// Gets the path.
+ /// </summary>
+ /// <value>The path.</value>
+ string Path { get; set; }
+
+ /// <summary>
+ /// Gets the file name without extension.
+ /// </summary>
+ /// <value>The file name without extension.</value>
+ string FileNameWithoutExtension { get; }
+
+ /// <summary>
+ /// Gets the type of the location.
+ /// </summary>
+ /// <value>The type of the location.</value>
+ LocationType LocationType { get; }
+
+ /// <summary>
+ /// Gets the locked fields.
+ /// </summary>
+ /// <value>The locked fields.</value>
+ MetadataFields[] LockedFields { get; }
+
+ /// <summary>
+ /// Gets the images.
+ /// </summary>
+ /// <param name="imageType">Type of the image.</param>
+ /// <returns>IEnumerable{ItemImageInfo}.</returns>
+ IEnumerable<ItemImageInfo> GetImages(ImageType imageType);
+
+ /// <summary>
+ /// Gets the image path.
+ /// </summary>
+ /// <param name="imageType">Type of the image.</param>
+ /// <param name="imageIndex">Index of the image.</param>
+ /// <returns>System.String.</returns>
+ string GetImagePath(ImageType imageType, int imageIndex);
+
+ /// <summary>
+ /// Gets the image information.
+ /// </summary>
+ /// <param name="imageType">Type of the image.</param>
+ /// <param name="imageIndex">Index of the image.</param>
+ /// <returns>ItemImageInfo.</returns>
+ ItemImageInfo GetImageInfo(ImageType imageType, int imageIndex);
+
+ /// <summary>
+ /// Sets the image.
+ /// </summary>
+ /// <param name="type">The type.</param>
+ /// <param name="index">The index.</param>
+ /// <param name="file">The file.</param>
+ void SetImagePath(ImageType type, int index, FileSystemMetadata file);
+
+ /// <summary>
+ /// Determines whether the specified type has image.
+ /// </summary>
+ /// <param name="type">The type.</param>
+ /// <param name="imageIndex">Index of the image.</param>
+ /// <returns><c>true</c> if the specified type has image; otherwise, <c>false</c>.</returns>
+ bool HasImage(ImageType type, int imageIndex);
+
+ /// <summary>
+ /// Allowses the multiple images.
+ /// </summary>
+ /// <param name="type">The type.</param>
+ /// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
+ bool AllowsMultipleImages(ImageType type);
+
+ /// <summary>
+ /// Swaps the images.
+ /// </summary>
+ /// <param name="type">The type.</param>
+ /// <param name="index1">The index1.</param>
+ /// <param name="index2">The index2.</param>
+ /// <returns>Task.</returns>
+ Task SwapImages(ImageType type, int index1, int index2);
+
+ /// <summary>
+ /// Gets or sets the primary image path.
+ /// </summary>
+ /// <value>The primary image path.</value>
+ string PrimaryImagePath { get; }
+
+ /// <summary>
+ /// Gets the preferred metadata language.
+ /// </summary>
+ /// <returns>System.String.</returns>
+ string GetPreferredMetadataLanguage();
+
+ /// <summary>
+ /// Validates the images and returns true or false indicating if any were removed.
+ /// </summary>
+ bool ValidateImages(IDirectoryService directoryService);
+
+ /// <summary>
+ /// Gets a value indicating whether this instance is owned item.
+ /// </summary>
+ /// <value><c>true</c> if this instance is owned item; otherwise, <c>false</c>.</value>
+ bool IsOwnedItem { get; }
+
+ /// <summary>
+ /// Gets the containing folder path.
+ /// </summary>
+ /// <value>The containing folder path.</value>
+ string ContainingFolderPath { get; }
+
+ /// <summary>
+ /// Adds the images.
+ /// </summary>
+ /// <param name="imageType">Type of the image.</param>
+ /// <param name="images">The images.</param>
+ /// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
+ bool AddImages(ImageType imageType, List<FileSystemMetadata> images);
+
+ /// <summary>
+ /// Determines whether [is save local metadata enabled].
+ /// </summary>
+ /// <returns><c>true</c> if [is save local metadata enabled]; otherwise, <c>false</c>.</returns>
+ bool IsSaveLocalMetadataEnabled();
+
+ /// <summary>
+ /// Gets a value indicating whether [supports local metadata].
+ /// </summary>
+ /// <value><c>true</c> if [supports local metadata]; otherwise, <c>false</c>.</value>
+ bool SupportsLocalMetadata { get; }
+
+ bool IsInMixedFolder { get; }
+
+ /// <summary>
+ /// Gets a value indicating whether this instance is locked.
+ /// </summary>
+ /// <value><c>true</c> if this instance is locked; otherwise, <c>false</c>.</value>
+ bool IsLocked { get; }
+
+ /// <summary>
+ /// Gets a value indicating whether [supports remote image downloading].
+ /// </summary>
+ /// <value><c>true</c> if [supports remote image downloading]; otherwise, <c>false</c>.</value>
+ bool SupportsRemoteImageDownloading { get; }
+
+ /// <summary>
+ /// Gets the internal metadata path.
+ /// </summary>
+ /// <returns>System.String.</returns>
+ string GetInternalMetadataPath();
+
+ /// <summary>
+ /// Gets a value indicating whether [always scan internal metadata path].
+ /// </summary>
+ /// <value><c>true</c> if [always scan internal metadata path]; otherwise, <c>false</c>.</value>
+ bool AlwaysScanInternalMetadataPath { get; }
+
+ /// <summary>
+ /// Determines whether [is internet metadata enabled].
+ /// </summary>
+ /// <returns><c>true</c> if [is internet metadata enabled]; otherwise, <c>false</c>.</returns>
+ bool IsInternetMetadataEnabled();
+
+ /// <summary>
+ /// Removes the image.
+ /// </summary>
+ /// <param name="image">The image.</param>
+ void RemoveImage(ItemImageInfo image);
+
+ void RemoveImages(List<ItemImageInfo> images);
+
+ /// <summary>
+ /// Updates to repository.
+ /// </summary>
+ /// <param name="updateReason">The update reason.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task.</returns>
+ Task UpdateToRepository(ItemUpdateType updateReason, CancellationToken cancellationToken);
+
+ /// <summary>
+ /// Sets the image.
+ /// </summary>
+ /// <param name="image">The image.</param>
+ /// <param name="index">The index.</param>
+ void SetImage(ItemImageInfo image, int index);
+
+ double? GetDefaultPrimaryImageAspectRatio();
+
+ int? ProductionYear { get; set; }
+
+ string[] Tags { get; set; }
+ }
+
+ public static class HasMetadataExtensions
+ {
+ /// <summary>
+ /// Gets the image path.
+ /// </summary>
+ /// <param name="item">The item.</param>
+ /// <param name="imageType">Type of the image.</param>
+ /// <returns>System.String.</returns>
+ public static string GetImagePath(this IHasMetadata item, ImageType imageType)
+ {
+ return item.GetImagePath(imageType, 0);
+ }
+
+ public static bool HasImage(this IHasMetadata item, ImageType imageType)
+ {
+ return item.HasImage(imageType, 0);
+ }
+
+ /// <summary>
+ /// Sets the image path.
+ /// </summary>
+ /// <param name="item">The item.</param>
+ /// <param name="imageType">Type of the image.</param>
+ /// <param name="file">The file.</param>
+ public static void SetImagePath(this IHasMetadata item, ImageType imageType, FileSystemMetadata file)
+ {
+ item.SetImagePath(imageType, 0, file);
+ }
+
+ /// <summary>
+ /// Sets the image path.
+ /// </summary>
+ /// <param name="item">The item.</param>
+ /// <param name="imageType">Type of the image.</param>
+ /// <param name="file">The file.</param>
+ public static void SetImagePath(this IHasMetadata item, ImageType imageType, string file)
+ {
+ if (file.StartsWith("http", System.StringComparison.OrdinalIgnoreCase))
+ {
+ item.SetImage(new ItemImageInfo
+ {
+ Path = file,
+ Type = imageType
+ }, 0);
+ }
+ else
+ {
+ item.SetImagePath(imageType, BaseItem.FileSystem.GetFileInfo(file));
+ }
+ }
}
}
diff --git a/MediaBrowser.Controller/Entities/IHasSpecialFeatures.cs b/MediaBrowser.Controller/Entities/IHasSpecialFeatures.cs
index b3a0dc237..f4905b7dc 100644
--- a/MediaBrowser.Controller/Entities/IHasSpecialFeatures.cs
+++ b/MediaBrowser.Controller/Entities/IHasSpecialFeatures.cs
@@ -1,5 +1,4 @@
using System;
-using System.Collections.Generic;
namespace MediaBrowser.Controller.Entities
{
@@ -9,6 +8,6 @@ namespace MediaBrowser.Controller.Entities
/// Gets or sets the special feature ids.
/// </summary>
/// <value>The special feature ids.</value>
- List<Guid> SpecialFeatureIds { get; set; }
+ Guid[] SpecialFeatureIds { get; set; }
}
}
diff --git a/MediaBrowser.Controller/Entities/IHasTrailers.cs b/MediaBrowser.Controller/Entities/IHasTrailers.cs
index e5cbdff72..8686c802a 100644
--- a/MediaBrowser.Controller/Entities/IHasTrailers.cs
+++ b/MediaBrowser.Controller/Entities/IHasTrailers.cs
@@ -11,14 +11,14 @@ namespace MediaBrowser.Controller.Entities
/// Gets or sets the remote trailers.
/// </summary>
/// <value>The remote trailers.</value>
- List<MediaUrl> RemoteTrailers { get; set; }
+ MediaUrl[] RemoteTrailers { get; set; }
/// <summary>
/// Gets or sets the local trailer ids.
/// </summary>
/// <value>The local trailer ids.</value>
- List<Guid> LocalTrailerIds { get; set; }
- List<Guid> RemoteTrailerIds { get; set; }
+ Guid[] LocalTrailerIds { get; set; }
+ Guid[] RemoteTrailerIds { get; set; }
}
public static class HasTrailerExtensions
diff --git a/MediaBrowser.Controller/Entities/IHasUserData.cs b/MediaBrowser.Controller/Entities/IHasUserData.cs
index 0029947ee..ce4a482ba 100644
--- a/MediaBrowser.Controller/Entities/IHasUserData.cs
+++ b/MediaBrowser.Controller/Entities/IHasUserData.cs
@@ -1,4 +1,5 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
using System.Threading.Tasks;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Querying;
@@ -8,7 +9,7 @@ namespace MediaBrowser.Controller.Entities
/// <summary>
/// Interface IHasUserData
/// </summary>
- public interface IHasUserData : IHasId
+ public interface IHasUserData
{
List<string> GetUserDataKeys();
@@ -20,5 +21,7 @@ namespace MediaBrowser.Controller.Entities
bool EnableRememberingTrackSelections { get; }
bool SupportsPlayedStatus { get; }
+
+ Guid Id { get; }
}
}
diff --git a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs
index 608e3f56c..04833d049 100644
--- a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs
+++ b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs
@@ -38,12 +38,10 @@ namespace MediaBrowser.Controller.Entities
public string[] ExcludeTags { get; set; }
public string[] ExcludeInheritedTags { get; set; }
public string[] Genres { get; set; }
- public string[] Keywords { get; set; }
public bool? IsSpecialSeason { get; set; }
public bool? IsMissing { get; set; }
public bool? IsUnaired { get; set; }
- public bool? IsVirtualUnaired { get; set; }
public bool? CollapseBoxSetItems { get; set; }
public string NameStartsWithOrGreater { get; set; }
@@ -150,7 +148,6 @@ namespace MediaBrowser.Controller.Entities
public TrailerType[] TrailerTypes { get; set; }
public SourceType[] SourceTypes { get; set; }
- public DayOfWeek[] AirDays { get; set; }
public SeriesStatus[] SeriesStatuses { get; set; }
public string ExternalSeriesId { get; set; }
public string ExternalId { get; set; }
@@ -162,6 +159,7 @@ namespace MediaBrowser.Controller.Entities
public string SeriesPresentationUniqueKey { get; set; }
public bool GroupByPresentationUniqueKey { get; set; }
+ public bool GroupBySeriesPresentationUniqueKey { get; set; }
public bool EnableTotalRecordCount { get; set; }
public bool ForceDirect { get; set; }
public Dictionary<string, string> ExcludeProviderIds { get; set; }
@@ -194,7 +192,6 @@ namespace MediaBrowser.Controller.Entities
OfficialRatings = new string[] { };
SortBy = new string[] { };
MediaTypes = new string[] { };
- Keywords = new string[] { };
IncludeItemTypes = new string[] { };
ExcludeItemTypes = new string[] { };
Genres = new string[] { };
@@ -215,7 +212,6 @@ namespace MediaBrowser.Controller.Entities
PresetViews = new string[] { };
TrailerTypes = new TrailerType[] { };
SourceTypes = new SourceType[] { };
- AirDays = new DayOfWeek[] { };
SeriesStatuses = new SeriesStatus[] { };
OrderBy = new List<Tuple<string, SortOrder>>();
}
diff --git a/MediaBrowser.Controller/Entities/KeywordExtensions.cs b/MediaBrowser.Controller/Entities/KeywordExtensions.cs
deleted file mode 100644
index 5c9afdf3d..000000000
--- a/MediaBrowser.Controller/Entities/KeywordExtensions.cs
+++ /dev/null
@@ -1,21 +0,0 @@
-using System;
-using System.Linq;
-
-namespace MediaBrowser.Controller.Entities
-{
- public static class KeywordExtensions
- {
- public static void AddKeyword(this BaseItem item, string name)
- {
- if (string.IsNullOrWhiteSpace(name))
- {
- throw new ArgumentNullException("name");
- }
-
- if (!item.Keywords.Contains(name, StringComparer.OrdinalIgnoreCase))
- {
- item.Keywords.Add(name);
- }
- }
- }
-}
diff --git a/MediaBrowser.Controller/Entities/Movies/BoxSet.cs b/MediaBrowser.Controller/Entities/Movies/BoxSet.cs
index 071ed405f..6ba9577d1 100644
--- a/MediaBrowser.Controller/Entities/Movies/BoxSet.cs
+++ b/MediaBrowser.Controller/Entities/Movies/BoxSet.cs
@@ -21,9 +21,9 @@ namespace MediaBrowser.Controller.Entities.Movies
public BoxSet()
{
- RemoteTrailers = new List<MediaUrl>();
- LocalTrailerIds = new List<Guid>();
- RemoteTrailerIds = new List<Guid>();
+ RemoteTrailers = EmptyMediaUrlArray;
+ LocalTrailerIds = EmptyGuidArray;
+ RemoteTrailerIds = EmptyGuidArray;
DisplayOrder = ItemSortBy.PremiereDate;
Shares = new List<Share>();
@@ -47,14 +47,14 @@ namespace MediaBrowser.Controller.Entities.Movies
}
}
- public List<Guid> LocalTrailerIds { get; set; }
- public List<Guid> RemoteTrailerIds { get; set; }
+ public Guid[] LocalTrailerIds { get; set; }
+ public Guid[] RemoteTrailerIds { get; set; }
/// <summary>
/// Gets or sets the remote trailers.
/// </summary>
/// <value>The remote trailers.</value>
- public List<MediaUrl> RemoteTrailers { get; set; }
+ public MediaUrl[] RemoteTrailers { get; set; }
/// <summary>
/// Gets or sets the display order.
@@ -116,7 +116,7 @@ namespace MediaBrowser.Controller.Entities.Movies
{
if (IsLegacyBoxSet)
{
- return true;
+ return false;
}
return false;
@@ -148,17 +148,6 @@ namespace MediaBrowser.Controller.Entities.Movies
}
/// <summary>
- /// Gets the trailer ids.
- /// </summary>
- /// <returns>List&lt;Guid&gt;.</returns>
- public List<Guid> GetTrailerIds()
- {
- var list = LocalTrailerIds.ToList();
- list.AddRange(RemoteTrailerIds);
- return list;
- }
-
- /// <summary>
/// Updates the official rating based on content and returns true or false indicating if it changed.
/// </summary>
/// <returns></returns>
diff --git a/MediaBrowser.Controller/Entities/Movies/Movie.cs b/MediaBrowser.Controller/Entities/Movies/Movie.cs
index 8a5b726e2..3a41709fe 100644
--- a/MediaBrowser.Controller/Entities/Movies/Movie.cs
+++ b/MediaBrowser.Controller/Entities/Movies/Movie.cs
@@ -19,20 +19,20 @@ namespace MediaBrowser.Controller.Entities.Movies
/// </summary>
public class Movie : Video, IHasSpecialFeatures, IHasTrailers, IHasLookupInfo<MovieInfo>, ISupportsBoxSetGrouping
{
- public List<Guid> SpecialFeatureIds { get; set; }
+ public Guid[] SpecialFeatureIds { get; set; }
public Movie()
{
- SpecialFeatureIds = new List<Guid>();
- RemoteTrailers = new List<MediaUrl>();
- LocalTrailerIds = new List<Guid>();
- RemoteTrailerIds = new List<Guid>();
+ SpecialFeatureIds = EmptyGuidArray;
+ RemoteTrailers = EmptyMediaUrlArray;
+ LocalTrailerIds = EmptyGuidArray;
+ RemoteTrailerIds = EmptyGuidArray;
}
- public List<Guid> LocalTrailerIds { get; set; }
- public List<Guid> RemoteTrailerIds { get; set; }
+ public Guid[] LocalTrailerIds { get; set; }
+ public Guid[] RemoteTrailerIds { get; set; }
- public List<MediaUrl> RemoteTrailers { get; set; }
+ public MediaUrl[] RemoteTrailers { get; set; }
/// <summary>
/// Gets or sets the name of the TMDB collection.
@@ -55,22 +55,13 @@ namespace MediaBrowser.Controller.Entities.Movies
return value;
}
- [IgnoreDataMember]
- protected override bool SupportsIsInMixedFolderDetection
- {
- get
- {
- return false;
- }
- }
-
protected override async Task<bool> RefreshedOwnedItems(MetadataRefreshOptions options, List<FileSystemMetadata> fileSystemChildren, CancellationToken cancellationToken)
{
var hasChanges = await base.RefreshedOwnedItems(options, fileSystemChildren, cancellationToken).ConfigureAwait(false);
// Must have a parent to have special features
// In other words, it must be part of the Parent/Child tree
- if (LocationType == LocationType.FileSystem && GetParent() != null && !DetectIsInMixedFolder())
+ if (LocationType == LocationType.FileSystem && GetParent() != null && !IsInMixedFolder)
{
var specialFeaturesChanged = await RefreshSpecialFeatures(options, fileSystemChildren, cancellationToken).ConfigureAwait(false);
@@ -86,7 +77,7 @@ namespace MediaBrowser.Controller.Entities.Movies
private async Task<bool> RefreshSpecialFeatures(MetadataRefreshOptions options, List<FileSystemMetadata> fileSystemChildren, CancellationToken cancellationToken)
{
var newItems = LibraryManager.FindExtras(this, fileSystemChildren, options.DirectoryService).ToList();
- var newItemIds = newItems.Select(i => i.Id).ToList();
+ var newItemIds = newItems.Select(i => i.Id).ToArray();
var itemsChanged = !SpecialFeatureIds.SequenceEqual(newItemIds);
@@ -108,7 +99,7 @@ namespace MediaBrowser.Controller.Entities.Movies
{
var info = GetItemLookupInfo<MovieInfo>();
- if (!DetectIsInMixedFolder())
+ if (!IsInMixedFolder)
{
var name = System.IO.Path.GetFileName(ContainingFolderPath);
@@ -145,7 +136,7 @@ namespace MediaBrowser.Controller.Entities.Movies
else
{
// Try to get the year from the folder name
- if (!DetectIsInMixedFolder())
+ if (!IsInMixedFolder)
{
info = LibraryManager.ParseName(System.IO.Path.GetFileName(ContainingFolderPath));
diff --git a/MediaBrowser.Controller/Entities/MusicVideo.cs b/MediaBrowser.Controller/Entities/MusicVideo.cs
index 7344cb8e4..2028c1c3b 100644
--- a/MediaBrowser.Controller/Entities/MusicVideo.cs
+++ b/MediaBrowser.Controller/Entities/MusicVideo.cs
@@ -8,6 +8,7 @@ namespace MediaBrowser.Controller.Entities
{
public class MusicVideo : Video, IHasArtist, IHasMusicGenres, IHasLookupInfo<MusicVideoInfo>
{
+ [IgnoreDataMember]
public List<string> Artists { get; set; }
public MusicVideo()
@@ -24,15 +25,6 @@ namespace MediaBrowser.Controller.Entities
}
}
- [IgnoreDataMember]
- protected override bool SupportsIsInMixedFolderDetection
- {
- get
- {
- return false;
- }
- }
-
public override UnratedItem GetBlockUnratedType()
{
return UnratedItem.Music;
@@ -61,7 +53,7 @@ namespace MediaBrowser.Controller.Entities
else
{
// Try to get the year from the folder name
- if (!DetectIsInMixedFolder())
+ if (!IsInMixedFolder)
{
info = LibraryManager.ParseName(System.IO.Path.GetFileName(ContainingFolderPath));
diff --git a/MediaBrowser.Controller/Entities/TV/Episode.cs b/MediaBrowser.Controller/Entities/TV/Episode.cs
index 45b4de1b3..c30e0ef8e 100644
--- a/MediaBrowser.Controller/Entities/TV/Episode.cs
+++ b/MediaBrowser.Controller/Entities/TV/Episode.cs
@@ -17,14 +17,14 @@ namespace MediaBrowser.Controller.Entities.TV
{
public Episode()
{
- RemoteTrailers = new List<MediaUrl>();
- LocalTrailerIds = new List<Guid>();
- RemoteTrailerIds = new List<Guid>();
+ RemoteTrailers = EmptyMediaUrlArray;
+ LocalTrailerIds = EmptyGuidArray;
+ RemoteTrailerIds = EmptyGuidArray;
}
- public List<Guid> LocalTrailerIds { get; set; }
- public List<Guid> RemoteTrailerIds { get; set; }
- public List<MediaUrl> RemoteTrailers { get; set; }
+ public Guid[] LocalTrailerIds { get; set; }
+ public Guid[] RemoteTrailerIds { get; set; }
+ public MediaUrl[] RemoteTrailers { get; set; }
/// <summary>
/// Gets the season in which it aired.
@@ -282,17 +282,11 @@ namespace MediaBrowser.Controller.Entities.TV
{
get
{
- return LocationType == LocationType.Virtual && !IsUnaired;
+ return LocationType == LocationType.Virtual;
}
}
[IgnoreDataMember]
- public bool IsVirtualUnaired
- {
- get { return LocationType == LocationType.Virtual && IsUnaired; }
- }
-
- [IgnoreDataMember]
public Guid? SeasonId { get; set; }
[IgnoreDataMember]
public Guid? SeriesId { get; set; }
@@ -346,7 +340,6 @@ namespace MediaBrowser.Controller.Entities.TV
id.IsMissingEpisode = IsMissingEpisode;
id.IndexNumberEnd = IndexNumberEnd;
- id.IsVirtualUnaired = IsVirtualUnaired;
return id;
}
diff --git a/MediaBrowser.Controller/Entities/TV/Series.cs b/MediaBrowser.Controller/Entities/TV/Series.cs
index 8b73b80b0..3350a6579 100644
--- a/MediaBrowser.Controller/Entities/TV/Series.cs
+++ b/MediaBrowser.Controller/Entities/TV/Series.cs
@@ -22,13 +22,15 @@ namespace MediaBrowser.Controller.Entities.TV
{
public Series()
{
- AirDays = new List<DayOfWeek>();
-
- RemoteTrailers = new List<MediaUrl>();
- LocalTrailerIds = new List<Guid>();
- RemoteTrailerIds = new List<Guid>();
+ RemoteTrailers = EmptyMediaUrlArray;
+ LocalTrailerIds = EmptyGuidArray;
+ RemoteTrailerIds = EmptyGuidArray;
+ AirDays = new DayOfWeek[] { };
}
+ public DayOfWeek[] AirDays { get; set; }
+ public string AirTime { get; set; }
+
[IgnoreDataMember]
public override bool SupportsAddingToPlaylist
{
@@ -62,10 +64,10 @@ namespace MediaBrowser.Controller.Entities.TV
}
}
- public List<Guid> LocalTrailerIds { get; set; }
- public List<Guid> RemoteTrailerIds { get; set; }
+ public Guid[] LocalTrailerIds { get; set; }
+ public Guid[] RemoteTrailerIds { get; set; }
- public List<MediaUrl> RemoteTrailers { get; set; }
+ public MediaUrl[] RemoteTrailers { get; set; }
/// <summary>
/// airdate, dvd or absolute
@@ -77,16 +79,6 @@ namespace MediaBrowser.Controller.Entities.TV
/// </summary>
/// <value>The status.</value>
public SeriesStatus? Status { get; set; }
- /// <summary>
- /// Gets or sets the air days.
- /// </summary>
- /// <value>The air days.</value>
- public List<DayOfWeek> AirDays { get; set; }
- /// <summary>
- /// Gets or sets the air time.
- /// </summary>
- /// <value>The air time.</value>
- public string AirTime { get; set; }
/// <summary>
/// Gets or sets the date last episode added.
@@ -193,7 +185,7 @@ namespace MediaBrowser.Controller.Entities.TV
if (query.IncludeItemTypes.Length == 0)
{
- query.IncludeItemTypes = new[] { typeof(Episode).Name, typeof(Season).Name };
+ query.IncludeItemTypes = new[] { typeof(Episode).Name };
}
query.IsVirtualItem = false;
query.Limit = 0;
@@ -225,17 +217,6 @@ namespace MediaBrowser.Controller.Entities.TV
return list;
}
- /// <summary>
- /// Gets the trailer ids.
- /// </summary>
- /// <returns>List&lt;Guid&gt;.</returns>
- public List<Guid> GetTrailerIds()
- {
- var list = LocalTrailerIds.ToList();
- list.AddRange(RemoteTrailerIds);
- return list;
- }
-
[IgnoreDataMember]
public bool ContainsEpisodesWithoutSeasonFolders
{
@@ -273,18 +254,10 @@ namespace MediaBrowser.Controller.Entities.TV
query.IncludeItemTypes = new[] { typeof(Season).Name };
query.SortBy = new[] {ItemSortBy.SortName};
- if (!config.DisplayMissingEpisodes && !config.DisplayUnairedEpisodes)
- {
- query.IsVirtualItem = false;
- }
- else if (!config.DisplayMissingEpisodes)
+ if (!config.DisplayMissingEpisodes)
{
query.IsMissing = false;
}
- else if (!config.DisplayUnairedEpisodes)
- {
- query.IsVirtualUnaired = false;
- }
}
protected override QueryResult<BaseItem> GetItemsInternal(InternalItemsQuery query)
@@ -332,27 +305,18 @@ namespace MediaBrowser.Controller.Entities.TV
DtoOptions = options
};
var config = user.Configuration;
- if (!config.DisplayMissingEpisodes && !config.DisplayUnairedEpisodes)
- {
- query.IsVirtualItem = false;
- }
- else if (!config.DisplayMissingEpisodes)
+ if (!config.DisplayMissingEpisodes)
{
query.IsMissing = false;
}
- else if (!config.DisplayUnairedEpisodes)
- {
- query.IsVirtualUnaired = false;
- }
- var allItems = LibraryManager.GetItemList(query).ToList();
+ var allItems = LibraryManager.GetItemList(query);
- var allSeriesEpisodes = allItems.OfType<Episode>().ToList();
+ var allSeriesEpisodes = allItems.OfType<Episode>();
var allEpisodes = allItems.OfType<Season>()
.SelectMany(i => i.GetEpisodes(this, user, allSeriesEpisodes, options))
- .Reverse()
- .ToList();
+ .Reverse();
// Specials could appear twice based on above - once in season 0, once in the aired season
// This depends on settings for that series
@@ -365,20 +329,22 @@ namespace MediaBrowser.Controller.Entities.TV
{
// Refresh bottom up, children first, then the boxset
// By then hopefully the movies within will have Tmdb collection values
- var items = GetRecursiveChildren().ToList();
-
- var seasons = items.OfType<Season>().ToList();
- var otherItems = items.Except(seasons).ToList();
+ var items = GetRecursiveChildren();
- var totalItems = seasons.Count + otherItems.Count;
+ var totalItems = items.Count;
var numComplete = 0;
// Refresh current item
await RefreshMetadata(refreshOptions, cancellationToken).ConfigureAwait(false);
// Refresh seasons
- foreach (var item in seasons)
+ foreach (var item in items)
{
+ if (!(item is Season))
+ {
+ continue;
+ }
+
cancellationToken.ThrowIfCancellationRequested();
await item.RefreshMetadata(refreshOptions, cancellationToken).ConfigureAwait(false);
@@ -390,8 +356,13 @@ namespace MediaBrowser.Controller.Entities.TV
}
// Refresh episodes and other children
- foreach (var item in otherItems)
+ foreach (var item in items)
{
+ if ((item is Season))
+ {
+ continue;
+ }
+
cancellationToken.ThrowIfCancellationRequested();
var skipItem = false;
@@ -445,18 +416,10 @@ namespace MediaBrowser.Controller.Entities.TV
if (user != null)
{
var config = user.Configuration;
- if (!config.DisplayMissingEpisodes && !config.DisplayUnairedEpisodes)
- {
- query.IsVirtualItem = false;
- }
- else if (!config.DisplayMissingEpisodes)
+ if (!config.DisplayMissingEpisodes)
{
query.IsMissing = false;
}
- else if (!config.DisplayUnairedEpisodes)
- {
- query.IsVirtualUnaired = false;
- }
}
var allItems = LibraryManager.GetItemList(query).OfType<Episode>();
diff --git a/MediaBrowser.Controller/Entities/TagExtensions.cs b/MediaBrowser.Controller/Entities/TagExtensions.cs
index 0e1df72cd..e5d8f35d9 100644
--- a/MediaBrowser.Controller/Entities/TagExtensions.cs
+++ b/MediaBrowser.Controller/Entities/TagExtensions.cs
@@ -1,5 +1,7 @@
using System;
+using System.Collections.Generic;
using System.Linq;
+using MediaBrowser.Model.Extensions;
namespace MediaBrowser.Controller.Entities
{
@@ -12,9 +14,21 @@ namespace MediaBrowser.Controller.Entities
throw new ArgumentNullException("name");
}
- if (!item.Tags.Contains(name, StringComparer.OrdinalIgnoreCase))
+ var current = item.Tags;
+
+ if (!current.Contains(name, StringComparer.OrdinalIgnoreCase))
{
- item.Tags.Add(name);
+ if (current.Length == 0)
+ {
+ item.Tags = new[] { name };
+ }
+ else
+ {
+ var list = current.ToArray(current.Length + 1);
+ list[list.Length - 1] = name;
+
+ item.Tags = list;
+ }
}
}
}
diff --git a/MediaBrowser.Controller/Entities/Trailer.cs b/MediaBrowser.Controller/Entities/Trailer.cs
index b4a142a8e..c5144aadf 100644
--- a/MediaBrowser.Controller/Entities/Trailer.cs
+++ b/MediaBrowser.Controller/Entities/Trailer.cs
@@ -15,7 +15,6 @@ namespace MediaBrowser.Controller.Entities
public Trailer()
{
RemoteTrailers = new List<MediaUrl>();
- Keywords = new List<string>();
TrailerTypes = new List<TrailerType> { TrailerType.LocalTrailer };
}
@@ -48,7 +47,7 @@ namespace MediaBrowser.Controller.Entities
info.IsLocalTrailer = TrailerTypes.Contains(TrailerType.LocalTrailer);
- if (!DetectIsInMixedFolder() && LocationType == LocationType.FileSystem)
+ if (!IsInMixedFolder && LocationType == LocationType.FileSystem)
{
info.Name = System.IO.Path.GetFileName(ContainingFolderPath);
}
@@ -74,7 +73,7 @@ namespace MediaBrowser.Controller.Entities
else
{
// Try to get the year from the folder name
- if (!DetectIsInMixedFolder())
+ if (!IsInMixedFolder)
{
info = LibraryManager.ParseName(System.IO.Path.GetFileName(ContainingFolderPath));
diff --git a/MediaBrowser.Controller/Entities/UserView.cs b/MediaBrowser.Controller/Entities/UserView.cs
index 0d2d69c94..4c44a613b 100644
--- a/MediaBrowser.Controller/Entities/UserView.cs
+++ b/MediaBrowser.Controller/Entities/UserView.cs
@@ -82,7 +82,7 @@ namespace MediaBrowser.Controller.Entities
public override IEnumerable<BaseItem> GetChildren(User user, bool includeLinkedChildren)
{
- var result = GetItems(new InternalItemsQuery
+ var result = GetItemList(new InternalItemsQuery
{
User = user,
EnableTotalRecordCount = false,
@@ -90,7 +90,7 @@ namespace MediaBrowser.Controller.Entities
});
- return result.Items;
+ return result;
}
public override bool CanDelete()
@@ -105,7 +105,7 @@ namespace MediaBrowser.Controller.Entities
public override IEnumerable<BaseItem> GetRecursiveChildren(User user, InternalItemsQuery query)
{
- var result = GetItems(new InternalItemsQuery
+ var result = GetItemList(new InternalItemsQuery
{
User = user,
Recursive = true,
@@ -117,7 +117,7 @@ namespace MediaBrowser.Controller.Entities
});
- return result.Items.Where(i => UserViewBuilder.FilterItem(i, query));
+ return result.Where(i => UserViewBuilder.FilterItem(i, query));
}
protected override IEnumerable<BaseItem> GetEligibleChildrenForRecursiveChildren(User user)
diff --git a/MediaBrowser.Controller/Entities/UserViewBuilder.cs b/MediaBrowser.Controller/Entities/UserViewBuilder.cs
index 91e24caeb..9323404e3 100644
--- a/MediaBrowser.Controller/Entities/UserViewBuilder.cs
+++ b/MediaBrowser.Controller/Entities/UserViewBuilder.cs
@@ -779,7 +779,6 @@ namespace MediaBrowser.Controller.Entities
items = FilterVirtualEpisodes(items,
query.IsMissing,
- query.IsVirtualUnaired,
query.IsUnaired);
if (collapseBoxSetItems && user != null)
@@ -1065,7 +1064,6 @@ namespace MediaBrowser.Controller.Entities
private static IEnumerable<BaseItem> FilterVirtualEpisodes(
IEnumerable<BaseItem> items,
bool? isMissing,
- bool? isVirtualUnaired,
bool? isUnaired)
{
if (isMissing.HasValue)
@@ -1096,20 +1094,6 @@ namespace MediaBrowser.Controller.Entities
});
}
- if (isVirtualUnaired.HasValue)
- {
- var val = isVirtualUnaired.Value;
- items = items.Where(i =>
- {
- var e = i as Episode;
- if (e != null)
- {
- return e.IsVirtualUnaired == val;
- }
- return true;
- });
- }
-
return items;
}
@@ -1387,8 +1371,8 @@ namespace MediaBrowser.Controller.Entities
if (movie != null)
{
var ok = filterValue
- ? movie.SpecialFeatureIds.Count > 0
- : movie.SpecialFeatureIds.Count == 0;
+ ? movie.SpecialFeatureIds.Length > 0
+ : movie.SpecialFeatureIds.Length == 0;
if (!ok)
{
@@ -1463,7 +1447,7 @@ namespace MediaBrowser.Controller.Entities
{
var filterValue = query.HasThemeSong.Value;
- var themeCount = item.ThemeSongIds.Count;
+ var themeCount = item.ThemeSongIds.Length;
var ok = filterValue ? themeCount > 0 : themeCount == 0;
if (!ok)
@@ -1476,7 +1460,7 @@ namespace MediaBrowser.Controller.Entities
{
var filterValue = query.HasThemeVideo.Value;
- var themeCount = item.ThemeVideoIds.Count;
+ var themeCount = item.ThemeVideoIds.Length;
var ok = filterValue ? themeCount > 0 : themeCount == 0;
if (!ok)
@@ -1674,15 +1658,6 @@ namespace MediaBrowser.Controller.Entities
}
}
- if (query.AirDays.Length > 0)
- {
- var ok = new[] { item }.OfType<Series>().Any(p => p.AirDays != null && query.AirDays.Any(d => p.AirDays.Contains(d)));
- if (!ok)
- {
- return false;
- }
- }
-
if (query.SeriesStatuses.Length > 0)
{
var ok = new[] { item }.OfType<Series>().Any(p => p.Status.HasValue && query.SeriesStatuses.Contains(p.Status.Value));
diff --git a/MediaBrowser.Controller/Entities/Video.cs b/MediaBrowser.Controller/Entities/Video.cs
index c5d9b9203..fbeefbbd9 100644
--- a/MediaBrowser.Controller/Entities/Video.cs
+++ b/MediaBrowser.Controller/Entities/Video.cs
@@ -16,6 +16,7 @@ using MediaBrowser.Controller.Channels;
using MediaBrowser.Controller.IO;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Serialization;
+using MediaBrowser.Model.Extensions;
namespace MediaBrowser.Controller.Entities
{
@@ -30,9 +31,9 @@ namespace MediaBrowser.Controller.Entities
[IgnoreDataMember]
public string PrimaryVersionId { get; set; }
- public List<string> AdditionalParts { get; set; }
- public List<string> LocalAlternateVersions { get; set; }
- public List<LinkedChild> LinkedAlternateVersions { get; set; }
+ public string[] AdditionalParts { get; set; }
+ public string[] LocalAlternateVersions { get; set; }
+ public LinkedChild[] LinkedAlternateVersions { get; set; }
[IgnoreDataMember]
public override bool SupportsPlayedStatus
@@ -52,6 +53,12 @@ namespace MediaBrowser.Controller.Entities
}
}
+ /// <summary>
+ /// Gets or sets the display type of the media.
+ /// </summary>
+ /// <value>The display type of the media.</value>
+ public string DisplayMediaType { get; set; }
+
[IgnoreDataMember]
public override bool SupportsPositionTicksResume
{
@@ -77,15 +84,6 @@ namespace MediaBrowser.Controller.Entities
}
}
- [IgnoreDataMember]
- protected override bool SupportsIsInMixedFolderDetection
- {
- get
- {
- return true;
- }
- }
-
public override string CreatePresentationUniqueKey()
{
if (!string.IsNullOrWhiteSpace(PrimaryVersionId))
@@ -121,7 +119,7 @@ namespace MediaBrowser.Controller.Entities
/// Gets or sets the subtitle paths.
/// </summary>
/// <value>The subtitle paths.</value>
- public List<string> SubtitleFiles { get; set; }
+ public string[] SubtitleFiles { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this instance has subtitles.
@@ -158,11 +156,6 @@ namespace MediaBrowser.Controller.Entities
public Video3DFormat? Video3DFormat { get; set; }
/// <summary>
- /// If the video is a folder-rip, this will hold the file list for the largest playlist
- /// </summary>
- public List<string> PlayableStreamFileNames { get; set; }
-
- /// <summary>
/// Gets the playable stream files.
/// </summary>
/// <returns>List{System.String}.</returns>
@@ -171,6 +164,11 @@ namespace MediaBrowser.Controller.Entities
return GetPlayableStreamFiles(Path);
}
+ public List<string> GetPlayableStreamFileNames()
+ {
+ return GetPlayableStreamFiles().Select(System.IO.Path.GetFileName).ToList(); ;
+ }
+
/// <summary>
/// Gets or sets the aspect ratio.
/// </summary>
@@ -179,17 +177,15 @@ namespace MediaBrowser.Controller.Entities
public Video()
{
- PlayableStreamFileNames = new List<string>();
- AdditionalParts = new List<string>();
- LocalAlternateVersions = new List<string>();
- SubtitleFiles = new List<string>();
- LinkedAlternateVersions = new List<LinkedChild>();
+ AdditionalParts = EmptyStringArray;
+ LocalAlternateVersions = EmptyStringArray;
+ SubtitleFiles = EmptyStringArray;
+ LinkedAlternateVersions = EmptyLinkedChildArray;
}
public override bool CanDownload()
{
- if (VideoType == VideoType.HdDvd || VideoType == VideoType.Dvd ||
- VideoType == VideoType.BluRay)
+ if (VideoType == VideoType.Dvd || VideoType == VideoType.BluRay)
{
return false;
}
@@ -218,20 +214,20 @@ namespace MediaBrowser.Controller.Entities
return item.MediaSourceCount;
}
}
- return LinkedAlternateVersions.Count + LocalAlternateVersions.Count + 1;
+ return LinkedAlternateVersions.Length + LocalAlternateVersions.Length + 1;
}
}
[IgnoreDataMember]
public bool IsStacked
{
- get { return AdditionalParts.Count > 0; }
+ get { return AdditionalParts.Length > 0; }
}
[IgnoreDataMember]
public bool HasLocalAlternateVersions
{
- get { return LocalAlternateVersions.Count > 0; }
+ get { return LocalAlternateVersions.Length > 0; }
}
public IEnumerable<Guid> GetAdditionalPartIds()
@@ -339,8 +335,7 @@ namespace MediaBrowser.Controller.Entities
if (!IsPlaceHolder)
{
- if (VideoType == VideoType.BluRay || VideoType == VideoType.Dvd ||
- VideoType == VideoType.HdDvd)
+ if (VideoType == VideoType.BluRay || VideoType == VideoType.Dvd)
{
return Path;
}
@@ -357,7 +352,7 @@ namespace MediaBrowser.Controller.Entities
{
if (LocationType == LocationType.FileSystem)
{
- if (VideoType == VideoType.BluRay || VideoType == VideoType.Dvd || VideoType == VideoType.HdDvd)
+ if (VideoType == VideoType.BluRay || VideoType == VideoType.Dvd)
{
return System.IO.Path.GetFileName(Path);
}
@@ -402,13 +397,52 @@ namespace MediaBrowser.Controller.Entities
/// <returns>List{System.String}.</returns>
public List<string> GetPlayableStreamFiles(string rootPath)
{
+ if (VideoType == VideoType.VideoFile)
+ {
+ return new List<string>();
+ }
+
var allFiles = FileSystem.GetFilePaths(rootPath, true).ToList();
- return PlayableStreamFileNames.Select(name => allFiles.FirstOrDefault(f => string.Equals(System.IO.Path.GetFileName(f), name, StringComparison.OrdinalIgnoreCase)))
+ var videoType = VideoType;
+
+ if (videoType == VideoType.Iso && IsoType == Model.Entities.IsoType.BluRay)
+ {
+ videoType = VideoType.BluRay;
+ }
+ else if (videoType == VideoType.Iso && IsoType == Model.Entities.IsoType.Dvd)
+ {
+ videoType = VideoType.Dvd;
+ }
+
+ return QueryPlayableStreamFiles(rootPath, videoType).Select(name => allFiles.FirstOrDefault(f => string.Equals(System.IO.Path.GetFileName(f), name, StringComparison.OrdinalIgnoreCase)))
.Where(f => !string.IsNullOrEmpty(f))
.ToList();
}
+ public static List<string> QueryPlayableStreamFiles(string rootPath, VideoType videoType)
+ {
+ if (videoType == VideoType.Dvd)
+ {
+ return FileSystem.GetFiles(rootPath, new[] { ".vob" }, false, true)
+ .OrderByDescending(i => i.Length)
+ .ThenBy(i => i.FullName)
+ .Take(1)
+ .Select(i => i.FullName)
+ .ToList();
+ }
+ if (videoType == VideoType.BluRay)
+ {
+ return FileSystem.GetFiles(rootPath, new[] { ".m2ts" }, false, true)
+ .OrderByDescending(i => i.Length)
+ .ThenBy(i => i.FullName)
+ .Take(1)
+ .Select(i => i.FullName)
+ .ToList();
+ }
+ return new List<string>();
+ }
+
/// <summary>
/// Gets a value indicating whether [is3 D].
/// </summary>
@@ -500,7 +534,7 @@ namespace MediaBrowser.Controller.Entities
public override IEnumerable<FileSystemMetadata> GetDeletePaths()
{
- if (!DetectIsInMixedFolder())
+ if (!IsInMixedFolder)
{
return new[] {
new FileSystemMetadata
@@ -514,17 +548,12 @@ namespace MediaBrowser.Controller.Entities
return base.GetDeletePaths();
}
- public IEnumerable<MediaStream> GetMediaStreams()
+ public List<MediaStream> GetMediaStreams()
{
- var mediaSource = GetMediaSources(false)
- .FirstOrDefault();
-
- if (mediaSource == null)
+ return MediaSourceManager.GetMediaStreams(new MediaStreamQuery
{
- return new List<MediaStream>();
- }
-
- return mediaSource.MediaStreams;
+ ItemId = Id
+ });
}
public virtual MediaStream GetDefaultVideoStream()
@@ -572,7 +601,7 @@ namespace MediaBrowser.Controller.Entities
return list;
}
- public virtual IEnumerable<MediaSourceInfo> GetMediaSources(bool enablePathSubstitution)
+ public virtual List<MediaSourceInfo> GetMediaSources(bool enablePathSubstitution)
{
if (SourceType == SourceType.Channel)
{
@@ -619,8 +648,7 @@ namespace MediaBrowser.Controller.Entities
throw new ArgumentNullException("media");
}
- var mediaStreams = MediaSourceManager.GetMediaStreams(media.Id)
- .ToList();
+ var mediaStreams = MediaSourceManager.GetMediaStreams(media.Id);
var locationType = media.LocationType;
@@ -639,7 +667,6 @@ namespace MediaBrowser.Controller.Entities
Size = media.Size,
Timestamp = media.Timestamp,
Type = type,
- PlayableStreamFileNames = media.PlayableStreamFileNames.ToList(),
SupportsDirectStream = media.VideoType == VideoType.VideoFile,
IsRemote = media.IsShortcut
};
@@ -714,10 +741,6 @@ namespace MediaBrowser.Controller.Entities
{
terms.Add("DVD");
}
- else if (video.VideoType == VideoType.HdDvd)
- {
- terms.Add("HD-DVD");
- }
else if (video.VideoType == VideoType.Iso)
{
if (video.IsoType.HasValue)
@@ -781,7 +804,7 @@ namespace MediaBrowser.Controller.Entities
}
}
- return string.Join("/", terms.ToArray());
+ return string.Join("/", terms.ToArray(terms.Count));
}
}