Merge pull request #1643 from Bond-009/docs3

Fix some documentation warnings for MediaBrowser.XbmcMetadata
pull/1788/head
Joshua M. Boniface 5 years ago committed by GitHub
commit e19474d22f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -6,6 +6,7 @@ namespace MediaBrowser.XbmcMetadata.Configuration
{ {
public class ConfigurationFactory : IConfigurationFactory public class ConfigurationFactory : IConfigurationFactory
{ {
/// <inheritdoc />
public IEnumerable<ConfigurationStore> GetConfigurations() public IEnumerable<ConfigurationStore> GetConfigurations()
{ {
return new[] return new[]

@ -15,4 +15,8 @@
<GenerateDocumentationFile>true</GenerateDocumentationFile> <GenerateDocumentationFile>true</GenerateDocumentationFile>
</PropertyGroup> </PropertyGroup>
<PropertyGroup>
<LangVersion>latest</LangVersion>
</PropertyGroup>
</Project> </Project>

@ -22,13 +22,6 @@ namespace MediaBrowser.XbmcMetadata.Parsers
public class BaseNfoParser<T> public class BaseNfoParser<T>
where T : BaseItem where T : BaseItem
{ {
/// <summary>
/// The logger
/// </summary>
protected ILogger Logger { get; private set; }
protected IProviderManager ProviderManager { get; private set; }
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
private readonly IConfigurationManager _config; private readonly IConfigurationManager _config;
private Dictionary<string, string> _validProviderIds; private Dictionary<string, string> _validProviderIds;
@ -42,6 +35,19 @@ namespace MediaBrowser.XbmcMetadata.Parsers
ProviderManager = providerManager; ProviderManager = providerManager;
} }
protected CultureInfo UsCulture { get; } = new CultureInfo("en-US");
/// <summary>
/// Gets the logger.
/// </summary>
protected ILogger Logger { get; }
protected IProviderManager ProviderManager { get; }
protected virtual bool SupportsUrlAfterClosingXmlTag => false;
protected virtual string MovieDbParserSearchString => "themoviedb.org/movie/";
/// <summary> /// <summary>
/// Fetches metadata for an item from one xml file /// Fetches metadata for an item from one xml file
/// </summary> /// </summary>
@ -83,8 +89,6 @@ namespace MediaBrowser.XbmcMetadata.Parsers
Fetch(item, metadataFile, GetXmlReaderSettings(), cancellationToken); Fetch(item, metadataFile, GetXmlReaderSettings(), cancellationToken);
} }
protected virtual bool SupportsUrlAfterClosingXmlTag => false;
/// <summary> /// <summary>
/// Fetches the specified item. /// Fetches the specified item.
/// </summary> /// </summary>
@ -198,8 +202,6 @@ namespace MediaBrowser.XbmcMetadata.Parsers
} }
} }
protected virtual string MovieDbParserSearchString => "themoviedb.org/movie/";
protected void ParseProviderLinks(T item, string xml) protected void ParseProviderLinks(T item, string xml)
{ {
//Look for a match for the Regex pattern "tt" followed by 7 digits //Look for a match for the Regex pattern "tt" followed by 7 digits
@ -219,7 +221,7 @@ namespace MediaBrowser.XbmcMetadata.Parsers
var tmdbId = xml.Substring(index + srch.Length).TrimEnd('/').Split('-')[0]; var tmdbId = xml.Substring(index + srch.Length).TrimEnd('/').Split('-')[0];
if (!string.IsNullOrWhiteSpace(tmdbId) && int.TryParse(tmdbId, NumberStyles.Integer, CultureInfo.InvariantCulture, out var value)) if (!string.IsNullOrWhiteSpace(tmdbId) && int.TryParse(tmdbId, NumberStyles.Integer, CultureInfo.InvariantCulture, out var value))
{ {
item.SetProviderId(MetadataProviders.Tmdb, value.ToString(_usCulture)); item.SetProviderId(MetadataProviders.Tmdb, value.ToString(UsCulture));
} }
} }
@ -234,7 +236,7 @@ namespace MediaBrowser.XbmcMetadata.Parsers
var tvdbId = xml.Substring(index + srch.Length).TrimEnd('/'); var tvdbId = xml.Substring(index + srch.Length).TrimEnd('/');
if (!string.IsNullOrWhiteSpace(tvdbId) && int.TryParse(tvdbId, NumberStyles.Integer, CultureInfo.InvariantCulture, out var value)) if (!string.IsNullOrWhiteSpace(tvdbId) && int.TryParse(tvdbId, NumberStyles.Integer, CultureInfo.InvariantCulture, out var value))
{ {
item.SetProviderId(MetadataProviders.Tvdb, value.ToString(_usCulture)); item.SetProviderId(MetadataProviders.Tvdb, value.ToString(UsCulture));
} }
} }
} }
@ -291,7 +293,7 @@ namespace MediaBrowser.XbmcMetadata.Parsers
if (!string.IsNullOrEmpty(text)) if (!string.IsNullOrEmpty(text))
{ {
if (float.TryParse(text, NumberStyles.Any, _usCulture, out var value)) if (float.TryParse(text, NumberStyles.Any, UsCulture, out var value))
{ {
item.CriticRating = value; item.CriticRating = value;
} }
@ -417,7 +419,7 @@ namespace MediaBrowser.XbmcMetadata.Parsers
if (!string.IsNullOrWhiteSpace(text)) if (!string.IsNullOrWhiteSpace(text))
{ {
if (int.TryParse(text.Split(' ')[0], NumberStyles.Integer, _usCulture, out var runtime)) if (int.TryParse(text.Split(' ')[0], NumberStyles.Integer, UsCulture, out var runtime))
{ {
item.RunTimeTicks = TimeSpan.FromMinutes(runtime).Ticks; item.RunTimeTicks = TimeSpan.FromMinutes(runtime).Ticks;
} }
@ -870,7 +872,7 @@ namespace MediaBrowser.XbmcMetadata.Parsers
if (!string.IsNullOrWhiteSpace(val)) if (!string.IsNullOrWhiteSpace(val))
{ {
if (int.TryParse(val, NumberStyles.Integer, _usCulture, out var intVal)) if (int.TryParse(val, NumberStyles.Integer, UsCulture, out var intVal))
{ {
sortOrder = intVal; sortOrder = intVal;
} }

@ -1,5 +1,4 @@
using System; using System;
using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.IO; using System.IO;
using System.Text; using System.Text;
@ -14,16 +13,12 @@ namespace MediaBrowser.XbmcMetadata.Parsers
{ {
public class EpisodeNfoParser : BaseNfoParser<Episode> public class EpisodeNfoParser : BaseNfoParser<Episode>
{ {
public void Fetch(MetadataResult<Episode> item, public EpisodeNfoParser(ILogger logger, IConfigurationManager config, IProviderManager providerManager)
List<LocalImageInfo> images, : base(logger, config, providerManager)
string metadataFile,
CancellationToken cancellationToken)
{ {
Fetch(item, metadataFile, cancellationToken);
} }
private readonly CultureInfo UsCulture = new CultureInfo("en-US"); /// <inheritdoc />
protected override void Fetch(MetadataResult<Episode> item, string metadataFile, XmlReaderSettings settings, CancellationToken cancellationToken) protected override void Fetch(MetadataResult<Episode> item, string metadataFile, XmlReaderSettings settings, CancellationToken cancellationToken)
{ {
using (var fileStream = File.OpenRead(metadataFile)) using (var fileStream = File.OpenRead(metadataFile))
@ -73,11 +68,7 @@ namespace MediaBrowser.XbmcMetadata.Parsers
} }
} }
/// <summary> /// <inheritdoc />
/// Fetches the data from XML node.
/// </summary>
/// <param name="reader">The reader.</param>
/// <param name="itemResult">The item result.</param>
protected override void FetchDataFromXmlNode(XmlReader reader, MetadataResult<Episode> itemResult) protected override void FetchDataFromXmlNode(XmlReader reader, MetadataResult<Episode> itemResult)
{ {
var item = itemResult.Item; var item = itemResult.Item;
@ -212,10 +203,5 @@ namespace MediaBrowser.XbmcMetadata.Parsers
break; break;
} }
} }
public EpisodeNfoParser(ILogger logger, IConfigurationManager config, IProviderManager providerManager)
: base(logger, config, providerManager)
{
}
} }
} }

@ -13,13 +13,15 @@ namespace MediaBrowser.XbmcMetadata.Parsers
{ {
public class MovieNfoParser : BaseNfoParser<Video> public class MovieNfoParser : BaseNfoParser<Video>
{ {
public MovieNfoParser(ILogger logger, IConfigurationManager config, IProviderManager providerManager)
: base(logger, config, providerManager)
{
}
/// <inheritdoc />
protected override bool SupportsUrlAfterClosingXmlTag => true; protected override bool SupportsUrlAfterClosingXmlTag => true;
/// <summary> /// <inheritdoc />
/// Fetches the data from XML node.
/// </summary>
/// <param name="reader">The reader.</param>
/// <param name="itemResult">The item result.</param>
protected override void FetchDataFromXmlNode(XmlReader reader, MetadataResult<Video> itemResult) protected override void FetchDataFromXmlNode(XmlReader reader, MetadataResult<Video> itemResult)
{ {
var item = itemResult.Item; var item = itemResult.Item;
@ -35,14 +37,17 @@ namespace MediaBrowser.XbmcMetadata.Parsers
{ {
imdbId = reader.ReadElementContentAsString(); imdbId = reader.ReadElementContentAsString();
} }
if (!string.IsNullOrWhiteSpace(imdbId)) if (!string.IsNullOrWhiteSpace(imdbId))
{ {
item.SetProviderId(MetadataProviders.Imdb, imdbId); item.SetProviderId(MetadataProviders.Imdb, imdbId);
} }
if (!string.IsNullOrWhiteSpace(tmdbId)) if (!string.IsNullOrWhiteSpace(tmdbId))
{ {
item.SetProviderId(MetadataProviders.Tmdb, tmdbId); item.SetProviderId(MetadataProviders.Tmdb, tmdbId);
} }
break; break;
} }
case "set": case "set":
@ -83,9 +88,8 @@ namespace MediaBrowser.XbmcMetadata.Parsers
case "artist": case "artist":
{ {
var val = reader.ReadElementContentAsString(); var val = reader.ReadElementContentAsString();
var movie = item as MusicVideo;
if (!string.IsNullOrWhiteSpace(val) && movie != null) if (!string.IsNullOrWhiteSpace(val) && item is MusicVideo movie)
{ {
var list = movie.Artists.ToList(); var list = movie.Artists.ToList();
list.Add(val); list.Add(val);
@ -98,9 +102,8 @@ namespace MediaBrowser.XbmcMetadata.Parsers
case "album": case "album":
{ {
var val = reader.ReadElementContentAsString(); var val = reader.ReadElementContentAsString();
var movie = item as MusicVideo;
if (!string.IsNullOrWhiteSpace(val) && movie != null) if (!string.IsNullOrWhiteSpace(val) && item is MusicVideo movie)
{ {
movie.Album = val; movie.Album = val;
} }
@ -119,48 +122,41 @@ namespace MediaBrowser.XbmcMetadata.Parsers
//xml = xml.Substring(xml.IndexOf('<')); //xml = xml.Substring(xml.IndexOf('<'));
//xml = xml.Substring(0, xml.LastIndexOf('>')); //xml = xml.Substring(0, xml.LastIndexOf('>'));
using (var stringReader = new StringReader("<set>" + xml + "</set>")) // These are not going to be valid xml so no sense in causing the provider to fail and spamming the log with exceptions
try
{ {
// These are not going to be valid xml so no sense in causing the provider to fail and spamming the log with exceptions using (var stringReader = new StringReader("<set>" + xml + "</set>"))
try using (var reader = XmlReader.Create(stringReader, GetXmlReaderSettings()))
{ {
using (var reader = XmlReader.Create(stringReader, GetXmlReaderSettings())) reader.MoveToContent();
{ reader.Read();
reader.MoveToContent();
reader.Read();
// Loop through each element // Loop through each element
while (!reader.EOF && reader.ReadState == ReadState.Interactive) while (!reader.EOF && reader.ReadState == ReadState.Interactive)
{
if (reader.NodeType == XmlNodeType.Element)
{ {
if (reader.NodeType == XmlNodeType.Element) switch (reader.Name)
{
switch (reader.Name)
{
case "name":
movie.CollectionName = reader.ReadElementContentAsString();
break;
default:
reader.Skip();
break;
}
}
else
{ {
reader.Read(); case "name":
movie.CollectionName = reader.ReadElementContentAsString();
break;
default:
reader.Skip();
break;
} }
} }
else
{
reader.Read();
}
} }
} }
catch (XmlException)
{
}
} }
} catch (XmlException)
{
public MovieNfoParser(ILogger logger, IConfigurationManager config, IProviderManager providerManager) }
: base(logger, config, providerManager)
{
} }
} }
} }

@ -9,11 +9,12 @@ namespace MediaBrowser.XbmcMetadata.Parsers
{ {
public class SeasonNfoParser : BaseNfoParser<Season> public class SeasonNfoParser : BaseNfoParser<Season>
{ {
/// <summary> public SeasonNfoParser(ILogger logger, IConfigurationManager config, IProviderManager providerManager)
/// Fetches the data from XML node. : base(logger, config, providerManager)
/// </summary> {
/// <param name="reader">The reader.</param> }
/// <param name="itemResult">The item result.</param>
/// <inheritdoc />
protected override void FetchDataFromXmlNode(XmlReader reader, MetadataResult<Season> itemResult) protected override void FetchDataFromXmlNode(XmlReader reader, MetadataResult<Season> itemResult)
{ {
var item = itemResult.Item; var item = itemResult.Item;
@ -39,10 +40,5 @@ namespace MediaBrowser.XbmcMetadata.Parsers
break; break;
} }
} }
public SeasonNfoParser(ILogger logger, IConfigurationManager config, IProviderManager providerManager)
: base(logger, config, providerManager)
{
}
} }
} }

@ -11,15 +11,18 @@ namespace MediaBrowser.XbmcMetadata.Parsers
{ {
public class SeriesNfoParser : BaseNfoParser<Series> public class SeriesNfoParser : BaseNfoParser<Series>
{ {
public SeriesNfoParser(ILogger logger, IConfigurationManager config, IProviderManager providerManager)
: base(logger, config, providerManager)
{
}
/// <inheritdoc />
protected override bool SupportsUrlAfterClosingXmlTag => true; protected override bool SupportsUrlAfterClosingXmlTag => true;
/// <inheritdoc />
protected override string MovieDbParserSearchString => "themoviedb.org/tv/"; protected override string MovieDbParserSearchString => "themoviedb.org/tv/";
/// <summary> /// <inheritdoc />
/// Fetches the data from XML node.
/// </summary>
/// <param name="reader">The reader.</param>
/// <param name="itemResult">The item result.</param>
protected override void FetchDataFromXmlNode(XmlReader reader, MetadataResult<Series> itemResult) protected override void FetchDataFromXmlNode(XmlReader reader, MetadataResult<Series> itemResult)
{ {
var item = itemResult.Item; var item = itemResult.Item;
@ -91,10 +94,5 @@ namespace MediaBrowser.XbmcMetadata.Parsers
break; break;
} }
} }
public SeriesNfoParser(ILogger logger, IConfigurationManager config, IProviderManager providerManager)
: base(logger, config, providerManager)
{
}
} }
} }

@ -23,14 +23,14 @@ namespace MediaBrowser.XbmcMetadata.Providers
_providerManager = providerManager; _providerManager = providerManager;
} }
/// <inheritdoc />
protected override void Fetch(MetadataResult<MusicAlbum> result, string path, CancellationToken cancellationToken) protected override void Fetch(MetadataResult<MusicAlbum> result, string path, CancellationToken cancellationToken)
{ {
new BaseNfoParser<MusicAlbum>(_logger, _config, _providerManager).Fetch(result, path, cancellationToken); new BaseNfoParser<MusicAlbum>(_logger, _config, _providerManager).Fetch(result, path, cancellationToken);
} }
/// <inheritdoc />
protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService) protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService)
{ => directoryService.GetFile(Path.Combine(info.Path, "album.nfo"));
return directoryService.GetFile(Path.Combine(info.Path, "album.nfo"));
}
} }
} }

