added artist/slbum xml savers

This commit is contained in:
Luke Pulverenti 2013-06-23 14:55:30 -04:00
parent 41f84fc6b2
commit 10caa7ff83
20 changed files with 441 additions and 210 deletions

View File

@ -1142,6 +1142,19 @@ namespace MediaBrowser.Controller.Entities
} }
} }
public void AddTag(string name)
{
if (string.IsNullOrWhiteSpace(name))
{
throw new ArgumentNullException("name");
}
if (!Tags.Contains(name, StringComparer.OrdinalIgnoreCase))
{
Tags.Add(name);
}
}
/// <summary> /// <summary>
/// Adds a tagline to the item /// Adds a tagline to the item
/// </summary> /// </summary>

View File

@ -65,6 +65,7 @@ namespace MediaBrowser.Controller.Providers
item.Studios.Clear(); item.Studios.Clear();
item.Genres.Clear(); item.Genres.Clear();
item.People.Clear(); item.People.Clear();
item.Tags.Clear();
// Use european encoding as it will accept more characters // Use european encoding as it will accept more characters
using (var streamReader = new StreamReader(metadataFile, Encoding.GetEncoding("ISO-8859-1"))) using (var streamReader = new StreamReader(metadataFile, Encoding.GetEncoding("ISO-8859-1")))
@ -397,6 +398,7 @@ namespace MediaBrowser.Controller.Providers
break; break;
} }
case "PremiereDate":
case "FirstAired": case "FirstAired":
{ {
var firstAired = reader.ReadElementContentAsString(); var firstAired = reader.ReadElementContentAsString();
@ -453,6 +455,10 @@ namespace MediaBrowser.Controller.Providers
FetchFromGenresNode(reader.ReadSubtree(), item); FetchFromGenresNode(reader.ReadSubtree(), item);
break; break;
case "Tags":
FetchFromTagsNode(reader.ReadSubtree(), item);
break;
case "Persons": case "Persons":
FetchDataFromPersonsNode(reader.ReadSubtree(), item); FetchDataFromPersonsNode(reader.ReadSubtree(), item);
break; break;
@ -539,6 +545,35 @@ namespace MediaBrowser.Controller.Providers
} }
} }
private void FetchFromTagsNode(XmlReader reader, T item)
{
reader.MoveToContent();
while (reader.Read())
{
if (reader.NodeType == XmlNodeType.Element)
{
switch (reader.Name)
{
case "Tag":
{
var tag = reader.ReadElementContentAsString();
if (!string.IsNullOrWhiteSpace(tag))
{
item.AddTagline(tag);
}
break;
}
default:
reader.Skip();
break;
}
}
}
}
/// <summary> /// <summary>
/// Fetches the data from persons node. /// Fetches the data from persons node.
/// </summary> /// </summary>

View File

