From 3d47b495a96fce84c03d9f3177dc6dbc8a4afa3c Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sun, 29 Jun 2014 23:04:50 -0400 Subject: fixes #795 - Support reading Xbmc nfo's --- MediaBrowser.LocalMetadata/Savers/AlbumXmlSaver.cs | 68 ++ .../Savers/ArtistXmlSaver.cs | 68 ++ .../Savers/BoxSetXmlSaver.cs | 68 ++ .../Savers/ChannelXmlSaver.cs | 73 +++ .../Savers/EpisodeXmlSaver.cs | 151 +++++ .../Savers/FolderXmlSaver.cs | 80 +++ .../Savers/GameSystemXmlSaver.cs | 75 +++ MediaBrowser.LocalMetadata/Savers/GameXmlSaver.cs | 112 ++++ MediaBrowser.LocalMetadata/Savers/MovieXmlSaver.cs | 133 ++++ .../Savers/PersonXmlSaver.cs | 81 +++ .../Savers/SeasonXmlSaver.cs | 87 +++ .../Savers/SeriesXmlSaver.cs | 135 ++++ .../Savers/XmlSaverHelpers.cs | 718 +++++++++++++++++++++ 13 files changed, 1849 insertions(+) create mode 100644 MediaBrowser.LocalMetadata/Savers/AlbumXmlSaver.cs create mode 100644 MediaBrowser.LocalMetadata/Savers/ArtistXmlSaver.cs create mode 100644 MediaBrowser.LocalMetadata/Savers/BoxSetXmlSaver.cs create mode 100644 MediaBrowser.LocalMetadata/Savers/ChannelXmlSaver.cs create mode 100644 MediaBrowser.LocalMetadata/Savers/EpisodeXmlSaver.cs create mode 100644 MediaBrowser.LocalMetadata/Savers/FolderXmlSaver.cs create mode 100644 MediaBrowser.LocalMetadata/Savers/GameSystemXmlSaver.cs create mode 100644 MediaBrowser.LocalMetadata/Savers/GameXmlSaver.cs create mode 100644 MediaBrowser.LocalMetadata/Savers/MovieXmlSaver.cs create mode 100644 MediaBrowser.LocalMetadata/Savers/PersonXmlSaver.cs create mode 100644 MediaBrowser.LocalMetadata/Savers/SeasonXmlSaver.cs create mode 100644 MediaBrowser.LocalMetadata/Savers/SeriesXmlSaver.cs create mode 100644 MediaBrowser.LocalMetadata/Savers/XmlSaverHelpers.cs (limited to 'MediaBrowser.LocalMetadata/Savers') diff --git a/MediaBrowser.LocalMetadata/Savers/AlbumXmlSaver.cs b/MediaBrowser.LocalMetadata/Savers/AlbumXmlSaver.cs new file mode 100644 index 0000000000..05022464d9 --- /dev/null +++ b/MediaBrowser.LocalMetadata/Savers/AlbumXmlSaver.cs @@ -0,0 +1,68 @@ +using System.Collections.Generic; +using System.IO; +using System.Text; +using System.Threading; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities.Audio; +using MediaBrowser.Controller.Library; + +namespace MediaBrowser.LocalMetadata.Savers +{ + class AlbumXmlSaver : IMetadataFileSaver + { + public string Name + { + get + { + return "Media Browser Xml"; + } + } + + /// + /// Determines whether [is enabled for] [the specified item]. + /// + /// The item. + /// Type of the update. + /// true if [is enabled for] [the specified item]; otherwise, false. + public bool IsEnabledFor(IHasMetadata item, ItemUpdateType updateType) + { + if (!item.SupportsLocalMetadata) + { + return false; + } + + return item is MusicAlbum && updateType >= ItemUpdateType.MetadataDownload; + } + + /// + /// Saves the specified item. + /// + /// The item. + /// The cancellation token. + /// Task. + public void Save(IHasMetadata item, CancellationToken cancellationToken) + { + var builder = new StringBuilder(); + + builder.Append(""); + + XmlSaverHelpers.AddCommonNodes((MusicAlbum)item, builder); + + builder.Append(""); + + var xmlFilePath = GetSavePath(item); + + XmlSaverHelpers.Save(builder, xmlFilePath, new List { }); + } + + /// + /// Gets the save path. + /// + /// The item. + /// System.String. + public string GetSavePath(IHasMetadata item) + { + return Path.Combine(item.Path, "album.xml"); + } + } +} diff --git a/MediaBrowser.LocalMetadata/Savers/ArtistXmlSaver.cs b/MediaBrowser.LocalMetadata/Savers/ArtistXmlSaver.cs new file mode 100644 index 0000000000..b932c5c7c7 --- /dev/null +++ b/MediaBrowser.LocalMetadata/Savers/ArtistXmlSaver.cs @@ -0,0 +1,68 @@ +using System.Collections.Generic; +using System.IO; +using System.Text; +using System.Threading; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities.Audio; +using MediaBrowser.Controller.Library; + +namespace MediaBrowser.LocalMetadata.Savers +{ + class ArtistXmlSaver : IMetadataFileSaver + { + public string Name + { + get + { + return "Media Browser Xml"; + } + } + + /// + /// Determines whether [is enabled for] [the specified item]. + /// + /// The item. + /// Type of the update. + /// true if [is enabled for] [the specified item]; otherwise, false. + public bool IsEnabledFor(IHasMetadata item, ItemUpdateType updateType) + { + if (!item.SupportsLocalMetadata) + { + return false; + } + + return item is MusicArtist && updateType >= ItemUpdateType.MetadataDownload; + } + + /// + /// Saves the specified item. + /// + /// The item. + /// The cancellation token. + /// Task. + public void Save(IHasMetadata item, CancellationToken cancellationToken) + { + var builder = new StringBuilder(); + + builder.Append(""); + + XmlSaverHelpers.AddCommonNodes((MusicArtist)item, builder); + + builder.Append(""); + + var xmlFilePath = GetSavePath(item); + + XmlSaverHelpers.Save(builder, xmlFilePath, new List { }); + } + + /// + /// Gets the save path. + /// + /// The item. + /// System.String. + public string GetSavePath(IHasMetadata item) + { + return Path.Combine(item.Path, "artist.xml"); + } + } +} diff --git a/MediaBrowser.LocalMetadata/Savers/BoxSetXmlSaver.cs b/MediaBrowser.LocalMetadata/Savers/BoxSetXmlSaver.cs new file mode 100644 index 0000000000..db7b40c7de --- /dev/null +++ b/MediaBrowser.LocalMetadata/Savers/BoxSetXmlSaver.cs @@ -0,0 +1,68 @@ +using System.Collections.Generic; +using System.IO; +using System.Text; +using System.Threading; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities.Movies; +using MediaBrowser.Controller.Library; + +namespace MediaBrowser.LocalMetadata.Savers +{ + public class BoxSetXmlSaver : IMetadataFileSaver + { + public string Name + { + get + { + return "Media Browser Xml"; + } + } + + /// + /// Determines whether [is enabled for] [the specified item]. + /// + /// The item. + /// Type of the update. + /// true if [is enabled for] [the specified item]; otherwise, false. + public bool IsEnabledFor(IHasMetadata item, ItemUpdateType updateType) + { + if (!item.SupportsLocalMetadata) + { + return false; + } + + return item is BoxSet && updateType >= ItemUpdateType.MetadataDownload; + } + + /// + /// Saves the specified item. + /// + /// The item. + /// The cancellation token. + /// Task. + public void Save(IHasMetadata item, CancellationToken cancellationToken) + { + var builder = new StringBuilder(); + + builder.Append(""); + + XmlSaverHelpers.AddCommonNodes((BoxSet)item, builder); + + builder.Append(""); + + var xmlFilePath = GetSavePath(item); + + XmlSaverHelpers.Save(builder, xmlFilePath, new List { }); + } + + /// + /// Gets the save path. + /// + /// The item. + /// System.String. + public string GetSavePath(IHasMetadata item) + { + return Path.Combine(item.Path, "collection.xml"); + } + } +} diff --git a/MediaBrowser.LocalMetadata/Savers/ChannelXmlSaver.cs b/MediaBrowser.LocalMetadata/Savers/ChannelXmlSaver.cs new file mode 100644 index 0000000000..3b77830121 --- /dev/null +++ b/MediaBrowser.LocalMetadata/Savers/ChannelXmlSaver.cs @@ -0,0 +1,73 @@ +using System.Collections.Generic; +using System.IO; +using System.Text; +using System.Threading; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.LiveTv; + +namespace MediaBrowser.LocalMetadata.Savers +{ + /// + /// Class PersonXmlSaver + /// + public class ChannelXmlSaver : IMetadataFileSaver + { + /// + /// Determines whether [is enabled for] [the specified item]. + /// + /// The item. + /// Type of the update. + /// true if [is enabled for] [the specified item]; otherwise, false. + public bool IsEnabledFor(IHasMetadata item, ItemUpdateType updateType) + { + if (!item.SupportsLocalMetadata) + { + return false; + } + + return item is LiveTvChannel && updateType >= ItemUpdateType.MetadataDownload; + } + + public string Name + { + get + { + return "Media Browser Xml"; + } + } + + /// + /// Saves the specified item. + /// + /// The item. + /// The cancellation token. + /// Task. + public void Save(IHasMetadata item, CancellationToken cancellationToken) + { + var builder = new StringBuilder(); + + builder.Append(""); + + XmlSaverHelpers.AddCommonNodes((LiveTvChannel)item, builder); + + builder.Append(""); + + var xmlFilePath = GetSavePath(item); + + XmlSaverHelpers.Save(builder, xmlFilePath, new List + { + }); + } + + /// + /// Gets the save path. + /// + /// The item. + /// System.String. + public string GetSavePath(IHasMetadata item) + { + return Path.Combine(item.Path, "channel.xml"); + } + } +} diff --git a/MediaBrowser.LocalMetadata/Savers/EpisodeXmlSaver.cs b/MediaBrowser.LocalMetadata/Savers/EpisodeXmlSaver.cs new file mode 100644 index 0000000000..275ec2fe8f --- /dev/null +++ b/MediaBrowser.LocalMetadata/Savers/EpisodeXmlSaver.cs @@ -0,0 +1,151 @@ +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Security; +using System.Text; +using System.Threading; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities.TV; +using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Persistence; + +namespace MediaBrowser.LocalMetadata.Savers +{ + public class EpisodeXmlSaver : IMetadataFileSaver + { + private readonly IItemRepository _itemRepository; + + private readonly CultureInfo _usCulture = new CultureInfo("en-US"); + + public EpisodeXmlSaver(IItemRepository itemRepository) + { + _itemRepository = itemRepository; + } + + /// + /// Determines whether [is enabled for] [the specified item]. + /// + /// The item. + /// Type of the update. + /// true if [is enabled for] [the specified item]; otherwise, false. + public bool IsEnabledFor(IHasMetadata item, ItemUpdateType updateType) + { + if (!item.SupportsLocalMetadata) + { + return false; + } + + return item is Episode && updateType >= ItemUpdateType.MetadataDownload; + } + + public string Name + { + get + { + return "Media Browser Xml"; + } + } + + /// + /// Saves the specified item. + /// + /// The item. + /// The cancellation token. + /// Task. + public void Save(IHasMetadata item, CancellationToken cancellationToken) + { + var episode = (Episode)item; + + var builder = new StringBuilder(); + + builder.Append(""); + + if (!string.IsNullOrEmpty(item.Name)) + { + builder.Append("" + SecurityElement.Escape(episode.Name) + ""); + } + + if (episode.IndexNumber.HasValue) + { + builder.Append("" + SecurityElement.Escape(episode.IndexNumber.Value.ToString(_usCulture)) + ""); + } + + if (episode.IndexNumberEnd.HasValue) + { + builder.Append("" + SecurityElement.Escape(episode.IndexNumberEnd.Value.ToString(_usCulture)) + ""); + } + + if (episode.AirsAfterSeasonNumber.HasValue) + { + builder.Append("" + SecurityElement.Escape(episode.AirsAfterSeasonNumber.Value.ToString(_usCulture)) + ""); + } + if (episode.AirsBeforeEpisodeNumber.HasValue) + { + builder.Append("" + SecurityElement.Escape(episode.AirsBeforeEpisodeNumber.Value.ToString(_usCulture)) + ""); + } + if (episode.AirsBeforeSeasonNumber.HasValue) + { + builder.Append("" + SecurityElement.Escape(episode.AirsBeforeSeasonNumber.Value.ToString(_usCulture)) + ""); + } + + if (episode.ParentIndexNumber.HasValue) + { + builder.Append("" + SecurityElement.Escape(episode.ParentIndexNumber.Value.ToString(_usCulture)) + ""); + } + + if (episode.AbsoluteEpisodeNumber.HasValue) + { + builder.Append("" + SecurityElement.Escape(episode.AbsoluteEpisodeNumber.Value.ToString(_usCulture)) + ""); + } + + if (episode.DvdEpisodeNumber.HasValue) + { + builder.Append("" + SecurityElement.Escape(episode.DvdEpisodeNumber.Value.ToString(_usCulture)) + ""); + } + + if (episode.DvdSeasonNumber.HasValue) + { + builder.Append("" + SecurityElement.Escape(episode.DvdSeasonNumber.Value.ToString(_usCulture)) + ""); + } + + if (episode.PremiereDate.HasValue) + { + builder.Append("" + SecurityElement.Escape(episode.PremiereDate.Value.ToLocalTime().ToString("yyyy-MM-dd")) + ""); + } + + XmlSaverHelpers.AddCommonNodes(episode, builder); + XmlSaverHelpers.AddMediaInfo(episode, builder, _itemRepository); + + builder.Append(""); + + var xmlFilePath = GetSavePath(item); + + XmlSaverHelpers.Save(builder, xmlFilePath, new List + { + "FirstAired", + "SeasonNumber", + "EpisodeNumber", + "EpisodeName", + "EpisodeNumberEnd", + "airsafter_season", + "airsbefore_episode", + "airsbefore_season", + "DVD_episodenumber", + "DVD_season", + "absolute_number" + }); + } + + /// + /// Gets the save path. + /// + /// The item. + /// System.String. + public string GetSavePath(IHasMetadata item) + { + var filename = Path.ChangeExtension(Path.GetFileName(item.Path), ".xml"); + + return Path.Combine(Path.GetDirectoryName(item.Path), "metadata", filename); + } + } +} diff --git a/MediaBrowser.LocalMetadata/Savers/FolderXmlSaver.cs b/MediaBrowser.LocalMetadata/Savers/FolderXmlSaver.cs new file mode 100644 index 0000000000..6dd65b69c5 --- /dev/null +++ b/MediaBrowser.LocalMetadata/Savers/FolderXmlSaver.cs @@ -0,0 +1,80 @@ +using System.Collections.Generic; +using System.IO; +using System.Text; +using System.Threading; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities.Audio; +using MediaBrowser.Controller.Entities.Movies; +using MediaBrowser.Controller.Entities.TV; +using MediaBrowser.Controller.Library; + +namespace MediaBrowser.LocalMetadata.Savers +{ + public class FolderXmlSaver : IMetadataFileSaver + { + public string Name + { + get + { + return "Media Browser Xml"; + } + } + + /// + /// Determines whether [is enabled for] [the specified item]. + /// + /// The item. + /// Type of the update. + /// true if [is enabled for] [the specified item]; otherwise, false. + public bool IsEnabledFor(IHasMetadata item, ItemUpdateType updateType) + { + if (!item.SupportsLocalMetadata) + { + return false; + } + + if (item is Folder) + { + if (!(item is Series) && !(item is BoxSet) && !(item is MusicArtist) && !(item is MusicAlbum) && + !(item is Season) && + !(item is GameSystem)) + { + return updateType >= ItemUpdateType.MetadataDownload; + } + } + + return false; + } + + /// + /// Saves the specified item. + /// + /// The item. + /// The cancellation token. + /// Task. + public void Save(IHasMetadata item, CancellationToken cancellationToken) + { + var builder = new StringBuilder(); + + builder.Append(""); + + XmlSaverHelpers.AddCommonNodes((Folder)item, builder); + + builder.Append(""); + + var xmlFilePath = GetSavePath(item); + + XmlSaverHelpers.Save(builder, xmlFilePath, new List { }); + } + + /// + /// Gets the save path. + /// + /// The item. + /// System.String. + public string GetSavePath(IHasMetadata item) + { + return Path.Combine(item.Path, "folder.xml"); + } + } +} diff --git a/MediaBrowser.LocalMetadata/Savers/GameSystemXmlSaver.cs b/MediaBrowser.LocalMetadata/Savers/GameSystemXmlSaver.cs new file mode 100644 index 0000000000..163c79ce23 --- /dev/null +++ b/MediaBrowser.LocalMetadata/Savers/GameSystemXmlSaver.cs @@ -0,0 +1,75 @@ +using System.Collections.Generic; +using System.IO; +using System.Security; +using System.Text; +using System.Threading; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Library; + +namespace MediaBrowser.LocalMetadata.Savers +{ + public class GameSystemXmlSaver : IMetadataFileSaver + { + public string Name + { + get + { + return "Media Browser Xml"; + } + } + + /// + /// Determines whether [is enabled for] [the specified item]. + /// + /// The item. + /// Type of the update. + /// true if [is enabled for] [the specified item]; otherwise, false. + public bool IsEnabledFor(IHasMetadata item, ItemUpdateType updateType) + { + if (!item.SupportsLocalMetadata) + { + return false; + } + + return item is GameSystem && updateType >= ItemUpdateType.MetadataDownload; + } + + /// + /// Saves the specified item. + /// + /// The item. + /// The cancellation token. + /// Task. + public void Save(IHasMetadata item, CancellationToken cancellationToken) + { + var gameSystem = (GameSystem)item; + + var builder = new StringBuilder(); + + builder.Append(""); + + if (!string.IsNullOrEmpty(gameSystem.GameSystemName)) + { + builder.Append("" + SecurityElement.Escape(gameSystem.GameSystemName) + ""); + } + + XmlSaverHelpers.AddCommonNodes(gameSystem, builder); + + builder.Append(""); + + var xmlFilePath = GetSavePath(item); + + XmlSaverHelpers.Save(builder, xmlFilePath, new List { }); + } + + /// + /// Gets the save path. + /// + /// The item. + /// System.String. + public string GetSavePath(IHasMetadata item) + { + return Path.Combine(item.Path, "gamesystem.xml"); + } + } +} diff --git a/MediaBrowser.LocalMetadata/Savers/GameXmlSaver.cs b/MediaBrowser.LocalMetadata/Savers/GameXmlSaver.cs new file mode 100644 index 0000000000..7eeaa211fa --- /dev/null +++ b/MediaBrowser.LocalMetadata/Savers/GameXmlSaver.cs @@ -0,0 +1,112 @@ +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Security; +using System.Text; +using System.Threading; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Library; +using MediaBrowser.Model.Entities; + +namespace MediaBrowser.LocalMetadata.Savers +{ + /// + /// Saves game.xml for games + /// + public class GameXmlSaver : IMetadataFileSaver + { + public string Name + { + get + { + return "Media Browser Xml"; + } + } + + /// + /// Determines whether [is enabled for] [the specified item]. + /// + /// The item. + /// Type of the update. + /// true if [is enabled for] [the specified item]; otherwise, false. + public bool IsEnabledFor(IHasMetadata item, ItemUpdateType updateType) + { + if (!item.SupportsLocalMetadata) + { + return false; + } + + return item is Game && updateType >= ItemUpdateType.MetadataDownload; + } + + private static readonly CultureInfo UsCulture = new CultureInfo("en-US"); + + /// + /// Saves the specified item. + /// + /// The item. + /// The cancellation token. + /// Task. + public void Save(IHasMetadata item, CancellationToken cancellationToken) + { + var builder = new StringBuilder(); + + builder.Append(""); + + var game = (Game)item; + + if (game.PlayersSupported.HasValue) + { + builder.Append("" + SecurityElement.Escape(game.PlayersSupported.Value.ToString(UsCulture)) + ""); + } + + if (!string.IsNullOrEmpty(game.GameSystem)) + { + builder.Append("" + SecurityElement.Escape(game.GameSystem) + ""); + } + + var val = game.GetProviderId(MetadataProviders.NesBox); + + if (!string.IsNullOrEmpty(val)) + { + builder.Append("" + SecurityElement.Escape(val) + ""); + } + + val = game.GetProviderId(MetadataProviders.NesBoxRom); + + if (!string.IsNullOrEmpty(val)) + { + builder.Append("" + SecurityElement.Escape(val) + ""); + } + + XmlSaverHelpers.AddCommonNodes(game, builder); + + builder.Append(""); + + var xmlFilePath = GetSavePath(item); + + XmlSaverHelpers.Save(builder, xmlFilePath, new List + { + "Players", + "GameSystem", + "NesBox", + "NesBoxRom" + }); + } + + public string GetSavePath(IHasMetadata item) + { + return GetGameSavePath((Game)item); + } + + public static string GetGameSavePath(Game item) + { + if (item.IsInMixedFolder) + { + return Path.ChangeExtension(item.Path, ".xml"); + } + + return Path.Combine(item.ContainingFolderPath, "game.xml"); + } + } +} diff --git a/MediaBrowser.LocalMetadata/Savers/MovieXmlSaver.cs b/MediaBrowser.LocalMetadata/Savers/MovieXmlSaver.cs new file mode 100644 index 0000000000..ef81790a62 --- /dev/null +++ b/MediaBrowser.LocalMetadata/Savers/MovieXmlSaver.cs @@ -0,0 +1,133 @@ +using System.Collections.Generic; +using System.IO; +using System.Security; +using System.Text; +using System.Threading; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities.Movies; +using MediaBrowser.Controller.Entities.TV; +using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Persistence; + +namespace MediaBrowser.LocalMetadata.Savers +{ + /// + /// Saves movie.xml for movies, trailers and music videos + /// + public class MovieXmlSaver : IMetadataFileSaver + { + private readonly IItemRepository _itemRepository; + + public MovieXmlSaver(IItemRepository itemRepository) + { + _itemRepository = itemRepository; + } + + public string Name + { + get + { + return "Media Browser Xml"; + } + } + + /// + /// Determines whether [is enabled for] [the specified item]. + /// + /// The item. + /// Type of the update. + /// true if [is enabled for] [the specified item]; otherwise, false. + public bool IsEnabledFor(IHasMetadata item, ItemUpdateType updateType) + { + if (!item.SupportsLocalMetadata) + { + return false; + } + + var video = item as Video; + + // Check parent for null to avoid running this against things like video backdrops + if (video != null && !(item is Episode) && !video.IsOwnedItem) + { + return updateType >= ItemUpdateType.MetadataDownload; + } + + return false; + } + + /// + /// Saves the specified item. + /// + /// The item. + /// The cancellation token. + /// Task. + public void Save(IHasMetadata item, CancellationToken cancellationToken) + { + var video = (Video)item; + + var builder = new StringBuilder(); + + builder.Append(""); + + XmlSaverHelpers.AddCommonNodes(video, builder); + + var musicVideo = item as MusicVideo; + + if (musicVideo != null) + { + if (!string.IsNullOrEmpty(musicVideo.Artist)) + { + builder.Append("<Artist>" + SecurityElement.Escape(musicVideo.Artist) + "</Artist>"); + } + if (!string.IsNullOrEmpty(musicVideo.Album)) + { + builder.Append("<Album>" + SecurityElement.Escape(musicVideo.Album) + "</Album>"); + } + } + + var movie = item as Movie; + + if (movie != null) + { + if (!string.IsNullOrEmpty(movie.TmdbCollectionName)) + { + builder.Append("<TmdbCollectionName>" + SecurityElement.Escape(movie.TmdbCollectionName) + "</TmdbCollectionName>"); + } + } + + XmlSaverHelpers.AddMediaInfo(video, builder, _itemRepository); + + builder.Append(""); + + var xmlFilePath = GetSavePath(item); + + XmlSaverHelpers.Save(builder, xmlFilePath, new List + { + // Deprecated. No longer saving in this field. + "IMDBrating", + + // Deprecated. No longer saving in this field. + "Description", + + "Artist", + "Album", + "TmdbCollectionName" + }); + } + + public string GetSavePath(IHasMetadata item) + { + return GetMovieSavePath((Video)item); + } + + public static string GetMovieSavePath(Video item) + { + if (item.IsInMixedFolder) + { + return Path.ChangeExtension(item.Path, ".xml"); + } + + return Path.Combine(item.ContainingFolderPath, "movie.xml"); + } + } +} diff --git a/MediaBrowser.LocalMetadata/Savers/PersonXmlSaver.cs b/MediaBrowser.LocalMetadata/Savers/PersonXmlSaver.cs new file mode 100644 index 0000000000..2ea60f47c2 --- /dev/null +++ b/MediaBrowser.LocalMetadata/Savers/PersonXmlSaver.cs @@ -0,0 +1,81 @@ +using System.Collections.Generic; +using System.IO; +using System.Security; +using System.Text; +using System.Threading; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Library; + +namespace MediaBrowser.LocalMetadata.Savers +{ + /// + /// Class PersonXmlSaver + /// + public class PersonXmlSaver : IMetadataFileSaver + { + public string Name + { + get + { + return "Media Browser Xml"; + } + } + + /// + /// Determines whether [is enabled for] [the specified item]. + /// + /// The item. + /// Type of the update. + /// true if [is enabled for] [the specified item]; otherwise, false. + public bool IsEnabledFor(IHasMetadata item, ItemUpdateType updateType) + { + if (!item.SupportsLocalMetadata) + { + return false; + } + + return item is Person && updateType >= ItemUpdateType.MetadataDownload; + } + + /// + /// Saves the specified item. + /// + /// The item. + /// The cancellation token. + /// Task. + public void Save(IHasMetadata item, CancellationToken cancellationToken) + { + var person = (Person)item; + + var builder = new StringBuilder(); + + builder.Append(""); + + XmlSaverHelpers.AddCommonNodes(person, builder); + + if (!string.IsNullOrEmpty(person.PlaceOfBirth)) + { + builder.Append("" + SecurityElement.Escape(person.PlaceOfBirth) + ""); + } + + builder.Append(""); + + var xmlFilePath = GetSavePath(item); + + XmlSaverHelpers.Save(builder, xmlFilePath, new List + { + "PlaceOfBirth" + }); + } + + /// + /// Gets the save path. + /// + /// The item. + /// System.String. + public string GetSavePath(IHasMetadata item) + { + return Path.Combine(item.Path, "person.xml"); + } + } +} diff --git a/MediaBrowser.LocalMetadata/Savers/SeasonXmlSaver.cs b/MediaBrowser.LocalMetadata/Savers/SeasonXmlSaver.cs new file mode 100644 index 0000000000..b9908875dc --- /dev/null +++ b/MediaBrowser.LocalMetadata/Savers/SeasonXmlSaver.cs @@ -0,0 +1,87 @@ +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Security; +using System.Text; +using System.Threading; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities.TV; +using MediaBrowser.Controller.Library; + +namespace MediaBrowser.LocalMetadata.Savers +{ + public class SeasonXmlSaver : IMetadataFileSaver + { + public string Name + { + get + { + return "Media Browser Xml"; + } + } + + /// + /// Determines whether [is enabled for] [the specified item]. + /// + /// The item. + /// Type of the update. + /// true if [is enabled for] [the specified item]; otherwise, false. + public bool IsEnabledFor(IHasMetadata item, ItemUpdateType updateType) + { + if (!item.SupportsLocalMetadata) + { + return false; + } + + if (!(item is Season)) + { + return false; + } + + return updateType >= ItemUpdateType.MetadataDownload || (updateType >= ItemUpdateType.MetadataImport && File.Exists(GetSavePath(item))); + } + + private readonly CultureInfo _usCulture = new CultureInfo("en-US"); + + /// + /// Saves the specified item. + /// + /// The item. + /// The cancellation token. + /// Task. + public void Save(IHasMetadata item, CancellationToken cancellationToken) + { + var builder = new StringBuilder(); + + builder.Append(""); + + var season = (Season)item; + + if (season.IndexNumber.HasValue) + { + builder.Append("" + SecurityElement.Escape(season.IndexNumber.Value.ToString(_usCulture)) + ""); + } + + XmlSaverHelpers.AddCommonNodes((Season)item, builder); + + builder.Append(""); + + var xmlFilePath = GetSavePath(item); + + XmlSaverHelpers.Save(builder, xmlFilePath, new List + { + "SeasonNumber" + }); + } + + /// + /// Gets the save path. + /// + /// The item. + /// System.String. + public string GetSavePath(IHasMetadata item) + { + return Path.Combine(item.Path, "season.xml"); + } + } +} diff --git a/MediaBrowser.LocalMetadata/Savers/SeriesXmlSaver.cs b/MediaBrowser.LocalMetadata/Savers/SeriesXmlSaver.cs new file mode 100644 index 0000000000..23ea528204 --- /dev/null +++ b/MediaBrowser.LocalMetadata/Savers/SeriesXmlSaver.cs @@ -0,0 +1,135 @@ +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Security; +using System.Text; +using System.Threading; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities.TV; +using MediaBrowser.Controller.Library; +using MediaBrowser.Model.Entities; + +namespace MediaBrowser.LocalMetadata.Savers +{ + public class SeriesXmlSaver : IMetadataFileSaver + { + public string Name + { + get + { + return "Media Browser Xml"; + } + } + + /// + /// Determines whether [is enabled for] [the specified item]. + /// + /// The item. + /// Type of the update. + /// true if [is enabled for] [the specified item]; otherwise, false. + public bool IsEnabledFor(IHasMetadata item, ItemUpdateType updateType) + { + if (!item.SupportsLocalMetadata) + { + return false; + } + + return item is Series && updateType >= ItemUpdateType.MetadataDownload; + } + + private static readonly CultureInfo UsCulture = new CultureInfo("en-US"); + + /// + /// Saves the specified item. + /// + /// The item. + /// The cancellation token. + /// Task. + public void Save(IHasMetadata item, CancellationToken cancellationToken) + { + var series = (Series)item; + + var builder = new StringBuilder(); + + builder.Append(""); + + var tvdb = item.GetProviderId(MetadataProviders.Tvdb); + + if (!string.IsNullOrEmpty(tvdb)) + { + builder.Append("" + SecurityElement.Escape(tvdb) + ""); + } + + if (series.Status.HasValue) + { + builder.Append("" + SecurityElement.Escape(series.Status.Value.ToString()) + ""); + } + + if (series.Studios.Count > 0) + { + builder.Append("" + SecurityElement.Escape(series.Studios[0]) + ""); + } + + if (!string.IsNullOrEmpty(series.AirTime)) + { + builder.Append("" + SecurityElement.Escape(series.AirTime) + ""); + } + + if (series.AirDays != null) + { + if (series.AirDays.Count == 7) + { + builder.Append("" + SecurityElement.Escape("Daily") + ""); + } + else if (series.AirDays.Count > 0) + { + builder.Append("" + SecurityElement.Escape(series.AirDays[0].ToString()) + ""); + } + } + + if (series.PremiereDate.HasValue) + { + builder.Append("" + SecurityElement.Escape(series.PremiereDate.Value.ToLocalTime().ToString("yyyy-MM-dd")) + ""); + } + + if (series.AnimeSeriesIndex.HasValue) + { + builder.Append("" + SecurityElement.Escape(series.AnimeSeriesIndex.Value.ToString(UsCulture)) + ""); + } + + XmlSaverHelpers.AddCommonNodes(series, builder); + + builder.Append(""); + + var xmlFilePath = GetSavePath(item); + + XmlSaverHelpers.Save(builder, xmlFilePath, new List + { + "id", + "Status", + "Network", + "Airs_Time", + "Airs_DayOfWeek", + "FirstAired", + + // Don't preserve old series node + "Series", + + "SeriesName", + + // Deprecated. No longer saving in this field. + "AnimeSeriesIndex" + }); + } + + /// + /// Gets the save path. + /// + /// The item. + /// System.String. + public string GetSavePath(IHasMetadata item) + { + return Path.Combine(item.Path, "series.xml"); + } + } +} diff --git a/MediaBrowser.LocalMetadata/Savers/XmlSaverHelpers.cs b/MediaBrowser.LocalMetadata/Savers/XmlSaverHelpers.cs new file mode 100644 index 0000000000..c43875b042 --- /dev/null +++ b/MediaBrowser.LocalMetadata/Savers/XmlSaverHelpers.cs @@ -0,0 +1,718 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Security; +using System.Text; +using System.Xml; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities.Movies; +using MediaBrowser.Controller.Entities.TV; +using MediaBrowser.Controller.Persistence; +using MediaBrowser.Model.Entities; + +namespace MediaBrowser.LocalMetadata.Savers +{ + /// + /// Class XmlHelpers + /// + public static class XmlSaverHelpers + { + private static readonly Dictionary CommonTags = new[] { + + "Added", + "AspectRatio", + "AudioDbAlbumId", + "AudioDbArtistId", + "AwardSummary", + "BirthDate", + "Budget", + + // Deprecated. No longer saving in this field. + "certification", + + "Chapters", + "ContentRating", + "Countries", + "CustomRating", + "CriticRating", + "CriticRatingSummary", + "DeathDate", + "DisplayOrder", + "EndDate", + "Genres", + "Genre", + "GamesDbId", + + // Deprecated. No longer saving in this field. + "IMDB_ID", + + "IMDB", + + // Deprecated. No longer saving in this field. + "IMDbId", + + "Language", + "LocalTitle", + "LockData", + "LockedFields", + "Format3D", + "Metascore", + + // Deprecated. No longer saving in this field. + "MPAARating", + + "MusicBrainzArtistId", + "MusicBrainzAlbumArtistId", + "MusicBrainzAlbumId", + "MusicBrainzReleaseGroupId", + + // Deprecated. No longer saving in this field. + "MusicbrainzId", + + "Overview", + "ShortOverview", + "Persons", + "PlotKeywords", + "PremiereDate", + "ProductionYear", + "Rating", + "Revenue", + "RottenTomatoesId", + "RunningTime", + + // Deprecated. No longer saving in this field. + "Runtime", + + "SortTitle", + "Studios", + "Tags", + + // Deprecated. No longer saving in this field. + "TagLine", + + "Taglines", + "TMDbCollectionId", + "TMDbId", + + // Deprecated. No longer saving in this field. + "Trailer", + + "Trailers", + "TVcomId", + "TvDbId", + "Type", + "TVRageId", + "VoteCount", + "Website", + "Zap2ItId", + "CollectionItems" + + }.ToDictionary(i => i, StringComparer.OrdinalIgnoreCase); + + /// + /// The us culture + /// + private static readonly CultureInfo UsCulture = new CultureInfo("en-US"); + + /// + /// Saves the specified XML. + /// + /// The XML. + /// The path. + /// The XML tags used. + public static void Save(StringBuilder xml, string path, List xmlTagsUsed) + { + if (File.Exists(path)) + { + var position = xml.ToString().LastIndexOf(" + /// Gets the custom tags. + /// + /// The path. + /// The XML tags used. + /// System.String. + private static string GetCustomTags(string path, List xmlTagsUsed) + { + var settings = new XmlReaderSettings + { + CheckCharacters = false, + IgnoreProcessingInstructions = true, + IgnoreComments = true, + ValidationType = ValidationType.None + }; + + var builder = new StringBuilder(); + + using (var streamReader = new StreamReader(path, Encoding.UTF8)) + { + // Use XmlReader for best performance + using (var reader = XmlReader.Create(streamReader, settings)) + { + reader.MoveToContent(); + + // Loop through each element + while (reader.Read()) + { + if (reader.NodeType == XmlNodeType.Element) + { + var name = reader.Name; + + if (!CommonTags.ContainsKey(name) && !xmlTagsUsed.Contains(name, StringComparer.OrdinalIgnoreCase)) + { + builder.AppendLine(reader.ReadOuterXml()); + } + else + { + reader.Skip(); + } + } + } + } + } + + return builder.ToString(); + } + + /// + /// Adds the common nodes. + /// + /// The item. + /// The builder. + public static void AddCommonNodes(BaseItem item, StringBuilder builder) + { + if (!string.IsNullOrEmpty(item.OfficialRating)) + { + builder.Append("" + SecurityElement.Escape(item.OfficialRating) + ""); + } + + builder.Append("" + SecurityElement.Escape(item.DateCreated.ToLocalTime().ToString("G")) + ""); + + builder.Append("" + item.IsLocked.ToString().ToLower() + ""); + + if (item.LockedFields.Count > 0) + { + builder.Append("" + string.Join("|", item.LockedFields.Select(i => i.ToString()).ToArray()) + ""); + } + + if (!string.IsNullOrEmpty(item.DisplayMediaType)) + { + builder.Append("" + SecurityElement.Escape(item.DisplayMediaType) + ""); + } + + var hasCriticRating = item as IHasCriticRating; + if (hasCriticRating != null) + { + if (hasCriticRating.CriticRating.HasValue) + { + builder.Append("" + SecurityElement.Escape(hasCriticRating.CriticRating.Value.ToString(UsCulture)) + ""); + } + + if (!string.IsNullOrEmpty(hasCriticRating.CriticRatingSummary)) + { + builder.Append(""); + } + } + + if (!string.IsNullOrEmpty(item.Overview)) + { + builder.Append(""); + } + + var hasShortOverview = item as IHasShortOverview; + if (hasShortOverview != null) + { + if (!string.IsNullOrEmpty(hasShortOverview.ShortOverview)) + { + builder.Append(""); + } + } + + if (!string.IsNullOrEmpty(item.CustomRating)) + { + builder.Append("" + SecurityElement.Escape(item.CustomRating) + ""); + } + + if (!string.IsNullOrEmpty(item.Name) && !(item is Episode)) + { + builder.Append("" + SecurityElement.Escape(item.Name) + ""); + } + + if (!string.IsNullOrEmpty(item.ForcedSortName)) + { + builder.Append("" + SecurityElement.Escape(item.ForcedSortName) + ""); + } + + if (item.PremiereDate.HasValue) + { + if (item is Person) + { + builder.Append("" + SecurityElement.Escape(item.PremiereDate.Value.ToLocalTime().ToString("yyyy-MM-dd")) + ""); + } + else if (!(item is Episode)) + { + builder.Append("" + SecurityElement.Escape(item.PremiereDate.Value.ToLocalTime().ToString("yyyy-MM-dd")) + ""); + } + } + + if (item.EndDate.HasValue) + { + if (item is Person) + { + builder.Append("" + SecurityElement.Escape(item.EndDate.Value.ToString("yyyy-MM-dd")) + ""); + } + else if (!(item is Episode)) + { + builder.Append("" + SecurityElement.Escape(item.EndDate.Value.ToString("yyyy-MM-dd")) + ""); + } + } + + var hasTrailers = item as IHasTrailers; + if (hasTrailers != null) + { + if (hasTrailers.RemoteTrailers.Count > 0) + { + builder.Append(""); + + foreach (var trailer in hasTrailers.RemoteTrailers) + { + builder.Append("" + SecurityElement.Escape(trailer.Url) + ""); + } + + builder.Append(""); + } + } + + var hasProductionLocations = item as IHasProductionLocations; + if (hasProductionLocations != null) + { + if (hasProductionLocations.ProductionLocations.Count > 0) + { + builder.Append(""); + + foreach (var name in hasProductionLocations.ProductionLocations) + { + builder.Append("" + SecurityElement.Escape(name) + ""); + } + + builder.Append(""); + } + } + + var hasDisplayOrder = item as IHasDisplayOrder; + if (hasDisplayOrder != null && !string.IsNullOrEmpty(hasDisplayOrder.DisplayOrder)) + { + builder.Append("" + SecurityElement.Escape(hasDisplayOrder.DisplayOrder) + ""); + } + + var hasMetascore = item as IHasMetascore; + if (hasMetascore != null && hasMetascore.Metascore.HasValue) + { + builder.Append("" + SecurityElement.Escape(hasMetascore.Metascore.Value.ToString(UsCulture)) + ""); + } + + var hasAwards = item as IHasAwards; + if (hasAwards != null && !string.IsNullOrEmpty(hasAwards.AwardSummary)) + { + builder.Append("" + SecurityElement.Escape(hasAwards.AwardSummary) + ""); + } + + var hasBudget = item as IHasBudget; + if (hasBudget != null) + { + if (hasBudget.Budget.HasValue) + { + builder.Append("" + SecurityElement.Escape(hasBudget.Budget.Value.ToString(UsCulture)) + ""); + } + + if (hasBudget.Revenue.HasValue) + { + builder.Append("" + SecurityElement.Escape(hasBudget.Revenue.Value.ToString(UsCulture)) + ""); + } + } + + if (item.CommunityRating.HasValue) + { + builder.Append("" + SecurityElement.Escape(item.CommunityRating.Value.ToString(UsCulture)) + ""); + } + if (item.VoteCount.HasValue) + { + builder.Append("" + SecurityElement.Escape(item.VoteCount.Value.ToString(UsCulture)) + ""); + } + + if (item.ProductionYear.HasValue && !(item is Person)) + { + builder.Append("" + SecurityElement.Escape(item.ProductionYear.Value.ToString(UsCulture)) + ""); + } + + if (!string.IsNullOrEmpty(item.HomePageUrl)) + { + builder.Append("" + SecurityElement.Escape(item.HomePageUrl) + ""); + } + + var hasAspectRatio = item as IHasAspectRatio; + if (hasAspectRatio != null) + { + if (!string.IsNullOrEmpty(hasAspectRatio.AspectRatio)) + { + builder.Append("" + SecurityElement.Escape(hasAspectRatio.AspectRatio) + ""); + } + } + + var hasLanguage = item as IHasPreferredMetadataLanguage; + if (hasLanguage != null) + { + if (!string.IsNullOrEmpty(hasLanguage.PreferredMetadataLanguage)) + { + builder.Append("" + SecurityElement.Escape(hasLanguage.PreferredMetadataLanguage) + ""); + } + } + + // Use original runtime here, actual file runtime later in MediaInfo + var runTimeTicks = item.RunTimeTicks; + + if (runTimeTicks.HasValue) + { + var timespan = TimeSpan.FromTicks(runTimeTicks.Value); + + builder.Append("" + Convert.ToInt32(timespan.TotalMinutes).ToString(UsCulture) + ""); + } + + var imdb = item.GetProviderId(MetadataProviders.Imdb); + + if (!string.IsNullOrEmpty(imdb)) + { + builder.Append("" + SecurityElement.Escape(imdb) + ""); + } + + var tmdb = item.GetProviderId(MetadataProviders.Tmdb); + + if (!string.IsNullOrEmpty(tmdb)) + { + builder.Append("" + SecurityElement.Escape(tmdb) + ""); + } + + if (!(item is Series)) + { + var tvdb = item.GetProviderId(MetadataProviders.Tvdb); + + if (!string.IsNullOrEmpty(tvdb)) + { + builder.Append("" + SecurityElement.Escape(tvdb) + ""); + } + } + + var externalId = item.GetProviderId(MetadataProviders.Tvcom); + + if (!string.IsNullOrEmpty(externalId)) + { + builder.Append("" + SecurityElement.Escape(externalId) + ""); + } + + externalId = item.GetProviderId(MetadataProviders.RottenTomatoes); + + if (!string.IsNullOrEmpty(externalId)) + { + builder.Append("" + SecurityElement.Escape(externalId) + ""); + } + + externalId = item.GetProviderId(MetadataProviders.Zap2It); + + if (!string.IsNullOrEmpty(externalId)) + { + builder.Append("" + SecurityElement.Escape(externalId) + ""); + } + + externalId = item.GetProviderId(MetadataProviders.MusicBrainzAlbum); + + if (!string.IsNullOrEmpty(externalId)) + { + builder.Append("" + SecurityElement.Escape(externalId) + ""); + } + + externalId = item.GetProviderId(MetadataProviders.MusicBrainzAlbumArtist); + + if (!string.IsNullOrEmpty(externalId)) + { + builder.Append("" + SecurityElement.Escape(externalId) + ""); + } + + externalId = item.GetProviderId(MetadataProviders.MusicBrainzArtist); + + if (!string.IsNullOrEmpty(externalId)) + { + builder.Append("" + SecurityElement.Escape(externalId) + ""); + } + + externalId = item.GetProviderId(MetadataProviders.MusicBrainzReleaseGroup); + + if (!string.IsNullOrEmpty(externalId)) + { + builder.Append("" + SecurityElement.Escape(externalId) + ""); + } + + externalId = item.GetProviderId(MetadataProviders.Gamesdb); + + if (!string.IsNullOrEmpty(externalId)) + { + builder.Append("" + SecurityElement.Escape(externalId) + ""); + } + + externalId = item.GetProviderId(MetadataProviders.TmdbCollection); + + if (!string.IsNullOrEmpty(externalId)) + { + builder.Append("" + SecurityElement.Escape(externalId) + ""); + } + + externalId = item.GetProviderId(MetadataProviders.AudioDbArtist); + + if (!string.IsNullOrEmpty(externalId)) + { + builder.Append("" + SecurityElement.Escape(externalId) + ""); + } + + externalId = item.GetProviderId(MetadataProviders.AudioDbAlbum); + + if (!string.IsNullOrEmpty(externalId)) + { + builder.Append("" + SecurityElement.Escape(externalId) + ""); + } + + externalId = item.GetProviderId(MetadataProviders.TvRage); + + if (!string.IsNullOrEmpty(externalId)) + { + builder.Append("" + SecurityElement.Escape(externalId) + ""); + } + + var hasTagline = item as IHasTaglines; + if (hasTagline != null) + { + if (hasTagline.Taglines.Count > 0) + { + builder.Append(""); + + foreach (var tagline in hasTagline.Taglines) + { + builder.Append("" + SecurityElement.Escape(tagline) + ""); + } + + builder.Append(""); + } + } + + if (item.Genres.Count > 0) + { + builder.Append(""); + + foreach (var genre in item.Genres) + { + builder.Append("" + SecurityElement.Escape(genre) + ""); + } + + builder.Append(""); + } + + if (item.Studios.Count > 0) + { + builder.Append(""); + + foreach (var studio in item.Studios) + { + builder.Append("" + SecurityElement.Escape(studio) + ""); + } + + builder.Append(""); + } + + var hasTags = item as IHasTags; + if (hasTags != null) + { + if (hasTags.Tags.Count > 0) + { + builder.Append(""); + + foreach (var tag in hasTags.Tags) + { + builder.Append("" + SecurityElement.Escape(tag) + ""); + } + + builder.Append(""); + } + } + + var hasKeywords = item as IHasKeywords; + if (hasKeywords != null) + { + if (hasKeywords.Keywords.Count > 0) + { + builder.Append(""); + + foreach (var tag in hasKeywords.Keywords) + { + builder.Append("" + SecurityElement.Escape(tag) + ""); + } + + builder.Append(""); + } + } + + if (item.People.Count > 0) + { + builder.Append(""); + + foreach (var person in item.People) + { + builder.Append(""); + builder.Append("" + SecurityElement.Escape(person.Name) + ""); + builder.Append("" + SecurityElement.Escape(person.Type) + ""); + builder.Append("" + SecurityElement.Escape(person.Role) + ""); + + if (person.SortOrder.HasValue) + { + builder.Append("" + SecurityElement.Escape(person.SortOrder.Value.ToString(UsCulture)) + ""); + } + + builder.Append(""); + } + + builder.Append(""); + } + + var folder = item as BoxSet; + if (folder != null) + { + AddCollectionItems(folder, builder); + } + } + + public static void AddChapters(Video item, StringBuilder builder, IItemRepository repository) + { + var chapters = repository.GetChapters(item.Id); + + builder.Append(""); + + foreach (var chapter in chapters) + { + builder.Append(""); + builder.Append("" + SecurityElement.Escape(chapter.Name) + ""); + + var time = TimeSpan.FromTicks(chapter.StartPositionTicks); + var ms = Convert.ToInt64(time.TotalMilliseconds); + + builder.Append("" + SecurityElement.Escape(ms.ToString(UsCulture)) + ""); + builder.Append(""); + } + + builder.Append(""); + } + + /// + /// Appends the media info. + /// + /// + public static void AddMediaInfo(T item, StringBuilder builder, IItemRepository itemRepository) + where T : BaseItem + { + var video = item as Video; + + if (video != null) + { + //AddChapters(video, builder, itemRepository); + + if (video.Video3DFormat.HasValue) + { + switch (video.Video3DFormat.Value) + { + case Video3DFormat.FullSideBySide: + builder.Append("FSBS"); + break; + case Video3DFormat.FullTopAndBottom: + builder.Append("FTAB"); + break; + case Video3DFormat.HalfSideBySide: + builder.Append("HSBS"); + break; + case Video3DFormat.HalfTopAndBottom: + builder.Append("HTAB"); + break; + } + } + } + } + + public static void AddCollectionItems(Folder item, StringBuilder builder) + { + var items = item.LinkedChildren + .Where(i => i.Type == LinkedChildType.Manual && !string.IsNullOrWhiteSpace(i.ItemName)) + .ToList(); + + if (items.Count == 0) + { + return; + } + + builder.Append(""); + foreach (var link in items) + { + builder.Append(""); + + builder.Append("" + SecurityElement.Escape(link.ItemName) + ""); + builder.Append("" + SecurityElement.Escape(link.ItemType) + ""); + + if (link.ItemYear.HasValue) + { + builder.Append("" + SecurityElement.Escape(link.ItemYear.Value.ToString(UsCulture)) + ""); + } + + builder.Append(""); + } + builder.Append(""); + } + } +} -- cgit v1.2.3