@ -23,14 +23,14 @@ namespace MediaBrowser.XbmcMetadata.Providers
_providerManager = providerManager; _providerManager = providerManager;
} }
/// <inheritdoc />
protected override void Fetch(MetadataResult<MusicArtist> result, string path, CancellationToken cancellationToken) protected override void Fetch(MetadataResult<MusicArtist> result, string path, CancellationToken cancellationToken)
{ {
new BaseNfoParser<MusicArtist>(_logger, _config, _providerManager).Fetch(result, path, cancellationToken); new BaseNfoParser<MusicArtist>(_logger, _config, _providerManager).Fetch(result, path, cancellationToken);
} }
/// <inheritdoc />
protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService) protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService)
{ => directoryService.GetFile(Path.Combine(info.Path, "artist.nfo"));
return directoryService.GetFile(Path.Combine(info.Path, "artist.nfo"));
}
} }
} }

@ -11,9 +11,16 @@ namespace MediaBrowser.XbmcMetadata.Providers
public abstract class BaseNfoProvider<T> : ILocalMetadataProvider<T>, IHasItemChangeMonitor public abstract class BaseNfoProvider<T> : ILocalMetadataProvider<T>, IHasItemChangeMonitor
where T : BaseItem, new() where T : BaseItem, new()
{ {
protected IFileSystem FileSystem; private IFileSystem _fileSystem;
public Task<MetadataResult<T>> GetMetadata(ItemInfo info, protected BaseNfoProvider(IFileSystem fileSystem)
{
_fileSystem = fileSystem;
}
/// <inheritdoc />
public Task<MetadataResult<T>> GetMetadata(
ItemInfo info,
IDirectoryService directoryService, IDirectoryService directoryService,
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
@ -47,15 +54,13 @@ namespace MediaBrowser.XbmcMetadata.Providers
return Task.FromResult(result); return Task.FromResult(result);
} }
/// <inheritdoc />
protected abstract void Fetch(MetadataResult<T> result, string path, CancellationToken cancellationToken); protected abstract void Fetch(MetadataResult<T> result, string path, CancellationToken cancellationToken);
protected BaseNfoProvider(IFileSystem fileSystem) /// <inheritdoc />
{
FileSystem = fileSystem;
}
protected abstract FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService); protected abstract FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService);
/// <inheritdoc />
public bool HasChanged(BaseItem item, IDirectoryService directoryService) public bool HasChanged(BaseItem item, IDirectoryService directoryService)
{ {
var file = GetXmlFile(new ItemInfo(item), directoryService); var file = GetXmlFile(new ItemInfo(item), directoryService);
@ -65,7 +70,7 @@ namespace MediaBrowser.XbmcMetadata.Providers
return false; return false;
} }
return file.Exists && FileSystem.GetLastWriteTimeUtc(file) > item.DateLastSaved; return file.Exists && _fileSystem.GetLastWriteTimeUtc(file) > item.DateLastSaved;
} }
public string Name => BaseNfoSaver.SaverName; public string Name => BaseNfoSaver.SaverName;

