diff options
| author | Eric Reed <ebr@mediabrowser3.com> | 2013-12-04 15:07:56 -0500 |
|---|---|---|
| committer | Eric Reed <ebr@mediabrowser3.com> | 2013-12-04 15:07:56 -0500 |
| commit | 6819be81601f6a95a60ce2735474ae0015d19bff (patch) | |
| tree | 7e2743455e53d4a028fae789f2fc74a7c5ae87b9 /MediaBrowser.Controller | |
| parent | 190be6311fbdf3a73f9c8e330f44edafe7764284 (diff) | |
| parent | cb882a4b48e9cf03cd363c54d93338ad62153e7e (diff) | |
Merge branch 'master' of https://github.com/MediaBrowser/MediaBrowser
Diffstat (limited to 'MediaBrowser.Controller')
39 files changed, 1260 insertions, 249 deletions
diff --git a/MediaBrowser.Controller/Entities/Audio/Artist.cs b/MediaBrowser.Controller/Entities/Audio/Artist.cs deleted file mode 100644 index 947ee11227..0000000000 --- a/MediaBrowser.Controller/Entities/Audio/Artist.cs +++ /dev/null @@ -1,86 +0,0 @@ -using MediaBrowser.Controller.Library; -using MediaBrowser.Model.Dto; -using MediaBrowser.Model.Entities; -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Linq; -using System.Runtime.Serialization; - -namespace MediaBrowser.Controller.Entities.Audio -{ - /// <summary> - /// Class Artist - /// </summary> - public class Artist : BaseItem, IItemByName, IHasMusicGenres - { - public Artist() - { - UserItemCounts = new Dictionary<Guid, ItemByNameCounts>(); - } - - public string LastFmImageUrl { get; set; } - public string LastFmImageSize { get; set; } - - /// <summary> - /// Gets the user data key. - /// </summary> - /// <returns>System.String.</returns> - public override string GetUserDataKey() - { - return GetUserDataKey(this); - } - - [IgnoreDataMember] - public Dictionary<Guid, ItemByNameCounts> UserItemCounts { get; set; } - - /// <summary> - /// Finds the music artist. - /// </summary> - /// <param name="artist">The artist.</param> - /// <param name="libraryManager">The library manager.</param> - /// <returns>MusicArtist.</returns> - public static MusicArtist FindMusicArtist(Artist artist, ILibraryManager libraryManager) - { - return FindMusicArtist(artist, libraryManager.RootFolder.RecursiveChildren.OfType<MusicArtist>()); - } - - /// <summary> - /// Finds the music artist. - /// </summary> - /// <param name="artist">The artist.</param> - /// <param name="allMusicArtists">All music artists.</param> - /// <returns>MusicArtist.</returns> - public static MusicArtist FindMusicArtist(Artist artist, IEnumerable<MusicArtist> allMusicArtists) - { - var musicBrainzId = artist.GetProviderId(MetadataProviders.Musicbrainz); - - return allMusicArtists.FirstOrDefault(i => - { - if (!string.IsNullOrWhiteSpace(musicBrainzId) && string.Equals(musicBrainzId, i.GetProviderId(MetadataProviders.Musicbrainz), StringComparison.OrdinalIgnoreCase)) - { - return true; - } - - return string.Compare(i.Name, artist.Name, CultureInfo.CurrentCulture, CompareOptions.IgnoreNonSpace | CompareOptions.IgnoreCase | CompareOptions.IgnoreSymbols) == 0; - }); - } - - /// <summary> - /// Gets the user data key. - /// </summary> - /// <param name="item">The item.</param> - /// <returns>System.String.</returns> - public static string GetUserDataKey(BaseItem item) - { - var id = item.GetProviderId(MetadataProviders.Musicbrainz); - - if (!string.IsNullOrEmpty(id)) - { - return "Artist-Musicbrainz-" + id; - } - - return "Artist-" + item.Name; - } - } -} diff --git a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs index d791c92ae9..d5572b9a5e 100644 --- a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs +++ b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs @@ -1,11 +1,65 @@ - +using MediaBrowser.Model.Dto; +using MediaBrowser.Model.Entities; +using System; +using System.Collections.Generic; +using System.Runtime.Serialization; +using System.Threading; +using System.Threading.Tasks; + namespace MediaBrowser.Controller.Entities.Audio { /// <summary> /// Class MusicArtist /// </summary> - public class MusicArtist : Folder + public class MusicArtist : Folder, IItemByName, IHasMusicGenres, IHasDualAccess { + [IgnoreDataMember] + public List<ItemByNameCounts> UserItemCountList { get; set; } + + public bool IsAccessedByName { get; set; } + + public override bool IsFolder + { + get + { + return !IsAccessedByName; + } + } + + protected override IEnumerable<BaseItem> ActualChildren + { + get + { + if (IsAccessedByName) + { + return new List<BaseItem>(); + } + + return base.ActualChildren; + } + } + + protected override Task ValidateChildrenInternal(IProgress<double> progress, CancellationToken cancellationToken, bool? recursive = null, bool forceRefreshMetadata = false) + { + if (IsAccessedByName) + { + // Should never get in here anyway + return Task.FromResult(true); + } + + return base.ValidateChildrenInternal(progress, cancellationToken, recursive, forceRefreshMetadata); + } + + public override string GetClientTypeName() + { + if (IsAccessedByName) + { + //return "Artist"; + } + + return base.GetClientTypeName(); + } + /// <summary> /// Gets or sets the last fm image URL. /// </summary> @@ -13,13 +67,35 @@ namespace MediaBrowser.Controller.Entities.Audio public string LastFmImageUrl { get; set; } public string LastFmImageSize { get; set; } + public MusicArtist() + { + UserItemCountList = new List<ItemByNameCounts>(); + } + /// <summary> /// Gets the user data key. /// </summary> /// <returns>System.String.</returns> public override string GetUserDataKey() { - return Artist.GetUserDataKey(this); + return GetUserDataKey(this); + } + + /// <summary> + /// Gets the user data key. + /// </summary> + /// <param name="item">The item.</param> + /// <returns>System.String.</returns> + public static string GetUserDataKey(BaseItem item) + { + var id = item.GetProviderId(MetadataProviders.Musicbrainz); + + if (!string.IsNullOrEmpty(id)) + { + return "Artist-Musicbrainz-" + id; + } + + return "Artist-" + item.Name; } } } diff --git a/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs b/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs index ec2995fb2f..b54e14f2da 100644 --- a/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs +++ b/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs @@ -12,7 +12,7 @@ namespace MediaBrowser.Controller.Entities.Audio { public MusicGenre() { - UserItemCounts = new Dictionary<Guid, ItemByNameCounts>(); + UserItemCountList = new List<ItemByNameCounts>(); } /// <summary> @@ -25,6 +25,6 @@ namespace MediaBrowser.Controller.Entities.Audio } [IgnoreDataMember] - public Dictionary<Guid, ItemByNameCounts> UserItemCounts { get; set; } + public List<ItemByNameCounts> UserItemCountList { get; set; } } } diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index a6178536c6..4f7889f975 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -1,7 +1,6 @@ using MediaBrowser.Common.Extensions; using MediaBrowser.Common.IO; using MediaBrowser.Controller.Configuration; -using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.IO; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Localization; @@ -38,10 +37,8 @@ namespace MediaBrowser.Controller.Entities Tags = new List<string>(); ThemeSongIds = new List<Guid>(); ThemeVideoIds = new List<Guid>(); - LocalTrailerIds = new List<Guid>(); LockedFields = new List<MetadataFields>(); Taglines = new List<string>(); - RemoteTrailers = new List<MediaUrl>(); ImageSources = new List<ImageSourceInfo>(); } @@ -88,30 +85,12 @@ namespace MediaBrowser.Controller.Entities public Guid Id { get; set; } /// <summary> - /// Gets or sets the budget. - /// </summary> - /// <value>The budget.</value> - public double? Budget { get; set; } - - /// <summary> /// Gets or sets the taglines. /// </summary> /// <value>The taglines.</value> public List<string> Taglines { get; set; } /// <summary> - /// Gets or sets the revenue. - /// </summary> - /// <value>The revenue.</value> - public double? Revenue { get; set; } - - /// <summary> - /// Gets or sets the trailer URL. - /// </summary> - /// <value>The trailer URL.</value> - public List<MediaUrl> RemoteTrailers { get; set; } - - /// <summary> /// Return the id that should be used to key display prefs for this item. /// Default is based on the type for everything except actual generic folders. /// </summary> @@ -139,6 +118,7 @@ namespace MediaBrowser.Controller.Entities /// Gets or sets the type of the location. /// </summary> /// <value>The type of the location.</value> + [IgnoreDataMember] public virtual LocationType LocationType { get @@ -483,6 +463,22 @@ namespace MediaBrowser.Controller.Entities [IgnoreDataMember] public Folder Parent { get; set; } + [IgnoreDataMember] + public IEnumerable<Folder> Parents + { + get + { + var parent = Parent; + + while (parent != null) + { + yield return parent; + + parent = parent.Parent; + } + } + } + /// <summary> /// When the item first debuted. For movies this could be premiere date, episodes would be first aired /// </summary> @@ -630,11 +626,6 @@ namespace MediaBrowser.Controller.Entities /// <value>The original run time ticks.</value> public long? OriginalRunTimeTicks { get; set; } /// <summary> - /// Gets or sets the aspect ratio. - /// </summary> - /// <value>The aspect ratio.</value> - public string AspectRatio { get; set; } - /// <summary> /// Gets or sets the production year. /// </summary> /// <value>The production year.</value> @@ -655,7 +646,6 @@ namespace MediaBrowser.Controller.Entities public List<Guid> ThemeSongIds { get; set; } public List<Guid> ThemeVideoIds { get; set; } - public List<Guid> LocalTrailerIds { get; set; } [IgnoreDataMember] public virtual string OfficialRatingForComparison @@ -898,7 +888,11 @@ namespace MediaBrowser.Controller.Entities themeVideosChanged = await RefreshThemeVideos(cancellationToken, forceSave, forceRefresh, allowSlowProviders).ConfigureAwait(false); - localTrailersChanged = await RefreshLocalTrailers(cancellationToken, forceSave, forceRefresh, allowSlowProviders).ConfigureAwait(false); + var hasTrailers = this as IHasTrailers; + if (hasTrailers != null) + { + localTrailersChanged = await RefreshLocalTrailers(hasTrailers, cancellationToken, forceSave, forceRefresh, allowSlowProviders).ConfigureAwait(false); + } } cancellationToken.ThrowIfCancellationRequested(); @@ -918,18 +912,18 @@ namespace MediaBrowser.Controller.Entities return changed; } - private async Task<bool> RefreshLocalTrailers(CancellationToken cancellationToken, bool forceSave = false, bool forceRefresh = false, bool allowSlowProviders = true) + private async Task<bool> RefreshLocalTrailers(IHasTrailers item, CancellationToken cancellationToken, bool forceSave = false, bool forceRefresh = false, bool allowSlowProviders = true) { var newItems = LoadLocalTrailers().ToList(); var newItemIds = newItems.Select(i => i.Id).ToList(); - var itemsChanged = !LocalTrailerIds.SequenceEqual(newItemIds); + var itemsChanged = !item.LocalTrailerIds.SequenceEqual(newItemIds); var tasks = newItems.Select(i => i.RefreshMetadata(cancellationToken, forceSave, forceRefresh, allowSlowProviders, resetResolveArgs: false)); var results = await Task.WhenAll(tasks).ConfigureAwait(false); - LocalTrailerIds = newItemIds; + item.LocalTrailerIds = newItemIds; return itemsChanged || results.Contains(true); } @@ -1134,6 +1128,11 @@ namespace MediaBrowser.Controller.Entities return changed; } + public virtual string GetClientTypeName() + { + return GetType().Name; + } + /// <summary> /// Determines if the item is considered new based on user settings /// </summary> @@ -1187,6 +1186,7 @@ namespace MediaBrowser.Controller.Entities if (existing != null) { existing.Type = PersonType.GuestStar; + existing.SortOrder = person.SortOrder ?? existing.SortOrder; return; } } @@ -1203,23 +1203,35 @@ namespace MediaBrowser.Controller.Entities else { // Was there, if no role and we have one - fill it in - if (string.IsNullOrWhiteSpace(existing.Role) && !string.IsNullOrWhiteSpace(person.Role)) existing.Role = person.Role; + if (string.IsNullOrWhiteSpace(existing.Role) && !string.IsNullOrWhiteSpace(person.Role)) + { + existing.Role = person.Role; + } + + existing.SortOrder = person.SortOrder ?? existing.SortOrder; } } else { + var existing = People.FirstOrDefault(p => + string.Equals(p.Name, person.Name, StringComparison.OrdinalIgnoreCase) && + string.Equals(p.Type, person.Type, StringComparison.OrdinalIgnoreCase)); + // Check for dupes based on the combination of Name and Type - if (!People.Any(p => string.Equals(p.Name, person.Name, StringComparison.OrdinalIgnoreCase) && string.Equals(p.Type, person.Type, StringComparison.OrdinalIgnoreCase))) + if (existing == null) { People.Add(person); } + else + { + existing.SortOrder = person.SortOrder ?? existing.SortOrder; + } } } /// <summary> /// Adds the tagline. /// </summary> - /// <param name="item">The item.</param> /// <param name="tagline">The tagline.</param> /// <exception cref="System.ArgumentNullException">tagline</exception> public void AddTagline(string tagline) @@ -1737,5 +1749,14 @@ namespace MediaBrowser.Controller.Entities // See if we can avoid a file system lookup by looking for the file in ResolveArgs return metaFileEntry == null ? FileSystem.GetLastWriteTimeUtc(imagePath) : FileSystem.GetLastWriteTimeUtc(metaFileEntry); } + + /// <summary> + /// Gets the file system path to delete when the item is to be deleted + /// </summary> + /// <returns></returns> + public virtual IEnumerable<string> GetDeletePaths() + { + return new[] { Path }; + } } } diff --git a/MediaBrowser.Controller/Entities/Extensions.cs b/MediaBrowser.Controller/Entities/Extensions.cs index d189f4e71b..2a64bd3a41 100644 --- a/MediaBrowser.Controller/Entities/Extensions.cs +++ b/MediaBrowser.Controller/Entities/Extensions.cs @@ -16,7 +16,7 @@ namespace MediaBrowser.Controller.Entities /// <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 BaseItem item, string url, bool isDirectLink) + public static void AddTrailerUrl(this IHasTrailers item, string url, bool isDirectLink) { if (string.IsNullOrWhiteSpace(url)) { diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index 8dbc981938..e8b5831813 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -90,7 +90,7 @@ namespace MediaBrowser.Controller.Entities item.Id = item.Path.GetMBId(item.GetType()); } - if (_children.Any(i => i.Id == item.Id)) + if (ActualChildren.Any(i => i.Id == item.Id)) { throw new ArgumentException(string.Format("A child with the Id {0} already exists.", item.Id)); } @@ -108,14 +108,14 @@ namespace MediaBrowser.Controller.Entities await LibraryManager.CreateItem(item, cancellationToken).ConfigureAwait(false); - await ItemRepository.SaveChildren(Id, _children.Select(i => i.Id).ToList(), cancellationToken).ConfigureAwait(false); + await ItemRepository.SaveChildren(Id, ActualChildren.Select(i => i.Id).ToList(), cancellationToken).ConfigureAwait(false); } protected void AddChildrenInternal(IEnumerable<BaseItem> children) { lock (_childrenSyncLock) { - var newChildren = _children.ToList(); + var newChildren = ActualChildren.ToList(); newChildren.AddRange(children); _children = newChildren; } @@ -124,7 +124,7 @@ namespace MediaBrowser.Controller.Entities { lock (_childrenSyncLock) { - var newChildren = _children.ToList(); + var newChildren = ActualChildren.ToList(); newChildren.Add(child); _children = newChildren; } @@ -134,7 +134,7 @@ namespace MediaBrowser.Controller.Entities { lock (_childrenSyncLock) { - _children = _children.Except(children).ToList(); + _children = ActualChildren.Except(children).ToList(); } } @@ -519,7 +519,7 @@ namespace MediaBrowser.Controller.Entities /// <summary> /// The children /// </summary> - private IReadOnlyList<BaseItem> _children = new List<BaseItem>(); + private IReadOnlyList<BaseItem> _children; /// <summary> /// The _children sync lock /// </summary> @@ -532,15 +532,10 @@ namespace MediaBrowser.Controller.Entities { get { - return _children; + return _children ?? (_children = LoadChildrenInternal()); } } - public void LoadSavedChildren() - { - _children = LoadChildrenInternal(); - } - /// <summary> /// thread-safe access to the actual children of this folder - without regard to user /// </summary> @@ -758,7 +753,7 @@ namespace MediaBrowser.Controller.Entities AddChildrenInternal(newItems); - await ItemRepository.SaveChildren(Id, _children.Select(i => i.Id).ToList(), cancellationToken).ConfigureAwait(false); + await ItemRepository.SaveChildren(Id, ActualChildren.Select(i => i.Id).ToList(), cancellationToken).ConfigureAwait(false); //force the indexes to rebuild next time if (IndexCache != null) @@ -1007,8 +1002,7 @@ namespace MediaBrowser.Controller.Entities return result; } - var initialCount = _children.Count; - var list = new List<BaseItem>(initialCount); + var list = new List<BaseItem>(); AddChildrenToList(user, includeLinkedChildren, list, false, null); @@ -1038,16 +1032,13 @@ namespace MediaBrowser.Controller.Entities } } - if (recursive) + if (recursive && child.IsFolder) { - var folder = child as Folder; + var folder = (Folder)child; - if (folder != null) + if (folder.AddChildrenToList(user, includeLinkedChildren, list, true, filter)) { - if (folder.AddChildrenToList(user, includeLinkedChildren, list, true, filter)) - { - hasLinkedChildren = true; - } + hasLinkedChildren = true; } } } @@ -1073,7 +1064,6 @@ namespace MediaBrowser.Controller.Entities return hasLinkedChildren; } - private int _lastRecursiveCount; /// <summary> /// Gets allowed recursive children of an item /// </summary> @@ -1101,13 +1091,10 @@ namespace MediaBrowser.Controller.Entities throw new ArgumentNullException("user"); } - var initialCount = _lastRecursiveCount == 0 ? _children.Count : _lastRecursiveCount; - var list = new List<BaseItem>(initialCount); + var list = new List<BaseItem>(); var hasLinkedChildren = AddChildrenToList(user, includeLinkedChildren, list, true, filter); - _lastRecursiveCount = list.Count; - return hasLinkedChildren ? list.DistinctBy(i => i.Id).ToList() : list; } @@ -1127,8 +1114,7 @@ namespace MediaBrowser.Controller.Entities /// <returns>IEnumerable{BaseItem}.</returns> public IList<BaseItem> GetRecursiveChildren(Func<BaseItem, bool> filter) { - var initialCount = _lastRecursiveCount == 0 ? _children.Count : _lastRecursiveCount; - var list = new List<BaseItem>(initialCount); + var list = new List<BaseItem>(); AddChildrenToList(list, true, filter); @@ -1150,14 +1136,11 @@ namespace MediaBrowser.Controller.Entities list.Add(child); } - if (recursive) + if (recursive && child.IsFolder) { - var folder = child as Folder; + var folder = (Folder)child; - if (folder != null) - { - folder.AddChildrenToList(list, true, filter); - } + folder.AddChildrenToList(list, true, filter); } } } diff --git a/MediaBrowser.Controller/Entities/Game.cs b/MediaBrowser.Controller/Entities/Game.cs index e8374c2743..e15b7e4c9d 100644 --- a/MediaBrowser.Controller/Entities/Game.cs +++ b/MediaBrowser.Controller/Entities/Game.cs @@ -4,16 +4,26 @@ using System.Collections.Generic; namespace MediaBrowser.Controller.Entities { - public class Game : BaseItem, IHasSoundtracks + public class Game : BaseItem, IHasSoundtracks, IHasTrailers { public List<Guid> SoundtrackIds { get; set; } - + public Game() { MultiPartGameFiles = new List<string>(); SoundtrackIds = new List<Guid>(); + RemoteTrailers = new List<MediaUrl>(); + LocalTrailerIds = new List<Guid>(); } + public List<Guid> LocalTrailerIds { get; set; } + + /// <summary> + /// Gets or sets the remote trailers. + /// </summary> + /// <value>The remote trailers.</value> + public List<MediaUrl> RemoteTrailers { get; set; } + /// <summary> /// Gets the type of the media. /// </summary> @@ -84,5 +94,15 @@ namespace MediaBrowser.Controller.Entities } return base.GetUserDataKey(); } + + public override IEnumerable<string> GetDeletePaths() + { + if (!IsInMixedFolder) + { + return new[] { System.IO.Path.GetDirectoryName(Path) }; + } + + return base.GetDeletePaths(); + } } } diff --git a/MediaBrowser.Controller/Entities/GameGenre.cs b/MediaBrowser.Controller/Entities/GameGenre.cs index 0c877782e6..ffe62ba03f 100644 --- a/MediaBrowser.Controller/Entities/GameGenre.cs +++ b/MediaBrowser.Controller/Entities/GameGenre.cs @@ -9,7 +9,7 @@ namespace MediaBrowser.Controller.Entities { public GameGenre() { - UserItemCounts = new Dictionary<Guid, ItemByNameCounts>(); + UserItemCountList = new List<ItemByNameCounts>(); } /// <summary> @@ -22,6 +22,6 @@ namespace MediaBrowser.Controller.Entities } [IgnoreDataMember] - public Dictionary<Guid, ItemByNameCounts> UserItemCounts { get; set; } + public List<ItemByNameCounts> UserItemCountList { get; set; } } } diff --git a/MediaBrowser.Controller/Entities/Genre.cs b/MediaBrowser.Controller/Entities/Genre.cs index 71fa057206..0fa49639bf 100644 --- a/MediaBrowser.Controller/Entities/Genre.cs +++ b/MediaBrowser.Controller/Entities/Genre.cs @@ -1,7 +1,7 @@ -using System.Runtime.Serialization; -using MediaBrowser.Model.Dto; +using MediaBrowser.Model.Dto; using System; using System.Collections.Generic; +using System.Runtime.Serialization; namespace MediaBrowser.Controller.Entities { @@ -12,7 +12,7 @@ namespace MediaBrowser.Controller.Entities { public Genre() { - UserItemCounts = new Dictionary<Guid, ItemByNameCounts>(); + UserItemCountList = new List<ItemByNameCounts>(); } /// <summary> @@ -25,6 +25,6 @@ namespace MediaBrowser.Controller.Entities } [IgnoreDataMember] - public Dictionary<Guid, ItemByNameCounts> UserItemCounts { get; set; } + public List<ItemByNameCounts> UserItemCountList { get; set; } } } diff --git a/MediaBrowser.Controller/Entities/IHasAspectRatio.cs b/MediaBrowser.Controller/Entities/IHasAspectRatio.cs new file mode 100644 index 0000000000..5aecf4eac1 --- /dev/null +++ b/MediaBrowser.Controller/Entities/IHasAspectRatio.cs @@ -0,0 +1,14 @@ +namespace MediaBrowser.Controller.Entities +{ + /// <summary> + /// Interface IHasAspectRatio + /// </summary> + public interface IHasAspectRatio + { + /// <summary> + /// Gets or sets the aspect ratio. + /// </summary> + /// <value>The aspect ratio.</value> + string AspectRatio { get; set; } + } +} diff --git a/MediaBrowser.Controller/Entities/IHasBudget.cs b/MediaBrowser.Controller/Entities/IHasBudget.cs new file mode 100644 index 0000000000..f697715c16 --- /dev/null +++ b/MediaBrowser.Controller/Entities/IHasBudget.cs @@ -0,0 +1,18 @@ + +namespace MediaBrowser.Controller.Entities +{ + public interface IHasBudget + { + /// <summary> + /// Gets or sets the budget. + /// </summary> + /// <value>The budget.</value> + double? Budget { get; set; } + + /// <summary> + /// Gets or sets the revenue. + /// </summary> + /// <value>The revenue.</value> + double? Revenue { get; set; } + } +} diff --git a/MediaBrowser.Controller/Entities/IHasTrailers.cs b/MediaBrowser.Controller/Entities/IHasTrailers.cs new file mode 100644 index 0000000000..47779064b4 --- /dev/null +++ b/MediaBrowser.Controller/Entities/IHasTrailers.cs @@ -0,0 +1,21 @@ +using MediaBrowser.Model.Entities; +using System; +using System.Collections.Generic; + +namespace MediaBrowser.Controller.Entities +{ + public interface IHasTrailers + { + /// <summary> + /// Gets or sets the remote trailers. + /// </summary> + /// <value>The remote trailers.</value> + List<MediaUrl> RemoteTrailers { get; set; } + + /// <summary> + /// Gets or sets the local trailer ids. + /// </summary> + /// <value>The local trailer ids.</value> + List<Guid> LocalTrailerIds { get; set; } + } +} diff --git a/MediaBrowser.Controller/Entities/IItemByName.cs b/MediaBrowser.Controller/Entities/IItemByName.cs index 7284bf101d..1e83c7466e 100644 --- a/MediaBrowser.Controller/Entities/IItemByName.cs +++ b/MediaBrowser.Controller/Entities/IItemByName.cs @@ -1,6 +1,7 @@ using MediaBrowser.Model.Dto; using System; using System.Collections.Generic; +using System.Linq; namespace MediaBrowser.Controller.Entities { @@ -9,26 +10,37 @@ namespace MediaBrowser.Controller.Entities /// </summary> public interface IItemByName { - Dictionary<Guid, ItemByNameCounts> UserItemCounts { get; set; } + List<ItemByNameCounts> UserItemCountList { get; set; } } - public static class IItemByNameExtensions + public interface IHasDualAccess : IItemByName { - public static ItemByNameCounts GetItemByNameCounts(this IItemByName item, User user) + bool IsAccessedByName { get; } + } + + public static class ItemByNameExtensions + { + public static ItemByNameCounts GetItemByNameCounts(this IItemByName item, Guid userId) { - if (user == null) + if (userId == Guid.Empty) { - throw new ArgumentNullException("user"); + throw new ArgumentNullException("userId"); } - ItemByNameCounts counts; + return item.UserItemCountList.FirstOrDefault(i => i.UserId == userId); + } + + public static void SetItemByNameCounts(this IItemByName item, Guid userId, ItemByNameCounts counts) + { + var current = item.UserItemCountList.FirstOrDefault(i => i.UserId == userId); - if (item.UserItemCounts.TryGetValue(user.Id, out counts)) + if (current != null) { - return counts; + item.UserItemCountList.Remove(current); } - return null; + counts.UserId = userId; + item.UserItemCountList.Add(counts); } } } diff --git a/MediaBrowser.Controller/Entities/IndexFolder.cs b/MediaBrowser.Controller/Entities/IndexFolder.cs index 35c11ef5ca..57e4a35d3f 100644 --- a/MediaBrowser.Controller/Entities/IndexFolder.cs +++ b/MediaBrowser.Controller/Entities/IndexFolder.cs @@ -40,7 +40,6 @@ namespace MediaBrowser.Controller.Entities IndexName = indexName; Parent = parent; - LoadSavedChildren(); } /// <summary> diff --git a/MediaBrowser.Controller/Entities/Movies/BoxSet.cs b/MediaBrowser.Controller/Entities/Movies/BoxSet.cs index e52ece502b..4a6221ee98 100644 --- a/MediaBrowser.Controller/Entities/Movies/BoxSet.cs +++ b/MediaBrowser.Controller/Entities/Movies/BoxSet.cs @@ -1,10 +1,26 @@ - +using System; +using MediaBrowser.Model.Entities; +using System.Collections.Generic; + namespace MediaBrowser.Controller.Entities.Movies { /// <summary> /// Class BoxSet /// </summary> - public class BoxSet : Folder + public class BoxSet : Folder, IHasTrailers { + public BoxSet() + { + RemoteTrailers = new List<MediaUrl>(); + LocalTrailerIds = new List<Guid>(); + } + + public List<Guid> LocalTrailerIds { get; set; } + + /// <summary> + /// Gets or sets the remote trailers. + /// </summary> + /// <value>The remote trailers.</value> + public List<MediaUrl> RemoteTrailers { get; set; } } } diff --git a/MediaBrowser.Controller/Entities/Movies/Movie.cs b/MediaBrowser.Controller/Entities/Movies/Movie.cs index eef348f61c..473ea4996d 100644 --- a/MediaBrowser.Controller/Entities/Movies/Movie.cs +++ b/MediaBrowser.Controller/Entities/Movies/Movie.cs @@ -11,7 +11,7 @@ namespace MediaBrowser.Controller.Entities.Movies /// <summary> /// Class Movie /// </summary> - public class Movie : Video, IHasCriticRating, IHasSoundtracks + public class Movie : Video, IHasCriticRating, IHasSoundtracks, IHasBudget, IHasTrailers { public List<Guid> SpecialFeatureIds { get; set; } @@ -21,8 +21,26 @@ namespace MediaBrowser.Controller.Entities.Movies { SpecialFeatureIds = new List<Guid>(); SoundtrackIds = new List<Guid>(); + RemoteTrailers = new List<MediaUrl>(); + LocalTrailerIds = new List<Guid>(); } + public List<Guid> LocalTrailerIds { get; set; } + + public List<MediaUrl> RemoteTrailers { get; set; } + + /// <summary> + /// Gets or sets the budget. + /// </summary> + /// <value>The budget.</value> + public double? Budget { get; set; } + + /// <summary> + /// Gets or sets the revenue. + /// </summary> + /// <value>The revenue.</value> + public double? Revenue { get; set; } + /// <summary> /// Gets or sets the critic rating. /// </summary> diff --git a/MediaBrowser.Controller/Entities/MusicVideo.cs b/MediaBrowser.Controller/Entities/MusicVideo.cs index 207f76efda..68ad4630a5 100644 --- a/MediaBrowser.Controller/Entities/MusicVideo.cs +++ b/MediaBrowser.Controller/Entities/MusicVideo.cs @@ -4,7 +4,7 @@ using System; namespace MediaBrowser.Controller.Entities { - public class MusicVideo : Video, IHasArtist, IHasMusicGenres + public class MusicVideo : Video, IHasArtist, IHasMusicGenres, IHasBudget { /// <summary> /// Gets or sets the artist. @@ -19,6 +19,18 @@ namespace MediaBrowser.Controller.Entities public string Album { get; set; } /// <summary> + /// Gets or sets the budget. + /// </summary> + /// <value>The budget.</value> + public double? Budget { get; set; } + + /// <summary> + /// Gets or sets the revenue. + /// </summary> + /// <value>The revenue.</value> + public double? Revenue { get; set; } + + /// <summary> /// Determines whether the specified name has artist. /// </summary> /// <param name="name">The name.</param> diff --git a/MediaBrowser.Controller/Entities/Person.cs b/MediaBrowser.Controller/Entities/Person.cs index e5cf48ad08..243861da76 100644 --- a/MediaBrowser.Controller/Entities/Person.cs +++ b/MediaBrowser.Controller/Entities/Person.cs @@ -1,7 +1,7 @@ -using System.Runtime.Serialization; -using MediaBrowser.Model.Dto; +using MediaBrowser.Model.Dto; using System; using System.Collections.Generic; +using System.Runtime.Serialization; namespace MediaBrowser.Controller.Entities { @@ -12,11 +12,11 @@ namespace MediaBrowser.Controller.Entities { public Person() { - UserItemCounts = new Dictionary<Guid, ItemByNameCounts>(); + UserItemCountList = new List<ItemByNameCounts>(); } [IgnoreDataMember] - public Dictionary<Guid, ItemByNameCounts> UserItemCounts { get; set; } + public List<ItemByNameCounts> UserItemCountList { get; set; } /// <summary> /// Gets the user data key. @@ -50,6 +50,12 @@ namespace MediaBrowser.Controller.Entities public string Type { get; set; } /// <summary> + /// Gets or sets the sort order - ascending + /// </summary> + /// <value>The sort order.</value> + public int? SortOrder { get; set; } + + /// <summary> /// Returns a <see cref="System.String" /> that represents this instance. /// </summary> /// <returns>A <see cref="System.String" /> that represents this instance.</returns> diff --git a/MediaBrowser.Controller/Entities/Studio.cs b/MediaBrowser.Controller/Entities/Studio.cs index bbe96a88b9..7bc17549f3 100644 --- a/MediaBrowser.Controller/Entities/Studio.cs +++ b/MediaBrowser.Controller/Entities/Studio.cs @@ -12,7 +12,7 @@ namespace MediaBrowser.Controller.Entities { public Studio() { - UserItemCounts = new Dictionary<Guid, ItemByNameCounts>(); + UserItemCountList = new List<ItemByNameCounts>(); } /// <summary> @@ -25,6 +25,6 @@ namespace MediaBrowser.Controller.Entities } [IgnoreDataMember] - public Dictionary<Guid, ItemByNameCounts> UserItemCounts { get; set; } + public List<ItemByNameCounts> UserItemCountList { get; set; } } } diff --git a/MediaBrowser.Controller/Entities/TV/Episode.cs b/MediaBrowser.Controller/Entities/TV/Episode.cs index c68ba0ad1f..e9f250d2a4 100644 --- a/MediaBrowser.Controller/Entities/TV/Episode.cs +++ b/MediaBrowser.Controller/Entities/TV/Episode.cs @@ -50,6 +50,33 @@ namespace MediaBrowser.Controller.Entities.TV get { return true; } } + [IgnoreDataMember] + public int? AiredSeasonNumber + { + get + { + return AirsAfterSeasonNumber ?? AirsBeforeSeasonNumber ?? PhysicalSeasonNumber; + } + } + + [IgnoreDataMember] + public int? PhysicalSeasonNumber + { + get + { + var value = ParentIndexNumber; + + if (value.HasValue) + { + return value; + } + + var season = Parent as Season; + + return season != null ? season.IndexNumber : null; + } + } + /// <summary> /// We roll up into series /// </summary> @@ -59,7 +86,7 @@ namespace MediaBrowser.Controller.Entities.TV { get { - return Season; + return FindParent<Season>(); } } @@ -152,20 +179,6 @@ namespace MediaBrowser.Controller.Entities.TV } /// <summary> - /// The _season - /// </summary> - private Season _season; - /// <summary> - /// This Episode's Season Instance - /// </summary> - /// <value>The season.</value> - [IgnoreDataMember] - public Season Season - { - get { return _season ?? (_season = FindParent<Season>()); } - } - - /// <summary> /// This is the ending episode number for double episodes. /// </summary> /// <value>The index number.</value> @@ -221,5 +234,46 @@ namespace MediaBrowser.Controller.Entities.TV { get { return LocationType == Model.Entities.LocationType.Virtual && IsUnaired; } } + + [IgnoreDataMember] + public Guid? SeasonId + { + get + { + // First see if the parent is a Season + var season = Parent as Season; + + if (season != null) + { + return season.Id; + } + + var seasonNumber = ParentIndexNumber; + + // Parent is a Series + if (seasonNumber.HasValue) + { + var series = Parent as Series; + + if (series != null) + { + season = series.Children.OfType<Season>() + .FirstOrDefault(i => i.IndexNumber.HasValue && i.IndexNumber.Value == seasonNumber.Value); + + if (season != null) + { + return season.Id; + } + } + } + + return null; + } + } + + public override IEnumerable<string> GetDeletePaths() + { + return new[] { Path }; + } } } diff --git a/MediaBrowser.Controller/Entities/TV/Season.cs b/MediaBrowser.Controller/Entities/TV/Season.cs index 97a09b7b55..78e0b8bc4a 100644 --- a/MediaBrowser.Controller/Entities/TV/Season.cs +++ b/MediaBrowser.Controller/Entities/TV/Season.cs @@ -1,9 +1,9 @@ -using System.Linq; -using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Localization; using System; using System.Collections.Generic; using System.IO; +using System.Linq; using System.Runtime.Serialization; namespace MediaBrowser.Controller.Entities.TV @@ -94,6 +94,22 @@ namespace MediaBrowser.Controller.Entities.TV get { return _series ?? (_series = FindParent<Series>()); } } + [IgnoreDataMember] + public string SeriesPath + { + get + { + var series = Series; + + if (series != null) + { + return series.Path; + } + + return System.IO.Path.GetDirectoryName(Path); + } + } + /// <summary> /// Our rating comes from our series /// </summary> @@ -149,16 +165,34 @@ namespace MediaBrowser.Controller.Entities.TV return IndexNumber != null ? IndexNumber.Value.ToString("0000") : Name; } + private IEnumerable<Episode> GetEpisodes() + { + var series = Series; + + if (series != null && series.ContainsEpisodesWithoutSeasonFolders) + { + var seasonNumber = IndexNumber; + + if (seasonNumber.HasValue) + { + return series.RecursiveChildren.OfType<Episode>() + .Where(i => i.ParentIndexNumber.HasValue && i.ParentIndexNumber.Value == seasonNumber.Value); + } + } + + return Children.OfType<Episode>(); + } + [IgnoreDataMember] public bool IsMissingSeason { - get { return LocationType == Model.Entities.LocationType.Virtual && Children.OfType<Episode>().All(i => i.IsMissingEpisode); } + get { return LocationType == Model.Entities.LocationType.Virtual && GetEpisodes().All(i => i.IsMissingEpisode); } } [IgnoreDataMember] public bool IsUnaired { - get { return Children.OfType<Episode>().All(i => i.IsUnaired); } + get { return GetEpisodes().All(i => i.IsUnaired); } } [IgnoreDataMember] @@ -170,7 +204,13 @@ namespace MediaBrowser.Controller.Entities.TV [IgnoreDataMember] public bool IsMissingOrVirtualUnaired { - get { return LocationType == Model.Entities.LocationType.Virtual && Children.OfType<Episode>().All(i => i.IsVirtualUnaired || i.IsMissingEpisode); } + get { return LocationType == Model.Entities.LocationType.Virtual && GetEpisodes().All(i => i.IsVirtualUnaired || i.IsMissingEpisode); } + } + + [IgnoreDataMember] + public bool IsSpecialSeason + { + get { return (IndexNumber ?? -1) == 0; } } } } diff --git a/MediaBrowser.Controller/Entities/TV/Series.cs b/MediaBrowser.Controller/Entities/TV/Series.cs index 02ea50c6b5..b4a3fc811f 100644 --- a/MediaBrowser.Controller/Entities/TV/Series.cs +++ b/MediaBrowser.Controller/Entities/TV/Series.cs @@ -4,6 +4,7 @@ using MediaBrowser.Model.Entities; using System; using System.Collections.Generic; using System.IO; +using System.Linq; using System.Runtime.Serialization; namespace MediaBrowser.Controller.Entities.TV @@ -11,7 +12,7 @@ namespace MediaBrowser.Controller.Entities.TV /// <summary> /// Class Series /// </summary> - public class Series : Folder, IHasSoundtracks + public class Series : Folder, IHasSoundtracks, IHasTrailers { public List<Guid> SpecialFeatureIds { get; set; } public List<Guid> SoundtrackIds { get; set; } @@ -24,8 +25,14 @@ namespace MediaBrowser.Controller.Entities.TV SpecialFeatureIds = new List<Guid>(); SoundtrackIds = new List<Guid>(); + RemoteTrailers = new List<MediaUrl>(); + LocalTrailerIds = new List<Guid>(); } + public List<Guid> LocalTrailerIds { get; set; } + + public List<MediaUrl> RemoteTrailers { get; set; } + /// <summary> /// Gets or sets the status. /// </summary> @@ -94,5 +101,14 @@ namespace MediaBrowser.Controller.Entities.TV return args; } + + [IgnoreDataMember] + public bool ContainsEpisodesWithoutSeasonFolders + { + get + { + return Children.OfType<Video>().Any(); + } + } } } diff --git a/MediaBrowser.Controller/Entities/Trailer.cs b/MediaBrowser.Controller/Entities/Trailer.cs index 26814ad40b..77efe8e8c1 100644 --- a/MediaBrowser.Controller/Entities/Trailer.cs +++ b/MediaBrowser.Controller/Entities/Trailer.cs @@ -8,7 +8,7 @@ namespace MediaBrowser.Controller.Entities /// <summary> /// Class Trailer /// </summary> - public class Trailer : Video, IHasCriticRating, IHasSoundtracks + public class Trailer : Video, IHasCriticRating, IHasSoundtracks, IHasBudget, IHasTrailers { public List<Guid> SoundtrackIds { get; set; } @@ -17,8 +17,25 @@ namespace MediaBrowser.Controller.Entities RemoteTrailers = new List<MediaUrl>(); Taglines = new List<string>(); SoundtrackIds = new List<Guid>(); + LocalTrailerIds = new List<Guid>(); } + public List<Guid> LocalTrailerIds { get; set; } + + public List<MediaUrl> RemoteTrailers { get; set; } + + /// <summary> + /// Gets or sets the budget. + /// </summary> + /// <value>The budget.</value> + public double? Budget { get; set; } + + /// <summary> + /// Gets or sets the revenue. + /// </summary> + /// <value>The revenue.</value> + public double? Revenue { get; set; } + /// <summary> /// Gets or sets the critic rating. /// </summary> diff --git a/MediaBrowser.Controller/Entities/Video.cs b/MediaBrowser.Controller/Entities/Video.cs index e900dd77e9..9b02571b00 100644 --- a/MediaBrowser.Controller/Entities/Video.cs +++ b/MediaBrowser.Controller/Entities/Video.cs @@ -14,7 +14,7 @@ namespace MediaBrowser.Controller.Entities /// <summary> /// Class Video /// </summary> - public class Video : BaseItem, IHasMediaStreams + public class Video : BaseItem, IHasMediaStreams, IHasAspectRatio { public bool IsMultiPart { get; set; } @@ -66,6 +66,12 @@ namespace MediaBrowser.Controller.Entities } /// <summary> + /// Gets or sets the aspect ratio. + /// </summary> + /// <value>The aspect ratio.</value> + public string AspectRatio { get; set; } + + /// <summary> /// Should be overridden to return the proper folder where metadata lives /// </summary> /// <value>The meta location.</value> @@ -252,5 +258,17 @@ namespace MediaBrowser.Controller.Entities }).ToList(); } + public override IEnumerable<string> GetDeletePaths() + { + if (!IsInMixedFolder) + { + if (VideoType == VideoType.VideoFile || VideoType == VideoType.Iso) + { + return new[] { System.IO.Path.GetDirectoryName(Path) }; + } + } + + return base.GetDeletePaths(); + } } } diff --git a/MediaBrowser.Controller/Entities/Year.cs b/MediaBrowser.Controller/Entities/Year.cs index d0f4577183..cd50a1c60c 100644 --- a/MediaBrowser.Controller/Entities/Year.cs +++ b/MediaBrowser.Controller/Entities/Year.cs @@ -12,11 +12,11 @@ namespace MediaBrowser.Controller.Entities { public Year() { - UserItemCounts = new Dictionary<Guid, ItemByNameCounts>(); + UserItemCountList = new List<ItemByNameCounts>(); } [IgnoreDataMember] - public Dictionary<Guid, ItemByNameCounts> UserItemCounts { get; set; } + public List<ItemByNameCounts> UserItemCountList { get; set; } /// <summary> /// Gets the user data key. diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs index 0a89c0df88..338edd5684 100644 --- a/MediaBrowser.Controller/Library/ILibraryManager.cs +++ b/MediaBrowser.Controller/Library/ILibraryManager.cs @@ -60,7 +60,7 @@ namespace MediaBrowser.Controller.Library /// </summary> /// <param name="name">The name.</param> /// <returns>Task{Artist}.</returns> - Artist GetArtist(string name); + MusicArtist GetArtist(string name); /// <summary> /// Gets a Studio @@ -302,5 +302,18 @@ namespace MediaBrowser.Controller.Library /// <param name="updateType">Type of the update.</param> /// <returns>Task.</returns> Task SaveMetadata(BaseItem item, ItemUpdateType updateType); + + /// <summary> + /// Gets all artists. + /// </summary> + /// <returns>IEnumerable{System.String}.</returns> + IEnumerable<string> GetAllArtists(); + + /// <summary> + /// Gets all artists. + /// </summary> + /// <param name="items">The items.</param> + /// <returns>IEnumerable{System.String}.</returns> + IEnumerable<string> GetAllArtists(IEnumerable<BaseItem> items); } }
\ No newline at end of file diff --git a/MediaBrowser.Controller/Library/TVUtils.cs b/MediaBrowser.Controller/Library/TVUtils.cs index 7a5722746e..65308bd100 100644 --- a/MediaBrowser.Controller/Library/TVUtils.cs +++ b/MediaBrowser.Controller/Library/TVUtils.cs @@ -257,7 +257,7 @@ namespace MediaBrowser.Controller.Library if (match != null) { - return ParseEpisodeNumber(match.Value); + return ParseEpisodeNumber(match.Groups["epnumber"].Value); } } diff --git a/MediaBrowser.Controller/LiveTv/Channel.cs b/MediaBrowser.Controller/LiveTv/Channel.cs new file mode 100644 index 0000000000..8097cea1de --- /dev/null +++ b/MediaBrowser.Controller/LiveTv/Channel.cs @@ -0,0 +1,73 @@ +using MediaBrowser.Controller.Entities; +using MediaBrowser.Model.Dto; +using MediaBrowser.Model.LiveTv; +using System; +using System.Collections.Generic; +using System.Runtime.Serialization; + +namespace MediaBrowser.Controller.LiveTv +{ + public class Channel : BaseItem, IItemByName + { + public Channel() + { + UserItemCountList = new List<ItemByNameCounts>(); + } + + /// <summary> + /// Gets the user data key. + /// </summary> + /// <returns>System.String.</returns> + public override string GetUserDataKey() + { + return "Channel-" + Name; + } + + [IgnoreDataMember] + public List<ItemByNameCounts> UserItemCountList { get; set; } + + /// <summary> + /// Gets or sets the number. + /// </summary> + /// <value>The number.</value> + public string ChannelNumber { get; set; } + + /// <summary> + /// Get or sets the Id. + /// </summary> + /// <value>The id of the channel.</value> + public string ChannelId { get; set; } + + /// <summary> + /// Gets or sets the name of the service. + /// </summary> + /// <value>The name of the service.</value> + public string ServiceName { get; set; } + + /// <summary> + /// Gets or sets the type of the channel. + /// </summary> + /// <value>The type of the channel.</value> + public ChannelType ChannelType { get; set; } + + protected override string CreateSortName() + { + double number = 0; + + if (!string.IsNullOrEmpty(ChannelNumber)) + { + double.TryParse(ChannelNumber, out number); + } + + return number.ToString("000-") + (Name ?? string.Empty); + } + + public override string MediaType + { + get + { + return ChannelType == ChannelType.Radio ? Model.Entities.MediaType.Audio : Model.Entities.MediaType.Video; + } + } + } +} diff --git a/MediaBrowser.Controller/LiveTv/ChannelInfo.cs b/MediaBrowser.Controller/LiveTv/ChannelInfo.cs index 721c1e40a8..27fc596303 100644 --- a/MediaBrowser.Controller/LiveTv/ChannelInfo.cs +++ b/MediaBrowser.Controller/LiveTv/ChannelInfo.cs @@ -26,12 +26,6 @@ namespace MediaBrowser.Controller.LiveTv public string Id { get; set; } /// <summary> - /// Gets or sets the name of the service. - /// </summary> - /// <value>The name of the service.</value> - public string ServiceName { get; set; } - - /// <summary> /// Gets or sets the type of the channel. /// </summary> /// <value>The type of the channel.</value> diff --git a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs index 62bfdf3e58..4e73fc109f 100644 --- a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs +++ b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs @@ -1,6 +1,8 @@ -using System.Threading.Tasks; -using MediaBrowser.Model.LiveTv; +using MediaBrowser.Model.LiveTv; +using MediaBrowser.Model.Querying; using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; namespace MediaBrowser.Controller.LiveTv { @@ -16,16 +18,92 @@ namespace MediaBrowser.Controller.LiveTv IReadOnlyList<ILiveTvService> Services { get; } /// <summary> + /// Schedules the recording. + /// </summary> + /// <param name="programId">The program identifier.</param> + /// <returns>Task.</returns> + Task ScheduleRecording(string programId); + + /// <summary> + /// Deletes the recording. + /// </summary> + /// <param name="id">The identifier.</param> + /// <returns>Task.</returns> + Task DeleteRecording(string id); + + /// <summary> + /// Cancels the timer. + /// </summary> + /// <param name="id">The identifier.</param> + /// <returns>Task.</returns> + Task CancelTimer(string id); + + /// <summary> /// Adds the parts. /// </summary> /// <param name="services">The services.</param> void AddParts(IEnumerable<ILiveTvService> services); /// <summary> - /// Gets the channel info dto. + /// Gets the channels. + /// </summary> + /// <param name="query">The query.</param> + /// <returns>IEnumerable{Channel}.</returns> + QueryResult<ChannelInfoDto> GetChannels(ChannelQuery query); + + /// <summary> + /// Gets the recording. + /// </summary> + /// <param name="id">The identifier.</param> + /// <param name="cancellationToken">The cancellation token.</param> + /// <returns>Task{RecordingInfoDto}.</returns> + Task<RecordingInfoDto> GetRecording(string id, CancellationToken cancellationToken); + + /// <summary> + /// Gets the timer. + /// </summary> + /// <param name="id">The identifier.</param> + /// <param name="cancellationToken">The cancellation token.</param> + /// <returns>Task{TimerInfoDto}.</returns> + Task<TimerInfoDto> GetTimer(string id, CancellationToken cancellationToken); + + /// <summary> + /// Gets the recordings. + /// </summary> + /// <param name="query">The query.</param> + /// <param name="cancellationToken">The cancellation token.</param> + /// <returns>QueryResult{RecordingInfoDto}.</returns> + Task<QueryResult<RecordingInfoDto>> GetRecordings(RecordingQuery query, CancellationToken cancellationToken); + + /// <summary> + /// Gets the timers. + /// </summary> + /// <param name="query">The query.</param> + /// <param name="cancellationToken">The cancellation token.</param> + /// <returns>Task{QueryResult{TimerInfoDto}}.</returns> + Task<QueryResult<TimerInfoDto>> GetTimers(TimerQuery query, CancellationToken cancellationToken); + + /// <summary> + /// Gets the channel. + /// </summary> + /// <param name="id">The identifier.</param> + /// <returns>Channel.</returns> + Channel GetChannel(string id); + + /// <summary> + /// Gets the channel. + /// </summary> + /// <param name="id">The identifier.</param> + /// <param name="userId">The user identifier.</param> + /// <returns>Channel.</returns> + ChannelInfoDto GetChannelInfoDto(string id, string userId); + + /// <summary> + /// Gets the programs. /// </summary> - /// <param name="info">The info.</param> - /// <returns>ChannelInfoDto.</returns> - ChannelInfoDto GetChannelInfoDto(ChannelInfo info); + /// <param name="query">The query.</param> + /// <param name="cancellationToken">The cancellation token.</param> + /// <returns>IEnumerable{ProgramInfo}.</returns> + Task<QueryResult<ProgramInfoDto>> GetPrograms(ProgramQuery query, CancellationToken cancellationToken); } } diff --git a/MediaBrowser.Controller/LiveTv/ILiveTvService.cs b/MediaBrowser.Controller/LiveTv/ILiveTvService.cs index 5c019ae8c4..a6c60d468d 100644 --- a/MediaBrowser.Controller/LiveTv/ILiveTvService.cs +++ b/MediaBrowser.Controller/LiveTv/ILiveTvService.cs @@ -1,4 +1,4 @@ -using MediaBrowser.Model.LiveTv; +using MediaBrowser.Common.Net; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; @@ -24,19 +24,88 @@ namespace MediaBrowser.Controller.LiveTv Task<IEnumerable<ChannelInfo>> GetChannelsAsync(CancellationToken cancellationToken); /// <summary> + /// Cancels the timer asynchronous. + /// </summary> + /// <param name="timerId">The timer identifier.</param> + /// <param name="cancellationToken">The cancellation token.</param> + /// <returns>Task.</returns> + Task CancelTimerAsync(string timerId, CancellationToken cancellationToken); + + /// <summary> + /// Deletes the recording asynchronous. + /// </summary> + /// <param name="recordingId">The recording identifier.</param> + /// <param name="cancellationToken">The cancellation token.</param> + /// <returns>Task.</returns> + Task DeleteRecordingAsync(string recordingId, CancellationToken cancellationToken); + + /// <summary> + /// Creates the timer asynchronous. + /// </summary> + /// <param name="info">The information.</param> + /// <param name="cancellationToken">The cancellation token.</param> + /// <returns>Task.</returns> + Task CreateTimerAsync(TimerInfo info, CancellationToken cancellationToken); + + /// <summary> + /// Creates the series timer asynchronous. + /// </summary> + /// <param name="info">The information.</param> + /// <param name="cancellationToken">The cancellation token.</param> + /// <returns>Task.</returns> + Task CreateSeriesTimerAsync(SeriesTimerInfo info, CancellationToken cancellationToken); + + /// <summary> + /// Updates the series timer asynchronous. + /// </summary> + /// <param name="info">The information.</param> + /// <param name="cancellationToken">The cancellation token.</param> + /// <returns>Task.</returns> + Task UpdateSeriesTimerAsync(SeriesTimerInfo info, CancellationToken cancellationToken); + + /// <summary> + /// Gets the channel image asynchronous. + /// </summary> + /// <param name="channelId">The channel identifier.</param> + /// <param name="cancellationToken">The cancellation token.</param> + /// <returns>Task{Stream}.</returns> + Task<ImageResponseInfo> GetChannelImageAsync(string channelId, CancellationToken cancellationToken); + + /// <summary> + /// Gets the program image asynchronous. + /// </summary> + /// <param name="programId">The program identifier.</param> + /// <param name="cancellationToken">The cancellation token.</param> + /// <returns>Task{ImageResponseInfo}.</returns> + Task<ImageResponseInfo> GetProgramImageAsync(string programId, CancellationToken cancellationToken); + + /// <summary> /// Gets the recordings asynchronous. /// </summary> - /// <param name="query">The query.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task{IEnumerable{RecordingInfo}}.</returns> - Task<IEnumerable<RecordingInfo>> GetRecordingsAsync(RecordingQuery query, CancellationToken cancellationToken); + Task<IEnumerable<RecordingInfo>> GetRecordingsAsync(CancellationToken cancellationToken); /// <summary> - /// Gets the channel guides. + /// Gets the recordings asynchronous. + /// </summary> + /// <param name="cancellationToken">The cancellation token.</param> + /// <returns>Task{IEnumerable{RecordingInfo}}.</returns> + Task<IEnumerable<TimerInfo>> GetTimersAsync(CancellationToken cancellationToken); + + /// <summary> + /// Gets the series timers asynchronous. + /// </summary> + /// <param name="cancellationToken">The cancellation token.</param> + /// <returns>Task{IEnumerable{SeriesTimerInfo}}.</returns> + Task<IEnumerable<SeriesTimerInfo>> GetSeriesTimersAsync(CancellationToken cancellationToken); + + /// <summary> + /// Gets the programs asynchronous. /// </summary> - /// <param name="channelIdList">The channel identifier list.</param> + /// <param name="channelId">The channel identifier.</param> /// <param name="cancellationToken">The cancellation token.</param> - /// <returns>Task{IEnumerable{ChannelGuide}}.</returns> - Task<IEnumerable<ChannelGuide>> GetChannelGuidesAsync(IEnumerable<string> channelIdList, CancellationToken cancellationToken); + /// <returns>Task{IEnumerable{ProgramInfo}}.</returns> + Task<IEnumerable<ProgramInfo>> GetProgramsAsync(string channelId, CancellationToken cancellationToken); } } diff --git a/MediaBrowser.Controller/LiveTv/ImageResponseInfo.cs b/MediaBrowser.Controller/LiveTv/ImageResponseInfo.cs new file mode 100644 index 0000000000..d454a1ef8d --- /dev/null +++ b/MediaBrowser.Controller/LiveTv/ImageResponseInfo.cs @@ -0,0 +1,19 @@ +using System.IO; + +namespace MediaBrowser.Controller.LiveTv +{ + public class ImageResponseInfo + { + /// <summary> + /// Gets or sets the stream. + /// </summary> + /// <value>The stream.</value> + public Stream Stream { get; set; } + + /// <summary> + /// Gets or sets the type of the MIME. + /// </summary> + /// <value>The type of the MIME.</value> + public string MimeType { get; set; } + } +} diff --git a/MediaBrowser.Controller/LiveTv/ProgramInfo.cs b/MediaBrowser.Controller/LiveTv/ProgramInfo.cs new file mode 100644 index 0000000000..cf5cdb94c9 --- /dev/null +++ b/MediaBrowser.Controller/LiveTv/ProgramInfo.cs @@ -0,0 +1,98 @@ +using MediaBrowser.Model.LiveTv; +using System; +using System.Collections.Generic; + +namespace MediaBrowser.Controller.LiveTv +{ + public class ProgramInfo + { + /// <summary> + /// Id of the program. + /// </summary> + public string Id { get; set; } + + /// <summary> + /// Gets or sets the channel identifier. + /// </summary> + /// <value>The channel identifier.</value> + public string ChannelId { get; set; } + + /// <summary> + /// Name of the program + /// </summary> + public string Name { get; set; } + + /// <summary> + /// Gets or sets the official rating. + /// </summary> + /// <value>The official rating.</value> + public string OfficialRating { get; set; } + + /// <summary> + /// Description of the progam. + /// </summary> + public string Description { get; set; } + + /// <summary> + /// The start date of the program, in UTC. + /// </summary> + public DateTime StartDate { get; set; } + + /// <summary> + /// The end date of the program, in UTC. + /// </summary> + public DateTime EndDate { get; set; } + + /// <summary> + /// Gets or sets the aspect ratio. + /// </summary> + /// <value>The aspect ratio.</value> + public string AspectRatio { get; set; } + + /// <summary> + /// Genre of the program. + /// </summary> + public List<string> Genres { get; set; } + + /// <summary> + /// Gets or sets the quality. + /// </summary> + /// <value>The quality.</value> + public ProgramVideoQuality Quality { get; set; } + + /// <summary> + /// Gets or sets the original air date. + /// </summary> + /// <value>The original air date.</value> + public DateTime? OriginalAirDate { get; set; } + + /// <summary> + /// Gets or sets the audio. + /// </summary> + /// <value>The audio.</value> + public ProgramAudio Audio { get; set; } + + /// <summary> + /// Gets or sets the community rating. + /// </summary> + /// <value>The community rating.</value> + public float? CommunityRating { get; set; } + + /// <summary> + /// Gets or sets a value indicating whether this instance is repeat. + /// </summary> + /// <value><c>true</c> if this instance is repeat; otherwise, <c>false</c>.</value> + public bool IsRepeat { get; set; } + + /// <summary> + /// Gets or sets the episode title. + /// </summary> + /// <value>The episode title.</value> + public string EpisodeTitle { get; set; } + + public ProgramInfo() + { + Genres = new List<string>(); + } + } +} diff --git a/MediaBrowser.Controller/LiveTv/RecordingInfo.cs b/MediaBrowser.Controller/LiveTv/RecordingInfo.cs new file mode 100644 index 0000000000..2c8e8cb464 --- /dev/null +++ b/MediaBrowser.Controller/LiveTv/RecordingInfo.cs @@ -0,0 +1,102 @@ +using MediaBrowser.Model.LiveTv; +using System; +using System.Collections.Generic; + +namespace MediaBrowser.Controller.LiveTv +{ + public class RecordingInfo + { + /// <summary> + /// Id of the recording. + /// </summary> + public string Id { get; set; } + + /// <summary> + /// ChannelId of the recording. + /// </summary> + public string ChannelId { get; set; } + + /// <summary> + /// ChannelName of the recording. + /// </summary> + public string ChannelName { get; set; } + + /// <summary> + /// Gets or sets the type of the channel. + /// </summary> + /// <value>The type of the channel.</value> + public ChannelType ChannelType { get; set; } + + /// <summary> + /// Name of the recording. + /// </summary> + public string Name { get; set; } + + /// <summary> + /// Gets or sets the path. + /// </summary> + /// <value>The path.</value> + public string Path { get; set; } + + /// <summary> + /// Description of the recording. + /// </summary> + public string Description { get; set; } + + /// <summary> + /// The start date of the recording, in UTC. + /// </summary> + public DateTime StartDate { get; set; } + + /// <summary> + /// The end date of the recording, in UTC. + /// </summary> + public DateTime EndDate { get; set; } + + /// <summary> + /// Gets or sets the program identifier. + /// </summary> + /// <value>The program identifier.</value> + public string ProgramId { get; set; } + + /// <summary> + /// Gets or sets the status. + /// </summary> + /// <value>The status.</value> + public RecordingStatus Status { get; set; } + + /// <summary> + /// Genre of the program. + /// </summary> + public List<string> Genres { get; set; } + + /// <summary> + /// Gets or sets a value indicating whether this instance is repeat. + /// </summary> + /// <value><c>true</c> if this instance is repeat; otherwise, <c>false</c>.</value> + public bool IsRepeat { get; set; } + + /// <summary> + /// Gets or sets the episode title. + /// </summary> + /// <value>The episode title.</value> + public string EpisodeTitle { get; set; } + + /// <summary> + /// Gets or sets the official rating. + /// </summary> + /// <value>The official rating.</value> + public string OfficialRating { get; set; } + + /// <summary> + /// Gets or sets the community rating. + /// </summary> + /// <value>The community rating.</value> + public float? CommunityRating { get; set; } + + public RecordingInfo() + { + Genres = new List<string>(); + } + } +} diff --git a/MediaBrowser.Controller/LiveTv/SeriesTimerInfo.cs b/MediaBrowser.Controller/LiveTv/SeriesTimerInfo.cs new file mode 100644 index 0000000000..44594882cd --- /dev/null +++ b/MediaBrowser.Controller/LiveTv/SeriesTimerInfo.cs @@ -0,0 +1,85 @@ +using MediaBrowser.Model.LiveTv; +using System; +using System.Collections.Generic; + +namespace MediaBrowser.Controller.LiveTv +{ + public class SeriesTimerInfo + { + /// <summary> + /// Id of the recording. + /// </summary> + public string Id { get; set; } + + /// <summary> + /// ChannelId of the recording. + /// </summary> + public string ChannelId { get; set; } + + /// <summary> + /// ChannelName of the recording. + /// </summary> + public string ChannelName { get; set; } + + /// <summary> + /// Gets or sets the program identifier. + /// </summary> + /// <value>The program identifier.</value> + public string ProgramId { get; set; } + + /// <summary> + /// Name of the recording. + /// </summary> + public string Name { get; set; } + + /// <summary> + /// Description of the recording. + /// </summary> + public string Description { get; set; } + + /// <summary> + /// The start date of the recording, in UTC. + /// </summary> + public DateTime StartDate { get; set; } + + /// <summary> + /// The end date of the recording, in UTC. + /// </summary> + public DateTime EndDate { get; set; } + + /// <summary> + /// Gets or sets the pre padding seconds. + /// </summary> + /// <value>The pre padding seconds.</value> + public int PrePaddingSeconds { get; set; } + + /// <summary> + /// Gets or sets the post padding seconds. + /// </summary> + /// <value>The post padding seconds.</value> + public int PostPaddingSeconds { get; set; } + + /// <summary> + /// Gets or sets the type of the recurrence. + /// </summary> + /// <value>The type of the recurrence.</value> + public RecurrenceType RecurrenceType { get; set; } + + /// <summary> + /// Gets or sets the days. + /// </summary> + /// <value>The days.</value> + public List<DayOfWeek> Days { get; set; } + + /// <summary> + /// Gets or sets the priority. + /// </summary> + /// <value>The priority.</value> + public int Priority { get; set; } + + public SeriesTimerInfo() + { + Days = new List<DayOfWeek>(); + } + } +} diff --git a/MediaBrowser.Controller/LiveTv/TimerInfo.cs b/MediaBrowser.Controller/LiveTv/TimerInfo.cs new file mode 100644 index 0000000000..3df0b8ccab --- /dev/null +++ b/MediaBrowser.Controller/LiveTv/TimerInfo.cs @@ -0,0 +1,73 @@ +using MediaBrowser.Model.LiveTv; +using System; + +namespace MediaBrowser.Controller.LiveTv +{ + public class TimerInfo + { + /// <summary> + /// Id of the recording. + /// </summary> + public string Id { get; set; } + + /// <summary> + /// Gets or sets the series timer identifier. + /// </summary> + /// <value>The series timer identifier.</value> + public string SeriesTimerId { get; set; } + + /// <summary> + /// ChannelId of the recording. + /// </summary> + public string ChannelId { get; set; } + + /// <summary> + /// ChannelName of the recording. + /// </summary> + public string ChannelName { get; set; } + + /// <summary> + /// Gets or sets the program identifier. + /// </summary> + /// <value>The program identifier.</value> + public string ProgramId { get; set; } + + /// <summary> + /// Name of the recording. + /// </summary> + public string Name { get; set; } + + /// <summary> + /// Description of the recording. + /// </summary> + public string Description { get; set; } + + /// <summary> + /// The start date of the recording, in UTC. + /// </summary> + public DateTime StartDate { get; set; } + + /// <summary> + /// The end date of the recording, in UTC. + /// </summary> + public DateTime EndDate { get; set; } + + /// <summary> + /// Gets or sets the status. + /// </summary> + /// <value>The status.</value> + public RecordingStatus Status { get; set; } + + /// <summary> + /// Gets or sets the pre padding seconds. + /// </summary> + /// <value>The pre padding seconds.</value> + public int PrePaddingSeconds { get; set; } + + /// <summary> + /// Gets or sets the post padding seconds. + /// </summary> + /// <value>The post padding seconds.</value> + public int PostPaddingSeconds { get; set; } + } +} diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index f2837a1f1d..2beb3588ed 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -89,8 +89,11 @@ <Compile Include="Entities\GameGenre.cs" /> <Compile Include="Entities\GameSystem.cs" /> <Compile Include="Entities\IByReferenceItem.cs" /> + <Compile Include="Entities\IHasAspectRatio.cs" /> + <Compile Include="Entities\IHasBudget.cs" /> <Compile Include="Entities\IHasCriticRating.cs" /> <Compile Include="Entities\IHasSoundtracks.cs" /> + <Compile Include="Entities\IHasTrailers.cs" /> <Compile Include="Entities\IItemByName.cs" /> <Compile Include="Entities\ILibraryItem.cs" /> <Compile Include="Entities\ImageSourceInfo.cs" /> @@ -103,18 +106,24 @@ <Compile Include="Library\ItemUpdateType.cs" /> <Compile Include="Library\IUserDataManager.cs" /> <Compile Include="Library\UserDataSaveEventArgs.cs" /> + <Compile Include="LiveTv\Channel.cs" /> <Compile Include="LiveTv\ChannelInfo.cs" /> <Compile Include="LiveTv\ILiveTvManager.cs" /> <Compile Include="LiveTv\ILiveTvService.cs" /> + <Compile Include="LiveTv\ImageResponseInfo.cs" /> + <Compile Include="LiveTv\ProgramInfo.cs" /> + <Compile Include="LiveTv\RecordingInfo.cs" /> + <Compile Include="LiveTv\SeriesTimerInfo.cs" /> + <Compile Include="LiveTv\TimerInfo.cs" /> <Compile Include="Localization\ILocalizationManager.cs" /> <Compile Include="Notifications\INotificationsRepository.cs" /> <Compile Include="Notifications\NotificationUpdateEventArgs.cs" /> <Compile Include="Providers\IDynamicInfoProvider.cs" /> <Compile Include="Providers\IImageProvider.cs" /> + <Compile Include="Providers\NameParser.cs" /> <Compile Include="Session\ISessionManager.cs" /> <Compile Include="Drawing\ImageExtensions.cs" /> <Compile Include="Entities\AggregateFolder.cs" /> - <Compile Include="Entities\Audio\Artist.cs" /> <Compile Include="Entities\Audio\Audio.cs" /> <Compile Include="Entities\Audio\MusicAlbum.cs" /> <Compile Include="Entities\Audio\MusicArtist.cs" /> diff --git a/MediaBrowser.Controller/Providers/BaseItemXmlParser.cs b/MediaBrowser.Controller/Providers/BaseItemXmlParser.cs index 9fdbbf3b7e..617e4fd819 100644 --- a/MediaBrowser.Controller/Providers/BaseItemXmlParser.cs +++ b/MediaBrowser.Controller/Providers/BaseItemXmlParser.cs @@ -69,6 +69,12 @@ namespace MediaBrowser.Controller.Providers item.People.Clear(); item.Tags.Clear(); + var hasTrailers = item as IHasTrailers; + if (hasTrailers != null) + { + hasTrailers.RemoteTrailers.Clear(); + } + //Fetch(item, metadataFile, settings, Encoding.GetEncoding("ISO-8859-1"), cancellationToken); Fetch(item, metadataFile, settings, Encoding.UTF8, cancellationToken); } @@ -161,10 +167,14 @@ namespace MediaBrowser.Controller.Providers case "Budget": { var text = reader.ReadElementContentAsString(); - double value; - if (double.TryParse(text, NumberStyles.Any, _usCulture, out value)) + var hasBudget = item as IHasBudget; + if (hasBudget != null) { - item.Budget = value; + double value; + if (double.TryParse(text, NumberStyles.Any, _usCulture, out value)) + { + hasBudget.Budget = value; + } } break; @@ -173,10 +183,14 @@ namespace MediaBrowser.Controller.Providers case "Revenue": { var text = reader.ReadElementContentAsString(); - double value; - if (double.TryParse(text, NumberStyles.Any, _usCulture, out value)) + var hasBudget = item as IHasBudget; + if (hasBudget != null) { - item.Revenue = value; + double value; + if (double.TryParse(text, NumberStyles.Any, _usCulture, out value)) + { + hasBudget.Revenue = value; + } } break; @@ -375,9 +389,10 @@ namespace MediaBrowser.Controller.Providers { var val = reader.ReadElementContentAsString(); - if (!string.IsNullOrWhiteSpace(val)) + var hasAspectRatio = item as IHasAspectRatio; + if (!string.IsNullOrWhiteSpace(val) && hasAspectRatio != null) { - item.AspectRatio = val; + hasAspectRatio.AspectRatio = val; } break; } @@ -474,9 +489,26 @@ namespace MediaBrowser.Controller.Providers { var val = reader.ReadElementContentAsString(); - if (!string.IsNullOrWhiteSpace(val)) + var hasTrailers = item as IHasTrailers; + if (hasTrailers != null) { - item.AddTrailerUrl(val, false); + if (!string.IsNullOrWhiteSpace(val)) + { + hasTrailers.AddTrailerUrl(val, false); + } + } + break; + } + + case "Trailers": + { + using (var subtree = reader.ReadSubtree()) + { + var hasTrailers = item as IHasTrailers; + if (hasTrailers != null) + { + FetchDataFromTrailersNode(subtree, hasTrailers); + } } break; } @@ -921,6 +953,35 @@ namespace MediaBrowser.Controller.Providers } } + private void FetchDataFromTrailersNode(XmlReader reader, IHasTrailers item) + { + reader.MoveToContent(); + + while (reader.Read()) + { + if (reader.NodeType == XmlNodeType.Element) + { + switch (reader.Name) + { + case "Trailer": + { + var val = reader.ReadElementContentAsString(); + + if (!string.IsNullOrWhiteSpace(val)) + { + item.AddTrailerUrl(val, false); + } + break; + } + + default: + reader.Skip(); + break; + } + } + } + } + protected async Task FetchChaptersFromXmlNode(BaseItem item, XmlReader reader, IItemRepository repository, CancellationToken cancellationToken) { var runtime = item.RunTimeTicks ?? 0; @@ -1071,9 +1132,10 @@ namespace MediaBrowser.Controller.Providers /// <returns>IEnumerable{PersonInfo}.</returns> private IEnumerable<PersonInfo> GetPersonsFromXmlNode(XmlReader reader) { - var names = new List<string>(); + var name = string.Empty; var type = "Actor"; // If type is not specified assume actor var role = string.Empty; + int? sortOrder = null; reader.MoveToContent(); @@ -1084,7 +1146,7 @@ namespace MediaBrowser.Controller.Providers switch (reader.Name) { case "Name": - names.AddRange(SplitNames(reader.ReadElementContentAsString())); + name = reader.ReadElementContentAsString() ?? string.Empty; break; case "Type": @@ -1108,6 +1170,20 @@ namespace MediaBrowser.Controller.Providers } break; } + case "SortOrder": + { + var val = reader.ReadElementContentAsString(); + + if (!string.IsNullOrWhiteSpace(val)) + { + int intVal; + if (int.TryParse(val, NumberStyles.Integer, _usCulture, out intVal)) + { + sortOrder = intVal; + } + } + break; + } default: reader.Skip(); @@ -1116,7 +1192,15 @@ namespace MediaBrowser.Controller.Providers } } - return names.Select(n => new PersonInfo { Name = n.Trim(), Role = role, Type = type }); + var personInfo = new PersonInfo + { + Name = name.Trim(), + Role = role, + Type = type, + SortOrder = sortOrder + }; + + return new[] { personInfo }; } /// <summary> diff --git a/MediaBrowser.Controller/Providers/NameParser.cs b/MediaBrowser.Controller/Providers/NameParser.cs new file mode 100644 index 0000000000..726f0e60e3 --- /dev/null +++ b/MediaBrowser.Controller/Providers/NameParser.cs @@ -0,0 +1,39 @@ +using System; +using System.Text.RegularExpressions; + +namespace MediaBrowser.Controller.Providers +{ + public static class NameParser + { + static readonly Regex[] NameMatches = new[] { + new Regex(@"(?<name>.*)\((?<year>\d{4})\)"), // matches "My Movie (2001)" and gives us the name and the year + new Regex(@"(?<name>.*)(\.(?<year>\d{4})(\.|$)).*$"), + new Regex(@"(?<name>.*)") // last resort matches the whole string as the name + }; + + + /// <summary> + /// Parses the name. + /// </summary> + /// <param name="name">The name.</param> + /// <param name="justName">Name of the just.</param> + /// <param name="year">The year.</param> + public static void ParseName(string name, out string justName, out int? year) + { + justName = null; + year = null; + foreach (var re in NameMatches) + { + Match m = re.Match(name); + if (m.Success) + { + justName = m.Groups["name"].Value.Trim(); + string y = m.Groups["year"] != null ? m.Groups["year"].Value : null; + int temp; + year = Int32.TryParse(y, out temp) ? temp : (int?)null; + break; + } + } + } + } +} |