@ -15,7 +15,8 @@ namespace MediaBrowser.Providers
/// </summary> /// </summary>
public class FolderProviderFromXml : BaseMetadataProvider public class FolderProviderFromXml : BaseMetadataProvider
{ {
public FolderProviderFromXml(ILogManager logManager, IServerConfigurationManager configurationManager) : base(logManager, configurationManager) public FolderProviderFromXml(ILogManager logManager, IServerConfigurationManager configurationManager)
: base(logManager, configurationManager)
{ {
} }

View File

@ -64,6 +64,7 @@
<Compile Include="Movies\OpenMovieDatabaseProvider.cs" /> <Compile Include="Movies\OpenMovieDatabaseProvider.cs" />
<Compile Include="Movies\PersonProviderFromXml.cs" /> <Compile Include="Movies\PersonProviderFromXml.cs" />
<Compile Include="Movies\TmdbPersonProvider.cs" /> <Compile Include="Movies\TmdbPersonProvider.cs" />
<Compile Include="Music\ArtistProviderFromXml.cs" />
<Compile Include="Music\ArtistsPostScanTask.cs" /> <Compile Include="Music\ArtistsPostScanTask.cs" />
<Compile Include="Music\FanArtAlbumProvider.cs" /> <Compile Include="Music\FanArtAlbumProvider.cs" />
<Compile Include="Music\FanArtArtistByNameProvider.cs" /> <Compile Include="Music\FanArtArtistByNameProvider.cs" />
@ -74,14 +75,15 @@
<Compile Include="Music\LastfmArtistProvider.cs" /> <Compile Include="Music\LastfmArtistProvider.cs" />
<Compile Include="Music\LastfmBaseProvider.cs" /> <Compile Include="Music\LastfmBaseProvider.cs" />
<Compile Include="Music\LastfmHelper.cs" /> <Compile Include="Music\LastfmHelper.cs" />
<Compile Include="Music\MusicArtistProviderFromJson.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Savers\AlbumXmlSaver.cs" />
<Compile Include="Savers\ArtistXmlSaver.cs" />
<Compile Include="Savers\EpisodeXmlSaver.cs" /> <Compile Include="Savers\EpisodeXmlSaver.cs" />
<Compile Include="Savers\FolderXmlSaver.cs" /> <Compile Include="Savers\FolderXmlSaver.cs" />
<Compile Include="Savers\MovieXmlSaver.cs" /> <Compile Include="Savers\MovieXmlSaver.cs" />
<Compile Include="Savers\PersonXmlSaver.cs" /> <Compile Include="Savers\PersonXmlSaver.cs" />
<Compile Include="Savers\SeriesXmlSaver.cs" /> <Compile Include="Savers\SeriesXmlSaver.cs" />
<Compile Include="Savers\XmlHelpers.cs" /> <Compile Include="Savers\XmlSaverHelpers.cs" />
<Compile Include="TV\EpisodeImageFromMediaLocationProvider.cs" /> <Compile Include="TV\EpisodeImageFromMediaLocationProvider.cs" />
<Compile Include="TV\EpisodeIndexNumberProvider.cs" /> <Compile Include="TV\EpisodeIndexNumberProvider.cs" />
<Compile Include="TV\EpisodeProviderFromXml.cs" /> <Compile Include="TV\EpisodeProviderFromXml.cs" />

View File

@ -1,11 +1,9 @@
using MediaBrowser.Common.Net; using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Controller.Providers.Music;
using MediaBrowser.Model.Logging; using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Net;
using MediaBrowser.Model.Serialization; using MediaBrowser.Model.Serialization;
using MediaBrowser.Providers.Music;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization; using System.Globalization;
@ -14,7 +12,6 @@ using System.Linq;
using System.Text; using System.Text;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using MediaBrowser.Providers.Music;
namespace MediaBrowser.Providers.Movies namespace MediaBrowser.Providers.Movies
{ {

View File

@ -0,0 +1,107 @@
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging;
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
namespace MediaBrowser.Providers.Music
{
class ArtistProviderFromXml : BaseMetadataProvider
{
public ArtistProviderFromXml(ILogManager logManager, IServerConfigurationManager configurationManager)
: base(logManager, configurationManager)
{
}
/// <summary>
/// Supportses the specified item.
/// </summary>
/// <param name="item">The item.</param>
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
public override bool Supports(BaseItem item)
{
return (item is Artist || item is MusicArtist) && item.LocationType == LocationType.FileSystem;
}
/// <summary>
/// Gets the priority.
/// </summary>
/// <value>The priority.</value>
public override MetadataProviderPriority Priority
{
get { return MetadataProviderPriority.First; }
}
/// <summary>
/// Override this to return the date that should be compared to the last refresh date
/// to determine if this provider should be re-fetched.
/// </summary>
/// <param name="item">The item.</param>
/// <returns>DateTime.</returns>
protected override DateTime CompareDate(BaseItem item)
{
var entry = item.MetaLocation != null ? item.ResolveArgs.GetMetaFileByPath(Path.Combine(item.MetaLocation, "artist.xml")) : null;
return entry != null ? entry.LastWriteTimeUtc : DateTime.MinValue;
}
/// <summary>
/// Fetches metadata and returns true or false indicating if any work that requires persistence was done
/// </summary>
/// <param name="item">The item.</param>
/// <param name="force">if set to <c>true</c> [force].</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task{System.Boolean}.</returns>
public override Task<bool> FetchAsync(BaseItem item, bool force, CancellationToken cancellationToken)
{
return Fetch(item, cancellationToken);
}
/// <summary>
/// Fetches the specified item.
/// </summary>
/// <param name="item">The item.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
private async Task<bool> Fetch(BaseItem item, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
var metadataFile = item.ResolveArgs.GetMetaFileByPath(Path.Combine(item.MetaLocation, "artist.xml"));
if (metadataFile != null)
{
var path = metadataFile.FullName;
await XmlParsingResourcePool.WaitAsync(cancellationToken).ConfigureAwait(false);
try
{
var artist = item as Artist;
if (artist != null)
{
new BaseItemXmlParser<Artist>(Logger).Fetch(artist, path, cancellationToken);
}
else
{
new BaseItemXmlParser<MusicArtist>(Logger).Fetch((MusicArtist)item, path, cancellationToken);
}
}
finally
{
XmlParsingResourcePool.Release();
}
SetLastRefreshed(item, DateTime.UtcNow);
return true;
}
return false;
}
}
}

View File

@ -7,12 +7,11 @@ using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities; using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging; using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Serialization; using MediaBrowser.Model.Serialization;
using MoreLinq;
using System; using System;
using System.IO;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using MoreLinq;
namespace MediaBrowser.Providers.Music namespace MediaBrowser.Providers.Music
{ {
@ -20,18 +19,9 @@ namespace MediaBrowser.Providers.Music
{ {
private static readonly Task<string> BlankId = Task.FromResult(""); private static readonly Task<string> BlankId = Task.FromResult("");
private readonly IProviderManager _providerManager; public LastfmAlbumProvider(IJsonSerializer jsonSerializer, IHttpClient httpClient, ILogManager logManager, IServerConfigurationManager configurationManager)
/// <summary>
/// The name of the local json meta file for this item type
/// </summary>
protected string LocalMetaFileName { get; set; }
public LastfmAlbumProvider(IJsonSerializer jsonSerializer, IHttpClient httpClient, ILogManager logManager, IServerConfigurationManager configurationManager, IProviderManager providerManager)
: base(jsonSerializer, httpClient, logManager, configurationManager) : base(jsonSerializer, httpClient, logManager, configurationManager)
{ {
_providerManager = providerManager;
LocalMetaFileName = LastfmHelper.LocalAlbumMetaFileName;
} }
protected override Task<string> FindId(BaseItem item, CancellationToken cancellationToken) protected override Task<string> FindId(BaseItem item, CancellationToken cancellationToken)
@ -40,6 +30,11 @@ namespace MediaBrowser.Providers.Music
return BlankId; return BlankId;
} }
private bool HasAltMeta(BaseItem item)
{
return item.LocationType == LocationType.FileSystem && item.ResolveArgs.ContainsMetaFileByName("album.xml");
}
/// <summary> /// <summary>
/// Needses the refresh internal. /// Needses the refresh internal.
/// </summary> /// </summary>
@ -48,6 +43,11 @@ namespace MediaBrowser.Providers.Music
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns> /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
protected override bool NeedsRefreshInternal(BaseItem item, BaseProviderInfo providerInfo) protected override bool NeedsRefreshInternal(BaseItem item, BaseProviderInfo providerInfo)
{ {
if (HasAltMeta(item))
{
return false;
}
// If song metadata has changed and we don't have an mbid, refresh // If song metadata has changed and we don't have an mbid, refresh
if (string.IsNullOrEmpty(item.GetProviderId(MetadataProviders.Musicbrainz)) && if (string.IsNullOrEmpty(item.GetProviderId(MetadataProviders.Musicbrainz)) &&
GetComparisonData(item as MusicAlbum) != providerInfo.FileStamp) GetComparisonData(item as MusicAlbum) != providerInfo.FileStamp)
@ -65,17 +65,6 @@ namespace MediaBrowser.Providers.Music
if (result != null && result.album != null) if (result != null && result.album != null)
{ {
LastfmHelper.ProcessAlbumData(item, result.album); LastfmHelper.ProcessAlbumData(item, result.album);
//And save locally if indicated
if (ConfigurationManager.Configuration.SaveLocalMeta)
{
var ms = new MemoryStream();
JsonSerializer.SerializeToStream(result.album, ms);
cancellationToken.ThrowIfCancellationRequested();
await _providerManager.SaveToLibraryFilesystem(item, Path.Combine(item.MetaLocation, LocalMetaFileName), ms, cancellationToken).ConfigureAwait(false);
}
} }
BaseProviderInfo data; BaseProviderInfo data;

View File

@ -3,7 +3,6 @@ using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities; using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging; using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Serialization; using MediaBrowser.Model.Serialization;
@ -26,10 +25,9 @@ namespace MediaBrowser.Providers.Music
/// <param name="httpClient">The HTTP client.</param> /// <param name="httpClient">The HTTP client.</param>
/// <param name="logManager">The log manager.</param> /// <param name="logManager">The log manager.</param>
/// <param name="configurationManager">The configuration manager.</param> /// <param name="configurationManager">The configuration manager.</param>
/// <param name="providerManager">The provider manager.</param>
/// <param name="libraryManager">The library manager.</param> /// <param name="libraryManager">The library manager.</param>
public LastfmArtistByNameProvider(IJsonSerializer jsonSerializer, IHttpClient httpClient, ILogManager logManager, IServerConfigurationManager configurationManager, IProviderManager providerManager, ILibraryManager libraryManager) public LastfmArtistByNameProvider(IJsonSerializer jsonSerializer, IHttpClient httpClient, ILogManager logManager, IServerConfigurationManager configurationManager, ILibraryManager libraryManager)
: base(jsonSerializer, httpClient, logManager, configurationManager, providerManager, libraryManager) : base(jsonSerializer, httpClient, logManager, configurationManager, libraryManager)
{ {
} }

View File

@ -4,7 +4,6 @@ using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Providers; using MediaBrowser.Controller.Providers;
using MediaBrowser.Controller.Providers.Music;
using MediaBrowser.Model.Entities; using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging; using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Net; using MediaBrowser.Model.Net;
@ -26,35 +25,38 @@ namespace MediaBrowser.Providers.Music
/// </summary> /// </summary>
public class LastfmArtistProvider : LastfmBaseProvider public class LastfmArtistProvider : LastfmBaseProvider
{ {
/// <summary>
/// The _provider manager
/// </summary>
private readonly IProviderManager _providerManager;
/// <summary> /// <summary>
/// The _library manager /// The _library manager
/// </summary> /// </summary>
protected readonly ILibraryManager LibraryManager; protected readonly ILibraryManager LibraryManager;
/// <summary> /// <summary>
/// The name of the local json meta file for this item type /// Initializes a new instance of the <see cref="LastfmArtistProvider" /> class.
/// </summary>
protected string LocalMetaFileName { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="LastfmArtistProvider"/> class.
/// </summary> /// </summary>
/// <param name="jsonSerializer">The json serializer.</param> /// <param name="jsonSerializer">The json serializer.</param>
/// <param name="httpClient">The HTTP client.</param> /// <param name="httpClient">The HTTP client.</param>
/// <param name="logManager">The log manager.</param> /// <param name="logManager">The log manager.</param>
/// <param name="configurationManager">The configuration manager.</param> /// <param name="configurationManager">The configuration manager.</param>
/// <param name="providerManager">The provider manager.</param>
/// <param name="libraryManager">The library manager.</param> /// <param name="libraryManager">The library manager.</param>
public LastfmArtistProvider(IJsonSerializer jsonSerializer, IHttpClient httpClient, ILogManager logManager, IServerConfigurationManager configurationManager, IProviderManager providerManager, ILibraryManager libraryManager) public LastfmArtistProvider(IJsonSerializer jsonSerializer, IHttpClient httpClient, ILogManager logManager, IServerConfigurationManager configurationManager, ILibraryManager libraryManager)
: base(jsonSerializer, httpClient, logManager, configurationManager) : base(jsonSerializer, httpClient, logManager, configurationManager)
{ {
_providerManager = providerManager;
LibraryManager = libraryManager; LibraryManager = libraryManager;
LocalMetaFileName = LastfmHelper.LocalArtistMetaFileName; }
protected override bool NeedsRefreshInternal(BaseItem item, BaseProviderInfo providerInfo)
{
if (HasAltMeta(item))
{
return false;
}
return base.NeedsRefreshInternal(item, providerInfo);
}
private bool HasAltMeta(BaseItem item)
{
return item.LocationType == LocationType.FileSystem && item.ResolveArgs.ContainsMetaFileByName("artist.xml");
} }
/// <summary> /// <summary>
@ -259,21 +261,6 @@ namespace MediaBrowser.Providers.Music
if (result != null && result.artist != null) if (result != null && result.artist != null)
{ {
LastfmHelper.ProcessArtistData(item, result.artist); LastfmHelper.ProcessArtistData(item, result.artist);
//And save locally if indicated
if (SaveLocalMeta)
{
var ms = new MemoryStream();
JsonSerializer.SerializeToStream(result.artist, ms);
if (cancellationToken.IsCancellationRequested)
{
ms.Dispose();
cancellationToken.ThrowIfCancellationRequested();
}
await _providerManager.SaveToLibraryFilesystem(item, Path.Combine(item.MetaLocation, LocalMetaFileName), ms, cancellationToken).ConfigureAwait(false);
}
} }
} }

View File

@ -1,6 +1,5 @@
using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Providers.Music;
using MediaBrowser.Model.Entities; using MediaBrowser.Model.Entities;
using System; using System;
using System.Linq; using System.Linq;
@ -9,9 +8,6 @@ namespace MediaBrowser.Providers.Music
{ {
public static class LastfmHelper public static class LastfmHelper
{ {
public static string LocalArtistMetaFileName = "lastfmartist.json";
public static string LocalAlbumMetaFileName = "lastfmalbum.json";
public static void ProcessArtistData(BaseItem artist, LastfmArtist data) public static void ProcessArtistData(BaseItem artist, LastfmArtist data)
{ {
var yearFormed = 0; var yearFormed = 0;

View File

@ -1,101 +0,0 @@
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Serialization;
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Providers.Music;
namespace MediaBrowser.Controller.Providers.Music
{
public class MusicArtistProviderFromJson : BaseMetadataProvider
{
/// <summary>
/// Gets the json serializer.
/// </summary>
/// <value>The json serializer.</value>
protected IJsonSerializer JsonSerializer { get; private set; }
public MusicArtistProviderFromJson(IJsonSerializer jsonSerializer, ILogManager logManager, IServerConfigurationManager configurationManager)
: base(logManager, configurationManager)
{
if (jsonSerializer == null)
{
throw new ArgumentNullException("jsonSerializer");
}
JsonSerializer = jsonSerializer;
}
public override Task<bool> FetchAsync(BaseItem item, bool force, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
var entry = item.ResolveArgs.GetMetaFileByPath(Path.Combine(item.MetaLocation, LastfmHelper.LocalArtistMetaFileName));
if (entry != null)
{
// read in our saved meta and pass to processing function
var data = JsonSerializer.DeserializeFromFile<LastfmArtist>(entry.FullName);
cancellationToken.ThrowIfCancellationRequested();
LastfmHelper.ProcessArtistData(item, data);
item.SetProviderId(MetadataProviders.Musicbrainz, data.mbid);
SetLastRefreshed(item, DateTime.UtcNow);
return TrueTaskResult;
}
return FalseTaskResult;
}
public override MetadataProviderPriority Priority
{
get
{
return MetadataProviderPriority.First;
}
}
public override bool Supports(BaseItem item)
{
return false;
}
public override bool RequiresInternet
{
get
{
return false;
}
}
protected override bool NeedsRefreshInternal(BaseItem item, BaseProviderInfo providerInfo)
{
if (!item.ResolveArgs.ContainsMetaFileByName(LastfmHelper.LocalArtistMetaFileName))
{
return false; // nothing to read
}
// Need to re-override to jump over intermediate implementation
return CompareDate(item) > providerInfo.LastRefreshed;
}
/// <summary>
/// Override this to return the date that should be compared to the last refresh date
/// to determine if this provider should be re-fetched.
/// </summary>
/// <param name="item">The item.</param>
/// <returns>DateTime.</returns>
protected override DateTime CompareDate(BaseItem item)
{
var entry = item.ResolveArgs.GetMetaFileByPath(Path.Combine(item.MetaLocation, LastfmHelper.LocalArtistMetaFileName));
return entry != null ? entry.LastWriteTimeUtc : DateTime.MinValue;
}
}
}

View File

@ -0,0 +1,77 @@
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Library;
using MediaBrowser.Model.Entities;
using MediaBrowser.Providers.Movies;
using System;
using System.IO;
using System.Text;
using System.Threading;
namespace MediaBrowser.Providers.Savers
{
class AlbumXmlSaver : IMetadataSaver
{
private readonly IServerConfigurationManager _config;
public AlbumXmlSaver(IServerConfigurationManager config)
{
_config = config;
}
/// <summary>
/// Supportses the specified item.
/// </summary>
/// <param name="item">The item.</param>
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
public bool Supports(BaseItem item)
{
if (item.LocationType != LocationType.FileSystem)
{
return false;
}
if (item is MusicAlbum)
{
return _config.Configuration.SaveLocalMeta;
}
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(BaseItem item, CancellationToken cancellationToken)
{
var builder = new StringBuilder();
builder.Append("<Item>");
XmlSaverHelpers.AddCommonNodes(item, builder);
builder.Append("</Item>");
var xmlFilePath = GetSavePath(item);
XmlSaverHelpers.Save(builder, xmlFilePath);
// Set last refreshed so that the provider doesn't trigger after the file save
PersonProviderFromXml.Current.SetLastRefreshed(item, DateTime.UtcNow);
}
/// <summary>
/// Gets the save path.
/// </summary>
/// <param name="item">The item.</param>
/// <returns>System.String.</returns>
public string GetSavePath(BaseItem item)
{
return Path.Combine(item.Path, "album.xml");
}
}
}

View File

@ -0,0 +1,77 @@
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Library;
using MediaBrowser.Model.Entities;
using MediaBrowser.Providers.Movies;
using System;
using System.IO;
using System.Text;
using System.Threading;
namespace MediaBrowser.Providers.Savers
{
class ArtistXmlSaver : IMetadataSaver
{
private readonly IServerConfigurationManager _config;
public ArtistXmlSaver(IServerConfigurationManager config)
{
_config = config;
}
/// <summary>
/// Supportses the specified item.
/// </summary>
/// <param name="item">The item.</param>
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
public bool Supports(BaseItem item)
{
if (item.LocationType != LocationType.FileSystem)
{
return false;
}
if (item is MusicArtist)
{
return _config.Configuration.SaveLocalMeta;
}
return item is Artist;
}
/// <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(BaseItem item, CancellationToken cancellationToken)
{
var builder = new StringBuilder();
builder.Append("<Item>");
XmlSaverHelpers.AddCommonNodes(item, builder);
builder.Append("</Item>");
var xmlFilePath = GetSavePath(item);
XmlSaverHelpers.Save(builder, xmlFilePath);
// Set last refreshed so that the provider doesn't trigger after the file save
PersonProviderFromXml.Current.SetLastRefreshed(item, DateTime.UtcNow);
}
/// <summary>
/// Gets the save path.
/// </summary>
/// <param name="item">The item.</param>
/// <returns>System.String.</returns>
public string GetSavePath(BaseItem item)
{
return Path.Combine(item.Path, "artist.xml");
}
}
}

View File

@ -65,14 +65,14 @@ namespace MediaBrowser.Providers.Savers
builder.Append("<FirstAired>" + SecurityElement.Escape(episode.PremiereDate.Value.ToString("yyyy-MM-dd")) + "</FirstAired>"); builder.Append("<FirstAired>" + SecurityElement.Escape(episode.PremiereDate.Value.ToString("yyyy-MM-dd")) + "</FirstAired>");
} }
XmlHelpers.AddCommonNodes(item, builder); XmlSaverHelpers.AddCommonNodes(item, builder);
XmlHelpers.AppendMediaInfo(episode, builder); XmlSaverHelpers.AppendMediaInfo(episode, builder);
builder.Append("</Item>"); builder.Append("</Item>");
var xmlFilePath = GetSavePath(item); var xmlFilePath = GetSavePath(item);
XmlHelpers.Save(builder, xmlFilePath); XmlSaverHelpers.Save(builder, xmlFilePath);
// Set last refreshed so that the provider doesn't trigger after the file save // Set last refreshed so that the provider doesn't trigger after the file save
EpisodeProviderFromXml.Current.SetLastRefreshed(item, DateTime.UtcNow); EpisodeProviderFromXml.Current.SetLastRefreshed(item, DateTime.UtcNow);

View File

@ -1,4 +1,6 @@
using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Entities.Movies;
using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
@ -11,6 +13,13 @@ namespace MediaBrowser.Providers.Savers
{ {
public class FolderXmlSaver : IMetadataSaver public class FolderXmlSaver : IMetadataSaver
{ {
private readonly IServerConfigurationManager _config;
public FolderXmlSaver(IServerConfigurationManager config)
{
_config = config;
}
/// <summary> /// <summary>
/// Supportses the specified item. /// Supportses the specified item.
/// </summary> /// </summary>
@ -18,12 +27,12 @@ namespace MediaBrowser.Providers.Savers
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns> /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
public bool Supports(BaseItem item) public bool Supports(BaseItem item)
{ {
if (item.LocationType != LocationType.FileSystem) if (!_config.Configuration.SaveLocalMeta || item.LocationType != LocationType.FileSystem)
{ {
return false; return false;
} }
return item is Folder && !(item is Series) && !(item is BoxSet); return item is Folder && !(item is Series) && !(item is BoxSet) && !(item is MusicArtist) && !(item is MusicAlbum);
} }
/// <summary> /// <summary>
@ -38,13 +47,13 @@ namespace MediaBrowser.Providers.Savers
builder.Append("<Item>"); builder.Append("<Item>");
XmlHelpers.AddCommonNodes(item, builder); XmlSaverHelpers.AddCommonNodes(item, builder);
builder.Append("</Item>"); builder.Append("</Item>");
var xmlFilePath = GetSavePath(item); var xmlFilePath = GetSavePath(item);
XmlHelpers.Save(builder, xmlFilePath); XmlSaverHelpers.Save(builder, xmlFilePath);
} }
/// <summary> /// <summary>

View File

@ -1,4 +1,4 @@
using System.Text; using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Entities.Movies;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
@ -6,6 +6,7 @@ using MediaBrowser.Model.Entities;
using MediaBrowser.Providers.Movies; using MediaBrowser.Providers.Movies;
using System; using System;
using System.IO; using System.IO;
using System.Text;
using System.Threading; using System.Threading;
namespace MediaBrowser.Providers.Savers namespace MediaBrowser.Providers.Savers
@ -15,6 +16,13 @@ namespace MediaBrowser.Providers.Savers
/// </summary> /// </summary>
public class MovieXmlSaver : IMetadataSaver public class MovieXmlSaver : IMetadataSaver
{ {
private readonly IServerConfigurationManager _config;
public MovieXmlSaver(IServerConfigurationManager config)
{
_config = config;
}
/// <summary> /// <summary>
/// Supportses the specified item. /// Supportses the specified item.
/// </summary> /// </summary>
@ -22,7 +30,7 @@ namespace MediaBrowser.Providers.Savers
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns> /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
public bool Supports(BaseItem item) public bool Supports(BaseItem item)
{ {
if (item.LocationType != LocationType.FileSystem) if (!_config.Configuration.SaveLocalMeta || item.LocationType != LocationType.FileSystem)
{ {
return false; return false;
} }
@ -50,13 +58,13 @@ namespace MediaBrowser.Providers.Savers
builder.Append("<Title>"); builder.Append("<Title>");
XmlHelpers.AddCommonNodes(item, builder); XmlSaverHelpers.AddCommonNodes(item, builder);
builder.Append("</Title>"); builder.Append("</Title>");
var xmlFilePath = GetSavePath(item); var xmlFilePath = GetSavePath(item);
XmlHelpers.Save(builder, xmlFilePath); XmlSaverHelpers.Save(builder, xmlFilePath);
// Set last refreshed so that the provider doesn't trigger after the file save // Set last refreshed so that the provider doesn't trigger after the file save
MovieProviderFromXml.Current.SetLastRefreshed(item, DateTime.UtcNow); MovieProviderFromXml.Current.SetLastRefreshed(item, DateTime.UtcNow);

View File

@ -41,13 +41,13 @@ namespace MediaBrowser.Providers.Savers
builder.Append("<Item>"); builder.Append("<Item>");
XmlHelpers.AddCommonNodes(item, builder); XmlSaverHelpers.AddCommonNodes(item, builder);
builder.Append("</Item>"); builder.Append("</Item>");
var xmlFilePath = GetSavePath(item); var xmlFilePath = GetSavePath(item);
XmlHelpers.Save(builder, xmlFilePath); XmlSaverHelpers.Save(builder, xmlFilePath);
// Set last refreshed so that the provider doesn't trigger after the file save // Set last refreshed so that the provider doesn't trigger after the file save
PersonProviderFromXml.Current.SetLastRefreshed(item, DateTime.UtcNow); PersonProviderFromXml.Current.SetLastRefreshed(item, DateTime.UtcNow);

View File

@ -1,4 +1,5 @@
using System; using System;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
@ -13,6 +14,13 @@ namespace MediaBrowser.Providers.Savers
{ {
public class SeriesXmlSaver : IMetadataSaver public class SeriesXmlSaver : IMetadataSaver
{ {
private readonly IServerConfigurationManager _config;
public SeriesXmlSaver(IServerConfigurationManager config)
{
_config = config;
}
/// <summary> /// <summary>
/// Supportses the specified item. /// Supportses the specified item.
/// </summary> /// </summary>
@ -20,7 +28,7 @@ namespace MediaBrowser.Providers.Savers
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns> /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
public bool Supports(BaseItem item) public bool Supports(BaseItem item)
{ {
if (item.LocationType != LocationType.FileSystem) if (!_config.Configuration.SaveLocalMeta || item.LocationType != LocationType.FileSystem)
{ {
return false; return false;
} }
@ -78,13 +86,13 @@ namespace MediaBrowser.Providers.Savers
builder.Append("<Airs_DayOfWeek>" + SecurityElement.Escape(series.AirDays[0].ToString()) + "</Airs_DayOfWeek>"); builder.Append("<Airs_DayOfWeek>" + SecurityElement.Escape(series.AirDays[0].ToString()) + "</Airs_DayOfWeek>");
} }
XmlHelpers.AddCommonNodes(item, builder); XmlSaverHelpers.AddCommonNodes(item, builder);
builder.Append("</Series>"); builder.Append("</Series>");
var xmlFilePath = GetSavePath(item); var xmlFilePath = GetSavePath(item);
XmlHelpers.Save(builder, xmlFilePath); XmlSaverHelpers.Save(builder, xmlFilePath);
// Set last refreshed so that the provider doesn't trigger after the file save // Set last refreshed so that the provider doesn't trigger after the file save
SeriesProviderFromXml.Current.SetLastRefreshed(item, DateTime.UtcNow); SeriesProviderFromXml.Current.SetLastRefreshed(item, DateTime.UtcNow);

View File

@ -4,7 +4,6 @@ using MediaBrowser.Model.Entities;
using System; using System;
using System.Globalization; using System.Globalization;
using System.IO; using System.IO;
using System.Linq;
using System.Security; using System.Security;
using System.Text; using System.Text;
using System.Xml; using System.Xml;
@ -14,7 +13,7 @@ namespace MediaBrowser.Providers.Savers
/// <summary> /// <summary>
/// Class XmlHelpers /// Class XmlHelpers
/// </summary> /// </summary>
public static class XmlHelpers public static class XmlSaverHelpers
{ {
/// <summary> /// <summary>
/// The us culture /// The us culture
@ -34,6 +33,13 @@ namespace MediaBrowser.Providers.Savers
//Add the new node to the document. //Add the new node to the document.
xmlDocument.InsertBefore(xmlDocument.CreateXmlDeclaration("1.0", "UTF-8", "yes"), xmlDocument.DocumentElement); xmlDocument.InsertBefore(xmlDocument.CreateXmlDeclaration("1.0", "UTF-8", "yes"), xmlDocument.DocumentElement);
var parentPath = Path.GetDirectoryName(path);
if (!Directory.Exists(parentPath))
{
Directory.CreateDirectory(parentPath);
}
using (var streamWriter = new StreamWriter(path, false, Encoding.UTF8)) using (var streamWriter = new StreamWriter(path, false, Encoding.UTF8))
{ {
xmlDocument.Save(streamWriter); xmlDocument.Save(streamWriter);
@ -95,6 +101,11 @@ namespace MediaBrowser.Providers.Savers
builder.Append("<SortTitle>" + SecurityElement.Escape(item.ForcedSortName) + "</SortTitle>"); builder.Append("<SortTitle>" + SecurityElement.Escape(item.ForcedSortName) + "</SortTitle>");
} }
if (item.PremiereDate.HasValue)
{
builder.Append("<PremiereDate>" + SecurityElement.Escape(item.PremiereDate.Value.ToString("yyyy-MM-dd")) + "</PremiereDate>");
}
if (item.Budget.HasValue) if (item.Budget.HasValue)
{ {
builder.Append("<Budget>" + SecurityElement.Escape(item.Budget.Value.ToString(UsCulture)) + "</Budget>"); builder.Append("<Budget>" + SecurityElement.Escape(item.Budget.Value.ToString(UsCulture)) + "</Budget>");
@ -182,6 +193,13 @@ namespace MediaBrowser.Providers.Savers
builder.Append("<RottenTomatoesId>" + SecurityElement.Escape(rt) + "</RottenTomatoesId>"); builder.Append("<RottenTomatoesId>" + SecurityElement.Escape(rt) + "</RottenTomatoesId>");
} }
var mbz = item.GetProviderId(MetadataProviders.Musicbrainz);
if (!string.IsNullOrEmpty(mbz))
{
builder.Append("<MusicbrainzId>" + SecurityElement.Escape(mbz) + "</MusicbrainzId>");
}
var tmdbCollection = item.GetProviderId(MetadataProviders.TmdbCollection); var tmdbCollection = item.GetProviderId(MetadataProviders.TmdbCollection);
if (!string.IsNullOrEmpty(tmdbCollection)) if (!string.IsNullOrEmpty(tmdbCollection))
@ -213,6 +231,18 @@ namespace MediaBrowser.Providers.Savers
builder.Append("</Studios>"); 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>");
}
builder.Append("<Added>" + SecurityElement.Escape(item.DateCreated.ToString(UsCulture)) + "</Added>"); builder.Append("<Added>" + SecurityElement.Escape(item.DateCreated.ToString(UsCulture)) + "</Added>");
} }

View File

@ -83,40 +83,38 @@ namespace MediaBrowser.Server.Implementations.Providers
libraryManager.ItemUpdated += libraryManager_ItemUpdated; libraryManager.ItemUpdated += libraryManager_ItemUpdated;
} }
private readonly ConcurrentDictionary<string, SemaphoreSlim> _fileLocks = new ConcurrentDictionary<string, SemaphoreSlim>();
/// <summary> /// <summary>
/// Handles the ItemUpdated event of the libraryManager control. /// Handles the ItemUpdated event of the libraryManager control.
/// </summary> /// </summary>
/// <param name="sender">The source of the event.</param> /// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="ItemChangeEventArgs"/> instance containing the event data.</param> /// <param name="e">The <see cref="ItemChangeEventArgs"/> instance containing the event data.</param>
void libraryManager_ItemUpdated(object sender, ItemChangeEventArgs e) async void libraryManager_ItemUpdated(object sender, ItemChangeEventArgs e)
{ {
var item = e.Item; var item = e.Item;
if (ConfigurationManager.Configuration.SaveLocalMeta) foreach (var saver in _savers.Where(i => i.Supports(item)))
{ {
if (item.LocationType != LocationType.FileSystem) var path = saver.GetSavePath(item);
{
return;
}
foreach (var saver in _savers.Where(i => i.Supports(item))) var semaphore = _fileLocks.GetOrAdd(path, key => new SemaphoreSlim(1, 1));
{
var path = saver.GetSavePath(item);
await semaphore.WaitAsync().ConfigureAwait(false);
try
{
_directoryWatchers.TemporarilyIgnore(path); _directoryWatchers.TemporarilyIgnore(path);
saver.Save(item, CancellationToken.None);
try }
{ catch (Exception ex)
saver.Save(item, CancellationToken.None); {
} _logger.ErrorException("Error in metadata saver", ex);
catch (Exception ex) }
{ finally
_logger.ErrorException("Error in metadata saver", ex); {
} _directoryWatchers.RemoveTempIgnore(path);
finally semaphore.Release();
{
_directoryWatchers.RemoveTempIgnore(path);
}
} }
} }
} }