@ -25,6 +25,7 @@ namespace MediaBrowser.XbmcMetadata.Providers
_providerManager = providerManager; _providerManager = providerManager;
} }
/// <inheritdoc />
protected override void Fetch(MetadataResult<T> result, string path, CancellationToken cancellationToken) protected override void Fetch(MetadataResult<T> result, string path, CancellationToken cancellationToken)
{ {
var tmpItem = new MetadataResult<Video> var tmpItem = new MetadataResult<Video>
@ -42,9 +43,10 @@ namespace MediaBrowser.XbmcMetadata.Providers
} }
} }
/// <inheritdoc />
protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService) protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService)
{ {
return MovieNfoSaver.GetMovieSavePaths(info, FileSystem) return MovieNfoSaver.GetMovieSavePaths(info)
.Select(directoryService.GetFile) .Select(directoryService.GetFile)
.FirstOrDefault(i => i != null); .FirstOrDefault(i => i != null);
} }

@ -1,4 +1,3 @@
using System.Collections.Generic;
using System.IO; using System.IO;
using System.Threading; using System.Threading;
using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Configuration;
@ -24,15 +23,13 @@ namespace MediaBrowser.XbmcMetadata.Providers
_providerManager = providerManager; _providerManager = providerManager;
} }
/// <inheritdoc />
protected override void Fetch(MetadataResult<Episode> result, string path, CancellationToken cancellationToken) protected override void Fetch(MetadataResult<Episode> result, string path, CancellationToken cancellationToken)
{ {
var images = new List<LocalImageInfo>(); new EpisodeNfoParser(_logger, _config, _providerManager).Fetch(result, path, cancellationToken);
new EpisodeNfoParser(_logger, _config, _providerManager).Fetch(result, images, path, cancellationToken);
result.Images = images;
} }
/// <inheritdoc />
protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService) protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService)
{ {
var path = Path.ChangeExtension(info.Path, ".nfo"); var path = Path.ChangeExtension(info.Path, ".nfo");

@ -23,11 +23,13 @@ namespace MediaBrowser.XbmcMetadata.Providers
_providerManager = providerManager; _providerManager = providerManager;
} }
/// <inheritdoc />
protected override void Fetch(MetadataResult<Season> result, string path, CancellationToken cancellationToken) protected override void Fetch(MetadataResult<Season> result, string path, CancellationToken cancellationToken)
{ {
new SeasonNfoParser(_logger, _config, _providerManager).Fetch(result, path, cancellationToken); new SeasonNfoParser(_logger, _config, _providerManager).Fetch(result, path, cancellationToken);
} }
/// <inheritdoc />
protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService) protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService)
=> directoryService.GetFile(Path.Combine(info.Path, "season.nfo")); => directoryService.GetFile(Path.Combine(info.Path, "season.nfo"));
} }

@ -23,11 +23,13 @@ namespace MediaBrowser.XbmcMetadata.Providers
_providerManager = providerManager; _providerManager = providerManager;
} }
/// <inheritdoc />
protected override void Fetch(MetadataResult<Series> result, string path, CancellationToken cancellationToken) protected override void Fetch(MetadataResult<Series> result, string path, CancellationToken cancellationToken)
{ {
new SeriesNfoParser(_logger, _config, _providerManager).Fetch(result, path, cancellationToken); new SeriesNfoParser(_logger, _config, _providerManager).Fetch(result, path, cancellationToken);
} }
/// <inheritdoc />
protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService) protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService)
=> directoryService.GetFile(Path.Combine(info.Path, "tvshow.nfo")); => directoryService.GetFile(Path.Combine(info.Path, "tvshow.nfo"));
} }

@ -28,26 +28,15 @@ namespace MediaBrowser.XbmcMetadata.Savers
/// <inheritdoc /> /// <inheritdoc />
protected override string GetLocalSavePath(BaseItem item) protected override string GetLocalSavePath(BaseItem item)
{ => Path.Combine(item.Path, "album.nfo");
return Path.Combine(item.Path, "album.nfo");
}
/// <inheritdoc /> /// <inheritdoc />
protected override string GetRootElementName(BaseItem item) protected override string GetRootElementName(BaseItem item)
{ => "album";
return "album";
}
/// <inheritdoc /> /// <inheritdoc />
public override bool IsEnabledFor(BaseItem item, ItemUpdateType updateType) public override bool IsEnabledFor(BaseItem item, ItemUpdateType updateType)
{ => item.SupportsLocalMetadata && item is MusicAlbum && updateType >= MinimumUpdateType;
if (!item.SupportsLocalMetadata)
{
return false;
}
return item is MusicAlbum && updateType >= MinimumUpdateType;
}
/// <inheritdoc /> /// <inheritdoc />
protected override void WriteCustomElements(BaseItem item, XmlWriter writer) protected override void WriteCustomElements(BaseItem item, XmlWriter writer)

@ -14,26 +14,24 @@ namespace MediaBrowser.XbmcMetadata.Savers
{ {
public class ArtistNfoSaver : BaseNfoSaver public class ArtistNfoSaver : BaseNfoSaver
{ {
protected override string GetLocalSavePath(BaseItem item) public ArtistNfoSaver(IFileSystem fileSystem, IServerConfigurationManager configurationManager, ILibraryManager libraryManager, IUserManager userManager, IUserDataManager userDataManager, ILogger logger)
: base(fileSystem, configurationManager, libraryManager, userManager, userDataManager, logger)
{ {
return Path.Combine(item.Path, "artist.nfo");
} }
/// <inheritdoc />
protected override string GetLocalSavePath(BaseItem item)
=> Path.Combine(item.Path, "artist.nfo");
/// <inheritdoc />
protected override string GetRootElementName(BaseItem item) protected override string GetRootElementName(BaseItem item)
{ => "artist";
return "artist";
}
/// <inheritdoc />
public override bool IsEnabledFor(BaseItem item, ItemUpdateType updateType) public override bool IsEnabledFor(BaseItem item, ItemUpdateType updateType)
{ => item.SupportsLocalMetadata && item is MusicArtist && updateType >= MinimumUpdateType;
if (!item.SupportsLocalMetadata)
{
return false;
}
return item is MusicArtist && updateType >= MinimumUpdateType;
}
/// <inheritdoc />
protected override void WriteCustomElements(BaseItem item, XmlWriter writer) protected override void WriteCustomElements(BaseItem item, XmlWriter writer)
{ {
var artist = (MusicArtist)item; var artist = (MusicArtist)item;
@ -51,8 +49,6 @@ namespace MediaBrowser.XbmcMetadata.Savers
AddAlbums(albums, writer); AddAlbums(albums, writer);
} }
private readonly CultureInfo UsCulture = new CultureInfo("en-US");
private void AddAlbums(IList<BaseItem> albums, XmlWriter writer) private void AddAlbums(IList<BaseItem> albums, XmlWriter writer)
{ {
foreach (var album in albums) foreach (var album in albums)
@ -66,13 +62,14 @@ namespace MediaBrowser.XbmcMetadata.Savers
if (album.ProductionYear.HasValue) if (album.ProductionYear.HasValue)
{ {
writer.WriteElementString("year", album.ProductionYear.Value.ToString(UsCulture)); writer.WriteElementString("year", album.ProductionYear.Value.ToString(CultureInfo.InvariantCulture));
} }
writer.WriteEndElement(); writer.WriteEndElement();
} }
} }
/// <inheritdoc />
protected override List<string> GetTagsUsed(BaseItem item) protected override List<string> GetTagsUsed(BaseItem item)
{ {
var list = base.GetTagsUsed(item); var list = base.GetTagsUsed(item);
@ -81,12 +78,8 @@ namespace MediaBrowser.XbmcMetadata.Savers
"album", "album",
"disbanded" "disbanded"
}); });
return list;
}
public ArtistNfoSaver(IFileSystem fileSystem, IServerConfigurationManager configurationManager, ILibraryManager libraryManager, IUserManager userManager, IUserDataManager userDataManager, ILogger logger) return list;
: base(fileSystem, configurationManager, libraryManager, userManager, userDataManager, logger)
{
} }
} }
} }

