aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.Controller
diff options
context:
space:
mode:
Diffstat (limited to 'MediaBrowser.Controller')
-rw-r--r--MediaBrowser.Controller/Extensions/XmlExtensions.cs238
-rw-r--r--MediaBrowser.Controller/MediaBrowser.Controller.csproj49
-rw-r--r--MediaBrowser.Controller/MediaInfo/FFMpegManager.cs1
-rw-r--r--MediaBrowser.Controller/MediaInfo/MediaEncoderHelpers.cs (renamed from MediaBrowser.Controller/Providers/MediaInfo/MediaEncoderHelpers.cs)2
-rw-r--r--MediaBrowser.Controller/Providers/FanartBaseProvider.cs106
-rw-r--r--MediaBrowser.Controller/Providers/FolderProviderFromXml.cs98
-rw-r--r--MediaBrowser.Controller/Providers/ImageFromMediaLocationProvider.cs323
-rw-r--r--MediaBrowser.Controller/Providers/ImagesByNameProvider.cs184
-rw-r--r--MediaBrowser.Controller/Providers/MediaInfo/AudioImageProvider.cs208
-rw-r--r--MediaBrowser.Controller/Providers/MediaInfo/BaseFFMpegProvider.cs76
-rw-r--r--MediaBrowser.Controller/Providers/MediaInfo/BaseFFProbeProvider.cs358
-rw-r--r--MediaBrowser.Controller/Providers/MediaInfo/FFProbeAudioInfoProvider.cs223
-rw-r--r--MediaBrowser.Controller/Providers/MediaInfo/FFProbeVideoInfoProvider.cs439
-rw-r--r--MediaBrowser.Controller/Providers/Movies/FanArtMovieProvider.cs400
-rw-r--r--MediaBrowser.Controller/Providers/Movies/FanArtMovieUpdatesPrescanTask.cs185
-rw-r--r--MediaBrowser.Controller/Providers/Movies/MovieDbImagesProvider.cs412
-rw-r--r--MediaBrowser.Controller/Providers/Movies/MovieDbProvider.cs1270
-rw-r--r--MediaBrowser.Controller/Providers/Movies/MovieProviderFromJson.cs121
-rw-r--r--MediaBrowser.Controller/Providers/Movies/MovieProviderFromXml.cs113
-rw-r--r--MediaBrowser.Controller/Providers/Movies/OpenMovieDatabaseProvider.cs225
-rw-r--r--MediaBrowser.Controller/Providers/Movies/PersonProviderFromJson.cs114
-rw-r--r--MediaBrowser.Controller/Providers/Movies/TmdbPersonProvider.cs435
-rw-r--r--MediaBrowser.Controller/Providers/Music/ArtistsPostScanTask.cs132
-rw-r--r--MediaBrowser.Controller/Providers/Music/FanArtAlbumProvider.cs307
-rw-r--r--MediaBrowser.Controller/Providers/Music/FanArtArtistByNameProvider.cs48
-rw-r--r--MediaBrowser.Controller/Providers/Music/FanArtArtistProvider.cs378
-rw-r--r--MediaBrowser.Controller/Providers/Music/FanArtUpdatesPrescanTask.cs206
-rw-r--r--MediaBrowser.Controller/Providers/Music/LastfmAlbumProvider.cs166
-rw-r--r--MediaBrowser.Controller/Providers/Music/LastfmArtistByNameProvider.cs117
-rw-r--r--MediaBrowser.Controller/Providers/Music/LastfmArtistProvider.cs283
-rw-r--r--MediaBrowser.Controller/Providers/Music/LastfmBaseProvider.cs277
-rw-r--r--MediaBrowser.Controller/Providers/Music/LastfmHelper.cs73
-rw-r--r--MediaBrowser.Controller/Providers/Music/MusicArtistProviderFromJson.cs100
-rw-r--r--MediaBrowser.Controller/Providers/TV/EpisodeImageFromMediaLocationProvider.cs132
-rw-r--r--MediaBrowser.Controller/Providers/TV/EpisodeProviderFromXml.cs116
-rw-r--r--MediaBrowser.Controller/Providers/TV/EpisodeXmlParser.cs119
-rw-r--r--MediaBrowser.Controller/Providers/TV/FanArtSeasonProvider.cs229
-rw-r--r--MediaBrowser.Controller/Providers/TV/FanArtTVProvider.cs338
-rw-r--r--MediaBrowser.Controller/Providers/TV/FanArtTvUpdatesPrescanTask.cs200
-rw-r--r--MediaBrowser.Controller/Providers/TV/RemoteEpisodeProvider.cs367
-rw-r--r--MediaBrowser.Controller/Providers/TV/RemoteSeasonProvider.cs289
-rw-r--r--MediaBrowser.Controller/Providers/TV/RemoteSeriesProvider.cs639
-rw-r--r--MediaBrowser.Controller/Providers/TV/SeriesProviderFromXml.cs100
-rw-r--r--MediaBrowser.Controller/Providers/TV/SeriesXmlParser.cs106
-rw-r--r--MediaBrowser.Controller/Providers/TV/TvdbPrescanTask.cs223
-rw-r--r--MediaBrowser.Controller/Providers/TV/TvdbSeriesImageProvider.cs283
46 files changed, 2 insertions, 10806 deletions
diff --git a/MediaBrowser.Controller/Extensions/XmlExtensions.cs b/MediaBrowser.Controller/Extensions/XmlExtensions.cs
deleted file mode 100644
index ce689e47d..000000000
--- a/MediaBrowser.Controller/Extensions/XmlExtensions.cs
+++ /dev/null
@@ -1,238 +0,0 @@
-using System;
-using System.Globalization;
-using System.Xml;
-
-namespace MediaBrowser.Controller.Extensions
-{
- /// <summary>
- /// Class XmlExtensions
- /// </summary>
- public static class XmlExtensions
- {
-
- /// <summary>
- /// Safes the get int32.
- /// </summary>
- /// <param name="doc">The doc.</param>
- /// <param name="path">The path.</param>
- /// <returns>System.Int32.</returns>
- public static int SafeGetInt32(this XmlDocument doc, string path)
- {
- return SafeGetInt32(doc, path, 0);
- }
-
- /// <summary>
- /// Safes the get int32.
- /// </summary>
- /// <param name="doc">The doc.</param>
- /// <param name="path">The path.</param>
- /// <param name="defaultInt">The default int.</param>
- /// <returns>System.Int32.</returns>
- public static int SafeGetInt32(this XmlDocument doc, string path, int defaultInt)
- {
- XmlNode rvalNode = doc.SelectSingleNode(path);
- if (rvalNode != null && rvalNode.InnerText.Length > 0)
- {
- int rval;
- if (Int32.TryParse(rvalNode.InnerText, out rval))
- {
- return rval;
- }
-
- }
- return defaultInt;
- }
-
- /// <summary>
- /// The _us culture
- /// </summary>
- private static readonly CultureInfo _usCulture = new CultureInfo("en-US");
-
- /// <summary>
- /// Safes the get single.
- /// </summary>
- /// <param name="doc">The doc.</param>
- /// <param name="path">The path.</param>
- /// <param name="minValue">The min value.</param>
- /// <param name="maxValue">The max value.</param>
- /// <returns>System.Single.</returns>
- public static float SafeGetSingle(this XmlDocument doc, string path, float minValue, float maxValue)
- {
- XmlNode rvalNode = doc.SelectSingleNode(path);
- if (rvalNode != null && rvalNode.InnerText.Length > 0)
- {
- float rval;
- // float.TryParse is local aware, so it can be probamatic, force us culture
- if (float.TryParse(rvalNode.InnerText, NumberStyles.AllowDecimalPoint, _usCulture, out rval))
- {
- if (rval >= minValue && rval <= maxValue)
- {
- return rval;
- }
- }
-
- }
- return minValue;
- }
-
-
- /// <summary>
- /// Safes the get string.
- /// </summary>
- /// <param name="doc">The doc.</param>
- /// <param name="path">The path.</param>
- /// <returns>System.String.</returns>
- public static string SafeGetString(this XmlDocument doc, string path)
- {
- return SafeGetString(doc, path, null);
- }
-
- /// <summary>
- /// Safes the get string.
- /// </summary>
- /// <param name="doc">The doc.</param>
- /// <param name="path">The path.</param>
- /// <param name="defaultString">The default string.</param>
- /// <returns>System.String.</returns>
- public static string SafeGetString(this XmlDocument doc, string path, string defaultString)
- {
- var rvalNode = doc.SelectSingleNode(path);
-
- if (rvalNode != null)
- {
- var text = rvalNode.InnerText;
-
- return !string.IsNullOrWhiteSpace(text) ? text : defaultString;
- }
-
- return defaultString;
- }
-
- /// <summary>
- /// Safes the get DateTime.
- /// </summary>
- /// <param name="doc">The doc.</param>
- /// <param name="path">The path.</param>
- /// <returns>System.DateTime.</returns>
- public static DateTime? SafeGetDateTime(this XmlDocument doc, string path)
- {
- return SafeGetDateTime(doc, path, null);
- }
-
- /// <summary>
- /// Safes the get DateTime.
- /// </summary>
- /// <param name="doc">The doc.</param>
- /// <param name="path">The path.</param>
- /// <param name="defaultDate">The default date.</param>
- /// <returns>System.DateTime.</returns>
- public static DateTime? SafeGetDateTime(this XmlDocument doc, string path, DateTime? defaultDate)
- {
- var rvalNode = doc.SelectSingleNode(path);
-
- if (rvalNode != null)
- {
- var text = rvalNode.InnerText;
- DateTime date;
- if (DateTime.TryParse(text, out date))
- return date.ToUniversalTime();
- }
- return defaultDate;
- }
-
- /// <summary>
- /// Safes the get string.
- /// </summary>
- /// <param name="doc">The doc.</param>
- /// <param name="path">The path.</param>
- /// <returns>System.String.</returns>
- public static string SafeGetString(this XmlNode doc, string path)
- {
- return SafeGetString(doc, path, null);
- }
-
- /// <summary>
- /// Safes the get string.
- /// </summary>
- /// <param name="doc">The doc.</param>
- /// <param name="path">The path.</param>
- /// <param name="defaultValue">The default value.</param>
- /// <returns>System.String.</returns>
- public static string SafeGetString(this XmlNode doc, string path, string defaultValue)
- {
- var rvalNode = doc.SelectSingleNode(path);
- if (rvalNode != null)
- {
- var text = rvalNode.InnerText;
-
- return !string.IsNullOrWhiteSpace(text) ? text : defaultValue;
- }
- return defaultValue;
- }
-
- /// <summary>
- /// Reads the string safe.
- /// </summary>
- /// <param name="reader">The reader.</param>
- /// <returns>System.String.</returns>
- public static string ReadStringSafe(this XmlReader reader)
- {
- var val = reader.ReadElementContentAsString();
-
- return string.IsNullOrWhiteSpace(val) ? null : val;
- }
-
- /// <summary>
- /// Reads the value safe.
- /// </summary>
- /// <param name="reader">The reader.</param>
- /// <returns>System.String.</returns>
- public static string ReadValueSafe(this XmlReader reader)
- {
- reader.Read();
-
- var val = reader.Value;
-
- return string.IsNullOrWhiteSpace(val) ? null : val;
- }
-
- /// <summary>
- /// Reads a float from the current element of an XmlReader
- /// </summary>
- /// <param name="reader">The reader.</param>
- /// <returns>System.Single.</returns>
- public static float ReadFloatSafe(this XmlReader reader)
- {
- string valueString = reader.ReadElementContentAsString();
-
- float value = 0;
-
- if (!string.IsNullOrWhiteSpace(valueString))
- {
- // float.TryParse is local aware, so it can be probamatic, force us culture
- float.TryParse(valueString, NumberStyles.AllowDecimalPoint, _usCulture, out value);
- }
-
- return value;
- }
-
- /// <summary>
- /// Reads an int from the current element of an XmlReader
- /// </summary>
- /// <param name="reader">The reader.</param>
- /// <returns>System.Int32.</returns>
- public static int ReadIntSafe(this XmlReader reader)
- {
- string valueString = reader.ReadElementContentAsString();
-
- int value = 0;
-
- if (!string.IsNullOrWhiteSpace(valueString))
- {
- int.TryParse(valueString, out value);
- }
-
- return value;
- }
- }
-} \ No newline at end of file
diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj
index feb3d90dd..4422f0036 100644
--- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj
+++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj
@@ -78,14 +78,6 @@
<Compile Include="Library\ILibraryPrescanTask.cs" />
<Compile Include="Library\IMetadataSaver.cs" />
<Compile Include="Localization\ILocalizationManager.cs" />
- <Compile Include="Providers\Movies\FanArtMovieUpdatesPrescanTask.cs" />
- <Compile Include="Providers\Movies\MovieDbImagesProvider.cs" />
- <Compile Include="Providers\Music\ArtistsPostScanTask.cs" />
- <Compile Include="Providers\Music\FanArtUpdatesPrescanTask.cs" />
- <Compile Include="Providers\TV\FanArtSeasonProvider.cs" />
- <Compile Include="Providers\TV\FanArtTvUpdatesPrescanTask.cs" />
- <Compile Include="Providers\TV\TvdbPrescanTask.cs" />
- <Compile Include="Providers\TV\TvdbSeriesImageProvider.cs" />
<Compile Include="Session\ISessionManager.cs" />
<Compile Include="Drawing\ImageExtensions.cs" />
<Compile Include="Drawing\ImageHeader.cs" />
@@ -122,7 +114,6 @@
<Compile Include="Entities\Video.cs" />
<Compile Include="Entities\CollectionFolder.cs" />
<Compile Include="Entities\Year.cs" />
- <Compile Include="Extensions\XmlExtensions.cs" />
<Compile Include="IO\FileSystem.cs" />
<Compile Include="IO\IDirectoryWatchers.cs" />
<Compile Include="IO\NativeMethods.cs" />
@@ -131,17 +122,8 @@
<Compile Include="Dto\DtoBuilder.cs" />
<Compile Include="Library\SearchHintInfo.cs" />
<Compile Include="Providers\IProviderManager.cs" />
- <Compile Include="Providers\MediaInfo\MediaEncoderHelpers.cs" />
+ <Compile Include="MediaInfo\MediaEncoderHelpers.cs" />
<Compile Include="Providers\MetadataProviderPriority.cs" />
- <Compile Include="Providers\Movies\OpenMovieDatabaseProvider.cs" />
- <Compile Include="Providers\Music\FanArtArtistByNameProvider.cs" />
- <Compile Include="Providers\Music\LastfmAlbumProvider.cs" />
- <Compile Include="Providers\Music\FanArtAlbumProvider.cs" />
- <Compile Include="Providers\Music\FanArtArtistProvider.cs" />
- <Compile Include="Providers\Music\LastfmArtistByNameProvider.cs" />
- <Compile Include="Providers\Music\LastfmArtistProvider.cs" />
- <Compile Include="Providers\Music\LastfmHelper.cs" />
- <Compile Include="Providers\Music\MusicArtistProviderFromJson.cs" />
<Compile Include="Resolvers\BaseItemResolver.cs" />
<Compile Include="Resolvers\BaseVideoResolver.cs" />
<Compile Include="Resolvers\IItemResolver.cs" />
@@ -166,33 +148,8 @@
<Compile Include="Library\IIntroProvider.cs" />
<Compile Include="Plugins\IPluginConfigurationPage.cs" />
<Compile Include="Plugins\IServerEntryPoint.cs" />
- <Compile Include="Providers\Music\LastfmBaseProvider.cs" />
- <Compile Include="Providers\FanartBaseProvider.cs" />
<Compile Include="Providers\IImageEnhancer.cs" />
- <Compile Include="Providers\ImagesByNameProvider.cs" />
- <Compile Include="Providers\MediaInfo\BaseFFMpegProvider.cs" />
- <Compile Include="Providers\MediaInfo\AudioImageProvider.cs" />
- <Compile Include="Providers\MediaInfo\BaseFFProbeProvider.cs" />
<Compile Include="Providers\BaseProviderInfo.cs" />
- <Compile Include="Providers\Movies\FanArtMovieProvider.cs" />
- <Compile Include="Providers\Movies\MovieDbProvider.cs" />
- <Compile Include="Providers\Movies\MovieProviderFromJson.cs" />
- <Compile Include="Providers\Movies\MovieProviderFromXml.cs" />
- <Compile Include="Providers\Movies\PersonProviderFromJson.cs" />
- <Compile Include="Providers\Movies\TmdbPersonProvider.cs" />
- <Compile Include="Providers\TV\EpisodeImageFromMediaLocationProvider.cs" />
- <Compile Include="Providers\TV\EpisodeProviderFromXml.cs" />
- <Compile Include="Providers\TV\EpisodeXmlParser.cs" />
- <Compile Include="Providers\TV\FanArtTVProvider.cs" />
- <Compile Include="Providers\TV\RemoteEpisodeProvider.cs">
- <SubType>Code</SubType>
- </Compile>
- <Compile Include="Providers\TV\RemoteSeasonProvider.cs">
- <SubType>Code</SubType>
- </Compile>
- <Compile Include="Providers\TV\RemoteSeriesProvider.cs" />
- <Compile Include="Providers\TV\SeriesProviderFromXml.cs" />
- <Compile Include="Providers\TV\SeriesXmlParser.cs" />
<Compile Include="Resolvers\IResolverIgnoreRule.cs" />
<Compile Include="Resolvers\EntityResolutionHelper.cs" />
<Compile Include="Resolvers\ResolverPriority.cs" />
@@ -202,10 +159,6 @@
<Compile Include="Kernel.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Providers\BaseMetadataProvider.cs" />
- <Compile Include="Providers\MediaInfo\FFProbeAudioInfoProvider.cs" />
- <Compile Include="Providers\FolderProviderFromXml.cs" />
- <Compile Include="Providers\ImageFromMediaLocationProvider.cs" />
- <Compile Include="Providers\MediaInfo\FFProbeVideoInfoProvider.cs" />
<Compile Include="Session\SessionInfo.cs" />
<Compile Include="Sorting\IBaseItemComparer.cs" />
<Compile Include="Sorting\IUserBaseItemComparer.cs" />
diff --git a/MediaBrowser.Controller/MediaInfo/FFMpegManager.cs b/MediaBrowser.Controller/MediaInfo/FFMpegManager.cs
index 91359cd29..4b992fd81 100644
--- a/MediaBrowser.Controller/MediaInfo/FFMpegManager.cs
+++ b/MediaBrowser.Controller/MediaInfo/FFMpegManager.cs
@@ -2,7 +2,6 @@
using MediaBrowser.Common.MediaInfo;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.Providers.MediaInfo;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging;
using System;
diff --git a/MediaBrowser.Controller/Providers/MediaInfo/MediaEncoderHelpers.cs b/MediaBrowser.Controller/MediaInfo/MediaEncoderHelpers.cs
index 7ea2a339a..e20a425aa 100644
--- a/MediaBrowser.Controller/Providers/MediaInfo/MediaEncoderHelpers.cs
+++ b/MediaBrowser.Controller/MediaInfo/MediaEncoderHelpers.cs
@@ -3,7 +3,7 @@ using MediaBrowser.Common.MediaInfo;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Model.Entities;
-namespace MediaBrowser.Controller.Providers.MediaInfo
+namespace MediaBrowser.Controller.MediaInfo
{
/// <summary>
/// Class MediaEncoderHelpers
diff --git a/MediaBrowser.Controller/Providers/FanartBaseProvider.cs b/MediaBrowser.Controller/Providers/FanartBaseProvider.cs
deleted file mode 100644
index f5dff25f6..000000000
--- a/MediaBrowser.Controller/Providers/FanartBaseProvider.cs
+++ /dev/null
@@ -1,106 +0,0 @@
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Model.Logging;
-using System.Collections.Generic;
-using System.Threading;
-
-namespace MediaBrowser.Controller.Providers
-{
- /// <summary>
- /// Class FanartBaseProvider
- /// </summary>
- public abstract class FanartBaseProvider : BaseMetadataProvider
- {
- internal static readonly SemaphoreSlim FanArtResourcePool = new SemaphoreSlim(3, 3);
-
- /// <summary>
- /// The LOG o_ FILE
- /// </summary>
- protected const string LogoFile = "logo.png";
-
- /// <summary>
- /// The AR t_ FILE
- /// </summary>
- protected const string ArtFile = "clearart.png";
-
- /// <summary>
- /// The THUM b_ FILE
- /// </summary>
- protected const string ThumbFile = "thumb.jpg";
-
- /// <summary>
- /// The DIS c_ FILE
- /// </summary>
- protected const string DiscFile = "disc.png";
-
- /// <summary>
- /// The BANNE r_ FILE
- /// </summary>
- protected const string BannerFile = "banner.png";
-
- /// <summary>
- /// The Backdrop
- /// </summary>
- protected const string BackdropFile = "backdrop.jpg";
-
- /// <summary>
- /// The Primary image
- /// </summary>
- protected const string PrimaryFile = "folder.jpg";
-
- /// <summary>
- /// The API key
- /// </summary>
- internal const string ApiKey = "5c6b04c68e904cfed1e6cbc9a9e683d4";
-
- protected FanartBaseProvider(ILogManager logManager, IServerConfigurationManager configurationManager)
- : base(logManager, configurationManager)
- {
- }
-
- /// <summary>
- /// Gets a value indicating whether [requires internet].
- /// </summary>
- /// <value><c>true</c> if [requires internet]; otherwise, <c>false</c>.</value>
- public override bool RequiresInternet
- {
- get { return true; }
- }
-
- /// <summary>
- /// Gets the priority.
- /// </summary>
- /// <value>The priority.</value>
- public override MetadataProviderPriority Priority
- {
- get { return MetadataProviderPriority.Third; }
- }
-
- #region Result Objects
-
- protected class FanArtImageInfo
- {
- public string id { get; set; }
- public string url { get; set; }
- public string likes { get; set; }
- }
-
- protected class FanArtMusicInfo
- {
- public string mbid_id { get; set; }
- public List<FanArtImageInfo> musiclogo { get; set; }
- public List<FanArtImageInfo> artistbackground { get; set; }
- public List<FanArtImageInfo> artistthumb { get; set; }
- public List<FanArtImageInfo> hdmusiclogo { get; set; }
- public List<FanArtImageInfo> musicbanner { get; set; }
- }
-
- protected class FanArtMusicResult
- {
- public FanArtMusicInfo result { get; set; }
- }
-
- #endregion
-
- }
-
-}
diff --git a/MediaBrowser.Controller/Providers/FolderProviderFromXml.cs b/MediaBrowser.Controller/Providers/FolderProviderFromXml.cs
deleted file mode 100644
index 641a291ff..000000000
--- a/MediaBrowser.Controller/Providers/FolderProviderFromXml.cs
+++ /dev/null
@@ -1,98 +0,0 @@
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Model.Entities;
-using System;
-using System.IO;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Model.Logging;
-
-namespace MediaBrowser.Controller.Providers
-{
- /// <summary>
- /// Provides metadata for Folders and all subclasses by parsing folder.xml
- /// </summary>
- public class FolderProviderFromXml : BaseMetadataProvider
- {
- public FolderProviderFromXml(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 Folder && 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, "folder.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, "folder.xml"));
-
- if (metadataFile != null)
- {
- var path = metadataFile.FullName;
-
- await XmlParsingResourcePool.WaitAsync(cancellationToken).ConfigureAwait(false);
-
- try
- {
- new BaseItemXmlParser<Folder>(Logger).Fetch((Folder)item, path, cancellationToken);
- }
- finally
- {
- XmlParsingResourcePool.Release();
- }
-
- SetLastRefreshed(item, DateTime.UtcNow);
- return true;
- }
-
- return false;
- }
- }
-}
diff --git a/MediaBrowser.Controller/Providers/ImageFromMediaLocationProvider.cs b/MediaBrowser.Controller/Providers/ImageFromMediaLocationProvider.cs
deleted file mode 100644
index 1bd4ce0ca..000000000
--- a/MediaBrowser.Controller/Providers/ImageFromMediaLocationProvider.cs
+++ /dev/null
@@ -1,323 +0,0 @@
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Logging;
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace MediaBrowser.Controller.Providers
-{
- /// <summary>
- /// Provides images for all types by looking for standard images - folder, backdrop, logo, etc.
- /// </summary>
- public class ImageFromMediaLocationProvider : BaseMetadataProvider
- {
- public ImageFromMediaLocationProvider(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.LocationType == LocationType.FileSystem && item.ResolveArgs.IsDirectory;
- }
-
- /// <summary>
- /// Gets the priority.
- /// </summary>
- /// <value>The priority.</value>
- public override MetadataProviderPriority Priority
- {
- get { return MetadataProviderPriority.First; }
- }
-
- /// <summary>
- /// Returns true or false indicating if the provider should refresh when the contents of it's directory changes
- /// </summary>
- /// <value><c>true</c> if [refresh on file system stamp change]; otherwise, <c>false</c>.</value>
- protected override bool RefreshOnFileSystemStampChange
- {
- get
- {
- return true;
- }
- }
-
- /// <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)
- {
- cancellationToken.ThrowIfCancellationRequested();
-
- // Make sure current image paths still exist
- ValidateImages(item);
-
- cancellationToken.ThrowIfCancellationRequested();
-
- // Make sure current backdrop paths still exist
- ValidateBackdrops(item);
-
- cancellationToken.ThrowIfCancellationRequested();
-
- PopulateBaseItemImages(item);
-
- SetLastRefreshed(item, DateTime.UtcNow);
- return TrueTaskResult;
- }
-
- /// <summary>
- /// Validates that images within the item are still on the file system
- /// </summary>
- /// <param name="item">The item.</param>
- private void ValidateImages(BaseItem item)
- {
- if (item.Images == null)
- {
- return;
- }
-
- // Only validate paths from the same directory - need to copy to a list because we are going to potentially modify the collection below
- var deletedKeys = item.Images.ToList().Where(image =>
- {
- var path = image.Value;
-
- return IsInMetaLocation(item, path) && item.ResolveArgs.GetMetaFileByPath(path) == null;
-
- }).Select(i => i.Key).ToList();
-
- // Now remove them from the dictionary
- foreach (var key in deletedKeys)
- {
- item.Images.Remove(key);
- }
- }
-
- /// <summary>
- /// Validates that backdrops within the item are still on the file system
- /// </summary>
- /// <param name="item">The item.</param>
- private void ValidateBackdrops(BaseItem item)
- {
- if (item.BackdropImagePaths == null)
- {
- return;
- }
-
- // Only validate paths from the same directory - need to copy to a list because we are going to potentially modify the collection below
- var deletedImages = item.BackdropImagePaths.Where(path => IsInMetaLocation(item, path) && item.ResolveArgs.GetMetaFileByPath(path) == null).ToList();
-
- // Now remove them from the dictionary
- foreach (var path in deletedImages)
- {
- item.BackdropImagePaths.Remove(path);
- }
- }
-
- /// <summary>
- /// Determines whether [is in same directory] [the specified item].
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="path">The path.</param>
- /// <returns><c>true</c> if [is in same directory] [the specified item]; otherwise, <c>false</c>.</returns>
- private bool IsInMetaLocation(BaseItem item, string path)
- {
- return string.Equals(Path.GetDirectoryName(path), item.MetaLocation, StringComparison.OrdinalIgnoreCase);
- }
-
- /// <summary>
- /// Gets the image.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="filenameWithoutExtension">The filename without extension.</param>
- /// <returns>FileSystemInfo.</returns>
- protected virtual FileSystemInfo GetImage(BaseItem item, string filenameWithoutExtension)
- {
- return BaseItem.SupportedImageExtensions.Select(i => item.ResolveArgs.GetMetaFileByPath(Path.Combine(item.ResolveArgs.Path, filenameWithoutExtension + i))).FirstOrDefault(i => i != null);
- }
-
- /// <summary>
- /// Fills in image paths based on files win the folder
- /// </summary>
- /// <param name="item">The item.</param>
- private void PopulateBaseItemImages(BaseItem item)
- {
- // Primary Image
- var image = GetImage(item, "folder") ??
- GetImage(item, "poster") ??
- GetImage(item, "cover") ??
- GetImage(item, "default");
-
- if (image != null)
- {
- item.SetImage(ImageType.Primary, image.FullName);
- }
-
- // Logo Image
- image = GetImage(item, "logo");
-
- if (image != null)
- {
- item.SetImage(ImageType.Logo, image.FullName);
- }
-
- // Banner Image
- image = GetImage(item, "banner");
-
- if (image != null)
- {
- item.SetImage(ImageType.Banner, image.FullName);
- }
-
- // Clearart
- image = GetImage(item, "clearart");
-
- if (image != null)
- {
- item.SetImage(ImageType.Art, image.FullName);
- }
-
- // Thumbnail Image
- image = GetImage(item, "thumb");
-
- if (image != null)
- {
- item.SetImage(ImageType.Thumb, image.FullName);
- }
-
- // Box Image
- image = GetImage(item, "box");
-
- if (image != null)
- {
- item.SetImage(ImageType.Box, image.FullName);
- }
-
- // BoxRear Image
- image = GetImage(item, "boxrear");
-
- if (image != null)
- {
- item.SetImage(ImageType.BoxRear, image.FullName);
- }
-
- // Thumbnail Image
- image = GetImage(item, "menu");
-
- if (image != null)
- {
- item.SetImage(ImageType.Menu, image.FullName);
- }
-
- // Backdrop Image
- PopulateBackdrops(item);
-
- // Screenshot Image
- image = GetImage(item, "screenshot");
-
- var screenshotFiles = new List<string>();
-
- if (image != null)
- {
- screenshotFiles.Add(image.FullName);
- }
-
- var unfound = 0;
- for (var i = 1; i <= 20; i++)
- {
- // Screenshot Image
- image = GetImage(item, "screenshot" + i);
-
- if (image != null)
- {
- screenshotFiles.Add(image.FullName);
- }
- else
- {
- unfound++;
-
- if (unfound >= 3)
- {
- break;
- }
- }
- }
-
- if (screenshotFiles.Count > 0)
- {
- item.ScreenshotImagePaths = screenshotFiles;
- }
- }
-
- /// <summary>
- /// Populates the backdrops.
- /// </summary>
- /// <param name="item">The item.</param>
- private void PopulateBackdrops(BaseItem item)
- {
- var backdropFiles = new List<string>();
-
- PopulateBackdrops(item, backdropFiles, "backdrop", "backdrop");
-
- // Support plex/xbmc conventions
- PopulateBackdrops(item, backdropFiles, "fanart", "fanart-");
- PopulateBackdrops(item, backdropFiles, "background", "background-");
-
- if (backdropFiles.Count > 0)
- {
- item.BackdropImagePaths = backdropFiles;
- }
- }
-
- /// <summary>
- /// Populates the backdrops.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="backdropFiles">The backdrop files.</param>
- /// <param name="filename">The filename.</param>
- /// <param name="numberedSuffix">The numbered suffix.</param>
- private void PopulateBackdrops(BaseItem item, List<string> backdropFiles, string filename, string numberedSuffix)
- {
- var image = GetImage(item, filename);
-
- if (image != null)
- {
- backdropFiles.Add(image.FullName);
- }
-
- var unfound = 0;
- for (var i = 1; i <= 20; i++)
- {
- // Backdrop Image
- image = GetImage(item, numberedSuffix + i);
-
- if (image != null)
- {
- backdropFiles.Add(image.FullName);
- }
- else
- {
- unfound++;
-
- if (unfound >= 3)
- {
- break;
- }
- }
- }
- }
- }
-}
diff --git a/MediaBrowser.Controller/Providers/ImagesByNameProvider.cs b/MediaBrowser.Controller/Providers/ImagesByNameProvider.cs
deleted file mode 100644
index 20305006e..000000000
--- a/MediaBrowser.Controller/Providers/ImagesByNameProvider.cs
+++ /dev/null
@@ -1,184 +0,0 @@
-using MediaBrowser.Common.Extensions;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.IO;
-using MediaBrowser.Model.Logging;
-using System;
-using System.IO;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace MediaBrowser.Controller.Providers
-{
- /// <summary>
- /// Provides images for generic types by looking for standard images in the IBN
- /// </summary>
- public class ImagesByNameProvider : ImageFromMediaLocationProvider
- {
- public ImagesByNameProvider(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)
- {
- //only run for these generic types since we are expensive in file i/o
- return item is IndexFolder || item is BasePluginFolder || item is CollectionFolder;
- }
-
- /// <summary>
- /// Gets the priority.
- /// </summary>
- /// <value>The priority.</value>
- public override MetadataProviderPriority Priority
- {
- get
- {
- return MetadataProviderPriority.Last;
- }
- }
-
- /// <summary>
- /// Needses the refresh internal.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="providerInfo">The provider info.</param>
- /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
- protected override bool NeedsRefreshInternal(BaseItem item, BaseProviderInfo providerInfo)
- {
- // Force a refresh if the IBN path changed
- if (providerInfo.Data != ConfigurationManager.ApplicationPaths.ItemsByNamePath.GetMD5())
- {
- return true;
- }
-
- return base.NeedsRefreshInternal(item, providerInfo);
- }
-
- /// <summary>
- /// Gets a value indicating whether [refresh on file system stamp change].
- /// </summary>
- /// <value><c>true</c> if [refresh on file system stamp change]; otherwise, <c>false</c>.</value>
- protected override bool RefreshOnFileSystemStampChange
- {
- get
- {
- return false;
- }
- }
-
- /// <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)
- {
- // If the IBN location exists return the last modified date of any file in it
- var location = GetLocation(item);
-
- var directoryInfo = new DirectoryInfo(location);
-
- if (!directoryInfo.Exists)
- {
- return DateTime.MinValue;
- }
-
- var files = directoryInfo.EnumerateFiles().ToList();
-
- if (files.Count == 0)
- {
- return DateTime.MinValue;
- }
-
- return files.Select(f =>
- {
- var lastWriteTime = FileSystem.GetLastWriteTimeUtc(f, Logger);
- var creationTime = FileSystem.GetCreationTimeUtc(f, Logger);
-
- return creationTime > lastWriteTime ? creationTime : lastWriteTime;
-
- }).Max();
- }
-
- /// <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 async Task<bool> FetchAsync(BaseItem item, bool force, CancellationToken cancellationToken)
- {
- var result = await base.FetchAsync(item, force, cancellationToken).ConfigureAwait(false);
-
- BaseProviderInfo data;
-
- if (!item.ProviderData.TryGetValue(Id, out data))
- {
- data = new BaseProviderInfo();
- item.ProviderData[Id] = data;
- }
-
- data.Data = ConfigurationManager.ApplicationPaths.ItemsByNamePath.GetMD5();
- SetLastRefreshed(item, DateTime.UtcNow);
-
- return result;
- }
-
- /// <summary>
- /// Gets the location.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <returns>System.String.</returns>
- protected string GetLocation(BaseItem item)
- {
- var name = FileSystem.GetValidFilename(item.Name);
-
- return Path.Combine(ConfigurationManager.ApplicationPaths.GeneralPath, name);
- }
-
- /// <summary>
- /// Gets the image.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="filenameWithoutExtension">The filename without extension.</param>
- /// <returns>FileSystemInfo.</returns>
- protected override FileSystemInfo GetImage(BaseItem item, string filenameWithoutExtension)
- {
- var location = GetLocation(item);
-
- var directoryInfo = new DirectoryInfo(location);
-
- if (!directoryInfo.Exists)
- {
- return null;
- }
-
- var files = directoryInfo.EnumerateFiles("*", SearchOption.TopDirectoryOnly).ToList();
-
- var file = files.FirstOrDefault(i => string.Equals(i.Name, filenameWithoutExtension + ".png", StringComparison.OrdinalIgnoreCase));
-
- if (file != null)
- {
- return file;
- }
-
- file = files.FirstOrDefault(i => string.Equals(i.Name, filenameWithoutExtension + ".jpg", StringComparison.OrdinalIgnoreCase));
-
- if (file != null)
- {
- return file;
- }
-
- return null;
- }
- }
-}
diff --git a/MediaBrowser.Controller/Providers/MediaInfo/AudioImageProvider.cs b/MediaBrowser.Controller/Providers/MediaInfo/AudioImageProvider.cs
deleted file mode 100644
index 9fd67f477..000000000
--- a/MediaBrowser.Controller/Providers/MediaInfo/AudioImageProvider.cs
+++ /dev/null
@@ -1,208 +0,0 @@
-using System.IO;
-using MediaBrowser.Common.IO;
-using MediaBrowser.Common.MediaInfo;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Entities.Audio;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Logging;
-using System;
-using System.Collections.Concurrent;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace MediaBrowser.Controller.Providers.MediaInfo
-{
- /// <summary>
- /// Uses ffmpeg to create video images
- /// </summary>
- public class AudioImageProvider : BaseMetadataProvider
- {
- /// <summary>
- /// Gets or sets the image cache.
- /// </summary>
- /// <value>The image cache.</value>
- public FileSystemRepository ImageCache { get; set; }
-
- /// <summary>
- /// The _locks
- /// </summary>
- private readonly ConcurrentDictionary<string, SemaphoreSlim> _locks = new ConcurrentDictionary<string, SemaphoreSlim>();
-
- /// <summary>
- /// The _media encoder
- /// </summary>
- private readonly IMediaEncoder _mediaEncoder;
-
- /// <summary>
- /// The _library manager
- /// </summary>
- private readonly ILibraryManager _libraryManager;
-
- /// <summary>
- /// Initializes a new instance of the <see cref="BaseMetadataProvider" /> class.
- /// </summary>
- /// <param name="logManager">The log manager.</param>
- /// <param name="configurationManager">The configuration manager.</param>
- /// <param name="libraryManager">The library manager.</param>
- /// <param name="mediaEncoder">The media encoder.</param>
- public AudioImageProvider(ILogManager logManager, IServerConfigurationManager configurationManager, ILibraryManager libraryManager, IMediaEncoder mediaEncoder)
- : base(logManager, configurationManager)
- {
- _libraryManager = libraryManager;
- _mediaEncoder = mediaEncoder;
-
- ImageCache = new FileSystemRepository(Kernel.Instance.FFMpegManager.AudioImagesDataPath);
- }
-
- /// <summary>
- /// Gets a value indicating whether [refresh on version change].
- /// </summary>
- /// <value><c>true</c> if [refresh on version change]; otherwise, <c>false</c>.</value>
- protected override bool RefreshOnVersionChange
- {
- get
- {
- return true;
- }
- }
-
- /// <summary>
- /// Gets the provider version.
- /// </summary>
- /// <value>The provider version.</value>
- protected override string ProviderVersion
- {
- get
- {
- return "1";
- }
- }
-
- /// <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.LocationType == LocationType.FileSystem && item is Audio;
- }
-
- /// <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)
- {
- return item.DateModified;
- }
-
- /// <summary>
- /// Gets the priority.
- /// </summary>
- /// <value>The priority.</value>
- public override MetadataProviderPriority Priority
- {
- get { return MetadataProviderPriority.Last; }
- }
-
- /// <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 async Task<bool> FetchAsync(BaseItem item, bool force, CancellationToken cancellationToken)
- {
- var audio = (Audio)item;
-
- if (string.IsNullOrEmpty(audio.PrimaryImagePath) && audio.MediaStreams.Any(s => s.Type == MediaStreamType.Video))
- {
- try
- {
- await CreateImagesForSong(audio, cancellationToken).ConfigureAwait(false);
- }
- catch (Exception ex)
- {
- Logger.ErrorException("Error extracting image for {0}", ex, item.Name);
- }
- }
-
- SetLastRefreshed(item, DateTime.UtcNow);
- return true;
- }
-
- /// <summary>
- /// Creates the images for song.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- /// <exception cref="System.InvalidOperationException">Can't extract an image unless the audio file has an embedded image.</exception>
- private async Task CreateImagesForSong(Audio item, CancellationToken cancellationToken)
- {
- cancellationToken.ThrowIfCancellationRequested();
-
- var album = item.Parent as MusicAlbum;
-
- var filename = item.Album ?? string.Empty;
- filename += item.Artist ?? string.Empty;
- filename += album == null ? item.Id.ToString("N") + item.DateModified.Ticks : album.Id.ToString("N") + album.DateModified.Ticks;
-
- var path = ImageCache.GetResourcePath(filename + "_primary", ".jpg");
-
- if (!File.Exists(path))
- {
- var semaphore = GetLock(path);
-
- // Acquire a lock
- await semaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
-
- // Check again
- if (!File.Exists(path))
- {
- try
- {
- var parentPath = Path.GetDirectoryName(path);
-
- if (!Directory.Exists(parentPath))
- {
- Directory.CreateDirectory(parentPath);
- }
-
- await _mediaEncoder.ExtractImage(new[] { item.Path }, InputType.AudioFile, null, path, cancellationToken).ConfigureAwait(false);
- }
- finally
- {
- semaphore.Release();
- }
- }
- else
- {
- semaphore.Release();
- }
- }
-
- // Image is already in the cache
- item.PrimaryImagePath = path;
-
- await _libraryManager.UpdateItem(item, cancellationToken).ConfigureAwait(false);
- }
-
- /// <summary>
- /// Gets the lock.
- /// </summary>
- /// <param name="filename">The filename.</param>
- /// <returns>SemaphoreSlim.</returns>
- private SemaphoreSlim GetLock(string filename)
- {
- return _locks.GetOrAdd(filename, key => new SemaphoreSlim(1, 1));
- }
- }
-}
diff --git a/MediaBrowser.Controller/Providers/MediaInfo/BaseFFMpegProvider.cs b/MediaBrowser.Controller/Providers/MediaInfo/BaseFFMpegProvider.cs
deleted file mode 100644
index 919c2ae21..000000000
--- a/MediaBrowser.Controller/Providers/MediaInfo/BaseFFMpegProvider.cs
+++ /dev/null
@@ -1,76 +0,0 @@
-using MediaBrowser.Common.IO;
-using MediaBrowser.Common.MediaInfo;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Logging;
-using System;
-using System.Threading.Tasks;
-
-namespace MediaBrowser.Controller.Providers.MediaInfo
-{
- /// <summary>
- /// Class BaseFFMpegProvider
- /// </summary>
- /// <typeparam name="T"></typeparam>
- public abstract class BaseFFMpegProvider<T> : BaseMetadataProvider
- where T : BaseItem
- {
- protected readonly IMediaEncoder MediaEncoder;
-
- protected BaseFFMpegProvider(ILogManager logManager, IServerConfigurationManager configurationManager, IMediaEncoder mediaEncoder) : base(logManager, configurationManager)
- {
- MediaEncoder = mediaEncoder;
- }
-
- /// <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.LocationType == LocationType.FileSystem && item is T;
- }
-
- /// <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)
- {
- return item.DateModified;
- }
-
- /// <summary>
- /// The null mount task result
- /// </summary>
- protected readonly Task<IIsoMount> NullMountTaskResult = Task.FromResult<IIsoMount>(null);
-
- /// <summary>
- /// Gets the provider version.
- /// </summary>
- /// <value>The provider version.</value>
- protected override string ProviderVersion
- {
- get
- {
- return MediaEncoder.Version;
- }
- }
-
- /// <summary>
- /// Gets a value indicating whether [refresh on version change].
- /// </summary>
- /// <value><c>true</c> if [refresh on version change]; otherwise, <c>false</c>.</value>
- protected override bool RefreshOnVersionChange
- {
- get
- {
- return true;
- }
- }
- }
-}
diff --git a/MediaBrowser.Controller/Providers/MediaInfo/BaseFFProbeProvider.cs b/MediaBrowser.Controller/Providers/MediaInfo/BaseFFProbeProvider.cs
deleted file mode 100644
index 4f40cffa1..000000000
--- a/MediaBrowser.Controller/Providers/MediaInfo/BaseFFProbeProvider.cs
+++ /dev/null
@@ -1,358 +0,0 @@
-using MediaBrowser.Common.IO;
-using MediaBrowser.Common.MediaInfo;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.Serialization;
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace MediaBrowser.Controller.Providers.MediaInfo
-{
- /// <summary>
- /// Provides a base class for extracting media information through ffprobe
- /// </summary>
- /// <typeparam name="T"></typeparam>
- public abstract class BaseFFProbeProvider<T> : BaseFFMpegProvider<T>
- where T : BaseItem
- {
- protected BaseFFProbeProvider(ILogManager logManager, IServerConfigurationManager configurationManager, IMediaEncoder mediaEncoder, IJsonSerializer jsonSerializer)
- : base(logManager, configurationManager, mediaEncoder)
- {
- JsonSerializer = jsonSerializer;
- }
-
- protected readonly IJsonSerializer JsonSerializer;
-
- /// <summary>
- /// Gets the priority.
- /// </summary>
- /// <value>The priority.</value>
- public override MetadataProviderPriority Priority
- {
- // Give this second priority
- // Give metadata xml providers a chance to fill in data first, so that we can skip this whenever possible
- get { return MetadataProviderPriority.Second; }
- }
-
- protected readonly CultureInfo UsCulture = new CultureInfo("en-US");
-
- /// <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 async Task<bool> FetchAsync(BaseItem item, bool force, CancellationToken cancellationToken)
- {
- var myItem = (T)item;
-
- var isoMount = await MountIsoIfNeeded(myItem, cancellationToken).ConfigureAwait(false);
-
- try
- {
- OnPreFetch(myItem, isoMount);
-
- var result = await GetMediaInfo(item, isoMount, cancellationToken).ConfigureAwait(false);
-
- cancellationToken.ThrowIfCancellationRequested();
-
- NormalizeFFProbeResult(result);
-
- cancellationToken.ThrowIfCancellationRequested();
-
- Fetch(myItem, cancellationToken, result, isoMount);
-
- var video = myItem as Video;
-
- if (video != null)
- {
- await Kernel.Instance.FFMpegManager.PopulateChapterImages(video, cancellationToken, false, false).ConfigureAwait(false);
- }
-
- SetLastRefreshed(item, DateTime.UtcNow);
- }
- finally
- {
- if (isoMount != null)
- {
- isoMount.Dispose();
- }
- }
-
- return true;
- }
-
- /// <summary>
- /// Gets the media info.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="isoMount">The iso mount.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task{MediaInfoResult}.</returns>
- /// <exception cref="System.ArgumentNullException">inputPath
- /// or
- /// cache</exception>
- private async Task<MediaInfoResult> GetMediaInfo(BaseItem item, IIsoMount isoMount, CancellationToken cancellationToken)
- {
- cancellationToken.ThrowIfCancellationRequested();
-
- var type = InputType.AudioFile;
- var inputPath = isoMount == null ? new[] { item.Path } : new[] { isoMount.MountedPath };
-
- var video = item as Video;
-
- if (video != null)
- {
- inputPath = MediaEncoderHelpers.GetInputArgument(video, isoMount, out type);
- }
-
- return await MediaEncoder.GetMediaInfo(inputPath, type, cancellationToken).ConfigureAwait(false);
- }
-
- /// <summary>
- /// Mounts the iso if needed.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>IsoMount.</returns>
- protected virtual Task<IIsoMount> MountIsoIfNeeded(T item, CancellationToken cancellationToken)
- {
- return NullMountTaskResult;
- }
-
- /// <summary>
- /// Called when [pre fetch].
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="mount">The mount.</param>
- protected virtual void OnPreFetch(T item, IIsoMount mount)
- {
-
- }
-
- /// <summary>
- /// Normalizes the FF probe result.
- /// </summary>
- /// <param name="result">The result.</param>
- private void NormalizeFFProbeResult(MediaInfoResult result)
- {
- if (result.format != null && result.format.tags != null)
- {
- result.format.tags = ConvertDictionaryToCaseInSensitive(result.format.tags);
- }
-
- if (result.streams != null)
- {
- // Convert all dictionaries to case insensitive
- foreach (var stream in result.streams)
- {
- if (stream.tags != null)
- {
- stream.tags = ConvertDictionaryToCaseInSensitive(stream.tags);
- }
-
- if (stream.disposition != null)
- {
- stream.disposition = ConvertDictionaryToCaseInSensitive(stream.disposition);
- }
- }
- }
- }
-
- /// <summary>
- /// Subclasses must set item values using this
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <param name="result">The result.</param>
- /// <param name="isoMount">The iso mount.</param>
- /// <returns>Task.</returns>
- protected abstract void Fetch(T item, CancellationToken cancellationToken, MediaInfoResult result, IIsoMount isoMount);
-
- /// <summary>
- /// Converts ffprobe stream info to our MediaStream class
- /// </summary>
- /// <param name="streamInfo">The stream info.</param>
- /// <param name="formatInfo">The format info.</param>
- /// <returns>MediaStream.</returns>
- protected MediaStream GetMediaStream(MediaStreamInfo streamInfo, MediaFormatInfo formatInfo)
- {
- var stream = new MediaStream
- {
- Codec = streamInfo.codec_name,
- Language = GetDictionaryValue(streamInfo.tags, "language"),
- Profile = streamInfo.profile,
- Level = streamInfo.level,
- Index = streamInfo.index
- };
-
- if (streamInfo.codec_type.Equals("audio", StringComparison.OrdinalIgnoreCase))
- {
- stream.Type = MediaStreamType.Audio;
-
- stream.Channels = streamInfo.channels;
-
- if (!string.IsNullOrEmpty(streamInfo.sample_rate))
- {
- stream.SampleRate = int.Parse(streamInfo.sample_rate, UsCulture);
- }
- }
- else if (streamInfo.codec_type.Equals("subtitle", StringComparison.OrdinalIgnoreCase))
- {
- stream.Type = MediaStreamType.Subtitle;
- }
- else if (streamInfo.codec_type.Equals("video", StringComparison.OrdinalIgnoreCase))
- {
- stream.Type = MediaStreamType.Video;
-
- stream.Width = streamInfo.width;
- stream.Height = streamInfo.height;
- stream.PixelFormat = streamInfo.pix_fmt;
- stream.AspectRatio = streamInfo.display_aspect_ratio;
-
- stream.AverageFrameRate = GetFrameRate(streamInfo.avg_frame_rate);
- stream.RealFrameRate = GetFrameRate(streamInfo.r_frame_rate);
- }
- else
- {
- return null;
- }
-
- // Get stream bitrate
- if (stream.Type != MediaStreamType.Subtitle)
- {
- if (!string.IsNullOrEmpty(streamInfo.bit_rate))
- {
- stream.BitRate = int.Parse(streamInfo.bit_rate, UsCulture);
- }
- else if (formatInfo != null && !string.IsNullOrEmpty(formatInfo.bit_rate))
- {
- // If the stream info doesn't have a bitrate get the value from the media format info
- stream.BitRate = int.Parse(formatInfo.bit_rate, UsCulture);
- }
- }
-
- if (streamInfo.disposition != null)
- {
- var isDefault = GetDictionaryValue(streamInfo.disposition, "default");
- var isForced = GetDictionaryValue(streamInfo.disposition, "forced");
-
- stream.IsDefault = string.Equals(isDefault, "1", StringComparison.OrdinalIgnoreCase);
-
- stream.IsForced = string.Equals(isForced, "1", StringComparison.OrdinalIgnoreCase);
- }
-
- return stream;
- }
-
- /// <summary>
- /// Gets a frame rate from a string value in ffprobe output
- /// This could be a number or in the format of 2997/125.
- /// </summary>
- /// <param name="value">The value.</param>
- /// <returns>System.Nullable{System.Single}.</returns>
- private float? GetFrameRate(string value)
- {
- if (!string.IsNullOrEmpty(value))
- {
- var parts = value.Split('/');
-
- float result;
-
- if (parts.Length == 2)
- {
- result = float.Parse(parts[0], UsCulture) / float.Parse(parts[1], UsCulture);
- }
- else
- {
- result = float.Parse(parts[0], UsCulture);
- }
-
- return float.IsNaN(result) ? (float?)null : result;
- }
-
- return null;
- }
-
- /// <summary>
- /// Gets a string from an FFProbeResult tags dictionary
- /// </summary>
- /// <param name="tags">The tags.</param>
- /// <param name="key">The key.</param>
- /// <returns>System.String.</returns>
- protected string GetDictionaryValue(Dictionary<string, string> tags, string key)
- {
- if (tags == null)
- {
- return null;
- }
-
- string val;
-
- tags.TryGetValue(key, out val);
- return val;
- }
-
- /// <summary>
- /// Gets an int from an FFProbeResult tags dictionary
- /// </summary>
- /// <param name="tags">The tags.</param>
- /// <param name="key">The key.</param>
- /// <returns>System.Nullable{System.Int32}.</returns>
- protected int? GetDictionaryNumericValue(Dictionary<string, string> tags, string key)
- {
- var val = GetDictionaryValue(tags, key);
-
- if (!string.IsNullOrEmpty(val))
- {
- int i;
-
- if (int.TryParse(val, out i))
- {
- return i;
- }
- }
-
- return null;
- }
-
- /// <summary>
- /// Gets a DateTime from an FFProbeResult tags dictionary
- /// </summary>
- /// <param name="tags">The tags.</param>
- /// <param name="key">The key.</param>
- /// <returns>System.Nullable{DateTime}.</returns>
- protected DateTime? GetDictionaryDateTime(Dictionary<string, string> tags, string key)
- {
- var val = GetDictionaryValue(tags, key);
-
- if (!string.IsNullOrEmpty(val))
- {
- DateTime i;
-
- if (DateTime.TryParse(val, out i))
- {
- return i.ToUniversalTime();
- }
- }
-
- return null;
- }
-
- /// <summary>
- /// Converts a dictionary to case insensitive
- /// </summary>
- /// <param name="dict">The dict.</param>
- /// <returns>Dictionary{System.StringSystem.String}.</returns>
- private Dictionary<string, string> ConvertDictionaryToCaseInSensitive(Dictionary<string, string> dict)
- {
- return new Dictionary<string, string>(dict, StringComparer.OrdinalIgnoreCase);
- }
- }
-}
diff --git a/MediaBrowser.Controller/Providers/MediaInfo/FFProbeAudioInfoProvider.cs b/MediaBrowser.Controller/Providers/MediaInfo/FFProbeAudioInfoProvider.cs
deleted file mode 100644
index f234611bd..000000000
--- a/MediaBrowser.Controller/Providers/MediaInfo/FFProbeAudioInfoProvider.cs
+++ /dev/null
@@ -1,223 +0,0 @@
-using MediaBrowser.Common.IO;
-using MediaBrowser.Common.MediaInfo;
-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.Collections.Generic;
-using System.Linq;
-using System.Threading;
-
-namespace MediaBrowser.Controller.Providers.MediaInfo
-{
- /// <summary>
- /// Extracts audio information using ffprobe
- /// </summary>
- public class FFProbeAudioInfoProvider : BaseFFProbeProvider<Audio>
- {
- public FFProbeAudioInfoProvider(ILogManager logManager, IServerConfigurationManager configurationManager, IMediaEncoder mediaEncoder, IJsonSerializer jsonSerializer)
- : base(logManager, configurationManager, mediaEncoder, jsonSerializer)
- {
- }
-
- /// <summary>
- /// Fetches the specified audio.
- /// </summary>
- /// <param name="audio">The audio.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <param name="data">The data.</param>
- /// <param name="isoMount">The iso mount.</param>
- /// <returns>Task.</returns>
- protected override void Fetch(Audio audio, CancellationToken cancellationToken, MediaInfoResult data, IIsoMount isoMount)
- {
- if (data.streams == null)
- {
- Logger.Error("Audio item has no streams: " + audio.Path);
- return;
- }
-
- audio.MediaStreams = data.streams.Select(s => GetMediaStream(s, data.format))
- .Where(i => i != null)
- .ToList();
-
- // Get the first audio stream
- var stream = data.streams.FirstOrDefault(s => s.codec_type.Equals("audio", StringComparison.OrdinalIgnoreCase));
-
- if (stream != null)
- {
- // Get duration from stream properties
- var duration = stream.duration;
-
- // If it's not there go into format properties
- if (string.IsNullOrEmpty(duration))
- {
- duration = data.format.duration;
- }
-
- // If we got something, parse it
- if (!string.IsNullOrEmpty(duration))
- {
- audio.RunTimeTicks = TimeSpan.FromSeconds(double.Parse(duration, UsCulture)).Ticks;
- }
- }
-
- if (data.format.tags != null)
- {
- FetchDataFromTags(audio, data.format.tags);
- }
- }
-
- /// <summary>
- /// Fetches data from the tags dictionary
- /// </summary>
- /// <param name="audio">The audio.</param>
- /// <param name="tags">The tags.</param>
- private void FetchDataFromTags(Audio audio, Dictionary<string, string> tags)
- {
- var title = GetDictionaryValue(tags, "title");
-
- // Only set Name if title was found in the dictionary
- if (!string.IsNullOrEmpty(title))
- {
- audio.Name = title;
- }
-
- var composer = GetDictionaryValue(tags, "composer");
-
- if (!string.IsNullOrWhiteSpace(composer))
- {
- foreach (var person in Split(composer))
- {
- var name = person.Trim();
-
- if (!string.IsNullOrEmpty(name))
- {
- audio.AddPerson(new PersonInfo { Name = name, Type = PersonType.Composer });
- }
- }
- }
-
- audio.Album = GetDictionaryValue(tags, "album");
-
- audio.Artist = GetDictionaryValue(tags, "artist");
-
- // Several different forms of albumartist
- audio.AlbumArtist = GetDictionaryValue(tags, "albumartist") ?? GetDictionaryValue(tags, "album artist") ?? GetDictionaryValue(tags, "album_artist");
-
- // Track number
- audio.IndexNumber = GetDictionaryNumericValue(tags, "track");
-
- // Disc number
- audio.ParentIndexNumber = GetDictionaryDiscValue(tags);
-
- audio.Language = GetDictionaryValue(tags, "language");
-
- audio.ProductionYear = GetDictionaryNumericValue(tags, "date");
-
- // Several different forms of retaildate
- audio.PremiereDate = GetDictionaryDateTime(tags, "retaildate") ?? GetDictionaryDateTime(tags, "retail date") ?? GetDictionaryDateTime(tags, "retail_date");
-
- // If we don't have a ProductionYear try and get it from PremiereDate
- if (audio.PremiereDate.HasValue && !audio.ProductionYear.HasValue)
- {
- audio.ProductionYear = audio.PremiereDate.Value.ToLocalTime().Year;
- }
-
- FetchGenres(audio, tags);
-
- // There's several values in tags may or may not be present
- FetchStudios(audio, tags, "organization");
- FetchStudios(audio, tags, "ensemble");
- FetchStudios(audio, tags, "publisher");
- }
-
- /// <summary>
- /// Splits the specified val.
- /// </summary>
- /// <param name="val">The val.</param>
- /// <returns>System.String[][].</returns>
- private IEnumerable<string> Split(string val)
- {
- // Only use the comma as a delimeter if there are no slashes or pipes.
- // We want to be careful not to split names that have commas in them
- var delimeter = val.IndexOf('/') == -1 && val.IndexOf('|') == -1 ? new[] { ',' } : new[] { '/', '|' };
-
- return val.Split(delimeter, StringSplitOptions.RemoveEmptyEntries);
- }
-
- /// <summary>
- /// Gets the studios from the tags collection
- /// </summary>
- /// <param name="audio">The audio.</param>
- /// <param name="tags">The tags.</param>
- /// <param name="tagName">Name of the tag.</param>
- private void FetchStudios(Audio audio, Dictionary<string, string> tags, string tagName)
- {
- var val = GetDictionaryValue(tags, tagName);
-
- if (!string.IsNullOrEmpty(val))
- {
- var studios =
- val.Split(new[] { '/', '|' }, StringSplitOptions.RemoveEmptyEntries)
- .Where(i => !string.Equals(i, audio.Artist, StringComparison.OrdinalIgnoreCase) && !string.Equals(i, audio.AlbumArtist, StringComparison.OrdinalIgnoreCase));
-
- audio.Studios.Clear();
-
- foreach (var studio in studios)
- {
- audio.AddStudio(studio);
- }
- }
- }
-
- /// <summary>
- /// Gets the genres from the tags collection
- /// </summary>
- /// <param name="audio">The audio.</param>
- /// <param name="tags">The tags.</param>
- private void FetchGenres(Audio audio, Dictionary<string, string> tags)
- {
- var val = GetDictionaryValue(tags, "genre");
-
- if (!string.IsNullOrEmpty(val))
- {
- audio.Genres.Clear();
-
- foreach (var genre in val
- .Split(new[] { '/', '|' }, StringSplitOptions.RemoveEmptyEntries)
- .Where(i => !string.IsNullOrWhiteSpace(i)))
- {
- audio.AddGenre(genre);
- }
- }
- }
-
- /// <summary>
- /// Gets the disc number, which is sometimes can be in the form of '1', or '1/3'
- /// </summary>
- /// <param name="tags">The tags.</param>
- /// <returns>System.Nullable{System.Int32}.</returns>
- private int? GetDictionaryDiscValue(Dictionary<string, string> tags)
- {
- var disc = GetDictionaryValue(tags, "disc");
-
- if (!string.IsNullOrEmpty(disc))
- {
- disc = disc.Split('/')[0];
-
- int num;
-
- if (int.TryParse(disc, out num))
- {
- return num;
- }
- }
-
- return null;
- }
- }
-
-}
diff --git a/MediaBrowser.Controller/Providers/MediaInfo/FFProbeVideoInfoProvider.cs b/MediaBrowser.Controller/Providers/MediaInfo/FFProbeVideoInfoProvider.cs
deleted file mode 100644
index d4e5a30c6..000000000
--- a/MediaBrowser.Controller/Providers/MediaInfo/FFProbeVideoInfoProvider.cs
+++ /dev/null
@@ -1,439 +0,0 @@
-using MediaBrowser.Common.IO;
-using MediaBrowser.Common.MediaInfo;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Entities.Movies;
-using MediaBrowser.Controller.Localization;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.MediaInfo;
-using MediaBrowser.Model.Serialization;
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace MediaBrowser.Controller.Providers.MediaInfo
-{
- /// <summary>
- /// Extracts video information using ffprobe
- /// </summary>
- public class FFProbeVideoInfoProvider : BaseFFProbeProvider<Video>
- {
- public FFProbeVideoInfoProvider(IIsoManager isoManager, IBlurayExaminer blurayExaminer, IJsonSerializer jsonSerializer, ILogManager logManager, IServerConfigurationManager configurationManager, IMediaEncoder mediaEncoder, ILocalizationManager localization)
- : base(logManager, configurationManager, mediaEncoder, jsonSerializer)
- {
- if (isoManager == null)
- {
- throw new ArgumentNullException("isoManager");
- }
- if (blurayExaminer == null)
- {
- throw new ArgumentNullException("blurayExaminer");
- }
-
- _blurayExaminer = blurayExaminer;
- _localization = localization;
- _isoManager = isoManager;
- }
-
- /// <summary>
- /// Gets or sets the bluray examiner.
- /// </summary>
- /// <value>The bluray examiner.</value>
- private readonly IBlurayExaminer _blurayExaminer;
-
- /// <summary>
- /// The _iso manager
- /// </summary>
- private readonly IIsoManager _isoManager;
-
- private readonly ILocalizationManager _localization;
-
- /// <summary>
- /// Returns true or false indicating if the provider should refresh when the contents of it's directory changes
- /// </summary>
- /// <value><c>true</c> if [refresh on file system stamp change]; otherwise, <c>false</c>.</value>
- protected override bool RefreshOnFileSystemStampChange
- {
- get
- {
- return true;
- }
- }
-
- /// <summary>
- /// Supports video files and dvd structures
- /// </summary>
- /// <param name="item">The item.</param>
- /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
- public override bool Supports(BaseItem item)
- {
- if (item.LocationType != LocationType.FileSystem)
- {
- return false;
- }
-
- var video = item as Video;
-
- if (video != null)
- {
- if (video.VideoType == VideoType.Iso)
- {
- return _isoManager.CanMount(item.Path);
- }
-
- return video.VideoType == VideoType.VideoFile || video.VideoType == VideoType.Dvd || video.VideoType == VideoType.BluRay;
- }
-
- return false;
- }
-
- /// <summary>
- /// Called when [pre fetch].
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="mount">The mount.</param>
- protected override void OnPreFetch(Video item, IIsoMount mount)
- {
- if (item.VideoType == VideoType.Iso)
- {
- item.IsoType = DetermineIsoType(mount);
- }
-
- if (item.VideoType == VideoType.Dvd || (item.IsoType.HasValue && item.IsoType == IsoType.Dvd))
- {
- PopulateDvdStreamFiles(item, mount);
- }
-
- base.OnPreFetch(item, mount);
- }
-
- /// <summary>
- /// Mounts the iso if needed.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>IsoMount.</returns>
- protected override Task<IIsoMount> MountIsoIfNeeded(Video item, CancellationToken cancellationToken)
- {
- if (item.VideoType == VideoType.Iso)
- {
- return _isoManager.Mount(item.Path, cancellationToken);
- }
-
- return base.MountIsoIfNeeded(item, cancellationToken);
- }
-
- /// <summary>
- /// Determines the type of the iso.
- /// </summary>
- /// <param name="isoMount">The iso mount.</param>
- /// <returns>System.Nullable{IsoType}.</returns>
- private IsoType? DetermineIsoType(IIsoMount isoMount)
- {
- var folders = Directory.EnumerateDirectories(isoMount.MountedPath).Select(Path.GetFileName).ToList();
-
- if (folders.Contains("video_ts", StringComparer.OrdinalIgnoreCase))
- {
- return IsoType.Dvd;
- }
- if (folders.Contains("bdmv", StringComparer.OrdinalIgnoreCase))
- {
- return IsoType.BluRay;
- }
-
- return null;
- }
-
- /// <summary>
- /// Finds vob files and populates the dvd stream file properties
- /// </summary>
- /// <param name="video">The video.</param>
- /// <param name="isoMount">The iso mount.</param>
- private void PopulateDvdStreamFiles(Video video, IIsoMount isoMount)
- {
- // min size 300 mb
- const long minPlayableSize = 314572800;
-
- var root = isoMount != null ? isoMount.MountedPath : video.Path;
-
- // Try to eliminate menus and intros by skipping all files at the front of the list that are less than the minimum size
- // Once we reach a file that is at least the minimum, return all subsequent ones
- var files = Directory.EnumerateFiles(root, "*.vob", SearchOption.AllDirectories).SkipWhile(f => new FileInfo(f).Length < minPlayableSize).ToList();
-
- // Assuming they're named "vts_05_01", take all files whose second part matches that of the first file
- if (files.Count > 0)
- {
- var parts = Path.GetFileNameWithoutExtension(files[0]).Split('_');
-
- if (parts.Length == 3)
- {
- var title = parts[1];
-
- files = files.TakeWhile(f =>
- {
- var fileParts = Path.GetFileNameWithoutExtension(f).Split('_');
-
- return fileParts.Length == 3 && string.Equals(title, fileParts[1], StringComparison.OrdinalIgnoreCase);
-
- }).ToList();
- }
- }
-
- video.PlayableStreamFileNames = files.Select(Path.GetFileName).ToList();
- }
-
- /// <summary>
- /// Fetches the specified video.
- /// </summary>
- /// <param name="video">The video.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <param name="data">The data.</param>
- /// <param name="isoMount">The iso mount.</param>
- /// <returns>Task.</returns>
- protected override void Fetch(Video video, CancellationToken cancellationToken, MediaInfoResult data, IIsoMount isoMount)
- {
- if (data.format != null)
- {
- // For dvd's this may not always be accurate, so don't set the runtime if the item already has one
- var needToSetRuntime = video.VideoType != VideoType.Dvd || video.RunTimeTicks == null || video.RunTimeTicks.Value == 0;
-
- if (needToSetRuntime && !string.IsNullOrEmpty(data.format.duration))
- {
- video.RunTimeTicks = TimeSpan.FromSeconds(double.Parse(data.format.duration, UsCulture)).Ticks;
- }
- }
-
- if (data.streams != null)
- {
- video.MediaStreams = data.streams.Select(s => GetMediaStream(s, data.format))
- .Where(i => i != null)
- .ToList();
- }
-
- if (data.Chapters != null)
- {
- video.Chapters = data.Chapters;
- }
-
- if (video.Chapters == null || video.Chapters.Count == 0)
- {
- AddDummyChapters(video);
- }
-
- if (video.VideoType == VideoType.BluRay || (video.IsoType.HasValue && video.IsoType.Value == IsoType.BluRay))
- {
- var inputPath = isoMount != null ? isoMount.MountedPath : video.Path;
- FetchBdInfo(video, inputPath, cancellationToken);
- }
-
- AddExternalSubtitles(video);
- }
-
- /// <summary>
- /// Adds the external subtitles.
- /// </summary>
- /// <param name="video">The video.</param>
- private void AddExternalSubtitles(Video video)
- {
- var useParent = (video.VideoType == VideoType.VideoFile || video.VideoType == VideoType.Iso) && !(video is Movie) && !(video is MusicVideo);
-
- if (useParent && video.Parent == null)
- {
- return;
- }
-
- var fileSystemChildren = useParent
- ? video.Parent.ResolveArgs.FileSystemChildren
- : video.ResolveArgs.FileSystemChildren;
-
- var startIndex = video.MediaStreams == null ? 0 : video.MediaStreams.Count;
- var streams = new List<MediaStream>();
-
- var videoFileNameWithoutExtension = Path.GetFileNameWithoutExtension(video.Path);
-
- foreach (var file in fileSystemChildren
- .Where(f => !f.Attributes.HasFlag(FileAttributes.Directory) && string.Equals(Path.GetExtension(f.FullName), ".srt", StringComparison.OrdinalIgnoreCase)))
- {
- var fullName = file.FullName;
-
- var fileNameWithoutExtension = Path.GetFileNameWithoutExtension(fullName);
-
- // If the subtitle file matches the video file name
- if (string.Equals(videoFileNameWithoutExtension, fileNameWithoutExtension, StringComparison.OrdinalIgnoreCase))
- {
- streams.Add(new MediaStream
- {
- Index = startIndex++,
- Type = MediaStreamType.Subtitle,
- IsExternal = true,
- Path = fullName,
- Codec = "srt"
- });
- }
- else if (fileNameWithoutExtension.StartsWith(videoFileNameWithoutExtension + ".", StringComparison.OrdinalIgnoreCase))
- {
- // Support xbmc naming conventions - 300.spanish.srt
- var language = fileNameWithoutExtension.Split('.').LastOrDefault();
-
- // Try to translate to three character code
- // Be flexible and check against both the full and three character versions
- var culture = _localization.GetCultures()
- .FirstOrDefault(i => string.Equals(i.DisplayName, language, StringComparison.OrdinalIgnoreCase) || string.Equals(i.Name, language, StringComparison.OrdinalIgnoreCase) || string.Equals(i.ThreeLetterISOLanguageName, language, StringComparison.OrdinalIgnoreCase));
-
- if (culture != null)
- {
- language = culture.ThreeLetterISOLanguageName;
- }
-
- streams.Add(new MediaStream
- {
- Index = startIndex++,
- Type = MediaStreamType.Subtitle,
- IsExternal = true,
- Path = fullName,
- Codec = "srt",
- Language = language
- });
- }
- }
-
- if (video.MediaStreams == null)
- {
- video.MediaStreams = new List<MediaStream>();
- }
- video.MediaStreams.AddRange(streams);
- }
-
- /// <summary>
- /// The dummy chapter duration
- /// </summary>
- private readonly long _dummyChapterDuration = TimeSpan.FromMinutes(5).Ticks;
-
- /// <summary>
- /// Adds the dummy chapters.
- /// </summary>
- /// <param name="video">The video.</param>
- private void AddDummyChapters(Video video)
- {
- var runtime = video.RunTimeTicks ?? 0;
-
- if (runtime < _dummyChapterDuration)
- {
- return;
- }
-
- long currentChapterTicks = 0;
- var index = 1;
-
- var chapters = new List<ChapterInfo>();
-
- while (currentChapterTicks < runtime)
- {
- chapters.Add(new ChapterInfo
- {
- Name = "Chapter " + index,
- StartPositionTicks = currentChapterTicks
- });
-
- index++;
- currentChapterTicks += _dummyChapterDuration;
- }
-
- video.Chapters = chapters;
- }
-
- /// <summary>
- /// Fetches the bd info.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="inputPath">The input path.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- private void FetchBdInfo(BaseItem item, string inputPath, CancellationToken cancellationToken)
- {
- var video = (Video)item;
-
- var result = GetBDInfo(inputPath);
-
- cancellationToken.ThrowIfCancellationRequested();
-
- int? currentHeight = null;
- int? currentWidth = null;
- int? currentBitRate = null;
-
- var videoStream = video.MediaStreams.FirstOrDefault(s => s.Type == MediaStreamType.Video);
-
- // Grab the values that ffprobe recorded
- if (videoStream != null)
- {
- currentBitRate = videoStream.BitRate;
- currentWidth = videoStream.Width;
- currentHeight = videoStream.Height;
- }
-
- // Fill video properties from the BDInfo result
- Fetch(video, result);
-
- videoStream = video.MediaStreams.FirstOrDefault(s => s.Type == MediaStreamType.Video);
-
- // Use the ffprobe values if these are empty
- if (videoStream != null)
- {
- videoStream.BitRate = IsEmpty(videoStream.BitRate) ? currentBitRate : videoStream.BitRate;
- videoStream.Width = IsEmpty(videoStream.Width) ? currentWidth : videoStream.Width;
- videoStream.Height = IsEmpty(videoStream.Height) ? currentHeight : videoStream.Height;
- }
- }
-
- /// <summary>
- /// Determines whether the specified num is empty.
- /// </summary>
- /// <param name="num">The num.</param>
- /// <returns><c>true</c> if the specified num is empty; otherwise, <c>false</c>.</returns>
- private bool IsEmpty(int? num)
- {
- return !num.HasValue || num.Value == 0;
- }
-
- /// <summary>
- /// Fills video properties from the VideoStream of the largest playlist
- /// </summary>
- /// <param name="video">The video.</param>
- /// <param name="stream">The stream.</param>
- private void Fetch(Video video, BlurayDiscInfo stream)
- {
- // Check all input for null/empty/zero
-
- video.MediaStreams = stream.MediaStreams;
-
- if (stream.RunTimeTicks.HasValue && stream.RunTimeTicks.Value > 0)
- {
- video.RunTimeTicks = stream.RunTimeTicks;
- }
-
- video.PlayableStreamFileNames = stream.Files.ToList();
-
- if (stream.Chapters != null)
- {
- video.Chapters = stream.Chapters.Select(c => new ChapterInfo
- {
- StartPositionTicks = TimeSpan.FromSeconds(c).Ticks
-
- }).ToList();
- }
- }
-
- /// <summary>
- /// Gets information about the longest playlist on a bdrom
- /// </summary>
- /// <param name="path">The path.</param>
- /// <returns>VideoStream.</returns>
- private BlurayDiscInfo GetBDInfo(string path)
- {
- return _blurayExaminer.GetDiscInfo(path);
- }
- }
-}
diff --git a/MediaBrowser.Controller/Providers/Movies/FanArtMovieProvider.cs b/MediaBrowser.Controller/Providers/Movies/FanArtMovieProvider.cs
deleted file mode 100644
index f1e670862..000000000
--- a/MediaBrowser.Controller/Providers/Movies/FanArtMovieProvider.cs
+++ /dev/null
@@ -1,400 +0,0 @@
-using MediaBrowser.Common.Configuration;
-using MediaBrowser.Common.Extensions;
-using MediaBrowser.Common.IO;
-using MediaBrowser.Common.Net;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Entities.Movies;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Logging;
-using System;
-using System.Globalization;
-using System.IO;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-using System.Xml;
-
-namespace MediaBrowser.Controller.Providers.Movies
-{
- /// <summary>
- /// Class FanArtMovieProvider
- /// </summary>
- class FanArtMovieProvider : FanartBaseProvider
- {
- /// <summary>
- /// Gets the HTTP client.
- /// </summary>
- /// <value>The HTTP client.</value>
- protected IHttpClient HttpClient { get; private set; }
-
- /// <summary>
- /// The _provider manager
- /// </summary>
- private readonly IProviderManager _providerManager;
-
- /// <summary>
- /// The us culture
- /// </summary>
- private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
-
- internal static FanArtMovieProvider Current { get; private set; }
-
- /// <summary>
- /// Initializes a new instance of the <see cref="FanArtMovieProvider" /> class.
- /// </summary>
- /// <param name="httpClient">The HTTP client.</param>
- /// <param name="logManager">The log manager.</param>
- /// <param name="configurationManager">The configuration manager.</param>
- /// <param name="providerManager">The provider manager.</param>
- /// <exception cref="System.ArgumentNullException">httpClient</exception>
- public FanArtMovieProvider(IHttpClient httpClient, ILogManager logManager, IServerConfigurationManager configurationManager, IProviderManager providerManager)
- : base(logManager, configurationManager)
- {
- if (httpClient == null)
- {
- throw new ArgumentNullException("httpClient");
- }
- HttpClient = httpClient;
- _providerManager = providerManager;
- Current = this;
- }
-
- /// <summary>
- /// Gets a value indicating whether [refresh on version change].
- /// </summary>
- /// <value><c>true</c> if [refresh on version change]; otherwise, <c>false</c>.</value>
- protected override bool RefreshOnVersionChange
- {
- get
- {
- return true;
- }
- }
-
- /// <summary>
- /// Gets the provider version.
- /// </summary>
- /// <value>The provider version.</value>
- protected override string ProviderVersion
- {
- get
- {
- return "13";
- }
- }
-
- /// <summary>
- /// The fan art base URL
- /// </summary>
- protected string FanArtBaseUrl = "http://api.fanart.tv/webservice/movie/{0}/{1}/xml/all/1/1";
-
- /// <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)
- {
- var trailer = item as Trailer;
-
- if (trailer != null)
- {
- return !trailer.IsLocalTrailer;
- }
-
- return item is Movie || item is BoxSet || item is MusicVideo;
- }
-
- /// <summary>
- /// Needses the refresh internal.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="providerInfo">The provider info.</param>
- /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
- protected override bool NeedsRefreshInternal(BaseItem item, BaseProviderInfo providerInfo)
- {
- if (string.IsNullOrEmpty(item.GetProviderId(MetadataProviders.Tmdb)))
- {
- return false;
- }
-
- if (!ConfigurationManager.Configuration.DownloadMovieImages.Art &&
- !ConfigurationManager.Configuration.DownloadMovieImages.Logo &&
- !ConfigurationManager.Configuration.DownloadMovieImages.Disc &&
- !ConfigurationManager.Configuration.DownloadMovieImages.Backdrops &&
- !ConfigurationManager.Configuration.DownloadMovieImages.Banner &&
- !ConfigurationManager.Configuration.DownloadMovieImages.Thumb)
- {
- return false;
- }
-
- if (item.HasImage(ImageType.Art) &&
- item.HasImage(ImageType.Logo) &&
- item.HasImage(ImageType.Disc) &&
- item.HasImage(ImageType.Banner) &&
- item.HasImage(ImageType.Thumb) &&
- item.BackdropImagePaths.Count > 0)
- {
- return false;
- }
-
- // Refresh if tmdb id has changed
- if (providerInfo.Data != GetComparisonData(item.GetProviderId(MetadataProviders.Tmdb)))
- {
- return true;
- }
-
- return base.NeedsRefreshInternal(item, providerInfo);
- }
-
- /// <summary>
- /// Gets the comparison data.
- /// </summary>
- /// <param name="id">The id.</param>
- /// <returns>Guid.</returns>
- private Guid GetComparisonData(string id)
- {
- if (!string.IsNullOrEmpty(id))
- {
- // Process images
- var path = GetMovieDataPath(ConfigurationManager.ApplicationPaths, id);
-
- var files = new DirectoryInfo(path)
- .EnumerateFiles("*.xml", SearchOption.TopDirectoryOnly)
- .Select(i => i.FullName + i.LastWriteTimeUtc.Ticks)
- .ToArray();
-
- if (files.Length > 0)
- {
- return string.Join(string.Empty, files).GetMD5();
- }
- }
-
- return Guid.Empty;
- }
-
- /// <summary>
- /// Gets the movie data path.
- /// </summary>
- /// <param name="appPaths">The app paths.</param>
- /// <param name="tmdbId">The TMDB id.</param>
- /// <returns>System.String.</returns>
- internal static string GetMovieDataPath(IApplicationPaths appPaths, string tmdbId)
- {
- var dataPath = Path.Combine(GetMoviesDataPath(appPaths), tmdbId);
-
- if (!Directory.Exists(dataPath))
- {
- Directory.CreateDirectory(dataPath);
- }
-
- return dataPath;
- }
-
- /// <summary>
- /// Gets the movie data path.
- /// </summary>
- /// <param name="appPaths">The app paths.</param>
- /// <returns>System.String.</returns>
- internal static string GetMoviesDataPath(IApplicationPaths appPaths)
- {
- var dataPath = Path.Combine(appPaths.DataPath, "fanart-movies");
-
- if (!Directory.Exists(dataPath))
- {
- Directory.CreateDirectory(dataPath);
- }
-
- return dataPath;
- }
-
- /// <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 async Task<bool> FetchAsync(BaseItem item, bool force, CancellationToken cancellationToken)
- {
- cancellationToken.ThrowIfCancellationRequested();
-
- BaseProviderInfo data;
-
- if (!item.ProviderData.TryGetValue(Id, out data))
- {
- data = new BaseProviderInfo();
- item.ProviderData[Id] = data;
- }
-
- var movieId = item.GetProviderId(MetadataProviders.Tmdb);
-
- var movieDataPath = GetMovieDataPath(ConfigurationManager.ApplicationPaths, movieId);
- var xmlPath = Path.Combine(movieDataPath, "fanart.xml");
-
- // Only download the xml if it doesn't already exist. The prescan task will take care of getting updates
- if (!File.Exists(xmlPath))
- {
- await DownloadMovieXml(movieDataPath, movieId, cancellationToken).ConfigureAwait(false);
- }
-
- if (File.Exists(xmlPath))
- {
- await FetchFromXml(item, xmlPath, cancellationToken).ConfigureAwait(false);
- }
-
- data.Data = GetComparisonData(item.GetProviderId(MetadataProviders.Tmdb));
- SetLastRefreshed(item, DateTime.UtcNow);
- return true;
- }
-
- /// <summary>
- /// Downloads the movie XML.
- /// </summary>
- /// <param name="movieDataPath">The movie data path.</param>
- /// <param name="tmdbId">The TMDB id.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- internal async Task DownloadMovieXml(string movieDataPath, string tmdbId, CancellationToken cancellationToken)
- {
- cancellationToken.ThrowIfCancellationRequested();
-
- string url = string.Format(FanArtBaseUrl, ApiKey, tmdbId);
-
- var xmlPath = Path.Combine(movieDataPath, "fanart.xml");
-
- using (var response = await HttpClient.Get(new HttpRequestOptions
- {
- Url = url,
- ResourcePool = FanArtResourcePool,
- CancellationToken = cancellationToken
-
- }).ConfigureAwait(false))
- {
- using (var xmlFileStream = new FileStream(xmlPath, FileMode.Create, FileAccess.Write, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, FileOptions.Asynchronous))
- {
- await response.CopyToAsync(xmlFileStream).ConfigureAwait(false);
- }
- }
- }
-
- /// <summary>
- /// Fetches from XML.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="xmlFilePath">The XML file path.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- private async Task FetchFromXml(BaseItem item, string xmlFilePath, CancellationToken cancellationToken)
- {
- var doc = new XmlDocument();
- doc.Load(xmlFilePath);
-
- var language = ConfigurationManager.Configuration.PreferredMetadataLanguage.ToLower();
-
- cancellationToken.ThrowIfCancellationRequested();
-
- var saveLocal = ConfigurationManager.Configuration.SaveLocalMeta &&
- item.LocationType == LocationType.FileSystem;
-
- string path;
- var hd = ConfigurationManager.Configuration.DownloadHDFanArt ? "hd" : "";
-
- if (ConfigurationManager.Configuration.DownloadMovieImages.Logo && !item.HasImage(ImageType.Logo))
- {
- var node =
- doc.SelectSingleNode("//fanart/movie/movielogos/" + hd + "movielogo[@lang = \"" + language + "\"]/@url") ??
- doc.SelectSingleNode("//fanart/movie/movielogos/movielogo[@lang = \"" + language + "\"]/@url");
- if (node == null && language != "en")
- {
- //maybe just couldn't find language - try just first one
- node = doc.SelectSingleNode("//fanart/movie/movielogos/" + hd + "movielogo/@url");
- }
- path = node != null ? node.Value : null;
- if (!string.IsNullOrEmpty(path))
- {
- item.SetImage(ImageType.Logo, await _providerManager.DownloadAndSaveImage(item, path, LogoFile, saveLocal, FanArtResourcePool, cancellationToken).ConfigureAwait(false));
- }
- }
- cancellationToken.ThrowIfCancellationRequested();
-
- if (ConfigurationManager.Configuration.DownloadMovieImages.Art && !item.HasImage(ImageType.Art))
- {
- var node =
- doc.SelectSingleNode("//fanart/movie/moviearts/" + hd + "movieart[@lang = \"" + language + "\"]/@url") ??
- doc.SelectSingleNode("//fanart/movie/moviearts/" + hd + "movieart/@url") ??
- doc.SelectSingleNode("//fanart/movie/moviearts/movieart[@lang = \"" + language + "\"]/@url") ??
- doc.SelectSingleNode("//fanart/movie/moviearts/movieart/@url");
- path = node != null ? node.Value : null;
- if (!string.IsNullOrEmpty(path))
- {
- item.SetImage(ImageType.Art, await _providerManager.DownloadAndSaveImage(item, path, ArtFile, saveLocal, FanArtResourcePool, cancellationToken).ConfigureAwait(false));
- }
- }
- cancellationToken.ThrowIfCancellationRequested();
-
- if (ConfigurationManager.Configuration.DownloadMovieImages.Disc && !item.HasImage(ImageType.Disc))
- {
- var node = doc.SelectSingleNode("//fanart/movie/moviediscs/moviedisc[@lang = \"" + language + "\"]/@url") ??
- doc.SelectSingleNode("//fanart/movie/moviediscs/moviedisc/@url");
- path = node != null ? node.Value : null;
- if (!string.IsNullOrEmpty(path))
- {
- item.SetImage(ImageType.Disc, await _providerManager.DownloadAndSaveImage(item, path, DiscFile, saveLocal, FanArtResourcePool, cancellationToken).ConfigureAwait(false));
- }
- }
-
- cancellationToken.ThrowIfCancellationRequested();
-
- if (ConfigurationManager.Configuration.DownloadMovieImages.Banner && !item.HasImage(ImageType.Banner))
- {
- var node = doc.SelectSingleNode("//fanart/movie/moviebanners/moviebanner[@lang = \"" + language + "\"]/@url") ??
- doc.SelectSingleNode("//fanart/movie/moviebanners/moviebanner/@url");
- path = node != null ? node.Value : null;
- if (!string.IsNullOrEmpty(path))
- {
- item.SetImage(ImageType.Banner, await _providerManager.DownloadAndSaveImage(item, path, BannerFile, saveLocal, FanArtResourcePool, cancellationToken).ConfigureAwait(false));
- }
- }
-
- cancellationToken.ThrowIfCancellationRequested();
-
- if (ConfigurationManager.Configuration.DownloadMovieImages.Thumb && !item.HasImage(ImageType.Thumb))
- {
- var node = doc.SelectSingleNode("//fanart/movie/moviethumbs/moviethumb[@lang = \"" + language + "\"]/@url") ??
- doc.SelectSingleNode("//fanart/movie/moviethumbs/moviethumb/@url");
- path = node != null ? node.Value : null;
- if (!string.IsNullOrEmpty(path))
- {
- item.SetImage(ImageType.Thumb, await _providerManager.DownloadAndSaveImage(item, path, ThumbFile, saveLocal, FanArtResourcePool, cancellationToken).ConfigureAwait(false));
- }
- }
-
- if (ConfigurationManager.Configuration.DownloadMovieImages.Backdrops && item.BackdropImagePaths.Count == 0)
- {
- var nodes = doc.SelectNodes("//fanart/movie/moviebackgrounds//@url");
-
- if (nodes != null)
- {
- var numBackdrops = item.BackdropImagePaths.Count;
-
- foreach (XmlNode node in nodes)
- {
- path = node.Value;
-
- if (!string.IsNullOrEmpty(path))
- {
- item.BackdropImagePaths.Add(await _providerManager.DownloadAndSaveImage(item, path, ("backdrop" + (numBackdrops > 0 ? numBackdrops.ToString(UsCulture) : "") + ".jpg"), saveLocal, FanArtResourcePool, cancellationToken).ConfigureAwait(false));
-
- numBackdrops++;
-
- if (item.BackdropImagePaths.Count >= ConfigurationManager.Configuration.MaxBackdrops) break;
- }
- }
-
- }
- }
- }
- }
-}
diff --git a/MediaBrowser.Controller/Providers/Movies/FanArtMovieUpdatesPrescanTask.cs b/MediaBrowser.Controller/Providers/Movies/FanArtMovieUpdatesPrescanTask.cs
deleted file mode 100644
index b8efddfb4..000000000
--- a/MediaBrowser.Controller/Providers/Movies/FanArtMovieUpdatesPrescanTask.cs
+++ /dev/null
@@ -1,185 +0,0 @@
-using MediaBrowser.Common.Net;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.Providers.Music;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.Net;
-using MediaBrowser.Model.Serialization;
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.IO;
-using System.Linq;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace MediaBrowser.Controller.Providers.Movies
-{
- class FanArtMovieUpdatesPrescanTask : ILibraryPrescanTask
- {
- private const string UpdatesUrl = "http://api.fanart.tv/webservice/newmovies/{0}/{1}/";
-
- /// <summary>
- /// The _HTTP client
- /// </summary>
- private readonly IHttpClient _httpClient;
- /// <summary>
- /// The _logger
- /// </summary>
- private readonly ILogger _logger;
- /// <summary>
- /// The _config
- /// </summary>
- private readonly IServerConfigurationManager _config;
- private readonly IJsonSerializer _jsonSerializer;
-
- private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
-
- public FanArtMovieUpdatesPrescanTask(IJsonSerializer jsonSerializer, IServerConfigurationManager config, ILogger logger, IHttpClient httpClient)
- {
- _jsonSerializer = jsonSerializer;
- _config = config;
- _logger = logger;
- _httpClient = httpClient;
- }
-
- /// <summary>
- /// Runs the specified progress.
- /// </summary>
- /// <param name="progress">The progress.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- public async Task Run(IProgress<double> progress, CancellationToken cancellationToken)
- {
- if (!_config.Configuration.EnableInternetProviders)
- {
- progress.Report(100);
- return;
- }
-
- var path = FanArtMovieProvider.GetMoviesDataPath(_config.CommonApplicationPaths);
-
- var timestampFile = Path.Combine(path, "time.txt");
-
- var timestampFileInfo = new FileInfo(timestampFile);
-
- // Don't check for tvdb updates anymore frequently than 24 hours
- if (timestampFileInfo.Exists && (DateTime.UtcNow - timestampFileInfo.LastWriteTimeUtc).TotalDays < 1)
- {
- return;
- }
-
- // Find out the last time we queried for updates
- var lastUpdateTime = timestampFileInfo.Exists ? File.ReadAllText(timestampFile, Encoding.UTF8) : string.Empty;
-
- var existingDirectories = Directory.EnumerateDirectories(path).Select(Path.GetFileName).ToList();
-
- // If this is our first time, don't do any updates and just record the timestamp
- if (!string.IsNullOrEmpty(lastUpdateTime))
- {
- var moviesToUpdate = await GetMovieIdsToUpdate(existingDirectories, lastUpdateTime, cancellationToken).ConfigureAwait(false);
-
- progress.Report(5);
-
- await UpdateMovies(moviesToUpdate, path, progress, cancellationToken).ConfigureAwait(false);
- }
-
- var newUpdateTime = Convert.ToInt64(DateTimeToUnixTimestamp(DateTime.UtcNow)).ToString(UsCulture);
-
- File.WriteAllText(timestampFile, newUpdateTime, Encoding.UTF8);
-
- progress.Report(100);
- }
-
- private async Task<IEnumerable<string>> GetMovieIdsToUpdate(IEnumerable<string> existingIds, string lastUpdateTime, CancellationToken cancellationToken)
- {
- // First get last time
- using (var stream = await _httpClient.Get(new HttpRequestOptions
- {
- Url = string.Format(UpdatesUrl, FanartBaseProvider.ApiKey, lastUpdateTime),
- CancellationToken = cancellationToken,
- EnableHttpCompression = true,
- ResourcePool = FanartBaseProvider.FanArtResourcePool
-
- }).ConfigureAwait(false))
- {
- // If empty fanart will return a string of "null", rather than an empty list
- using (var reader = new StreamReader(stream))
- {
- var json = await reader.ReadToEndAsync().ConfigureAwait(false);
-
- if (string.Equals(json, "null", StringComparison.OrdinalIgnoreCase))
- {
- return new List<string>();
- }
-
- var updates = _jsonSerializer.DeserializeFromString<List<FanArtUpdatesPrescanTask.FanArtUpdate>>(json);
-
- return updates.Select(i => i.id).Where(i => existingIds.Contains(i, StringComparer.OrdinalIgnoreCase));
- }
- }
- }
-
- private async Task UpdateMovies(IEnumerable<string> idList, string moviesDataPath, IProgress<double> progress, CancellationToken cancellationToken)
- {
- var list = idList.ToList();
- var numComplete = 0;
-
- foreach (var id in list)
- {
- try
- {
- await UpdateMovie(id, moviesDataPath, cancellationToken).ConfigureAwait(false);
- }
- catch (HttpException ex)
- {
- // Already logged at lower levels, but don't fail the whole operation, unless something other than a timeout
- if (!ex.IsTimedOut)
- {
- throw;
- }
- }
-
- numComplete++;
- double percent = numComplete;
- percent /= list.Count;
- percent *= 95;
-
- progress.Report(percent + 5);
- }
- }
-
- private Task UpdateMovie(string tmdbId, string movieDataPath, CancellationToken cancellationToken)
- {
- _logger.Info("Updating movie " + tmdbId);
-
- movieDataPath = Path.Combine(movieDataPath, tmdbId);
-
- if (!Directory.Exists(movieDataPath))
- {
- Directory.CreateDirectory(movieDataPath);
- }
-
- return FanArtMovieProvider.Current.DownloadMovieXml(movieDataPath, tmdbId, cancellationToken);
- }
-
- /// <summary>
- /// Dates the time to unix timestamp.
- /// </summary>
- /// <param name="dateTime">The date time.</param>
- /// <returns>System.Double.</returns>
- private static double DateTimeToUnixTimestamp(DateTime dateTime)
- {
- return (dateTime - new DateTime(1970, 1, 1).ToUniversalTime()).TotalSeconds;
- }
-
- public class FanArtUpdate
- {
- public string id { get; set; }
- public string name { get; set; }
- public string new_images { get; set; }
- public string total_images { get; set; }
- }
- }
-}
diff --git a/MediaBrowser.Controller/Providers/Movies/MovieDbImagesProvider.cs b/MediaBrowser.Controller/Providers/Movies/MovieDbImagesProvider.cs
deleted file mode 100644
index 5a30f447b..000000000
--- a/MediaBrowser.Controller/Providers/Movies/MovieDbImagesProvider.cs
+++ /dev/null
@@ -1,412 +0,0 @@
-using MediaBrowser.Common.Extensions;
-using MediaBrowser.Common.Net;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Entities.Movies;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.Net;
-using MediaBrowser.Model.Serialization;
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.IO;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace MediaBrowser.Controller.Providers.Movies
-{
- /// <summary>
- /// Class MovieDbImagesProvider
- /// </summary>
- public class MovieDbImagesProvider : BaseMetadataProvider
- {
- /// <summary>
- /// The get images
- /// </summary>
- private const string GetImages = @"http://api.themoviedb.org/3/{2}/{0}/images?api_key={1}";
-
- /// <summary>
- /// The _provider manager
- /// </summary>
- private readonly IProviderManager _providerManager;
-
- /// <summary>
- /// The _json serializer
- /// </summary>
- private readonly IJsonSerializer _jsonSerializer;
-
- /// <summary>
- /// The _HTTP client
- /// </summary>
- private readonly IHttpClient _httpClient;
-
- /// <summary>
- /// Initializes a new instance of the <see cref="MovieDbImagesProvider"/> class.
- /// </summary>
- /// <param name="logManager">The log manager.</param>
- /// <param name="configurationManager">The configuration manager.</param>
- /// <param name="providerManager">The provider manager.</param>
- /// <param name="jsonSerializer">The json serializer.</param>
- /// <param name="httpClient">The HTTP client.</param>
- public MovieDbImagesProvider(ILogManager logManager, IServerConfigurationManager configurationManager, IProviderManager providerManager, IJsonSerializer jsonSerializer, IHttpClient httpClient)
- : base(logManager, configurationManager)
- {
- _providerManager = providerManager;
- _jsonSerializer = jsonSerializer;
- _httpClient = httpClient;
- }
-
- /// <summary>
- /// Gets the priority.
- /// </summary>
- /// <value>The priority.</value>
- public override MetadataProviderPriority Priority
- {
- get { return MetadataProviderPriority.Fourth; }
- }
-
- /// <summary>
- /// Supports 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)
- {
- var trailer = item as Trailer;
-
- if (trailer != null)
- {
- return !trailer.IsLocalTrailer;
- }
-
- // Don't support local trailers
- return item is Movie || item is BoxSet || item is MusicVideo;
- }
-
- /// <summary>
- /// Gets a value indicating whether [requires internet].
- /// </summary>
- /// <value><c>true</c> if [requires internet]; otherwise, <c>false</c>.</value>
- public override bool RequiresInternet
- {
- get
- {
- return true;
- }
- }
-
- /// <summary>
- /// If we save locally, refresh if they delete something
- /// </summary>
- /// <value><c>true</c> if [refresh on file system stamp change]; otherwise, <c>false</c>.</value>
- protected override bool RefreshOnFileSystemStampChange
- {
- get
- {
- return ConfigurationManager.Configuration.SaveLocalMeta;
- }
- }
-
- /// <summary>
- /// Gets a value indicating whether [refresh on version change].
- /// </summary>
- /// <value><c>true</c> if [refresh on version change]; otherwise, <c>false</c>.</value>
- protected override bool RefreshOnVersionChange
- {
- get
- {
- return true;
- }
- }
-
- /// <summary>
- /// Gets the provider version.
- /// </summary>
- /// <value>The provider version.</value>
- protected override string ProviderVersion
- {
- get
- {
- return "3";
- }
- }
-
- /// <summary>
- /// Needses the refresh internal.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="providerInfo">The provider info.</param>
- /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
- protected override bool NeedsRefreshInternal(BaseItem item, BaseProviderInfo providerInfo)
- {
- if (string.IsNullOrEmpty(item.GetProviderId(MetadataProviders.Tmdb)))
- {
- return false;
- }
-
- // Refresh if tmdb id has changed
- if (providerInfo.Data != GetComparisonData(item.GetProviderId(MetadataProviders.Tmdb)))
- {
- return true;
- }
-
- // Don't refresh if we already have both poster and backdrop and we're not refreshing images
- if (item.HasImage(ImageType.Primary) && item.BackdropImagePaths.Count > 0)
- {
- return false;
- }
-
- return base.NeedsRefreshInternal(item, providerInfo);
- }
-
- /// <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 async Task<bool> FetchAsync(BaseItem item, bool force, CancellationToken cancellationToken)
- {
- BaseProviderInfo data;
-
- if (!item.ProviderData.TryGetValue(Id, out data))
- {
- data = new BaseProviderInfo();
- item.ProviderData[Id] = data;
- }
-
- var images = await FetchImages(item, item.GetProviderId(MetadataProviders.Tmdb), cancellationToken).ConfigureAwait(false);
-
- var status = await ProcessImages(item, images, cancellationToken).ConfigureAwait(false);
-
- data.Data = GetComparisonData(item.GetProviderId(MetadataProviders.Tmdb));
-
- SetLastRefreshed(item, DateTime.UtcNow, status);
- return true;
- }
-
- /// <summary>
- /// Gets the comparison data.
- /// </summary>
- /// <returns>Guid.</returns>
- private Guid GetComparisonData(string id)
- {
- return string.IsNullOrEmpty(id) ? Guid.Empty : id.GetMD5();
- }
-
- /// <summary>
- /// Fetches the images.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="id">The id.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task{MovieImages}.</returns>
- private async Task<MovieImages> FetchImages(BaseItem item, string id, CancellationToken cancellationToken)
- {
- using (var json = await MovieDbProvider.Current.GetMovieDbResponse(new HttpRequestOptions
- {
- Url = string.Format(GetImages, id, MovieDbProvider.ApiKey, item is BoxSet ? "collection" : "movie"),
- CancellationToken = cancellationToken,
- AcceptHeader = MovieDbProvider.AcceptHeader
-
- }).ConfigureAwait(false))
- {
- return _jsonSerializer.DeserializeFromStream<MovieImages>(json);
- }
- }
-
- /// <summary>
- /// Processes the images.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="images">The images.</param>
- /// <param name="cancellationToken">The cancellation token</param>
- /// <returns>Task.</returns>
- protected virtual async Task<ProviderRefreshStatus> ProcessImages(BaseItem item, MovieImages images, CancellationToken cancellationToken)
- {
- cancellationToken.ThrowIfCancellationRequested();
-
- var status = ProviderRefreshStatus.Success;
-
- // poster
- if (images.posters != null && images.posters.Count > 0 && !item.HasImage(ImageType.Primary))
- {
- var tmdbSettings = await MovieDbProvider.Current.GetTmdbSettings(cancellationToken).ConfigureAwait(false);
-
- var tmdbImageUrl = tmdbSettings.images.base_url + ConfigurationManager.Configuration.TmdbFetchedPosterSize;
- // get highest rated poster for our language
-
- var postersSortedByVote = images.posters.OrderByDescending(i => i.vote_average);
-
- var poster = postersSortedByVote.FirstOrDefault(p => p.iso_639_1 != null && p.iso_639_1.Equals(ConfigurationManager.Configuration.PreferredMetadataLanguage, StringComparison.OrdinalIgnoreCase));
- if (poster == null && !ConfigurationManager.Configuration.PreferredMetadataLanguage.Equals("en"))
- {
- // couldn't find our specific language, find english (if that wasn't our language)
- poster = postersSortedByVote.FirstOrDefault(p => p.iso_639_1 != null && p.iso_639_1.Equals("en", StringComparison.OrdinalIgnoreCase));
- }
- if (poster == null)
- {
- //still couldn't find it - try highest rated null one
- poster = postersSortedByVote.FirstOrDefault(p => p.iso_639_1 == null);
- }
- if (poster == null)
- {
- //finally - just get the highest rated one
- poster = postersSortedByVote.FirstOrDefault();
- }
- if (poster != null)
- {
- var img = await MovieDbProvider.Current.GetMovieDbResponse(new HttpRequestOptions
- {
- Url = tmdbImageUrl + poster.file_path,
- CancellationToken = cancellationToken
-
- }).ConfigureAwait(false);
-
- item.PrimaryImagePath = await _providerManager.SaveImage(item, img, "folder" + Path.GetExtension(poster.file_path), ConfigurationManager.Configuration.SaveLocalMeta && item.LocationType == LocationType.FileSystem, cancellationToken).ConfigureAwait(false);
- }
- }
-
- cancellationToken.ThrowIfCancellationRequested();
-
- // backdrops - only download if earlier providers didn't find any (fanart)
- if (images.backdrops != null && images.backdrops.Count > 0 && ConfigurationManager.Configuration.DownloadMovieImages.Backdrops && item.BackdropImagePaths.Count == 0)
- {
- var tmdbSettings = await MovieDbProvider.Current.GetTmdbSettings(cancellationToken).ConfigureAwait(false);
-
- var tmdbImageUrl = tmdbSettings.images.base_url + ConfigurationManager.Configuration.TmdbFetchedBackdropSize;
-
- for (var i = 0; i < images.backdrops.Count; i++)
- {
- var bdName = "backdrop" + (i == 0 ? "" : i.ToString(CultureInfo.InvariantCulture));
-
- var hasLocalBackdrop = item.LocationType == LocationType.FileSystem && ConfigurationManager.Configuration.SaveLocalMeta ? item.HasLocalImage(bdName) : item.BackdropImagePaths.Count > i;
-
- if (!hasLocalBackdrop)
- {
- var img = await MovieDbProvider.Current.GetMovieDbResponse(new HttpRequestOptions
- {
- Url = tmdbImageUrl + images.backdrops[i].file_path,
- CancellationToken = cancellationToken
-
- }).ConfigureAwait(false);
-
- item.BackdropImagePaths.Add(await _providerManager.SaveImage(item, img, bdName + Path.GetExtension(images.backdrops[i].file_path), ConfigurationManager.Configuration.SaveLocalMeta && item.LocationType == LocationType.FileSystem, cancellationToken).ConfigureAwait(false));
- }
-
- if (item.BackdropImagePaths.Count >= ConfigurationManager.Configuration.MaxBackdrops)
- {
- break;
- }
- }
- }
-
- return status;
- }
-
- /// <summary>
- /// Class Backdrop
- /// </summary>
- protected class Backdrop
- {
- /// <summary>
- /// Gets or sets the file_path.
- /// </summary>
- /// <value>The file_path.</value>
- public string file_path { get; set; }
- /// <summary>
- /// Gets or sets the width.
- /// </summary>
- /// <value>The width.</value>
- public int width { get; set; }
- /// <summary>
- /// Gets or sets the height.
- /// </summary>
- /// <value>The height.</value>
- public int height { get; set; }
- /// <summary>
- /// Gets or sets the iso_639_1.
- /// </summary>
- /// <value>The iso_639_1.</value>
- public string iso_639_1 { get; set; }
- /// <summary>
- /// Gets or sets the aspect_ratio.
- /// </summary>
- /// <value>The aspect_ratio.</value>
- public double aspect_ratio { get; set; }
- /// <summary>
- /// Gets or sets the vote_average.
- /// </summary>
- /// <value>The vote_average.</value>
- public double vote_average { get; set; }
- /// <summary>
- /// Gets or sets the vote_count.
- /// </summary>
- /// <value>The vote_count.</value>
- public int vote_count { get; set; }
- }
-
- /// <summary>
- /// Class Poster
- /// </summary>
- protected class Poster
- {
- /// <summary>
- /// Gets or sets the file_path.
- /// </summary>
- /// <value>The file_path.</value>
- public string file_path { get; set; }
- /// <summary>
- /// Gets or sets the width.
- /// </summary>
- /// <value>The width.</value>
- public int width { get; set; }
- /// <summary>
- /// Gets or sets the height.
- /// </summary>
- /// <value>The height.</value>
- public int height { get; set; }
- /// <summary>
- /// Gets or sets the iso_639_1.
- /// </summary>
- /// <value>The iso_639_1.</value>
- public string iso_639_1 { get; set; }
- /// <summary>
- /// Gets or sets the aspect_ratio.
- /// </summary>
- /// <value>The aspect_ratio.</value>
- public double aspect_ratio { get; set; }
- /// <summary>
- /// Gets or sets the vote_average.
- /// </summary>
- /// <value>The vote_average.</value>
- public double vote_average { get; set; }
- /// <summary>
- /// Gets or sets the vote_count.
- /// </summary>
- /// <value>The vote_count.</value>
- public int vote_count { get; set; }
- }
-
- /// <summary>
- /// Class MovieImages
- /// </summary>
- protected class MovieImages
- {
- /// <summary>
- /// Gets or sets the backdrops.
- /// </summary>
- /// <value>The backdrops.</value>
- public List<Backdrop> backdrops { get; set; }
- /// <summary>
- /// Gets or sets the posters.
- /// </summary>
- /// <value>The posters.</value>
- public List<Poster> posters { get; set; }
- }
-
- }
-}
diff --git a/MediaBrowser.Controller/Providers/Movies/MovieDbProvider.cs b/MediaBrowser.Controller/Providers/Movies/MovieDbProvider.cs
deleted file mode 100644
index 6a9806d84..000000000
--- a/MediaBrowser.Controller/Providers/Movies/MovieDbProvider.cs
+++ /dev/null
@@ -1,1270 +0,0 @@
-using MediaBrowser.Common.Extensions;
-using MediaBrowser.Common.Net;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Entities.Movies;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.Serialization;
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.IO;
-using System.Linq;
-using System.Net;
-using System.Text;
-using System.Text.RegularExpressions;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace MediaBrowser.Controller.Providers.Movies
-{
- /// <summary>
- /// Class MovieDbProvider
- /// </summary>
- public class MovieDbProvider : BaseMetadataProvider, IDisposable
- {
- protected static CultureInfo EnUs = new CultureInfo("en-US");
-
- protected readonly IProviderManager ProviderManager;
-
- /// <summary>
- /// The movie db
- /// </summary>
- private readonly SemaphoreSlim _movieDbResourcePool = new SemaphoreSlim(1,1);
-
- internal static MovieDbProvider Current { get; private set; }
-
- /// <summary>
- /// Gets the json serializer.
- /// </summary>
- /// <value>The json serializer.</value>
- protected IJsonSerializer JsonSerializer { get; private set; }
-
- /// <summary>
- /// Gets the HTTP client.
- /// </summary>
- /// <value>The HTTP client.</value>
- protected IHttpClient HttpClient { get; private set; }
-
- /// <summary>
- /// Initializes a new instance of the <see cref="MovieDbProvider" /> class.
- /// </summary>
- /// <param name="logManager">The log manager.</param>
- /// <param name="configurationManager">The configuration manager.</param>
- /// <param name="jsonSerializer">The json serializer.</param>
- /// <param name="httpClient">The HTTP client.</param>
- /// <param name="providerManager">The provider manager.</param>
- public MovieDbProvider(ILogManager logManager, IServerConfigurationManager configurationManager, IJsonSerializer jsonSerializer, IHttpClient httpClient, IProviderManager providerManager)
- : base(logManager, configurationManager)
- {
- JsonSerializer = jsonSerializer;
- HttpClient = httpClient;
- ProviderManager = providerManager;
- Current = this;
- }
-
- /// <summary>
- /// Releases unmanaged and - optionally - managed resources.
- /// </summary>
- /// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
- protected virtual void Dispose(bool dispose)
- {
- if (dispose)
- {
- _movieDbResourcePool.Dispose();
- }
- }
-
- /// <summary>
- /// Gets the priority.
- /// </summary>
- /// <value>The priority.</value>
- public override MetadataProviderPriority Priority
- {
- get { return MetadataProviderPriority.Second; }
- }
-
- /// <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)
- {
- var trailer = item as Trailer;
-
- if (trailer != null)
- {
- return !trailer.IsLocalTrailer;
- }
-
- // Don't support local trailers
- return item is Movie || item is BoxSet || item is MusicVideo;
- }
-
- /// <summary>
- /// Gets a value indicating whether [requires internet].
- /// </summary>
- /// <value><c>true</c> if [requires internet]; otherwise, <c>false</c>.</value>
- public override bool RequiresInternet
- {
- get
- {
- return true;
- }
- }
-
- /// <summary>
- /// If we save locally, refresh if they delete something
- /// </summary>
- protected override bool RefreshOnFileSystemStampChange
- {
- get
- {
- return ConfigurationManager.Configuration.SaveLocalMeta;
- }
- }
-
- protected override bool RefreshOnVersionChange
- {
- get
- {
- return true;
- }
- }
-
- protected override string ProviderVersion
- {
- get
- {
- return "2";
- }
- }
-
- /// <summary>
- /// The _TMDB settings task
- /// </summary>
- private TmdbSettingsResult _tmdbSettings;
-
- private readonly SemaphoreSlim _tmdbSettingsSemaphore = new SemaphoreSlim(1, 1);
-
- /// <summary>
- /// Gets the TMDB settings.
- /// </summary>
- /// <returns>Task{TmdbSettingsResult}.</returns>
- internal async Task<TmdbSettingsResult> GetTmdbSettings(CancellationToken cancellationToken)
- {
- if (_tmdbSettings != null)
- {
- return _tmdbSettings;
- }
-
- await _tmdbSettingsSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
-
- // Check again in case it got populated while we were waiting.
- if (_tmdbSettings != null)
- {
- _tmdbSettingsSemaphore.Release();
- return _tmdbSettings;
- }
-
- try
- {
- using (var json = await GetMovieDbResponse(new HttpRequestOptions
- {
- Url = string.Format(TmdbConfigUrl, ApiKey),
- CancellationToken = cancellationToken,
- AcceptHeader = AcceptHeader
-
- }).ConfigureAwait(false))
- {
- _tmdbSettings = JsonSerializer.DeserializeFromStream<TmdbSettingsResult>(json);
-
- return _tmdbSettings;
- }
- }
- finally
- {
- _tmdbSettingsSemaphore.Release();
- }
- }
-
- /// <summary>
- /// The json provider
- /// </summary>
- protected MovieProviderFromJson JsonProvider;
-
- /// <summary>
- /// Sets the persisted last refresh date on the item for this provider.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="value">The value.</param>
- /// <param name="providerVersion">The provider version.</param>
- /// <param name="status">The status.</param>
- public override void SetLastRefreshed(BaseItem item, DateTime value, string providerVersion, ProviderRefreshStatus status = ProviderRefreshStatus.Success)
- {
- base.SetLastRefreshed(item, value, providerVersion, status);
-
- if (ConfigurationManager.Configuration.SaveLocalMeta && item.LocationType == LocationType.FileSystem)
- {
- //in addition to ours, we need to set the last refreshed time for the local data provider
- //so it won't see the new files we download and process them all over again
- if (JsonProvider == null) JsonProvider = new MovieProviderFromJson(LogManager, ConfigurationManager, JsonSerializer, HttpClient, ProviderManager);
-
- BaseProviderInfo data;
-
- if (!item.ProviderData.TryGetValue(JsonProvider.Id, out data))
- {
- data = new BaseProviderInfo();
- }
-
- data.LastRefreshed = value;
- item.ProviderData[JsonProvider.Id] = data;
- }
- }
-
- private const string TmdbConfigUrl = "http://api.themoviedb.org/3/configuration?api_key={0}";
- private const string Search3 = @"http://api.themoviedb.org/3/search/movie?api_key={1}&query={0}&language={2}";
- private const string AltTitleSearch = @"http://api.themoviedb.org/3/movie/{0}/alternative_titles?api_key={1}&country={2}";
- private const string GetMovieInfo3 = @"http://api.themoviedb.org/3/movie/{0}?api_key={1}&language={2}&append_to_response=casts,releases,images,keywords";
- private const string GetBoxSetInfo3 = @"http://api.themoviedb.org/3/collection/{0}?api_key={1}&language={2}&append_to_response=images";
-
- internal static string ApiKey = "f6bd687ffa63cd282b6ff2c6877f2669";
- internal static string AcceptHeader = "application/json,image/*";
-
- static readonly Regex[] NameMatches = new[] {
- new Regex(@"(?<name>.*)\((?<year>\d{4})\)"), // matches "My Movie (2001)" and gives us the name and the year
- new Regex(@"(?<name>.*)") // last resort matches the whole string as the name
- };
-
- public const string LocalMetaFileName = "tmdb3.json";
- public const string AltMetaFileName = "movie.xml";
-
- protected override bool NeedsRefreshInternal(BaseItem item, BaseProviderInfo providerInfo)
- {
- if (HasAltMeta(item))
- return false; //never refresh if has meta from other source
-
- return base.NeedsRefreshInternal(item, providerInfo);
- }
-
- /// <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 async Task<bool> FetchAsync(BaseItem item, bool force, CancellationToken cancellationToken)
- {
- if (HasAltMeta(item))
- {
- Logger.Info("MovieDbProvider - Not fetching because 3rd party meta exists for " + item.Name);
- SetLastRefreshed(item, DateTime.UtcNow);
- return true;
- }
-
- cancellationToken.ThrowIfCancellationRequested();
-
- await FetchMovieData(item, cancellationToken).ConfigureAwait(false);
-
- SetLastRefreshed(item, DateTime.UtcNow);
- return true;
- }
-
- /// <summary>
- /// Determines whether [has local meta] [the specified item].
- /// </summary>
- /// <param name="item">The item.</param>
- /// <returns><c>true</c> if [has local meta] [the specified item]; otherwise, <c>false</c>.</returns>
- private bool HasLocalMeta(BaseItem item)
- {
- //need at least the xml and folder.jpg/png or a movie.xml put in by someone else
- return item.LocationType == LocationType.FileSystem && item.ResolveArgs.ContainsMetaFileByName(LocalMetaFileName);
- }
-
- /// <summary>
- /// Determines whether [has alt meta] [the specified item].
- /// </summary>
- /// <param name="item">The item.</param>
- /// <returns><c>true</c> if [has alt meta] [the specified item]; otherwise, <c>false</c>.</returns>
- private bool HasAltMeta(BaseItem item)
- {
- return item.LocationType == LocationType.FileSystem && item.ResolveArgs.ContainsMetaFileByName(AltMetaFileName);
- }
-
- /// <summary>
- /// Fetches the movie data.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="cancellationToken"></param>
- /// <returns>Task.</returns>
- private async Task FetchMovieData(BaseItem item, CancellationToken cancellationToken)
- {
- string id = item.GetProviderId(MetadataProviders.Tmdb) ?? await FindId(item, item.ProductionYear, cancellationToken).ConfigureAwait(false);
- if (id != null)
- {
- Logger.Debug("MovieDbProvider - getting movie info with id: " + id);
-
- cancellationToken.ThrowIfCancellationRequested();
-
- await FetchMovieData(item, id, cancellationToken).ConfigureAwait(false);
- }
- else
- {
- Logger.Info("MovieDBProvider could not find " + item.Name + ". Check name on themoviedb.org.");
- }
- }
-
- /// <summary>
- /// Parses the name.
- /// </summary>
- /// <param name="name">The name.</param>
- /// <param name="justName">Name of the just.</param>
- /// <param name="year">The year.</param>
- protected void ParseName(string name, out string justName, out int? year)
- {
- justName = null;
- year = null;
- foreach (var re in NameMatches)
- {
- Match m = re.Match(name);
- if (m.Success)
- {
- justName = m.Groups["name"].Value.Trim();
- string y = m.Groups["year"] != null ? m.Groups["year"].Value : null;
- int temp;
- year = Int32.TryParse(y, out temp) ? temp : (int?)null;
- break;
- }
- }
- }
-
- /// <summary>
- /// Finds the id.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="productionYear">The production year.</param>
- /// <param name="cancellationToken">The cancellation token</param>
- /// <returns>Task{System.String}.</returns>
- public async Task<string> FindId(BaseItem item, int? productionYear, CancellationToken cancellationToken)
- {
- string id = null;
-
- if (item.LocationType == LocationType.FileSystem)
- {
- string justName = item.Path != null ? item.Path.Substring(item.Path.LastIndexOf(Path.DirectorySeparatorChar)) : string.Empty;
- id = justName.GetAttributeValue("tmdbid");
- if (id != null)
- {
- Logger.Debug("Using tmdb id specified in path.");
- return id;
- }
- }
-
- int? year;
- string name = item.Name;
- ParseName(name, out name, out year);
-
- if (year == null && productionYear != null)
- {
- year = productionYear;
- }
-
- Logger.Info("MovieDbProvider: Finding id for movie: " + name);
- string language = ConfigurationManager.Configuration.PreferredMetadataLanguage.ToLower();
-
- //if we are a boxset - look at our first child
- var boxset = item as BoxSet;
- if (boxset != null)
- {
- var firstChild = boxset.Children.FirstOrDefault();
-
- if (firstChild != null)
- {
- Logger.Debug("MovieDbProvider - Attempting to find boxset ID from: " + firstChild.Name);
- string childName;
- int? childYear;
- ParseName(firstChild.Name, out childName, out childYear);
- id = await GetBoxsetIdFromMovie(childName, childYear, language, cancellationToken).ConfigureAwait(false);
- if (id != null)
- {
- Logger.Info("MovieDbProvider - Found Boxset ID: " + id);
- }
- }
-
- return id;
- }
- //nope - search for it
- id = await AttemptFindId(name, year, language, cancellationToken).ConfigureAwait(false);
- if (id == null)
- {
- //try in english if wasn't before
- if (language != "en")
- {
- id = await AttemptFindId(name, year, "en", cancellationToken).ConfigureAwait(false);
- }
- else
- {
- // try with dot and _ turned to space
- var originalName = name;
-
- name = name.Replace(",", " ");
- name = name.Replace(".", " ");
- name = name.Replace("_", " ");
- name = name.Replace("-", "");
-
- // Search again if the new name is different
- if (!string.Equals(name, originalName))
- {
- id = await AttemptFindId(name, year, language, cancellationToken).ConfigureAwait(false);
-
- if (id == null && language != "en")
- {
- //one more time, in english
- id = await AttemptFindId(name, year, "en", cancellationToken).ConfigureAwait(false);
-
- }
- }
-
- if (id == null && item.LocationType == LocationType.FileSystem)
- {
- //last resort - try using the actual folder name
- var pathName = Path.GetFileName(item.ResolveArgs.Path);
-
- // Only search if it's a name we haven't already tried.
- if (!string.Equals(pathName, name, StringComparison.OrdinalIgnoreCase)
- && !string.Equals(pathName, originalName, StringComparison.OrdinalIgnoreCase))
- {
- id = await AttemptFindId(pathName, year, "en", cancellationToken).ConfigureAwait(false);
- }
- }
- }
- }
-
- return id;
- }
-
- /// <summary>
- /// Attempts the find id.
- /// </summary>
- /// <param name="name">The name.</param>
- /// <param name="year">The year.</param>
- /// <param name="language">The language.</param>
- /// <param name="cancellationToken">The cancellation token</param>
- /// <returns>Task{System.String}.</returns>
- public virtual async Task<string> AttemptFindId(string name, int? year, string language, CancellationToken cancellationToken)
- {
- string url3 = string.Format(Search3, UrlEncode(name), ApiKey, language);
- TmdbMovieSearchResults searchResult = null;
-
- using (Stream json = await GetMovieDbResponse(new HttpRequestOptions
- {
- Url = url3,
- CancellationToken = cancellationToken,
- AcceptHeader = AcceptHeader
-
- }).ConfigureAwait(false))
- {
- searchResult = JsonSerializer.DeserializeFromStream<TmdbMovieSearchResults>(json);
- }
-
- if (searchResult == null || searchResult.results.Count == 0)
- {
- //try replacing numbers
- foreach (var pair in ReplaceStartNumbers)
- {
- if (name.StartsWith(pair.Key))
- {
- name = name.Remove(0, pair.Key.Length);
- name = pair.Value + name;
- }
- }
- foreach (var pair in ReplaceEndNumbers)
- {
- if (name.EndsWith(pair.Key))
- {
- name = name.Remove(name.IndexOf(pair.Key), pair.Key.Length);
- name = name + pair.Value;
- }
- }
- Logger.Info("MovieDBProvider - No results. Trying replacement numbers: " + name);
- url3 = string.Format(Search3, UrlEncode(name), ApiKey, language);
-
- using (var json = await GetMovieDbResponse(new HttpRequestOptions
- {
- Url = url3,
- CancellationToken = cancellationToken,
- AcceptHeader = AcceptHeader
-
- }).ConfigureAwait(false))
- {
- searchResult = JsonSerializer.DeserializeFromStream<TmdbMovieSearchResults>(json);
- }
- }
- if (searchResult != null)
- {
- string compName = GetComparableName(name, Logger);
- foreach (var possible in searchResult.results)
- {
- string matchedName = null;
- string id = possible.id.ToString(CultureInfo.InvariantCulture);
- string n = possible.title;
- if (GetComparableName(n, Logger) == compName)
- {
- matchedName = n;
- }
- else
- {
- n = possible.original_title;
- if (GetComparableName(n, Logger) == compName)
- {
- matchedName = n;
- }
- }
-
- Logger.Debug("MovieDbProvider - " + compName + " didn't match " + n);
- //if main title matches we don't have to look for alternatives
- if (matchedName == null)
- {
- //that title didn't match - look for alternatives
- url3 = string.Format(AltTitleSearch, id, ApiKey, ConfigurationManager.Configuration.MetadataCountryCode);
-
- using (var json = await GetMovieDbResponse(new HttpRequestOptions
- {
- Url = url3,
- CancellationToken = cancellationToken,
- AcceptHeader = AcceptHeader
-
- }).ConfigureAwait(false))
- {
- var response = JsonSerializer.DeserializeFromStream<TmdbAltTitleResults>(json);
-
- if (response != null && response.titles != null)
- {
- foreach (var title in response.titles)
- {
- var t = GetComparableName(title.title, Logger);
- if (t == compName)
- {
- Logger.Debug("MovieDbProvider - " + compName +
- " matched " + t);
- matchedName = t;
- break;
- }
- Logger.Debug("MovieDbProvider - " + compName +
- " did not match " + t);
- }
- }
- }
- }
-
- if (matchedName != null)
- {
- Logger.Debug("Match " + matchedName + " for " + name);
- if (year != null)
- {
- DateTime r;
-
- //These dates are always in this exact format
- if (DateTime.TryParseExact(possible.release_date, "yyyy-MM-dd", EnUs, DateTimeStyles.None, out r))
- {
- if (Math.Abs(r.Year - year.Value) > 1) // allow a 1 year tolerance on release date
- {
- Logger.Debug("Result " + matchedName + " released on " + r + " did not match year " + year);
- continue;
- }
- }
- }
- //matched name and year
- return id;
- }
-
- }
- }
-
- return null;
- }
-
- /// <summary>
- /// URLs the encode.
- /// </summary>
- /// <param name="name">The name.</param>
- /// <returns>System.String.</returns>
- private static string UrlEncode(string name)
- {
- return WebUtility.UrlEncode(name);
- }
-
- /// <summary>
- /// Gets the boxset id from movie.
- /// </summary>
- /// <param name="name">The name.</param>
- /// <param name="year">The year.</param>
- /// <param name="language">The language.</param>
- /// <param name="cancellationToken">The cancellation token</param>
- /// <returns>Task{System.String}.</returns>
- protected async Task<string> GetBoxsetIdFromMovie(string name, int? year, string language, CancellationToken cancellationToken)
- {
- string id = null;
- string childId = await AttemptFindId(name, year, language, cancellationToken).ConfigureAwait(false);
- if (childId != null)
- {
- string url = string.Format(GetMovieInfo3, childId, ApiKey, language);
-
- using (Stream json = await GetMovieDbResponse(new HttpRequestOptions
- {
- Url = url,
- CancellationToken = cancellationToken,
- AcceptHeader = AcceptHeader
-
- }).ConfigureAwait(false))
- {
- var movieResult = JsonSerializer.DeserializeFromStream<CompleteMovieData>(json);
-
- if (movieResult != null && movieResult.belongs_to_collection != null)
- {
- id = movieResult.belongs_to_collection.id.ToString(CultureInfo.InvariantCulture);
- }
- else
- {
- Logger.Error("Unable to obtain boxset id.");
- }
- }
- }
- return id;
- }
-
- /// <summary>
- /// Fetches the movie data.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="id">The id.</param>
- /// <param name="cancellationToken">The cancellation token</param>
- /// <returns>Task.</returns>
- protected async Task FetchMovieData(BaseItem item, string id, CancellationToken cancellationToken)
- {
- cancellationToken.ThrowIfCancellationRequested();
-
- if (String.IsNullOrEmpty(id))
- {
- Logger.Info("MoviedbProvider: Ignoring " + item.Name + " because ID forced blank.");
- return;
- }
- if (item.GetProviderId(MetadataProviders.Tmdb) == null) item.SetProviderId(MetadataProviders.Tmdb, id);
-
- var mainResult = await FetchMainResult(item, id, cancellationToken).ConfigureAwait(false);
-
- if (mainResult == null) return;
-
- ProcessMainInfo(item, mainResult);
-
- cancellationToken.ThrowIfCancellationRequested();
-
- //and save locally
- if (ConfigurationManager.Configuration.SaveLocalMeta && item.LocationType == LocationType.FileSystem)
- {
- var ms = new MemoryStream();
- JsonSerializer.SerializeToStream(mainResult, ms);
-
- cancellationToken.ThrowIfCancellationRequested();
-
- await ProviderManager.SaveToLibraryFilesystem(item, Path.Combine(item.MetaLocation, LocalMetaFileName), ms, cancellationToken).ConfigureAwait(false);
- }
- }
-
- /// <summary>
- /// Fetches the main result.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="id">The id.</param>
- /// <param name="cancellationToken">The cancellation token</param>
- /// <returns>Task{CompleteMovieData}.</returns>
- protected async Task<CompleteMovieData> FetchMainResult(BaseItem item, string id, CancellationToken cancellationToken)
- {
- var baseUrl = item is BoxSet ? GetBoxSetInfo3 : GetMovieInfo3;
-
- string url = string.Format(baseUrl, id, ApiKey, ConfigurationManager.Configuration.PreferredMetadataLanguage);
- CompleteMovieData mainResult;
-
- cancellationToken.ThrowIfCancellationRequested();
-
- using (var json = await GetMovieDbResponse(new HttpRequestOptions
- {
- Url = url,
- CancellationToken = cancellationToken,
- AcceptHeader = AcceptHeader
-
- }).ConfigureAwait(false))
- {
- mainResult = JsonSerializer.DeserializeFromStream<CompleteMovieData>(json);
- }
-
- cancellationToken.ThrowIfCancellationRequested();
-
- if (mainResult != null && string.IsNullOrEmpty(mainResult.overview))
- {
- if (ConfigurationManager.Configuration.PreferredMetadataLanguage.ToLower() != "en")
- {
- Logger.Info("MovieDbProvider couldn't find meta for language " + ConfigurationManager.Configuration.PreferredMetadataLanguage + ". Trying English...");
-
- url = string.Format(baseUrl, id, ApiKey, "en");
-
- using (Stream json = await GetMovieDbResponse(new HttpRequestOptions
- {
- Url = url,
- CancellationToken = cancellationToken,
- AcceptHeader = AcceptHeader
-
- }).ConfigureAwait(false))
- {
- mainResult = JsonSerializer.DeserializeFromStream<CompleteMovieData>(json);
- }
-
- if (String.IsNullOrEmpty(mainResult.overview))
- {
- Logger.Error("MovieDbProvider - Unable to find information for " + item.Name + " (id:" + id + ")");
- return null;
- }
- }
- }
- return mainResult;
- }
-
- /// <summary>
- /// Processes the main info.
- /// </summary>
- /// <param name="movie">The movie.</param>
- /// <param name="movieData">The movie data.</param>
- protected virtual void ProcessMainInfo(BaseItem movie, CompleteMovieData movieData)
- {
- if (movie != null && movieData != null)
- {
-
- movie.Name = movieData.title ?? movieData.original_title ?? movie.Name;
- movie.Overview = movieData.overview;
- movie.Overview = movie.Overview != null ? movie.Overview.Replace("\n\n", "\n") : null;
- movie.HomePageUrl = movieData.homepage;
- movie.Budget = movieData.budget;
- movie.Revenue = movieData.revenue;
-
- if (!string.IsNullOrEmpty(movieData.tagline))
- {
- movie.Taglines.Clear();
- movie.AddTagline(movieData.tagline);
- }
-
- movie.SetProviderId(MetadataProviders.Imdb, movieData.imdb_id);
-
- if (movieData.belongs_to_collection != null)
- {
- movie.SetProviderId(MetadataProviders.TmdbCollection, movieData.belongs_to_collection.id.ToString(CultureInfo.InvariantCulture));
- }
-
- float rating;
- string voteAvg = movieData.vote_average.ToString(CultureInfo.InvariantCulture);
- //tmdb appears to have unified their numbers to always report "7.3" regardless of country
- // so I removed the culture-specific processing here because it was not working for other countries -ebr
- if (float.TryParse(voteAvg, NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out rating))
- movie.CommunityRating = rating;
-
- //release date and certification are retrieved based on configured country and we fall back on US if not there
- if (movieData.releases != null && movieData.releases.countries != null)
- {
- var ourRelease = movieData.releases.countries.FirstOrDefault(c => c.iso_3166_1.Equals(ConfigurationManager.Configuration.MetadataCountryCode, StringComparison.OrdinalIgnoreCase)) ?? new Country();
- var usRelease = movieData.releases.countries.FirstOrDefault(c => c.iso_3166_1.Equals("US", StringComparison.OrdinalIgnoreCase)) ?? new Country();
- var ratingPrefix = ConfigurationManager.Configuration.MetadataCountryCode.Equals("us", StringComparison.OrdinalIgnoreCase) ? "" : ConfigurationManager.Configuration.MetadataCountryCode +"-";
- movie.OfficialRating = !string.IsNullOrEmpty(ourRelease.certification) ? ratingPrefix + ourRelease.certification : !string.IsNullOrEmpty(usRelease.certification) ? usRelease.certification : null;
-
- if (ourRelease.release_date > new DateTime(1900, 1, 1))
- {
- if (ourRelease.release_date.Year != 1)
- {
- movie.PremiereDate = ourRelease.release_date.ToUniversalTime();
- movie.ProductionYear = ourRelease.release_date.Year;
- }
- }
- else
- {
- if (usRelease.release_date.Year != 1)
- {
- movie.PremiereDate = usRelease.release_date.ToUniversalTime();
- movie.ProductionYear = usRelease.release_date.Year;
- }
- }
- }
- else
- {
- if (movieData.release_date.Year != 1)
- {
- //no specific country release info at all
- movie.PremiereDate = movieData.release_date.ToUniversalTime();
- movie.ProductionYear = movieData.release_date.Year;
- }
- }
-
- //if that didn't find a rating and we are a boxset, use the one from our first child
- if (movie.OfficialRating == null && movie is BoxSet)
- {
- var boxset = movie as BoxSet;
- Logger.Info("MovieDbProvider - Using rating of first child of boxset...");
-
- var firstChild = boxset.Children.FirstOrDefault();
-
- boxset.OfficialRating = firstChild != null ? firstChild.OfficialRating : null;
- }
-
- if (movieData.runtime > 0)
- movie.OriginalRunTimeTicks = TimeSpan.FromMinutes(movieData.runtime).Ticks;
-
- //studios
- if (movieData.production_companies != null)
- {
- movie.Studios.Clear();
-
- foreach (var studio in movieData.production_companies.Select(c => c.name))
- {
- movie.AddStudio(studio);
- }
- }
-
- //genres
- if (movieData.genres != null)
- {
- movie.Genres.Clear();
-
- foreach (var genre in movieData.genres.Select(g => g.name))
- {
- movie.AddGenre(genre);
- }
- }
-
- movie.People.Clear();
- movie.Tags.Clear();
-
- //Actors, Directors, Writers - all in People
- //actors come from cast
- if (movieData.casts != null && movieData.casts.cast != null)
- {
- foreach (var actor in movieData.casts.cast.OrderBy(a => a.order)) movie.AddPerson(new PersonInfo { Name = actor.name, Role = actor.character, Type = PersonType.Actor });
- }
-
- //and the rest from crew
- if (movieData.casts != null && movieData.casts.crew != null)
- {
- foreach (var person in movieData.casts.crew) movie.AddPerson(new PersonInfo { Name = person.name, Role = person.job, Type = person.department });
- }
-
- if (movieData.keywords != null && movieData.keywords.keywords != null)
- {
- movie.Tags = movieData.keywords.keywords.Select(i => i.name).ToList();
- }
- }
-
- }
-
- private DateTime _lastRequestDate = DateTime.MinValue;
-
- /// <summary>
- /// Gets the movie db response.
- /// </summary>
- internal async Task<Stream> GetMovieDbResponse(HttpRequestOptions options)
- {
- var cancellationToken = options.CancellationToken;
-
- await _movieDbResourcePool.WaitAsync(cancellationToken).ConfigureAwait(false);
-
- try
- {
- // Limit to three requests per second
- var diff = 340 - (DateTime.Now - _lastRequestDate).TotalMilliseconds;
-
- if (diff > 0)
- {
- await Task.Delay(Convert.ToInt32(diff), cancellationToken).ConfigureAwait(false);
- }
-
- _lastRequestDate = DateTime.Now;
-
- return await HttpClient.Get(options).ConfigureAwait(false);
- }
- finally
- {
- _lastRequestDate = DateTime.Now;
-
- _movieDbResourcePool.Release();
- }
- }
-
- /// <summary>
- /// The remove
- /// </summary>
- const string Remove = "\"'!`?";
- // "Face/Off" support.
- /// <summary>
- /// The spacers
- /// </summary>
- const string Spacers = "/,.:;\\(){}[]+-_=–*"; // (there are not actually two - in the they are different char codes)
- /// <summary>
- /// The replace start numbers
- /// </summary>
- static readonly Dictionary<string, string> ReplaceStartNumbers = new Dictionary<string, string> {
- {"1 ","one "},
- {"2 ","two "},
- {"3 ","three "},
- {"4 ","four "},
- {"5 ","five "},
- {"6 ","six "},
- {"7 ","seven "},
- {"8 ","eight "},
- {"9 ","nine "},
- {"10 ","ten "},
- {"11 ","eleven "},
- {"12 ","twelve "},
- {"13 ","thirteen "},
- {"100 ","one hundred "},
- {"101 ","one hundred one "}
- };
-
- /// <summary>
- /// The replace end numbers
- /// </summary>
- static readonly Dictionary<string, string> ReplaceEndNumbers = new Dictionary<string, string> {
- {" 1"," i"},
- {" 2"," ii"},
- {" 3"," iii"},
- {" 4"," iv"},
- {" 5"," v"},
- {" 6"," vi"},
- {" 7"," vii"},
- {" 8"," viii"},
- {" 9"," ix"},
- {" 10"," x"}
- };
-
- /// <summary>
- /// Gets the name of the comparable.
- /// </summary>
- /// <param name="name">The name.</param>
- /// <param name="logger">The logger.</param>
- /// <returns>System.String.</returns>
- internal static string GetComparableName(string name, ILogger logger)
- {
- name = name.ToLower();
- name = name.Replace("á", "a");
- name = name.Replace("é", "e");
- name = name.Replace("í", "i");
- name = name.Replace("ó", "o");
- name = name.Replace("ú", "u");
- name = name.Replace("ü", "u");
- name = name.Replace("ñ", "n");
- foreach (var pair in ReplaceStartNumbers)
- {
- if (name.StartsWith(pair.Key))
- {
- name = name.Remove(0, pair.Key.Length);
- name = pair.Value + name;
- logger.Info("MovieDbProvider - Replaced Start Numbers: " + name);
- }
- }
- foreach (var pair in ReplaceEndNumbers)
- {
- if (name.EndsWith(pair.Key))
- {
- name = name.Remove(name.IndexOf(pair.Key), pair.Key.Length);
- name = name + pair.Value;
- logger.Info("MovieDbProvider - Replaced End Numbers: " + name);
- }
- }
- name = name.Normalize(NormalizationForm.FormKD);
- var sb = new StringBuilder();
- foreach (var c in name)
- {
- if (c >= 0x2B0 && c <= 0x0333)
- {
- // skip char modifier and diacritics
- }
- else if (Remove.IndexOf(c) > -1)
- {
- // skip chars we are removing
- }
- else if (Spacers.IndexOf(c) > -1)
- {
- sb.Append(" ");
- }
- else if (c == '&')
- {
- sb.Append(" and ");
- }
- else
- {
- sb.Append(c);
- }
- }
- name = sb.ToString();
- name = name.Replace(", the", "");
- name = name.Replace(" the ", " ");
- name = name.Replace("the ", "");
-
- string prev_name;
- do
- {
- prev_name = name;
- name = name.Replace(" ", " ");
- } while (name.Length != prev_name.Length);
-
- return name.Trim();
- }
-
- #region Result Objects
-
-
- /// <summary>
- /// Class TmdbTitle
- /// </summary>
- protected class TmdbTitle
- {
- /// <summary>
- /// Gets or sets the iso_3166_1.
- /// </summary>
- /// <value>The iso_3166_1.</value>
- public string iso_3166_1 { get; set; }
- /// <summary>
- /// Gets or sets the title.
- /// </summary>
- /// <value>The title.</value>
- public string title { get; set; }
- }
-
- /// <summary>
- /// Class TmdbAltTitleResults
- /// </summary>
- protected class TmdbAltTitleResults
- {
- /// <summary>
- /// Gets or sets the id.
- /// </summary>
- /// <value>The id.</value>
- public int id { get; set; }
- /// <summary>
- /// Gets or sets the titles.
- /// </summary>
- /// <value>The titles.</value>
- public List<TmdbTitle> titles { get; set; }
- }
-
- /// <summary>
- /// Class TmdbMovieSearchResult
- /// </summary>
- protected class TmdbMovieSearchResult
- {
- /// <summary>
- /// Gets or sets a value indicating whether this <see cref="TmdbMovieSearchResult" /> is adult.
- /// </summary>
- /// <value><c>true</c> if adult; otherwise, <c>false</c>.</value>
- public bool adult { get; set; }
- /// <summary>
- /// Gets or sets the backdrop_path.
- /// </summary>
- /// <value>The backdrop_path.</value>
- public string backdrop_path { get; set; }
- /// <summary>
- /// Gets or sets the id.
- /// </summary>
- /// <value>The id.</value>
- public int id { get; set; }
- /// <summary>
- /// Gets or sets the original_title.
- /// </summary>
- /// <value>The original_title.</value>
- public string original_title { get; set; }
- /// <summary>
- /// Gets or sets the release_date.
- /// </summary>
- /// <value>The release_date.</value>
- public string release_date { get; set; }
- /// <summary>
- /// Gets or sets the poster_path.
- /// </summary>
- /// <value>The poster_path.</value>
- public string poster_path { get; set; }
- /// <summary>
- /// Gets or sets the popularity.
- /// </summary>
- /// <value>The popularity.</value>
- public double popularity { get; set; }
- /// <summary>
- /// Gets or sets the title.
- /// </summary>
- /// <value>The title.</value>
- public string title { get; set; }
- /// <summary>
- /// Gets or sets the vote_average.
- /// </summary>
- /// <value>The vote_average.</value>
- public double vote_average { get; set; }
- /// <summary>
- /// Gets or sets the vote_count.
- /// </summary>
- /// <value>The vote_count.</value>
- public int vote_count { get; set; }
- }
-
- /// <summary>
- /// Class TmdbMovieSearchResults
- /// </summary>
- protected class TmdbMovieSearchResults
- {
- /// <summary>
- /// Gets or sets the page.
- /// </summary>
- /// <value>The page.</value>
- public int page { get; set; }
- /// <summary>
- /// Gets or sets the results.
- /// </summary>
- /// <value>The results.</value>
- public List<TmdbMovieSearchResult> results { get; set; }
- /// <summary>
- /// Gets or sets the total_pages.
- /// </summary>
- /// <value>The total_pages.</value>
- public int total_pages { get; set; }
- /// <summary>
- /// Gets or sets the total_results.
- /// </summary>
- /// <value>The total_results.</value>
- public int total_results { get; set; }
- }
-
- protected class BelongsToCollection
- {
- public int id { get; set; }
- public string name { get; set; }
- public string poster_path { get; set; }
- public string backdrop_path { get; set; }
- }
-
- protected class GenreItem
- {
- public int id { get; set; }
- public string name { get; set; }
- }
-
- protected class ProductionCompany
- {
- public string name { get; set; }
- public int id { get; set; }
- }
-
- protected class ProductionCountry
- {
- public string iso_3166_1 { get; set; }
- public string name { get; set; }
- }
-
- protected class SpokenLanguage
- {
- public string iso_639_1 { get; set; }
- public string name { get; set; }
- }
-
- protected class Cast
- {
- public int id { get; set; }
- public string name { get; set; }
- public string character { get; set; }
- public int order { get; set; }
- public int cast_id { get; set; }
- public string profile_path { get; set; }
- }
-
- protected class Crew
- {
- public int id { get; set; }
- public string name { get; set; }
- public string department { get; set; }
- public string job { get; set; }
- public string profile_path { get; set; }
- }
-
- protected class Casts
- {
- public List<Cast> cast { get; set; }
- public List<Crew> crew { get; set; }
- }
-
- protected class Country
- {
- public string iso_3166_1 { get; set; }
- public string certification { get; set; }
- public DateTime release_date { get; set; }
- }
-
- protected class Releases
- {
- public List<Country> countries { get; set; }
- }
-
- protected class Keyword
- {
- public int id { get; set; }
- public string name { get; set; }
- }
-
- protected class Keywords
- {
- public List<Keyword> keywords { get; set; }
- }
-
- protected class CompleteMovieData
- {
- public bool adult { get; set; }
- public string backdrop_path { get; set; }
- public BelongsToCollection belongs_to_collection { get; set; }
- public int budget { get; set; }
- public List<GenreItem> genres { get; set; }
- public string homepage { get; set; }
- public int id { get; set; }
- public string imdb_id { get; set; }
- public string original_title { get; set; }
- public string overview { get; set; }
- public double popularity { get; set; }
- public string poster_path { get; set; }
- public List<ProductionCompany> production_companies { get; set; }
- public List<ProductionCountry> production_countries { get; set; }
- public DateTime release_date { get; set; }
- public int revenue { get; set; }
- public int runtime { get; set; }
- public List<SpokenLanguage> spoken_languages { get; set; }
- public string status { get; set; }
- public string tagline { get; set; }
- public string title { get; set; }
- public double vote_average { get; set; }
- public int vote_count { get; set; }
- public Casts casts { get; set; }
- public Releases releases { get; set; }
- public Keywords keywords { get; set; }
- }
-
- public class TmdbImageSettings
- {
- public List<string> backdrop_sizes { get; set; }
- public string base_url { get; set; }
- public List<string> poster_sizes { get; set; }
- public List<string> profile_sizes { get; set; }
- }
-
- public class TmdbSettingsResult
- {
- public TmdbImageSettings images { get; set; }
- }
- #endregion
-
- public void Dispose()
- {
- Dispose(true);
- }
- }
-}
diff --git a/MediaBrowser.Controller/Providers/Movies/MovieProviderFromJson.cs b/MediaBrowser.Controller/Providers/Movies/MovieProviderFromJson.cs
deleted file mode 100644
index bdd4f88d2..000000000
--- a/MediaBrowser.Controller/Providers/Movies/MovieProviderFromJson.cs
+++ /dev/null
@@ -1,121 +0,0 @@
-using MediaBrowser.Common.Net;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Entities.Movies;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.Serialization;
-using System;
-using System.IO;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace MediaBrowser.Controller.Providers.Movies
-{
- /// <summary>
- /// Class MovieProviderFromJson
- /// </summary>
- public class MovieProviderFromJson : MovieDbProvider
- {
- public MovieProviderFromJson(ILogManager logManager, IServerConfigurationManager configurationManager, IJsonSerializer jsonSerializer, IHttpClient httpClient, IProviderManager providerManager)
- : base(logManager, configurationManager, jsonSerializer, httpClient, providerManager)
- {
- }
-
- public override bool Supports(BaseItem item)
- {
- if (item.LocationType != LocationType.FileSystem)
- {
- return false;
- }
-
- var trailer = item as Trailer;
-
- if (trailer != null)
- {
- return !trailer.IsLocalTrailer;
- }
-
- return item is Movie || item is BoxSet || item is MusicVideo;
- }
-
- /// <summary>
- /// Gets the priority.
- /// </summary>
- /// <value>The priority.</value>
- public override MetadataProviderPriority Priority
- {
- get { return MetadataProviderPriority.First; }
- }
-
- /// <summary>
- /// Gets a value indicating whether [requires internet].
- /// </summary>
- /// <value><c>true</c> if [requires internet]; otherwise, <c>false</c>.</value>
- public override bool RequiresInternet
- {
- get { return false; }
- }
-
- /// <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, LocalMetaFileName));
- return entry != null ? entry.LastWriteTimeUtc : DateTime.MinValue;
- }
-
- /// <summary>
- /// Needses the refresh internal.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="providerInfo">The provider info.</param>
- /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
- protected override bool NeedsRefreshInternal(BaseItem item, BaseProviderInfo providerInfo)
- {
- if (item.ResolveArgs.ContainsMetaFileByName(AltMetaFileName))
- {
- return false; // don't read our file if 3rd party data exists
- }
-
- if (!item.ResolveArgs.ContainsMetaFileByName(LocalMetaFileName))
- {
- return false; // nothing to read
- }
-
- // Need to re-override to jump over intermediate implementation
- return CompareDate(item) > providerInfo.LastRefreshed;
- }
-
- /// <summary>
- /// Fetches the async.
- /// </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)
- {
- cancellationToken.ThrowIfCancellationRequested();
-
- var entry = item.ResolveArgs.GetMetaFileByPath(Path.Combine(item.MetaLocation, LocalMetaFileName));
- if (entry != null)
- {
- // read in our saved meta and pass to processing function
- var movieData = JsonSerializer.DeserializeFromFile<CompleteMovieData>(entry.FullName);
-
- cancellationToken.ThrowIfCancellationRequested();
-
- ProcessMainInfo(item, movieData);
-
- SetLastRefreshed(item, DateTime.UtcNow);
- return TrueTaskResult;
- }
- return FalseTaskResult;
- }
- }
-}
diff --git a/MediaBrowser.Controller/Providers/Movies/MovieProviderFromXml.cs b/MediaBrowser.Controller/Providers/Movies/MovieProviderFromXml.cs
deleted file mode 100644
index 25fd94138..000000000
--- a/MediaBrowser.Controller/Providers/Movies/MovieProviderFromXml.cs
+++ /dev/null
@@ -1,113 +0,0 @@
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Entities.Movies;
-using System;
-using System.IO;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Model.Logging;
-
-namespace MediaBrowser.Controller.Providers.Movies
-{
- /// <summary>
- /// Class MovieProviderFromXml
- /// </summary>
- public class MovieProviderFromXml : BaseMetadataProvider
- {
- public MovieProviderFromXml(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)
- {
- var trailer = item as Trailer;
-
- if (trailer != null)
- {
- return !trailer.IsLocalTrailer;
- }
-
- return item is Movie || item is BoxSet || item is MusicVideo;
- }
-
- /// <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.ResolveArgs.GetMetaFileByPath(Path.Combine(item.MetaLocation, "movie.xml"));
- 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, "movie.xml"));
-
- if (metadataFile != null)
- {
- var path = metadataFile.FullName;
- var boxset = item as BoxSet;
-
- await XmlParsingResourcePool.WaitAsync(cancellationToken).ConfigureAwait(false);
-
- try
- {
- if (boxset != null)
- {
- new BaseItemXmlParser<BoxSet>(Logger).Fetch(boxset, path, cancellationToken);
- }
- else
- {
- new BaseItemXmlParser<Movie>(Logger).Fetch((Movie)item, path, cancellationToken);
- }
- }
- finally
- {
- XmlParsingResourcePool.Release();
- }
-
- SetLastRefreshed(item, DateTime.UtcNow);
- return true;
- }
-
- return false;
- }
- }
-}
diff --git a/MediaBrowser.Controller/Providers/Movies/OpenMovieDatabaseProvider.cs b/MediaBrowser.Controller/Providers/Movies/OpenMovieDatabaseProvider.cs
deleted file mode 100644
index 855e527bf..000000000
--- a/MediaBrowser.Controller/Providers/Movies/OpenMovieDatabaseProvider.cs
+++ /dev/null
@@ -1,225 +0,0 @@
-using MediaBrowser.Common.Extensions;
-using MediaBrowser.Common.Net;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Entities.Movies;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.Serialization;
-using System;
-using System.Globalization;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace MediaBrowser.Controller.Providers.Movies
-{
- public class OpenMovieDatabaseProvider : BaseMetadataProvider
- {
- private readonly SemaphoreSlim _resourcePool = new SemaphoreSlim(2, 2);
-
- /// <summary>
- /// Gets the json serializer.
- /// </summary>
- /// <value>The json serializer.</value>
- protected IJsonSerializer JsonSerializer { get; private set; }
-
- /// <summary>
- /// Gets the HTTP client.
- /// </summary>
- /// <value>The HTTP client.</value>
- protected IHttpClient HttpClient { get; private set; }
-
- public OpenMovieDatabaseProvider(ILogManager logManager, IServerConfigurationManager configurationManager, IJsonSerializer jsonSerializer, IHttpClient httpClient)
- : base(logManager, configurationManager)
- {
- JsonSerializer = jsonSerializer;
- HttpClient = httpClient;
- }
-
- /// <summary>
- /// Gets the provider version.
- /// </summary>
- /// <value>The provider version.</value>
- protected override string ProviderVersion
- {
- get
- {
- return "6";
- }
- }
-
- /// <summary>
- /// Gets a value indicating whether [requires internet].
- /// </summary>
- /// <value><c>true</c> if [requires internet]; otherwise, <c>false</c>.</value>
- public override bool RequiresInternet
- {
- get
- {
- return true;
- }
- }
-
- /// <summary>
- /// Gets a value indicating whether [refresh on version change].
- /// </summary>
- /// <value><c>true</c> if [refresh on version change]; otherwise, <c>false</c>.</value>
- protected override bool RefreshOnVersionChange
- {
- get
- {
- return true;
- }
- }
-
- /// <summary>
- /// Supports 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)
- {
- var trailer = item as Trailer;
-
- // Don't support local trailers
- if (trailer != null)
- {
- return !trailer.IsLocalTrailer;
- }
-
- return item is Movie || item is MusicVideo;
- }
-
- /// <summary>
- /// Gets the comparison data.
- /// </summary>
- /// <param name="imdbId">The imdb id.</param>
- /// <returns>Guid.</returns>
- private Guid GetComparisonData(string imdbId)
- {
- return string.IsNullOrEmpty(imdbId) ? Guid.Empty : imdbId.GetMD5();
- }
-
- /// <summary>
- /// Gets the priority.
- /// </summary>
- /// <value>The priority.</value>
- public override MetadataProviderPriority Priority
- {
- get
- {
- // Run after moviedb and xml providers
- return MetadataProviderPriority.Last;
- }
- }
-
- /// <summary>
- /// Needses the refresh internal.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="providerInfo">The provider info.</param>
- /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
- protected override bool NeedsRefreshInternal(BaseItem item, BaseProviderInfo providerInfo)
- {
- // Refresh if imdb id has changed
- if (providerInfo.Data != GetComparisonData(item.GetProviderId(MetadataProviders.Imdb)))
- {
- return true;
- }
-
- return base.NeedsRefreshInternal(item, providerInfo);
- }
-
- protected readonly CultureInfo UsCulture = new CultureInfo("en-US");
-
- public override async Task<bool> FetchAsync(BaseItem item, bool force, CancellationToken cancellationToken)
- {
- BaseProviderInfo data;
-
- if (!item.ProviderData.TryGetValue(Id, out data))
- {
- data = new BaseProviderInfo();
- item.ProviderData[Id] = data;
- }
-
- var imdbId = item.GetProviderId(MetadataProviders.Imdb);
-
- if (string.IsNullOrEmpty(imdbId))
- {
- data.Data = GetComparisonData(imdbId);
- data.LastRefreshStatus = ProviderRefreshStatus.Success;
- return true;
- }
-
- var imdbParam = imdbId.StartsWith("tt", StringComparison.OrdinalIgnoreCase) ? imdbId : "tt" + imdbId;
-
- var url = string.Format("http://www.omdbapi.com/?i={0}&tomatoes=true", imdbParam);
-
- using (var stream = await HttpClient.Get(new HttpRequestOptions
- {
- Url = url,
- ResourcePool = _resourcePool,
- CancellationToken = cancellationToken
-
- }).ConfigureAwait(false))
- {
- var result = JsonSerializer.DeserializeFromStream<RootObject>(stream);
-
- int tomatoMeter;
-
- if (!string.IsNullOrEmpty(result.tomatoMeter) && int.TryParse(result.tomatoMeter, NumberStyles.Integer, UsCulture, out tomatoMeter))
- {
- item.CriticRating = tomatoMeter;
- }
-
- if (!string.IsNullOrEmpty(result.tomatoConsensus)
- && !string.Equals(result.tomatoConsensus, "n/a", StringComparison.OrdinalIgnoreCase)
- && !string.Equals(result.tomatoConsensus, "No consensus yet.", StringComparison.OrdinalIgnoreCase))
- {
- item.CriticRatingSummary = result.tomatoConsensus;
- }
- }
-
- data.Data = GetComparisonData(item.GetProviderId(MetadataProviders.Imdb));
- data.LastRefreshStatus = ProviderRefreshStatus.Success;
- SetLastRefreshed(item, DateTime.UtcNow);
-
- return true;
- }
-
-
- protected class RootObject
- {
- public string Title { get; set; }
- public string Year { get; set; }
- public string Rated { get; set; }
- public string Released { get; set; }
- public string Runtime { get; set; }
- public string Genre { get; set; }
- public string Director { get; set; }
- public string Writer { get; set; }
- public string Actors { get; set; }
- public string Plot { get; set; }
- public string Poster { get; set; }
- public string imdbRating { get; set; }
- public string imdbVotes { get; set; }
- public string imdbID { get; set; }
- public string Type { get; set; }
- public string tomatoMeter { get; set; }
- public string tomatoImage { get; set; }
- public string tomatoRating { get; set; }
- public string tomatoReviews { get; set; }
- public string tomatoFresh { get; set; }
- public string tomatoRotten { get; set; }
- public string tomatoConsensus { get; set; }
- public string tomatoUserMeter { get; set; }
- public string tomatoUserRating { get; set; }
- public string tomatoUserReviews { get; set; }
- public string DVD { get; set; }
- public string BoxOffice { get; set; }
- public string Production { get; set; }
- public string Website { get; set; }
- public string Response { get; set; }
- }
- }
-}
diff --git a/MediaBrowser.Controller/Providers/Movies/PersonProviderFromJson.cs b/MediaBrowser.Controller/Providers/Movies/PersonProviderFromJson.cs
deleted file mode 100644
index da53e316e..000000000
--- a/MediaBrowser.Controller/Providers/Movies/PersonProviderFromJson.cs
+++ /dev/null
@@ -1,114 +0,0 @@
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.Serialization;
-using System;
-using System.IO;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace MediaBrowser.Controller.Providers.Movies
-{
- /// <summary>
- /// Class PersonProviderFromJson
- /// </summary>
- class PersonProviderFromJson : TmdbPersonProvider
- {
- public PersonProviderFromJson(IJsonSerializer jsonSerializer, ILogManager logManager, IServerConfigurationManager configurationManager, IProviderManager providerManager)
- : base(jsonSerializer, logManager, configurationManager, providerManager)
- {
- }
-
- /// <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 Person;
- }
-
- /// <summary>
- /// Gets a value indicating whether [requires internet].
- /// </summary>
- /// <value><c>true</c> if [requires internet]; otherwise, <c>false</c>.</value>
- public override bool RequiresInternet
- {
- get
- {
- return false;
- }
- }
-
- // Need to re-override to jump over intermediate implementation
- /// <summary>
- /// Needses the refresh internal.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="providerInfo">The provider info.</param>
- /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
- protected override bool NeedsRefreshInternal(BaseItem item, BaseProviderInfo providerInfo)
- {
- if (!item.ResolveArgs.ContainsMetaFileByName(MetaFileName))
- {
- return false;
- }
-
- 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,MetaFileName));
- return entry != null ? entry.LastWriteTimeUtc : DateTime.MinValue;
- }
-
- /// <summary>
- /// Gets the priority.
- /// </summary>
- /// <value>The priority.</value>
- public override MetadataProviderPriority Priority
- {
- get
- {
- return MetadataProviderPriority.Third;
- }
- }
-
- /// <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)
- {
- cancellationToken.ThrowIfCancellationRequested();
-
- try
- {
- var personInfo = JsonSerializer.DeserializeFromFile<PersonResult>(Path.Combine(item.MetaLocation, MetaFileName));
-
- cancellationToken.ThrowIfCancellationRequested();
-
- ProcessInfo((Person)item, personInfo);
-
- SetLastRefreshed(item, DateTime.UtcNow);
- return TrueTaskResult;
- }
- catch (FileNotFoundException)
- {
- // This is okay - just means we force refreshed and there isn't a json file
- return FalseTaskResult;
- }
- }
- }
-}
diff --git a/MediaBrowser.Controller/Providers/Movies/TmdbPersonProvider.cs b/MediaBrowser.Controller/Providers/Movies/TmdbPersonProvider.cs
deleted file mode 100644
index dd9d8353c..000000000
--- a/MediaBrowser.Controller/Providers/Movies/TmdbPersonProvider.cs
+++ /dev/null
@@ -1,435 +0,0 @@
-using MediaBrowser.Common.Net;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.Serialization;
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.IO;
-using System.Linq;
-using System.Net;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace MediaBrowser.Controller.Providers.Movies
-{
- /// <summary>
- /// Class TmdbPersonProvider
- /// </summary>
- public class TmdbPersonProvider : BaseMetadataProvider
- {
- /// <summary>
- /// The meta file name
- /// </summary>
- protected const string MetaFileName = "tmdb3.json";
-
- protected readonly IProviderManager ProviderManager;
-
- public TmdbPersonProvider(IJsonSerializer jsonSerializer, ILogManager logManager, IServerConfigurationManager configurationManager, IProviderManager providerManager)
- : base(logManager, configurationManager)
- {
- if (jsonSerializer == null)
- {
- throw new ArgumentNullException("jsonSerializer");
- }
- JsonSerializer = jsonSerializer;
- ProviderManager = providerManager;
- }
-
- /// <summary>
- /// Gets the json serializer.
- /// </summary>
- /// <value>The json serializer.</value>
- protected IJsonSerializer JsonSerializer { get; private set; }
-
- /// <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 Person;
- }
-
- protected override bool RefreshOnVersionChange
- {
- get
- {
- return true;
- }
- }
-
- protected override string ProviderVersion
- {
- get
- {
- return "2";
- }
- }
-
- /// <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 async Task<bool> FetchAsync(BaseItem item, bool force, CancellationToken cancellationToken)
- {
- cancellationToken.ThrowIfCancellationRequested();
-
- var person = (Person)item;
-
- var id = person.GetProviderId(MetadataProviders.Tmdb);
-
- // We don't already have an Id, need to fetch it
- if (string.IsNullOrEmpty(id))
- {
- id = await GetTmdbId(item, cancellationToken).ConfigureAwait(false);
- }
-
- cancellationToken.ThrowIfCancellationRequested();
-
- if (!string.IsNullOrEmpty(id))
- {
- await FetchInfo(person, id, cancellationToken).ConfigureAwait(false);
- }
- else
- {
- Logger.Debug("TmdbPersonProvider Unable to obtain id for " + item.Name);
- }
-
- SetLastRefreshed(item, DateTime.UtcNow);
- return true;
- }
-
- /// <summary>
- /// Gets the priority.
- /// </summary>
- /// <value>The priority.</value>
- public override MetadataProviderPriority Priority
- {
- get { return MetadataProviderPriority.Second; }
- }
-
- /// <summary>
- /// Gets a value indicating whether [requires internet].
- /// </summary>
- /// <value><c>true</c> if [requires internet]; otherwise, <c>false</c>.</value>
- public override bool RequiresInternet
- {
- get
- {
- return true;
- }
- }
-
- protected readonly CultureInfo UsCulture = new CultureInfo("en-US");
-
- /// <summary>
- /// Gets the TMDB id.
- /// </summary>
- /// <param name="person">The person.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task{System.String}.</returns>
- private async Task<string> GetTmdbId(BaseItem person, CancellationToken cancellationToken)
- {
- string url = string.Format(@"http://api.themoviedb.org/3/search/person?api_key={1}&query={0}", WebUtility.UrlEncode(person.Name), MovieDbProvider.ApiKey);
- PersonSearchResults searchResult = null;
-
- using (Stream json = await MovieDbProvider.Current.GetMovieDbResponse(new HttpRequestOptions
- {
- Url = url,
- CancellationToken = cancellationToken,
- AcceptHeader = MovieDbProvider.AcceptHeader
-
- }).ConfigureAwait(false))
- {
- searchResult = JsonSerializer.DeserializeFromStream<PersonSearchResults>(json);
- }
-
- return searchResult != null && searchResult.Total_Results > 0 ? searchResult.Results[0].Id.ToString(UsCulture) : null;
- }
-
- /// <summary>
- /// Fetches the info.
- /// </summary>
- /// <param name="person">The person.</param>
- /// <param name="id">The id.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- private async Task FetchInfo(Person person, string id, CancellationToken cancellationToken)
- {
- string url = string.Format(@"http://api.themoviedb.org/3/person/{1}?api_key={0}&append_to_response=credits,images", MovieDbProvider.ApiKey, id);
- PersonResult searchResult = null;
-
- using (var json = await MovieDbProvider.Current.GetMovieDbResponse(new HttpRequestOptions
- {
- Url = url,
- CancellationToken = cancellationToken,
- AcceptHeader = MovieDbProvider.AcceptHeader
-
- }).ConfigureAwait(false))
- {
- searchResult = JsonSerializer.DeserializeFromStream<PersonResult>(json);
- }
-
- cancellationToken.ThrowIfCancellationRequested();
-
- if (searchResult != null)
- {
- ProcessInfo(person, searchResult);
-
- //save locally
- var memoryStream = new MemoryStream();
-
- JsonSerializer.SerializeToStream(searchResult, memoryStream);
-
- await ProviderManager.SaveToLibraryFilesystem(person, Path.Combine(person.MetaLocation, MetaFileName), memoryStream, cancellationToken);
-
- Logger.Debug("TmdbPersonProvider downloaded and saved information for {0}", person.Name);
-
- await FetchImages(person, searchResult.images, cancellationToken).ConfigureAwait(false);
- }
- }
-
- /// <summary>
- /// Processes the info.
- /// </summary>
- /// <param name="person">The person.</param>
- /// <param name="searchResult">The search result.</param>
- protected void ProcessInfo(Person person, PersonResult searchResult)
- {
- person.Overview = searchResult.biography;
-
- DateTime date;
-
- if (DateTime.TryParseExact(searchResult.birthday, "yyyy-MM-dd", new CultureInfo("en-US"), DateTimeStyles.None, out date))
- {
- person.PremiereDate = date.ToUniversalTime();
- }
-
- if (DateTime.TryParseExact(searchResult.deathday, "yyyy-MM-dd", new CultureInfo("en-US"), DateTimeStyles.None, out date))
- {
- person.EndDate = date.ToUniversalTime();
- }
-
- if (!string.IsNullOrEmpty(searchResult.homepage))
- {
- person.HomePageUrl = searchResult.homepage;
- }
-
- if (!string.IsNullOrEmpty(searchResult.place_of_birth))
- {
- person.AddProductionLocation(searchResult.place_of_birth);
- }
-
- person.SetProviderId(MetadataProviders.Tmdb, searchResult.id.ToString(UsCulture));
- }
-
- /// <summary>
- /// Fetches the images.
- /// </summary>
- /// <param name="person">The person.</param>
- /// <param name="searchResult">The search result.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- private async Task FetchImages(Person person, Images searchResult, CancellationToken cancellationToken)
- {
- if (searchResult != null && searchResult.profiles.Count > 0)
- {
- //get our language
- var profile =
- searchResult.profiles.FirstOrDefault(
- p =>
- !string.IsNullOrEmpty(GetIso639(p)) &&
- GetIso639(p).Equals(ConfigurationManager.Configuration.PreferredMetadataLanguage,
- StringComparison.OrdinalIgnoreCase));
- if (profile == null)
- {
- //didn't find our language - try first null one
- profile =
- searchResult.profiles.FirstOrDefault(
- p =>
- !string.IsNullOrEmpty(GetIso639(p)) &&
- GetIso639(p).Equals(ConfigurationManager.Configuration.PreferredMetadataLanguage,
- StringComparison.OrdinalIgnoreCase));
-
- }
- if (profile == null)
- {
- //still nothing - just get first one
- profile = searchResult.profiles[0];
- }
- if (profile != null && !person.HasImage(ImageType.Primary))
- {
- var tmdbSettings = await MovieDbProvider.Current.GetTmdbSettings(cancellationToken).ConfigureAwait(false);
-
- var img = await DownloadAndSaveImage(person, tmdbSettings.images.base_url + ConfigurationManager.Configuration.TmdbFetchedProfileSize + profile.file_path,
- "folder" + Path.GetExtension(profile.file_path), cancellationToken).ConfigureAwait(false);
-
- if (!string.IsNullOrEmpty(img))
- {
- person.PrimaryImagePath = img;
- }
- }
- }
- }
-
- private string GetIso639(Profile p)
- {
- return p.iso_639_1 == null ? string.Empty : p.iso_639_1.ToString();
- }
-
- /// <summary>
- /// Downloads the and save image.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="source">The source.</param>
- /// <param name="targetName">Name of the target.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task{System.String}.</returns>
- private async Task<string> DownloadAndSaveImage(BaseItem item, string source, string targetName, CancellationToken cancellationToken)
- {
- if (source == null) return null;
-
- //download and save locally (if not already there)
- var localPath = Path.Combine(item.MetaLocation, targetName);
-
- using (var sourceStream = await MovieDbProvider.Current.GetMovieDbResponse(new HttpRequestOptions
- {
- Url = source,
- CancellationToken = cancellationToken
-
- }).ConfigureAwait(false))
- {
- await ProviderManager.SaveToLibraryFilesystem(item, localPath, sourceStream, cancellationToken).ConfigureAwait(false);
-
- Logger.Debug("TmdbPersonProvider downloaded and saved image for {0}", item.Name);
- }
-
- return localPath;
- }
-
- #region Result Objects
- /// <summary>
- /// Class PersonSearchResult
- /// </summary>
- protected class PersonSearchResult
- {
- /// <summary>
- /// Gets or sets a value indicating whether this <see cref="PersonSearchResult" /> is adult.
- /// </summary>
- /// <value><c>true</c> if adult; otherwise, <c>false</c>.</value>
- public bool Adult { get; set; }
- /// <summary>
- /// Gets or sets the id.
- /// </summary>
- /// <value>The id.</value>
- public int Id { get; set; }
- /// <summary>
- /// Gets or sets the name.
- /// </summary>
- /// <value>The name.</value>
- public string Name { get; set; }
- /// <summary>
- /// Gets or sets the profile_ path.
- /// </summary>
- /// <value>The profile_ path.</value>
- public string Profile_Path { get; set; }
- }
-
- /// <summary>
- /// Class PersonSearchResults
- /// </summary>
- protected class PersonSearchResults
- {
- /// <summary>
- /// Gets or sets the page.
- /// </summary>
- /// <value>The page.</value>
- public int Page { get; set; }
- /// <summary>
- /// Gets or sets the results.
- /// </summary>
- /// <value>The results.</value>
- public List<PersonSearchResult> Results { get; set; }
- /// <summary>
- /// Gets or sets the total_ pages.
- /// </summary>
- /// <value>The total_ pages.</value>
- public int Total_Pages { get; set; }
- /// <summary>
- /// Gets or sets the total_ results.
- /// </summary>
- /// <value>The total_ results.</value>
- public int Total_Results { get; set; }
- }
-
- protected class Cast
- {
- public int id { get; set; }
- public string title { get; set; }
- public string character { get; set; }
- public string original_title { get; set; }
- public string poster_path { get; set; }
- public string release_date { get; set; }
- public bool adult { get; set; }
- }
-
- protected class Crew
- {
- public int id { get; set; }
- public string title { get; set; }
- public string original_title { get; set; }
- public string department { get; set; }
- public string job { get; set; }
- public string poster_path { get; set; }
- public string release_date { get; set; }
- public bool adult { get; set; }
- }
-
- protected class Credits
- {
- public List<Cast> cast { get; set; }
- public List<Crew> crew { get; set; }
- }
-
- protected class Profile
- {
- public string file_path { get; set; }
- public int width { get; set; }
- public int height { get; set; }
- public object iso_639_1 { get; set; }
- public double aspect_ratio { get; set; }
- }
-
- protected class Images
- {
- public List<Profile> profiles { get; set; }
- }
-
- protected class PersonResult
- {
- public bool adult { get; set; }
- public List<object> also_known_as { get; set; }
- public string biography { get; set; }
- public string birthday { get; set; }
- public string deathday { get; set; }
- public string homepage { get; set; }
- public int id { get; set; }
- public string imdb_id { get; set; }
- public string name { get; set; }
- public string place_of_birth { get; set; }
- public double popularity { get; set; }
- public string profile_path { get; set; }
- public Credits credits { get; set; }
- public Images images { get; set; }
- }
-
- #endregion
- }
-}
diff --git a/MediaBrowser.Controller/Providers/Music/ArtistsPostScanTask.cs b/MediaBrowser.Controller/Providers/Music/ArtistsPostScanTask.cs
deleted file mode 100644
index 67bb35b63..000000000
--- a/MediaBrowser.Controller/Providers/Music/ArtistsPostScanTask.cs
+++ /dev/null
@@ -1,132 +0,0 @@
-using MediaBrowser.Common.Progress;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Entities.Audio;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Model.Entities;
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace MediaBrowser.Controller.Providers.Music
-{
- /// <summary>
- /// Class ArtistsPostScanTask
- /// </summary>
- public class ArtistsPostScanTask : ILibraryPostScanTask
- {
- /// <summary>
- /// The _library manager
- /// </summary>
- private readonly ILibraryManager _libraryManager;
-
- /// <summary>
- /// Initializes a new instance of the <see cref="ArtistsPostScanTask"/> class.
- /// </summary>
- /// <param name="libraryManager">The library manager.</param>
- public ArtistsPostScanTask(ILibraryManager libraryManager)
- {
- _libraryManager = libraryManager;
- }
-
- /// <summary>
- /// Runs the specified progress.
- /// </summary>
- /// <param name="progress">The progress.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- public async Task Run(IProgress<double> progress, CancellationToken cancellationToken)
- {
- var allItems = _libraryManager.RootFolder.RecursiveChildren.ToList();
-
- var allArtists = await GetAllArtists(allItems).ConfigureAwait(false);
-
- progress.Report(10);
-
- var allMusicArtists = allItems.OfType<MusicArtist>().ToList();
-
- var numComplete = 0;
-
- foreach (var artist in allArtists)
- {
- var musicArtist = FindMusicArtist(artist, allMusicArtists);
-
- if (musicArtist != null)
- {
- artist.Images = new Dictionary<ImageType, string>(musicArtist.Images);
-
- artist.BackdropImagePaths = musicArtist.BackdropImagePaths.ToList();
- artist.ScreenshotImagePaths = musicArtist.ScreenshotImagePaths.ToList();
- artist.SetProviderId(MetadataProviders.Musicbrainz, musicArtist.GetProviderId(MetadataProviders.Musicbrainz));
- }
-
- numComplete++;
- double percent = numComplete;
- percent /= allArtists.Length;
- percent *= 5;
-
- progress.Report(10 + percent);
- }
-
- var innerProgress = new ActionableProgress<double>();
-
- innerProgress.RegisterAction(pct => progress.Report(15 + pct * .85));
-
- await _libraryManager.ValidateArtists(cancellationToken, innerProgress).ConfigureAwait(false);
- }
-
- /// <summary>
- /// Gets all artists.
- /// </summary>
- /// <param name="allItems">All items.</param>
- /// <returns>Task{Artist[]}.</returns>
- private Task<Artist[]> GetAllArtists(IEnumerable<BaseItem> allItems)
- {
- var itemsList = allItems.OfType<Audio>().ToList();
-
- var tasks = itemsList
- .SelectMany(i =>
- {
- var list = new List<string>();
-
- if (!string.IsNullOrEmpty(i.AlbumArtist))
- {
- list.Add(i.AlbumArtist);
- }
- if (!string.IsNullOrEmpty(i.Artist))
- {
- list.Add(i.Artist);
- }
-
- return list;
- })
- .Distinct(StringComparer.OrdinalIgnoreCase)
- .Select(i => _libraryManager.GetArtist(i));
-
- return Task.WhenAll(tasks);
- }
-
- /// <summary>
- /// Finds the music artist.
- /// </summary>
- /// <param name="artist">The artist.</param>
- /// <param name="allMusicArtists">All music artists.</param>
- /// <returns>MusicArtist.</returns>
- private static MusicArtist FindMusicArtist(Artist artist, IEnumerable<MusicArtist> allMusicArtists)
- {
- var musicBrainzId = artist.GetProviderId(MetadataProviders.Musicbrainz);
-
- return allMusicArtists.FirstOrDefault(i =>
- {
- if (!string.IsNullOrWhiteSpace(musicBrainzId) && string.Equals(musicBrainzId, i.GetProviderId(MetadataProviders.Musicbrainz), StringComparison.OrdinalIgnoreCase))
- {
- return true;
- }
-
- return string.Compare(i.Name, artist.Name, CultureInfo.CurrentCulture, CompareOptions.IgnoreNonSpace | CompareOptions.IgnoreCase | CompareOptions.IgnoreSymbols) == 0;
- });
- }
- }
-}
diff --git a/MediaBrowser.Controller/Providers/Music/FanArtAlbumProvider.cs b/MediaBrowser.Controller/Providers/Music/FanArtAlbumProvider.cs
deleted file mode 100644
index 48a114704..000000000
--- a/MediaBrowser.Controller/Providers/Music/FanArtAlbumProvider.cs
+++ /dev/null
@@ -1,307 +0,0 @@
-using MediaBrowser.Common.Extensions;
-using MediaBrowser.Common.Net;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Entities.Audio;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Logging;
-using System;
-using System.IO;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-using System.Xml;
-
-namespace MediaBrowser.Controller.Providers.Music
-{
- /// <summary>
- /// Class FanArtAlbumProvider
- /// </summary>
- public class FanArtAlbumProvider : FanartBaseProvider
- {
- /// <summary>
- /// The _provider manager
- /// </summary>
- private readonly IProviderManager _providerManager;
-
- /// <summary>
- /// The _music brainz resource pool
- /// </summary>
- private readonly SemaphoreSlim _musicBrainzResourcePool = new SemaphoreSlim(1, 1);
-
- /// <summary>
- /// Gets the HTTP client.
- /// </summary>
- /// <value>The HTTP client.</value>
- protected IHttpClient HttpClient { get; private set; }
-
- internal static FanArtAlbumProvider Current { get; private set; }
-
- /// <summary>
- /// Initializes a new instance of the <see cref="FanArtAlbumProvider"/> class.
- /// </summary>
- /// <param name="httpClient">The HTTP client.</param>
- /// <param name="logManager">The log manager.</param>
- /// <param name="configurationManager">The configuration manager.</param>
- /// <param name="providerManager">The provider manager.</param>
- public FanArtAlbumProvider(IHttpClient httpClient, ILogManager logManager, IServerConfigurationManager configurationManager, IProviderManager providerManager)
- : base(logManager, configurationManager)
- {
- _providerManager = providerManager;
- HttpClient = httpClient;
-
- Current = this;
- }
-
- /// <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 MusicAlbum;
- }
-
- /// <summary>
- /// Gets a value indicating whether [refresh on version change].
- /// </summary>
- /// <value><c>true</c> if [refresh on version change]; otherwise, <c>false</c>.</value>
- protected override bool RefreshOnVersionChange
- {
- get
- {
- return true;
- }
- }
-
- /// <summary>
- /// Gets the provider version.
- /// </summary>
- /// <value>The provider version.</value>
- protected override string ProviderVersion
- {
- get
- {
- return "17";
- }
- }
-
- /// <summary>
- /// Needses the refresh internal.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="providerInfo">The provider info.</param>
- /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
- protected override bool NeedsRefreshInternal(BaseItem item, BaseProviderInfo providerInfo)
- {
- if (string.IsNullOrEmpty(item.GetProviderId(MetadataProviders.Musicbrainz)))
- {
- return false;
- }
-
- if (!ConfigurationManager.Configuration.DownloadMusicAlbumImages.Disc &&
- !ConfigurationManager.Configuration.DownloadMusicAlbumImages.Primary)
- {
- return false;
- }
-
- var comparisonData = Guid.Empty;
-
- var artistMusicBrainzId = item.Parent.GetProviderId(MetadataProviders.Musicbrainz);
-
- if (!string.IsNullOrEmpty(artistMusicBrainzId))
- {
- var artistXmlPath = FanArtArtistProvider.GetArtistDataPath(ConfigurationManager.CommonApplicationPaths, artistMusicBrainzId);
- artistXmlPath = Path.Combine(artistXmlPath, "fanart.xml");
-
- comparisonData = GetComparisonData(new FileInfo(artistXmlPath));
- }
-
- // Refresh anytime the parent mbz id changes
- if (providerInfo.Data != comparisonData)
- {
- return true;
- }
-
- return base.NeedsRefreshInternal(item, providerInfo);
- }
-
- /// <summary>
- /// Gets the comparison data.
- /// </summary>
- /// <returns>Guid.</returns>
- private Guid GetComparisonData(FileInfo artistXmlFileInfo)
- {
- return artistXmlFileInfo.Exists ? (artistXmlFileInfo.FullName + artistXmlFileInfo.LastWriteTimeUtc.Ticks).GetMD5() : Guid.Empty;
- }
-
- /// <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 async Task<bool> FetchAsync(BaseItem item, bool force, CancellationToken cancellationToken)
- {
- cancellationToken.ThrowIfCancellationRequested();
-
- var artistMusicBrainzId = item.Parent.GetProviderId(MetadataProviders.Musicbrainz);
-
- BaseProviderInfo data;
-
- if (!item.ProviderData.TryGetValue(Id, out data))
- {
- data = new BaseProviderInfo();
- item.ProviderData[Id] = data;
- }
-
- var comparisonData = Guid.Empty;
-
- if (!string.IsNullOrEmpty(artistMusicBrainzId))
- {
- var artistXmlPath = FanArtArtistProvider.GetArtistDataPath(ConfigurationManager.CommonApplicationPaths, artistMusicBrainzId);
- artistXmlPath = Path.Combine(artistXmlPath, "fanart.xml");
-
- var artistXmlFileInfo = new FileInfo(artistXmlPath);
-
- comparisonData = GetComparisonData(artistXmlFileInfo);
-
- if (artistXmlFileInfo.Exists)
- {
- var album = (MusicAlbum)item;
-
- var releaseEntryId = item.GetProviderId(MetadataProviders.Musicbrainz);
-
- // Fanart uses the release group id so we'll have to get that now using the release entry id
- if (string.IsNullOrEmpty(album.MusicBrainzReleaseGroupId))
- {
- album.MusicBrainzReleaseGroupId = await GetReleaseGroupId(releaseEntryId, cancellationToken).ConfigureAwait(false);
- }
-
- var doc = new XmlDocument();
-
- doc.Load(artistXmlPath);
-
- cancellationToken.ThrowIfCancellationRequested();
-
- if (ConfigurationManager.Configuration.DownloadMusicAlbumImages.Disc && !item.HasImage(ImageType.Disc))
- {
- // Try try with the release entry Id, if that doesn't produce anything try the release group id
- var node = doc.SelectSingleNode("//fanart/music/albums/album[@id=\"" + releaseEntryId + "\"]/cdart/@url");
-
- if (node == null && !string.IsNullOrEmpty(album.MusicBrainzReleaseGroupId))
- {
- node = doc.SelectSingleNode("//fanart/music/albums/album[@id=\"" + album.MusicBrainzReleaseGroupId + "\"]/cdart/@url");
- }
-
- var path = node != null ? node.Value : null;
-
- if (!string.IsNullOrEmpty(path))
- {
- item.SetImage(ImageType.Disc, await _providerManager.DownloadAndSaveImage(item, path, DiscFile, ConfigurationManager.Configuration.SaveLocalMeta, FanArtResourcePool, cancellationToken).ConfigureAwait(false));
- }
- }
-
- if (ConfigurationManager.Configuration.DownloadMusicAlbumImages.Primary && !item.HasImage(ImageType.Primary))
- {
- // Try try with the release entry Id, if that doesn't produce anything try the release group id
- var node = doc.SelectSingleNode("//fanart/music/albums/album[@id=\"" + releaseEntryId + "\"]/albumcover/@url");
-
- if (node == null && !string.IsNullOrEmpty(album.MusicBrainzReleaseGroupId))
- {
- node = doc.SelectSingleNode("//fanart/music/albums/album[@id=\"" + album.MusicBrainzReleaseGroupId + "\"]/albumcover/@url");
- }
-
- var path = node != null ? node.Value : null;
-
- if (!string.IsNullOrEmpty(path))
- {
- item.SetImage(ImageType.Primary, await _providerManager.DownloadAndSaveImage(item, path, PrimaryFile, ConfigurationManager.Configuration.SaveLocalMeta, FanArtResourcePool, cancellationToken).ConfigureAwait(false));
- }
- }
- }
-
- }
-
- data.Data = comparisonData;
- SetLastRefreshed(item, DateTime.UtcNow);
-
- return true;
- }
-
- /// <summary>
- /// The _last music brainz request
- /// </summary>
- private DateTime _lastRequestDate = DateTime.MinValue;
-
- /// <summary>
- /// Gets the music brainz response.
- /// </summary>
- /// <param name="url">The URL.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task{XmlDocument}.</returns>
- internal async Task<XmlDocument> GetMusicBrainzResponse(string url, CancellationToken cancellationToken)
- {
- await _musicBrainzResourcePool.WaitAsync(cancellationToken).ConfigureAwait(false);
-
- try
- {
- var diff = 1500 - (DateTime.Now - _lastRequestDate).TotalMilliseconds;
-
- // MusicBrainz is extremely adamant about limiting to one request per second
-
- if (diff > 0)
- {
- await Task.Delay(Convert.ToInt32(diff), cancellationToken).ConfigureAwait(false);
- }
-
- _lastRequestDate = DateTime.Now;
-
- var doc = new XmlDocument();
-
- using (var xml = await HttpClient.Get(new HttpRequestOptions
- {
- Url = url,
- CancellationToken = cancellationToken,
- UserAgent = Environment.MachineName
-
- }).ConfigureAwait(false))
- {
- using (var oReader = new StreamReader(xml, Encoding.UTF8))
- {
- doc.Load(oReader);
- }
- }
-
- return doc;
- }
- finally
- {
- _lastRequestDate = DateTime.Now;
-
- _musicBrainzResourcePool.Release();
- }
- }
-
- /// <summary>
- /// Gets the release group id internal.
- /// </summary>
- /// <param name="releaseEntryId">The release entry id.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task{System.String}.</returns>
- private async Task<string> GetReleaseGroupId(string releaseEntryId, CancellationToken cancellationToken)
- {
- var url = string.Format("http://www.musicbrainz.org/ws/2/release-group/?query=reid:{0}", releaseEntryId);
-
- var doc = await GetMusicBrainzResponse(url, cancellationToken).ConfigureAwait(false);
-
- var ns = new XmlNamespaceManager(doc.NameTable);
- ns.AddNamespace("mb", "http://musicbrainz.org/ns/mmd-2.0#");
- var node = doc.SelectSingleNode("//mb:release-group-list/mb:release-group/@id", ns);
-
- return node != null ? node.Value : null;
- }
- }
-}
diff --git a/MediaBrowser.Controller/Providers/Music/FanArtArtistByNameProvider.cs b/MediaBrowser.Controller/Providers/Music/FanArtArtistByNameProvider.cs
deleted file mode 100644
index 58200a458..000000000
--- a/MediaBrowser.Controller/Providers/Music/FanArtArtistByNameProvider.cs
+++ /dev/null
@@ -1,48 +0,0 @@
-using MediaBrowser.Common.Net;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Entities.Audio;
-using MediaBrowser.Model.Logging;
-
-namespace MediaBrowser.Controller.Providers.Music
-{
- /// <summary>
- /// Class FanArtArtistByNameProvider
- /// </summary>
- public class FanArtArtistByNameProvider : FanArtArtistProvider
- {
- /// <summary>
- /// Initializes a new instance of the <see cref="FanArtArtistByNameProvider" /> class.
- /// </summary>
- /// <param name="httpClient">The HTTP client.</param>
- /// <param name="logManager">The log manager.</param>
- /// <param name="configurationManager">The configuration manager.</param>
- /// <param name="providerManager">The provider manager.</param>
- public FanArtArtistByNameProvider(IHttpClient httpClient, ILogManager logManager, IServerConfigurationManager configurationManager, IProviderManager providerManager)
- : base(httpClient, logManager, configurationManager, providerManager)
- {
- }
-
- /// <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;
- }
-
- /// <summary>
- /// Gets a value indicating whether [save local meta].
- /// </summary>
- /// <value><c>true</c> if [save local meta]; otherwise, <c>false</c>.</value>
- protected override bool SaveLocalMeta
- {
- get
- {
- return true;
- }
- }
- }
-}
diff --git a/MediaBrowser.Controller/Providers/Music/FanArtArtistProvider.cs b/MediaBrowser.Controller/Providers/Music/FanArtArtistProvider.cs
deleted file mode 100644
index fc9500b40..000000000
--- a/MediaBrowser.Controller/Providers/Music/FanArtArtistProvider.cs
+++ /dev/null
@@ -1,378 +0,0 @@
-using MediaBrowser.Common.Configuration;
-using MediaBrowser.Common.Extensions;
-using MediaBrowser.Common.IO;
-using MediaBrowser.Common.Net;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Entities.Audio;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Logging;
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.IO;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-using System.Xml;
-
-namespace MediaBrowser.Controller.Providers.Music
-{
- /// <summary>
- /// Class FanArtArtistProvider
- /// </summary>
- public class FanArtArtistProvider : FanartBaseProvider
- {
- /// <summary>
- /// Gets the HTTP client.
- /// </summary>
- /// <value>The HTTP client.</value>
- protected IHttpClient HttpClient { get; private set; }
-
- /// <summary>
- /// The _provider manager
- /// </summary>
- private readonly IProviderManager _providerManager;
-
- internal static FanArtArtistProvider Current;
-
- /// <summary>
- /// Initializes a new instance of the <see cref="FanArtArtistProvider"/> class.
- /// </summary>
- /// <param name="httpClient">The HTTP client.</param>
- /// <param name="logManager">The log manager.</param>
- /// <param name="configurationManager">The configuration manager.</param>
- /// <param name="providerManager">The provider manager.</param>
- /// <exception cref="System.ArgumentNullException">httpClient</exception>
- public FanArtArtistProvider(IHttpClient httpClient, ILogManager logManager, IServerConfigurationManager configurationManager, IProviderManager providerManager)
- : base(logManager, configurationManager)
- {
- if (httpClient == null)
- {
- throw new ArgumentNullException("httpClient");
- }
- HttpClient = httpClient;
- _providerManager = providerManager;
-
- Current = this;
- }
-
- /// <summary>
- /// The fan art base URL
- /// </summary>
- protected string FanArtBaseUrl = "http://api.fanart.tv/webservice/artist/{0}/{1}/xml/all/1/1";
-
- /// <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 MusicArtist;
- }
-
- /// <summary>
- /// Gets a value indicating whether [save local meta].
- /// </summary>
- /// <value><c>true</c> if [save local meta]; otherwise, <c>false</c>.</value>
- protected virtual bool SaveLocalMeta
- {
- get { return ConfigurationManager.Configuration.SaveLocalMeta; }
- }
-
- /// <summary>
- /// Gets a value indicating whether [refresh on version change].
- /// </summary>
- /// <value><c>true</c> if [refresh on version change]; otherwise, <c>false</c>.</value>
- protected override bool RefreshOnVersionChange
- {
- get
- {
- return true;
- }
- }
-
- /// <summary>
- /// Gets the provider version.
- /// </summary>
- /// <value>The provider version.</value>
- protected override string ProviderVersion
- {
- get
- {
- return "7";
- }
- }
-
- /// <summary>
- /// Needses the refresh internal.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="providerInfo">The provider info.</param>
- /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
- protected override bool NeedsRefreshInternal(BaseItem item, BaseProviderInfo providerInfo)
- {
- if (string.IsNullOrEmpty(item.GetProviderId(MetadataProviders.Musicbrainz)))
- {
- return false;
- }
-
- if (!ConfigurationManager.Configuration.DownloadMusicArtistImages.Art &&
- !ConfigurationManager.Configuration.DownloadMusicArtistImages.Backdrops &&
- !ConfigurationManager.Configuration.DownloadMusicArtistImages.Banner &&
- !ConfigurationManager.Configuration.DownloadMusicArtistImages.Logo &&
- !ConfigurationManager.Configuration.DownloadMusicArtistImages.Primary &&
-
- // The fanart album provider depends on xml downloaded here, so honor it's settings too
- !ConfigurationManager.Configuration.DownloadMusicAlbumImages.Disc &&
- !ConfigurationManager.Configuration.DownloadMusicAlbumImages.Primary)
- {
- return false;
- }
-
- if (GetComparisonData(item) != providerInfo.Data)
- {
- return true;
- }
-
- return base.NeedsRefreshInternal(item, providerInfo);
- }
-
- /// <summary>
- /// Gets the comparison data.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <returns>Guid.</returns>
- private Guid GetComparisonData(BaseItem item)
- {
- var musicBrainzId = item.GetProviderId(MetadataProviders.Musicbrainz);
-
- if (!string.IsNullOrEmpty(musicBrainzId))
- {
- // Process images
- var path = GetArtistDataPath(ConfigurationManager.ApplicationPaths, musicBrainzId);
-
- var files = new DirectoryInfo(path)
- .EnumerateFiles("*.xml", SearchOption.TopDirectoryOnly)
- .Select(i => i.FullName + i.LastWriteTimeUtc.Ticks)
- .ToArray();
-
- if (files.Length > 0)
- {
- return string.Join(string.Empty, files).GetMD5();
- }
- }
-
- return Guid.Empty;
- }
-
- /// <summary>
- /// The us culture
- /// </summary>
- protected readonly CultureInfo UsCulture = new CultureInfo("en-US");
-
- /// <summary>
- /// Gets the series data path.
- /// </summary>
- /// <param name="appPaths">The app paths.</param>
- /// <param name="musicBrainzArtistId">The music brainz artist id.</param>
- /// <returns>System.String.</returns>
- internal static string GetArtistDataPath(IApplicationPaths appPaths, string musicBrainzArtistId)
- {
- var seriesDataPath = Path.Combine(GetArtistDataPath(appPaths), musicBrainzArtistId);
-
- if (!Directory.Exists(seriesDataPath))
- {
- Directory.CreateDirectory(seriesDataPath);
- }
-
- return seriesDataPath;
- }
-
- /// <summary>
- /// Gets the series data path.
- /// </summary>
- /// <param name="appPaths">The app paths.</param>
- /// <returns>System.String.</returns>
- internal static string GetArtistDataPath(IApplicationPaths appPaths)
- {
- var dataPath = Path.Combine(appPaths.DataPath, "fanart-music");
-
- if (!Directory.Exists(dataPath))
- {
- Directory.CreateDirectory(dataPath);
- }
-
- return dataPath;
- }
-
- /// <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 async Task<bool> FetchAsync(BaseItem item, bool force, CancellationToken cancellationToken)
- {
- cancellationToken.ThrowIfCancellationRequested();
-
- var musicBrainzId = item.GetProviderId(MetadataProviders.Musicbrainz);
-
- var artistDataPath = GetArtistDataPath(ConfigurationManager.ApplicationPaths, musicBrainzId);
- var xmlPath = Path.Combine(artistDataPath, "fanart.xml");
-
- // Only download the xml if it doesn't already exist. The prescan task will take care of getting updates
- if (!File.Exists(xmlPath))
- {
- await DownloadArtistXml(artistDataPath, musicBrainzId, cancellationToken).ConfigureAwait(false);
- }
-
- if (ConfigurationManager.Configuration.DownloadMusicArtistImages.Art ||
- ConfigurationManager.Configuration.DownloadMusicArtistImages.Backdrops ||
- ConfigurationManager.Configuration.DownloadMusicArtistImages.Banner ||
- ConfigurationManager.Configuration.DownloadMusicArtistImages.Logo ||
- ConfigurationManager.Configuration.DownloadMusicArtistImages.Primary)
- {
- if (File.Exists(xmlPath))
- {
- await FetchFromXml(item, xmlPath, cancellationToken).ConfigureAwait(false);
- }
- }
-
- BaseProviderInfo data;
- if (!item.ProviderData.TryGetValue(Id, out data))
- {
- data = new BaseProviderInfo();
- item.ProviderData[Id] = data;
- }
-
- data.Data = GetComparisonData(item);
-
- SetLastRefreshed(item, DateTime.UtcNow);
- return true;
- }
-
- /// <summary>
- /// Downloads the artist XML.
- /// </summary>
- /// <param name="artistPath">The artist path.</param>
- /// <param name="musicBrainzId">The music brainz id.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task{System.Boolean}.</returns>
- internal async Task DownloadArtistXml(string artistPath, string musicBrainzId, CancellationToken cancellationToken)
- {
- cancellationToken.ThrowIfCancellationRequested();
-
- var url = string.Format(FanArtBaseUrl, ApiKey, musicBrainzId);
-
- var xmlPath = Path.Combine(artistPath, "fanart.xml");
-
- using (var response = await HttpClient.Get(new HttpRequestOptions
- {
- Url = url,
- ResourcePool = FanArtResourcePool,
- CancellationToken = cancellationToken
-
- }).ConfigureAwait(false))
- {
- using (var xmlFileStream = new FileStream(xmlPath, FileMode.Create, FileAccess.Write, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, FileOptions.Asynchronous))
- {
- await response.CopyToAsync(xmlFileStream).ConfigureAwait(false);
- }
- }
- }
-
- /// <summary>
- /// Fetches from XML.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="xmlFilePath">The XML file path.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- private async Task FetchFromXml(BaseItem item, string xmlFilePath, CancellationToken cancellationToken)
- {
- var doc = new XmlDocument();
- doc.Load(xmlFilePath);
-
- cancellationToken.ThrowIfCancellationRequested();
-
- string path;
- var hd = ConfigurationManager.Configuration.DownloadHDFanArt ? "hd" : "";
- if (ConfigurationManager.Configuration.DownloadMusicArtistImages.Logo && !item.HasImage(ImageType.Logo))
- {
- var node =
- doc.SelectSingleNode("//fanart/music/musiclogos/" + hd + "musiclogo/@url") ??
- doc.SelectSingleNode("//fanart/music/musiclogos/musiclogo/@url");
- path = node != null ? node.Value : null;
- if (!string.IsNullOrEmpty(path))
- {
- item.SetImage(ImageType.Logo, await _providerManager.DownloadAndSaveImage(item, path, LogoFile, SaveLocalMeta, FanArtResourcePool, cancellationToken).ConfigureAwait(false));
- }
- }
- cancellationToken.ThrowIfCancellationRequested();
-
- if (ConfigurationManager.Configuration.DownloadMusicArtistImages.Backdrops && item.BackdropImagePaths.Count == 0)
- {
- var nodes = doc.SelectNodes("//fanart/music/artistbackgrounds//@url");
- if (nodes != null)
- {
- var numBackdrops = 0;
- item.BackdropImagePaths = new List<string>();
- foreach (XmlNode node in nodes)
- {
- path = node.Value;
- if (!string.IsNullOrEmpty(path))
- {
- item.BackdropImagePaths.Add(await _providerManager.DownloadAndSaveImage(item, path, ("Backdrop" + (numBackdrops > 0 ? numBackdrops.ToString(UsCulture) : "") + ".jpg"), SaveLocalMeta, FanArtResourcePool, cancellationToken).ConfigureAwait(false));
- numBackdrops++;
- if (numBackdrops >= ConfigurationManager.Configuration.MaxBackdrops) break;
- }
- }
-
- }
-
- }
-
- cancellationToken.ThrowIfCancellationRequested();
-
- if (ConfigurationManager.Configuration.DownloadMusicArtistImages.Art && !item.HasImage(ImageType.Art))
- {
- var node =
- doc.SelectSingleNode("//fanart/music/musicarts/" + hd + "musicart/@url") ??
- doc.SelectSingleNode("//fanart/music/musicarts/musicart/@url");
- path = node != null ? node.Value : null;
- if (!string.IsNullOrEmpty(path))
- {
- item.SetImage(ImageType.Art, await _providerManager.DownloadAndSaveImage(item, path, ArtFile, SaveLocalMeta, FanArtResourcePool, cancellationToken).ConfigureAwait(false));
- }
- }
- cancellationToken.ThrowIfCancellationRequested();
-
- if (ConfigurationManager.Configuration.DownloadMusicArtistImages.Banner && !item.HasImage(ImageType.Banner))
- {
- var node = doc.SelectSingleNode("//fanart/music/musicbanners/" + hd + "musicbanner/@url") ??
- doc.SelectSingleNode("//fanart/music/musicbanners/musicbanner/@url");
- path = node != null ? node.Value : null;
- if (!string.IsNullOrEmpty(path))
- {
- item.SetImage(ImageType.Banner, await _providerManager.DownloadAndSaveImage(item, path, BannerFile, SaveLocalMeta, FanArtResourcePool, cancellationToken).ConfigureAwait(false));
- }
- }
-
- cancellationToken.ThrowIfCancellationRequested();
-
- // Artist thumbs are actually primary images (they are square/portrait)
- if (ConfigurationManager.Configuration.DownloadMusicArtistImages.Primary && !item.HasImage(ImageType.Primary))
- {
- var node = doc.SelectSingleNode("//fanart/music/artistthumbs/artistthumb/@url");
- path = node != null ? node.Value : null;
- if (!string.IsNullOrEmpty(path))
- {
- item.SetImage(ImageType.Primary, await _providerManager.DownloadAndSaveImage(item, path, PrimaryFile, SaveLocalMeta, FanArtResourcePool, cancellationToken).ConfigureAwait(false));
- }
- }
- }
- }
-}
diff --git a/MediaBrowser.Controller/Providers/Music/FanArtUpdatesPrescanTask.cs b/MediaBrowser.Controller/Providers/Music/FanArtUpdatesPrescanTask.cs
deleted file mode 100644
index 8c15bd18a..000000000
--- a/MediaBrowser.Controller/Providers/Music/FanArtUpdatesPrescanTask.cs
+++ /dev/null
@@ -1,206 +0,0 @@
-using MediaBrowser.Common.Net;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.Net;
-using MediaBrowser.Model.Serialization;
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.IO;
-using System.Linq;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace MediaBrowser.Controller.Providers.Music
-{
- class FanArtUpdatesPrescanTask : ILibraryPrescanTask
- {
- private const string UpdatesUrl = "http://api.fanart.tv/webservice/newmusic/{0}/{1}/";
-
- /// <summary>
- /// The _HTTP client
- /// </summary>
- private readonly IHttpClient _httpClient;
- /// <summary>
- /// The _logger
- /// </summary>
- private readonly ILogger _logger;
- /// <summary>
- /// The _config
- /// </summary>
- private readonly IServerConfigurationManager _config;
- private readonly IJsonSerializer _jsonSerializer;
-
- private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
-
- public FanArtUpdatesPrescanTask(IJsonSerializer jsonSerializer, IServerConfigurationManager config, ILogger logger, IHttpClient httpClient)
- {
- _jsonSerializer = jsonSerializer;
- _config = config;
- _logger = logger;
- _httpClient = httpClient;
- }
-
- /// <summary>
- /// Runs the specified progress.
- /// </summary>
- /// <param name="progress">The progress.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- public async Task Run(IProgress<double> progress, CancellationToken cancellationToken)
- {
- if (!_config.Configuration.EnableInternetProviders)
- {
- progress.Report(100);
- return;
- }
-
- var path = FanArtArtistProvider.GetArtistDataPath(_config.CommonApplicationPaths);
-
- var timestampFile = Path.Combine(path, "time.txt");
-
- var timestampFileInfo = new FileInfo(timestampFile);
-
- // Don't check for tvdb updates anymore frequently than 24 hours
- if (timestampFileInfo.Exists && (DateTime.UtcNow - timestampFileInfo.LastWriteTimeUtc).TotalDays < 1)
- {
- return;
- }
-
- // Find out the last time we queried for updates
- var lastUpdateTime = timestampFileInfo.Exists ? File.ReadAllText(timestampFile, Encoding.UTF8) : string.Empty;
-
- var existingDirectories = Directory.EnumerateDirectories(path).Select(Path.GetFileName).ToList();
-
- // If this is our first time, don't do any updates and just record the timestamp
- if (!string.IsNullOrEmpty(lastUpdateTime))
- {
- var artistsToUpdate = await GetArtistIdsToUpdate(existingDirectories, lastUpdateTime, cancellationToken).ConfigureAwait(false);
-
- progress.Report(5);
-
- await UpdateArtists(artistsToUpdate, path, progress, cancellationToken).ConfigureAwait(false);
- }
-
- var newUpdateTime = Convert.ToInt64(DateTimeToUnixTimestamp(DateTime.UtcNow)).ToString(UsCulture);
-
- File.WriteAllText(timestampFile, newUpdateTime, Encoding.UTF8);
-
- progress.Report(100);
- }
-
- /// <summary>
- /// Gets the artist ids to update.
- /// </summary>
- /// <param name="existingArtistIds">The existing series ids.</param>
- /// <param name="lastUpdateTime">The last update time.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task{IEnumerable{System.String}}.</returns>
- private async Task<IEnumerable<string>> GetArtistIdsToUpdate(IEnumerable<string> existingArtistIds, string lastUpdateTime, CancellationToken cancellationToken)
- {
- // First get last time
- using (var stream = await _httpClient.Get(new HttpRequestOptions
- {
- Url = string.Format(UpdatesUrl, FanartBaseProvider.ApiKey, lastUpdateTime),
- CancellationToken = cancellationToken,
- EnableHttpCompression = true,
- ResourcePool = FanartBaseProvider.FanArtResourcePool
-
- }).ConfigureAwait(false))
- {
- // If empty fanart will return a string of "null", rather than an empty list
- using (var reader = new StreamReader(stream))
- {
- var json = await reader.ReadToEndAsync().ConfigureAwait(false);
-
- if (string.Equals(json, "null", StringComparison.OrdinalIgnoreCase))
- {
- return new List<string>();
- }
-
- var updates = _jsonSerializer.DeserializeFromString<List<FanArtUpdate>>(json);
-
- return updates.Select(i => i.id).Where(i => existingArtistIds.Contains(i, StringComparer.OrdinalIgnoreCase));
- }
- }
- }
-
- /// <summary>
- /// Updates the artists.
- /// </summary>
- /// <param name="idList">The id list.</param>
- /// <param name="artistsDataPath">The artists data path.</param>
- /// <param name="progress">The progress.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- private async Task UpdateArtists(IEnumerable<string> idList, string artistsDataPath, IProgress<double> progress, CancellationToken cancellationToken)
- {
- var list = idList.ToList();
- var numComplete = 0;
-
- foreach (var id in list)
- {
- try
- {
- await UpdateArtist(id, artistsDataPath, cancellationToken).ConfigureAwait(false);
- }
- catch (HttpException ex)
- {
- // Already logged at lower levels, but don't fail the whole operation, unless something other than a timeout
- if (!ex.IsTimedOut)
- {
- throw;
- }
- }
-
- numComplete++;
- double percent = numComplete;
- percent /= list.Count;
- percent *= 95;
-
- progress.Report(percent + 5);
- }
- }
-
- /// <summary>
- /// Updates the artist.
- /// </summary>
- /// <param name="musicBrainzId">The musicBrainzId.</param>
- /// <param name="artistsDataPath">The artists data path.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- private Task UpdateArtist(string musicBrainzId, string artistsDataPath, CancellationToken cancellationToken)
- {
- _logger.Info("Updating artist " + musicBrainzId);
-
- artistsDataPath = Path.Combine(artistsDataPath, musicBrainzId);
-
- if (!Directory.Exists(artistsDataPath))
- {
- Directory.CreateDirectory(artistsDataPath);
- }
-
- return FanArtArtistProvider.Current.DownloadArtistXml(artistsDataPath, musicBrainzId, cancellationToken);
- }
-
- /// <summary>
- /// Dates the time to unix timestamp.
- /// </summary>
- /// <param name="dateTime">The date time.</param>
- /// <returns>System.Double.</returns>
- private static double DateTimeToUnixTimestamp(DateTime dateTime)
- {
- return (dateTime - new DateTime(1970, 1, 1).ToUniversalTime()).TotalSeconds;
- }
-
- public class FanArtUpdate
- {
- public string id { get; set; }
- public string name { get; set; }
- public string new_images { get; set; }
- public string total_images { get; set; }
- }
- }
-}
diff --git a/MediaBrowser.Controller/Providers/Music/LastfmAlbumProvider.cs b/MediaBrowser.Controller/Providers/Music/LastfmAlbumProvider.cs
deleted file mode 100644
index 77cd2033d..000000000
--- a/MediaBrowser.Controller/Providers/Music/LastfmAlbumProvider.cs
+++ /dev/null
@@ -1,166 +0,0 @@
-using MediaBrowser.Common.Extensions;
-using MediaBrowser.Common.Net;
-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 MoreLinq;
-using System;
-using System.IO;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace MediaBrowser.Controller.Providers.Music
-{
- public class LastfmAlbumProvider : LastfmBaseProvider
- {
- private static readonly Task<string> BlankId = Task.FromResult("");
-
- private readonly IProviderManager _providerManager;
-
- public LastfmAlbumProvider(IJsonSerializer jsonSerializer, IHttpClient httpClient, ILogManager logManager, IServerConfigurationManager configurationManager, IProviderManager providerManager)
- : base(jsonSerializer, httpClient, logManager, configurationManager)
- {
- _providerManager = providerManager;
- LocalMetaFileName = LastfmHelper.LocalAlbumMetaFileName;
- }
-
- protected override Task<string> FindId(BaseItem item, CancellationToken cancellationToken)
- {
- // We don't fetch by id
- return BlankId;
- }
-
- /// <summary>
- /// Needses the refresh internal.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="providerInfo">The provider info.</param>
- /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
- protected override bool NeedsRefreshInternal(BaseItem item, BaseProviderInfo providerInfo)
- {
- // If song metadata has changed and we don't have an mbid, refresh
- if (string.IsNullOrEmpty(item.GetProviderId(MetadataProviders.Musicbrainz)) &&
- GetComparisonData(item as MusicAlbum) != providerInfo.Data)
- {
- return true;
- }
-
- return base.NeedsRefreshInternal(item, providerInfo);
- }
-
- protected override async Task FetchLastfmData(BaseItem item, string id, CancellationToken cancellationToken)
- {
- var result = await GetAlbumResult(item, cancellationToken).ConfigureAwait(false);
-
- if (result != null && result.album != null)
- {
- 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;
- if (!item.ProviderData.TryGetValue(Id, out data))
- {
- data = new BaseProviderInfo();
- item.ProviderData[Id] = data;
- }
-
- data.Data = GetComparisonData(item as MusicAlbum);
- }
-
- private async Task<LastfmGetAlbumResult> GetAlbumResult(BaseItem item, CancellationToken cancellationToken)
- {
- var folder = (Folder)item;
-
- // Get each song, distinct by the combination of AlbumArtist and Album
- var songs = folder.RecursiveChildren.OfType<Audio>().DistinctBy(i => (i.AlbumArtist ?? string.Empty) + (i.Album ?? string.Empty), StringComparer.OrdinalIgnoreCase).ToList();
-
- foreach (var song in songs.Where(song => !string.IsNullOrEmpty(song.Album) && !string.IsNullOrEmpty(song.AlbumArtist)))
- {
- var result = await GetAlbumResult(song.AlbumArtist, song.Album, cancellationToken).ConfigureAwait(false);
-
- if (result != null && result.album != null)
- {
- return result;
- }
- }
-
- // Try the folder name
- return await GetAlbumResult(item.Parent.Name, item.Name, cancellationToken);
- }
-
- private async Task<LastfmGetAlbumResult> GetAlbumResult(string artist, string album, CancellationToken cancellationToken)
- {
- // Get albu info using artist and album name
- var url = RootUrl + string.Format("method=album.getInfo&artist={0}&album={1}&api_key={2}&format=json", UrlEncode(artist), UrlEncode(album), ApiKey);
-
- using (var json = await HttpClient.Get(new HttpRequestOptions
- {
- Url = url,
- ResourcePool = LastfmResourcePool,
- CancellationToken = cancellationToken,
- EnableHttpCompression = false
-
- }).ConfigureAwait(false))
- {
- return JsonSerializer.DeserializeFromStream<LastfmGetAlbumResult>(json);
- }
- }
-
- protected override Task FetchData(BaseItem item, CancellationToken cancellationToken)
- {
- return FetchLastfmData(item, string.Empty, cancellationToken);
- }
-
- public override bool Supports(BaseItem item)
- {
- return item is MusicAlbum;
- }
-
- protected override bool RefreshOnFileSystemStampChange
- {
- get
- {
- return true;
- }
- }
-
- /// <summary>
- /// Gets the data.
- /// </summary>
- /// <param name="album">The album.</param>
- /// <returns>Guid.</returns>
- private Guid GetComparisonData(MusicAlbum album)
- {
- var songs = album.RecursiveChildren.OfType<Audio>().ToList();
-
- var albumArtists = songs.Select(i => i.AlbumArtist)
- .Where(i => !string.IsNullOrEmpty(i))
- .Distinct(StringComparer.OrdinalIgnoreCase)
- .ToList();
-
- var albumNames = songs.Select(i => i.AlbumArtist)
- .Where(i => !string.IsNullOrEmpty(i))
- .Distinct(StringComparer.OrdinalIgnoreCase)
- .ToList();
-
- albumArtists.AddRange(albumNames);
-
- return string.Join(string.Empty, albumArtists.OrderBy(i => i).ToArray()).GetMD5();
- }
- }
-}
diff --git a/MediaBrowser.Controller/Providers/Music/LastfmArtistByNameProvider.cs b/MediaBrowser.Controller/Providers/Music/LastfmArtistByNameProvider.cs
deleted file mode 100644
index c64a7fc99..000000000
--- a/MediaBrowser.Controller/Providers/Music/LastfmArtistByNameProvider.cs
+++ /dev/null
@@ -1,117 +0,0 @@
-using MediaBrowser.Common.Net;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Entities.Audio;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.Serialization;
-using System;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace MediaBrowser.Controller.Providers.Music
-{
- /// <summary>
- /// Class LastfmArtistByNameProvider
- /// </summary>
- public class LastfmArtistByNameProvider : LastfmArtistProvider
- {
- /// <summary>
- /// Initializes a new instance of the <see cref="LastfmArtistByNameProvider" /> class.
- /// </summary>
- /// <param name="jsonSerializer">The json serializer.</param>
- /// <param name="httpClient">The HTTP client.</param>
- /// <param name="logManager">The log manager.</param>
- /// <param name="configurationManager">The configuration manager.</param>
- /// <param name="providerManager">The provider manager.</param>
- /// <param name="libraryManager">The library manager.</param>
- public LastfmArtistByNameProvider(IJsonSerializer jsonSerializer, IHttpClient httpClient, ILogManager logManager, IServerConfigurationManager configurationManager, IProviderManager providerManager, ILibraryManager libraryManager)
- : base(jsonSerializer, httpClient, logManager, configurationManager, providerManager, libraryManager)
- {
- }
-
- /// <summary>
- /// Gets a value indicating whether [save local meta].
- /// </summary>
- /// <value><c>true</c> if [save local meta]; otherwise, <c>false</c>.</value>
- protected override bool SaveLocalMeta
- {
- get
- {
- return true;
- }
- }
-
- /// <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;
- }
-
- /// <summary>
- /// Gets the provider version.
- /// </summary>
- /// <value>The provider version.</value>
- protected override string ProviderVersion
- {
- get
- {
- return "7";
- }
- }
-
- /// <summary>
- /// Fetches the lastfm data.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="musicBrainzId">The music brainz id.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- protected override async Task FetchLastfmData(BaseItem item, string musicBrainzId, CancellationToken cancellationToken)
- {
- var artist = (Artist)item;
-
- // See if we can avoid an http request by finding the matching MusicArtist entity
- var musicArtist = FindMusicArtist(artist, LibraryManager);
-
- if (musicArtist != null)
- {
- LastfmHelper.ProcessArtistData(musicArtist, artist);
- }
- else
- {
- await base.FetchLastfmData(item, musicBrainzId, cancellationToken).ConfigureAwait(false);
- }
- }
-
-
- /// <summary>
- /// Finds the music artist.
- /// </summary>
- /// <param name="artist">The artist.</param>
- /// <param name="libraryManager">The library manager.</param>
- /// <returns>MusicArtist.</returns>
- private static MusicArtist FindMusicArtist(Artist artist, ILibraryManager libraryManager)
- {
- var musicBrainzId = artist.GetProviderId(MetadataProviders.Musicbrainz);
-
- return libraryManager.RootFolder.RecursiveChildren
- .OfType<MusicArtist>()
- .FirstOrDefault(i =>
- {
- if (!string.IsNullOrWhiteSpace(musicBrainzId) && string.Equals(musicBrainzId, i.GetProviderId(MetadataProviders.Musicbrainz), StringComparison.OrdinalIgnoreCase))
- {
- return true;
- }
-
- return false;
- });
- }
- }
-}
diff --git a/MediaBrowser.Controller/Providers/Music/LastfmArtistProvider.cs b/MediaBrowser.Controller/Providers/Music/LastfmArtistProvider.cs
deleted file mode 100644
index 38475317e..000000000
--- a/MediaBrowser.Controller/Providers/Music/LastfmArtistProvider.cs
+++ /dev/null
@@ -1,283 +0,0 @@
-using MediaBrowser.Common.Net;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Entities.Audio;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.Net;
-using MediaBrowser.Model.Serialization;
-using System;
-using System.Globalization;
-using System.IO;
-using System.Linq;
-using System.Net;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-using System.Xml;
-
-namespace MediaBrowser.Controller.Providers.Music
-{
- /// <summary>
- /// Class LastfmArtistProvider
- /// </summary>
- public class LastfmArtistProvider : LastfmBaseProvider
- {
- /// <summary>
- /// The _provider manager
- /// </summary>
- private readonly IProviderManager _providerManager;
- /// <summary>
- /// The _library manager
- /// </summary>
- protected readonly ILibraryManager LibraryManager;
-
- /// <summary>
- /// Initializes a new instance of the <see cref="LastfmArtistProvider"/> class.
- /// </summary>
- /// <param name="jsonSerializer">The json serializer.</param>
- /// <param name="httpClient">The HTTP client.</param>
- /// <param name="logManager">The log manager.</param>
- /// <param name="configurationManager">The configuration manager.</param>
- /// <param name="providerManager">The provider manager.</param>
- /// <param name="libraryManager">The library manager.</param>
- public LastfmArtistProvider(IJsonSerializer jsonSerializer, IHttpClient httpClient, ILogManager logManager, IServerConfigurationManager configurationManager, IProviderManager providerManager, ILibraryManager libraryManager)
- : base(jsonSerializer, httpClient, logManager, configurationManager)
- {
- _providerManager = providerManager;
- LibraryManager = libraryManager;
- LocalMetaFileName = LastfmHelper.LocalArtistMetaFileName;
- }
-
- /// <summary>
- /// Finds the id.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task{System.String}.</returns>
- protected override async Task<string> FindId(BaseItem item, CancellationToken cancellationToken)
- {
- if (item is Artist)
- {
- // Since MusicArtists are refreshed first, try to find it from one of them
- var id = FindIdFromMusicArtistEntity(item);
-
- if (!string.IsNullOrEmpty(id))
- {
- return id;
- }
- }
-
- // Try to find the id using last fm
- var result = await FindIdFromLastFm(item, cancellationToken).ConfigureAwait(false);
-
- if (result != null)
- {
- if (!string.IsNullOrEmpty(result))
- {
- return result;
- }
- }
-
- try
- {
- // If we don't get anything, go directly to music brainz
- return await FindIdFromMusicBrainz(item, cancellationToken).ConfigureAwait(false);
- }
- catch (HttpException e)
- {
- if (e.StatusCode.HasValue && e.StatusCode.Value == HttpStatusCode.BadRequest)
- {
- // They didn't like a character in the name. Handle the exception so that the provider doesn't keep retrying over and over
- return null;
- }
-
- throw;
- }
- }
-
- /// <summary>
- /// Finds the id from music artist entity.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <returns>System.String.</returns>
- private string FindIdFromMusicArtistEntity(BaseItem item)
- {
- var artist = LibraryManager.RootFolder.RecursiveChildren.OfType<MusicArtist>()
- .FirstOrDefault(i => string.Compare(i.Name, item.Name, CultureInfo.CurrentCulture, CompareOptions.IgnoreNonSpace | CompareOptions.IgnoreCase | CompareOptions.IgnoreSymbols) == 0);
-
- return artist != null ? artist.GetProviderId(MetadataProviders.Musicbrainz) : null;
- }
-
- /// <summary>
- /// Finds the id from last fm.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task{System.String}.</returns>
- private async Task<string> FindIdFromLastFm(BaseItem item, CancellationToken cancellationToken)
- {
- //Execute the Artist search against our name and assume first one is the one we want
- var url = RootUrl + string.Format("method=artist.search&artist={0}&api_key={1}&format=json", UrlEncode(item.Name), ApiKey);
-
- using (var json = await HttpClient.Get(new HttpRequestOptions
- {
- Url = url,
- ResourcePool = LastfmResourcePool,
- CancellationToken = cancellationToken,
- EnableHttpCompression = false
-
- }).ConfigureAwait(false))
- {
- using (var reader = new StreamReader(json, true))
- {
- var jsonString = await reader.ReadToEndAsync().ConfigureAwait(false);
-
- // Sometimes they send back an empty response or just the text "null"
- if (!jsonString.StartsWith("{", StringComparison.OrdinalIgnoreCase))
- {
- return null;
- }
-
- var searchResult = JsonSerializer.DeserializeFromString<LastfmArtistSearchResults>(jsonString);
-
- if (searchResult != null && searchResult.results != null && searchResult.results.artistmatches != null && searchResult.results.artistmatches.artist.Count > 0)
- {
- var artist = searchResult.results.artistmatches.artist
- .FirstOrDefault(i => i.name != null && string.Compare(i.name, item.Name, CultureInfo.CurrentCulture, CompareOptions.IgnoreNonSpace | CompareOptions.IgnoreCase | CompareOptions.IgnoreSymbols) == 0);
-
- return artist == null ? null : artist.mbid;
- }
- }
- }
-
- return null;
- }
-
- /// <summary>
- /// Finds the id from music brainz.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task{System.String}.</returns>
- private async Task<string> FindIdFromMusicBrainz(BaseItem item, CancellationToken cancellationToken)
- {
- // They seem to throw bad request failures on any term with a slash
- var nameToSearch = item.Name.Replace('/', ' ');
-
- var url = string.Format("http://www.musicbrainz.org/ws/2/artist/?query=artist:{0}", UrlEncode(nameToSearch));
-
- var doc = await FanArtAlbumProvider.Current.GetMusicBrainzResponse(url, cancellationToken).ConfigureAwait(false);
-
- var ns = new XmlNamespaceManager(doc.NameTable);
- ns.AddNamespace("mb", "http://musicbrainz.org/ns/mmd-2.0#");
- var node = doc.SelectSingleNode("//mb:artist-list/mb:artist[@type='Group']/@id", ns);
-
- if (node != null && node.Value != null)
- {
- return node.Value;
- }
-
- if (HasDiacritics(item.Name))
- {
- // Try again using the search with accent characters url
- url = string.Format("http://www.musicbrainz.org/ws/2/artist/?query=artistaccent:{0}", UrlEncode(nameToSearch));
-
- doc = await FanArtAlbumProvider.Current.GetMusicBrainzResponse(url, cancellationToken).ConfigureAwait(false);
-
- ns = new XmlNamespaceManager(doc.NameTable);
- ns.AddNamespace("mb", "http://musicbrainz.org/ns/mmd-2.0#");
- node = doc.SelectSingleNode("//mb:artist-list/mb:artist[@type='Group']/@id", ns);
-
- if (node != null && node.Value != null)
- {
- return node.Value;
- }
- }
-
- return null;
- }
-
- /// <summary>
- /// Determines whether the specified text has diacritics.
- /// </summary>
- /// <param name="text">The text.</param>
- /// <returns><c>true</c> if the specified text has diacritics; otherwise, <c>false</c>.</returns>
- private bool HasDiacritics(string text)
- {
- return !string.Equals(text, RemoveDiacritics(text), StringComparison.Ordinal);
- }
-
- /// <summary>
- /// Removes the diacritics.
- /// </summary>
- /// <param name="text">The text.</param>
- /// <returns>System.String.</returns>
- private string RemoveDiacritics(string text)
- {
- return string.Concat(
- text.Normalize(NormalizationForm.FormD)
- .Where(ch => CharUnicodeInfo.GetUnicodeCategory(ch) !=
- UnicodeCategory.NonSpacingMark)
- ).Normalize(NormalizationForm.FormC);
- }
-
- /// <summary>
- /// Fetches the lastfm data.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="musicBrainzId">The music brainz id.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- protected override async Task FetchLastfmData(BaseItem item, string musicBrainzId, CancellationToken cancellationToken)
- {
- // Get artist info with provided id
- var url = RootUrl + string.Format("method=artist.getInfo&mbid={0}&api_key={1}&format=json", UrlEncode(musicBrainzId), ApiKey);
-
- LastfmGetArtistResult result;
-
- using (var json = await HttpClient.Get(new HttpRequestOptions
- {
- Url = url,
- ResourcePool = LastfmResourcePool,
- CancellationToken = cancellationToken,
- EnableHttpCompression = false
-
- }).ConfigureAwait(false))
- {
- result = JsonSerializer.DeserializeFromStream<LastfmGetArtistResult>(json);
- }
-
- if (result != null && result.artist != null)
- {
- 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);
-
- }
- }
- }
-
- /// <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 MusicArtist;
- }
- }
-}
diff --git a/MediaBrowser.Controller/Providers/Music/LastfmBaseProvider.cs b/MediaBrowser.Controller/Providers/Music/LastfmBaseProvider.cs
deleted file mode 100644
index 54fe32959..000000000
--- a/MediaBrowser.Controller/Providers/Music/LastfmBaseProvider.cs
+++ /dev/null
@@ -1,277 +0,0 @@
-using MediaBrowser.Common.Net;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.Serialization;
-using System;
-using System.Collections.Generic;
-using System.Net;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace MediaBrowser.Controller.Providers.Music
-{
- /// <summary>
- /// Class MovieDbProvider
- /// </summary>
- public abstract class LastfmBaseProvider : BaseMetadataProvider
- {
- protected static readonly SemaphoreSlim LastfmResourcePool = new SemaphoreSlim(4, 4);
-
- /// <summary>
- /// Initializes a new instance of the <see cref="LastfmBaseProvider" /> class.
- /// </summary>
- /// <param name="jsonSerializer">The json serializer.</param>
- /// <param name="httpClient">The HTTP client.</param>
- /// <param name="logManager">The log manager.</param>
- /// <param name="configurationManager">The configuration manager.</param>
- /// <exception cref="System.ArgumentNullException">jsonSerializer</exception>
- protected LastfmBaseProvider(IJsonSerializer jsonSerializer, IHttpClient httpClient, ILogManager logManager, IServerConfigurationManager configurationManager)
- : base(logManager, configurationManager)
- {
- if (jsonSerializer == null)
- {
- throw new ArgumentNullException("jsonSerializer");
- }
- if (httpClient == null)
- {
- throw new ArgumentNullException("httpClient");
- }
- JsonSerializer = jsonSerializer;
- HttpClient = httpClient;
- }
-
- protected override string ProviderVersion
- {
- get
- {
- return "5";
- }
- }
-
- protected override bool RefreshOnVersionChange
- {
- get
- {
- return true;
- }
- }
-
- /// <summary>
- /// Gets the json serializer.
- /// </summary>
- /// <value>The json serializer.</value>
- protected IJsonSerializer JsonSerializer { get; private set; }
-
- /// <summary>
- /// Gets the HTTP client.
- /// </summary>
- /// <value>The HTTP client.</value>
- protected IHttpClient HttpClient { get; private set; }
-
- /// <summary>
- /// The name of the local json meta file for this item type
- /// </summary>
- protected string LocalMetaFileName { get; set; }
-
- protected virtual bool SaveLocalMeta
- {
- get
- {
- return ConfigurationManager.Configuration.SaveLocalMeta;
- }
- }
-
- /// <summary>
- /// If we save locally, refresh if they delete something
- /// </summary>
- protected override bool RefreshOnFileSystemStampChange
- {
- get
- {
- return SaveLocalMeta;
- }
- }
-
- /// <summary>
- /// Gets the priority.
- /// </summary>
- /// <value>The priority.</value>
- public override MetadataProviderPriority Priority
- {
- get { return MetadataProviderPriority.Second; }
- }
-
- /// <summary>
- /// Gets a value indicating whether [requires internet].
- /// </summary>
- /// <value><c>true</c> if [requires internet]; otherwise, <c>false</c>.</value>
- public override bool RequiresInternet
- {
- get
- {
- return true;
- }
- }
-
- protected const string RootUrl = @"http://ws.audioscrobbler.com/2.0/?";
- protected static string ApiKey = "7b76553c3eb1d341d642755aecc40a33";
-
- /// <summary>
- /// Determines whether [has local meta] [the specified item].
- /// </summary>
- /// <param name="item">The item.</param>
- /// <returns><c>true</c> if [has local meta] [the specified item]; otherwise, <c>false</c>.</returns>
- protected bool HasLocalMeta(BaseItem item)
- {
- return item.ResolveArgs.ContainsMetaFileByName(LocalMetaFileName);
- }
-
- /// <summary>
- /// Fetches the items data.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="cancellationToken"></param>
- /// <returns>Task.</returns>
- protected virtual async Task FetchData(BaseItem item, CancellationToken cancellationToken)
- {
- var id = item.GetProviderId(MetadataProviders.Musicbrainz) ?? await FindId(item, cancellationToken).ConfigureAwait(false);
- if (!string.IsNullOrWhiteSpace(id))
- {
- Logger.Debug("LastfmProvider - getting info for {0}", item.Name);
-
- cancellationToken.ThrowIfCancellationRequested();
-
- item.SetProviderId(MetadataProviders.Musicbrainz, id);
-
- await FetchLastfmData(item, id, cancellationToken).ConfigureAwait(false);
- }
- else
- {
- Logger.Info("LastfmProvider could not find " + item.Name + ". Check name on Last.fm.");
- }
-
- }
-
- protected abstract Task<string> FindId(BaseItem item, CancellationToken cancellationToken);
-
- protected abstract Task FetchLastfmData(BaseItem item, string id, CancellationToken cancellationToken);
-
- /// <summary>
- /// Encodes an URL.
- /// </summary>
- /// <param name="name">The name.</param>
- /// <returns>System.String.</returns>
- protected static string UrlEncode(string name)
- {
- return WebUtility.UrlEncode(name);
- }
-
- /// <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 async Task<bool> FetchAsync(BaseItem item, bool force, CancellationToken cancellationToken)
- {
- cancellationToken.ThrowIfCancellationRequested();
-
- await FetchData(item, cancellationToken).ConfigureAwait(false);
- SetLastRefreshed(item, DateTime.UtcNow);
- return true;
- }
- }
-
- #region Result Objects
-
- public class LastfmStats
- {
- public string listeners { get; set; }
- public string playcount { get; set; }
- }
-
- public class LastfmTag
- {
- public string name { get; set; }
- public string url { get; set; }
- }
-
-
- public class LastfmTags
- {
- public List<LastfmTag> tag { get; set; }
- }
-
- public class LastfmFormationInfo
- {
- public string yearfrom { get; set; }
- public string yearto { get; set; }
- }
-
- public class LastFmBio
- {
- public string published { get; set; }
- public string summary { get; set; }
- public string content { get; set; }
- public string placeformed { get; set; }
- public string yearformed { get; set; }
- public List<LastfmFormationInfo> formationlist { get; set; }
- }
-
- public class LastfmArtist
- {
- public string name { get; set; }
- public string mbid { get; set; }
- public string url { get; set; }
- public string streamable { get; set; }
- public string ontour { get; set; }
- public LastfmStats stats { get; set; }
- public List<LastfmArtist> similar { get; set; }
- public LastfmTags tags { get; set; }
- public LastFmBio bio { get; set; }
- }
-
-
- public class LastfmAlbum
- {
- public string name { get; set; }
- public string artist { get; set; }
- public string id { get; set; }
- public string mbid { get; set; }
- public string releasedate { get; set; }
- public int listeners { get; set; }
- public int playcount { get; set; }
- public LastfmTags toptags { get; set; }
- public LastFmBio wiki { get; set; }
- }
-
- public class LastfmGetAlbumResult
- {
- public LastfmAlbum album { get; set; }
- }
-
- public class LastfmGetArtistResult
- {
- public LastfmArtist artist { get; set; }
- }
-
- public class Artistmatches
- {
- public List<LastfmArtist> artist { get; set; }
- }
-
- public class LastfmArtistSearchResult
- {
- public Artistmatches artistmatches { get; set; }
- }
-
- public class LastfmArtistSearchResults
- {
- public LastfmArtistSearchResult results { get; set; }
- }
-
- #endregion
-}
diff --git a/MediaBrowser.Controller/Providers/Music/LastfmHelper.cs b/MediaBrowser.Controller/Providers/Music/LastfmHelper.cs
deleted file mode 100644
index ca9f8bc71..000000000
--- a/MediaBrowser.Controller/Providers/Music/LastfmHelper.cs
+++ /dev/null
@@ -1,73 +0,0 @@
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Entities.Audio;
-using MediaBrowser.Model.Entities;
-using System;
-using System.Linq;
-
-namespace MediaBrowser.Controller.Providers.Music
-{
- public static class LastfmHelper
- {
- public static string LocalArtistMetaFileName = "lastfmartist.json";
- public static string LocalAlbumMetaFileName = "lastfmalbum.json";
-
- public static void ProcessArtistData(BaseItem artist, LastfmArtist data)
- {
- var yearFormed = 0;
-
- if (data.bio != null)
- {
- Int32.TryParse(data.bio.yearformed, out yearFormed);
-
- artist.Overview = data.bio.content;
-
- if (!string.IsNullOrEmpty(data.bio.placeformed))
- {
- artist.AddProductionLocation(data.bio.placeformed);
- }
- }
-
- artist.PremiereDate = yearFormed > 0 ? new DateTime(yearFormed, 1, 1, 0, 0, 0, DateTimeKind.Utc) : (DateTime?)null;
- artist.ProductionYear = yearFormed;
- if (data.tags != null)
- {
- AddTags(artist, data.tags);
- }
- }
-
- public static void ProcessArtistData(MusicArtist source, Artist target)
- {
- target.PremiereDate = source.PremiereDate;
- target.ProductionYear = source.ProductionYear;
- target.Tags = source.Tags.ToList();
- target.Overview = source.Overview;
- target.ProductionLocations = source.ProductionLocations.ToList();
- target.Genres = source.Genres.ToList();
- }
-
- public static void ProcessAlbumData(BaseItem item, LastfmAlbum data)
- {
- if (!string.IsNullOrWhiteSpace(data.mbid)) item.SetProviderId(MetadataProviders.Musicbrainz, data.mbid);
-
- var overview = data.wiki != null ? data.wiki.content : null;
-
- item.Overview = overview;
-
- DateTime release;
- DateTime.TryParse(data.releasedate, out release);
- item.PremiereDate = release;
- item.ProductionYear = release.Year;
- if (data.toptags != null)
- {
- AddTags(item, data.toptags);
- }
- }
-
- private static void AddTags(BaseItem item, LastfmTags tags)
- {
- var itemTags = (from tag in tags.tag where !string.IsNullOrEmpty(tag.name) select tag.name).ToList();
-
- item.Tags = itemTags;
- }
- }
-}
diff --git a/MediaBrowser.Controller/Providers/Music/MusicArtistProviderFromJson.cs b/MediaBrowser.Controller/Providers/Music/MusicArtistProviderFromJson.cs
deleted file mode 100644
index e3df46ed2..000000000
--- a/MediaBrowser.Controller/Providers/Music/MusicArtistProviderFromJson.cs
+++ /dev/null
@@ -1,100 +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;
-
-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;
- }
-
- }
-}
diff --git a/MediaBrowser.Controller/Providers/TV/EpisodeImageFromMediaLocationProvider.cs b/MediaBrowser.Controller/Providers/TV/EpisodeImageFromMediaLocationProvider.cs
deleted file mode 100644
index 7eaf95a08..000000000
--- a/MediaBrowser.Controller/Providers/TV/EpisodeImageFromMediaLocationProvider.cs
+++ /dev/null
@@ -1,132 +0,0 @@
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Entities.TV;
-using MediaBrowser.Model.Entities;
-using System;
-using System.IO;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Model.Logging;
-
-namespace MediaBrowser.Controller.Providers.TV
-{
- /// <summary>
- /// Class EpisodeImageFromMediaLocationProvider
- /// </summary>
- public class EpisodeImageFromMediaLocationProvider : BaseMetadataProvider
- {
- public EpisodeImageFromMediaLocationProvider(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 Episode && item.LocationType == LocationType.FileSystem;
- }
-
- /// <summary>
- /// Gets the priority.
- /// </summary>
- /// <value>The priority.</value>
- public override MetadataProviderPriority Priority
- {
- get { return MetadataProviderPriority.First; }
- }
-
- /// <summary>
- /// Returns true or false indicating if the provider should refresh when the contents of it's directory changes
- /// </summary>
- /// <value><c>true</c> if [refresh on file system stamp change]; otherwise, <c>false</c>.</value>
- protected override bool RefreshOnFileSystemStampChange
- {
- get
- {
- return true;
- }
- }
-
- /// <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)
- {
- cancellationToken.ThrowIfCancellationRequested();
-
- var episode = (Episode)item;
-
- var episodeFileName = Path.GetFileName(episode.Path);
-
- var parent = item.ResolveArgs.Parent;
-
- ValidateImage(episode, item.MetaLocation);
-
- cancellationToken.ThrowIfCancellationRequested();
-
- SetPrimaryImagePath(episode, parent, item.MetaLocation, episodeFileName);
-
- SetLastRefreshed(item, DateTime.UtcNow);
- return TrueTaskResult;
- }
-
- /// <summary>
- /// Validates the primary image path still exists
- /// </summary>
- /// <param name="episode">The episode.</param>
- /// <param name="metadataFolderPath">The metadata folder path.</param>
- /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
- private void ValidateImage(Episode episode, string metadataFolderPath)
- {
- var path = episode.PrimaryImagePath;
-
- if (string.IsNullOrEmpty(path))
- {
- return;
- }
-
- // Only validate images in the season/metadata folder
- if (!string.Equals(Path.GetDirectoryName(path), metadataFolderPath, StringComparison.OrdinalIgnoreCase))
- {
- return;
- }
-
- if (episode.Parent.ResolveArgs.GetMetaFileByPath(path) == null)
- {
- episode.PrimaryImagePath = null;
- }
- }
-
- /// <summary>
- /// Sets the primary image path.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="parent">The parent.</param>
- /// <param name="metadataFolder">The metadata folder.</param>
- /// <param name="episodeFileName">Name of the episode file.</param>
- private void SetPrimaryImagePath(Episode item, Folder parent, string metadataFolder, string episodeFileName)
- {
- // Look for the image file in the metadata folder, and if found, set PrimaryImagePath
- var imageFiles = new[] {
- Path.Combine(metadataFolder, Path.ChangeExtension(episodeFileName, ".jpg")),
- Path.Combine(metadataFolder, Path.ChangeExtension(episodeFileName, ".png"))
- };
-
- var file = parent.ResolveArgs.GetMetaFileByPath(imageFiles[0]) ??
- parent.ResolveArgs.GetMetaFileByPath(imageFiles[1]);
-
- if (file != null)
- {
- item.PrimaryImagePath = file.FullName;
- }
- }
- }
-}
diff --git a/MediaBrowser.Controller/Providers/TV/EpisodeProviderFromXml.cs b/MediaBrowser.Controller/Providers/TV/EpisodeProviderFromXml.cs
deleted file mode 100644
index 0e7f1e66e..000000000
--- a/MediaBrowser.Controller/Providers/TV/EpisodeProviderFromXml.cs
+++ /dev/null
@@ -1,116 +0,0 @@
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Entities.TV;
-using MediaBrowser.Model.Entities;
-using System;
-using System.IO;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Model.Logging;
-
-namespace MediaBrowser.Controller.Providers.TV
-{
- /// <summary>
- /// Class EpisodeProviderFromXml
- /// </summary>
- public class EpisodeProviderFromXml : BaseMetadataProvider
- {
- public EpisodeProviderFromXml(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 Episode && item.LocationType == LocationType.FileSystem;
- }
-
- /// <summary>
- /// Gets the priority.
- /// </summary>
- /// <value>The priority.</value>
- public override MetadataProviderPriority Priority
- {
- get { return MetadataProviderPriority.First; }
- }
-
- protected override bool RefreshOnFileSystemStampChange
- {
- get
- {
- return true;
- }
- }
-
- /// <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>
- /// 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 metadataFile = Path.Combine(item.MetaLocation, Path.ChangeExtension(Path.GetFileName(item.Path), ".xml"));
-
- var file = item.ResolveArgs.Parent.ResolveArgs.GetMetaFileByPath(metadataFile);
-
- if (file == null)
- {
- return base.CompareDate(item);
- }
-
- return file.LastWriteTimeUtc;
- }
-
- /// <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 = Path.Combine(item.MetaLocation, Path.ChangeExtension(Path.GetFileName(item.Path), ".xml"));
-
- var file = item.ResolveArgs.Parent.ResolveArgs.GetMetaFileByPath(metadataFile);
-
- if (file == null)
- {
- return false;
- }
-
- await XmlParsingResourcePool.WaitAsync(cancellationToken).ConfigureAwait(false);
-
- try
- {
- new EpisodeXmlParser(Logger).Fetch((Episode)item, metadataFile, cancellationToken);
- }
- finally
- {
- XmlParsingResourcePool.Release();
- }
-
- SetLastRefreshed(item, DateTime.UtcNow);
- return true;
- }
- }
-}
diff --git a/MediaBrowser.Controller/Providers/TV/EpisodeXmlParser.cs b/MediaBrowser.Controller/Providers/TV/EpisodeXmlParser.cs
deleted file mode 100644
index 7ace1047e..000000000
--- a/MediaBrowser.Controller/Providers/TV/EpisodeXmlParser.cs
+++ /dev/null
@@ -1,119 +0,0 @@
-using MediaBrowser.Controller.Entities.TV;
-using MediaBrowser.Model.Logging;
-using System.IO;
-using System.Xml;
-
-namespace MediaBrowser.Controller.Providers.TV
-{
- /// <summary>
- /// Class EpisodeXmlParser
- /// </summary>
- public class EpisodeXmlParser : BaseItemXmlParser<Episode>
- {
- /// <summary>
- /// Initializes a new instance of the <see cref="EpisodeXmlParser" /> class.
- /// </summary>
- /// <param name="logger">The logger.</param>
- public EpisodeXmlParser(ILogger logger)
- : base(logger)
- {
- }
-
- /// <summary>
- /// Fetches the data from XML node.
- /// </summary>
- /// <param name="reader">The reader.</param>
- /// <param name="item">The item.</param>
- protected override void FetchDataFromXmlNode(XmlReader reader, Episode item)
- {
- switch (reader.Name)
- {
- case "Episode":
- //MB generated metadata is within an "Episode" node
- using (var subTree = reader.ReadSubtree())
- {
- subTree.MoveToContent();
-
- // Loop through each element
- while (subTree.Read())
- {
- if (subTree.NodeType == XmlNodeType.Element)
- {
- FetchDataFromXmlNode(subTree, item);
- }
- }
-
- }
- break;
-
- case "filename":
- {
- var filename = reader.ReadElementContentAsString();
-
- if (!string.IsNullOrWhiteSpace(filename))
- {
- // Strip off everything but the filename. Some metadata tools like MetaBrowser v1.0 will have an 'episodes' prefix
- // even though it's actually using the metadata folder.
- filename = Path.GetFileName(filename);
-
- var seasonFolder = Path.GetDirectoryName(item.Path);
- filename = Path.Combine(seasonFolder, "metadata", filename);
-
- if (File.Exists(filename))
- {
- item.PrimaryImagePath = filename;
- }
- }
- break;
- }
- case "SeasonNumber":
- {
- var number = reader.ReadElementContentAsString();
-
- if (!string.IsNullOrWhiteSpace(number))
- {
- int num;
-
- if (int.TryParse(number, out num))
- {
- item.ParentIndexNumber = num;
- }
- }
- break;
- }
-
- case "EpisodeNumber":
- {
- var number = reader.ReadElementContentAsString();
-
- if (!string.IsNullOrWhiteSpace(number))
- {
- int num;
-
- if (int.TryParse(number, out num))
- {
- item.IndexNumber = num;
- }
- }
- break;
- }
-
- case "EpisodeName":
- {
- var name = reader.ReadElementContentAsString();
-
- if (!string.IsNullOrWhiteSpace(name))
- {
- item.Name = name;
- }
- break;
- }
-
-
- default:
- base.FetchDataFromXmlNode(reader, item);
- break;
- }
- }
- }
-}
diff --git a/MediaBrowser.Controller/Providers/TV/FanArtSeasonProvider.cs b/MediaBrowser.Controller/Providers/TV/FanArtSeasonProvider.cs
deleted file mode 100644
index 167f855a4..000000000
--- a/MediaBrowser.Controller/Providers/TV/FanArtSeasonProvider.cs
+++ /dev/null
@@ -1,229 +0,0 @@
-using MediaBrowser.Common.Extensions;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Entities.TV;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Logging;
-using System;
-using System.IO;
-using System.Threading;
-using System.Threading.Tasks;
-using System.Xml;
-
-namespace MediaBrowser.Controller.Providers.TV
-{
- /// <summary>
- /// Class FanArtSeasonProvider
- /// </summary>
- class FanArtSeasonProvider : FanartBaseProvider
- {
- /// <summary>
- /// The _provider manager
- /// </summary>
- private readonly IProviderManager _providerManager;
-
- /// <summary>
- /// Initializes a new instance of the <see cref="FanArtSeasonProvider"/> class.
- /// </summary>
- /// <param name="logManager">The log manager.</param>
- /// <param name="configurationManager">The configuration manager.</param>
- /// <param name="providerManager">The provider manager.</param>
- public FanArtSeasonProvider(ILogManager logManager, IServerConfigurationManager configurationManager, IProviderManager providerManager)
- : base(logManager, configurationManager)
- {
- _providerManager = providerManager;
- }
-
- /// <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 Season;
- }
-
- /// <summary>
- /// Needses the refresh internal.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="providerInfo">The provider info.</param>
- /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
- protected override bool NeedsRefreshInternal(BaseItem item, BaseProviderInfo providerInfo)
- {
- if (GetComparisonData(item) != providerInfo.Data)
- {
- return true;
- }
-
- return base.NeedsRefreshInternal(item, providerInfo);
- }
-
- /// <summary>
- /// Gets the comparison data.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <returns>Guid.</returns>
- private Guid GetComparisonData(BaseItem item)
- {
- var season = (Season)item;
- var seriesId = season.Series != null ? season.Series.GetProviderId(MetadataProviders.Tvdb) : null;
-
- if (!string.IsNullOrEmpty(seriesId))
- {
- // Process images
- var imagesXmlPath = Path.Combine(FanArtTvProvider.GetSeriesDataPath(ConfigurationManager.ApplicationPaths, seriesId), "fanart.xml");
-
- var imagesFileInfo = new FileInfo(imagesXmlPath);
-
- return GetComparisonData(imagesFileInfo);
- }
-
- return Guid.Empty;
- }
-
- /// <summary>
- /// Gets the comparison data.
- /// </summary>
- /// <param name="imagesFileInfo">The images file info.</param>
- /// <returns>Guid.</returns>
- private Guid GetComparisonData(FileInfo imagesFileInfo)
- {
- var date = imagesFileInfo.Exists ? imagesFileInfo.LastWriteTimeUtc : DateTime.MinValue;
-
- var key = date.Ticks + imagesFileInfo.FullName;
-
- return key.GetMD5();
- }
-
- /// <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 async Task<bool> FetchAsync(BaseItem item, bool force, CancellationToken cancellationToken)
- {
- cancellationToken.ThrowIfCancellationRequested();
-
- var season = (Season)item;
-
- var seriesId = season.Series != null ? season.Series.GetProviderId(MetadataProviders.Tvdb) : null;
-
- if (!string.IsNullOrEmpty(seriesId))
- {
- // Process images
- var imagesXmlPath = Path.Combine(FanArtTvProvider.GetSeriesDataPath(ConfigurationManager.ApplicationPaths, seriesId), "fanart.xml");
-
- var imagesFileInfo = new FileInfo(imagesXmlPath);
-
- if (imagesFileInfo.Exists)
- {
- if (!season.HasImage(ImageType.Thumb))
- {
- var xmlDoc = new XmlDocument();
- xmlDoc.Load(imagesXmlPath);
-
- await FetchImages(season, xmlDoc, cancellationToken).ConfigureAwait(false);
- }
- }
-
- BaseProviderInfo data;
- if (!item.ProviderData.TryGetValue(Id, out data))
- {
- data = new BaseProviderInfo();
- item.ProviderData[Id] = data;
- }
-
- data.Data = GetComparisonData(imagesFileInfo);
-
- SetLastRefreshed(item, DateTime.UtcNow);
- return true;
- }
-
- return false;
- }
-
- /// <summary>
- /// Fetches the images.
- /// </summary>
- /// <param name="season">The season.</param>
- /// <param name="doc">The doc.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- private async Task FetchImages(Season season, XmlDocument doc, CancellationToken cancellationToken)
- {
- var seasonNumber = season.IndexNumber ?? -1;
-
- if (seasonNumber == -1)
- {
- return;
- }
-
- var language = ConfigurationManager.Configuration.PreferredMetadataLanguage.ToLower();
-
- if (ConfigurationManager.Configuration.DownloadSeasonImages.Thumb && !season.HasImage(ImageType.Thumb))
- {
- var node = doc.SelectSingleNode("//fanart/series/seasonthumbs/seasonthumb[@lang = \"" + language + "\"][@season = \"" + seasonNumber + "\"]/@url") ??
- doc.SelectSingleNode("//fanart/series/seasonthumbs/seasonthumb[@season = \"" + seasonNumber + "\"]/@url");
-
- var path = node != null ? node.Value : null;
-
- if (!string.IsNullOrEmpty(path))
- {
- season.SetImage(ImageType.Thumb, await _providerManager.DownloadAndSaveImage(season, path, ThumbFile, ConfigurationManager.Configuration.SaveLocalMeta, FanArtResourcePool, cancellationToken).ConfigureAwait(false));
- }
- }
- }
-
- /// <summary>
- /// Gets a value indicating whether [requires internet].
- /// </summary>
- /// <value><c>true</c> if [requires internet]; otherwise, <c>false</c>.</value>
- public override bool RequiresInternet
- {
- get
- {
- return true;
- }
- }
-
- /// <summary>
- /// Returns true or false indicating if the provider should refresh when the contents of it's directory changes
- /// </summary>
- /// <value><c>true</c> if [refresh on file system stamp change]; otherwise, <c>false</c>.</value>
- protected override bool RefreshOnFileSystemStampChange
- {
- get
- {
- return ConfigurationManager.Configuration.SaveLocalMeta;
- }
- }
-
- /// <summary>
- /// Gets a value indicating whether [refresh on version change].
- /// </summary>
- /// <value><c>true</c> if [refresh on version change]; otherwise, <c>false</c>.</value>
- protected override bool RefreshOnVersionChange
- {
- get
- {
- return true;
- }
- }
-
- /// <summary>
- /// Gets the provider version.
- /// </summary>
- /// <value>The provider version.</value>
- protected override string ProviderVersion
- {
- get
- {
- return "3";
- }
- }
- }
-}
diff --git a/MediaBrowser.Controller/Providers/TV/FanArtTVProvider.cs b/MediaBrowser.Controller/Providers/TV/FanArtTVProvider.cs
deleted file mode 100644
index 164c5d0c9..000000000
--- a/MediaBrowser.Controller/Providers/TV/FanArtTVProvider.cs
+++ /dev/null
@@ -1,338 +0,0 @@
-using MediaBrowser.Common.Configuration;
-using MediaBrowser.Common.Extensions;
-using MediaBrowser.Common.IO;
-using MediaBrowser.Common.Net;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Entities.TV;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Logging;
-using System;
-using System.Globalization;
-using System.IO;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-using System.Xml;
-
-namespace MediaBrowser.Controller.Providers.TV
-{
- class FanArtTvProvider : FanartBaseProvider
- {
- protected string FanArtBaseUrl = "http://api.fanart.tv/webservice/series/{0}/{1}/xml/all/1/1";
-
- internal static FanArtTvProvider Current { get; private set; }
-
- /// <summary>
- /// Gets the HTTP client.
- /// </summary>
- /// <value>The HTTP client.</value>
- protected IHttpClient HttpClient { get; private set; }
-
- private readonly IProviderManager _providerManager;
-
- public FanArtTvProvider(IHttpClient httpClient, ILogManager logManager, IServerConfigurationManager configurationManager, IProviderManager providerManager)
- : base(logManager, configurationManager)
- {
- if (httpClient == null)
- {
- throw new ArgumentNullException("httpClient");
- }
- HttpClient = httpClient;
- _providerManager = providerManager;
- Current = this;
- }
-
- public override bool Supports(BaseItem item)
- {
- return item is Series;
- }
-
- /// <summary>
- /// Needses the refresh internal.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="providerInfo">The provider info.</param>
- /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
- protected override bool NeedsRefreshInternal(BaseItem item, BaseProviderInfo providerInfo)
- {
- if (string.IsNullOrEmpty(item.GetProviderId(MetadataProviders.Tvdb)))
- {
- return false;
- }
-
- if (!ConfigurationManager.Configuration.DownloadSeriesImages.Art &&
- !ConfigurationManager.Configuration.DownloadSeriesImages.Logo &&
- !ConfigurationManager.Configuration.DownloadSeriesImages.Thumb &&
- !ConfigurationManager.Configuration.DownloadSeriesImages.Backdrops &&
- !ConfigurationManager.Configuration.DownloadSeriesImages.Banner)
- {
- return false;
- }
-
- if (item.HasImage(ImageType.Art) &&
- item.HasImage(ImageType.Logo) &&
- item.HasImage(ImageType.Banner) &&
- item.HasImage(ImageType.Thumb) &&
- item.BackdropImagePaths.Count > 0)
- {
- return false;
- }
-
- if (providerInfo.Data != GetComparisonData(item.GetProviderId(MetadataProviders.Tvdb)))
- {
- return true;
- }
-
- return base.NeedsRefreshInternal(item, providerInfo);
- }
-
- /// <summary>
- /// Gets the comparison data.
- /// </summary>
- /// <returns>Guid.</returns>
- private Guid GetComparisonData(string id)
- {
- if (!string.IsNullOrEmpty(id))
- {
- // Process images
- var path = GetSeriesDataPath(ConfigurationManager.ApplicationPaths, id);
-
- var files = new DirectoryInfo(path)
- .EnumerateFiles("*.xml", SearchOption.TopDirectoryOnly)
- .Select(i => i.FullName + i.LastWriteTimeUtc.Ticks)
- .ToArray();
-
- if (files.Length > 0)
- {
- return string.Join(string.Empty, files).GetMD5();
- }
- }
-
- return Guid.Empty;
- }
-
- /// <summary>
- /// Gets a value indicating whether [refresh on version change].
- /// </summary>
- /// <value><c>true</c> if [refresh on version change]; otherwise, <c>false</c>.</value>
- protected override bool RefreshOnVersionChange
- {
- get
- {
- return true;
- }
- }
-
- /// <summary>
- /// Gets the provider version.
- /// </summary>
- /// <value>The provider version.</value>
- protected override string ProviderVersion
- {
- get
- {
- return "1";
- }
- }
-
- /// <summary>
- /// Gets the series data path.
- /// </summary>
- /// <param name="appPaths">The app paths.</param>
- /// <param name="seriesId">The series id.</param>
- /// <returns>System.String.</returns>
- internal static string GetSeriesDataPath(IApplicationPaths appPaths, string seriesId)
- {
- var seriesDataPath = Path.Combine(GetSeriesDataPath(appPaths), seriesId);
-
- if (!Directory.Exists(seriesDataPath))
- {
- Directory.CreateDirectory(seriesDataPath);
- }
-
- return seriesDataPath;
- }
-
- /// <summary>
- /// Gets the series data path.
- /// </summary>
- /// <param name="appPaths">The app paths.</param>
- /// <returns>System.String.</returns>
- internal static string GetSeriesDataPath(IApplicationPaths appPaths)
- {
- var dataPath = Path.Combine(appPaths.DataPath, "fanart-tv");
-
- if (!Directory.Exists(dataPath))
- {
- Directory.CreateDirectory(dataPath);
- }
-
- return dataPath;
- }
-
- protected readonly CultureInfo UsCulture = new CultureInfo("en-US");
-
- public override async Task<bool> FetchAsync(BaseItem item, bool force, CancellationToken cancellationToken)
- {
- cancellationToken.ThrowIfCancellationRequested();
-
- BaseProviderInfo data;
-
- if (!item.ProviderData.TryGetValue(Id, out data))
- {
- data = new BaseProviderInfo();
- item.ProviderData[Id] = data;
- }
-
- var seriesId = item.GetProviderId(MetadataProviders.Tvdb);
-
- var seriesDataPath = GetSeriesDataPath(ConfigurationManager.ApplicationPaths, seriesId);
- var xmlPath = Path.Combine(seriesDataPath, "fanart.xml");
-
- // Only download the xml if it doesn't already exist. The prescan task will take care of getting updates
- if (!File.Exists(xmlPath))
- {
- await DownloadSeriesXml(seriesDataPath, seriesId, cancellationToken).ConfigureAwait(false);
- }
-
- if (File.Exists(xmlPath))
- {
- await FetchFromXml(item, xmlPath, cancellationToken).ConfigureAwait(false);
- }
-
- data.Data = GetComparisonData(item.GetProviderId(MetadataProviders.Tvdb));
- SetLastRefreshed(item, DateTime.UtcNow);
-
- return true;
- }
-
- /// <summary>
- /// Fetches from XML.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="xmlFilePath">The XML file path.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- private async Task FetchFromXml(BaseItem item, string xmlFilePath, CancellationToken cancellationToken)
- {
- var doc = new XmlDocument();
- doc.Load(xmlFilePath);
-
- cancellationToken.ThrowIfCancellationRequested();
-
- var language = ConfigurationManager.Configuration.PreferredMetadataLanguage.ToLower();
-
- var hd = ConfigurationManager.Configuration.DownloadHDFanArt ? "hdtv" : "clear";
- if (ConfigurationManager.Configuration.DownloadSeriesImages.Logo && !item.HasImage(ImageType.Logo))
- {
- var node = doc.SelectSingleNode("//fanart/series/" + hd + "logos/" + hd + "logo[@lang = \"" + language + "\"]/@url") ??
- doc.SelectSingleNode("//fanart/series/clearlogos/clearlogo[@lang = \"" + language + "\"]/@url") ??
- doc.SelectSingleNode("//fanart/series/" + hd + "logos/" + hd + "logo/@url") ??
- doc.SelectSingleNode("//fanart/series/clearlogos/clearlogo/@url");
- var path = node != null ? node.Value : null;
- if (!string.IsNullOrEmpty(path))
- {
- item.SetImage(ImageType.Logo, await _providerManager.DownloadAndSaveImage(item, path, LogoFile, ConfigurationManager.Configuration.SaveLocalMeta, FanArtResourcePool, cancellationToken).ConfigureAwait(false));
- }
- }
-
- cancellationToken.ThrowIfCancellationRequested();
-
- hd = ConfigurationManager.Configuration.DownloadHDFanArt ? "hd" : "";
- if (ConfigurationManager.Configuration.DownloadSeriesImages.Art && !item.HasImage(ImageType.Art))
- {
- var node = doc.SelectSingleNode("//fanart/series/" + hd + "cleararts/" + hd + "clearart[@lang = \"" + language + "\"]/@url") ??
- doc.SelectSingleNode("//fanart/series/cleararts/clearart[@lang = \"" + language + "\"]/@url") ??
- doc.SelectSingleNode("//fanart/series/" + hd + "cleararts/" + hd + "clearart/@url") ??
- doc.SelectSingleNode("//fanart/series/cleararts/clearart/@url");
- var path = node != null ? node.Value : null;
- if (!string.IsNullOrEmpty(path))
- {
- item.SetImage(ImageType.Art, await _providerManager.DownloadAndSaveImage(item, path, ArtFile, ConfigurationManager.Configuration.SaveLocalMeta, FanArtResourcePool, cancellationToken).ConfigureAwait(false));
- }
- }
-
- cancellationToken.ThrowIfCancellationRequested();
-
- if (ConfigurationManager.Configuration.DownloadSeriesImages.Thumb && !item.HasImage(ImageType.Thumb))
- {
- var node = doc.SelectSingleNode("//fanart/series/tvthumbs/tvthumb[@lang = \"" + language + "\"]/@url") ??
- doc.SelectSingleNode("//fanart/series/tvthumbs/tvthumb/@url");
- var path = node != null ? node.Value : null;
- if (!string.IsNullOrEmpty(path))
- {
- item.SetImage(ImageType.Thumb, await _providerManager.DownloadAndSaveImage(item, path, ThumbFile, ConfigurationManager.Configuration.SaveLocalMeta, FanArtResourcePool, cancellationToken).ConfigureAwait(false));
- }
- }
-
- if (ConfigurationManager.Configuration.DownloadSeriesImages.Banner && !item.HasImage(ImageType.Banner))
- {
- var node = doc.SelectSingleNode("//fanart/series/tbbanners/tvbanner[@lang = \"" + language + "\"]/@url") ??
- doc.SelectSingleNode("//fanart/series/tbbanners/tvbanner/@url");
- var path = node != null ? node.Value : null;
- if (!string.IsNullOrEmpty(path))
- {
- item.SetImage(ImageType.Banner, await _providerManager.DownloadAndSaveImage(item, path, BannerFile, ConfigurationManager.Configuration.SaveLocalMeta, FanArtResourcePool, cancellationToken).ConfigureAwait(false));
- }
- }
-
- if (ConfigurationManager.Configuration.DownloadMovieImages.Backdrops && item.BackdropImagePaths.Count == 0)
- {
- var nodes = doc.SelectNodes("//fanart/series/showbackgrounds//@url");
-
- if (nodes != null)
- {
- var numBackdrops = item.BackdropImagePaths.Count;
-
- foreach (XmlNode node in nodes)
- {
- var path = node.Value;
-
- if (!string.IsNullOrEmpty(path))
- {
- item.BackdropImagePaths.Add(await _providerManager.DownloadAndSaveImage(item, path, ("backdrop" + (numBackdrops > 0 ? numBackdrops.ToString(UsCulture) : "") + ".jpg"), ConfigurationManager.Configuration.SaveLocalMeta, FanArtResourcePool, cancellationToken).ConfigureAwait(false));
-
- numBackdrops++;
-
- if (item.BackdropImagePaths.Count >= ConfigurationManager.Configuration.MaxBackdrops) break;
- }
- }
-
- }
- }
-
- }
-
- /// <summary>
- /// Downloads the series XML.
- /// </summary>
- /// <param name="seriesDataPath">The series data path.</param>
- /// <param name="tvdbId">The TVDB id.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- internal async Task DownloadSeriesXml(string seriesDataPath, string tvdbId, CancellationToken cancellationToken)
- {
- cancellationToken.ThrowIfCancellationRequested();
-
- string url = string.Format(FanArtBaseUrl, ApiKey, tvdbId);
-
- var xmlPath = Path.Combine(seriesDataPath, "fanart.xml");
-
- using (var response = await HttpClient.Get(new HttpRequestOptions
- {
- Url = url,
- ResourcePool = FanArtResourcePool,
- CancellationToken = cancellationToken
-
- }).ConfigureAwait(false))
- {
- using (var xmlFileStream = new FileStream(xmlPath, FileMode.Create, FileAccess.Write, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, FileOptions.Asynchronous))
- {
- await response.CopyToAsync(xmlFileStream).ConfigureAwait(false);
- }
- }
- }
-
- }
-}
diff --git a/MediaBrowser.Controller/Providers/TV/FanArtTvUpdatesPrescanTask.cs b/MediaBrowser.Controller/Providers/TV/FanArtTvUpdatesPrescanTask.cs
deleted file mode 100644
index 84de5140e..000000000
--- a/MediaBrowser.Controller/Providers/TV/FanArtTvUpdatesPrescanTask.cs
+++ /dev/null
@@ -1,200 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.IO;
-using System.Linq;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Common.Net;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.Providers.Music;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.Net;
-using MediaBrowser.Model.Serialization;
-
-namespace MediaBrowser.Controller.Providers.TV
-{
- class FanArtTvUpdatesPrescanTask : ILibraryPrescanTask
- {
- private const string UpdatesUrl = "http://api.fanart.tv/webservice/newtv/{0}/{1}/";
-
- /// <summary>
- /// The _HTTP client
- /// </summary>
- private readonly IHttpClient _httpClient;
- /// <summary>
- /// The _logger
- /// </summary>
- private readonly ILogger _logger;
- /// <summary>
- /// The _config
- /// </summary>
- private readonly IServerConfigurationManager _config;
- private readonly IJsonSerializer _jsonSerializer;
-
- private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
-
- public FanArtTvUpdatesPrescanTask(IJsonSerializer jsonSerializer, IServerConfigurationManager config, ILogger logger, IHttpClient httpClient)
- {
- _jsonSerializer = jsonSerializer;
- _config = config;
- _logger = logger;
- _httpClient = httpClient;
- }
-
- /// <summary>
- /// Runs the specified progress.
- /// </summary>
- /// <param name="progress">The progress.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- public async Task Run(IProgress<double> progress, CancellationToken cancellationToken)
- {
- if (!_config.Configuration.EnableInternetProviders)
- {
- progress.Report(100);
- return;
- }
-
- var path = FanArtTvProvider.GetSeriesDataPath(_config.CommonApplicationPaths);
-
- var timestampFile = Path.Combine(path, "time.txt");
-
- var timestampFileInfo = new FileInfo(timestampFile);
-
- // Don't check for tvdb updates anymore frequently than 24 hours
- if (timestampFileInfo.Exists && (DateTime.UtcNow - timestampFileInfo.LastWriteTimeUtc).TotalDays < 1)
- {
- return;
- }
-
- // Find out the last time we queried for updates
- var lastUpdateTime = timestampFileInfo.Exists ? File.ReadAllText(timestampFile, Encoding.UTF8) : string.Empty;
-
- var existingDirectories = Directory.EnumerateDirectories(path).Select(Path.GetFileName).ToList();
-
- // If this is our first time, don't do any updates and just record the timestamp
- if (!string.IsNullOrEmpty(lastUpdateTime))
- {
- var seriesToUpdate = await GetSeriesIdsToUpdate(existingDirectories, lastUpdateTime, cancellationToken).ConfigureAwait(false);
-
- progress.Report(5);
-
- await UpdateSeries(seriesToUpdate, path, progress, cancellationToken).ConfigureAwait(false);
- }
-
- var newUpdateTime = Convert.ToInt64(DateTimeToUnixTimestamp(DateTime.UtcNow)).ToString(UsCulture);
-
- File.WriteAllText(timestampFile, newUpdateTime, Encoding.UTF8);
-
- progress.Report(100);
- }
-
- /// <summary>
- /// Gets the series ids to update.
- /// </summary>
- /// <param name="existingSeriesIds">The existing series ids.</param>
- /// <param name="lastUpdateTime">The last update time.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task{IEnumerable{System.String}}.</returns>
- private async Task<IEnumerable<string>> GetSeriesIdsToUpdate(IEnumerable<string> existingSeriesIds, string lastUpdateTime, CancellationToken cancellationToken)
- {
- // First get last time
- using (var stream = await _httpClient.Get(new HttpRequestOptions
- {
- Url = string.Format(UpdatesUrl, FanartBaseProvider.ApiKey, lastUpdateTime),
- CancellationToken = cancellationToken,
- EnableHttpCompression = true,
- ResourcePool = FanartBaseProvider.FanArtResourcePool
-
- }).ConfigureAwait(false))
- {
- // If empty fanart will return a string of "null", rather than an empty list
- using (var reader = new StreamReader(stream))
- {
- var json = await reader.ReadToEndAsync().ConfigureAwait(false);
-
- if (string.Equals(json, "null", StringComparison.OrdinalIgnoreCase))
- {
- return new List<string>();
- }
-
- var updates = _jsonSerializer.DeserializeFromString<List<FanArtUpdatesPrescanTask.FanArtUpdate>>(json);
-
- return updates.Select(i => i.id).Where(i => existingSeriesIds.Contains(i, StringComparer.OrdinalIgnoreCase));
- }
- }
- }
-
- /// <summary>
- /// Updates the series.
- /// </summary>
- /// <param name="idList">The id list.</param>
- /// <param name="seriesDataPath">The artists data path.</param>
- /// <param name="progress">The progress.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- private async Task UpdateSeries(IEnumerable<string> idList, string seriesDataPath, IProgress<double> progress, CancellationToken cancellationToken)
- {
- var list = idList.ToList();
- var numComplete = 0;
-
- foreach (var id in list)
- {
- try
- {
- await UpdateSeries(id, seriesDataPath, cancellationToken).ConfigureAwait(false);
- }
- catch (HttpException ex)
- {
- // Already logged at lower levels, but don't fail the whole operation, unless something other than a timeout
- if (!ex.IsTimedOut)
- {
- throw;
- }
- }
-
- numComplete++;
- double percent = numComplete;
- percent /= list.Count;
- percent *= 95;
-
- progress.Report(percent + 5);
- }
- }
-
- private Task UpdateSeries(string tvdbId, string seriesDataPath, CancellationToken cancellationToken)
- {
- _logger.Info("Updating series " + tvdbId);
-
- seriesDataPath = Path.Combine(seriesDataPath, tvdbId);
-
- if (!Directory.Exists(seriesDataPath))
- {
- Directory.CreateDirectory(seriesDataPath);
- }
-
- return FanArtTvProvider.Current.DownloadSeriesXml(seriesDataPath, tvdbId, cancellationToken);
- }
-
- /// <summary>
- /// Dates the time to unix timestamp.
- /// </summary>
- /// <param name="dateTime">The date time.</param>
- /// <returns>System.Double.</returns>
- private static double DateTimeToUnixTimestamp(DateTime dateTime)
- {
- return (dateTime - new DateTime(1970, 1, 1).ToUniversalTime()).TotalSeconds;
- }
-
- public class FanArtUpdate
- {
- public string id { get; set; }
- public string name { get; set; }
- public string new_images { get; set; }
- public string total_images { get; set; }
- }
- }
-}
diff --git a/MediaBrowser.Controller/Providers/TV/RemoteEpisodeProvider.cs b/MediaBrowser.Controller/Providers/TV/RemoteEpisodeProvider.cs
deleted file mode 100644
index 918930962..000000000
--- a/MediaBrowser.Controller/Providers/TV/RemoteEpisodeProvider.cs
+++ /dev/null
@@ -1,367 +0,0 @@
-using MediaBrowser.Common.Extensions;
-using MediaBrowser.Common.Net;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Entities.TV;
-using MediaBrowser.Controller.Extensions;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.Net;
-using System;
-using System.IO;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-using System.Xml;
-
-namespace MediaBrowser.Controller.Providers.TV
-{
-
- /// <summary>
- /// Class RemoteEpisodeProvider
- /// </summary>
- class RemoteEpisodeProvider : BaseMetadataProvider
- {
- /// <summary>
- /// The _provider manager
- /// </summary>
- private readonly IProviderManager _providerManager;
-
- /// <summary>
- /// Gets the HTTP client.
- /// </summary>
- /// <value>The HTTP client.</value>
- protected IHttpClient HttpClient { get; private set; }
-
- /// <summary>
- /// Initializes a new instance of the <see cref="RemoteEpisodeProvider" /> class.
- /// </summary>
- /// <param name="httpClient">The HTTP client.</param>
- /// <param name="logManager">The log manager.</param>
- /// <param name="configurationManager">The configuration manager.</param>
- /// <param name="providerManager">The provider manager.</param>
- public RemoteEpisodeProvider(IHttpClient httpClient, ILogManager logManager, IServerConfigurationManager configurationManager, IProviderManager providerManager)
- : base(logManager, configurationManager)
- {
- HttpClient = httpClient;
- _providerManager = providerManager;
- }
-
- /// <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 Episode;
- }
-
- /// <summary>
- /// Gets the priority.
- /// </summary>
- /// <value>The priority.</value>
- public override MetadataProviderPriority Priority
- {
- get { return MetadataProviderPriority.Second; }
- }
-
- /// <summary>
- /// Gets a value indicating whether [requires internet].
- /// </summary>
- /// <value><c>true</c> if [requires internet]; otherwise, <c>false</c>.</value>
- public override bool RequiresInternet
- {
- get { return true; }
- }
-
- /// <summary>
- /// Returns true or false indicating if the provider should refresh when the contents of it's directory changes
- /// </summary>
- /// <value><c>true</c> if [refresh on file system stamp change]; otherwise, <c>false</c>.</value>
- protected override bool RefreshOnFileSystemStampChange
- {
- get
- {
- return true;
- }
- }
-
- /// <summary>
- /// Gets a value indicating whether [refresh on version change].
- /// </summary>
- /// <value><c>true</c> if [refresh on version change]; otherwise, <c>false</c>.</value>
- protected override bool RefreshOnVersionChange
- {
- get
- {
- return true;
- }
- }
-
- /// <summary>
- /// Gets the provider version.
- /// </summary>
- /// <value>The provider version.</value>
- protected override string ProviderVersion
- {
- get
- {
- return "1";
- }
- }
-
- /// <summary>
- /// Needses the refresh internal.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="providerInfo">The provider info.</param>
- /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
- protected override bool NeedsRefreshInternal(BaseItem item, BaseProviderInfo providerInfo)
- {
- if (HasLocalMeta(item))
- {
- return false;
- }
-
- if (GetComparisonData(item) != providerInfo.Data)
- {
- return true;
- }
-
- return base.NeedsRefreshInternal(item, providerInfo);
- }
-
- /// <summary>
- /// Gets the comparison data.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <returns>Guid.</returns>
- private Guid GetComparisonData(BaseItem item)
- {
- var episode = (Episode)item;
-
- var seriesId = episode.Series != null ? episode.Series.GetProviderId(MetadataProviders.Tvdb) : null;
-
- if (!string.IsNullOrEmpty(seriesId))
- {
- // Process images
- var seriesXmlPath = Path.Combine(RemoteSeriesProvider.GetSeriesDataPath(ConfigurationManager.ApplicationPaths, seriesId), ConfigurationManager.Configuration.PreferredMetadataLanguage.ToLower() + ".xml");
-
- var seriesXmlFileInfo = new FileInfo(seriesXmlPath);
-
- return GetComparisonData(seriesXmlFileInfo);
- }
-
- return Guid.Empty;
- }
-
- /// <summary>
- /// Gets the comparison data.
- /// </summary>
- /// <param name="seriesXmlFileInfo">The series XML file info.</param>
- /// <returns>Guid.</returns>
- private Guid GetComparisonData(FileInfo seriesXmlFileInfo)
- {
- var date = seriesXmlFileInfo.Exists ? seriesXmlFileInfo.LastWriteTimeUtc : DateTime.MinValue;
-
- var key = date.Ticks + seriesXmlFileInfo.FullName;
-
- return key.GetMD5();
- }
-
- /// <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 async Task<bool> FetchAsync(BaseItem item, bool force, CancellationToken cancellationToken)
- {
- if (HasLocalMeta(item))
- {
- return false;
- }
-
- cancellationToken.ThrowIfCancellationRequested();
-
- var episode = (Episode)item;
-
- var seriesId = episode.Series != null ? episode.Series.GetProviderId(MetadataProviders.Tvdb) : null;
-
- if (!string.IsNullOrEmpty(seriesId))
- {
- var seriesXmlPath = Path.Combine(RemoteSeriesProvider.GetSeriesDataPath(ConfigurationManager.ApplicationPaths, seriesId), ConfigurationManager.Configuration.PreferredMetadataLanguage.ToLower() + ".xml");
-
- var seriesXmlFileInfo = new FileInfo(seriesXmlPath);
-
- var status = ProviderRefreshStatus.Success;
-
- if (seriesXmlFileInfo.Exists)
- {
- var xmlDoc = new XmlDocument();
- xmlDoc.Load(seriesXmlPath);
-
- status = await FetchEpisodeData(xmlDoc, episode, seriesId, cancellationToken).ConfigureAwait(false);
- }
-
- BaseProviderInfo data;
- if (!item.ProviderData.TryGetValue(Id, out data))
- {
- data = new BaseProviderInfo();
- item.ProviderData[Id] = data;
- }
-
- data.Data = GetComparisonData(seriesXmlFileInfo);
-
- SetLastRefreshed(item, DateTime.UtcNow, status);
- return true;
- }
-
- Logger.Info("Episode provider not fetching because series does not have a tvdb id: " + item.Path);
- return false;
- }
-
-
- /// <summary>
- /// Fetches the episode data.
- /// </summary>
- /// <param name="seriesXml">The series XML.</param>
- /// <param name="episode">The episode.</param>
- /// <param name="seriesId">The series id.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task{System.Boolean}.</returns>
- private async Task<ProviderRefreshStatus> FetchEpisodeData(XmlDocument seriesXml, Episode episode, string seriesId, CancellationToken cancellationToken)
- {
- var status = ProviderRefreshStatus.Success;
-
- if (episode.IndexNumber == null)
- {
- return status;
- }
-
- var seasonNumber = episode.ParentIndexNumber ?? TVUtils.GetSeasonNumberFromEpisodeFile(episode.Path);
-
- if (seasonNumber == null)
- {
- return status;
- }
-
- var usingAbsoluteData = false;
-
- var episodeNode = seriesXml.SelectSingleNode("//Episode[EpisodeNumber='" + episode.IndexNumber.Value + "'][SeasonNumber='" + seasonNumber.Value + "']");
-
- if (episodeNode == null)
- {
- if (seasonNumber.Value == 1)
- {
- episodeNode = seriesXml.SelectSingleNode("//Episode[absolute_number='" + episode.IndexNumber.Value + "']");
- usingAbsoluteData = true;
- }
- }
-
- // If still null, nothing we can do
- if (episodeNode == null)
- {
- return status;
- }
-
- var doc = new XmlDocument();
- doc.LoadXml(episodeNode.OuterXml);
-
- if (!episode.HasImage(ImageType.Primary))
- {
- var p = doc.SafeGetString("//filename");
- if (p != null)
- {
- if (!Directory.Exists(episode.MetaLocation)) Directory.CreateDirectory(episode.MetaLocation);
-
- try
- {
- episode.PrimaryImagePath = await _providerManager.DownloadAndSaveImage(episode, TVUtils.BannerUrl + p, Path.GetFileName(p), ConfigurationManager.Configuration.SaveLocalMeta, RemoteSeriesProvider.Current.TvDbResourcePool, cancellationToken);
- }
- catch (HttpException)
- {
- status = ProviderRefreshStatus.CompletedWithErrors;
- }
- }
- }
-
- episode.Overview = doc.SafeGetString("//Overview");
- if (usingAbsoluteData)
- episode.IndexNumber = doc.SafeGetInt32("//absolute_number", -1);
- if (episode.IndexNumber < 0)
- episode.IndexNumber = doc.SafeGetInt32("//EpisodeNumber");
-
- episode.Name = doc.SafeGetString("//EpisodeName");
- episode.CommunityRating = doc.SafeGetSingle("//Rating", -1, 10);
- var firstAired = doc.SafeGetString("//FirstAired");
- DateTime airDate;
- if (DateTime.TryParse(firstAired, out airDate) && airDate.Year > 1850)
- {
- episode.PremiereDate = airDate.ToUniversalTime();
- episode.ProductionYear = airDate.Year;
- }
-
- episode.People.Clear();
-
- var actors = doc.SafeGetString("//GuestStars");
- if (actors != null)
- {
- foreach (var person in actors.Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries)
- .Where(i => !string.IsNullOrWhiteSpace(i))
- .Select(str => new PersonInfo { Type = PersonType.GuestStar, Name = str }))
- {
- episode.AddPerson(person);
- }
- }
-
-
- var directors = doc.SafeGetString("//Director");
- if (directors != null)
- {
- foreach (var person in directors.Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries)
- .Where(i => !string.IsNullOrWhiteSpace(i))
- .Select(str => new PersonInfo { Type = PersonType.Director, Name = str }))
- {
- episode.AddPerson(person);
- }
- }
-
-
- var writers = doc.SafeGetString("//Writer");
- if (writers != null)
- {
- foreach (var person in writers.Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries)
- .Where(i => !string.IsNullOrWhiteSpace(i))
- .Select(str => new PersonInfo { Type = PersonType.Writer, Name = str }))
- {
- episode.AddPerson(person);
- }
- }
-
- if (ConfigurationManager.Configuration.SaveLocalMeta)
- {
- if (!Directory.Exists(episode.MetaLocation)) Directory.CreateDirectory(episode.MetaLocation);
- var ms = new MemoryStream();
- doc.Save(ms);
-
- await _providerManager.SaveToLibraryFilesystem(episode, Path.Combine(episode.MetaLocation, Path.GetFileNameWithoutExtension(episode.Path) + ".xml"), ms, cancellationToken).ConfigureAwait(false);
- }
-
- return status;
- }
-
- /// <summary>
- /// Determines whether [has local meta] [the specified episode].
- /// </summary>
- /// <param name="episode">The episode.</param>
- /// <returns><c>true</c> if [has local meta] [the specified episode]; otherwise, <c>false</c>.</returns>
- private bool HasLocalMeta(BaseItem episode)
- {
- return (episode.Parent.ResolveArgs.ContainsMetaFileByName(Path.GetFileNameWithoutExtension(episode.Path) + ".xml"));
- }
- }
-}
diff --git a/MediaBrowser.Controller/Providers/TV/RemoteSeasonProvider.cs b/MediaBrowser.Controller/Providers/TV/RemoteSeasonProvider.cs
deleted file mode 100644
index 5baaf9cd5..000000000
--- a/MediaBrowser.Controller/Providers/TV/RemoteSeasonProvider.cs
+++ /dev/null
@@ -1,289 +0,0 @@
-using System.Net;
-using MediaBrowser.Common.Extensions;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Entities.TV;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Logging;
-using System;
-using System.IO;
-using System.Threading;
-using System.Threading.Tasks;
-using System.Xml;
-using MediaBrowser.Model.Net;
-
-namespace MediaBrowser.Controller.Providers.TV
-{
- /// <summary>
- /// Class RemoteSeasonProvider
- /// </summary>
- class RemoteSeasonProvider : BaseMetadataProvider
- {
- /// <summary>
- /// The _provider manager
- /// </summary>
- private readonly IProviderManager _providerManager;
-
- /// <summary>
- /// Initializes a new instance of the <see cref="RemoteSeasonProvider"/> class.
- /// </summary>
- /// <param name="logManager">The log manager.</param>
- /// <param name="configurationManager">The configuration manager.</param>
- /// <param name="providerManager">The provider manager.</param>
- /// <exception cref="System.ArgumentNullException">httpClient</exception>
- public RemoteSeasonProvider(ILogManager logManager, IServerConfigurationManager configurationManager, IProviderManager providerManager)
- : base(logManager, configurationManager)
- {
- _providerManager = providerManager;
- }
-
- /// <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 Season;
- }
-
- /// <summary>
- /// Gets the priority.
- /// </summary>
- /// <value>The priority.</value>
- public override MetadataProviderPriority Priority
- {
- // Run after fanart
- get { return MetadataProviderPriority.Fourth; }
- }
-
- /// <summary>
- /// Gets a value indicating whether [requires internet].
- /// </summary>
- /// <value><c>true</c> if [requires internet]; otherwise, <c>false</c>.</value>
- public override bool RequiresInternet
- {
- get
- {
- return true;
- }
- }
-
- /// <summary>
- /// Returns true or false indicating if the provider should refresh when the contents of it's directory changes
- /// </summary>
- /// <value><c>true</c> if [refresh on file system stamp change]; otherwise, <c>false</c>.</value>
- protected override bool RefreshOnFileSystemStampChange
- {
- get
- {
- return ConfigurationManager.Configuration.SaveLocalMeta;
- }
- }
-
- /// <summary>
- /// Gets a value indicating whether [refresh on version change].
- /// </summary>
- /// <value><c>true</c> if [refresh on version change]; otherwise, <c>false</c>.</value>
- protected override bool RefreshOnVersionChange
- {
- get
- {
- return true;
- }
- }
-
- /// <summary>
- /// Gets the provider version.
- /// </summary>
- /// <value>The provider version.</value>
- protected override string ProviderVersion
- {
- get
- {
- return "1";
- }
- }
-
- /// <summary>
- /// Needses the refresh internal.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="providerInfo">The provider info.</param>
- /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
- protected override bool NeedsRefreshInternal(BaseItem item, BaseProviderInfo providerInfo)
- {
- if (GetComparisonData(item) != providerInfo.Data)
- {
- return true;
- }
-
- return base.NeedsRefreshInternal(item, providerInfo);
- }
-
- /// <summary>
- /// Gets the comparison data.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <returns>Guid.</returns>
- private Guid GetComparisonData(BaseItem item)
- {
- var season = (Season)item;
- var seriesId = season.Series != null ? season.Series.GetProviderId(MetadataProviders.Tvdb) : null;
-
- if (!string.IsNullOrEmpty(seriesId))
- {
- // Process images
- var imagesXmlPath = Path.Combine(RemoteSeriesProvider.GetSeriesDataPath(ConfigurationManager.ApplicationPaths, seriesId), "banners.xml");
-
- var imagesFileInfo = new FileInfo(imagesXmlPath);
-
- return GetComparisonData(imagesFileInfo);
- }
-
- return Guid.Empty;
- }
-
- /// <summary>
- /// Gets the comparison data.
- /// </summary>
- /// <param name="imagesFileInfo">The images file info.</param>
- /// <returns>Guid.</returns>
- private Guid GetComparisonData(FileInfo imagesFileInfo)
- {
- var date = imagesFileInfo.Exists ? imagesFileInfo.LastWriteTimeUtc : DateTime.MinValue;
-
- var key = date.Ticks + imagesFileInfo.FullName;
-
- return key.GetMD5();
- }
-
- /// <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 async Task<bool> FetchAsync(BaseItem item, bool force, CancellationToken cancellationToken)
- {
- cancellationToken.ThrowIfCancellationRequested();
-
- var season = (Season)item;
-
- var seriesId = season.Series != null ? season.Series.GetProviderId(MetadataProviders.Tvdb) : null;
-
- if (!string.IsNullOrEmpty(seriesId))
- {
- // Process images
- var imagesXmlPath = Path.Combine(RemoteSeriesProvider.GetSeriesDataPath(ConfigurationManager.ApplicationPaths, seriesId), "banners.xml");
-
- var imagesFileInfo = new FileInfo(imagesXmlPath);
-
- if (imagesFileInfo.Exists)
- {
- if (!season.HasImage(ImageType.Primary) || !season.HasImage(ImageType.Banner) || season.BackdropImagePaths.Count == 0)
- {
- var xmlDoc = new XmlDocument();
- xmlDoc.Load(imagesXmlPath);
-
- await FetchImages(season, xmlDoc, cancellationToken).ConfigureAwait(false);
- }
- }
-
- BaseProviderInfo data;
- if (!item.ProviderData.TryGetValue(Id, out data))
- {
- data = new BaseProviderInfo();
- item.ProviderData[Id] = data;
- }
-
- data.Data = GetComparisonData(imagesFileInfo);
-
- SetLastRefreshed(item, DateTime.UtcNow);
- return true;
- }
-
- return false;
- }
-
- /// <summary>
- /// Fetches the images.
- /// </summary>
- /// <param name="season">The season.</param>
- /// <param name="images">The images.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- private async Task FetchImages(Season season, XmlDocument images, CancellationToken cancellationToken)
- {
- var seasonNumber = season.IndexNumber ?? -1;
-
- if (seasonNumber == -1)
- {
- return;
- }
-
- if (!season.HasImage(ImageType.Primary))
- {
- var n = images.SelectSingleNode("//Banner[BannerType='season'][BannerType2='season'][Season='" + seasonNumber + "'][Language='" + ConfigurationManager.Configuration.PreferredMetadataLanguage + "']") ??
- images.SelectSingleNode("//Banner[BannerType='season'][BannerType2='season'][Season='" + seasonNumber + "'][Language='en']");
- if (n != null)
- {
- n = n.SelectSingleNode("./BannerPath");
-
- if (n != null)
- season.PrimaryImagePath = await _providerManager.DownloadAndSaveImage(season, TVUtils.BannerUrl + n.InnerText, "folder" + Path.GetExtension(n.InnerText), ConfigurationManager.Configuration.SaveLocalMeta, RemoteSeriesProvider.Current.TvDbResourcePool, cancellationToken).ConfigureAwait(false);
- }
- }
-
- if (ConfigurationManager.Configuration.DownloadSeasonImages.Banner && !season.HasImage(ImageType.Banner))
- {
- var n = images.SelectSingleNode("//Banner[BannerType='season'][BannerType2='seasonwide'][Season='" + seasonNumber + "'][Language='" + ConfigurationManager.Configuration.PreferredMetadataLanguage + "']") ??
- images.SelectSingleNode("//Banner[BannerType='season'][BannerType2='seasonwide'][Season='" + seasonNumber + "'][Language='en']");
- if (n != null)
- {
- n = n.SelectSingleNode("./BannerPath");
- if (n != null)
- {
- try
- {
- var bannerImagePath =
- await _providerManager.DownloadAndSaveImage(season,
- TVUtils.BannerUrl + n.InnerText,
- "banner" +
- Path.GetExtension(n.InnerText),
- ConfigurationManager.Configuration.SaveLocalMeta, RemoteSeriesProvider.Current.TvDbResourcePool, cancellationToken).
- ConfigureAwait(false);
-
- season.SetImage(ImageType.Banner, bannerImagePath);
- }
- catch (HttpException ex)
- {
- Logger.ErrorException("Error downloading season banner for {0}", ex, season.Path);
-
- // Sometimes banners will come up not found even though they're reported in tvdb xml
- if (ex.StatusCode.HasValue && ex.StatusCode.Value != HttpStatusCode.NotFound)
- {
- throw;
- }
- }
- }
- }
- }
-
- if (ConfigurationManager.Configuration.DownloadSeasonImages.Backdrops && season.BackdropImagePaths.Count == 0)
- {
- var n = images.SelectSingleNode("//Banner[BannerType='fanart'][Season='" + seasonNumber + "']");
- if (n != null)
- {
- n = n.SelectSingleNode("./BannerPath");
- if (n != null)
- {
- season.BackdropImagePaths.Add(await _providerManager.DownloadAndSaveImage(season, TVUtils.BannerUrl + n.InnerText, "backdrop" + Path.GetExtension(n.InnerText), ConfigurationManager.Configuration.SaveLocalMeta, RemoteSeriesProvider.Current.TvDbResourcePool, cancellationToken).ConfigureAwait(false));
- }
- }
- }
- }
- }
-}
diff --git a/MediaBrowser.Controller/Providers/TV/RemoteSeriesProvider.cs b/MediaBrowser.Controller/Providers/TV/RemoteSeriesProvider.cs
deleted file mode 100644
index aaa76a20c..000000000
--- a/MediaBrowser.Controller/Providers/TV/RemoteSeriesProvider.cs
+++ /dev/null
@@ -1,639 +0,0 @@
-using System.Xml.Linq;
-using MediaBrowser.Common.Configuration;
-using MediaBrowser.Common.Extensions;
-using MediaBrowser.Common.Net;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Entities.TV;
-using MediaBrowser.Controller.Extensions;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.Net;
-using System;
-using System.Globalization;
-using System.IO;
-using System.Linq;
-using System.Net;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-using System.Xml;
-
-namespace MediaBrowser.Controller.Providers.TV
-{
- /// <summary>
- /// Class RemoteSeriesProvider
- /// </summary>
- class RemoteSeriesProvider : BaseMetadataProvider, IDisposable
- {
- /// <summary>
- /// The _provider manager
- /// </summary>
- private readonly IProviderManager _providerManager;
-
- /// <summary>
- /// The tv db
- /// </summary>
- internal readonly SemaphoreSlim TvDbResourcePool = new SemaphoreSlim(2, 2);
-
- /// <summary>
- /// Gets the current.
- /// </summary>
- /// <value>The current.</value>
- internal static RemoteSeriesProvider Current { get; private set; }
-
- /// <summary>
- /// The _zip client
- /// </summary>
- private readonly IZipClient _zipClient;
-
- /// <summary>
- /// Gets the HTTP client.
- /// </summary>
- /// <value>The HTTP client.</value>
- protected IHttpClient HttpClient { get; private set; }
-
- /// <summary>
- /// Initializes a new instance of the <see cref="RemoteSeriesProvider" /> class.
- /// </summary>
- /// <param name="httpClient">The HTTP client.</param>
- /// <param name="logManager">The log manager.</param>
- /// <param name="configurationManager">The configuration manager.</param>
- /// <param name="providerManager">The provider manager.</param>
- /// <param name="zipClient">The zip client.</param>
- /// <exception cref="System.ArgumentNullException">httpClient</exception>
- public RemoteSeriesProvider(IHttpClient httpClient, ILogManager logManager, IServerConfigurationManager configurationManager, IProviderManager providerManager, IZipClient zipClient)
- : base(logManager, configurationManager)
- {
- if (httpClient == null)
- {
- throw new ArgumentNullException("httpClient");
- }
- HttpClient = httpClient;
- _providerManager = providerManager;
- _zipClient = zipClient;
- Current = this;
- }
-
- /// <summary>
- /// Releases unmanaged and - optionally - managed resources.
- /// </summary>
- /// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
- protected virtual void Dispose(bool dispose)
- {
- if (dispose)
- {
- TvDbResourcePool.Dispose();
- }
- }
-
- /// <summary>
- /// The root URL
- /// </summary>
- private const string RootUrl = "http://www.thetvdb.com/api/";
- /// <summary>
- /// The series query
- /// </summary>
- private const string SeriesQuery = "GetSeries.php?seriesname={0}";
- /// <summary>
- /// The series get zip
- /// </summary>
- private const string SeriesGetZip = "http://www.thetvdb.com/api/{0}/series/{1}/all/{2}.zip";
-
- /// <summary>
- /// The LOCA l_ MET a_ FIL e_ NAME
- /// </summary>
- protected const string LocalMetaFileName = "Series.xml";
-
- /// <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 Series;
- }
-
- /// <summary>
- /// Gets the priority.
- /// </summary>
- /// <value>The priority.</value>
- public override MetadataProviderPriority Priority
- {
- get { return MetadataProviderPriority.Second; }
- }
-
- /// <summary>
- /// Gets a value indicating whether [requires internet].
- /// </summary>
- /// <value><c>true</c> if [requires internet]; otherwise, <c>false</c>.</value>
- public override bool RequiresInternet
- {
- get
- {
- return true;
- }
- }
-
- /// <summary>
- /// Gets a value indicating whether [refresh on version change].
- /// </summary>
- /// <value><c>true</c> if [refresh on version change]; otherwise, <c>false</c>.</value>
- protected override bool RefreshOnVersionChange
- {
- get
- {
- return true;
- }
- }
-
- /// <summary>
- /// Gets the provider version.
- /// </summary>
- /// <value>The provider version.</value>
- protected override string ProviderVersion
- {
- get
- {
- return "1";
- }
- }
-
- /// <summary>
- /// Needses the refresh internal.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="providerInfo">The provider info.</param>
- /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
- protected override bool NeedsRefreshInternal(BaseItem item, BaseProviderInfo providerInfo)
- {
- // Refresh even if local metadata exists because we need episode infos
- if (GetComparisonData(item) != providerInfo.Data)
- {
- return true;
- }
-
- return base.NeedsRefreshInternal(item, providerInfo);
- }
-
- /// <summary>
- /// Gets the comparison data.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <returns>Guid.</returns>
- private Guid GetComparisonData(BaseItem item)
- {
- var seriesId = item.GetProviderId(MetadataProviders.Tvdb);
-
- if (!string.IsNullOrEmpty(seriesId))
- {
- // Process images
- var path = GetSeriesDataPath(ConfigurationManager.ApplicationPaths, seriesId);
-
- var files = new DirectoryInfo(path)
- .EnumerateFiles("*.xml", SearchOption.TopDirectoryOnly)
- .Select(i => i.FullName + i.LastWriteTimeUtc.Ticks)
- .ToArray();
-
- if (files.Length > 0)
- {
- return string.Join(string.Empty, files).GetMD5();
- }
- }
-
- return Guid.Empty;
- }
-
- /// <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 async Task<bool> FetchAsync(BaseItem item, bool force, CancellationToken cancellationToken)
- {
- cancellationToken.ThrowIfCancellationRequested();
-
- var series = (Series)item;
-
- var seriesId = series.GetProviderId(MetadataProviders.Tvdb);
-
- if (string.IsNullOrEmpty(seriesId))
- {
- seriesId = await GetSeriesId(series, cancellationToken);
- }
-
- cancellationToken.ThrowIfCancellationRequested();
-
- if (!string.IsNullOrEmpty(seriesId))
- {
- series.SetProviderId(MetadataProviders.Tvdb, seriesId);
-
- var seriesDataPath = GetSeriesDataPath(ConfigurationManager.ApplicationPaths, seriesId);
-
- await FetchSeriesData(series, seriesId, seriesDataPath, cancellationToken).ConfigureAwait(false);
- }
-
- BaseProviderInfo data;
- if (!item.ProviderData.TryGetValue(Id, out data))
- {
- data = new BaseProviderInfo();
- item.ProviderData[Id] = data;
- }
-
- data.Data = GetComparisonData(item);
-
- SetLastRefreshed(item, DateTime.UtcNow);
- return true;
- }
-
- /// <summary>
- /// Fetches the series data.
- /// </summary>
- /// <param name="series">The series.</param>
- /// <param name="seriesId">The series id.</param>
- /// <param name="seriesDataPath">The series data path.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task{System.Boolean}.</returns>
- private async Task FetchSeriesData(Series series, string seriesId, string seriesDataPath, CancellationToken cancellationToken)
- {
- var files = Directory.EnumerateFiles(seriesDataPath, "*.xml", SearchOption.TopDirectoryOnly).Select(Path.GetFileName).ToArray();
-
- var seriesXmlFilename = ConfigurationManager.Configuration.PreferredMetadataLanguage.ToLower() + ".xml";
-
- // Only download if not already there
- // The prescan task will take care of updates so we don't need to re-download here
- if (!files.Contains("banners.xml", StringComparer.OrdinalIgnoreCase) || !files.Contains("actors.xml", StringComparer.OrdinalIgnoreCase) || !files.Contains(seriesXmlFilename, StringComparer.OrdinalIgnoreCase))
- {
- await DownloadSeriesZip(seriesId, seriesDataPath, cancellationToken).ConfigureAwait(false);
- }
-
- // Only examine the main info if there's no local metadata
- if (!HasLocalMeta(series))
- {
- var seriesXmlPath = Path.Combine(seriesDataPath, seriesXmlFilename);
- var actorsXmlPath = Path.Combine(seriesDataPath, "actors.xml");
-
- var seriesDoc = new XmlDocument();
- seriesDoc.Load(seriesXmlPath);
-
- FetchMainInfo(series, seriesDoc);
-
- var actorsDoc = new XmlDocument();
- actorsDoc.Load(actorsXmlPath);
-
- FetchActors(series, actorsDoc, seriesDoc);
-
- if (ConfigurationManager.Configuration.SaveLocalMeta)
- {
- var ms = new MemoryStream();
- seriesDoc.Save(ms);
-
- await _providerManager.SaveToLibraryFilesystem(series, Path.Combine(series.MetaLocation, LocalMetaFileName), ms, cancellationToken).ConfigureAwait(false);
- }
- }
- }
-
- /// <summary>
- /// Downloads the series zip.
- /// </summary>
- /// <param name="seriesId">The series id.</param>
- /// <param name="seriesDataPath">The series data path.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- internal async Task DownloadSeriesZip(string seriesId, string seriesDataPath, CancellationToken cancellationToken)
- {
- var url = string.Format(SeriesGetZip, TVUtils.TvdbApiKey, seriesId, ConfigurationManager.Configuration.PreferredMetadataLanguage);
-
- using (var zipStream = await HttpClient.Get(new HttpRequestOptions
- {
- Url = url,
- ResourcePool = TvDbResourcePool,
- CancellationToken = cancellationToken
-
- }).ConfigureAwait(false))
- {
- // Copy to memory stream because we need a seekable stream
- using (var ms = new MemoryStream())
- {
- await zipStream.CopyToAsync(ms).ConfigureAwait(false);
-
- ms.Position = 0;
- _zipClient.ExtractAll(ms, seriesDataPath, true);
- }
- }
- }
-
- /// <summary>
- /// Gets the series data path.
- /// </summary>
- /// <param name="appPaths">The app paths.</param>
- /// <param name="seriesId">The series id.</param>
- /// <returns>System.String.</returns>
- internal static string GetSeriesDataPath(IApplicationPaths appPaths, string seriesId)
- {
- var seriesDataPath = Path.Combine(GetSeriesDataPath(appPaths), seriesId);
-
- if (!Directory.Exists(seriesDataPath))
- {
- Directory.CreateDirectory(seriesDataPath);
- }
-
- return seriesDataPath;
- }
-
- /// <summary>
- /// Gets the series data path.
- /// </summary>
- /// <param name="appPaths">The app paths.</param>
- /// <returns>System.String.</returns>
- internal static string GetSeriesDataPath(IApplicationPaths appPaths)
- {
- var dataPath = Path.Combine(appPaths.DataPath, "tvdb");
-
- if (!Directory.Exists(dataPath))
- {
- Directory.CreateDirectory(dataPath);
- }
-
- return dataPath;
- }
-
- /// <summary>
- /// Fetches the main info.
- /// </summary>
- /// <param name="series">The series.</param>
- /// <param name="doc">The doc.</param>
- private void FetchMainInfo(Series series, XmlDocument doc)
- {
- series.Name = doc.SafeGetString("//SeriesName");
- series.Overview = doc.SafeGetString("//Overview");
- series.CommunityRating = doc.SafeGetSingle("//Rating", 0, 10);
- series.AirDays = TVUtils.GetAirDays(doc.SafeGetString("//Airs_DayOfWeek"));
- series.AirTime = doc.SafeGetString("//Airs_Time");
- SeriesStatus seriesStatus;
- if(Enum.TryParse(doc.SafeGetString("//Status"), true, out seriesStatus))
- series.Status = seriesStatus;
- series.PremiereDate = doc.SafeGetDateTime("//FirstAired");
- if (series.PremiereDate.HasValue)
- series.ProductionYear = series.PremiereDate.Value.Year;
- //Runtime is in minutes, and 1 tick = 10000 ms
- series.RunTimeTicks = doc.SafeGetInt32("//Runtime") * 6;
-
- string s = doc.SafeGetString("//Network");
-
- if (!string.IsNullOrWhiteSpace(s))
- {
- series.Studios.Clear();
-
- foreach (var studio in s.Trim().Split('|'))
- {
- series.AddStudio(studio);
- }
- }
-
- series.OfficialRating = doc.SafeGetString("//ContentRating");
-
- string g = doc.SafeGetString("//Genre");
-
- if (g != null)
- {
- string[] genres = g.Trim('|').Split('|');
- if (g.Length > 0)
- {
- series.Genres.Clear();
-
- foreach (var genre in genres)
- {
- series.AddGenre(genre);
- }
- }
- }
-
- if (series.Status == SeriesStatus.Ended) {
-
- var document = XDocument.Load(new XmlNodeReader(doc));
- var dates = document.Descendants("Episode").Where(x => {
- var seasonNumber = x.Element("SeasonNumber");
- var firstAired = x.Element("FirstAired");
- return firstAired != null && seasonNumber != null && (!string.IsNullOrEmpty(seasonNumber.Value) && seasonNumber.Value != "0") && !string.IsNullOrEmpty(firstAired.Value);
- }).Select(x => {
- DateTime? date = null;
- DateTime tempDate;
- var firstAired = x.Element("FirstAired");
- if (firstAired != null && DateTime.TryParse(firstAired.Value, out tempDate))
- {
- date = tempDate;
- }
- return date;
- }).ToList();
- if(dates.Any(x=>x.HasValue))
- series.EndDate = dates.Where(x => x.HasValue).Max();
- }
- }
-
- /// <summary>
- /// Fetches the actors.
- /// </summary>
- /// <param name="series">The series.</param>
- /// <param name="actorsDoc">The actors doc.</param>
- /// <param name="seriesDoc">The seriesDoc.</param>
- /// <returns>Task.</returns>
- private void FetchActors(Series series, XmlDocument actorsDoc, XmlDocument seriesDoc)
- {
- XmlNode actorsNode = null;
- if (ConfigurationManager.Configuration.SaveLocalMeta)
- {
- //add to the main seriesDoc for saving
- var seriesNode = seriesDoc.SelectSingleNode("//Series");
- if (seriesNode != null)
- {
- actorsNode = seriesDoc.CreateNode(XmlNodeType.Element, "Persons", null);
- seriesNode.AppendChild(actorsNode);
- }
- }
-
- var xmlNodeList = actorsDoc.SelectNodes("Actors/Actor");
-
- if (xmlNodeList != null)
- {
- series.People.Clear();
-
- foreach (XmlNode p in xmlNodeList)
- {
- string actorName = p.SafeGetString("Name");
- string actorRole = p.SafeGetString("Role");
- if (!string.IsNullOrWhiteSpace(actorName))
- {
- series.AddPerson(new PersonInfo { Type = PersonType.Actor, Name = actorName, Role = actorRole });
-
- if (ConfigurationManager.Configuration.SaveLocalMeta && actorsNode != null)
- {
- //create in main seriesDoc
- var personNode = seriesDoc.CreateNode(XmlNodeType.Element, "Person", null);
- foreach (XmlNode subNode in p.ChildNodes)
- personNode.AppendChild(seriesDoc.ImportNode(subNode, true));
- //need to add the type
- var typeNode = seriesDoc.CreateNode(XmlNodeType.Element, "Type", null);
- typeNode.InnerText = PersonType.Actor;
- personNode.AppendChild(typeNode);
- actorsNode.AppendChild(personNode);
- }
-
- }
- }
- }
- }
-
- /// <summary>
- /// The us culture
- /// </summary>
- protected readonly CultureInfo UsCulture = new CultureInfo("en-US");
-
- /// <summary>
- /// Determines whether [has local meta] [the specified item].
- /// </summary>
- /// <param name="item">The item.</param>
- /// <returns><c>true</c> if [has local meta] [the specified item]; otherwise, <c>false</c>.</returns>
- private bool HasLocalMeta(BaseItem item)
- {
- return item.ResolveArgs.ContainsMetaFileByName(LocalMetaFileName);
- }
-
- /// <summary>
- /// Gets the series id.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task{System.String}.</returns>
- private async Task<string> GetSeriesId(BaseItem item, CancellationToken cancellationToken)
- {
- var seriesId = item.GetProviderId(MetadataProviders.Tvdb);
- if (string.IsNullOrEmpty(seriesId))
- {
- seriesId = await FindSeries(item.Name, cancellationToken).ConfigureAwait(false);
- }
- return seriesId;
- }
-
-
- /// <summary>
- /// Finds the series.
- /// </summary>
- /// <param name="name">The name.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task{System.String}.</returns>
- public async Task<string> FindSeries(string name, CancellationToken cancellationToken)
- {
-
- //nope - search for it
- string url = string.Format(RootUrl + SeriesQuery, WebUtility.UrlEncode(name));
- var doc = new XmlDocument();
-
- using (var results = await HttpClient.Get(new HttpRequestOptions
- {
- Url = url,
- ResourcePool = TvDbResourcePool,
- CancellationToken = cancellationToken
-
- }).ConfigureAwait(false))
- {
- doc.Load(results);
- }
-
- if (doc.HasChildNodes)
- {
- XmlNodeList nodes = doc.SelectNodes("//Series");
- string comparableName = GetComparableName(name);
- if (nodes != null)
- foreach (XmlNode node in nodes)
- {
- var n = node.SelectSingleNode("./SeriesName");
- if (n != null && GetComparableName(n.InnerText) == comparableName)
- {
- n = node.SelectSingleNode("./seriesid");
- if (n != null)
- return n.InnerText;
- }
- else
- {
- if (n != null)
- Logger.Info("TVDb Provider - " + n.InnerText + " did not match " + comparableName);
- }
- }
- }
-
- Logger.Info("TVDb Provider - Could not find " + name + ". Check name on Thetvdb.org.");
- return null;
- }
-
- /// <summary>
- /// The remove
- /// </summary>
- const string remove = "\"'!`?";
- /// <summary>
- /// The spacers
- /// </summary>
- const string spacers = "/,.:;\\(){}[]+-_=–*"; // (there are not actually two - in the they are different char codes)
-
- /// <summary>
- /// Gets the name of the comparable.
- /// </summary>
- /// <param name="name">The name.</param>
- /// <returns>System.String.</returns>
- internal static string GetComparableName(string name)
- {
- name = name.ToLower();
- name = name.Normalize(NormalizationForm.FormKD);
- var sb = new StringBuilder();
- foreach (var c in name)
- {
- if ((int)c >= 0x2B0 && (int)c <= 0x0333)
- {
- // skip char modifier and diacritics
- }
- else if (remove.IndexOf(c) > -1)
- {
- // skip chars we are removing
- }
- else if (spacers.IndexOf(c) > -1)
- {
- sb.Append(" ");
- }
- else if (c == '&')
- {
- sb.Append(" and ");
- }
- else
- {
- sb.Append(c);
- }
- }
- name = sb.ToString();
- name = name.Replace(", the", "");
- name = name.Replace("the ", " ");
- name = name.Replace(" the ", " ");
-
- string prevName;
- do
- {
- prevName = name;
- name = name.Replace(" ", " ");
- } while (name.Length != prevName.Length);
-
- return name.Trim();
- }
-
- /// <summary>
- /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
- /// </summary>
- public void Dispose()
- {
- Dispose(true);
- }
- }
-}
diff --git a/MediaBrowser.Controller/Providers/TV/SeriesProviderFromXml.cs b/MediaBrowser.Controller/Providers/TV/SeriesProviderFromXml.cs
deleted file mode 100644
index 786793069..000000000
--- a/MediaBrowser.Controller/Providers/TV/SeriesProviderFromXml.cs
+++ /dev/null
@@ -1,100 +0,0 @@
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Entities.TV;
-using MediaBrowser.Model.Entities;
-using System;
-using System.IO;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Model.Logging;
-
-namespace MediaBrowser.Controller.Providers.TV
-{
- /// <summary>
- /// Class SeriesProviderFromXml
- /// </summary>
- public class SeriesProviderFromXml : BaseMetadataProvider
- {
- public SeriesProviderFromXml(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 Series && 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.ResolveArgs.GetMetaFileByPath(Path.Combine(item.MetaLocation, "series.xml"));
- 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, "series.xml"));
-
- if (metadataFile != null)
- {
- var path = metadataFile.FullName;
-
- await XmlParsingResourcePool.WaitAsync(cancellationToken).ConfigureAwait(false);
-
- try
- {
- new SeriesXmlParser(Logger).Fetch((Series)item, path, cancellationToken);
- }
- finally
- {
- XmlParsingResourcePool.Release();
- }
-
- SetLastRefreshed(item, DateTime.UtcNow);
-
- return true;
- }
-
- return false;
- }
- }
-}
diff --git a/MediaBrowser.Controller/Providers/TV/SeriesXmlParser.cs b/MediaBrowser.Controller/Providers/TV/SeriesXmlParser.cs
deleted file mode 100644
index c03e2a7f5..000000000
--- a/MediaBrowser.Controller/Providers/TV/SeriesXmlParser.cs
+++ /dev/null
@@ -1,106 +0,0 @@
-using MediaBrowser.Controller.Entities.TV;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Logging;
-using System;
-using System.Xml;
-
-namespace MediaBrowser.Controller.Providers.TV
-{
- /// <summary>
- /// Class SeriesXmlParser
- /// </summary>
- public class SeriesXmlParser : BaseItemXmlParser<Series>
- {
- /// <summary>
- /// Initializes a new instance of the <see cref="BaseItemXmlParser{T}" /> class.
- /// </summary>
- /// <param name="logger">The logger.</param>
- public SeriesXmlParser(ILogger logger)
- : base(logger)
- {
- }
-
- /// <summary>
- /// Fetches the data from XML node.
- /// </summary>
- /// <param name="reader">The reader.</param>
- /// <param name="item">The item.</param>
- protected override void FetchDataFromXmlNode(XmlReader reader, Series item)
- {
- switch (reader.Name)
- {
- case "Series":
- //MB generated metadata is within a "Series" node
- using (var subTree = reader.ReadSubtree())
- {
- subTree.MoveToContent();
-
- // Loop through each element
- while (subTree.Read())
- {
- if (subTree.NodeType == XmlNodeType.Element)
- {
- FetchDataFromXmlNode(subTree, item);
- }
- }
-
- }
- break;
-
- case "id":
- string id = reader.ReadElementContentAsString();
- if (!string.IsNullOrWhiteSpace(id))
- {
- item.SetProviderId(MetadataProviders.Tvdb, id);
- }
- break;
-
- case "Airs_DayOfWeek":
- {
- item.AirDays = TVUtils.GetAirDays(reader.ReadElementContentAsString());
- break;
- }
-
- case "Airs_Time":
- {
- var val = reader.ReadElementContentAsString();
-
- if (!string.IsNullOrWhiteSpace(val))
- {
- item.AirTime = val;
- }
- break;
- }
-
- case "SeriesName":
- item.Name = reader.ReadElementContentAsString();
- break;
-
- case "Status":
- {
- var status = reader.ReadElementContentAsString();
-
- if (!string.IsNullOrWhiteSpace(status))
- {
- SeriesStatus seriesStatus;
- if (Enum.TryParse(status, true, out seriesStatus))
- {
- item.Status = seriesStatus;
- }
- else
- {
- Logger.Info("Unrecognized series status: " + status);
- }
- }
-
- break;
- }
-
- default:
- base.FetchDataFromXmlNode(reader, item);
- break;
- }
- }
- }
-}
diff --git a/MediaBrowser.Controller/Providers/TV/TvdbPrescanTask.cs b/MediaBrowser.Controller/Providers/TV/TvdbPrescanTask.cs
deleted file mode 100644
index dbd45245f..000000000
--- a/MediaBrowser.Controller/Providers/TV/TvdbPrescanTask.cs
+++ /dev/null
@@ -1,223 +0,0 @@
-using MediaBrowser.Common.Configuration;
-using MediaBrowser.Common.Net;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Extensions;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.Net;
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-using System.Xml;
-
-namespace MediaBrowser.Controller.Providers.TV
-{
- /// <summary>
- /// Class TvdbPrescanTask
- /// </summary>
- public class TvdbPrescanTask : ILibraryPrescanTask
- {
- /// <summary>
- /// The server time URL
- /// </summary>
- private const string ServerTimeUrl = "http://thetvdb.com/api/Updates.php?type=none";
-
- /// <summary>
- /// The updates URL
- /// </summary>
- private const string UpdatesUrl = "http://thetvdb.com/api/Updates.php?type=all&time={0}";
-
- /// <summary>
- /// The _HTTP client
- /// </summary>
- private readonly IHttpClient _httpClient;
- /// <summary>
- /// The _logger
- /// </summary>
- private readonly ILogger _logger;
- /// <summary>
- /// The _config
- /// </summary>
- private readonly IServerConfigurationManager _config;
-
- /// <summary>
- /// Initializes a new instance of the <see cref="TvdbPrescanTask"/> class.
- /// </summary>
- /// <param name="logger">The logger.</param>
- /// <param name="httpClient">The HTTP client.</param>
- /// <param name="config">The config.</param>
- public TvdbPrescanTask(ILogger logger, IHttpClient httpClient, IServerConfigurationManager config)
- {
- _logger = logger;
- _httpClient = httpClient;
- _config = config;
- }
-
- /// <summary>
- /// Runs the specified progress.
- /// </summary>
- /// <param name="progress">The progress.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- public async Task Run(IProgress<double> progress, CancellationToken cancellationToken)
- {
- if (!_config.Configuration.EnableInternetProviders)
- {
- progress.Report(100);
- return;
- }
-
- var path = RemoteSeriesProvider.GetSeriesDataPath(_config.CommonApplicationPaths);
-
- var timestampFile = Path.Combine(path, "time.txt");
-
- var timestampFileInfo = new FileInfo(timestampFile);
-
- // Don't check for tvdb updates anymore frequently than 24 hours
- if (timestampFileInfo.Exists && (DateTime.UtcNow - timestampFileInfo.LastWriteTimeUtc).TotalDays < 1)
- {
- return;
- }
-
- // Find out the last time we queried tvdb for updates
- var lastUpdateTime = timestampFileInfo.Exists ? File.ReadAllText(timestampFile, Encoding.UTF8) : string.Empty;
-
- string newUpdateTime;
-
- var existingDirectories = Directory.EnumerateDirectories(path).Select(Path.GetFileName).ToList();
-
- // If this is our first time, update all series
- if (string.IsNullOrEmpty(lastUpdateTime))
- {
- // First get tvdb server time
- using (var stream = await _httpClient.Get(new HttpRequestOptions
- {
- Url = ServerTimeUrl,
- CancellationToken = cancellationToken,
- EnableHttpCompression = true,
- ResourcePool = RemoteSeriesProvider.Current.TvDbResourcePool
-
- }).ConfigureAwait(false))
- {
- var doc = new XmlDocument();
-
- doc.Load(stream);
-
- newUpdateTime = doc.SafeGetString("//Time");
- }
-
- await UpdateSeries(existingDirectories, path, progress, cancellationToken).ConfigureAwait(false);
- }
- else
- {
- var seriesToUpdate = await GetSeriesIdsToUpdate(existingDirectories, lastUpdateTime, cancellationToken).ConfigureAwait(false);
-
- newUpdateTime = seriesToUpdate.Item2;
-
- await UpdateSeries(seriesToUpdate.Item1, path, progress, cancellationToken).ConfigureAwait(false);
- }
-
- File.WriteAllText(timestampFile, newUpdateTime, Encoding.UTF8);
- progress.Report(100);
- }
-
- /// <summary>
- /// Gets the series ids to update.
- /// </summary>
- /// <param name="existingSeriesIds">The existing series ids.</param>
- /// <param name="lastUpdateTime">The last update time.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task{IEnumerable{System.String}}.</returns>
- private async Task<Tuple<IEnumerable<string>, string>> GetSeriesIdsToUpdate(IEnumerable<string> existingSeriesIds, string lastUpdateTime, CancellationToken cancellationToken)
- {
- // First get last time
- using (var stream = await _httpClient.Get(new HttpRequestOptions
- {
- Url = string.Format(UpdatesUrl, lastUpdateTime),
- CancellationToken = cancellationToken,
- EnableHttpCompression = true,
- ResourcePool = RemoteSeriesProvider.Current.TvDbResourcePool
-
- }).ConfigureAwait(false))
- {
- var doc = new XmlDocument();
-
- doc.Load(stream);
-
- var newUpdateTime = doc.SafeGetString("//Time");
-
- var seriesNodes = doc.SelectNodes("//Series");
-
- var seriesList = seriesNodes == null ? new string[] { } :
- seriesNodes.Cast<XmlNode>()
- .Select(i => i.InnerText)
- .Where(i => !string.IsNullOrWhiteSpace(i) && existingSeriesIds.Contains(i, StringComparer.OrdinalIgnoreCase));
-
- return new Tuple<IEnumerable<string>, string>(seriesList, newUpdateTime);
- }
- }
-
- /// <summary>
- /// Updates the series.
- /// </summary>
- /// <param name="seriesIds">The series ids.</param>
- /// <param name="seriesDataPath">The series data path.</param>
- /// <param name="progress">The progress.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- private async Task UpdateSeries(IEnumerable<string> seriesIds, string seriesDataPath, IProgress<double> progress, CancellationToken cancellationToken)
- {
- var list = seriesIds.ToList();
- var numComplete = 0;
-
- foreach (var seriesId in list)
- {
- try
- {
- await UpdateSeries(seriesId, seriesDataPath, cancellationToken).ConfigureAwait(false);
- }
- catch (HttpException ex)
- {
- // Already logged at lower levels, but don't fail the whole operation, unless timed out
- // We have to fail this to make it run again otherwise new episode data could potentially be missing
- if (ex.IsTimedOut)
- {
- throw;
- }
- }
-
- numComplete++;
- double percent = numComplete;
- percent /= list.Count;
- percent *= 100;
-
- progress.Report(percent);
- }
- }
-
- /// <summary>
- /// Updates the series.
- /// </summary>
- /// <param name="id">The id.</param>
- /// <param name="seriesDataPath">The series data path.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- private Task UpdateSeries(string id, string seriesDataPath, CancellationToken cancellationToken)
- {
- _logger.Info("Updating series " + id);
-
- seriesDataPath = Path.Combine(seriesDataPath, id);
-
- if (!Directory.Exists(seriesDataPath))
- {
- Directory.CreateDirectory(seriesDataPath);
- }
-
- return RemoteSeriesProvider.Current.DownloadSeriesZip(id, seriesDataPath, cancellationToken);
- }
- }
-}
diff --git a/MediaBrowser.Controller/Providers/TV/TvdbSeriesImageProvider.cs b/MediaBrowser.Controller/Providers/TV/TvdbSeriesImageProvider.cs
deleted file mode 100644
index 68294a17b..000000000
--- a/MediaBrowser.Controller/Providers/TV/TvdbSeriesImageProvider.cs
+++ /dev/null
@@ -1,283 +0,0 @@
-using MediaBrowser.Common.Extensions;
-using MediaBrowser.Common.Net;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Entities.TV;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Logging;
-using System;
-using System.Globalization;
-using System.IO;
-using System.Threading;
-using System.Threading.Tasks;
-using System.Xml;
-
-namespace MediaBrowser.Controller.Providers.TV
-{
- public class TvdbSeriesImageProvider : BaseMetadataProvider
- {
- /// <summary>
- /// Gets the HTTP client.
- /// </summary>
- /// <value>The HTTP client.</value>
- protected IHttpClient HttpClient { get; private set; }
-
- /// <summary>
- /// The _provider manager
- /// </summary>
- private readonly IProviderManager _providerManager;
-
- /// <summary>
- /// Initializes a new instance of the <see cref="TvdbSeriesImageProvider"/> class.
- /// </summary>
- /// <param name="httpClient">The HTTP client.</param>
- /// <param name="logManager">The log manager.</param>
- /// <param name="configurationManager">The configuration manager.</param>
- /// <param name="providerManager">The provider manager.</param>
- /// <exception cref="System.ArgumentNullException">httpClient</exception>
- public TvdbSeriesImageProvider(IHttpClient httpClient, ILogManager logManager, IServerConfigurationManager configurationManager, IProviderManager providerManager)
- : base(logManager, configurationManager)
- {
- if (httpClient == null)
- {
- throw new ArgumentNullException("httpClient");
- }
- HttpClient = httpClient;
- _providerManager = providerManager;
- }
-
- /// <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 Series;
- }
-
- /// <summary>
- /// Gets the priority.
- /// </summary>
- /// <value>The priority.</value>
- public override MetadataProviderPriority Priority
- {
- // Run after fanart
- get { return MetadataProviderPriority.Fourth; }
- }
-
- /// <summary>
- /// Gets a value indicating whether [requires internet].
- /// </summary>
- /// <value><c>true</c> if [requires internet]; otherwise, <c>false</c>.</value>
- public override bool RequiresInternet
- {
- get
- {
- return true;
- }
- }
-
- /// <summary>
- /// Returns true or false indicating if the provider should refresh when the contents of it's directory changes
- /// </summary>
- /// <value><c>true</c> if [refresh on file system stamp change]; otherwise, <c>false</c>.</value>
- protected override bool RefreshOnFileSystemStampChange
- {
- get
- {
- return ConfigurationManager.Configuration.SaveLocalMeta;
- }
- }
-
- /// <summary>
- /// Gets a value indicating whether [refresh on version change].
- /// </summary>
- /// <value><c>true</c> if [refresh on version change]; otherwise, <c>false</c>.</value>
- protected override bool RefreshOnVersionChange
- {
- get
- {
- return true;
- }
- }
-
- /// <summary>
- /// Gets the provider version.
- /// </summary>
- /// <value>The provider version.</value>
- protected override string ProviderVersion
- {
- get
- {
- return "1";
- }
- }
-
- /// <summary>
- /// Needses the refresh internal.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="providerInfo">The provider info.</param>
- /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
- protected override bool NeedsRefreshInternal(BaseItem item, BaseProviderInfo providerInfo)
- {
- if (GetComparisonData(item) != providerInfo.Data)
- {
- return true;
- }
-
- return base.NeedsRefreshInternal(item, providerInfo);
- }
-
- /// <summary>
- /// Gets the comparison data.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <returns>Guid.</returns>
- private Guid GetComparisonData(BaseItem item)
- {
- var seriesId = item.GetProviderId(MetadataProviders.Tvdb);
-
- if (!string.IsNullOrEmpty(seriesId))
- {
- // Process images
- var imagesXmlPath = Path.Combine(RemoteSeriesProvider.GetSeriesDataPath(ConfigurationManager.ApplicationPaths, seriesId), "banners.xml");
-
- var imagesFileInfo = new FileInfo(imagesXmlPath);
-
- return GetComparisonData(imagesFileInfo);
- }
-
- return Guid.Empty;
- }
-
- /// <summary>
- /// Gets the comparison data.
- /// </summary>
- /// <param name="imagesFileInfo">The images file info.</param>
- /// <returns>Guid.</returns>
- private Guid GetComparisonData(FileInfo imagesFileInfo)
- {
- var date = imagesFileInfo.Exists ? imagesFileInfo.LastWriteTimeUtc : DateTime.MinValue;
-
- var key = date.Ticks + imagesFileInfo.FullName;
-
- return key.GetMD5();
- }
-
- /// <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 async Task<bool> FetchAsync(BaseItem item, bool force, CancellationToken cancellationToken)
- {
- cancellationToken.ThrowIfCancellationRequested();
-
- var series = (Series)item;
- var seriesId = series.GetProviderId(MetadataProviders.Tvdb);
-
- if (!string.IsNullOrEmpty(seriesId))
- {
- // Process images
- var imagesXmlPath = Path.Combine(RemoteSeriesProvider.GetSeriesDataPath(ConfigurationManager.ApplicationPaths, seriesId), "banners.xml");
-
- var imagesFileInfo = new FileInfo(imagesXmlPath);
-
- if (imagesFileInfo.Exists)
- {
- if (!series.HasImage(ImageType.Primary) || !series.HasImage(ImageType.Banner) || series.BackdropImagePaths.Count == 0)
- {
- var xmlDoc = new XmlDocument();
- xmlDoc.Load(imagesXmlPath);
-
- await FetchImages(series, xmlDoc, cancellationToken).ConfigureAwait(false);
- }
- }
-
- BaseProviderInfo data;
- if (!item.ProviderData.TryGetValue(Id, out data))
- {
- data = new BaseProviderInfo();
- item.ProviderData[Id] = data;
- }
-
- data.Data = GetComparisonData(imagesFileInfo);
-
- SetLastRefreshed(item, DateTime.UtcNow);
- return true;
- }
-
- return false;
- }
-
- protected readonly CultureInfo UsCulture = new CultureInfo("en-US");
-
- /// <summary>
- /// Fetches the images.
- /// </summary>
- /// <param name="series">The series.</param>
- /// <param name="images">The images.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- private async Task FetchImages(Series series, XmlDocument images, CancellationToken cancellationToken)
- {
- if (!series.HasImage(ImageType.Primary))
- {
- var n = images.SelectSingleNode("//Banner[BannerType='poster']");
- if (n != null)
- {
- n = n.SelectSingleNode("./BannerPath");
- if (n != null)
- {
- var path = await _providerManager.DownloadAndSaveImage(series, TVUtils.BannerUrl + n.InnerText, "folder" + Path.GetExtension(n.InnerText), ConfigurationManager.Configuration.SaveLocalMeta, RemoteSeriesProvider.Current.TvDbResourcePool, cancellationToken).ConfigureAwait(false);
-
- series.SetImage(ImageType.Primary, path);
- }
- }
- }
-
- if (ConfigurationManager.Configuration.DownloadSeriesImages.Banner && !series.HasImage(ImageType.Banner))
- {
- var n = images.SelectSingleNode("//Banner[BannerType='series']");
- if (n != null)
- {
- n = n.SelectSingleNode("./BannerPath");
- if (n != null)
- {
- var bannerImagePath = await _providerManager.DownloadAndSaveImage(series, TVUtils.BannerUrl + n.InnerText, "banner" + Path.GetExtension(n.InnerText), ConfigurationManager.Configuration.SaveLocalMeta, RemoteSeriesProvider.Current.TvDbResourcePool, cancellationToken);
-
- series.SetImage(ImageType.Banner, bannerImagePath);
- }
- }
- }
-
- if (series.BackdropImagePaths.Count == 0)
- {
- var bdNo = series.BackdropImagePaths.Count;
-
- var xmlNodeList = images.SelectNodes("//Banner[BannerType='fanart']");
- if (xmlNodeList != null)
- {
- foreach (XmlNode b in xmlNodeList)
- {
- var p = b.SelectSingleNode("./BannerPath");
-
- if (p != null)
- {
- var bdName = "backdrop" + (bdNo > 0 ? bdNo.ToString(UsCulture) : "");
- series.BackdropImagePaths.Add(await _providerManager.DownloadAndSaveImage(series, TVUtils.BannerUrl + p.InnerText, bdName + Path.GetExtension(p.InnerText), ConfigurationManager.Configuration.SaveLocalMeta, RemoteSeriesProvider.Current.TvDbResourcePool, cancellationToken).ConfigureAwait(false));
- bdNo++;
- }
-
- if (series.BackdropImagePaths.Count >= ConfigurationManager.Configuration.MaxBackdrops) break;
- }
- }
- }
- }
- }
-}