aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke Pulverenti <luke.pulverenti@gmail.com>2013-10-22 15:03:21 -0400
committerLuke Pulverenti <luke.pulverenti@gmail.com>2013-10-22 15:03:21 -0400
commit32cb872b06830b07d27c52ecad9695c669783730 (patch)
tree0c776cfa04ecd8cc6d0f726b7359caeeccba1f11
parent96fd6459b2c01c535ae5d0090861f838d45c5c47 (diff)
support backdrops from multiple sources
-rw-r--r--MediaBrowser.Api/Images/ImageService.cs23
-rw-r--r--MediaBrowser.Controller/Entities/BaseItem.cs128
-rw-r--r--MediaBrowser.Controller/Entities/ImageSourceInfo.cs10
-rw-r--r--MediaBrowser.Controller/MediaBrowser.Controller.csproj1
-rw-r--r--MediaBrowser.Controller/Providers/IProviderManager.cs3
-rw-r--r--MediaBrowser.Model/Configuration/ServerConfiguration.cs7
-rw-r--r--MediaBrowser.Providers/Movies/FanArtMovieProvider.cs9
-rw-r--r--MediaBrowser.Providers/Movies/MovieDbImagesProvider.cs25
-rw-r--r--MediaBrowser.Providers/Movies/MovieDbProvider.cs15
-rw-r--r--MediaBrowser.Providers/Movies/TmdbPersonProvider.cs2
-rw-r--r--MediaBrowser.Providers/Music/FanArtAlbumProvider.cs3
-rw-r--r--MediaBrowser.Providers/Music/FanArtArtistProvider.cs6
-rw-r--r--MediaBrowser.Providers/TV/FanArtTVProvider.cs10
-rw-r--r--MediaBrowser.Providers/TV/RemoteSeasonProvider.cs27
-rw-r--r--MediaBrowser.Providers/TV/TvdbSeriesImageProvider.cs85
-rw-r--r--MediaBrowser.Server.Implementations/Library/Validators/ArtistsValidator.cs18
-rw-r--r--MediaBrowser.Server.Implementations/Providers/ImageSaver.cs37
-rw-r--r--MediaBrowser.Server.Implementations/Providers/ProviderManager.cs7
-rw-r--r--MediaBrowser.Server.Implementations/Session/SessionManager.cs15
19 files changed, 336 insertions, 95 deletions
diff --git a/MediaBrowser.Api/Images/ImageService.cs b/MediaBrowser.Api/Images/ImageService.cs
index 298d26a13f..61259a4c25 100644
--- a/MediaBrowser.Api/Images/ImageService.cs
+++ b/MediaBrowser.Api/Images/ImageService.cs
@@ -699,11 +699,32 @@ namespace MediaBrowser.Api.Images
var temp1 = Path.Combine(_appPaths.TempDirectory, Guid.NewGuid() + ".tmp");
var temp2 = Path.Combine(_appPaths.TempDirectory, Guid.NewGuid() + ".tmp");
+ // Copying over will fail against hidden files
+ RemoveHiddenAttribute(file1);
+ RemoveHiddenAttribute(file2);
+
File.Copy(file1, temp1);
File.Copy(file2, temp2);
File.Copy(temp1, file2, true);
File.Copy(temp2, file1, true);
+
+ File.Delete(temp1);
+ File.Delete(temp2);
+ }
+
+ private void RemoveHiddenAttribute(string path)
+ {
+ var currentFile = new FileInfo(path);
+
+ // This will fail if the file is hidden
+ if (currentFile.Exists)
+ {
+ if ((currentFile.Attributes & FileAttributes.Hidden) == FileAttributes.Hidden)
+ {
+ currentFile.Attributes &= ~FileAttributes.Hidden;
+ }
+ }
}
/// <summary>
@@ -854,7 +875,7 @@ namespace MediaBrowser.Api.Images
// Handle image/png; charset=utf-8
mimeType = mimeType.Split(';').FirstOrDefault();
- await _providerManager.SaveImage(entity, memoryStream, mimeType, imageType, imageIndex, CancellationToken.None).ConfigureAwait(false);
+ await _providerManager.SaveImage(entity, memoryStream, mimeType, imageType, imageIndex, null, CancellationToken.None).ConfigureAwait(false);
await entity.RefreshMetadata(CancellationToken.None, forceRefresh: true, forceSave: true, allowSlowProviders: false).ConfigureAwait(false);
}
diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs
index 3459c25976..6832ca7141 100644
--- a/MediaBrowser.Controller/Entities/BaseItem.cs
+++ b/MediaBrowser.Controller/Entities/BaseItem.cs
@@ -47,6 +47,7 @@ namespace MediaBrowser.Controller.Entities
LockedFields = new List<MetadataFields>();
Taglines = new List<string>();
RemoteTrailers = new List<MediaUrl>();
+ ImageSources = new List<ImageSourceInfo>();
}
/// <summary>
@@ -234,23 +235,6 @@ namespace MediaBrowser.Controller.Entities
public List<MetadataFields> LockedFields { get; set; }
/// <summary>
- /// Determines whether the item has a saved local image of the specified name (jpg or png).
- /// </summary>
- /// <param name="name">The name.</param>
- /// <returns><c>true</c> if [has local image] [the specified item]; otherwise, <c>false</c>.</returns>
- /// <exception cref="System.ArgumentNullException">name</exception>
- public bool HasLocalImage(string name)
- {
- if (string.IsNullOrEmpty(name))
- {
- throw new ArgumentNullException("name");
- }
-
- return ResolveArgs.ContainsMetaFileByName(name + ".jpg") ||
- ResolveArgs.ContainsMetaFileByName(name + ".png");
- }
-
- /// <summary>
/// Should be overridden to return the proper folder where metadata lives
/// </summary>
/// <value>The meta location.</value>
@@ -537,6 +521,12 @@ namespace MediaBrowser.Controller.Entities
public List<string> BackdropImagePaths { get; set; }
/// <summary>
+ /// Gets or sets the backdrop image sources.
+ /// </summary>
+ /// <value>The backdrop image sources.</value>
+ public List<ImageSourceInfo> ImageSources { get; set; }
+
+ /// <summary>
/// Gets or sets the screenshot image paths.
/// </summary>
/// <value>The screenshot image paths.</value>
@@ -1508,8 +1498,10 @@ namespace MediaBrowser.Controller.Entities
BackdropImagePaths.Remove(file);
+ RemoveImageSourceForPath(file);
+
// Delete the source file
- File.Delete(file);
+ DeleteImagePath(file);
}
else if (type == ImageType.Screenshot)
{
@@ -1523,12 +1515,12 @@ namespace MediaBrowser.Controller.Entities
ScreenshotImagePaths.Remove(file);
// Delete the source file
- File.Delete(file);
+ DeleteImagePath(file);
}
else
{
// Delete the source file
- File.Delete(GetImage(type));
+ DeleteImagePath(GetImage(type));
// Remove it from the item
SetImage(type, null);
@@ -1539,6 +1531,26 @@ namespace MediaBrowser.Controller.Entities
}
/// <summary>
+ /// Deletes the image path.
+ /// </summary>
+ /// <param name="path">The path.</param>
+ private void DeleteImagePath(string path)
+ {
+ var currentFile = new FileInfo(path);
+
+ // This will fail if the file is hidden
+ if (currentFile.Exists)
+ {
+ if ((currentFile.Attributes & FileAttributes.Hidden) == FileAttributes.Hidden)
+ {
+ currentFile.Attributes &= ~FileAttributes.Hidden;
+ }
+
+ currentFile.Delete();
+ }
+ }
+
+ /// <summary>
/// Validates that images within the item are still on the file system
/// </summary>
public void ValidateImages()
@@ -1570,7 +1582,83 @@ namespace MediaBrowser.Controller.Entities
foreach (var path in deletedImages)
{
BackdropImagePaths.Remove(path);
+
+ RemoveImageSourceForPath(path);
+ }
+ }
+
+ /// <summary>
+ /// Adds the image source.
+ /// </summary>
+ /// <param name="path">The path.</param>
+ /// <param name="url">The URL.</param>
+ public void AddImageSource(string path, string url)
+ {
+ RemoveImageSourceForPath(path);
+
+ var pathMd5 = path.ToLower().GetMD5();
+
+ ImageSources.Add(new ImageSourceInfo
+ {
+ ImagePathMD5 = pathMd5,
+ ImageUrlMD5 = url.ToLower().GetMD5()
+ });
+ }
+
+ /// <summary>
+ /// Gets the image source info.
+ /// </summary>
+ /// <param name="path">The path.</param>
+ /// <returns>ImageSourceInfo.</returns>
+ public ImageSourceInfo GetImageSourceInfo(string path)
+ {
+ if (ImageSources.Count == 0)
+ {
+ return null;
+ }
+
+ var pathMd5 = path.ToLower().GetMD5();
+
+ return ImageSources.FirstOrDefault(i => i.ImagePathMD5 == pathMd5);
+ }
+
+ /// <summary>
+ /// Removes the image source for path.
+ /// </summary>
+ /// <param name="path">The path.</param>
+ public void RemoveImageSourceForPath(string path)
+ {
+ if (ImageSources.Count == 0)
+ {
+ return;
}
+
+ var pathMd5 = path.ToLower().GetMD5();
+
+ // Remove existing
+ foreach (var entry in ImageSources
+ .Where(i => i.ImagePathMD5 == pathMd5)
+ .ToList())
+ {
+ ImageSources.Remove(entry);
+ }
+ }
+
+ /// <summary>
+ /// Determines whether [contains image with source URL] [the specified URL].
+ /// </summary>
+ /// <param name="url">The URL.</param>
+ /// <returns><c>true</c> if [contains image with source URL] [the specified URL]; otherwise, <c>false</c>.</returns>
+ public bool ContainsImageWithSourceUrl(string url)
+ {
+ if (ImageSources.Count == 0)
+ {
+ return false;
+ }
+
+ var md5 = url.ToLower().GetMD5();
+
+ return ImageSources.Any(i => i.ImageUrlMD5 == md5);
}
/// <summary>
diff --git a/MediaBrowser.Controller/Entities/ImageSourceInfo.cs b/MediaBrowser.Controller/Entities/ImageSourceInfo.cs
new file mode 100644
index 0000000000..6dc072431c
--- /dev/null
+++ b/MediaBrowser.Controller/Entities/ImageSourceInfo.cs
@@ -0,0 +1,10 @@
+using System;
+
+namespace MediaBrowser.Controller.Entities
+{
+ public class ImageSourceInfo
+ {
+ public Guid ImagePathMD5 { get; set; }
+ public Guid ImageUrlMD5 { get; set; }
+ }
+}
diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj
index 5cde659ddf..8154cb0a28 100644
--- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj
+++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj
@@ -91,6 +91,7 @@
<Compile Include="Entities\IByReferenceItem.cs" />
<Compile Include="Entities\IItemByName.cs" />
<Compile Include="Entities\ILibraryItem.cs" />
+ <Compile Include="Entities\ImageSourceInfo.cs" />
<Compile Include="Entities\LinkedChild.cs" />
<Compile Include="Entities\MusicVideo.cs" />
<Compile Include="Library\ILibraryPostScanTask.cs" />
diff --git a/MediaBrowser.Controller/Providers/IProviderManager.cs b/MediaBrowser.Controller/Providers/IProviderManager.cs
index 46223efc33..6a4d132b76 100644
--- a/MediaBrowser.Controller/Providers/IProviderManager.cs
+++ b/MediaBrowser.Controller/Providers/IProviderManager.cs
@@ -43,9 +43,10 @@ namespace MediaBrowser.Controller.Providers
/// <param name="mimeType">Type of the MIME.</param>
/// <param name="type">The type.</param>
/// <param name="imageIndex">Index of the image.</param>
+ /// <param name="sourceUrl">The source URL.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
- Task SaveImage(BaseItem item, Stream source, string mimeType, ImageType type, int? imageIndex, CancellationToken cancellationToken);
+ Task SaveImage(BaseItem item, Stream source, string mimeType, ImageType type, int? imageIndex, string sourceUrl, CancellationToken cancellationToken);
/// <summary>
/// Adds the metadata providers.
diff --git a/MediaBrowser.Model/Configuration/ServerConfiguration.cs b/MediaBrowser.Model/Configuration/ServerConfiguration.cs
index 9c830789d7..5f606a06bf 100644
--- a/MediaBrowser.Model/Configuration/ServerConfiguration.cs
+++ b/MediaBrowser.Model/Configuration/ServerConfiguration.cs
@@ -234,6 +234,12 @@ namespace MediaBrowser.Model.Configuration
public int MinMovieBackdropWidth { get; set; }
/// <summary>
+ /// Gets or sets the width of the min series backdrop.
+ /// </summary>
+ /// <value>The width of the min series backdrop.</value>
+ public int MinSeriesBackdropWidth { get; set; }
+
+ /// <summary>
/// Gets or sets the width of the min movie poster.
/// </summary>
/// <value>The width of the min movie poster.</value>
@@ -286,6 +292,7 @@ namespace MediaBrowser.Model.Configuration
SeasonZeroDisplayName = "Specials";
MinMovieBackdropWidth = 1920;
+ MinSeriesBackdropWidth = 1920;
MinMoviePosterWidth = 1000;
}
}
diff --git a/MediaBrowser.Providers/Movies/FanArtMovieProvider.cs b/MediaBrowser.Providers/Movies/FanArtMovieProvider.cs
index 9ef4c68887..f34988481e 100644
--- a/MediaBrowser.Providers/Movies/FanArtMovieProvider.cs
+++ b/MediaBrowser.Providers/Movies/FanArtMovieProvider.cs
@@ -153,7 +153,7 @@ namespace MediaBrowser.Providers.Movies
item.HasImage(ImageType.Disc) &&
item.HasImage(ImageType.Banner) &&
item.HasImage(ImageType.Thumb) &&
- item.BackdropImagePaths.Count > 0)
+ item.BackdropImagePaths.Count >= ConfigurationManager.Configuration.MaxBackdrops)
{
return false;
}
@@ -389,7 +389,8 @@ namespace MediaBrowser.Providers.Movies
}
}
- if (ConfigurationManager.Configuration.DownloadMovieImages.Backdrops && item.BackdropImagePaths.Count == 0)
+ var backdropLimit = ConfigurationManager.Configuration.MaxBackdrops;
+ if (ConfigurationManager.Configuration.DownloadMovieImages.Backdrops && item.BackdropImagePaths.Count < backdropLimit)
{
var nodes = doc.SelectNodes("//fanart/movie/moviebackgrounds//@url");
@@ -401,14 +402,14 @@ namespace MediaBrowser.Providers.Movies
{
path = node.Value;
- if (!string.IsNullOrEmpty(path))
+ if (!string.IsNullOrEmpty(path) && !item.ContainsImageWithSourceUrl(path))
{
await _providerManager.SaveImage(item, path, FanArtResourcePool, ImageType.Backdrop, numBackdrops, cancellationToken)
.ConfigureAwait(false);
numBackdrops++;
- if (item.BackdropImagePaths.Count >= ConfigurationManager.Configuration.MaxBackdrops) break;
+ if (item.BackdropImagePaths.Count >= backdropLimit) break;
}
}
diff --git a/MediaBrowser.Providers/Movies/MovieDbImagesProvider.cs b/MediaBrowser.Providers/Movies/MovieDbImagesProvider.cs
index d03bc91ac9..b5d3443377 100644
--- a/MediaBrowser.Providers/Movies/MovieDbImagesProvider.cs
+++ b/MediaBrowser.Providers/Movies/MovieDbImagesProvider.cs
@@ -9,7 +9,6 @@ using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Serialization;
using System;
using System.Collections.Generic;
-using System.Globalization;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
@@ -135,7 +134,7 @@ namespace MediaBrowser.Providers.Movies
}
// 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)
+ if (item.HasImage(ImageType.Primary) && item.BackdropImagePaths.Count >= ConfigurationManager.Configuration.MaxBackdrops)
{
return false;
}
@@ -239,14 +238,16 @@ namespace MediaBrowser.Providers.Movies
if (poster != null)
{
+ var url = tmdbImageUrl + poster.file_path;
+
var img = await MovieDbProvider.Current.GetMovieDbResponse(new HttpRequestOptions
{
- Url = tmdbImageUrl + poster.file_path,
+ Url = url,
CancellationToken = cancellationToken
}).ConfigureAwait(false);
- await _providerManager.SaveImage(item, img, MimeTypes.GetMimeType(poster.file_path), ImageType.Primary, null, cancellationToken)
+ await _providerManager.SaveImage(item, img, MimeTypes.GetMimeType(poster.file_path), ImageType.Primary, null, url, cancellationToken)
.ConfigureAwait(false);
}
@@ -258,8 +259,10 @@ namespace MediaBrowser.Providers.Movies
images.backdrops.Where(i => i.width >= ConfigurationManager.Configuration.MinMovieBackdropWidth)
.ToList();
+ var backdropLimit = ConfigurationManager.Configuration.MaxBackdrops;
+
// backdrops - only download if earlier providers didn't find any (fanart)
- if (eligibleBackdrops.Count > 0 && ConfigurationManager.Configuration.DownloadMovieImages.Backdrops && item.BackdropImagePaths.Count == 0)
+ if (eligibleBackdrops.Count > 0 && ConfigurationManager.Configuration.DownloadMovieImages.Backdrops && item.BackdropImagePaths.Count < backdropLimit)
{
var tmdbSettings = await MovieDbProvider.Current.GetTmdbSettings(cancellationToken).ConfigureAwait(false);
@@ -267,24 +270,22 @@ namespace MediaBrowser.Providers.Movies
for (var i = 0; i < eligibleBackdrops.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;
+ var url = tmdbImageUrl + eligibleBackdrops[i].file_path;
- if (!hasLocalBackdrop)
+ if (!item.ContainsImageWithSourceUrl(url))
{
var img = await MovieDbProvider.Current.GetMovieDbResponse(new HttpRequestOptions
{
- Url = tmdbImageUrl + eligibleBackdrops[i].file_path,
+ Url = url,
CancellationToken = cancellationToken
}).ConfigureAwait(false);
- await _providerManager.SaveImage(item, img, MimeTypes.GetMimeType(eligibleBackdrops[i].file_path), ImageType.Backdrop, item.BackdropImagePaths.Count, cancellationToken)
+ await _providerManager.SaveImage(item, img, MimeTypes.GetMimeType(eligibleBackdrops[i].file_path), ImageType.Backdrop, item.BackdropImagePaths.Count, url, cancellationToken)
.ConfigureAwait(false);
}
- if (item.BackdropImagePaths.Count >= ConfigurationManager.Configuration.MaxBackdrops)
+ if (item.BackdropImagePaths.Count >= backdropLimit)
{
break;
}
diff --git a/MediaBrowser.Providers/Movies/MovieDbProvider.cs b/MediaBrowser.Providers/Movies/MovieDbProvider.cs
index 46d6b0aa93..6d467fc6c9 100644
--- a/MediaBrowser.Providers/Movies/MovieDbProvider.cs
+++ b/MediaBrowser.Providers/Movies/MovieDbProvider.cs
@@ -513,7 +513,7 @@ namespace MediaBrowser.Providers.Movies
{
var isBoxSet = item is BoxSet;
- var mainResult = await FetchMainResult(id, isBoxSet, cancellationToken).ConfigureAwait(false);
+ var mainResult = await FetchMainResult(id, isBoxSet, language, cancellationToken).ConfigureAwait(false);
if (mainResult == null) return;
@@ -550,7 +550,7 @@ namespace MediaBrowser.Providers.Movies
{
var language = ConfigurationManager.Configuration.PreferredMetadataLanguage;
- var mainResult = await FetchMainResult(id, isBoxSet, cancellationToken).ConfigureAwait(false);
+ var mainResult = await FetchMainResult(id, isBoxSet, language, cancellationToken).ConfigureAwait(false);
if (mainResult == null) return;
@@ -588,13 +588,14 @@ namespace MediaBrowser.Providers.Movies
/// </summary>
/// <param name="id">The id.</param>
/// <param name="isBoxSet">if set to <c>true</c> [is box set].</param>
+ /// <param name="language">The language.</param>
/// <param name="cancellationToken">The cancellation token</param>
/// <returns>Task{CompleteMovieData}.</returns>
- protected async Task<CompleteMovieData> FetchMainResult(string id, bool isBoxSet, CancellationToken cancellationToken)
+ protected async Task<CompleteMovieData> FetchMainResult(string id, bool isBoxSet, string language, CancellationToken cancellationToken)
{
var baseUrl = isBoxSet ? GetBoxSetInfo3 : GetMovieInfo3;
- string url = string.Format(baseUrl, id, ApiKey, ConfigurationManager.Configuration.PreferredMetadataLanguage);
+ string url = string.Format(baseUrl, id, ApiKey, language);
CompleteMovieData mainResult;
cancellationToken.ThrowIfCancellationRequested();
@@ -614,13 +615,13 @@ namespace MediaBrowser.Providers.Movies
if (mainResult != null && string.IsNullOrEmpty(mainResult.overview))
{
- if (ConfigurationManager.Configuration.PreferredMetadataLanguage.ToLower() != "en")
+ if (language.ToLower() != "en")
{
- Logger.Info("MovieDbProvider couldn't find meta for language " + ConfigurationManager.Configuration.PreferredMetadataLanguage + ". Trying English...");
+ Logger.Info("MovieDbProvider couldn't find meta for language " + language + ". Trying English...");
url = string.Format(baseUrl, id, ApiKey, "en");
- using (Stream json = await GetMovieDbResponse(new HttpRequestOptions
+ using (var json = await GetMovieDbResponse(new HttpRequestOptions
{
Url = url,
CancellationToken = cancellationToken,
diff --git a/MediaBrowser.Providers/Movies/TmdbPersonProvider.cs b/MediaBrowser.Providers/Movies/TmdbPersonProvider.cs
index 3fc32c7051..685f4bc6e4 100644
--- a/MediaBrowser.Providers/Movies/TmdbPersonProvider.cs
+++ b/MediaBrowser.Providers/Movies/TmdbPersonProvider.cs
@@ -390,7 +390,7 @@ namespace MediaBrowser.Providers.Movies
}).ConfigureAwait(false))
{
- await ProviderManager.SaveImage(item, sourceStream, mimeType, ImageType.Primary, null, cancellationToken)
+ await ProviderManager.SaveImage(item, sourceStream, mimeType, ImageType.Primary, null, source, cancellationToken)
.ConfigureAwait(false);
Logger.Debug("TmdbPersonProvider downloaded and saved image for {0}", item.Name);
diff --git a/MediaBrowser.Providers/Music/FanArtAlbumProvider.cs b/MediaBrowser.Providers/Music/FanArtAlbumProvider.cs
index fa7daaf251..e454b048c9 100644
--- a/MediaBrowser.Providers/Music/FanArtAlbumProvider.cs
+++ b/MediaBrowser.Providers/Music/FanArtAlbumProvider.cs
@@ -1,5 +1,4 @@
-using MediaBrowser.Common.Extensions;
-using MediaBrowser.Common.Net;
+using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
diff --git a/MediaBrowser.Providers/Music/FanArtArtistProvider.cs b/MediaBrowser.Providers/Music/FanArtArtistProvider.cs
index 35bbba0422..79d53d5785 100644
--- a/MediaBrowser.Providers/Music/FanArtArtistProvider.cs
+++ b/MediaBrowser.Providers/Music/FanArtArtistProvider.cs
@@ -332,6 +332,8 @@ namespace MediaBrowser.Providers.Music
}
cancellationToken.ThrowIfCancellationRequested();
+ var backdropLimit = ConfigurationManager.Configuration.MaxBackdrops;
+
if (ConfigurationManager.Configuration.DownloadMusicArtistImages.Backdrops && item.BackdropImagePaths.Count == 0)
{
var nodes = doc.SelectNodes("//fanart/music/artistbackgrounds//@url");
@@ -342,14 +344,14 @@ namespace MediaBrowser.Providers.Music
foreach (XmlNode node in nodes)
{
path = node.Value;
- if (!string.IsNullOrEmpty(path))
+ if (!string.IsNullOrEmpty(path) && !item.ContainsImageWithSourceUrl(path))
{
try
{
await _providerManager.SaveImage(item, path, FanArtResourcePool, ImageType.Backdrop, numBackdrops, cancellationToken)
.ConfigureAwait(false);
numBackdrops++;
- if (numBackdrops >= ConfigurationManager.Configuration.MaxBackdrops) break;
+ if (numBackdrops >= backdropLimit) break;
}
catch (HttpException ex)
{
diff --git a/MediaBrowser.Providers/TV/FanArtTVProvider.cs b/MediaBrowser.Providers/TV/FanArtTVProvider.cs
index 5412266090..ed7ca941c2 100644
--- a/MediaBrowser.Providers/TV/FanArtTVProvider.cs
+++ b/MediaBrowser.Providers/TV/FanArtTVProvider.cs
@@ -94,7 +94,7 @@ namespace MediaBrowser.Providers.TV
item.HasImage(ImageType.Logo) &&
item.HasImage(ImageType.Banner) &&
item.HasImage(ImageType.Thumb) &&
- item.BackdropImagePaths.Count > 0)
+ item.BackdropImagePaths.Count >= ConfigurationManager.Configuration.MaxBackdrops)
{
return false;
}
@@ -298,7 +298,9 @@ namespace MediaBrowser.Providers.TV
}
}
- if (ConfigurationManager.Configuration.DownloadMovieImages.Backdrops && item.BackdropImagePaths.Count == 0)
+ var backdropLimit = ConfigurationManager.Configuration.MaxBackdrops;
+
+ if (ConfigurationManager.Configuration.DownloadMovieImages.Backdrops && item.BackdropImagePaths.Count < backdropLimit)
{
var nodes = doc.SelectNodes("//fanart/series/showbackgrounds//@url");
@@ -310,14 +312,14 @@ namespace MediaBrowser.Providers.TV
{
var path = node.Value;
- if (!string.IsNullOrEmpty(path))
+ if (!string.IsNullOrEmpty(path) && !item.ContainsImageWithSourceUrl(path))
{
await _providerManager.SaveImage(item, path, FanArtResourcePool, ImageType.Backdrop, numBackdrops, cancellationToken)
.ConfigureAwait(false);
numBackdrops++;
- if (item.BackdropImagePaths.Count >= ConfigurationManager.Configuration.MaxBackdrops) break;
+ if (item.BackdropImagePaths.Count >= backdropLimit) break;
}
}
diff --git a/MediaBrowser.Providers/TV/RemoteSeasonProvider.cs b/MediaBrowser.Providers/TV/RemoteSeasonProvider.cs
index 3436a137f5..c0ff760549 100644
--- a/MediaBrowser.Providers/TV/RemoteSeasonProvider.cs
+++ b/MediaBrowser.Providers/TV/RemoteSeasonProvider.cs
@@ -121,6 +121,15 @@ namespace MediaBrowser.Providers.TV
return false;
}
+ protected override bool NeedsRefreshInternal(BaseItem item, BaseProviderInfo providerInfo)
+ {
+ if (item.HasImage(ImageType.Primary) && item.HasImage(ImageType.Banner) && 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>
@@ -146,7 +155,7 @@ namespace MediaBrowser.Providers.TV
try
{
var fanartData = FetchFanartXmlData(imagesXmlPath, seasonNumber.Value, cancellationToken);
- await DownloadImages(item, fanartData, ConfigurationManager.Configuration.MaxBackdrops, cancellationToken).ConfigureAwait(false);
+ await DownloadImages(item, fanartData, 1, cancellationToken).ConfigureAwait(false);
}
catch (FileNotFoundException)
{
@@ -186,13 +195,18 @@ namespace MediaBrowser.Providers.TV
}
}
- if (ConfigurationManager.Configuration.DownloadSeasonImages.Backdrops && item.BackdropImagePaths.Count == 0)
+ if (ConfigurationManager.Configuration.DownloadSeasonImages.Backdrops && item.BackdropImagePaths.Count < backdropLimit)
{
var bdNo = item.BackdropImagePaths.Count;
foreach (var backdrop in data.Backdrops)
{
- var url = TVUtils.BannerUrl + backdrop;
+ var url = TVUtils.BannerUrl + backdrop.Url;
+
+ if (item.ContainsImageWithSourceUrl(url))
+ {
+ continue;
+ }
await _providerManager.SaveImage(item, url, RemoteSeriesProvider.Current.TvDbResourcePool, ImageType.Backdrop, bdNo, cancellationToken)
.ConfigureAwait(false);
@@ -260,6 +274,7 @@ namespace MediaBrowser.Providers.TV
string bannerType2 = null;
string url = null;
int? bannerSeason = null;
+ string resolution = null;
while (reader.Read())
{
@@ -319,7 +334,11 @@ namespace MediaBrowser.Providers.TV
}
else if (string.Equals(bannerType, "fanart", StringComparison.OrdinalIgnoreCase))
{
- data.Backdrops.Add(url);
+ data.Backdrops.Add(new ImageInfo
+ {
+ Url = url,
+ Resolution = resolution
+ });
}
}
}
diff --git a/MediaBrowser.Providers/TV/TvdbSeriesImageProvider.cs b/MediaBrowser.Providers/TV/TvdbSeriesImageProvider.cs
index be97285c6c..fa42257607 100644
--- a/MediaBrowser.Providers/TV/TvdbSeriesImageProvider.cs
+++ b/MediaBrowser.Providers/TV/TvdbSeriesImageProvider.cs
@@ -1,4 +1,5 @@
-using MediaBrowser.Common.Net;
+using System.Linq;
+using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.TV;
@@ -133,6 +134,15 @@ namespace MediaBrowser.Providers.TV
return base.CompareDate(item);
}
+ protected override bool NeedsRefreshInternal(BaseItem item, BaseProviderInfo providerInfo)
+ {
+ if (item.HasImage(ImageType.Primary) && item.HasImage(ImageType.Banner) && item.BackdropImagePaths.Count >= ConfigurationManager.Configuration.MaxBackdrops)
+ {
+ 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>
@@ -154,10 +164,10 @@ namespace MediaBrowser.Providers.TV
var imagesXmlPath = Path.Combine(seriesDataPath, "banners.xml");
- if (!series.HasImage(ImageType.Primary) || !series.HasImage(ImageType.Banner) || series.BackdropImagePaths.Count == 0)
- {
- var backdropLimit = ConfigurationManager.Configuration.MaxBackdrops;
+ var backdropLimit = ConfigurationManager.Configuration.MaxBackdrops;
+ if (!series.HasImage(ImageType.Primary) || !series.HasImage(ImageType.Banner) || series.BackdropImagePaths.Count < backdropLimit)
+ {
Directory.CreateDirectory(seriesDataPath);
try
@@ -171,13 +181,6 @@ namespace MediaBrowser.Providers.TV
}
}
- BaseProviderInfo data;
- if (!item.ProviderData.TryGetValue(Id, out data))
- {
- data = new BaseProviderInfo();
- item.ProviderData[Id] = data;
- }
-
SetLastRefreshed(item, DateTime.UtcNow);
return true;
}
@@ -213,13 +216,39 @@ namespace MediaBrowser.Providers.TV
}
}
- if (ConfigurationManager.Configuration.DownloadSeriesImages.Backdrops && item.BackdropImagePaths.Count == 0)
+ if (ConfigurationManager.Configuration.DownloadSeriesImages.Backdrops && item.BackdropImagePaths.Count < backdropLimit)
{
var bdNo = item.BackdropImagePaths.Count;
- foreach (var backdrop in data.Backdrops)
+ var eligibleBackdrops = data.Backdrops
+ .Where(i =>
+ {
+ if (string.IsNullOrEmpty(i.Resolution))
+ {
+ return true;
+ }
+
+ var parts = i.Resolution.Split('x');
+
+ int width;
+
+ if (int.TryParse(parts[0], NumberStyles.Any, UsCulture, out width))
+ {
+ return width >= ConfigurationManager.Configuration.MinSeriesBackdropWidth;
+ }
+
+ return true;
+ })
+ .ToList();
+
+ foreach (var backdrop in eligibleBackdrops)
{
- var url = TVUtils.BannerUrl + backdrop;
+ var url = TVUtils.BannerUrl + backdrop.Url;
+
+ if (item.ContainsImageWithSourceUrl(url))
+ {
+ continue;
+ }
await _providerManager.SaveImage(item, url, RemoteSeriesProvider.Current.TvDbResourcePool, ImageType.Backdrop, bdNo, cancellationToken)
.ConfigureAwait(false);
@@ -285,6 +314,7 @@ namespace MediaBrowser.Providers.TV
string type = null;
string url = null;
+ string resolution = null;
while (reader.Read())
{
@@ -312,13 +342,6 @@ namespace MediaBrowser.Providers.TV
return;
}
}
- else if (string.Equals(type, "fanart", StringComparison.OrdinalIgnoreCase))
- {
- if (data.Backdrops.Count >= backdropLimit)
- {
- return;
- }
- }
else
{
return;
@@ -333,6 +356,12 @@ namespace MediaBrowser.Providers.TV
break;
}
+ case "BannerType2":
+ {
+ resolution = reader.ReadElementContentAsString() ?? string.Empty;
+ break;
+ }
+
default:
reader.Skip();
break;
@@ -352,7 +381,11 @@ namespace MediaBrowser.Providers.TV
}
else if (string.Equals(type, "fanart", StringComparison.OrdinalIgnoreCase))
{
- data.Backdrops.Add(url);
+ data.Backdrops.Add(new ImageInfo
+ {
+ Url = url,
+ Resolution = resolution
+ });
}
}
}
@@ -364,6 +397,12 @@ namespace MediaBrowser.Providers.TV
public string LanguageBanner { get; set; }
public string Poster { get; set; }
public string Banner { get; set; }
- public List<string> Backdrops = new List<string>();
+ public List<ImageInfo> Backdrops = new List<ImageInfo>();
+ }
+
+ internal class ImageInfo
+ {
+ public string Url { get; set; }
+ public string Resolution { get; set; }
}
}
diff --git a/MediaBrowser.Server.Implementations/Library/Validators/ArtistsValidator.cs b/MediaBrowser.Server.Implementations/Library/Validators/ArtistsValidator.cs
index 7387b91662..51d31cd338 100644
--- a/MediaBrowser.Server.Implementations/Library/Validators/ArtistsValidator.cs
+++ b/MediaBrowser.Server.Implementations/Library/Validators/ArtistsValidator.cs
@@ -90,10 +90,22 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
MergeImages(musicArtist.Images, artist.Images);
// Merge backdrops
- var backdrops = musicArtist.BackdropImagePaths.ToList();
- backdrops.InsertRange(0, artist.BackdropImagePaths);
- artist.BackdropImagePaths = backdrops.Distinct(StringComparer.OrdinalIgnoreCase)
+ var additionalBackdrops = musicArtist
+ .BackdropImagePaths
+ .Except(artist.BackdropImagePaths)
.ToList();
+
+ var sources = additionalBackdrops
+ .Select(musicArtist.GetImageSourceInfo)
+ .ToList();
+
+ foreach (var path in additionalBackdrops)
+ {
+ artist.RemoveImageSourceForPath(path);
+ }
+
+ artist.BackdropImagePaths.AddRange(additionalBackdrops);
+ artist.ImageSources.AddRange(sources);
}
if (!artist.LockedFields.Contains(MetadataFields.Genres))
diff --git a/MediaBrowser.Server.Implementations/Providers/ImageSaver.cs b/MediaBrowser.Server.Implementations/Providers/ImageSaver.cs
index 18e64e414f..711b3f77ce 100644
--- a/MediaBrowser.Server.Implementations/Providers/ImageSaver.cs
+++ b/MediaBrowser.Server.Implementations/Providers/ImageSaver.cs
@@ -56,9 +56,11 @@ namespace MediaBrowser.Server.Implementations.Providers
/// <param name="mimeType">Type of the MIME.</param>
/// <param name="type">The type.</param>
/// <param name="imageIndex">Index of the image.</param>
+ /// <param name="sourceUrl">The source URL.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
- public async Task SaveImage(BaseItem item, Stream source, string mimeType, ImageType type, int? imageIndex, CancellationToken cancellationToken)
+ /// <exception cref="System.ArgumentNullException">mimeType</exception>
+ public async Task SaveImage(BaseItem item, Stream source, string mimeType, ImageType type, int? imageIndex, string sourceUrl, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(mimeType))
{
@@ -128,7 +130,7 @@ namespace MediaBrowser.Server.Implementations.Providers
}
// Set the path into the BaseItem
- SetImagePath(item, type, imageIndex, paths[0]);
+ SetImagePath(item, type, imageIndex, paths[0], sourceUrl);
// Delete the current path
if (!string.IsNullOrEmpty(currentPath) && !paths.Contains(currentPath, StringComparer.OrdinalIgnoreCase))
@@ -137,7 +139,18 @@ namespace MediaBrowser.Server.Implementations.Providers
try
{
- File.Delete(currentPath);
+ var currentFile = new FileInfo(currentPath);
+
+ // This will fail if the file is hidden
+ if (currentFile.Exists)
+ {
+ if ((currentFile.Attributes & FileAttributes.Hidden) == FileAttributes.Hidden)
+ {
+ currentFile.Attributes &= ~FileAttributes.Hidden;
+ }
+
+ currentFile.Delete();
+ }
}
finally
{
@@ -244,12 +257,11 @@ namespace MediaBrowser.Server.Implementations.Providers
/// <param name="type">The type.</param>
/// <param name="imageIndex">Index of the image.</param>
/// <param name="path">The path.</param>
- /// <exception cref="System.ArgumentNullException">
- /// imageIndex
+ /// <param name="sourceUrl">The source URL.</param>
+ /// <exception cref="System.ArgumentNullException">imageIndex
/// or
- /// imageIndex
- /// </exception>
- private void SetImagePath(BaseItem item, ImageType type, int? imageIndex, string path)
+ /// imageIndex</exception>
+ private void SetImagePath(BaseItem item, ImageType type, int? imageIndex, string path, string sourceUrl)
{
switch (type)
{
@@ -282,6 +294,15 @@ namespace MediaBrowser.Server.Implementations.Providers
{
item.BackdropImagePaths.Add(path);
}
+
+ if (string.IsNullOrEmpty(sourceUrl))
+ {
+ item.RemoveImageSourceForPath(path);
+ }
+ else
+ {
+ item.AddImageSource(path, sourceUrl);
+ }
break;
default:
item.SetImage(type, path);
diff --git a/MediaBrowser.Server.Implementations/Providers/ProviderManager.cs b/MediaBrowser.Server.Implementations/Providers/ProviderManager.cs
index 8bd5012713..19230cecdb 100644
--- a/MediaBrowser.Server.Implementations/Providers/ProviderManager.cs
+++ b/MediaBrowser.Server.Implementations/Providers/ProviderManager.cs
@@ -325,7 +325,7 @@ namespace MediaBrowser.Server.Implementations.Providers
}).ConfigureAwait(false);
- await SaveImage(item, response.Content, response.ContentType, type, imageIndex, cancellationToken)
+ await SaveImage(item, response.Content, response.ContentType, type, imageIndex, url, cancellationToken)
.ConfigureAwait(false);
}
@@ -337,11 +337,12 @@ namespace MediaBrowser.Server.Implementations.Providers
/// <param name="mimeType">Type of the MIME.</param>
/// <param name="type">The type.</param>
/// <param name="imageIndex">Index of the image.</param>
+ /// <param name="sourceUrl">The source URL.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
- public Task SaveImage(BaseItem item, Stream source, string mimeType, ImageType type, int? imageIndex, CancellationToken cancellationToken)
+ public Task SaveImage(BaseItem item, Stream source, string mimeType, ImageType type, int? imageIndex, string sourceUrl, CancellationToken cancellationToken)
{
- return new ImageSaver(ConfigurationManager, _directoryWatchers).SaveImage(item, source, mimeType, type, imageIndex, cancellationToken);
+ return new ImageSaver(ConfigurationManager, _directoryWatchers).SaveImage(item, source, mimeType, type, imageIndex, sourceUrl, cancellationToken);
}
}
}
diff --git a/MediaBrowser.Server.Implementations/Session/SessionManager.cs b/MediaBrowser.Server.Implementations/Session/SessionManager.cs
index 265cab1e71..473f2c67a7 100644
--- a/MediaBrowser.Server.Implementations/Session/SessionManager.cs
+++ b/MediaBrowser.Server.Implementations/Session/SessionManager.cs
@@ -174,6 +174,11 @@ namespace MediaBrowser.Server.Implementations.Session
/// <param name="item">The item.</param>
private void RemoveNowPlayingItem(SessionInfo session, BaseItem item)
{
+ if (item == null)
+ {
+ throw new ArgumentNullException("item");
+ }
+
if (session.NowPlayingItem != null && session.NowPlayingItem.Id == item.Id)
{
session.NowPlayingItem = null;
@@ -319,6 +324,16 @@ namespace MediaBrowser.Server.Implementations.Session
throw new ArgumentNullException("info");
}
+ if (info.Item == null)
+ {
+ throw new ArgumentException("PlaybackStopInfo.Item cannot be null");
+ }
+
+ if (info.SessionId == Guid.Empty)
+ {
+ throw new ArgumentException("PlaybackStopInfo.SessionId cannot be Guid.Empty");
+ }
+
if (info.PositionTicks.HasValue && info.PositionTicks.Value < 0)
{
throw new ArgumentOutOfRangeException("positionTicks");