@ -25,76 +25,78 @@ namespace MediaBrowser.XbmcMetadata.Savers
{ {
public abstract class BaseNfoSaver : IMetadataFileSaver public abstract class BaseNfoSaver : IMetadataFileSaver
{ {
public static readonly string YouTubeWatchUrl = "https://www.youtube.com/watch?v="; public const string DateAddedFormat = "yyyy-MM-dd HH:mm:ss";
private static readonly CultureInfo UsCulture = new CultureInfo("en-US"); public const string YouTubeWatchUrl = "https://www.youtube.com/watch?v=";
private static readonly Dictionary<string, string> CommonTags = new[] {
"plot",
"customrating",
"lockdata",
"dateadded",
"title",
"rating",
"year",
"sorttitle",
"mpaa",
"aspectratio",
"collectionnumber",
"tmdbid",
"rottentomatoesid",
"language",
"tvcomid",
"tagline",
"studio",
"genre",
"tag",
"runtime",
"actor",
"criticrating",
"fileinfo",
"director",
"writer",
"trailer",
"premiered",
"releasedate",
"outline",
"id",
"credits",
"originaltitle",
"watched",
"playcount",
"lastplayed",
"art",
"resume",
"biography",
"formed",
"review",
"style",
"imdbid",
"imdb_id",
"country",
"audiodbalbumid",
"audiodbartistid",
"enddate",
"lockedfields",
"zap2itid",
"tvrageid",
"musicbrainzartistid",
"musicbrainzalbumartistid",
"musicbrainzalbumid",
"musicbrainzreleasegroupid",
"tvdbid",
"collectionitem",
"isuserfavorite",
"userrating",
"countrycode" private static readonly HashSet<string> _commonTags = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
{
"plot",
"customrating",
"lockdata",
"dateadded",
"title",
"rating",
"year",
"sorttitle",
"mpaa",
"aspectratio",
"collectionnumber",
"tmdbid",
"rottentomatoesid",
"language",
"tvcomid",
"tagline",
"studio",
"genre",
"tag",
"runtime",
"actor",
"criticrating",
"fileinfo",
"director",
"writer",
"trailer",
"premiered",
"releasedate",
"outline",
"id",
"credits",
"originaltitle",
"watched",
"playcount",
"lastplayed",
"art",
"resume",
"biography",
"formed",
"review",
"style",
"imdbid",
"imdb_id",
"country",
"audiodbalbumid",
"audiodbartistid",
"enddate",
"lockedfields",
"zap2itid",
"tvrageid",
"musicbrainzartistid",
"musicbrainzalbumartistid",
"musicbrainzalbumid",
"musicbrainzreleasegroupid",
"tvdbid",
"collectionitem",
"isuserfavorite",
"userrating",
"countrycode"
};
}.ToDictionary(i => i, StringComparer.OrdinalIgnoreCase); // filters control characters but allows only properly-formed surrogate sequences
private const string _invalidXMLCharsRegex = @"(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|[\x00-\x08\x0B\x0C\x0E-\x1F\x7F-\x9F\uFEFF\uFFFE\uFFFF]";
protected BaseNfoSaver( protected BaseNfoSaver(
IFileSystem fileSystem, IFileSystem fileSystem,
@ -112,12 +114,17 @@ namespace MediaBrowser.XbmcMetadata.Savers
FileSystem = fileSystem; FileSystem = fileSystem;
} }
protected IFileSystem FileSystem { get; private set; } protected IFileSystem FileSystem { get; }
protected IServerConfigurationManager ConfigurationManager { get; private set; }
protected ILibraryManager LibraryManager { get; private set; } protected IServerConfigurationManager ConfigurationManager { get; }
protected IUserManager UserManager { get; private set; }
protected IUserDataManager UserDataManager { get; private set; } protected ILibraryManager LibraryManager { get; }
protected ILogger Logger { get; private set; }
protected IUserManager UserManager { get; }
protected IUserDataManager UserDataManager { get; }
protected ILogger Logger { get; }
protected ItemUpdateType MinimumUpdateType protected ItemUpdateType MinimumUpdateType
{ {
@ -132,35 +139,30 @@ namespace MediaBrowser.XbmcMetadata.Savers
} }
} }
/// <inheritdoc />
public string Name => SaverName; public string Name => SaverName;
public static string SaverName => "Nfo"; public static string SaverName => "Nfo";
/// <inheritdoc />
public string GetSavePath(BaseItem item) public string GetSavePath(BaseItem item)
{ => GetLocalSavePath(item);
return GetLocalSavePath(item);
}
/// <summary> /// <summary>
/// Gets the save path. /// Gets the save path.
/// </summary> /// </summary>
/// <param name="item">The item.</param> /// <param name="item">The item.</param>
/// <returns>System.String.</returns> /// <returns><see cref="string" />.</returns>
protected abstract string GetLocalSavePath(BaseItem item); protected abstract string GetLocalSavePath(BaseItem item);
/// <summary> /// <summary>
/// Gets the name of the root element. /// Gets the name of the root element.
/// </summary> /// </summary>
/// <param name="item">The item.</param> /// <param name="item">The item.</param>
/// <returns>System.String.</returns> /// <returns><see cref="string" />.</returns>
protected abstract string GetRootElementName(BaseItem item); protected abstract string GetRootElementName(BaseItem item);
/// <summary> /// <inheritdoc />
/// 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(BaseItem item, ItemUpdateType updateType); public abstract bool IsEnabledFor(BaseItem item, ItemUpdateType updateType);
protected virtual List<string> GetTagsUsed(BaseItem item) protected virtual List<string> GetTagsUsed(BaseItem item)
@ -169,14 +171,16 @@ namespace MediaBrowser.XbmcMetadata.Savers
foreach (var providerKey in item.ProviderIds.Keys) foreach (var providerKey in item.ProviderIds.Keys)
{ {
var providerIdTagName = GetTagForProviderKey(providerKey); var providerIdTagName = GetTagForProviderKey(providerKey);
if (!CommonTags.ContainsKey(providerIdTagName)) if (!_commonTags.Contains(providerIdTagName))
{ {
list.Add(providerIdTagName); list.Add(providerIdTagName);
} }
} }
return list; return list;
} }
/// <inheritdoc />
public void Save(BaseItem item, CancellationToken cancellationToken) public void Save(BaseItem item, CancellationToken cancellationToken)
{ {
var path = GetSavePath(item); var path = GetSavePath(item);
@ -196,10 +200,11 @@ namespace MediaBrowser.XbmcMetadata.Savers
private void SaveToFile(Stream stream, string path) private void SaveToFile(Stream stream, string path)
{ {
Directory.CreateDirectory(Path.GetDirectoryName(path)); Directory.CreateDirectory(Path.GetDirectoryName(path));
// On Windows, savint the file will fail if the file is hidden or readonly // On Windows, savint the file will fail if the file is hidden or readonly
FileSystem.SetAttributes(path, false, false); FileSystem.SetAttributes(path, false, false);
using (var filestream = FileSystem.GetFileStream(path, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read)) using (var filestream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read))
{ {
stream.CopyTo(filestream); stream.CopyTo(filestream);
} }
@ -216,9 +221,9 @@ namespace MediaBrowser.XbmcMetadata.Savers
{ {
FileSystem.SetHidden(path, hidden); FileSystem.SetHidden(path, hidden);
} }
catch (Exception ex) catch (IOException ex)
{ {
Logger.LogError(ex, "Error setting hidden attribute on {path}", path); Logger.LogError(ex, "Error setting hidden attribute on {Path}", path);
} }
} }
@ -248,9 +253,7 @@ namespace MediaBrowser.XbmcMetadata.Savers
WriteCustomElements(item, writer); WriteCustomElements(item, writer);
var hasMediaSources = baseItem as IHasMediaSources; if (baseItem is IHasMediaSources hasMediaSources)
if (hasMediaSources != null)
{ {
AddMediaInfo(hasMediaSources, writer); AddMediaInfo(hasMediaSources, writer);
} }
@ -259,7 +262,7 @@ namespace MediaBrowser.XbmcMetadata.Savers
try try
{ {
AddCustomTags(xmlPath, tagsUsed, writer, Logger, FileSystem); AddCustomTags(xmlPath, tagsUsed, writer, Logger);
} }
catch (FileNotFoundException) catch (FileNotFoundException)
{ {
@ -283,7 +286,7 @@ namespace MediaBrowser.XbmcMetadata.Savers
protected abstract void WriteCustomElements(BaseItem item, XmlWriter writer); protected abstract void WriteCustomElements(BaseItem item, XmlWriter writer);
public static void AddMediaInfo<T>(T item, XmlWriter writer) public static void AddMediaInfo<T>(T item, XmlWriter writer)
where T : IHasMediaSources where T : IHasMediaSources
{ {
writer.WriteStartElement("fileinfo"); writer.WriteStartElement("fileinfo");
writer.WriteStartElement("streamdetails"); writer.WriteStartElement("streamdetails");
@ -313,17 +316,17 @@ namespace MediaBrowser.XbmcMetadata.Savers
if (stream.BitRate.HasValue) if (stream.BitRate.HasValue)
{ {
writer.WriteElementString("bitrate", stream.BitRate.Value.ToString(UsCulture)); writer.WriteElementString("bitrate", stream.BitRate.Value.ToString(CultureInfo.InvariantCulture));
} }
if (stream.Width.HasValue) if (stream.Width.HasValue)
{ {
writer.WriteElementString("width", stream.Width.Value.ToString(UsCulture)); writer.WriteElementString("width", stream.Width.Value.ToString(CultureInfo.InvariantCulture));
} }
if (stream.Height.HasValue) if (stream.Height.HasValue)
{ {
writer.WriteElementString("height", stream.Height.Value.ToString(UsCulture)); writer.WriteElementString("height", stream.Height.Value.ToString(CultureInfo.InvariantCulture));
} }
if (!string.IsNullOrEmpty(stream.AspectRatio)) if (!string.IsNullOrEmpty(stream.AspectRatio))
@ -336,14 +339,14 @@ namespace MediaBrowser.XbmcMetadata.Savers
if (framerate.HasValue) if (framerate.HasValue)
{ {
writer.WriteElementString("framerate", framerate.Value.ToString(UsCulture)); writer.WriteElementString("framerate", framerate.Value.ToString(CultureInfo.InvariantCulture));
} }
if (!string.IsNullOrEmpty(stream.Language)) if (!string.IsNullOrEmpty(stream.Language))
{ {
// http://web.archive.org/web/20181230211547/https://emby.media/community/index.php?/topic/49071-nfo-not-generated-on-actualize-or-rescan-or-identify // http://web.archive.org/web/20181230211547/https://emby.media/community/index.php?/topic/49071-nfo-not-generated-on-actualize-or-rescan-or-identify
// Web Archive version of link since it's not really explained in the thread. // Web Archive version of link since it's not really explained in the thread.
writer.WriteElementString("language", RemoveInvalidXMLChars(stream.Language)); writer.WriteElementString("language", Regex.Replace(stream.Language, _invalidXMLCharsRegex, string.Empty));
} }
var scanType = stream.IsInterlaced ? "interlaced" : "progressive"; var scanType = stream.IsInterlaced ? "interlaced" : "progressive";
@ -354,12 +357,12 @@ namespace MediaBrowser.XbmcMetadata.Savers
if (stream.Channels.HasValue) if (stream.Channels.HasValue)
{ {
writer.WriteElementString("channels", stream.Channels.Value.ToString(UsCulture)); writer.WriteElementString("channels", stream.Channels.Value.ToString(CultureInfo.InvariantCulture));
} }
if (stream.SampleRate.HasValue) if (stream.SampleRate.HasValue)
{ {
writer.WriteElementString("samplingrate", stream.SampleRate.Value.ToString(UsCulture)); writer.WriteElementString("samplingrate", stream.SampleRate.Value.ToString(CultureInfo.InvariantCulture));
} }
writer.WriteElementString("default", stream.IsDefault.ToString()); writer.WriteElementString("default", stream.IsDefault.ToString());
@ -372,13 +375,15 @@ namespace MediaBrowser.XbmcMetadata.Savers
{ {
var timespan = TimeSpan.FromTicks(runtimeTicks.Value); var timespan = TimeSpan.FromTicks(runtimeTicks.Value);
writer.WriteElementString("duration", Math.Floor(timespan.TotalMinutes).ToString(UsCulture)); writer.WriteElementString(
writer.WriteElementString("durationinseconds", Math.Floor(timespan.TotalSeconds).ToString(UsCulture)); "duration",
Math.Floor(timespan.TotalMinutes).ToString(CultureInfo.InvariantCulture));
writer.WriteElementString(
"durationinseconds",
Math.Floor(timespan.TotalSeconds).ToString(CultureInfo.InvariantCulture));
} }
var video = item as Video; if (item is Video video)
if (video != null)
{ {
//AddChapters(video, builder, itemRepository); //AddChapters(video, builder, itemRepository);
@ -413,26 +418,18 @@ namespace MediaBrowser.XbmcMetadata.Savers
writer.WriteEndElement(); writer.WriteEndElement();
} }
// filters control characters but allows only properly-formed surrogate sequences
private static Regex _invalidXMLChars = new Regex(
@"(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|[\x00-\x08\x0B\x0C\x0E-\x1F\x7F-\x9F\uFEFF\uFFFE\uFFFF]");
/// <summary>
/// removes any unusual unicode characters that can't be encoded into XML
/// </summary>
public static string RemoveInvalidXMLChars(string text)
{
if (string.IsNullOrEmpty(text)) return string.Empty;
return _invalidXMLChars.Replace(text, string.Empty);
}
public const string DateAddedFormat = "yyyy-MM-dd HH:mm:ss";
/// <summary> /// <summary>
/// Adds the common nodes. /// Adds the common nodes.
/// </summary> /// </summary>
/// <returns>Task.</returns> /// <returns>Task.</returns>
private void AddCommonNodes(BaseItem item, XmlWriter writer, ILibraryManager libraryManager, IUserManager userManager, IUserDataManager userDataRepo, IFileSystem fileSystem, IServerConfigurationManager config) private void AddCommonNodes(
BaseItem item,
XmlWriter writer,
ILibraryManager libraryManager,
IUserManager userManager,
IUserDataManager userDataRepo,
IFileSystem fileSystem,
IServerConfigurationManager config)
{ {
var writtenProviderIds = new HashSet<string>(StringComparer.OrdinalIgnoreCase); var writtenProviderIds = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
@ -524,12 +521,12 @@ namespace MediaBrowser.XbmcMetadata.Savers
if (item.CommunityRating.HasValue) if (item.CommunityRating.HasValue)
{ {
writer.WriteElementString("rating", item.CommunityRating.Value.ToString(UsCulture)); writer.WriteElementString("rating", item.CommunityRating.Value.ToString(CultureInfo.InvariantCulture));
} }
if (item.ProductionYear.HasValue) if (item.ProductionYear.HasValue)
{ {
writer.WriteElementString("year", item.ProductionYear.Value.ToString(UsCulture)); writer.WriteElementString("year", item.ProductionYear.Value.ToString(CultureInfo.InvariantCulture));
} }
var forcedSortName = item.ForcedSortName; var forcedSortName = item.ForcedSortName;
@ -543,13 +540,10 @@ namespace MediaBrowser.XbmcMetadata.Savers
writer.WriteElementString("mpaa", item.OfficialRating); writer.WriteElementString("mpaa", item.OfficialRating);
} }
var hasAspectRatio = item as IHasAspectRatio; if (item is IHasAspectRatio hasAspectRatio
if (hasAspectRatio != null) && !string.IsNullOrEmpty(hasAspectRatio.AspectRatio))
{ {
if (!string.IsNullOrEmpty(hasAspectRatio.AspectRatio)) writer.WriteElementString("aspectratio", hasAspectRatio.AspectRatio);
{
writer.WriteElementString("aspectratio", hasAspectRatio.AspectRatio);
}
} }
var tmdbCollection = item.GetProviderId(MetadataProviders.TmdbCollection); var tmdbCollection = item.GetProviderId(MetadataProviders.TmdbCollection);
@ -571,6 +565,7 @@ namespace MediaBrowser.XbmcMetadata.Savers
{ {
writer.WriteElementString("imdbid", imdb); writer.WriteElementString("imdbid", imdb);
} }
writtenProviderIds.Add(MetadataProviders.Imdb.ToString()); writtenProviderIds.Add(MetadataProviders.Imdb.ToString());
} }
@ -607,12 +602,18 @@ namespace MediaBrowser.XbmcMetadata.Savers
if (item is MusicArtist) if (item is MusicArtist)
{ {
writer.WriteElementString("formed", item.PremiereDate.Value.ToLocalTime().ToString(formatString)); writer.WriteElementString(
"formed",
item.PremiereDate.Value.ToLocalTime().ToString(formatString));
} }
else else
{ {
writer.WriteElementString("premiered", item.PremiereDate.Value.ToLocalTime().ToString(formatString)); writer.WriteElementString(
writer.WriteElementString("releasedate", item.PremiereDate.Value.ToLocalTime().ToString(formatString)); "premiered",
item.PremiereDate.Value.ToLocalTime().ToString(formatString));
writer.WriteElementString(
"releasedate",
item.PremiereDate.Value.ToLocalTime().ToString(formatString));
} }
} }
@ -622,18 +623,20 @@ namespace MediaBrowser.XbmcMetadata.Savers
{ {
var formatString = options.ReleaseDateFormat; var formatString = options.ReleaseDateFormat;
writer.WriteElementString("enddate", item.EndDate.Value.ToLocalTime().ToString(formatString)); writer.WriteElementString(
"enddate",
item.EndDate.Value.ToLocalTime().ToString(formatString));
} }
} }
if (item.CriticRating.HasValue) if (item.CriticRating.HasValue)
{ {
writer.WriteElementString("criticrating", item.CriticRating.Value.ToString(UsCulture)); writer.WriteElementString(
"criticrating",
item.CriticRating.Value.ToString(CultureInfo.InvariantCulture));
} }
var hasDisplayOrder = item as IHasDisplayOrder; if (item is IHasDisplayOrder hasDisplayOrder)
if (hasDisplayOrder != null)
{ {
if (!string.IsNullOrEmpty(hasDisplayOrder.DisplayOrder)) if (!string.IsNullOrEmpty(hasDisplayOrder.DisplayOrder))
{ {
@ -648,7 +651,9 @@ namespace MediaBrowser.XbmcMetadata.Savers
{ {
var timespan = TimeSpan.FromTicks(runTimeTicks.Value); var timespan = TimeSpan.FromTicks(runTimeTicks.Value);
writer.WriteElementString("runtime", Convert.ToInt64(timespan.TotalMinutes).ToString(UsCulture)); writer.WriteElementString(
"runtime",
Convert.ToInt64(timespan.TotalMinutes).ToString(CultureInfo.InvariantCulture));
} }
if (!string.IsNullOrWhiteSpace(item.Tagline)) if (!string.IsNullOrWhiteSpace(item.Tagline))
@ -756,9 +761,9 @@ namespace MediaBrowser.XbmcMetadata.Savers
try try
{ {
var tagName = GetTagForProviderKey(providerKey); var tagName = GetTagForProviderKey(providerKey);
//logger.LogDebug("Verifying custom provider tagname {0}", tagName); Logger.LogDebug("Verifying custom provider tagname {0}", tagName);
XmlConvert.VerifyName(tagName); XmlConvert.VerifyName(tagName);
//logger.LogDebug("Saving custom provider tagname {0}", tagName); Logger.LogDebug("Saving custom provider tagname {0}", tagName);
writer.WriteElementString(GetTagForProviderKey(providerKey), providerId); writer.WriteElementString(GetTagForProviderKey(providerKey), providerId);
} }
@ -783,8 +788,7 @@ namespace MediaBrowser.XbmcMetadata.Savers
AddActors(people, writer, libraryManager, fileSystem, config, options.SaveImagePathsInNfo); AddActors(people, writer, libraryManager, fileSystem, config, options.SaveImagePathsInNfo);
var folder = item as BoxSet; if (item is BoxSet folder)
if (folder != null)
{ {
AddCollectionItems(folder, writer); AddCollectionItems(folder, writer);
} }
@ -866,29 +870,43 @@ namespace MediaBrowser.XbmcMetadata.Savers
var userdata = userDataRepo.GetUserData(user, item); var userdata = userDataRepo.GetUserData(user, item);
writer.WriteElementString("isuserfavorite", userdata.IsFavorite.ToString(CultureInfo.InvariantCulture).ToLowerInvariant()); writer.WriteElementString(
"isuserfavorite",
userdata.IsFavorite.ToString(CultureInfo.InvariantCulture).ToLowerInvariant());
if (userdata.Rating.HasValue) if (userdata.Rating.HasValue)
{ {
writer.WriteElementString("userrating", userdata.Rating.Value.ToString(CultureInfo.InvariantCulture).ToLowerInvariant()); writer.WriteElementString(
"userrating",
userdata.Rating.Value.ToString(CultureInfo.InvariantCulture).ToLowerInvariant());
} }
if (!item.IsFolder) if (!item.IsFolder)
{ {
writer.WriteElementString("playcount", userdata.PlayCount.ToString(UsCulture)); writer.WriteElementString(
writer.WriteElementString("watched", userdata.Played.ToString(CultureInfo.InvariantCulture).ToLowerInvariant()); "playcount",
userdata.PlayCount.ToString(CultureInfo.InvariantCulture));
writer.WriteElementString(
"watched",
userdata.Played.ToString(CultureInfo.InvariantCulture).ToLowerInvariant());
if (userdata.LastPlayedDate.HasValue) if (userdata.LastPlayedDate.HasValue)
{ {
writer.WriteElementString("lastplayed", userdata.LastPlayedDate.Value.ToLocalTime().ToString("yyyy-MM-dd HH:mm:ss").ToLowerInvariant()); writer.WriteElementString(
"lastplayed",
userdata.LastPlayedDate.Value.ToLocalTime().ToString("yyyy-MM-dd HH:mm:ss").ToLowerInvariant());
} }
writer.WriteStartElement("resume"); writer.WriteStartElement("resume");
var runTimeTicks = item.RunTimeTicks ?? 0; var runTimeTicks = item.RunTimeTicks ?? 0;
writer.WriteElementString("position", TimeSpan.FromTicks(userdata.PlaybackPositionTicks).TotalSeconds.ToString(UsCulture)); writer.WriteElementString(
writer.WriteElementString("total", TimeSpan.FromTicks(runTimeTicks).TotalSeconds.ToString(UsCulture)); "position",
TimeSpan.FromTicks(userdata.PlaybackPositionTicks).TotalSeconds.ToString(CultureInfo.InvariantCulture));
writer.WriteElementString(
"total",
TimeSpan.FromTicks(runTimeTicks).TotalSeconds.ToString(CultureInfo.InvariantCulture));
} }
writer.WriteEndElement(); writer.WriteEndElement();
@ -922,24 +940,21 @@ namespace MediaBrowser.XbmcMetadata.Savers
if (person.SortOrder.HasValue) if (person.SortOrder.HasValue)
{ {
writer.WriteElementString("sortorder", person.SortOrder.Value.ToString(UsCulture)); writer.WriteElementString(
"sortorder",
person.SortOrder.Value.ToString(CultureInfo.InvariantCulture));
} }
if (saveImagePath) if (saveImagePath)
{ {
try var personEntity = libraryManager.GetPerson(person.Name);
{ var image = personEntity.GetImageInfo(ImageType.Primary, 0);
var personEntity = libraryManager.GetPerson(person.Name);
var image = personEntity.GetImageInfo(ImageType.Primary, 0);
if (image != null) if (image != null)
{
writer.WriteElementString("thumb", GetImagePathToSave(image, libraryManager, config));
}
}
catch (Exception)
{ {
// Already logged in core writer.WriteElementString(
"thumb",
GetImagePathToSave(image, libraryManager, config));
} }
} }
@ -958,11 +973,10 @@ namespace MediaBrowser.XbmcMetadata.Savers
} }
private bool IsPersonType(PersonInfo person, string type) private bool IsPersonType(PersonInfo person, string type)
{ => string.Equals(person.Type, type, StringComparison.OrdinalIgnoreCase)
return string.Equals(person.Type, type, StringComparison.OrdinalIgnoreCase) || string.Equals(person.Role, type, StringComparison.OrdinalIgnoreCase); || string.Equals(person.Role, type, StringComparison.OrdinalIgnoreCase);
}
private void AddCustomTags(string path, List<string> xmlTagsUsed, XmlWriter writer, ILogger logger, IFileSystem fileSystem) private void AddCustomTags(string path, List<string> xmlTagsUsed, XmlWriter writer, ILogger logger)
{ {
var settings = new XmlReaderSettings() var settings = new XmlReaderSettings()
{ {
@ -982,7 +996,7 @@ namespace MediaBrowser.XbmcMetadata.Savers
} }
catch (Exception ex) catch (Exception ex)
{ {
logger.LogError(ex, "Error reading existing xml tags from {path}.", path); logger.LogError(ex, "Error reading existing xml tags from {Path}.", path);
return; return;
} }
@ -995,7 +1009,8 @@ namespace MediaBrowser.XbmcMetadata.Savers
{ {
var name = reader.Name; var name = reader.Name;
if (!CommonTags.ContainsKey(name) && !xmlTagsUsed.Contains(name, StringComparer.OrdinalIgnoreCase)) if (!_commonTags.Contains(name)
&& !xmlTagsUsed.Contains(name, StringComparer.OrdinalIgnoreCase))
{ {
writer.WriteNode(reader, false); writer.WriteNode(reader, false);
} }
@ -1013,8 +1028,6 @@ namespace MediaBrowser.XbmcMetadata.Savers
} }
private string GetTagForProviderKey(string providerKey) private string GetTagForProviderKey(string providerKey)
{ => providerKey.ToLowerInvariant() + "id";
return providerKey.ToLowerInvariant() + "id";
}
} }
} }

