diff options
| author | Luke <luke.pulverenti@gmail.com> | 2016-12-18 00:44:33 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2016-12-18 00:44:33 -0500 |
| commit | e7cebb91a73354dc3e0d0b6340c9fbd6511f4406 (patch) | |
| tree | 6f1c368c766c17b7514fe749c0e92e69cd89194a /MediaBrowser.LocalMetadata | |
| parent | 025905a3e4d50b9a2e07fbf4ff0a203af6604ced (diff) | |
| parent | aaa027f3229073e9a40756c3157d41af2a442922 (diff) | |
Merge pull request #2350 from MediaBrowser/beta
Beta
Diffstat (limited to 'MediaBrowser.LocalMetadata')
38 files changed, 2631 insertions, 1180 deletions
diff --git a/MediaBrowser.LocalMetadata/BaseXmlProvider.cs b/MediaBrowser.LocalMetadata/BaseXmlProvider.cs index f23559e4b..50e9de727 100644 --- a/MediaBrowser.LocalMetadata/BaseXmlProvider.cs +++ b/MediaBrowser.LocalMetadata/BaseXmlProvider.cs @@ -3,7 +3,9 @@ using MediaBrowser.Controller.Providers; using System.IO; using System.Threading; using System.Threading.Tasks; -using CommonIO; +using MediaBrowser.Common.IO; +using MediaBrowser.Controller.IO; +using MediaBrowser.Model.IO; namespace MediaBrowser.LocalMetadata { @@ -38,7 +40,7 @@ namespace MediaBrowser.LocalMetadata { result.HasMetadata = false; } - catch (DirectoryNotFoundException) + catch (IOException) { result.HasMetadata = false; } @@ -94,7 +96,5 @@ namespace MediaBrowser.LocalMetadata return "Emby Xml"; } } - - internal static readonly SemaphoreSlim XmlParsingResourcePool = new SemaphoreSlim(4, 4); } } diff --git a/MediaBrowser.LocalMetadata/Images/CollectionFolderImageProvider.cs b/MediaBrowser.LocalMetadata/Images/CollectionFolderImageProvider.cs index 21b3cedae..651273eb0 100644 --- a/MediaBrowser.LocalMetadata/Images/CollectionFolderImageProvider.cs +++ b/MediaBrowser.LocalMetadata/Images/CollectionFolderImageProvider.cs @@ -1,7 +1,9 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Providers; using System.Collections.Generic; -using CommonIO; +using MediaBrowser.Common.IO; +using MediaBrowser.Controller.IO; +using MediaBrowser.Model.IO; namespace MediaBrowser.LocalMetadata.Images { diff --git a/MediaBrowser.LocalMetadata/Images/EpisodeLocalImageProvider.cs b/MediaBrowser.LocalMetadata/Images/EpisodeLocalImageProvider.cs index 716d40d8f..e02326838 100644 --- a/MediaBrowser.LocalMetadata/Images/EpisodeLocalImageProvider.cs +++ b/MediaBrowser.LocalMetadata/Images/EpisodeLocalImageProvider.cs @@ -6,7 +6,9 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; -using CommonIO; +using MediaBrowser.Common.IO; +using MediaBrowser.Controller.IO; +using MediaBrowser.Model.IO; namespace MediaBrowser.LocalMetadata.Images { diff --git a/MediaBrowser.LocalMetadata/Images/ImagesByNameImageProvider.cs b/MediaBrowser.LocalMetadata/Images/ImagesByNameImageProvider.cs index 6034008de..8a6dde6c4 100644 --- a/MediaBrowser.LocalMetadata/Images/ImagesByNameImageProvider.cs +++ b/MediaBrowser.LocalMetadata/Images/ImagesByNameImageProvider.cs @@ -1,8 +1,10 @@ using System.Collections.Generic; using System.IO; -using CommonIO; +using MediaBrowser.Common.IO; +using MediaBrowser.Model.IO; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.IO; using MediaBrowser.Controller.Providers; namespace MediaBrowser.LocalMetadata.Images @@ -47,7 +49,7 @@ namespace MediaBrowser.LocalMetadata.Images { return new LocalImageProvider(_fileSystem).GetImages(item, path, directoryService); } - catch (DirectoryNotFoundException) + catch (IOException) { return new List<LocalImageInfo>(); } diff --git a/MediaBrowser.LocalMetadata/Images/InternalMetadataFolderImageProvider.cs b/MediaBrowser.LocalMetadata/Images/InternalMetadataFolderImageProvider.cs index 1cec4d305..b29182d96 100644 --- a/MediaBrowser.LocalMetadata/Images/InternalMetadataFolderImageProvider.cs +++ b/MediaBrowser.LocalMetadata/Images/InternalMetadataFolderImageProvider.cs @@ -4,7 +4,9 @@ using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Providers; using System.Collections.Generic; using System.IO; -using CommonIO; +using MediaBrowser.Common.IO; +using MediaBrowser.Controller.IO; +using MediaBrowser.Model.IO; namespace MediaBrowser.LocalMetadata.Images { @@ -67,7 +69,7 @@ namespace MediaBrowser.LocalMetadata.Images { return new LocalImageProvider(_fileSystem).GetImages(item, path, directoryService); } - catch (DirectoryNotFoundException) + catch (IOException) { return new List<LocalImageInfo>(); } diff --git a/MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs b/MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs index ef9160b70..2f7059fec 100644 --- a/MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs +++ b/MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs @@ -7,7 +7,9 @@ using System; using System.Collections.Generic; using System.Globalization; using System.Linq; -using CommonIO; +using MediaBrowser.Common.IO; +using MediaBrowser.Controller.IO; +using MediaBrowser.Model.IO; namespace MediaBrowser.LocalMetadata.Images { diff --git a/MediaBrowser.LocalMetadata/MediaBrowser.LocalMetadata.csproj b/MediaBrowser.LocalMetadata/MediaBrowser.LocalMetadata.csproj index ac127458e..f7b7fa5f2 100644 --- a/MediaBrowser.LocalMetadata/MediaBrowser.LocalMetadata.csproj +++ b/MediaBrowser.LocalMetadata/MediaBrowser.LocalMetadata.csproj @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8"?> -<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> +<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" /> <PropertyGroup> <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> @@ -9,9 +9,11 @@ <AppDesignerFolder>Properties</AppDesignerFolder> <RootNamespace>MediaBrowser.LocalMetadata</RootNamespace> <AssemblyName>MediaBrowser.LocalMetadata</AssemblyName> - <TargetFrameworkVersion>v4.5</TargetFrameworkVersion> <FileAlignment>512</FileAlignment> <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir> + <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> + <TargetFrameworkProfile>Profile7</TargetFrameworkProfile> + <TargetFrameworkVersion>v4.5</TargetFrameworkVersion> </PropertyGroup> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> <DebugSymbols>true</DebugSymbols> @@ -31,22 +33,6 @@ <WarningLevel>4</WarningLevel> </PropertyGroup> <ItemGroup> - <Reference Include="CommonIO, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL"> - <SpecificVersion>False</SpecificVersion> - <HintPath>..\packages\CommonIO.1.0.0.9\lib\net45\CommonIO.dll</HintPath> - </Reference> - <Reference Include="Patterns.Logging"> - <HintPath>..\packages\Patterns.Logging.1.0.0.2\lib\portable-net45+sl4+wp71+win8+wpa81\Patterns.Logging.dll</HintPath> - </Reference> - <Reference Include="System" /> - <Reference Include="System.Core" /> - <Reference Include="System.Xml.Linq" /> - <Reference Include="System.Data.DataSetExtensions" /> - <Reference Include="Microsoft.CSharp" /> - <Reference Include="System.Data" /> - <Reference Include="System.Xml" /> - </ItemGroup> - <ItemGroup> <Compile Include="..\SharedVersion.cs"> <Link>Properties\SharedVersion.cs</Link> </Compile> @@ -56,6 +42,7 @@ <Compile Include="Images\ImagesByNameImageProvider.cs" /> <Compile Include="Images\InternalMetadataFolderImageProvider.cs" /> <Compile Include="Images\LocalImageProvider.cs" /> + <Compile Include="Parsers\BaseItemXmlParser.cs" /> <Compile Include="Parsers\BoxSetXmlParser.cs" /> <Compile Include="Parsers\EpisodeXmlParser.cs" /> <Compile Include="Parsers\GameSystemXmlParser.cs" /> @@ -72,17 +59,16 @@ <Compile Include="Providers\GameXmlProvider.cs" /> <Compile Include="Providers\MovieXmlProvider.cs" /> <Compile Include="Providers\MusicVideoXmlProvider.cs" /> - <Compile Include="Providers\PersonXmlProvider.cs" /> <Compile Include="Providers\PlaylistXmlProvider.cs" /> <Compile Include="Providers\SeriesXmlProvider.cs" /> <Compile Include="Providers\VideoXmlProvider.cs" /> + <Compile Include="Savers\BaseXmlSaver.cs" /> <Compile Include="Savers\BoxSetXmlSaver.cs" /> <Compile Include="Savers\FolderXmlSaver.cs" /> <Compile Include="Savers\GameSystemXmlSaver.cs" /> <Compile Include="Savers\GameXmlSaver.cs" /> <Compile Include="Savers\PersonXmlSaver.cs" /> <Compile Include="Savers\PlaylistXmlSaver.cs" /> - <Compile Include="Savers\XmlSaverHelpers.cs" /> </ItemGroup> <ItemGroup> <ProjectReference Include="..\MediaBrowser.Common\MediaBrowser.Common.csproj"> @@ -98,10 +84,7 @@ <Name>MediaBrowser.Model</Name> </ProjectReference> </ItemGroup> - <ItemGroup> - <None Include="packages.config" /> - </ItemGroup> - <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> + <Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" /> <!-- To modify your build process, add your task inside one of the targets below and uncomment it. Other similar extension points exist, see Microsoft.Common.targets. <Target Name="BeforeBuild"> diff --git a/MediaBrowser.LocalMetadata/MediaBrowser.LocalMetadata.nuget.targets b/MediaBrowser.LocalMetadata/MediaBrowser.LocalMetadata.nuget.targets new file mode 100644 index 000000000..e69ce0e64 --- /dev/null +++ b/MediaBrowser.LocalMetadata/MediaBrowser.LocalMetadata.nuget.targets @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8" standalone="no"?> +<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Target Name="EmitMSBuildWarning" BeforeTargets="Build"> + <Warning Text="Packages containing MSBuild targets and props files cannot be fully installed in projects targeting multiple frameworks. The MSBuild targets and props files have been ignored." /> + </Target> +</Project>
\ No newline at end of file diff --git a/MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs b/MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs new file mode 100644 index 000000000..d66cdf801 --- /dev/null +++ b/MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs @@ -0,0 +1,1473 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading; +using System.Xml; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Providers; +using MediaBrowser.Model.Entities; +using MediaBrowser.Model.IO; +using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Xml; + +namespace MediaBrowser.LocalMetadata.Parsers +{ + /// <summary> + /// Provides a base class for parsing metadata xml + /// </summary> + /// <typeparam name="T"></typeparam> + public class BaseItemXmlParser<T> + where T : BaseItem + { + /// <summary> + /// The logger + /// </summary> + protected ILogger Logger { get; private set; } + protected IProviderManager ProviderManager { get; private set; } + + private Dictionary<string, string> _validProviderIds; + + protected IXmlReaderSettingsFactory XmlReaderSettingsFactory { get; private set; } + protected IFileSystem FileSystem { get; private set; } + + /// <summary> + /// Initializes a new instance of the <see cref="BaseItemXmlParser{T}" /> class. + /// </summary> + /// <param name="logger">The logger.</param> + public BaseItemXmlParser(ILogger logger, IProviderManager providerManager, IXmlReaderSettingsFactory xmlReaderSettingsFactory, IFileSystem fileSystem) + { + Logger = logger; + ProviderManager = providerManager; + XmlReaderSettingsFactory = xmlReaderSettingsFactory; + FileSystem = fileSystem; + } + + /// <summary> + /// Fetches metadata for an item from one xml file + /// </summary> + /// <param name="item">The item.</param> + /// <param name="metadataFile">The metadata file.</param> + /// <param name="cancellationToken">The cancellation token.</param> + /// <exception cref="System.ArgumentNullException"></exception> + public void Fetch(MetadataResult<T> item, string metadataFile, CancellationToken cancellationToken) + { + if (item == null) + { + throw new ArgumentNullException(); + } + + if (string.IsNullOrEmpty(metadataFile)) + { + throw new ArgumentNullException(); + } + + var settings = XmlReaderSettingsFactory.Create(false); + + settings.CheckCharacters = false; + settings.IgnoreProcessingInstructions = true; + settings.IgnoreComments = true; + + _validProviderIds = _validProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); + + var idInfos = ProviderManager.GetExternalIdInfos(item.Item); + + foreach (var info in idInfos) + { + var id = info.Key + "Id"; + if (!_validProviderIds.ContainsKey(id)) + { + _validProviderIds.Add(id, info.Key); + } + } + + //Additional Mappings + _validProviderIds.Add("IMDB", "Imdb"); + + //Fetch(item, metadataFile, settings, Encoding.GetEncoding("ISO-8859-1"), cancellationToken); + Fetch(item, metadataFile, settings, Encoding.UTF8, cancellationToken); + } + + /// <summary> + /// Fetches the specified item. + /// </summary> + /// <param name="item">The item.</param> + /// <param name="metadataFile">The metadata file.</param> + /// <param name="settings">The settings.</param> + /// <param name="encoding">The encoding.</param> + /// <param name="cancellationToken">The cancellation token.</param> + private void Fetch(MetadataResult<T> item, string metadataFile, XmlReaderSettings settings, Encoding encoding, CancellationToken cancellationToken) + { + item.ResetPeople(); + + using (Stream fileStream = FileSystem.OpenRead(metadataFile)) + { + using (var streamReader = new StreamReader(fileStream, encoding)) + { + // Use XmlReader for best performance + using (var reader = XmlReader.Create(streamReader, settings)) + { + reader.MoveToContent(); + reader.Read(); + + // Loop through each element + while (!reader.EOF && reader.ReadState == ReadState.Interactive) + { + cancellationToken.ThrowIfCancellationRequested(); + + if (reader.NodeType == XmlNodeType.Element) + { + FetchDataFromXmlNode(reader, item); + } + else + { + reader.Read(); + } + } + } + } + } + } + + private readonly CultureInfo _usCulture = new CultureInfo("en-US"); + + /// <summary> + /// Fetches metadata from one Xml Element + /// </summary> + /// <param name="reader">The reader.</param> + /// <param name="itemResult">The item result.</param> + protected virtual void FetchDataFromXmlNode(XmlReader reader, MetadataResult<T> itemResult) + { + var item = itemResult.Item; + + switch (reader.Name) + { + // DateCreated + case "Added": + { + var val = reader.ReadElementContentAsString(); + + if (!string.IsNullOrWhiteSpace(val)) + { + DateTime added; + if (DateTime.TryParse(val, out added)) + { + item.DateCreated = added.ToUniversalTime(); + } + else + { + Logger.Warn("Invalid Added value found: " + val); + } + } + break; + } + + case "OriginalTitle": + { + var val = reader.ReadElementContentAsString(); + + if (!string.IsNullOrEmpty(val)) + { + item.OriginalTitle = val; + } + break; + } + + case "LocalTitle": + item.Name = reader.ReadElementContentAsString(); + break; + + case "Type": + { + var type = reader.ReadElementContentAsString(); + + if (!string.IsNullOrWhiteSpace(type) && !type.Equals("none", StringComparison.OrdinalIgnoreCase)) + { + item.DisplayMediaType = type; + } + + break; + } + + case "CriticRating": + { + var text = reader.ReadElementContentAsString(); + + if (!string.IsNullOrEmpty(text)) + { + float value; + if (float.TryParse(text, NumberStyles.Any, _usCulture, out value)) + { + item.CriticRating = value; + } + } + + break; + } + + case "Budget": + { + var text = reader.ReadElementContentAsString(); + var hasBudget = item as IHasBudget; + if (hasBudget != null) + { + double value; + if (double.TryParse(text, NumberStyles.Any, _usCulture, out value)) + { + hasBudget.Budget = value; + } + } + + break; + } + + case "Revenue": + { + var text = reader.ReadElementContentAsString(); + var hasBudget = item as IHasBudget; + if (hasBudget != null) + { + double value; + if (double.TryParse(text, NumberStyles.Any, _usCulture, out value)) + { + hasBudget.Revenue = value; + } + } + + break; + } + + case "Metascore": + { + var text = reader.ReadElementContentAsString(); + var hasMetascore = item as IHasMetascore; + if (hasMetascore != null) + { + float value; + if (float.TryParse(text, NumberStyles.Any, _usCulture, out value)) + { + hasMetascore.Metascore = value; + } + } + + break; + } + + case "AwardSummary": + { + var text = reader.ReadElementContentAsString(); + var hasAwards = item as IHasAwards; + if (hasAwards != null) + { + if (!string.IsNullOrWhiteSpace(text)) + { + hasAwards.AwardSummary = text; + } + } + + break; + } + + case "SortTitle": + { + var val = reader.ReadElementContentAsString(); + + if (!string.IsNullOrWhiteSpace(val)) + { + item.ForcedSortName = val; + } + break; + } + + case "Overview": + case "Description": + { + var val = reader.ReadElementContentAsString(); + + if (!string.IsNullOrWhiteSpace(val)) + { + item.Overview = val; + } + + break; + } + + case "ShortOverview": + { + var val = reader.ReadElementContentAsString(); + + if (!string.IsNullOrWhiteSpace(val)) + { + item.ShortOverview = val; + } + + break; + } + + case "CriticRatingSummary": + { + var val = reader.ReadElementContentAsString(); + + if (!string.IsNullOrWhiteSpace(val)) + { + item.CriticRatingSummary = val; + } + + break; + } + + case "Language": + { + var val = reader.ReadElementContentAsString(); + + item.PreferredMetadataLanguage = val; + + break; + } + + case "CountryCode": + { + var val = reader.ReadElementContentAsString(); + + item.PreferredMetadataCountryCode = val; + + break; + } + + case "PlaceOfBirth": + { + var val = reader.ReadElementContentAsString(); + + if (!string.IsNullOrWhiteSpace(val)) + { + var person = item as Person; + if (person != null) + { + person.ProductionLocations = new List<string> { val }; + } + } + + break; + } + + case "Website": + { + var val = reader.ReadElementContentAsString(); + + if (!string.IsNullOrWhiteSpace(val)) + { + item.HomePageUrl = val; + } + + break; + } + + case "LockedFields": + { + var fields = new List<MetadataFields>(); + + var val = reader.ReadElementContentAsString(); + + if (!string.IsNullOrWhiteSpace(val)) + { + var list = val.Split('|').Select(i => + { + MetadataFields field; + + if (Enum.TryParse<MetadataFields>(i, true, out field)) + { + return (MetadataFields?)field; + } + + return null; + + }).Where(i => i.HasValue).Select(i => i.Value); + + fields.AddRange(list); + } + + item.LockedFields = fields; + + break; + } + + case "TagLines": + { + if (!reader.IsEmptyElement) + { + using (var subtree = reader.ReadSubtree()) + { + FetchFromTaglinesNode(subtree, item); + } + } + else + { + reader.Read(); + } + break; + } + + case "Countries": + { + if (!reader.IsEmptyElement) + { + using (var subtree = reader.ReadSubtree()) + { + FetchFromCountriesNode(subtree, item); + } + } + else + { + reader.Read(); + } + break; + } + + case "ContentRating": + case "MPAARating": + { + var rating = reader.ReadElementContentAsString(); + + if (!string.IsNullOrWhiteSpace(rating)) + { + item.OfficialRating = rating; + } + break; + } + + case "MPAADescription": + { + var rating = reader.ReadElementContentAsString(); + + if (!string.IsNullOrWhiteSpace(rating)) + { + item.OfficialRatingDescription = rating; + } + break; + } + + case "CustomRating": + { + var val = reader.ReadElementContentAsString(); + + if (!string.IsNullOrWhiteSpace(val)) + { + item.CustomRating = val; + } + break; + } + + case "RunningTime": + { + var text = reader.ReadElementContentAsString(); + + if (!string.IsNullOrWhiteSpace(text)) + { + int runtime; + if (int.TryParse(text.Split(' ')[0], NumberStyles.Integer, _usCulture, out runtime)) + { + item.RunTimeTicks = TimeSpan.FromMinutes(runtime).Ticks; + } + } + break; + } + + case "AspectRatio": + { + var val = reader.ReadElementContentAsString(); + + var hasAspectRatio = item as IHasAspectRatio; + if (!string.IsNullOrWhiteSpace(val) && hasAspectRatio != null) + { + hasAspectRatio.AspectRatio = val; + } + break; + } + + case "LockData": + { + var val = reader.ReadElementContentAsString(); + + if (!string.IsNullOrWhiteSpace(val)) + { + item.IsLocked = string.Equals("true", val, StringComparison.OrdinalIgnoreCase); + } + break; + } + + case "Network": + { + foreach (var name in SplitNames(reader.ReadElementContentAsString())) + { + if (string.IsNullOrWhiteSpace(name)) + { + continue; + } + item.AddStudio(name); + } + break; + } + + case "Director": + { + foreach (var p in SplitNames(reader.ReadElementContentAsString()).Select(v => new Controller.Entities.PersonInfo { Name = v.Trim(), Type = PersonType.Director })) + { + if (string.IsNullOrWhiteSpace(p.Name)) + { + continue; + } + itemResult.AddPerson(p); + } + break; + } + case "Writer": + { + foreach (var p in SplitNames(reader.ReadElementContentAsString()).Select(v => new Controller.Entities.PersonInfo { Name = v.Trim(), Type = PersonType.Writer })) + { + if (string.IsNullOrWhiteSpace(p.Name)) + { + continue; + } + itemResult.AddPerson(p); + } + break; + } + + case "Actors": + { + + var actors = reader.ReadInnerXml(); + + if (actors.Contains("<")) + { + // This is one of the mis-named "Actors" full nodes created by MB2 + // Create a reader and pass it to the persons node processor + FetchDataFromPersonsNode(XmlReader.Create(new StringReader("<Persons>" + actors + "</Persons>")), itemResult); + } + else + { + // Old-style piped string + foreach (var p in SplitNames(actors).Select(v => new Controller.Entities.PersonInfo { Name = v.Trim(), Type = PersonType.Actor })) + { + if (string.IsNullOrWhiteSpace(p.Name)) + { + continue; + } + itemResult.AddPerson(p); + } + } + break; + } + + case "GuestStars": + { + foreach (var p in SplitNames(reader.ReadElementContentAsString()).Select(v => new Controller.Entities.PersonInfo { Name = v.Trim(), Type = PersonType.GuestStar })) + { + if (string.IsNullOrWhiteSpace(p.Name)) + { + continue; + } + itemResult.AddPerson(p); + } + break; + } + + case "Trailer": + { + var val = reader.ReadElementContentAsString(); + + var hasTrailers = item as IHasTrailers; + if (hasTrailers != null) + { + if (!string.IsNullOrWhiteSpace(val)) + { + hasTrailers.AddTrailerUrl(val, false); + } + } + break; + } + + case "DisplayOrder": + { + var val = reader.ReadElementContentAsString(); + + var hasDisplayOrder = item as IHasDisplayOrder; + if (hasDisplayOrder != null) + { + if (!string.IsNullOrWhiteSpace(val)) + { + hasDisplayOrder.DisplayOrder = val; + } + } + break; + } + + case "Trailers": + { + if (!reader.IsEmptyElement) + { + using (var subtree = reader.ReadSubtree()) + { + var hasTrailers = item as IHasTrailers; + if (hasTrailers != null) + { + FetchDataFromTrailersNode(subtree, hasTrailers); + } + } + } + else + { + reader.Read(); + } + break; + } + + case "ProductionYear": + { + var val = reader.ReadElementContentAsString(); + + if (!string.IsNullOrWhiteSpace(val)) + { + int productionYear; + if (int.TryParse(val, out productionYear) && productionYear > 1850) + { + item.ProductionYear = productionYear; + } + } + + break; + } + + case "Rating": + case "IMDBrating": + { + + var rating = reader.ReadElementContentAsString(); + + if (!string.IsNullOrWhiteSpace(rating)) + { + float val; + // All external meta is saving this as '.' for decimal I believe...but just to be sure + if (float.TryParse(rating.Replace(',', '.'), NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out val)) + { + item.CommunityRating = val; + } + } + break; + } + + case "BirthDate": + case "PremiereDate": + case "FirstAired": + { + var firstAired = reader.ReadElementContentAsString(); + + if (!string.IsNullOrWhiteSpace(firstAired)) + { + DateTime airDate; + + if (DateTime.TryParseExact(firstAired, "yyyy-MM-dd", CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal, out airDate) && airDate.Year > 1850) + { + item.PremiereDate = airDate.ToUniversalTime(); + item.ProductionYear = airDate.Year; + } + } + + break; + } + + case "DeathDate": + case "EndDate": + { + var firstAired = reader.ReadElementContentAsString(); + + if (!string.IsNullOrWhiteSpace(firstAired)) + { + DateTime airDate; + + if (DateTime.TryParseExact(firstAired, "yyyy-MM-dd", CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal, out airDate) && airDate.Year > 1850) + { + item.EndDate = airDate.ToUniversalTime(); + } + } + + break; + } + + case "VoteCount": + { + var val = reader.ReadElementContentAsString(); + if (!string.IsNullOrWhiteSpace(val)) + { + int num; + + if (int.TryParse(val, NumberStyles.Integer, _usCulture, out num)) + { + item.VoteCount = num; + } + } + break; + } + case "CollectionNumber": + var tmdbCollection = reader.ReadElementContentAsString(); + if (!string.IsNullOrWhiteSpace(tmdbCollection)) + { + item.SetProviderId(MetadataProviders.TmdbCollection, tmdbCollection); + } + break; + + case "Genres": + { + if (!reader.IsEmptyElement) + { + using (var subtree = reader.ReadSubtree()) + { + FetchFromGenresNode(subtree, item); + } + } + else + { + reader.Read(); + } + break; + } + + case "Tags": + { + if (!reader.IsEmptyElement) + { + using (var subtree = reader.ReadSubtree()) + { + FetchFromTagsNode(subtree, item); + } + } + else + { + reader.Read(); + } + break; + } + + case "PlotKeywords": + { + if (!reader.IsEmptyElement) + { + using (var subtree = reader.ReadSubtree()) + { + FetchFromKeywordsNode(subtree, item); + } + } + else + { + reader.Read(); + } + break; + } + + case "Persons": + { + if (!reader.IsEmptyElement) + { + using (var subtree = reader.ReadSubtree()) + { + FetchDataFromPersonsNode(subtree, itemResult); + } + } + else + { + reader.Read(); + } + break; + } + + case "Studios": + { + if (!reader.IsEmptyElement) + { + using (var subtree = reader.ReadSubtree()) + { + FetchFromStudiosNode(subtree, item); + } + } + else + { + reader.Read(); + } + break; + } + + case "Shares": + { + if (!reader.IsEmptyElement) + { + using (var subtree = reader.ReadSubtree()) + { + var hasShares = item as IHasShares; + if (hasShares != null) + { + FetchFromSharesNode(subtree, hasShares); + } + } + } + else + { + reader.Read(); + } + break; + } + + case "Format3D": + { + var val = reader.ReadElementContentAsString(); + + var video = item as Video; + + if (video != null) + { + if (string.Equals("HSBS", val, StringComparison.OrdinalIgnoreCase)) + { + video.Video3DFormat = Video3DFormat.HalfSideBySide; + } + else if (string.Equals("HTAB", val, StringComparison.OrdinalIgnoreCase)) + { + video.Video3DFormat = Video3DFormat.HalfTopAndBottom; + } + else if (string.Equals("FTAB", val, StringComparison.OrdinalIgnoreCase)) + { + video.Video3DFormat = Video3DFormat.FullTopAndBottom; + } + else if (string.Equals("FSBS", val, StringComparison.OrdinalIgnoreCase)) + { + video.Video3DFormat = Video3DFormat.FullSideBySide; + } + else if (string.Equals("MVC", val, StringComparison.OrdinalIgnoreCase)) + { + video.Video3DFormat = Video3DFormat.MVC; + } + } + break; + } + + default: + { + string readerName = reader.Name; + string providerIdValue; + if (_validProviderIds.TryGetValue(readerName, out providerIdValue)) + { + var id = reader.ReadElementContentAsString(); + if (!string.IsNullOrWhiteSpace(id)) + { + item.SetProviderId(providerIdValue, id); + } + } + else + { + reader.Skip(); + } + + break; + + } + } + } + + private void FetchFromSharesNode(XmlReader reader, IHasShares item) + { + reader.MoveToContent(); + reader.Read(); + + // Loop through each element + while (!reader.EOF && reader.ReadState == ReadState.Interactive) + { + if (reader.NodeType == XmlNodeType.Element) + { + switch (reader.Name) + { + case "Share": + { + if (reader.IsEmptyElement) + { + reader.Read(); + continue; + } + using (var subtree = reader.ReadSubtree()) + { + var share = GetShareFromNode(subtree); + if (share != null) + { + item.Shares.Add(share); + } + } + break; + } + + default: + reader.Skip(); + break; + } + } + else + { + reader.Read(); + } + } + } + + private Share GetShareFromNode(XmlReader reader) + { + var share = new Share(); + + reader.MoveToContent(); + reader.Read(); + + // Loop through each element + while (!reader.EOF && reader.ReadState == ReadState.Interactive) + { + if (reader.NodeType == XmlNodeType.Element) + { + switch (reader.Name) + { + case "UserId": + { + share.UserId = reader.ReadElementContentAsString(); + break; + } + + case "CanEdit": + { + share.CanEdit = string.Equals(reader.ReadElementContentAsString(), true.ToString(), StringComparison.OrdinalIgnoreCase); + break; + } + + default: + reader.Skip(); + break; + } + } + else + { + reader.Read(); + } + } + + return share; + } + + private void FetchFromCountriesNode(XmlReader reader, T item) + { + reader.MoveToContent(); + reader.Read(); + + // Loop through each element + while (!reader.EOF && reader.ReadState == ReadState.Interactive) + { + if (reader.NodeType == XmlNodeType.Element) + { + switch (reader.Name) + { + case "Country": + { + var val = reader.ReadElementContentAsString(); + + if (!string.IsNullOrWhiteSpace(val)) + { + } + break; + } + + default: + reader.Skip(); + break; + } + } + else + { + reader.Read(); + } + } + } + + /// <summary> + /// Fetches from taglines node. + /// </summary> + /// <param name="reader">The reader.</param> + /// <param name="item">The item.</param> + private void FetchFromTaglinesNode(XmlReader reader, T item) + { + reader.MoveToContent(); + reader.Read(); + + // Loop through each element + while (!reader.EOF && reader.ReadState == ReadState.Interactive) + { + if (reader.NodeType == XmlNodeType.Element) + { + switch (reader.Name) + { + case "Tagline": + { + var val = reader.ReadElementContentAsString(); + + if (!string.IsNullOrWhiteSpace(val)) + { + item.Tagline = val; + } + break; + } + default: + reader.Skip(); + break; + } + } + else + { + reader.Read(); + } + } + } + + /// <summary> + /// Fetches from genres node. + /// </summary> + /// <param name="reader">The reader.</param> + /// <param name="item">The item.</param> + private void FetchFromGenresNode(XmlReader reader, T item) + { + reader.MoveToContent(); + reader.Read(); + + // Loop through each element + while (!reader.EOF && reader.ReadState == ReadState.Interactive) + { + if (reader.NodeType == XmlNodeType.Element) + { + switch (reader.Name) + { + case "Genre": + { + var genre = reader.ReadElementContentAsString(); + + if (!string.IsNullOrWhiteSpace(genre)) + { + item.AddGenre(genre); + } + break; + } + + default: + reader.Skip(); + break; + } + } + else + { + reader.Read(); + } + } + } + + private void FetchFromTagsNode(XmlReader reader, BaseItem item) + { + reader.MoveToContent(); + reader.Read(); + + // Loop through each element + while (!reader.EOF && reader.ReadState == ReadState.Interactive) + { + if (reader.NodeType == XmlNodeType.Element) + { + switch (reader.Name) + { + case "Tag": + { + var tag = reader.ReadElementContentAsString(); + + if (!string.IsNullOrWhiteSpace(tag)) + { + item.AddTag(tag); + } + break; + } + + default: + reader.Skip(); + break; + } + } + else + { + reader.Read(); + } + } + } + + private void FetchFromKeywordsNode(XmlReader reader, BaseItem item) + { + reader.MoveToContent(); + reader.Read(); + + // Loop through each element + while (!reader.EOF && reader.ReadState == ReadState.Interactive) + { + if (reader.NodeType == XmlNodeType.Element) + { + switch (reader.Name) + { + case "PlotKeyword": + { + var tag = reader.ReadElementContentAsString(); + + if (!string.IsNullOrWhiteSpace(tag)) + { + item.AddKeyword(tag); + } + break; + } + + default: + reader.Skip(); + break; + } + } + else + { + reader.Read(); + } + } + } + + /// <summary> + /// Fetches the data from persons node. + /// </summary> + /// <param name="reader">The reader.</param> + /// <param name="item">The item.</param> + private void FetchDataFromPersonsNode(XmlReader reader, MetadataResult<T> item) + { + reader.MoveToContent(); + reader.Read(); + + // Loop through each element + while (!reader.EOF && reader.ReadState == ReadState.Interactive) + { + if (reader.NodeType == XmlNodeType.Element) + { + switch (reader.Name) + { + case "Person": + case "Actor": + { + if (reader.IsEmptyElement) + { + reader.Read(); + continue; + } + using (var subtree = reader.ReadSubtree()) + { + foreach (var person in GetPersonsFromXmlNode(subtree)) + { + if (string.IsNullOrWhiteSpace(person.Name)) + { + continue; + } + item.AddPerson(person); + } + } + break; + } + + default: + reader.Skip(); + break; + } + } + else + { + reader.Read(); + } + } + } + + private void FetchDataFromTrailersNode(XmlReader reader, IHasTrailers item) + { + reader.MoveToContent(); + reader.Read(); + + // Loop through each element + while (!reader.EOF && reader.ReadState == ReadState.Interactive) + { + 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; + } + } + else + { + reader.Read(); + } + } + } + + /// <summary> + /// Fetches from studios node. + /// </summary> + /// <param name="reader">The reader.</param> + /// <param name="item">The item.</param> + private void FetchFromStudiosNode(XmlReader reader, T item) + { + reader.MoveToContent(); + reader.Read(); + + // Loop through each element + while (!reader.EOF && reader.ReadState == ReadState.Interactive) + { + if (reader.NodeType == XmlNodeType.Element) + { + switch (reader.Name) + { + case "Studio": + { + var studio = reader.ReadElementContentAsString(); + + if (!string.IsNullOrWhiteSpace(studio)) + { + item.AddStudio(studio); + } + break; + } + + default: + reader.Skip(); + break; + } + } + else + { + reader.Read(); + } + } + } + + /// <summary> + /// Gets the persons from XML node. + /// </summary> + /// <param name="reader">The reader.</param> + /// <returns>IEnumerable{PersonInfo}.</returns> + private IEnumerable<PersonInfo> GetPersonsFromXmlNode(XmlReader reader) + { + var name = string.Empty; + var type = PersonType.Actor; // If type is not specified assume actor + var role = string.Empty; + int? sortOrder = null; + + reader.MoveToContent(); + reader.Read(); + + // Loop through each element + while (!reader.EOF && reader.ReadState == ReadState.Interactive) + { + if (reader.NodeType == XmlNodeType.Element) + { + switch (reader.Name) + { + case "Name": + name = reader.ReadElementContentAsString() ?? string.Empty; + break; + + case "Type": + { + var val = reader.ReadElementContentAsString(); + + if (!string.IsNullOrWhiteSpace(val)) + { + type = val; + } + break; + } + + case "Role": + { + var val = reader.ReadElementContentAsString(); + + if (!string.IsNullOrWhiteSpace(val)) + { + role = val; + } + 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(); + break; + } + } + else + { + reader.Read(); + } + } + + var personInfo = new PersonInfo + { + Name = name.Trim(), + Role = role, + Type = type, + SortOrder = sortOrder + }; + + return new[] { personInfo }; + } + + protected LinkedChild GetLinkedChild(XmlReader reader) + { + var linkedItem = new LinkedChild + { + Type = LinkedChildType.Manual + }; + + reader.MoveToContent(); + reader.Read(); + + // Loop through each element + while (!reader.EOF && reader.ReadState == ReadState.Interactive) + { + if (reader.NodeType == XmlNodeType.Element) + { + switch (reader.Name) + { + case "Path": + { + linkedItem.Path = reader.ReadElementContentAsString(); + break; + } + + default: + reader.Skip(); + break; + } + } + else + { + reader.Read(); + } + } + + // This is valid + if (!string.IsNullOrWhiteSpace(linkedItem.Path)) + { + return linkedItem; + } + + return null; + } + + protected Share GetShare(XmlReader reader) + { + var item = new Share(); + + reader.MoveToContent(); + reader.Read(); + + // Loop through each element + while (!reader.EOF && reader.ReadState == ReadState.Interactive) + { + if (reader.NodeType == XmlNodeType.Element) + { + switch (reader.Name) + { + case "UserId": + { + item.UserId = reader.ReadElementContentAsString(); + break; + } + + case "CanEdit": + { + item.CanEdit = string.Equals(reader.ReadElementContentAsString(), "true", StringComparison.OrdinalIgnoreCase); + break; + } + default: + { + reader.Skip(); + break; + } + } + } + else + { + reader.Read(); + } + } + + // This is valid + if (!string.IsNullOrWhiteSpace(item.UserId)) + { + return item; + } + + return null; + } + + + /// <summary> + /// Used to split names of comma or pipe delimeted genres and people + /// </summary> + /// <param name="value">The value.</param> + /// <returns>IEnumerable{System.String}.</returns> + private IEnumerable<string> SplitNames(string value) + { + value = value ?? string.Empty; + + // Only split by comma if there is no pipe in the string + // We have to be careful to not split names like Matthew, Jr. + var separator = value.IndexOf('|') == -1 && value.IndexOf(';') == -1 ? new[] { ',' } : new[] { '|', ';' }; + + value = value.Trim().Trim(separator); + + return string.IsNullOrWhiteSpace(value) ? new string[] { } : Split(value, separator, StringSplitOptions.RemoveEmptyEntries); + } + + /// <summary> + /// Provides an additional overload for string.split + /// </summary> + /// <param name="val">The val.</param> + /// <param name="separators">The separators.</param> + /// <param name="options">The options.</param> + /// <returns>System.String[][].</returns> + private static string[] Split(string val, char[] separators, StringSplitOptions options) + { + return val.Split(separators, options); + } + + } +} diff --git a/MediaBrowser.LocalMetadata/Parsers/BoxSetXmlParser.cs b/MediaBrowser.LocalMetadata/Parsers/BoxSetXmlParser.cs index 9ebb357c6..9dcfa2f76 100644 --- a/MediaBrowser.LocalMetadata/Parsers/BoxSetXmlParser.cs +++ b/MediaBrowser.LocalMetadata/Parsers/BoxSetXmlParser.cs @@ -4,16 +4,13 @@ using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Logging; using System.Collections.Generic; using System.Xml; +using MediaBrowser.Model.IO; +using MediaBrowser.Model.Xml; namespace MediaBrowser.LocalMetadata.Parsers { public class BoxSetXmlParser : BaseItemXmlParser<BoxSet> { - public BoxSetXmlParser(ILogger logger, IProviderManager providerManager) - : base(logger, providerManager) - { - } - protected override void FetchDataFromXmlNode(XmlReader reader, MetadataResult<BoxSet> item) { switch (reader.Name) @@ -34,11 +31,13 @@ namespace MediaBrowser.LocalMetadata.Parsers private void FetchFromCollectionItemsNode(XmlReader reader, MetadataResult<BoxSet> item) { - reader.MoveToContent(); - var list = new List<LinkedChild>(); - while (reader.Read()) + reader.MoveToContent(); + reader.Read(); + + // Loop through each element + while (!reader.EOF && reader.ReadState == ReadState.Interactive) { if (reader.NodeType == XmlNodeType.Element) { @@ -58,15 +57,24 @@ namespace MediaBrowser.LocalMetadata.Parsers break; } - default: - reader.Skip(); - break; + { + reader.Skip(); + break; + } } } + else + { + reader.Read(); + } } item.Item.LinkedChildren = list; } + + public BoxSetXmlParser(ILogger logger, IProviderManager providerManager, IXmlReaderSettingsFactory xmlReaderSettingsFactory, IFileSystem fileSystem) : base(logger, providerManager, xmlReaderSettingsFactory, fileSystem) + { + } } } diff --git a/MediaBrowser.LocalMetadata/Parsers/EpisodeXmlParser.cs b/MediaBrowser.LocalMetadata/Parsers/EpisodeXmlParser.cs index 71f6d3fe9..9adc4e5a9 100644 --- a/MediaBrowser.LocalMetadata/Parsers/EpisodeXmlParser.cs +++ b/MediaBrowser.LocalMetadata/Parsers/EpisodeXmlParser.cs @@ -8,7 +8,10 @@ using System.Globalization; using System.IO; using System.Threading; using System.Xml; -using CommonIO; +using MediaBrowser.Common.IO; +using MediaBrowser.Controller.IO; +using MediaBrowser.Model.IO; +using MediaBrowser.Model.Xml; namespace MediaBrowser.LocalMetadata.Parsers { @@ -20,8 +23,8 @@ namespace MediaBrowser.LocalMetadata.Parsers private List<LocalImageInfo> _imagesFound; private readonly IFileSystem _fileSystem; - public EpisodeXmlParser(ILogger logger, IFileSystem fileSystem, IProviderManager providerManager) - : base(logger, providerManager) + public EpisodeXmlParser(ILogger logger, IFileSystem fileSystem, IProviderManager providerManager, IXmlReaderSettingsFactory xmlSettings) + : base(logger, providerManager, xmlSettings, fileSystem) { _fileSystem = fileSystem; } diff --git a/MediaBrowser.LocalMetadata/Parsers/GameSystemXmlParser.cs b/MediaBrowser.LocalMetadata/Parsers/GameSystemXmlParser.cs index 75df53958..8bf09e546 100644 --- a/MediaBrowser.LocalMetadata/Parsers/GameSystemXmlParser.cs +++ b/MediaBrowser.LocalMetadata/Parsers/GameSystemXmlParser.cs @@ -5,16 +5,13 @@ using MediaBrowser.Model.Logging; using System.Threading; using System.Threading.Tasks; using System.Xml; +using MediaBrowser.Model.IO; +using MediaBrowser.Model.Xml; namespace MediaBrowser.LocalMetadata.Parsers { public class GameSystemXmlParser : BaseItemXmlParser<GameSystem> { - public GameSystemXmlParser(ILogger logger, IProviderManager providerManager) - : base(logger, providerManager) - { - } - private readonly Task _cachedTask = Task.FromResult(true); public Task FetchAsync(MetadataResult<GameSystem> item, string metadataFile, CancellationToken cancellationToken) { @@ -62,5 +59,9 @@ namespace MediaBrowser.LocalMetadata.Parsers break; } } + + public GameSystemXmlParser(ILogger logger, IProviderManager providerManager, IXmlReaderSettingsFactory xmlReaderSettingsFactory, IFileSystem fileSystem) : base(logger, providerManager, xmlReaderSettingsFactory, fileSystem) + { + } } } diff --git a/MediaBrowser.LocalMetadata/Parsers/GameXmlParser.cs b/MediaBrowser.LocalMetadata/Parsers/GameXmlParser.cs index 956b8baef..abce0582c 100644 --- a/MediaBrowser.LocalMetadata/Parsers/GameXmlParser.cs +++ b/MediaBrowser.LocalMetadata/Parsers/GameXmlParser.cs @@ -5,7 +5,9 @@ using System.Xml; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; +using MediaBrowser.Model.IO; using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Xml; namespace MediaBrowser.LocalMetadata.Parsers { @@ -16,11 +18,6 @@ namespace MediaBrowser.LocalMetadata.Parsers { private readonly CultureInfo _usCulture = new CultureInfo("en-US"); - public GameXmlParser(ILogger logger, IProviderManager providerManager) - : base(logger, providerManager) - { - } - private readonly Task _cachedTask = Task.FromResult(true); public Task FetchAsync(MetadataResult<Game> item, string metadataFile, CancellationToken cancellationToken) { @@ -83,5 +80,9 @@ namespace MediaBrowser.LocalMetadata.Parsers break; } } + + public GameXmlParser(ILogger logger, IProviderManager providerManager, IXmlReaderSettingsFactory xmlReaderSettingsFactory, IFileSystem fileSystem) : base(logger, providerManager, xmlReaderSettingsFactory, fileSystem) + { + } } } diff --git a/MediaBrowser.LocalMetadata/Parsers/MovieXmlParser.cs b/MediaBrowser.LocalMetadata/Parsers/MovieXmlParser.cs index 6e78d365e..08c895c43 100644 --- a/MediaBrowser.LocalMetadata/Parsers/MovieXmlParser.cs +++ b/MediaBrowser.LocalMetadata/Parsers/MovieXmlParser.cs @@ -3,6 +3,8 @@ using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Logging; using System.Xml; +using MediaBrowser.Model.IO; +using MediaBrowser.Model.Xml; namespace MediaBrowser.LocalMetadata.Parsers { @@ -12,11 +14,6 @@ namespace MediaBrowser.LocalMetadata.Parsers public class BaseVideoXmlParser<T> : BaseItemXmlParser<T> where T : Video { - public BaseVideoXmlParser(ILogger logger, IProviderManager providerManager) - : base(logger, providerManager) - { - } - /// <summary> /// Fetches the data from XML node. /// </summary> @@ -46,19 +43,22 @@ namespace MediaBrowser.LocalMetadata.Parsers break; } } + + public BaseVideoXmlParser(ILogger logger, IProviderManager providerManager, IXmlReaderSettingsFactory xmlReaderSettingsFactory, IFileSystem fileSystem) : base(logger, providerManager, xmlReaderSettingsFactory, fileSystem) + { + } } public class MovieXmlParser : BaseVideoXmlParser<Movie> { - public MovieXmlParser(ILogger logger, IProviderManager providerManager) : base(logger, providerManager) + public MovieXmlParser(ILogger logger, IProviderManager providerManager, IXmlReaderSettingsFactory xmlReaderSettingsFactory, IFileSystem fileSystem) : base(logger, providerManager, xmlReaderSettingsFactory, fileSystem) { } } public class VideoXmlParser : BaseVideoXmlParser<Video> { - public VideoXmlParser(ILogger logger, IProviderManager providerManager) - : base(logger, providerManager) + public VideoXmlParser(ILogger logger, IProviderManager providerManager, IXmlReaderSettingsFactory xmlReaderSettingsFactory, IFileSystem fileSystem) : base(logger, providerManager, xmlReaderSettingsFactory, fileSystem) { } } diff --git a/MediaBrowser.LocalMetadata/Parsers/MusicVideoXmlParser.cs b/MediaBrowser.LocalMetadata/Parsers/MusicVideoXmlParser.cs index 5f0b447e8..f612d1108 100644 --- a/MediaBrowser.LocalMetadata/Parsers/MusicVideoXmlParser.cs +++ b/MediaBrowser.LocalMetadata/Parsers/MusicVideoXmlParser.cs @@ -3,21 +3,14 @@ using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Logging; using System; using System.Xml; +using MediaBrowser.Model.IO; +using MediaBrowser.Model.Xml; namespace MediaBrowser.LocalMetadata.Parsers { public class MusicVideoXmlParser : BaseVideoXmlParser<MusicVideo> { /// <summary> - /// Initializes a new instance of the <see cref="BaseItemXmlParser{T}" /> class. - /// </summary> - /// <param name="logger">The logger.</param> - public MusicVideoXmlParser(ILogger logger, IProviderManager providerManager) - : base(logger, providerManager) - { - } - - /// <summary> /// Fetches the data from XML node. /// </summary> /// <param name="reader">The reader.</param> @@ -50,5 +43,9 @@ namespace MediaBrowser.LocalMetadata.Parsers break; } } + + public MusicVideoXmlParser(ILogger logger, IProviderManager providerManager, IXmlReaderSettingsFactory xmlReaderSettingsFactory, IFileSystem fileSystem) : base(logger, providerManager, xmlReaderSettingsFactory, fileSystem) + { + } } } diff --git a/MediaBrowser.LocalMetadata/Parsers/PlaylistXmlParser.cs b/MediaBrowser.LocalMetadata/Parsers/PlaylistXmlParser.cs index de46c0a86..695fe2b12 100644 --- a/MediaBrowser.LocalMetadata/Parsers/PlaylistXmlParser.cs +++ b/MediaBrowser.LocalMetadata/Parsers/PlaylistXmlParser.cs @@ -6,16 +6,13 @@ using System; using System.Collections.Generic; using System.Linq; using System.Xml; +using MediaBrowser.Model.IO; +using MediaBrowser.Model.Xml; namespace MediaBrowser.LocalMetadata.Parsers { public class PlaylistXmlParser : BaseItemXmlParser<Playlist> { - public PlaylistXmlParser(ILogger logger, IProviderManager providerManager) - : base(logger, providerManager) - { - } - protected override void FetchDataFromXmlNode(XmlReader reader, MetadataResult<Playlist> result) { var item = result.Item; @@ -46,17 +43,31 @@ namespace MediaBrowser.LocalMetadata.Parsers case "PlaylistItems": - using (var subReader = reader.ReadSubtree()) + if (!reader.IsEmptyElement) + { + using (var subReader = reader.ReadSubtree()) + { + FetchFromCollectionItemsNode(subReader, item); + } + } + else { - FetchFromCollectionItemsNode(subReader, item); + reader.Read(); } break; case "Shares": - using (var subReader = reader.ReadSubtree()) + if (!reader.IsEmptyElement) + { + using (var subReader = reader.ReadSubtree()) + { + FetchFromSharesNode(subReader, item); + } + } + else { - FetchFromSharesNode(subReader, item); + reader.Read(); } break; @@ -68,11 +79,13 @@ namespace MediaBrowser.LocalMetadata.Parsers private void FetchFromCollectionItemsNode(XmlReader reader, Playlist item) { - reader.MoveToContent(); - var list = new List<LinkedChild>(); - while (reader.Read()) + reader.MoveToContent(); + reader.Read(); + + // Loop through each element + while (!reader.EOF && reader.ReadState == ReadState.Interactive) { if (reader.NodeType == XmlNodeType.Element) { @@ -80,6 +93,12 @@ namespace MediaBrowser.LocalMetadata.Parsers { case "PlaylistItem": { + if (reader.IsEmptyElement) + { + reader.Read(); + continue; + } + using (var subReader = reader.ReadSubtree()) { var child = GetLinkedChild(subReader); @@ -92,12 +111,17 @@ namespace MediaBrowser.LocalMetadata.Parsers break; } - default: - reader.Skip(); - break; + { + reader.Skip(); + break; + } } } + else + { + reader.Read(); + } } item.LinkedChildren = list; @@ -105,11 +129,13 @@ namespace MediaBrowser.LocalMetadata.Parsers private void FetchFromSharesNode(XmlReader reader, Playlist item) { - reader.MoveToContent(); - var list = new List<Share>(); - while (reader.Read()) + reader.MoveToContent(); + reader.Read(); + + // Loop through each element + while (!reader.EOF && reader.ReadState == ReadState.Interactive) { if (reader.NodeType == XmlNodeType.Element) { @@ -117,6 +143,12 @@ namespace MediaBrowser.LocalMetadata.Parsers { case "Share": { + if (reader.IsEmptyElement) + { + reader.Read(); + continue; + } + using (var subReader = reader.ReadSubtree()) { var child = GetShare(subReader); @@ -129,15 +161,24 @@ namespace MediaBrowser.LocalMetadata.Parsers break; } - default: - reader.Skip(); - break; + { + reader.Skip(); + break; + } } } + else + { + reader.Read(); + } } item.Shares = list; } + + public PlaylistXmlParser(ILogger logger, IProviderManager providerManager, IXmlReaderSettingsFactory xmlReaderSettingsFactory, IFileSystem fileSystem) : base(logger, providerManager, xmlReaderSettingsFactory, fileSystem) + { + } } } diff --git a/MediaBrowser.LocalMetadata/Parsers/SeriesXmlParser.cs b/MediaBrowser.LocalMetadata/Parsers/SeriesXmlParser.cs index 7b7fb4751..2ddd84378 100644 --- a/MediaBrowser.LocalMetadata/Parsers/SeriesXmlParser.cs +++ b/MediaBrowser.LocalMetadata/Parsers/SeriesXmlParser.cs @@ -4,7 +4,9 @@ using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; +using MediaBrowser.Model.IO; using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Xml; namespace MediaBrowser.LocalMetadata.Parsers { @@ -14,15 +16,6 @@ namespace MediaBrowser.LocalMetadata.Parsers public class SeriesXmlParser : BaseItemXmlParser<Series> { /// <summary> - /// Initializes a new instance of the <see cref="BaseItemXmlParser{T}" /> class. - /// </summary> - /// <param name="logger">The logger.</param> - public SeriesXmlParser(ILogger logger, IProviderManager providerManager) - : base(logger, providerManager) - { - } - - /// <summary> /// Fetches the data from XML node. /// </summary> /// <param name="reader">The reader.</param> @@ -116,5 +109,9 @@ namespace MediaBrowser.LocalMetadata.Parsers break; } } + + public SeriesXmlParser(ILogger logger, IProviderManager providerManager, IXmlReaderSettingsFactory xmlReaderSettingsFactory, IFileSystem fileSystem) : base(logger, providerManager, xmlReaderSettingsFactory, fileSystem) + { + } } } diff --git a/MediaBrowser.LocalMetadata/Providers/BoxSetXmlProvider.cs b/MediaBrowser.LocalMetadata/Providers/BoxSetXmlProvider.cs index 3acb2b74c..88c51caaa 100644 --- a/MediaBrowser.LocalMetadata/Providers/BoxSetXmlProvider.cs +++ b/MediaBrowser.LocalMetadata/Providers/BoxSetXmlProvider.cs @@ -4,7 +4,10 @@ using MediaBrowser.LocalMetadata.Parsers; using MediaBrowser.Model.Logging; using System.IO; using System.Threading; -using CommonIO; +using MediaBrowser.Common.IO; +using MediaBrowser.Controller.IO; +using MediaBrowser.Model.IO; +using MediaBrowser.Model.Xml; namespace MediaBrowser.LocalMetadata.Providers { @@ -15,17 +18,19 @@ namespace MediaBrowser.LocalMetadata.Providers { private readonly ILogger _logger; private readonly IProviderManager _providerManager; + protected IXmlReaderSettingsFactory XmlReaderSettingsFactory { get; private set; } - public BoxSetXmlProvider(IFileSystem fileSystem, ILogger logger, IProviderManager providerManager) + public BoxSetXmlProvider(IFileSystem fileSystem, ILogger logger, IProviderManager providerManager, IXmlReaderSettingsFactory xmlReaderSettingsFactory) : base(fileSystem) { _logger = logger; _providerManager = providerManager; + XmlReaderSettingsFactory = xmlReaderSettingsFactory; } protected override void Fetch(MetadataResult<BoxSet> result, string path, CancellationToken cancellationToken) { - new BoxSetXmlParser(_logger, _providerManager).Fetch(result, path, cancellationToken); + new BoxSetXmlParser(_logger, _providerManager, XmlReaderSettingsFactory, FileSystem).Fetch(result, path, cancellationToken); } protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService) diff --git a/MediaBrowser.LocalMetadata/Providers/EpisodeXmlProvider.cs b/MediaBrowser.LocalMetadata/Providers/EpisodeXmlProvider.cs index 493df8c6a..7e0f1707f 100644 --- a/MediaBrowser.LocalMetadata/Providers/EpisodeXmlProvider.cs +++ b/MediaBrowser.LocalMetadata/Providers/EpisodeXmlProvider.cs @@ -6,7 +6,10 @@ using MediaBrowser.Model.Logging; using System.Collections.Generic; using System.IO; using System.Threading; -using CommonIO; +using MediaBrowser.Common.IO; +using MediaBrowser.Controller.IO; +using MediaBrowser.Model.IO; +using MediaBrowser.Model.Xml; namespace MediaBrowser.LocalMetadata.Providers { @@ -14,12 +17,14 @@ namespace MediaBrowser.LocalMetadata.Providers { private readonly ILogger _logger; private readonly IProviderManager _providerManager; + private readonly IXmlReaderSettingsFactory _xmlSettings; - public EpisodeXmlProvider(IFileSystem fileSystem, ILogger logger, IProviderManager providerManager) + public EpisodeXmlProvider(IFileSystem fileSystem, ILogger logger, IProviderManager providerManager, IXmlReaderSettingsFactory xmlSettings) : base(fileSystem) { _logger = logger; _providerManager = providerManager; + _xmlSettings = xmlSettings; } protected override void Fetch(MetadataResult<Episode> result, string path, CancellationToken cancellationToken) @@ -27,7 +32,7 @@ namespace MediaBrowser.LocalMetadata.Providers var images = new List<LocalImageInfo>(); var chapters = new List<ChapterInfo>(); - new EpisodeXmlParser(_logger, FileSystem, _providerManager).Fetch(result, images, path, cancellationToken); + new EpisodeXmlParser(_logger, FileSystem, _providerManager, _xmlSettings).Fetch(result, images, path, cancellationToken); result.Images = images; } diff --git a/MediaBrowser.LocalMetadata/Providers/FolderXmlProvider.cs b/MediaBrowser.LocalMetadata/Providers/FolderXmlProvider.cs index 7ac41e5cc..45cd8eb93 100644 --- a/MediaBrowser.LocalMetadata/Providers/FolderXmlProvider.cs +++ b/MediaBrowser.LocalMetadata/Providers/FolderXmlProvider.cs @@ -1,9 +1,13 @@ using System.IO; using System.Threading; -using CommonIO; +using MediaBrowser.Common.IO; +using MediaBrowser.Model.IO; using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.IO; using MediaBrowser.Controller.Providers; +using MediaBrowser.LocalMetadata.Parsers; using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Xml; namespace MediaBrowser.LocalMetadata.Providers { @@ -14,17 +18,19 @@ namespace MediaBrowser.LocalMetadata.Providers { private readonly ILogger _logger; private readonly IProviderManager _providerManager; + protected IXmlReaderSettingsFactory XmlReaderSettingsFactory { get; private set; } - public FolderXmlProvider(IFileSystem fileSystem, ILogger logger, IProviderManager providerManager) + public FolderXmlProvider(IFileSystem fileSystem, ILogger logger, IProviderManager providerManager, IXmlReaderSettingsFactory xmlReaderSettingsFactory) : base(fileSystem) { _logger = logger; _providerManager = providerManager; + XmlReaderSettingsFactory = xmlReaderSettingsFactory; } protected override void Fetch(MetadataResult<Folder> result, string path, CancellationToken cancellationToken) { - new BaseItemXmlParser<Folder>(_logger, _providerManager).Fetch(result, path, cancellationToken); + new BaseItemXmlParser<Folder>(_logger, _providerManager, XmlReaderSettingsFactory, FileSystem).Fetch(result, path, cancellationToken); } protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService) diff --git a/MediaBrowser.LocalMetadata/Providers/GameSystemXmlProvider.cs b/MediaBrowser.LocalMetadata/Providers/GameSystemXmlProvider.cs index 942befb83..8054b1204 100644 --- a/MediaBrowser.LocalMetadata/Providers/GameSystemXmlProvider.cs +++ b/MediaBrowser.LocalMetadata/Providers/GameSystemXmlProvider.cs @@ -1,10 +1,13 @@ using System.IO; using System.Threading; -using CommonIO; +using MediaBrowser.Common.IO; +using MediaBrowser.Model.IO; using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.IO; using MediaBrowser.Controller.Providers; using MediaBrowser.LocalMetadata.Parsers; using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Xml; namespace MediaBrowser.LocalMetadata.Providers { @@ -12,17 +15,19 @@ namespace MediaBrowser.LocalMetadata.Providers { private readonly ILogger _logger; private readonly IProviderManager _providerManager; + private readonly IXmlReaderSettingsFactory _xmlSettings; - public GameSystemXmlProvider(IFileSystem fileSystem, ILogger logger, IProviderManager providerManager) + public GameSystemXmlProvider(IFileSystem fileSystem, ILogger logger, IProviderManager providerManager, IXmlReaderSettingsFactory xmlSettings) : base(fileSystem) { _logger = logger; _providerManager = providerManager; + _xmlSettings = xmlSettings; } protected override void Fetch(MetadataResult<GameSystem> result, string path, CancellationToken cancellationToken) { - new GameSystemXmlParser(_logger, _providerManager).Fetch(result, path, cancellationToken); + new GameSystemXmlParser(_logger, _providerManager, _xmlSettings, FileSystem).Fetch(result, path, cancellationToken); } protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService) diff --git a/MediaBrowser.LocalMetadata/Providers/GameXmlProvider.cs b/MediaBrowser.LocalMetadata/Providers/GameXmlProvider.cs index c562df7fb..888eff416 100644 --- a/MediaBrowser.LocalMetadata/Providers/GameXmlProvider.cs +++ b/MediaBrowser.LocalMetadata/Providers/GameXmlProvider.cs @@ -4,7 +4,10 @@ using MediaBrowser.LocalMetadata.Parsers; using MediaBrowser.Model.Logging; using System.IO; using System.Threading; -using CommonIO; +using MediaBrowser.Common.IO; +using MediaBrowser.Controller.IO; +using MediaBrowser.Model.IO; +using MediaBrowser.Model.Xml; namespace MediaBrowser.LocalMetadata.Providers { @@ -12,17 +15,19 @@ namespace MediaBrowser.LocalMetadata.Providers { private readonly ILogger _logger; private readonly IProviderManager _providerManager; + private readonly IXmlReaderSettingsFactory _xmlSettings; - public GameXmlProvider(IFileSystem fileSystem, ILogger logger, IProviderManager providerManager) + public GameXmlProvider(IFileSystem fileSystem, ILogger logger, IProviderManager providerManager, IXmlReaderSettingsFactory xmlSettings) : base(fileSystem) { _logger = logger; _providerManager = providerManager; + _xmlSettings = xmlSettings; } protected override void Fetch(MetadataResult<Game> result, string path, CancellationToken cancellationToken) { - new GameXmlParser(_logger, _providerManager).Fetch(result, path, cancellationToken); + new GameXmlParser(_logger, _providerManager, _xmlSettings, FileSystem).Fetch(result, path, cancellationToken); } protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService) diff --git a/MediaBrowser.LocalMetadata/Providers/MovieXmlProvider.cs b/MediaBrowser.LocalMetadata/Providers/MovieXmlProvider.cs index 333ea2823..0e59db75f 100644 --- a/MediaBrowser.LocalMetadata/Providers/MovieXmlProvider.cs +++ b/MediaBrowser.LocalMetadata/Providers/MovieXmlProvider.cs @@ -4,7 +4,10 @@ using MediaBrowser.LocalMetadata.Parsers; using MediaBrowser.Model.Logging; using System.IO; using System.Threading; -using CommonIO; +using MediaBrowser.Common.IO; +using MediaBrowser.Controller.IO; +using MediaBrowser.Model.IO; +using MediaBrowser.Model.Xml; namespace MediaBrowser.LocalMetadata.Providers { @@ -12,17 +15,19 @@ namespace MediaBrowser.LocalMetadata.Providers { private readonly ILogger _logger; private readonly IProviderManager _providerManager; + protected IXmlReaderSettingsFactory XmlReaderSettingsFactory { get; private set; } - public MovieXmlProvider(IFileSystem fileSystem, ILogger logger, IProviderManager providerManager) + public MovieXmlProvider(IFileSystem fileSystem, ILogger logger, IProviderManager providerManager, IXmlReaderSettingsFactory xmlReaderSettingsFactory) : base(fileSystem) { _logger = logger; _providerManager = providerManager; + XmlReaderSettingsFactory = xmlReaderSettingsFactory; } protected override void Fetch(MetadataResult<Movie> result, string path, CancellationToken cancellationToken) { - new MovieXmlParser(_logger, _providerManager).Fetch(result, path, cancellationToken); + new MovieXmlParser(_logger, _providerManager, XmlReaderSettingsFactory, FileSystem).Fetch(result, path, cancellationToken); } protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService) diff --git a/MediaBrowser.LocalMetadata/Providers/MusicVideoXmlProvider.cs b/MediaBrowser.LocalMetadata/Providers/MusicVideoXmlProvider.cs index 49d8c09cc..e0bbb119f 100644 --- a/MediaBrowser.LocalMetadata/Providers/MusicVideoXmlProvider.cs +++ b/MediaBrowser.LocalMetadata/Providers/MusicVideoXmlProvider.cs @@ -1,9 +1,12 @@ using System.Threading; -using CommonIO; +using MediaBrowser.Common.IO; +using MediaBrowser.Model.IO; using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.IO; using MediaBrowser.Controller.Providers; using MediaBrowser.LocalMetadata.Parsers; using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Xml; namespace MediaBrowser.LocalMetadata.Providers { @@ -11,17 +14,19 @@ namespace MediaBrowser.LocalMetadata.Providers { private readonly ILogger _logger; private readonly IProviderManager _providerManager; + protected IXmlReaderSettingsFactory XmlReaderSettingsFactory { get; private set; } - public MusicVideoXmlProvider(IFileSystem fileSystem, ILogger logger, IProviderManager providerManager) + public MusicVideoXmlProvider(IFileSystem fileSystem, ILogger logger, IProviderManager providerManager, IXmlReaderSettingsFactory xmlReaderSettingsFactory) : base(fileSystem) { _logger = logger; _providerManager = providerManager; + XmlReaderSettingsFactory = xmlReaderSettingsFactory; } protected override void Fetch(MetadataResult<MusicVideo> result, string path, CancellationToken cancellationToken) { - new MusicVideoXmlParser(_logger, _providerManager).Fetch(result, path, cancellationToken); + new MusicVideoXmlParser(_logger, _providerManager, XmlReaderSettingsFactory, FileSystem).Fetch(result, path, cancellationToken); } protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService) diff --git a/MediaBrowser.LocalMetadata/Providers/PersonXmlProvider.cs b/MediaBrowser.LocalMetadata/Providers/PersonXmlProvider.cs deleted file mode 100644 index 2ccb8968b..000000000 --- a/MediaBrowser.LocalMetadata/Providers/PersonXmlProvider.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System.IO; -using System.Threading; -using CommonIO; -using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Providers; -using MediaBrowser.Model.Logging; - -namespace MediaBrowser.LocalMetadata.Providers -{ - public class PersonXmlProvider : BaseXmlProvider<Person> - { - private readonly ILogger _logger; - private readonly IProviderManager _providerManager; - - public PersonXmlProvider(IFileSystem fileSystem, ILogger logger, IProviderManager providerManager) - : base(fileSystem) - { - _logger = logger; - _providerManager = providerManager; - } - - protected override void Fetch(MetadataResult<Person> result, string path, CancellationToken cancellationToken) - { - new BaseItemXmlParser<Person>(_logger, _providerManager).Fetch(result, path, cancellationToken); - } - - protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService) - { - return directoryService.GetFile(Path.Combine(info.Path, "person.xml")); - } - } -} diff --git a/MediaBrowser.LocalMetadata/Providers/PlaylistXmlProvider.cs b/MediaBrowser.LocalMetadata/Providers/PlaylistXmlProvider.cs index 149a3142d..cd839f9cc 100644 --- a/MediaBrowser.LocalMetadata/Providers/PlaylistXmlProvider.cs +++ b/MediaBrowser.LocalMetadata/Providers/PlaylistXmlProvider.cs @@ -4,7 +4,10 @@ using MediaBrowser.LocalMetadata.Parsers; using MediaBrowser.Model.Logging; using System.IO; using System.Threading; -using CommonIO; +using MediaBrowser.Common.IO; +using MediaBrowser.Controller.IO; +using MediaBrowser.Model.IO; +using MediaBrowser.Model.Xml; namespace MediaBrowser.LocalMetadata.Providers { @@ -12,17 +15,19 @@ namespace MediaBrowser.LocalMetadata.Providers { private readonly ILogger _logger; private readonly IProviderManager _providerManager; + protected IXmlReaderSettingsFactory XmlReaderSettingsFactory { get; private set; } - public PlaylistXmlProvider(IFileSystem fileSystem, ILogger logger, IProviderManager providerManager) + public PlaylistXmlProvider(IFileSystem fileSystem, ILogger logger, IProviderManager providerManager, IXmlReaderSettingsFactory xmlReaderSettingsFactory) : base(fileSystem) { _logger = logger; _providerManager = providerManager; + XmlReaderSettingsFactory = xmlReaderSettingsFactory; } protected override void Fetch(MetadataResult<Playlist> result, string path, CancellationToken cancellationToken) { - new PlaylistXmlParser(_logger, _providerManager).Fetch(result, path, cancellationToken); + new PlaylistXmlParser(_logger, _providerManager, XmlReaderSettingsFactory, FileSystem).Fetch(result, path, cancellationToken); } protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService) diff --git a/MediaBrowser.LocalMetadata/Providers/SeriesXmlProvider.cs b/MediaBrowser.LocalMetadata/Providers/SeriesXmlProvider.cs index 26d3c7539..ce006ef38 100644 --- a/MediaBrowser.LocalMetadata/Providers/SeriesXmlProvider.cs +++ b/MediaBrowser.LocalMetadata/Providers/SeriesXmlProvider.cs @@ -1,10 +1,13 @@ using System.IO; using System.Threading; -using CommonIO; +using MediaBrowser.Common.IO; +using MediaBrowser.Model.IO; using MediaBrowser.Controller.Entities.TV; +using MediaBrowser.Controller.IO; using MediaBrowser.Controller.Providers; using MediaBrowser.LocalMetadata.Parsers; using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Xml; namespace MediaBrowser.LocalMetadata.Providers { @@ -15,17 +18,19 @@ namespace MediaBrowser.LocalMetadata.Providers { private readonly ILogger _logger; private readonly IProviderManager _providerManager; + protected IXmlReaderSettingsFactory XmlReaderSettingsFactory { get; private set; } - public SeriesXmlProvider(IFileSystem fileSystem, ILogger logger, IProviderManager providerManager) + public SeriesXmlProvider(IFileSystem fileSystem, ILogger logger, IProviderManager providerManager, IXmlReaderSettingsFactory xmlReaderSettingsFactory) : base(fileSystem) { _logger = logger; _providerManager = providerManager; + XmlReaderSettingsFactory = xmlReaderSettingsFactory; } protected override void Fetch(MetadataResult<Series> result, string path, CancellationToken cancellationToken) { - new SeriesXmlParser(_logger, _providerManager).Fetch(result, path, cancellationToken); + new SeriesXmlParser(_logger, _providerManager, XmlReaderSettingsFactory, FileSystem).Fetch(result, path, cancellationToken); } protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService) diff --git a/MediaBrowser.LocalMetadata/Providers/VideoXmlProvider.cs b/MediaBrowser.LocalMetadata/Providers/VideoXmlProvider.cs index 50f3bcda4..4a7149657 100644 --- a/MediaBrowser.LocalMetadata/Providers/VideoXmlProvider.cs +++ b/MediaBrowser.LocalMetadata/Providers/VideoXmlProvider.cs @@ -3,7 +3,10 @@ using MediaBrowser.Controller.Providers; using MediaBrowser.LocalMetadata.Parsers; using MediaBrowser.Model.Logging; using System.Threading; -using CommonIO; +using MediaBrowser.Common.IO; +using MediaBrowser.Controller.IO; +using MediaBrowser.Model.IO; +using MediaBrowser.Model.Xml; namespace MediaBrowser.LocalMetadata.Providers { @@ -11,17 +14,19 @@ namespace MediaBrowser.LocalMetadata.Providers { private readonly ILogger _logger; private readonly IProviderManager _providerManager; + protected IXmlReaderSettingsFactory XmlReaderSettingsFactory { get; private set; } - public VideoXmlProvider(IFileSystem fileSystem, ILogger logger, IProviderManager providerManager) + public VideoXmlProvider(IFileSystem fileSystem, ILogger logger, IProviderManager providerManager, IXmlReaderSettingsFactory xmlReaderSettingsFactory) : base(fileSystem) { _logger = logger; _providerManager = providerManager; + XmlReaderSettingsFactory = xmlReaderSettingsFactory; } protected override void Fetch(MetadataResult<Video> result, string path, CancellationToken cancellationToken) { - new VideoXmlParser(_logger, _providerManager).Fetch(result, path, cancellationToken); + new VideoXmlParser(_logger, _providerManager, XmlReaderSettingsFactory, FileSystem).Fetch(result, path, cancellationToken); } protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService) diff --git a/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs b/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs new file mode 100644 index 000000000..b52bae2ce --- /dev/null +++ b/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs @@ -0,0 +1,752 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Security; +using System.Text; +using System.Threading; +using System.Xml; +using MediaBrowser.Common.Extensions; +using MediaBrowser.Controller.Configuration; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities.Audio; +using MediaBrowser.Controller.Entities.Movies; +using MediaBrowser.Controller.Entities.TV; +using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Persistence; +using MediaBrowser.Controller.Playlists; +using MediaBrowser.Model.Configuration; +using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Extensions; +using MediaBrowser.Model.IO; +using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Xml; + +namespace MediaBrowser.LocalMetadata.Savers +{ + public abstract class BaseXmlSaver : IMetadataFileSaver + { + private static readonly CultureInfo UsCulture = new CultureInfo("en-US"); + + private static readonly Dictionary<string, string> 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", + "OriginalTitle", + "LockData", + "LockedFields", + "Format3D", + "Metascore", + + // Deprecated. No longer saving in this field. + "MPAARating", + + "MPAADescription", + + "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", + "PlaylistItems", + "Shares" + + }.ToDictionary(i => i, StringComparer.OrdinalIgnoreCase); + + public BaseXmlSaver(IFileSystem fileSystem, IServerConfigurationManager configurationManager, ILibraryManager libraryManager, IUserManager userManager, IUserDataManager userDataManager, ILogger logger, IXmlReaderSettingsFactory xmlReaderSettingsFactory) + { + FileSystem = fileSystem; + ConfigurationManager = configurationManager; + LibraryManager = libraryManager; + UserManager = userManager; + UserDataManager = userDataManager; + Logger = logger; + XmlReaderSettingsFactory = xmlReaderSettingsFactory; + } + + protected IFileSystem FileSystem { get; private set; } + protected IServerConfigurationManager ConfigurationManager { get; private set; } + protected ILibraryManager LibraryManager { get; private set; } + protected IUserManager UserManager { get; private set; } + protected IUserDataManager UserDataManager { get; private set; } + protected ILogger Logger { get; private set; } + protected IXmlReaderSettingsFactory XmlReaderSettingsFactory { get; private set; } + + protected ItemUpdateType MinimumUpdateType + { + get + { + return ItemUpdateType.MetadataDownload; + } + } + + public string Name + { + get + { + return XmlProviderUtils.Name; + } + } + + public string GetSavePath(IHasMetadata item) + { + return GetLocalSavePath(item); + } + + /// <summary> + /// Gets the save path. + /// </summary> + /// <param name="item">The item.</param> + /// <returns>System.String.</returns> + protected abstract string GetLocalSavePath(IHasMetadata item); + + /// <summary> + /// Gets the name of the root element. + /// </summary> + /// <param name="item">The item.</param> + /// <returns>System.String.</returns> + protected virtual string GetRootElementName(IHasMetadata item) + { + return "Item"; + } + + /// <summary> + /// Determines whether [is enabled for] [the specified item]. + /// </summary> + /// <param name="item">The item.</param> + /// <param name="updateType">Type of the update.</param> + /// <returns><c>true</c> if [is enabled for] [the specified item]; otherwise, <c>false</c>.</returns> + public abstract bool IsEnabledFor(IHasMetadata item, ItemUpdateType updateType); + + protected virtual List<string> GetTagsUsed() + { + return new List<string>(); + } + + public void Save(IHasMetadata item, CancellationToken cancellationToken) + { + var path = GetSavePath(item); + + using (var memoryStream = new MemoryStream()) + { + Save(item, memoryStream, path); + + memoryStream.Position = 0; + + cancellationToken.ThrowIfCancellationRequested(); + + SaveToFile(memoryStream, path); + } + } + + private void SaveToFile(Stream stream, string path) + { + FileSystem.CreateDirectory(Path.GetDirectoryName(path)); + + var file = FileSystem.GetFileInfo(path); + + var wasHidden = false; + + // This will fail if the file is hidden + if (file.Exists) + { + if (file.IsHidden) + { + FileSystem.SetHidden(path, false); + wasHidden = true; + } + if (file.IsReadOnly) + { + FileSystem.SetReadOnly(path, false); + } + } + + using (var filestream = FileSystem.GetFileStream(path, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read)) + { + stream.CopyTo(filestream); + } + + if (wasHidden || ConfigurationManager.Configuration.SaveMetadataHidden) + { + FileSystem.SetHidden(path, true); + } + } + + private void Save(IHasMetadata item, Stream stream, string xmlPath) + { + var settings = new XmlWriterSettings + { + Indent = true, + Encoding = Encoding.UTF8, + CloseOutput = false + }; + + using (XmlWriter writer = XmlWriter.Create(stream, settings)) + { + var root = GetRootElementName(item); + + writer.WriteStartDocument(true); + + writer.WriteStartElement(root); + + var baseItem = item as BaseItem; + + if (baseItem != null) + { + AddCommonNodes(baseItem, writer, LibraryManager, UserManager, UserDataManager, FileSystem, ConfigurationManager); + } + + WriteCustomElements(item, writer); + + var tagsUsed = GetTagsUsed(); + + try + { + AddCustomTags(xmlPath, tagsUsed, writer, Logger, FileSystem); + } + catch (FileNotFoundException) + { + + } + catch (IOException) + { + + } + catch (XmlException ex) + { + Logger.ErrorException("Error reading existng xml", ex); + } + + writer.WriteEndElement(); + + writer.WriteEndDocument(); + } + } + + protected abstract void WriteCustomElements(IHasMetadata item, XmlWriter writer); + + public const string DateAddedFormat = "yyyy-MM-dd HH:mm:ss"; + + /// <summary> + /// Adds the common nodes. + /// </summary> + /// <returns>Task.</returns> + public static void AddCommonNodes(BaseItem item, XmlWriter writer, ILibraryManager libraryManager, IUserManager userManager, IUserDataManager userDataRepo, IFileSystem fileSystem, IServerConfigurationManager config) + { + var writtenProviderIds = new HashSet<string>(StringComparer.OrdinalIgnoreCase); + + if (!string.IsNullOrEmpty(item.OfficialRating)) + { + writer.WriteElementString("ContentRating", item.OfficialRating); + } + + if (!string.IsNullOrEmpty(item.OfficialRatingDescription)) + { + writer.WriteElementString("MPAADescription", item.OfficialRatingDescription); + } + + writer.WriteElementString("Added", item.DateCreated.ToLocalTime().ToString("G")); + + writer.WriteElementString("LockData", item.IsLocked.ToString().ToLower()); + + if (item.LockedFields.Count > 0) + { + writer.WriteElementString("LockedFields", string.Join("|", item.LockedFields.Select(i => i.ToString()).ToArray())); + } + + if (!string.IsNullOrEmpty(item.DisplayMediaType)) + { + writer.WriteElementString("Type", item.DisplayMediaType); + } + + if (item.CriticRating.HasValue) + { + writer.WriteElementString("CriticRating", item.CriticRating.Value.ToString(UsCulture)); + } + + if (!string.IsNullOrEmpty(item.CriticRatingSummary)) + { + writer.WriteElementString("CriticRatingSummary", item.CriticRatingSummary); + } + + if (!string.IsNullOrEmpty(item.Overview)) + { + writer.WriteElementString("Overview", item.Overview); + } + + if (!string.IsNullOrEmpty(item.OriginalTitle)) + { + writer.WriteElementString("OriginalTitle", item.OriginalTitle); + } + if (!string.IsNullOrEmpty(item.ShortOverview)) + { + writer.WriteElementString("ShortOverview", item.ShortOverview); + } + if (!string.IsNullOrEmpty(item.CustomRating)) + { + writer.WriteElementString("CustomRating", item.CustomRating); + } + + if (!string.IsNullOrEmpty(item.Name) && !(item is Episode)) + { + writer.WriteElementString("LocalTitle", item.Name); + } + + if (!string.IsNullOrEmpty(item.ForcedSortName)) + { + writer.WriteElementString("SortTitle", item.ForcedSortName); + } + + if (item.PremiereDate.HasValue) + { + if (item is Person) + { + writer.WriteElementString("BirthDate", item.PremiereDate.Value.ToLocalTime().ToString("yyyy-MM-dd")); + } + else if (!(item is Episode)) + { + writer.WriteElementString("PremiereDate", item.PremiereDate.Value.ToLocalTime().ToString("yyyy-MM-dd")); + } + } + + if (item.EndDate.HasValue) + { + if (item is Person) + { + writer.WriteElementString("DeathDate", item.EndDate.Value.ToLocalTime().ToString("yyyy-MM-dd")); + } + else if (!(item is Episode)) + { + writer.WriteElementString("EndDate", item.EndDate.Value.ToLocalTime().ToString("yyyy-MM-dd")); + } + } + + var hasTrailers = item as IHasTrailers; + if (hasTrailers != null) + { + if (hasTrailers.RemoteTrailers.Count > 0) + { + writer.WriteStartElement("Trailers"); + + foreach (var trailer in hasTrailers.RemoteTrailers) + { + writer.WriteElementString("Trailer", trailer.Url); + } + + writer.WriteEndElement(); + } + } + + if (item.ProductionLocations.Count > 0) + { + writer.WriteStartElement("Countries"); + + foreach (var name in item.ProductionLocations) + { + writer.WriteElementString("Country", name); + } + + writer.WriteEndElement(); + } + + var hasDisplayOrder = item as IHasDisplayOrder; + if (hasDisplayOrder != null && !string.IsNullOrEmpty(hasDisplayOrder.DisplayOrder)) + { + writer.WriteElementString("DisplayOrder", hasDisplayOrder.DisplayOrder); + } + + var hasMetascore = item as IHasMetascore; + if (hasMetascore != null && hasMetascore.Metascore.HasValue) + { + writer.WriteElementString("Metascore", hasMetascore.Metascore.Value.ToString(UsCulture)); + } + + var hasAwards = item as IHasAwards; + if (hasAwards != null && !string.IsNullOrEmpty(hasAwards.AwardSummary)) + { + writer.WriteElementString("AwardSummary", hasAwards.AwardSummary); + } + + var hasBudget = item as IHasBudget; + if (hasBudget != null) + { + if (hasBudget.Budget.HasValue) + { + writer.WriteElementString("Budget", hasBudget.Budget.Value.ToString(UsCulture)); + } + + if (hasBudget.Revenue.HasValue) + { + writer.WriteElementString("Revenue", hasBudget.Revenue.Value.ToString(UsCulture)); + } + } + + if (item.CommunityRating.HasValue) + { + writer.WriteElementString("Rating", item.CommunityRating.Value.ToString(UsCulture)); + } + if (item.VoteCount.HasValue) + { + writer.WriteElementString("VoteCount", item.VoteCount.Value.ToString(UsCulture)); + } + + if (item.ProductionYear.HasValue && !(item is Person)) + { + writer.WriteElementString("ProductionYear", item.ProductionYear.Value.ToString(UsCulture)); + } + + if (!string.IsNullOrEmpty(item.HomePageUrl)) + { + writer.WriteElementString("Website", item.HomePageUrl); + } + + var hasAspectRatio = item as IHasAspectRatio; + if (hasAspectRatio != null) + { + if (!string.IsNullOrEmpty(hasAspectRatio.AspectRatio)) + { + writer.WriteElementString("AspectRatio", hasAspectRatio.AspectRatio); + } + } + + if (!string.IsNullOrEmpty(item.PreferredMetadataLanguage)) + { + writer.WriteElementString("Language", item.PreferredMetadataLanguage); + } + if (!string.IsNullOrEmpty(item.PreferredMetadataCountryCode)) + { + writer.WriteElementString("CountryCode", item.PreferredMetadataCountryCode); + } + + // Use original runtime here, actual file runtime later in MediaInfo + var runTimeTicks = item.RunTimeTicks; + + if (runTimeTicks.HasValue) + { + var timespan = TimeSpan.FromTicks(runTimeTicks.Value); + + writer.WriteElementString("RunningTime", Convert.ToInt32(timespan.TotalMinutes).ToString(UsCulture)); + } + + if (item.ProviderIds != null) + { + foreach (var providerKey in item.ProviderIds.Keys) + { + var providerId = item.ProviderIds[providerKey]; + if (!string.IsNullOrEmpty(providerId)) + { + writer.WriteElementString(providerKey + "Id", providerId); + } + } + } + + if (!string.IsNullOrWhiteSpace(item.Tagline)) + { + writer.WriteStartElement("Taglines"); + writer.WriteElementString("Tagline", item.Tagline); + writer.WriteEndElement(); + } + + if (item.Genres.Count > 0) + { + writer.WriteStartElement("Genres"); + + foreach (var genre in item.Genres) + { + writer.WriteElementString("Genre", genre); + } + + writer.WriteEndElement(); + } + + if (item.Studios.Count > 0) + { + writer.WriteStartElement("Studios"); + + foreach (var studio in item.Studios) + { + writer.WriteElementString("Studio", studio); + } + + writer.WriteEndElement(); + } + + if (item.Tags.Count > 0) + { + writer.WriteStartElement("Tags"); + + foreach (var tag in item.Tags) + { + writer.WriteElementString("Tag", tag); + } + + writer.WriteEndElement(); + } + + if (item.Keywords.Count > 0) + { + writer.WriteStartElement("PlotKeywords"); + + foreach (var tag in item.Keywords) + { + writer.WriteElementString("PlotKeyword", tag); + } + + writer.WriteEndElement(); + } + + var people = libraryManager.GetPeople(item); + + if (people.Count > 0) + { + writer.WriteStartElement("Persons"); + + foreach (var person in people) + { + writer.WriteStartElement("Person"); + writer.WriteElementString("Name", person.Name); + writer.WriteElementString("Type", person.Type); + writer.WriteElementString("Role", person.Role); + + if (person.SortOrder.HasValue) + { + writer.WriteElementString("SortOrder", person.SortOrder.Value.ToString(UsCulture)); + } + + writer.WriteEndElement(); + } + + writer.WriteEndElement(); + } + + var boxset = item as BoxSet; + if (boxset != null) + { + AddLinkedChildren(boxset, writer, "CollectionItems", "CollectionItem"); + } + + var playlist = item as Playlist; + if (playlist != null) + { + AddLinkedChildren(playlist, writer, "PlaylistItems", "PlaylistItem"); + } + + var hasShares = item as IHasShares; + if (hasShares != null) + { + AddShares(hasShares, writer); + } + + AddMediaInfo(item, writer); + } + + public static void AddShares(IHasShares item, XmlWriter writer) + { + writer.WriteStartElement("Shares"); + + foreach (var share in item.Shares) + { + writer.WriteStartElement("Share"); + + writer.WriteElementString("UserId", share.UserId); + writer.WriteElementString("CanEdit", share.CanEdit.ToString().ToLower()); + + writer.WriteEndElement(); + } + + writer.WriteEndElement(); + } + + /// <summary> + /// Appends the media info. + /// </summary> + /// <typeparam name="T"></typeparam> + public static void AddMediaInfo<T>(T item, XmlWriter writer) + where T : BaseItem + { + var video = item as Video; + + if (video != null) + { + if (video.Video3DFormat.HasValue) + { + switch (video.Video3DFormat.Value) + { + case Video3DFormat.FullSideBySide: + writer.WriteElementString("Format3D", "FSBS"); + break; + case Video3DFormat.FullTopAndBottom: + writer.WriteElementString("Format3D", "FTAB"); + break; + case Video3DFormat.HalfSideBySide: + writer.WriteElementString("Format3D", "HSBS"); + break; + case Video3DFormat.HalfTopAndBottom: + writer.WriteElementString("Format3D", "HTAB"); + break; + case Video3DFormat.MVC: + writer.WriteElementString("Format3D", "MVC"); + break; + } + } + } + } + + public static void AddLinkedChildren(Folder item, XmlWriter writer, string pluralNodeName, string singularNodeName) + { + var items = item.LinkedChildren + .Where(i => i.Type == LinkedChildType.Manual) + .ToList(); + + if (items.Count == 0) + { + return; + } + + writer.WriteStartElement(pluralNodeName); + + foreach (var link in items) + { + if (!string.IsNullOrWhiteSpace(link.Path)) + { + writer.WriteStartElement(singularNodeName); + writer.WriteElementString("Path", link.Path); + writer.WriteEndElement(); + } + } + + writer.WriteEndElement(); + } + + private static bool IsPersonType(PersonInfo person, string type) + { + return string.Equals(person.Type, type, StringComparison.OrdinalIgnoreCase) || string.Equals(person.Role, type, StringComparison.OrdinalIgnoreCase); + } + + private void AddCustomTags(string path, List<string> xmlTagsUsed, XmlWriter writer, ILogger logger, IFileSystem fileSystem) + { + var settings = XmlReaderSettingsFactory.Create(false); + + settings.CheckCharacters = false; + settings.IgnoreProcessingInstructions = true; + settings.IgnoreComments = true; + + using (var fileStream = fileSystem.OpenRead(path)) + { + using (var streamReader = new StreamReader(fileStream, Encoding.UTF8)) + { + // Use XmlReader for best performance + using (var reader = XmlReader.Create(streamReader, settings)) + { + try + { + reader.MoveToContent(); + } + catch (Exception ex) + { + logger.ErrorException("Error reading existing xml tags from {0}.", ex, path); + return; + } + + reader.Read(); + + // Loop through each element + while (!reader.EOF && reader.ReadState == ReadState.Interactive) + { + if (reader.NodeType == XmlNodeType.Element) + { + var name = reader.Name; + + if (!CommonTags.ContainsKey(name) && !xmlTagsUsed.Contains(name, StringComparer.OrdinalIgnoreCase)) + { + writer.WriteNode(reader, false); + } + else + { + reader.Skip(); + } + } + else + { + reader.Read(); + } + } + } + } + } + } + } +} diff --git a/MediaBrowser.LocalMetadata/Savers/BoxSetXmlSaver.cs b/MediaBrowser.LocalMetadata/Savers/BoxSetXmlSaver.cs index b307ded97..8167f6002 100644 --- a/MediaBrowser.LocalMetadata/Savers/BoxSetXmlSaver.cs +++ b/MediaBrowser.LocalMetadata/Savers/BoxSetXmlSaver.cs @@ -6,38 +6,18 @@ using System.Collections.Generic; using System.IO; using System.Text; using System.Threading; -using CommonIO; +using System.Xml; +using MediaBrowser.Common.IO; +using MediaBrowser.Controller.IO; +using MediaBrowser.Model.IO; +using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Xml; namespace MediaBrowser.LocalMetadata.Savers { - public class BoxSetXmlSaver : IMetadataFileSaver + public class BoxSetXmlSaver : BaseXmlSaver { - public string Name - { - get - { - return XmlProviderUtils.Name; - } - } - - private readonly IServerConfigurationManager _config; - private readonly ILibraryManager _libraryManager; - private readonly IFileSystem _fileSystem; - - public BoxSetXmlSaver(IServerConfigurationManager config, ILibraryManager libraryManager, IFileSystem fileSystem) - { - _config = config; - _libraryManager = libraryManager; - _fileSystem = fileSystem; - } - - /// <summary> - /// Determines whether [is enabled for] [the specified item]. - /// </summary> - /// <param name="item">The item.</param> - /// <param name="updateType">Type of the update.</param> - /// <returns><c>true</c> if [is enabled for] [the specified item]; otherwise, <c>false</c>.</returns> - public bool IsEnabledFor(IHasMetadata item, ItemUpdateType updateType) + public override bool IsEnabledFor(IHasMetadata item, ItemUpdateType updateType) { if (!item.SupportsLocalMetadata) { @@ -47,35 +27,17 @@ namespace MediaBrowser.LocalMetadata.Savers return item is BoxSet && updateType >= ItemUpdateType.MetadataDownload; } - /// <summary> - /// Saves the specified item. - /// </summary> - /// <param name="item">The item.</param> - /// <param name="cancellationToken">The cancellation token.</param> - /// <returns>Task.</returns> - public void Save(IHasMetadata item, CancellationToken cancellationToken) + protected override void WriteCustomElements(IHasMetadata item, XmlWriter writer) { - var builder = new StringBuilder(); - - builder.Append("<Item>"); - - XmlSaverHelpers.AddCommonNodes((BoxSet)item, _libraryManager, builder); - - builder.Append("</Item>"); - - var xmlFilePath = GetSavePath(item); - - XmlSaverHelpers.Save(builder, xmlFilePath, new List<string>(), _config, _fileSystem); } - /// <summary> - /// Gets the save path. - /// </summary> - /// <param name="item">The item.</param> - /// <returns>System.String.</returns> - public string GetSavePath(IHasMetadata item) + protected override string GetLocalSavePath(IHasMetadata item) { return Path.Combine(item.Path, "collection.xml"); } + + public BoxSetXmlSaver(IFileSystem fileSystem, IServerConfigurationManager configurationManager, ILibraryManager libraryManager, IUserManager userManager, IUserDataManager userDataManager, ILogger logger, IXmlReaderSettingsFactory xmlReaderSettingsFactory) : base(fileSystem, configurationManager, libraryManager, userManager, userDataManager, logger, xmlReaderSettingsFactory) + { + } } } diff --git a/MediaBrowser.LocalMetadata/Savers/FolderXmlSaver.cs b/MediaBrowser.LocalMetadata/Savers/FolderXmlSaver.cs index 8dad16fc2..b51bd5b91 100644 --- a/MediaBrowser.LocalMetadata/Savers/FolderXmlSaver.cs +++ b/MediaBrowser.LocalMetadata/Savers/FolderXmlSaver.cs @@ -9,38 +9,28 @@ using System.Collections.Generic; using System.IO; using System.Text; using System.Threading; -using CommonIO; +using System.Xml; +using MediaBrowser.Common.IO; +using MediaBrowser.Controller.IO; +using MediaBrowser.Model.IO; +using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Xml; namespace MediaBrowser.LocalMetadata.Savers { - public class FolderXmlSaver : IMetadataFileSaver + public class FolderXmlSaver : BaseXmlSaver { - public string Name + protected override string GetLocalSavePath(IHasMetadata item) { - get - { - return XmlProviderUtils.Name; - } + return Path.Combine(item.Path, "folder.xml"); } - private readonly IServerConfigurationManager _config; - private readonly ILibraryManager _libraryManager; - private readonly IFileSystem _fileSystem; - - public FolderXmlSaver(IServerConfigurationManager config, ILibraryManager libraryManager, IFileSystem fileSystem) + protected override string GetRootElementName(IHasMetadata item) { - _config = config; - _libraryManager = libraryManager; - _fileSystem = fileSystem; + return "Item"; } - /// <summary> - /// Determines whether [is enabled for] [the specified item]. - /// </summary> - /// <param name="item">The item.</param> - /// <param name="updateType">Type of the update.</param> - /// <returns><c>true</c> if [is enabled for] [the specified item]; otherwise, <c>false</c>.</returns> - public bool IsEnabledFor(IHasMetadata item, ItemUpdateType updateType) + public override bool IsEnabledFor(IHasMetadata item, ItemUpdateType updateType) { if (!item.SupportsLocalMetadata) { @@ -61,35 +51,12 @@ namespace MediaBrowser.LocalMetadata.Savers return false; } - /// <summary> - /// Saves the specified item. - /// </summary> - /// <param name="item">The item.</param> - /// <param name="cancellationToken">The cancellation token.</param> - /// <returns>Task.</returns> - public void Save(IHasMetadata item, CancellationToken cancellationToken) + protected override void WriteCustomElements(IHasMetadata item, XmlWriter writer) { - var builder = new StringBuilder(); - - builder.Append("<Item>"); - - XmlSaverHelpers.AddCommonNodes((Folder)item, _libraryManager, builder); - - builder.Append("</Item>"); - - var xmlFilePath = GetSavePath(item); - - XmlSaverHelpers.Save(builder, xmlFilePath, new List<string>(), _config, _fileSystem); } - /// <summary> - /// Gets the save path. - /// </summary> - /// <param name="item">The item.</param> - /// <returns>System.String.</returns> - public string GetSavePath(IHasMetadata item) + public FolderXmlSaver(IFileSystem fileSystem, IServerConfigurationManager configurationManager, ILibraryManager libraryManager, IUserManager userManager, IUserDataManager userDataManager, ILogger logger, IXmlReaderSettingsFactory xmlReaderSettingsFactory) : base(fileSystem, configurationManager, libraryManager, userManager, userDataManager, logger, xmlReaderSettingsFactory) { - return Path.Combine(item.Path, "folder.xml"); } } } diff --git a/MediaBrowser.LocalMetadata/Savers/GameSystemXmlSaver.cs b/MediaBrowser.LocalMetadata/Savers/GameSystemXmlSaver.cs index ddfaedba6..59b69746a 100644 --- a/MediaBrowser.LocalMetadata/Savers/GameSystemXmlSaver.cs +++ b/MediaBrowser.LocalMetadata/Savers/GameSystemXmlSaver.cs @@ -3,41 +3,20 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; using System.Collections.Generic; using System.IO; -using System.Security; -using System.Text; -using System.Threading; -using CommonIO; +using System.Xml; +using MediaBrowser.Model.IO; +using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Xml; namespace MediaBrowser.LocalMetadata.Savers { - public class GameSystemXmlSaver : IMetadataFileSaver + public class GameSystemXmlSaver : BaseXmlSaver { - public string Name + public GameSystemXmlSaver(IFileSystem fileSystem, IServerConfigurationManager configurationManager, ILibraryManager libraryManager, IUserManager userManager, IUserDataManager userDataManager, ILogger logger, IXmlReaderSettingsFactory xmlReaderSettingsFactory) : base(fileSystem, configurationManager, libraryManager, userManager, userDataManager, logger, xmlReaderSettingsFactory) { - get - { - return XmlProviderUtils.Name; - } } - private readonly IServerConfigurationManager _config; - private readonly ILibraryManager _libraryManager; - private readonly IFileSystem _fileSystem; - - public GameSystemXmlSaver(IServerConfigurationManager config, ILibraryManager libraryManager, IFileSystem fileSystem) - { - _config = config; - _libraryManager = libraryManager; - _fileSystem = fileSystem; - } - - /// <summary> - /// Determines whether [is enabled for] [the specified item]. - /// </summary> - /// <param name="item">The item.</param> - /// <param name="updateType">Type of the update.</param> - /// <returns><c>true</c> if [is enabled for] [the specified item]; otherwise, <c>false</c>.</returns> - public bool IsEnabledFor(IHasMetadata item, ItemUpdateType updateType) + public override bool IsEnabledFor(IHasMetadata item, ItemUpdateType updateType) { if (!item.SupportsLocalMetadata) { @@ -47,42 +26,34 @@ namespace MediaBrowser.LocalMetadata.Savers return item is GameSystem && updateType >= ItemUpdateType.MetadataDownload; } - /// <summary> - /// Saves the specified item. - /// </summary> - /// <param name="item">The item.</param> - /// <param name="cancellationToken">The cancellation token.</param> - /// <returns>Task.</returns> - public void Save(IHasMetadata item, CancellationToken cancellationToken) + protected override List<string> GetTagsUsed() { - var gameSystem = (GameSystem)item; + var list = new List<string> + { + "GameSystem" + }; - var builder = new StringBuilder(); + return list; + } - builder.Append("<Item>"); + protected override void WriteCustomElements(IHasMetadata item, XmlWriter writer) + { + var gameSystem = (GameSystem)item; if (!string.IsNullOrEmpty(gameSystem.GameSystemName)) { - builder.Append("<GameSystem>" + SecurityElement.Escape(gameSystem.GameSystemName) + "</GameSystem>"); + writer.WriteElementString("GameSystem", gameSystem.GameSystemName); } - - XmlSaverHelpers.AddCommonNodes(gameSystem, _libraryManager, builder); - - builder.Append("</Item>"); - - var xmlFilePath = GetSavePath(item); - - XmlSaverHelpers.Save(builder, xmlFilePath, new List<string>(), _config, _fileSystem); } - /// <summary> - /// Gets the save path. - /// </summary> - /// <param name="item">The item.</param> - /// <returns>System.String.</returns> - public string GetSavePath(IHasMetadata item) + protected override string GetLocalSavePath(IHasMetadata item) { return Path.Combine(item.Path, "gamesystem.xml"); } + + protected override string GetRootElementName(IHasMetadata item) + { + return "Item"; + } } } diff --git a/MediaBrowser.LocalMetadata/Savers/GameXmlSaver.cs b/MediaBrowser.LocalMetadata/Savers/GameXmlSaver.cs index 5592c068c..26c4b4a93 100644 --- a/MediaBrowser.LocalMetadata/Savers/GameXmlSaver.cs +++ b/MediaBrowser.LocalMetadata/Savers/GameXmlSaver.cs @@ -4,44 +4,21 @@ using MediaBrowser.Controller.Library; using System.Collections.Generic; using System.Globalization; using System.IO; -using System.Security; -using System.Text; -using System.Threading; -using CommonIO; +using System.Xml; +using MediaBrowser.Model.IO; +using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Xml; namespace MediaBrowser.LocalMetadata.Savers { /// <summary> /// Saves game.xml for games /// </summary> - public class GameXmlSaver : IMetadataFileSaver + public class GameXmlSaver : BaseXmlSaver { - public string Name - { - get - { - return XmlProviderUtils.Name; - } - } - - private readonly IServerConfigurationManager _config; - private readonly ILibraryManager _libraryManager; - private readonly IFileSystem _fileSystem; - - public GameXmlSaver(IServerConfigurationManager config, ILibraryManager libraryManager, IFileSystem fileSystem) - { - _config = config; - _libraryManager = libraryManager; - _fileSystem = fileSystem; - } + private static readonly CultureInfo UsCulture = new CultureInfo("en-US"); - /// <summary> - /// Determines whether [is enabled for] [the specified item]. - /// </summary> - /// <param name="item">The item.</param> - /// <param name="updateType">Type of the update.</param> - /// <returns><c>true</c> if [is enabled for] [the specified item]; otherwise, <c>false</c>.</returns> - public bool IsEnabledFor(IHasMetadata item, ItemUpdateType updateType) + public override bool IsEnabledFor(IHasMetadata item, ItemUpdateType updateType) { if (!item.SupportsLocalMetadata) { @@ -51,52 +28,41 @@ namespace MediaBrowser.LocalMetadata.Savers return item is Game && updateType >= ItemUpdateType.MetadataDownload; } - private static readonly CultureInfo UsCulture = new CultureInfo("en-US"); - - /// <summary> - /// Saves the specified item. - /// </summary> - /// <param name="item">The item.</param> - /// <param name="cancellationToken">The cancellation token.</param> - /// <returns>Task.</returns> - public void Save(IHasMetadata item, CancellationToken cancellationToken) + protected override List<string> GetTagsUsed() { - var builder = new StringBuilder(); + var list = new List<string> + { + "GameSystem", + "Players" + }; - builder.Append("<Item>"); + return list; + } + protected override void WriteCustomElements(IHasMetadata item, XmlWriter writer) + { var game = (Game)item; - if (game.PlayersSupported.HasValue) + if (!string.IsNullOrEmpty(game.GameSystem)) { - builder.Append("<Players>" + SecurityElement.Escape(game.PlayersSupported.Value.ToString(UsCulture)) + "</Players>"); + writer.WriteElementString("GameSystem", game.GameSystem); } - - if (!string.IsNullOrEmpty(game.GameSystem)) + if (game.PlayersSupported.HasValue) { - builder.Append("<GameSystem>" + SecurityElement.Escape(game.GameSystem) + "</GameSystem>"); + writer.WriteElementString("Players", game.PlayersSupported.Value.ToString(UsCulture)); } - - XmlSaverHelpers.AddCommonNodes(game, _libraryManager, builder); - - builder.Append("</Item>"); - - var xmlFilePath = GetSavePath(item); - - XmlSaverHelpers.Save(builder, xmlFilePath, new List<string> - { - "Players", - "GameSystem", - "NesBox", - "NesBoxRom" - }, _config, _fileSystem); } - public string GetSavePath(IHasMetadata item) + protected override string GetLocalSavePath(IHasMetadata item) { return GetGameSavePath((Game)item); } + protected override string GetRootElementName(IHasMetadata item) + { + return "Item"; + } + public static string GetGameSavePath(Game item) { if (item.DetectIsInMixedFolder()) @@ -106,5 +72,9 @@ namespace MediaBrowser.LocalMetadata.Savers return Path.Combine(item.ContainingFolderPath, "game.xml"); } + + public GameXmlSaver(IFileSystem fileSystem, IServerConfigurationManager configurationManager, ILibraryManager libraryManager, IUserManager userManager, IUserDataManager userDataManager, ILogger logger, IXmlReaderSettingsFactory xmlReaderSettingsFactory) : base(fileSystem, configurationManager, libraryManager, userManager, userDataManager, logger, xmlReaderSettingsFactory) + { + } } } diff --git a/MediaBrowser.LocalMetadata/Savers/PersonXmlSaver.cs b/MediaBrowser.LocalMetadata/Savers/PersonXmlSaver.cs index 295e64881..8409e483d 100644 --- a/MediaBrowser.LocalMetadata/Savers/PersonXmlSaver.cs +++ b/MediaBrowser.LocalMetadata/Savers/PersonXmlSaver.cs @@ -3,92 +3,55 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; using System.Collections.Generic; using System.IO; -using System.Security; -using System.Text; -using System.Threading; -using CommonIO; +using System.Xml; +using MediaBrowser.Model.IO; +using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Xml; namespace MediaBrowser.LocalMetadata.Savers { - /// <summary> - /// Class PersonXmlSaver - /// </summary> - public class PersonXmlSaver : IMetadataFileSaver - { - public string Name - { - get - { - return XmlProviderUtils.Name; - } - } - - private readonly IServerConfigurationManager _config; - private readonly ILibraryManager _libraryManager; - private readonly IFileSystem _fileSystem; - - public PersonXmlSaver(IServerConfigurationManager config, ILibraryManager libraryManager, IFileSystem fileSystem) - { - _config = config; - _libraryManager = libraryManager; - _fileSystem = fileSystem; - } - - /// <summary> - /// Determines whether [is enabled for] [the specified item]. - /// </summary> - /// <param name="item">The item.</param> - /// <param name="updateType">Type of the update.</param> - /// <returns><c>true</c> if [is enabled for] [the specified item]; otherwise, <c>false</c>.</returns> - public bool IsEnabledFor(IHasMetadata item, ItemUpdateType updateType) - { - if (!item.SupportsLocalMetadata) - { - return false; - } - - return item is Person && updateType >= ItemUpdateType.MetadataDownload; - } - - /// <summary> - /// Saves the specified item. - /// </summary> - /// <param name="item">The item.</param> - /// <param name="cancellationToken">The cancellation token.</param> - /// <returns>Task.</returns> - public void Save(IHasMetadata item, CancellationToken cancellationToken) - { - var person = (Person)item; - - var builder = new StringBuilder(); - - builder.Append("<Item>"); - - XmlSaverHelpers.AddCommonNodes(person, _libraryManager, builder); - - if (person.ProductionLocations.Count > 0) - { - builder.Append("<PlaceOfBirth>" + SecurityElement.Escape(person.ProductionLocations[0]) + "</PlaceOfBirth>"); - } - - builder.Append("</Item>"); - - var xmlFilePath = GetSavePath(item); - - XmlSaverHelpers.Save(builder, xmlFilePath, new List<string> - { - "PlaceOfBirth" - }, _config, _fileSystem); - } - - /// <summary> - /// Gets the save path. - /// </summary> - /// <param name="item">The item.</param> - /// <returns>System.String.</returns> - public string GetSavePath(IHasMetadata item) - { - return Path.Combine(item.Path, "person.xml"); - } - } + ///// <summary> + ///// Class PersonXmlSaver + ///// </summary> + //public class PersonXmlSaver : BaseXmlSaver + //{ + // public override bool IsEnabledFor(IHasMetadata item, ItemUpdateType updateType) + // { + // if (!item.SupportsLocalMetadata) + // { + // return false; + // } + + // return item is Person && updateType >= ItemUpdateType.MetadataDownload; + // } + + // protected override List<string> GetTagsUsed() + // { + // var list = new List<string> + // { + // "PlaceOfBirth" + // }; + + // return list; + // } + + // protected override void WriteCustomElements(IHasMetadata item, XmlWriter writer) + // { + // var person = (Person)item; + + // if (person.ProductionLocations.Count > 0) + // { + // writer.WriteElementString("PlaceOfBirth", person.ProductionLocations[0]); + // } + // } + + // protected override string GetLocalSavePath(IHasMetadata item) + // { + // return Path.Combine(item.Path, "person.xml"); + // } + + // public PersonXmlSaver(IFileSystem fileSystem, IServerConfigurationManager configurationManager, ILibraryManager libraryManager, IUserManager userManager, IUserDataManager userDataManager, ILogger logger, IXmlReaderSettingsFactory xmlReaderSettingsFactory) : base(fileSystem, configurationManager, libraryManager, userManager, userDataManager, logger, xmlReaderSettingsFactory) + // { + // } + //} } diff --git a/MediaBrowser.LocalMetadata/Savers/PlaylistXmlSaver.cs b/MediaBrowser.LocalMetadata/Savers/PlaylistXmlSaver.cs index 8862f9c03..ef28dde36 100644 --- a/MediaBrowser.LocalMetadata/Savers/PlaylistXmlSaver.cs +++ b/MediaBrowser.LocalMetadata/Savers/PlaylistXmlSaver.cs @@ -4,41 +4,16 @@ using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Playlists; using System.Collections.Generic; using System.IO; -using System.Security; -using System.Text; -using System.Threading; -using CommonIO; +using System.Xml; +using MediaBrowser.Model.IO; +using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Xml; namespace MediaBrowser.LocalMetadata.Savers { - public class PlaylistXmlSaver : IMetadataFileSaver + public class PlaylistXmlSaver : BaseXmlSaver { - public string Name - { - get - { - return XmlProviderUtils.Name; - } - } - - private readonly IServerConfigurationManager _config; - private readonly ILibraryManager _libraryManager; - private readonly IFileSystem _fileSystem; - - public PlaylistXmlSaver(IServerConfigurationManager config, ILibraryManager libraryManager, IFileSystem fileSystem) - { - _config = config; - _libraryManager = libraryManager; - _fileSystem = fileSystem; - } - - /// <summary> - /// Determines whether [is enabled for] [the specified item]. - /// </summary> - /// <param name="item">The item.</param> - /// <param name="updateType">Type of the update.</param> - /// <returns><c>true</c> if [is enabled for] [the specified item]; otherwise, <c>false</c>.</returns> - public bool IsEnabledFor(IHasMetadata item, ItemUpdateType updateType) + public override bool IsEnabledFor(IHasMetadata item, ItemUpdateType updateType) { if (!item.SupportsLocalMetadata) { @@ -48,47 +23,34 @@ namespace MediaBrowser.LocalMetadata.Savers return item is Playlist && updateType >= ItemUpdateType.MetadataImport; } - /// <summary> - /// Saves the specified item. - /// </summary> - /// <param name="item">The item.</param> - /// <param name="cancellationToken">The cancellation token.</param> - /// <returns>Task.</returns> - public void Save(IHasMetadata item, CancellationToken cancellationToken) + protected override List<string> GetTagsUsed() { - var playlist = (Playlist)item; - - var builder = new StringBuilder(); - - builder.Append("<Item>"); - - if (!string.IsNullOrEmpty(playlist.PlaylistMediaType)) + var list = new List<string> { - builder.Append("<PlaylistMediaType>" + SecurityElement.Escape(playlist.PlaylistMediaType) + "</PlaylistMediaType>"); - } - - XmlSaverHelpers.AddCommonNodes(playlist, _libraryManager, builder); + "OwnerUserId", + "PlaylistMediaType" + }; - builder.Append("</Item>"); + return list; + } - var xmlFilePath = GetSavePath(item); + protected override void WriteCustomElements(IHasMetadata item, XmlWriter writer) + { + var game = (Playlist)item; - XmlSaverHelpers.Save(builder, xmlFilePath, new List<string> + if (!string.IsNullOrEmpty(game.PlaylistMediaType)) { - "OwnerUserId", - "PlaylistMediaType" - - }, _config, _fileSystem); + writer.WriteElementString("PlaylistMediaType", game.PlaylistMediaType); + } } - /// <summary> - /// Gets the save path. - /// </summary> - /// <param name="item">The item.</param> - /// <returns>System.String.</returns> - public string GetSavePath(IHasMetadata item) + protected override string GetLocalSavePath(IHasMetadata item) { return Path.Combine(item.Path, "playlist.xml"); } + + public PlaylistXmlSaver(IFileSystem fileSystem, IServerConfigurationManager configurationManager, ILibraryManager libraryManager, IUserManager userManager, IUserDataManager userDataManager, ILogger logger, IXmlReaderSettingsFactory xmlReaderSettingsFactory) : base(fileSystem, configurationManager, libraryManager, userManager, userDataManager, logger, xmlReaderSettingsFactory) + { + } } } diff --git a/MediaBrowser.LocalMetadata/Savers/XmlSaverHelpers.cs b/MediaBrowser.LocalMetadata/Savers/XmlSaverHelpers.cs deleted file mode 100644 index 314840558..000000000 --- a/MediaBrowser.LocalMetadata/Savers/XmlSaverHelpers.cs +++ /dev/null @@ -1,647 +0,0 @@ -using MediaBrowser.Controller.Configuration; -using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Entities.Movies; -using MediaBrowser.Controller.Entities.TV; -using MediaBrowser.Controller.Library; -using MediaBrowser.Controller.Persistence; -using MediaBrowser.Controller.Playlists; -using MediaBrowser.Model.Entities; -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 CommonIO; - -namespace MediaBrowser.LocalMetadata.Savers -{ - /// <summary> - /// Class XmlHelpers - /// </summary> - public static class XmlSaverHelpers - { - private static readonly Dictionary<string, string> 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", - "OriginalTitle", - "LockData", - "LockedFields", - "Format3D", - "Metascore", - - // Deprecated. No longer saving in this field. - "MPAARating", - - "MPAADescription", - - "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", - "PlaylistItems", - "Shares" - - }.ToDictionary(i => i, StringComparer.OrdinalIgnoreCase); - - /// <summary> - /// The us culture - /// </summary> - private static readonly CultureInfo UsCulture = new CultureInfo("en-US"); - - /// <summary> - /// Saves the specified XML. - /// </summary> - /// <param name="xml">The XML.</param> - /// <param name="path">The path.</param> - /// <param name="xmlTagsUsed">The XML tags used.</param> - public static void Save(StringBuilder xml, string path, List<string> xmlTagsUsed, IServerConfigurationManager config, IFileSystem fileSystem) - { - if (fileSystem.FileExists(path)) - { - var position = xml.ToString().LastIndexOf("</", StringComparison.OrdinalIgnoreCase); - xml.Insert(position, GetCustomTags(path, xmlTagsUsed)); - } - - var xmlDocument = new XmlDocument(); - xmlDocument.LoadXml(xml.ToString()); - - //Add the new node to the document. - xmlDocument.InsertBefore(xmlDocument.CreateXmlDeclaration("1.0", "UTF-8", "yes"), xmlDocument.DocumentElement); - - fileSystem.CreateDirectory(Path.GetDirectoryName(path)); - - var wasHidden = false; - - var file = new FileInfo(path); - - // This will fail if the file is hidden - if (file.Exists) - { - if ((file.Attributes & FileAttributes.Hidden) == FileAttributes.Hidden) - { - file.Attributes &= ~FileAttributes.Hidden; - - wasHidden = true; - } - } - - using (var filestream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read)) - { - using (var streamWriter = new StreamWriter(filestream, Encoding.UTF8)) - { - xmlDocument.Save(streamWriter); - } - } - - if (wasHidden || config.Configuration.SaveMetadataHidden) - { - file.Refresh(); - - // Add back the attribute - file.Attributes |= FileAttributes.Hidden; - } - } - - /// <summary> - /// Gets the custom tags. - /// </summary> - /// <param name="path">The path.</param> - /// <param name="xmlTagsUsed">The XML tags used.</param> - /// <returns>System.String.</returns> - private static string GetCustomTags(string path, List<string> 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(); - } - - /// <summary> - /// Adds the common nodes. - /// </summary> - /// <param name="item">The item.</param> - /// <param name="builder">The builder.</param> - public static void AddCommonNodes(BaseItem item, ILibraryManager libraryManager, StringBuilder builder) - { - if (!string.IsNullOrEmpty(item.OfficialRating)) - { - builder.Append("<ContentRating>" + SecurityElement.Escape(item.OfficialRating) + "</ContentRating>"); - } - - if (!string.IsNullOrEmpty(item.OfficialRatingDescription)) - { - builder.Append("<MPAADescription>" + SecurityElement.Escape(item.OfficialRatingDescription) + "</MPAADescription>"); - } - - builder.Append("<Added>" + SecurityElement.Escape(item.DateCreated.ToLocalTime().ToString("G")) + "</Added>"); - - builder.Append("<LockData>" + item.IsLocked.ToString().ToLower() + "</LockData>"); - - if (item.LockedFields.Count > 0) - { - builder.Append("<LockedFields>" + string.Join("|", item.LockedFields.Select(i => i.ToString()).ToArray()) + "</LockedFields>"); - } - - if (!string.IsNullOrEmpty(item.DisplayMediaType)) - { - builder.Append("<Type>" + SecurityElement.Escape(item.DisplayMediaType) + "</Type>"); - } - - if (item.CriticRating.HasValue) - { - builder.Append("<CriticRating>" + SecurityElement.Escape(item.CriticRating.Value.ToString(UsCulture)) + "</CriticRating>"); - } - - if (!string.IsNullOrEmpty(item.CriticRatingSummary)) - { - builder.Append("<CriticRatingSummary><![CDATA[" + item.CriticRatingSummary + "]]></CriticRatingSummary>"); - } - - if (!string.IsNullOrEmpty(item.Overview)) - { - builder.Append("<Overview><![CDATA[" + item.Overview + "]]></Overview>"); - } - - var hasOriginalTitle = item as IHasOriginalTitle; - if (hasOriginalTitle != null) - { - if (!string.IsNullOrEmpty(hasOriginalTitle.OriginalTitle)) - { - builder.Append("<OriginalTitle>" + SecurityElement.Escape(hasOriginalTitle.OriginalTitle) + "</OriginalTitle>"); - } - } - - if (!string.IsNullOrEmpty(item.ShortOverview)) - { - builder.Append("<ShortOverview><![CDATA[" + item.ShortOverview + "]]></ShortOverview>"); - } - - if (!string.IsNullOrEmpty(item.CustomRating)) - { - builder.Append("<CustomRating>" + SecurityElement.Escape(item.CustomRating) + "</CustomRating>"); - } - - if (!string.IsNullOrEmpty(item.Name) && !(item is Episode)) - { - builder.Append("<LocalTitle>" + SecurityElement.Escape(item.Name) + "</LocalTitle>"); - } - - if (!string.IsNullOrEmpty(item.ForcedSortName)) - { - builder.Append("<SortTitle>" + SecurityElement.Escape(item.ForcedSortName) + "</SortTitle>"); - } - - if (item.PremiereDate.HasValue) - { - if (item is Person) - { - builder.Append("<BirthDate>" + SecurityElement.Escape(item.PremiereDate.Value.ToLocalTime().ToString("yyyy-MM-dd")) + "</BirthDate>"); - } - else if (!(item is Episode)) - { - builder.Append("<PremiereDate>" + SecurityElement.Escape(item.PremiereDate.Value.ToLocalTime().ToString("yyyy-MM-dd")) + "</PremiereDate>"); - } - } - - if (item.EndDate.HasValue) - { - if (item is Person) - { - builder.Append("<DeathDate>" + SecurityElement.Escape(item.EndDate.Value.ToString("yyyy-MM-dd")) + "</DeathDate>"); - } - else if (!(item is Episode)) - { - builder.Append("<EndDate>" + SecurityElement.Escape(item.EndDate.Value.ToString("yyyy-MM-dd")) + "</EndDate>"); - } - } - - var hasTrailers = item as IHasTrailers; - if (hasTrailers != null) - { - if (hasTrailers.RemoteTrailers.Count > 0) - { - builder.Append("<Trailers>"); - - foreach (var trailer in hasTrailers.RemoteTrailers) - { - builder.Append("<Trailer>" + SecurityElement.Escape(trailer.Url) + "</Trailer>"); - } - - builder.Append("</Trailers>"); - } - } - - //if (hasProductionLocations.ProductionLocations.Count > 0) - //{ - // builder.Append("<Countries>"); - - // foreach (var name in hasProductionLocations.ProductionLocations) - // { - // builder.Append("<Country>" + SecurityElement.Escape(name) + "</Country>"); - // } - - // builder.Append("</Countries>"); - //} - - var hasDisplayOrder = item as IHasDisplayOrder; - if (hasDisplayOrder != null && !string.IsNullOrEmpty(hasDisplayOrder.DisplayOrder)) - { - builder.Append("<DisplayOrder>" + SecurityElement.Escape(hasDisplayOrder.DisplayOrder) + "</DisplayOrder>"); - } - - var hasMetascore = item as IHasMetascore; - if (hasMetascore != null && hasMetascore.Metascore.HasValue) - { - builder.Append("<Metascore>" + SecurityElement.Escape(hasMetascore.Metascore.Value.ToString(UsCulture)) + "</Metascore>"); - } - - var hasAwards = item as IHasAwards; - if (hasAwards != null && !string.IsNullOrEmpty(hasAwards.AwardSummary)) - { - builder.Append("<AwardSummary>" + SecurityElement.Escape(hasAwards.AwardSummary) + "</AwardSummary>"); - } - - var hasBudget = item as IHasBudget; - if (hasBudget != null) - { - if (hasBudget.Budget.HasValue) - { - builder.Append("<Budget>" + SecurityElement.Escape(hasBudget.Budget.Value.ToString(UsCulture)) + "</Budget>"); - } - - if (hasBudget.Revenue.HasValue) - { - builder.Append("<Revenue>" + SecurityElement.Escape(hasBudget.Revenue.Value.ToString(UsCulture)) + "</Revenue>"); - } - } - - if (item.CommunityRating.HasValue) - { - builder.Append("<Rating>" + SecurityElement.Escape(item.CommunityRating.Value.ToString(UsCulture)) + "</Rating>"); - } - if (item.VoteCount.HasValue) - { - builder.Append("<VoteCount>" + SecurityElement.Escape(item.VoteCount.Value.ToString(UsCulture)) + "</VoteCount>"); - } - - if (item.ProductionYear.HasValue && !(item is Person)) - { - builder.Append("<ProductionYear>" + SecurityElement.Escape(item.ProductionYear.Value.ToString(UsCulture)) + "</ProductionYear>"); - } - - if (!string.IsNullOrEmpty(item.HomePageUrl)) - { - builder.Append("<Website>" + SecurityElement.Escape(item.HomePageUrl) + "</Website>"); - } - - var hasAspectRatio = item as IHasAspectRatio; - if (hasAspectRatio != null) - { - if (!string.IsNullOrEmpty(hasAspectRatio.AspectRatio)) - { - builder.Append("<AspectRatio>" + SecurityElement.Escape(hasAspectRatio.AspectRatio) + "</AspectRatio>"); - } - } - - if (!string.IsNullOrEmpty(item.PreferredMetadataLanguage)) - { - builder.Append("<Language>" + SecurityElement.Escape(item.PreferredMetadataLanguage) + "</Language>"); - } - if (!string.IsNullOrEmpty(item.PreferredMetadataCountryCode)) - { - builder.Append("<CountryCode>" + SecurityElement.Escape(item.PreferredMetadataCountryCode) + "</CountryCode>"); - } - - // 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("<RunningTime>" + Convert.ToInt32(timespan.TotalMinutes).ToString(UsCulture) + "</RunningTime>"); - } - - if (item.ProviderIds != null) - { - foreach (var providerKey in item.ProviderIds.Keys) - { - var providerId = item.ProviderIds[providerKey]; - if (!string.IsNullOrEmpty(providerId)) - { - builder.Append(string.Format("<{0}>{1}</{0}>", providerKey + "Id", SecurityElement.Escape(providerId))); - } - } - } - - if (!string.IsNullOrWhiteSpace(item.Tagline)) - { - builder.Append("<Taglines>"); - builder.Append("<Tagline>" + SecurityElement.Escape(item.Tagline) + "</Tagline>"); - builder.Append("</Taglines>"); - } - - if (item.Genres.Count > 0) - { - builder.Append("<Genres>"); - - foreach (var genre in item.Genres) - { - builder.Append("<Genre>" + SecurityElement.Escape(genre) + "</Genre>"); - } - - builder.Append("</Genres>"); - } - - if (item.Studios.Count > 0) - { - builder.Append("<Studios>"); - - foreach (var studio in item.Studios) - { - builder.Append("<Studio>" + SecurityElement.Escape(studio) + "</Studio>"); - } - - builder.Append("</Studios>"); - } - - if (item.Tags.Count > 0) - { - builder.Append("<Tags>"); - - foreach (var tag in item.Tags) - { - builder.Append("<Tag>" + SecurityElement.Escape(tag) + "</Tag>"); - } - - builder.Append("</Tags>"); - } - - if (item.Keywords.Count > 0) - { - builder.Append("<PlotKeywords>"); - - foreach (var tag in item.Keywords) - { - builder.Append("<PlotKeyword>" + SecurityElement.Escape(tag) + "</PlotKeyword>"); - } - - builder.Append("</PlotKeywords>"); - } - - var people = libraryManager.GetPeople(item); - - if (people.Count > 0) - { - builder.Append("<Persons>"); - - foreach (var person in people) - { - builder.Append("<Person>"); - builder.Append("<Name>" + SecurityElement.Escape(person.Name) + "</Name>"); - builder.Append("<Type>" + SecurityElement.Escape(person.Type) + "</Type>"); - builder.Append("<Role>" + SecurityElement.Escape(person.Role) + "</Role>"); - - if (person.SortOrder.HasValue) - { - builder.Append("<SortOrder>" + SecurityElement.Escape(person.SortOrder.Value.ToString(UsCulture)) + "</SortOrder>"); - } - - builder.Append("</Person>"); - } - - builder.Append("</Persons>"); - } - - var boxset = item as BoxSet; - if (boxset != null) - { - AddLinkedChildren(boxset, builder, "CollectionItems", "CollectionItem"); - } - - var playlist = item as Playlist; - if (playlist != null) - { - AddLinkedChildren(playlist, builder, "PlaylistItems", "PlaylistItem"); - } - - var hasShares = item as IHasShares; - if (hasShares != null) - { - AddShares(hasShares, builder); - } - } - - public static void AddShares(IHasShares item, StringBuilder builder) - { - builder.Append("<Shares>"); - - foreach (var share in item.Shares) - { - builder.Append("<Share>"); - - builder.Append("<UserId>" + SecurityElement.Escape(share.UserId) + "</UserId>"); - builder.Append("<CanEdit>" + SecurityElement.Escape(share.CanEdit.ToString().ToLower()) + "</CanEdit>"); - - builder.Append("</Share>"); - } - - builder.Append("</Shares>"); - } - - public static void AddChapters(Video item, StringBuilder builder, IItemRepository repository) - { - var chapters = repository.GetChapters(item.Id); - - builder.Append("<Chapters>"); - - foreach (var chapter in chapters) - { - builder.Append("<Chapter>"); - builder.Append("<Name>" + SecurityElement.Escape(chapter.Name) + "</Name>"); - - var time = TimeSpan.FromTicks(chapter.StartPositionTicks); - var ms = Convert.ToInt64(time.TotalMilliseconds); - - builder.Append("<StartPositionMs>" + SecurityElement.Escape(ms.ToString(UsCulture)) + "</StartPositionMs>"); - builder.Append("</Chapter>"); - } - - builder.Append("</Chapters>"); - } - - /// <summary> - /// Appends the media info. - /// </summary> - /// <typeparam name="T"></typeparam> - public static void AddMediaInfo<T>(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("<Format3D>FSBS</Format3D>"); - break; - case Video3DFormat.FullTopAndBottom: - builder.Append("<Format3D>FTAB</Format3D>"); - break; - case Video3DFormat.HalfSideBySide: - builder.Append("<Format3D>HSBS</Format3D>"); - break; - case Video3DFormat.HalfTopAndBottom: - builder.Append("<Format3D>HTAB</Format3D>"); - break; - case Video3DFormat.MVC: - builder.Append("<Format3D>MVC</Format3D>"); - break; - } - } - } - } - - public static void AddLinkedChildren(Folder item, StringBuilder builder, string pluralNodeName, string singularNodeName) - { - var items = item.LinkedChildren - .Where(i => i.Type == LinkedChildType.Manual) - .ToList(); - - if (items.Count == 0) - { - return; - } - - builder.Append("<" + pluralNodeName + ">"); - foreach (var link in items) - { - builder.Append("<" + singularNodeName + ">"); - - if (!string.IsNullOrWhiteSpace(link.Path)) - { - builder.Append("<Path>" + SecurityElement.Escape((link.Path)) + "</Path>"); - } - - builder.Append("</" + singularNodeName + ">"); - } - builder.Append("</" + pluralNodeName + ">"); - } - } -} diff --git a/MediaBrowser.LocalMetadata/packages.config b/MediaBrowser.LocalMetadata/packages.config deleted file mode 100644 index ccef6d686..000000000 --- a/MediaBrowser.LocalMetadata/packages.config +++ /dev/null @@ -1,5 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<packages> - <package id="CommonIO" version="1.0.0.9" targetFramework="net45" /> - <package id="Patterns.Logging" version="1.0.0.2" targetFramework="net45" /> -</packages>
\ No newline at end of file diff --git a/MediaBrowser.LocalMetadata/project.json b/MediaBrowser.LocalMetadata/project.json new file mode 100644 index 000000000..fbbe9eaf3 --- /dev/null +++ b/MediaBrowser.LocalMetadata/project.json @@ -0,0 +1,17 @@ +{ + "frameworks":{ + "netstandard1.6":{ + "dependencies":{ + "NETStandard.Library":"1.6.0", + } + }, + ".NETPortable,Version=v4.5,Profile=Profile7":{ + "buildOptions": { + "define": [ ] + }, + "frameworkAssemblies":{ + + } + } + } +}
\ No newline at end of file |