@ -14,43 +14,43 @@ namespace MediaBrowser.XbmcMetadata.Savers
{ {
public class EpisodeNfoSaver : BaseNfoSaver public class EpisodeNfoSaver : BaseNfoSaver
{ {
protected override string GetLocalSavePath(BaseItem item) public EpisodeNfoSaver(IFileSystem fileSystem, IServerConfigurationManager configurationManager, ILibraryManager libraryManager, IUserManager userManager, IUserDataManager userDataManager, ILogger logger)
: base(fileSystem, configurationManager, libraryManager, userManager, userDataManager, logger)
{ {
return Path.ChangeExtension(item.Path, ".nfo");
} }
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
/// <inheritdoc />
protected override string GetLocalSavePath(BaseItem item)
=> Path.ChangeExtension(item.Path, ".nfo");
/// <inheritdoc />
protected override string GetRootElementName(BaseItem item) protected override string GetRootElementName(BaseItem item)
{ => "episodedetails";
return "episodedetails";
}
/// <inheritdoc />
public override bool IsEnabledFor(BaseItem item, ItemUpdateType updateType) public override bool IsEnabledFor(BaseItem item, ItemUpdateType updateType)
{ => !item.SupportsLocalMetadata && item is Episode && updateType >= MinimumUpdateType;
if (!item.SupportsLocalMetadata)
{
return false;
}
return item is Episode && updateType >= MinimumUpdateType;
}
/// <inheritdoc />
protected override void WriteCustomElements(BaseItem item, XmlWriter writer) protected override void WriteCustomElements(BaseItem item, XmlWriter writer)
{ {
var episode = (Episode)item; var episode = (Episode)item;
if (episode.IndexNumber.HasValue) if (episode.IndexNumber.HasValue)
{ {
writer.WriteElementString("episode", episode.IndexNumber.Value.ToString(UsCulture)); writer.WriteElementString("episode", episode.IndexNumber.Value.ToString(_usCulture));
} }
if (episode.IndexNumberEnd.HasValue) if (episode.IndexNumberEnd.HasValue)
{ {
writer.WriteElementString("episodenumberend", episode.IndexNumberEnd.Value.ToString(UsCulture)); writer.WriteElementString("episodenumberend", episode.IndexNumberEnd.Value.ToString(_usCulture));
} }
if (episode.ParentIndexNumber.HasValue) if (episode.ParentIndexNumber.HasValue)
{ {
writer.WriteElementString("season", episode.ParentIndexNumber.Value.ToString(UsCulture)); writer.WriteElementString("season", episode.ParentIndexNumber.Value.ToString(_usCulture));
} }
if (episode.PremiereDate.HasValue) if (episode.PremiereDate.HasValue)
@ -64,32 +64,33 @@ namespace MediaBrowser.XbmcMetadata.Savers
{ {
if (episode.AirsAfterSeasonNumber.HasValue && episode.AirsAfterSeasonNumber.Value != -1) if (episode.AirsAfterSeasonNumber.HasValue && episode.AirsAfterSeasonNumber.Value != -1)
{ {
writer.WriteElementString("airsafter_season", episode.AirsAfterSeasonNumber.Value.ToString(UsCulture)); writer.WriteElementString("airsafter_season", episode.AirsAfterSeasonNumber.Value.ToString(_usCulture));
} }
if (episode.AirsBeforeEpisodeNumber.HasValue && episode.AirsBeforeEpisodeNumber.Value != -1) if (episode.AirsBeforeEpisodeNumber.HasValue && episode.AirsBeforeEpisodeNumber.Value != -1)
{ {
writer.WriteElementString("airsbefore_episode", episode.AirsBeforeEpisodeNumber.Value.ToString(UsCulture)); writer.WriteElementString("airsbefore_episode", episode.AirsBeforeEpisodeNumber.Value.ToString(_usCulture));
} }
if (episode.AirsBeforeSeasonNumber.HasValue && episode.AirsBeforeSeasonNumber.Value != -1) if (episode.AirsBeforeSeasonNumber.HasValue && episode.AirsBeforeSeasonNumber.Value != -1)
{ {
writer.WriteElementString("airsbefore_season", episode.AirsBeforeSeasonNumber.Value.ToString(UsCulture)); writer.WriteElementString("airsbefore_season", episode.AirsBeforeSeasonNumber.Value.ToString(_usCulture));
} }
if (episode.AirsBeforeEpisodeNumber.HasValue && episode.AirsBeforeEpisodeNumber.Value != -1) if (episode.AirsBeforeEpisodeNumber.HasValue && episode.AirsBeforeEpisodeNumber.Value != -1)
{ {
writer.WriteElementString("displayepisode", episode.AirsBeforeEpisodeNumber.Value.ToString(UsCulture)); writer.WriteElementString("displayepisode", episode.AirsBeforeEpisodeNumber.Value.ToString(_usCulture));
} }
var specialSeason = episode.AiredSeasonNumber; var specialSeason = episode.AiredSeasonNumber;
if (specialSeason.HasValue && specialSeason.Value != -1) if (specialSeason.HasValue && specialSeason.Value != -1)
{ {
writer.WriteElementString("displayseason", specialSeason.Value.ToString(UsCulture)); writer.WriteElementString("displayseason", specialSeason.Value.ToString(_usCulture));
} }
} }
} }
private readonly CultureInfo UsCulture = new CultureInfo("en-US"); /// <inheritdoc />
protected override List<string> GetTagsUsed(BaseItem item) protected override List<string> GetTagsUsed(BaseItem item)
{ {
var list = base.GetTagsUsed(item); var list = base.GetTagsUsed(item);
@ -105,12 +106,8 @@ namespace MediaBrowser.XbmcMetadata.Savers
"displayseason", "displayseason",
"displayepisode" "displayepisode"
}); });
return list;
}
public EpisodeNfoSaver(IFileSystem fileSystem, IServerConfigurationManager configurationManager, ILibraryManager libraryManager, IUserManager userManager, IUserDataManager userDataManager, ILogger logger) return list;
: base(fileSystem, configurationManager, libraryManager, userManager, userDataManager, logger)
{
} }
} }
} }

@ -1,5 +1,6 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq;
using System.Xml; using System.Xml;
using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities;
@ -15,28 +16,29 @@ namespace MediaBrowser.XbmcMetadata.Savers
{ {
public class MovieNfoSaver : BaseNfoSaver public class MovieNfoSaver : BaseNfoSaver
{ {
protected override string GetLocalSavePath(BaseItem item) public MovieNfoSaver(IFileSystem fileSystem, IServerConfigurationManager configurationManager, ILibraryManager libraryManager, IUserManager userManager, IUserDataManager userDataManager, ILogger logger)
: base(fileSystem, configurationManager, libraryManager, userManager, userDataManager, logger)
{ {
var paths = GetMovieSavePaths(new ItemInfo(item), FileSystem);
return paths.Count == 0 ? null : paths[0];
} }
public static List<string> GetMovieSavePaths(ItemInfo item, IFileSystem fileSystem) /// <inheritdoc />
{ protected override string GetLocalSavePath(BaseItem item)
var list = new List<string>(); => GetMovieSavePaths(new ItemInfo(item)).FirstOrDefault();
public static IEnumerable<string> GetMovieSavePaths(ItemInfo item)
{
if (item.VideoType == VideoType.Dvd && !item.IsPlaceHolder) if (item.VideoType == VideoType.Dvd && !item.IsPlaceHolder)
{ {
var path = item.ContainingFolderPath; var path = item.ContainingFolderPath;
list.Add(Path.Combine(path, "VIDEO_TS", "VIDEO_TS.nfo")); yield return Path.Combine(path, "VIDEO_TS", "VIDEO_TS.nfo");
} }
if (!item.IsPlaceHolder && (item.VideoType == VideoType.Dvd || item.VideoType == VideoType.BluRay)) if (!item.IsPlaceHolder && (item.VideoType == VideoType.Dvd || item.VideoType == VideoType.BluRay))
{ {
var path = item.ContainingFolderPath; var path = item.ContainingFolderPath;
list.Add(Path.Combine(path, Path.GetFileName(path) + ".nfo")); yield return Path.Combine(path, Path.GetFileName(path) + ".nfo");
} }
else else
{ {
@ -47,22 +49,20 @@ namespace MediaBrowser.XbmcMetadata.Savers
// list.Add(Path.Combine(item.ContainingFolderPath, "movie.nfo")); // list.Add(Path.Combine(item.ContainingFolderPath, "movie.nfo"));
//} //}
list.Add(Path.ChangeExtension(item.Path, ".nfo")); yield return Path.ChangeExtension(item.Path, ".nfo");
if (!item.IsInMixedFolder) if (!item.IsInMixedFolder)
{ {
list.Add(Path.Combine(item.ContainingFolderPath, "movie.nfo")); yield return Path.Combine(item.ContainingFolderPath, "movie.nfo");
} }
} }
return list;
} }
/// <inheritdoc />
protected override string GetRootElementName(BaseItem item) protected override string GetRootElementName(BaseItem item)
{ => item is MusicVideo ? "musicvideo" : "movie";
return item is MusicVideo ? "musicvideo" : "movie";
}
/// <inheritdoc />
public override bool IsEnabledFor(BaseItem item, ItemUpdateType updateType) public override bool IsEnabledFor(BaseItem item, ItemUpdateType updateType)
{ {
if (!item.SupportsLocalMetadata) if (!item.SupportsLocalMetadata)
@ -70,10 +70,8 @@ namespace MediaBrowser.XbmcMetadata.Savers
return false; return false;
} }
var video = item as Video;
// Check parent for null to avoid running this against things like video backdrops // Check parent for null to avoid running this against things like video backdrops
if (video != null && !(item is Episode) && !video.ExtraType.HasValue) if (item is Video video && !(item is Episode) && !video.ExtraType.HasValue)
{ {
return updateType >= MinimumUpdateType; return updateType >= MinimumUpdateType;
} }
@ -81,6 +79,7 @@ namespace MediaBrowser.XbmcMetadata.Savers
return false; return false;
} }
/// <inheritdoc />
protected override void WriteCustomElements(BaseItem item, XmlWriter writer) protected override void WriteCustomElements(BaseItem item, XmlWriter writer)
{ {
var imdb = item.GetProviderId(MetadataProviders.Imdb); var imdb = item.GetProviderId(MetadataProviders.Imdb);
@ -90,9 +89,7 @@ namespace MediaBrowser.XbmcMetadata.Savers
writer.WriteElementString("id", imdb); writer.WriteElementString("id", imdb);
} }
var musicVideo = item as MusicVideo; if (item is MusicVideo musicVideo)
if (musicVideo != null)
{ {
foreach (var artist in musicVideo.Artists) foreach (var artist in musicVideo.Artists)
{ {
@ -104,9 +101,7 @@ namespace MediaBrowser.XbmcMetadata.Savers
} }
} }
var movie = item as Movie; if (item is Movie movie)
if (movie != null)
{ {
if (!string.IsNullOrEmpty(movie.CollectionName)) if (!string.IsNullOrEmpty(movie.CollectionName))
{ {
@ -115,6 +110,7 @@ namespace MediaBrowser.XbmcMetadata.Savers
} }
} }
/// <inheritdoc />
protected override List<string> GetTagsUsed(BaseItem item) protected override List<string> GetTagsUsed(BaseItem item)
{ {
var list = base.GetTagsUsed(item); var list = base.GetTagsUsed(item);
@ -125,12 +121,8 @@ namespace MediaBrowser.XbmcMetadata.Savers
"set", "set",
"id" "id"
}); });
return list;
}
public MovieNfoSaver(IFileSystem fileSystem, IServerConfigurationManager configurationManager, ILibraryManager libraryManager, IUserManager userManager, IUserDataManager userDataManager, ILogger logger) return list;
: base(fileSystem, configurationManager, libraryManager, userManager, userDataManager, logger)
{
} }
} }
} }

@ -13,16 +13,26 @@ namespace MediaBrowser.XbmcMetadata.Savers
{ {
public class SeasonNfoSaver : BaseNfoSaver public class SeasonNfoSaver : BaseNfoSaver
{ {
protected override string GetLocalSavePath(BaseItem item) public SeasonNfoSaver(
IFileSystem fileSystem,
IServerConfigurationManager configurationManager,
ILibraryManager libraryManager,
IUserManager userManager,
IUserDataManager userDataManager,
ILogger logger)
: base(fileSystem, configurationManager, libraryManager, userManager, userDataManager, logger)
{ {
return Path.Combine(item.Path, "season.nfo");
} }
/// <inheritdoc />
protected override string GetLocalSavePath(BaseItem item)
=> Path.Combine(item.Path, "season.nfo");
/// <inheritdoc />
protected override string GetRootElementName(BaseItem item) protected override string GetRootElementName(BaseItem item)
{ => "season";
return "season";
}
/// <inheritdoc />
public override bool IsEnabledFor(BaseItem item, ItemUpdateType updateType) public override bool IsEnabledFor(BaseItem item, ItemUpdateType updateType)
{ {
if (!item.SupportsLocalMetadata) if (!item.SupportsLocalMetadata)
@ -38,6 +48,7 @@ namespace MediaBrowser.XbmcMetadata.Savers
return updateType >= MinimumUpdateType || (updateType >= ItemUpdateType.MetadataImport && File.Exists(GetSavePath(item))); return updateType >= MinimumUpdateType || (updateType >= ItemUpdateType.MetadataImport && File.Exists(GetSavePath(item)));
} }
/// <inheritdoc />
protected override void WriteCustomElements(BaseItem item, XmlWriter writer) protected override void WriteCustomElements(BaseItem item, XmlWriter writer)
{ {
var season = (Season)item; var season = (Season)item;
@ -48,6 +59,7 @@ namespace MediaBrowser.XbmcMetadata.Savers
} }
} }
/// <inheritdoc />
protected override List<string> GetTagsUsed(BaseItem item) protected override List<string> GetTagsUsed(BaseItem item)
{ {
var list = base.GetTagsUsed(item); var list = base.GetTagsUsed(item);
@ -58,16 +70,5 @@ namespace MediaBrowser.XbmcMetadata.Savers
return list; return list;
} }
public SeasonNfoSaver(
IFileSystem fileSystem,
IServerConfigurationManager configurationManager,
ILibraryManager libraryManager,
IUserManager userManager,
IUserDataManager userDataManager,
ILogger logger)
: base(fileSystem, configurationManager, libraryManager, userManager, userDataManager, logger)
{
}
} }
} }

@ -1,4 +1,5 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization;
using System.IO; using System.IO;
using System.Xml; using System.Xml;
using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Configuration;
@ -13,26 +14,30 @@ namespace MediaBrowser.XbmcMetadata.Savers
{ {
public class SeriesNfoSaver : BaseNfoSaver public class SeriesNfoSaver : BaseNfoSaver
{ {
protected override string GetLocalSavePath(BaseItem item) public SeriesNfoSaver(
IFileSystem fileSystem,
IServerConfigurationManager configurationManager,
ILibraryManager libraryManager,
IUserManager userManager,
IUserDataManager userDataManager,
ILogger logger)
: base(fileSystem, configurationManager, libraryManager, userManager, userDataManager, logger)
{ {
return Path.Combine(item.Path, "tvshow.nfo");
} }
/// <inheritdoc />
protected override string GetLocalSavePath(BaseItem item)
=> Path.Combine(item.Path, "tvshow.nfo");
/// <inheritdoc />
protected override string GetRootElementName(BaseItem item) protected override string GetRootElementName(BaseItem item)
{ => "tvshow";
return "tvshow";
}
/// <inheritdoc />
public override bool IsEnabledFor(BaseItem item, ItemUpdateType updateType) public override bool IsEnabledFor(BaseItem item, ItemUpdateType updateType)
{ => item.SupportsLocalMetadata && item is Series && updateType >= MinimumUpdateType;
if (!item.SupportsLocalMetadata)
{
return false;
}
return item is Series && updateType >= MinimumUpdateType;
}
/// <inheritdoc />
protected override void WriteCustomElements(BaseItem item, XmlWriter writer) protected override void WriteCustomElements(BaseItem item, XmlWriter writer)
{ {
var series = (Series)item; var series = (Series)item;
@ -52,7 +57,12 @@ namespace MediaBrowser.XbmcMetadata.Savers
writer.WriteStartElement("url"); writer.WriteStartElement("url");
writer.WriteAttributeString("cache", string.Format("{0}.xml", tvdb)); writer.WriteAttributeString("cache", string.Format("{0}.xml", tvdb));
writer.WriteString(string.Format("http://www.thetvdb.com/api/1D62F2F90030C444/series/{0}/all/{1}.zip", tvdb, language)); writer.WriteString(
string.Format(
CultureInfo.InvariantCulture,
"http://www.thetvdb.com/api/1D62F2F90030C444/series/{0}/all/{1}.zip",
tvdb,
language));
writer.WriteEndElement(); writer.WriteEndElement();
writer.WriteEndElement(); writer.WriteEndElement();
@ -67,6 +77,7 @@ namespace MediaBrowser.XbmcMetadata.Savers
} }
} }
/// <inheritdoc />
protected override List<string> GetTagsUsed(BaseItem item) protected override List<string> GetTagsUsed(BaseItem item)
{ {
var list = base.GetTagsUsed(item); var list = base.GetTagsUsed(item);
@ -79,12 +90,8 @@ namespace MediaBrowser.XbmcMetadata.Savers
"status", "status",
"displayorder" "displayorder"
}); });
return list;
}
public SeriesNfoSaver(IFileSystem fileSystem, IServerConfigurationManager configurationManager, ILibraryManager libraryManager, IUserManager userManager, IUserDataManager userDataManager, ILogger logger) return list;
: base(fileSystem, configurationManager, libraryManager, userManager, userDataManager, logger)
{
} }
} }
} }

Loading…
Cancel
Save