diff --git a/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs b/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs index c29924c35..2e0035f5d 100644 --- a/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs +++ b/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs @@ -285,17 +285,8 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager EnsureSuccessStatusCode(httpResponse); options.CancellationToken.ThrowIfCancellationRequested(); - - return new HttpResponseInfo - { - Content = httpResponse.GetResponseStream(), - StatusCode = httpResponse.StatusCode, - - ContentType = httpResponse.ContentType, - - Headers = httpResponse.Headers - }; + return GetResponseInfo(httpResponse, httpResponse.GetResponseStream(), GetContentLength(httpResponse)); } using (var response = await httpWebRequest.GetResponseAsync().ConfigureAwait(false)) @@ -314,16 +305,7 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager memoryStream.Position = 0; - return new HttpResponseInfo - { - Content = memoryStream, - - StatusCode = httpResponse.StatusCode, - - ContentType = httpResponse.ContentType, - - Headers = httpResponse.Headers - }; + return GetResponseInfo(httpResponse, memoryStream, memoryStream.Length); } } } @@ -367,6 +349,38 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager } } + private HttpResponseInfo GetResponseInfo(HttpWebResponse httpResponse, Stream content, long? contentLength) + { + return new HttpResponseInfo + { + Content = content, + + StatusCode = httpResponse.StatusCode, + + ContentType = httpResponse.ContentType, + + Headers = httpResponse.Headers, + + ContentLength = contentLength + }; + } + + private HttpResponseInfo GetResponseInfo(HttpWebResponse httpResponse, string tempFile, long? contentLength) + { + return new HttpResponseInfo + { + TempFilePath = tempFile, + + StatusCode = httpResponse.StatusCode, + + ContentType = httpResponse.ContentType, + + Headers = httpResponse.Headers, + + ContentLength = contentLength + }; + } + public Task Post(HttpRequestOptions options) { return SendAsync(options, "POST"); @@ -493,16 +507,7 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager options.Progress.Report(100); - return new HttpResponseInfo - { - TempFilePath = tempFile, - - StatusCode = httpResponse.StatusCode, - - ContentType = httpResponse.ContentType, - - Headers = httpResponse.Headers - }; + return GetResponseInfo(httpResponse, tempFile, contentLength); } } catch (OperationCanceledException ex) diff --git a/MediaBrowser.Common/Net/HttpResponseInfo.cs b/MediaBrowser.Common/Net/HttpResponseInfo.cs index 83c98007d..bc0319209 100644 --- a/MediaBrowser.Common/Net/HttpResponseInfo.cs +++ b/MediaBrowser.Common/Net/HttpResponseInfo.cs @@ -33,6 +33,12 @@ namespace MediaBrowser.Common.Net /// The temp file path. public string TempFilePath { get; set; } + /// + /// Gets or sets the length of the content. + /// + /// The length of the content. + public long? ContentLength { get; set; } + /// /// Gets or sets the headers. /// diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index e682a0d2f..954b36bf2 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -940,7 +940,7 @@ namespace MediaBrowser.Controller.Entities // First get using the cached Id if (info.ItemId != Guid.Empty) { - item = LibraryManager.GetItemById(info.ItemId) as BaseItem; + item = LibraryManager.GetItemById(info.ItemId); } // If still null, search by path @@ -1098,7 +1098,9 @@ namespace MediaBrowser.Controller.Entities return this; } - return RecursiveChildren.FirstOrDefault(i => string.Equals(i.Path, path, StringComparison.OrdinalIgnoreCase) || i.PhysicalLocations.Contains(path, StringComparer.OrdinalIgnoreCase)); + return RecursiveChildren.FirstOrDefault(i => string.Equals(i.Path, path, StringComparison.OrdinalIgnoreCase) || + (!i.IsFolder && !i.IsInMixedFolder && string.Equals(i.ContainingFolderPath, path, StringComparison.OrdinalIgnoreCase)) || + i.PhysicalLocations.Contains(path, StringComparer.OrdinalIgnoreCase)); } public override bool IsPlayed(User user) diff --git a/MediaBrowser.Controller/Entities/TV/Season.cs b/MediaBrowser.Controller/Entities/TV/Season.cs index 2847c397e..4fadd8f6e 100644 --- a/MediaBrowser.Controller/Entities/TV/Season.cs +++ b/MediaBrowser.Controller/Entities/TV/Season.cs @@ -250,7 +250,16 @@ namespace MediaBrowser.Controller.Entities.TV /// SeasonInfo. public SeasonInfo GetLookupInfo() { - return GetItemLookupInfo(); + var id = GetItemLookupInfo(); + + var series = Series; + + if (series != null) + { + id.SeriesProviderIds = series.ProviderIds; + } + + return id; } /// diff --git a/MediaBrowser.Controller/Providers/BaseItemXmlParser.cs b/MediaBrowser.Controller/Providers/BaseItemXmlParser.cs index ada0aa6e2..0163dec20 100644 --- a/MediaBrowser.Controller/Providers/BaseItemXmlParser.cs +++ b/MediaBrowser.Controller/Providers/BaseItemXmlParser.cs @@ -683,6 +683,22 @@ namespace MediaBrowser.Controller.Providers } break; } + case "MusicbrainzId": + { + var mbz = reader.ReadElementContentAsString(); + if (!string.IsNullOrWhiteSpace(mbz)) + { + if (item is MusicAlbum) + { + item.SetProviderId(MetadataProviders.MusicBrainzAlbum, mbz); + } + else if (item is MusicArtist) + { + item.SetProviderId(MetadataProviders.MusicBrainzArtist, mbz); + } + } + break; + } case "MusicBrainzAlbumId": { var mbz = reader.ReadElementContentAsString(); diff --git a/MediaBrowser.Controller/Providers/ItemLookupInfo.cs b/MediaBrowser.Controller/Providers/ItemLookupInfo.cs index 665da28f4..c2409715a 100644 --- a/MediaBrowser.Controller/Providers/ItemLookupInfo.cs +++ b/MediaBrowser.Controller/Providers/ItemLookupInfo.cs @@ -152,6 +152,11 @@ namespace MediaBrowser.Controller.Providers public class SeasonInfo : ItemLookupInfo { - + public Dictionary SeriesProviderIds { get; set; } + + public SeasonInfo() + { + SeriesProviderIds = new Dictionary(StringComparer.OrdinalIgnoreCase); + } } } diff --git a/MediaBrowser.Providers/All/LocalImageProvider.cs b/MediaBrowser.Providers/All/LocalImageProvider.cs index 354b081cf..dbdaa87a1 100644 --- a/MediaBrowser.Providers/All/LocalImageProvider.cs +++ b/MediaBrowser.Providers/All/LocalImageProvider.cs @@ -172,7 +172,7 @@ namespace MediaBrowser.Providers.All AddImage(files, images, imagePrefix + "movie", ImageType.Primary); } - if (string.IsNullOrEmpty(item.Path)) + if (!string.IsNullOrEmpty(item.Path)) { var name = Path.GetFileNameWithoutExtension(item.Path); diff --git a/MediaBrowser.Providers/Manager/ItemImageProvider.cs b/MediaBrowser.Providers/Manager/ItemImageProvider.cs index 7610f7249..a0ab069d3 100644 --- a/MediaBrowser.Providers/Manager/ItemImageProvider.cs +++ b/MediaBrowser.Providers/Manager/ItemImageProvider.cs @@ -60,8 +60,8 @@ namespace MediaBrowser.Providers.Manager var providerIds = new List(); // In order to avoid duplicates, only download these if there are none already - var backdropLimit = item.HasImage(ImageType.Backdrop) ? 0 : savedOptions.GetLimit(ImageType.Backdrop); - var screenshotLimit = item.HasImage(ImageType.Screenshot) ? 0 : savedOptions.GetLimit(ImageType.Screenshot); + var backdropLimit = savedOptions.GetLimit(ImageType.Backdrop); + var screenshotLimit = savedOptions.GetLimit(ImageType.Screenshot); foreach (var provider in providers) { @@ -362,9 +362,25 @@ namespace MediaBrowser.Providers.Manager { var response = await provider.GetImageResponse(url, cancellationToken).ConfigureAwait(false); + // If there's already an image of the same size, skip it + if (response.ContentLength.HasValue) + { + try + { + if (item.GetImages(imageType).Any(i => new FileInfo(i.Path).Length == response.ContentLength.Value)) + { + response.Content.Dispose(); + continue; + } + } + catch (IOException ex) + { + _logger.ErrorException("Error examining images", ex); + } + } + await _providerManager.SaveImage(item, response.Content, response.ContentType, imageType, null, cancellationToken).ConfigureAwait(false); result.UpdateType = result.UpdateType | ItemUpdateType.ImageUpdate; - break; } catch (HttpException ex) { diff --git a/MediaBrowser.Providers/MediaBrowser.Providers.csproj b/MediaBrowser.Providers/MediaBrowser.Providers.csproj index 393aae6fe..a5ea1b64b 100644 --- a/MediaBrowser.Providers/MediaBrowser.Providers.csproj +++ b/MediaBrowser.Providers/MediaBrowser.Providers.csproj @@ -66,6 +66,9 @@ + + Properties\SharedVersion.cs + diff --git a/MediaBrowser.Providers/Movies/FanartMovieImageProvider.cs b/MediaBrowser.Providers/Movies/FanartMovieImageProvider.cs index 730d66cc2..9182587b1 100644 --- a/MediaBrowser.Providers/Movies/FanartMovieImageProvider.cs +++ b/MediaBrowser.Providers/Movies/FanartMovieImageProvider.cs @@ -334,7 +334,7 @@ namespace MediaBrowser.Providers.Movies { CancellationToken = cancellationToken, Url = url, - ResourcePool = FanartArtistProvider.FanArtResourcePool + ResourcePool = FanartArtistProvider.Current.FanArtResourcePool }); } @@ -410,7 +410,7 @@ namespace MediaBrowser.Providers.Movies using (var response = await _httpClient.Get(new HttpRequestOptions { Url = url, - ResourcePool = FanartArtistProvider.FanArtResourcePool, + ResourcePool = FanartArtistProvider.Current.FanArtResourcePool, CancellationToken = cancellationToken }).ConfigureAwait(false)) diff --git a/MediaBrowser.Providers/Music/FanArtAlbumProvider.cs b/MediaBrowser.Providers/Music/FanArtAlbumProvider.cs index 93db4f5b4..ccab30bc6 100644 --- a/MediaBrowser.Providers/Music/FanArtAlbumProvider.cs +++ b/MediaBrowser.Providers/Music/FanArtAlbumProvider.cs @@ -346,7 +346,7 @@ namespace MediaBrowser.Providers.Music { CancellationToken = cancellationToken, Url = url, - ResourcePool = FanartArtistProvider.FanArtResourcePool + ResourcePool = FanartArtistProvider.Current.FanArtResourcePool }); } diff --git a/MediaBrowser.Providers/Music/FanArtArtistProvider.cs b/MediaBrowser.Providers/Music/FanArtArtistProvider.cs index b5557d6f0..270219a2b 100644 --- a/MediaBrowser.Providers/Music/FanArtArtistProvider.cs +++ b/MediaBrowser.Providers/Music/FanArtArtistProvider.cs @@ -22,7 +22,7 @@ namespace MediaBrowser.Providers.Music { public class FanartArtistProvider : IRemoteImageProvider, IHasChangeMonitor, IHasOrder { - internal static readonly SemaphoreSlim FanArtResourcePool = new SemaphoreSlim(3, 3); + internal readonly SemaphoreSlim FanArtResourcePool = new SemaphoreSlim(3, 3); internal const string ApiKey = "5c6b04c68e904cfed1e6cbc9a9e683d4"; private const string FanArtBaseUrl = "http://api.fanart.tv/webservice/artist/{0}/{1}/xml/all/1/1"; diff --git a/MediaBrowser.Providers/Music/FanArtUpdatesPostScanTask.cs b/MediaBrowser.Providers/Music/FanArtUpdatesPostScanTask.cs index 525886055..4c6706287 100644 --- a/MediaBrowser.Providers/Music/FanArtUpdatesPostScanTask.cs +++ b/MediaBrowser.Providers/Music/FanArtUpdatesPostScanTask.cs @@ -110,7 +110,7 @@ namespace MediaBrowser.Providers.Music Url = string.Format(UpdatesUrl, FanartArtistProvider.ApiKey, lastUpdateTime), CancellationToken = cancellationToken, EnableHttpCompression = true, - ResourcePool = FanartArtistProvider.FanArtResourcePool + ResourcePool = FanartArtistProvider.Current.FanArtResourcePool }).ConfigureAwait(false)) { diff --git a/MediaBrowser.Providers/Music/MusicExternalIds.cs b/MediaBrowser.Providers/Music/MusicExternalIds.cs index e7340d018..a25ab9deb 100644 --- a/MediaBrowser.Providers/Music/MusicExternalIds.cs +++ b/MediaBrowser.Providers/Music/MusicExternalIds.cs @@ -46,7 +46,7 @@ namespace MediaBrowser.Providers.Music public bool Supports(IHasProviderIds item) { - return item is Audio || item is MusicAlbum; + return item is Audio; } } diff --git a/MediaBrowser.Providers/Omdb/OmdbProvider.cs b/MediaBrowser.Providers/Omdb/OmdbProvider.cs index 07fee988c..75f9cf06d 100644 --- a/MediaBrowser.Providers/Omdb/OmdbProvider.cs +++ b/MediaBrowser.Providers/Omdb/OmdbProvider.cs @@ -12,7 +12,7 @@ namespace MediaBrowser.Providers.Omdb { public class OmdbProvider { - internal readonly SemaphoreSlim ResourcePool = new SemaphoreSlim(1, 1); + private static readonly SemaphoreSlim ResourcePool = new SemaphoreSlim(1, 1); private readonly IJsonSerializer _jsonSerializer; private readonly IHttpClient _httpClient; private readonly CultureInfo _usCulture = new CultureInfo("en-US"); diff --git a/MediaBrowser.Providers/Properties/AssemblyInfo.cs b/MediaBrowser.Providers/Properties/AssemblyInfo.cs index d69df1581..a11011569 100644 --- a/MediaBrowser.Providers/Properties/AssemblyInfo.cs +++ b/MediaBrowser.Providers/Properties/AssemblyInfo.cs @@ -28,9 +28,4 @@ using System.Runtime.InteropServices; // Minor Version // Build Number // Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] +// \ No newline at end of file diff --git a/MediaBrowser.Providers/Savers/XmlSaverHelpers.cs b/MediaBrowser.Providers/Savers/XmlSaverHelpers.cs index eed91dfaa..b8ab55db0 100644 --- a/MediaBrowser.Providers/Savers/XmlSaverHelpers.cs +++ b/MediaBrowser.Providers/Savers/XmlSaverHelpers.cs @@ -53,6 +53,10 @@ namespace MediaBrowser.Providers.Savers "MusicBrainzAlbumArtistId", "MusicBrainzAlbumId", "MusicBrainzReleaseGroupId", + + // Old - not used anymore + "MusicbrainzId", + "Overview", "Persons", "PlotKeywords", diff --git a/MediaBrowser.Providers/TV/FanArtSeasonProvider.cs b/MediaBrowser.Providers/TV/FanArtSeasonProvider.cs index 908094bdd..9c5d70e3d 100644 --- a/MediaBrowser.Providers/TV/FanArtSeasonProvider.cs +++ b/MediaBrowser.Providers/TV/FanArtSeasonProvider.cs @@ -264,7 +264,7 @@ namespace MediaBrowser.Providers.TV { CancellationToken = cancellationToken, Url = url, - ResourcePool = FanartArtistProvider.FanArtResourcePool + ResourcePool = FanartArtistProvider.Current.FanArtResourcePool }); } diff --git a/MediaBrowser.Providers/TV/FanArtTvUpdatesPostScanTask.cs b/MediaBrowser.Providers/TV/FanArtTvUpdatesPostScanTask.cs index 1b2530dba..33100db73 100644 --- a/MediaBrowser.Providers/TV/FanArtTvUpdatesPostScanTask.cs +++ b/MediaBrowser.Providers/TV/FanArtTvUpdatesPostScanTask.cs @@ -111,7 +111,7 @@ namespace MediaBrowser.Providers.TV Url = string.Format(UpdatesUrl, FanartArtistProvider.ApiKey, lastUpdateTime), CancellationToken = cancellationToken, EnableHttpCompression = true, - ResourcePool = FanartArtistProvider.FanArtResourcePool + ResourcePool = FanartArtistProvider.Current.FanArtResourcePool }).ConfigureAwait(false)) { diff --git a/MediaBrowser.Providers/TV/FanartSeriesProvider.cs b/MediaBrowser.Providers/TV/FanartSeriesProvider.cs index b640e373b..f8fee5e3d 100644 --- a/MediaBrowser.Providers/TV/FanartSeriesProvider.cs +++ b/MediaBrowser.Providers/TV/FanartSeriesProvider.cs @@ -332,7 +332,7 @@ namespace MediaBrowser.Providers.TV { CancellationToken = cancellationToken, Url = url, - ResourcePool = FanartArtistProvider.FanArtResourcePool + ResourcePool = FanartArtistProvider.Current.FanArtResourcePool }); } @@ -414,7 +414,7 @@ namespace MediaBrowser.Providers.TV using (var response = await _httpClient.Get(new HttpRequestOptions { Url = url, - ResourcePool = FanartArtistProvider.FanArtResourcePool, + ResourcePool = FanartArtistProvider.Current.FanArtResourcePool, CancellationToken = cancellationToken }).ConfigureAwait(false)) diff --git a/MediaBrowser.Providers/TV/TvdbSeriesProvider.cs b/MediaBrowser.Providers/TV/TvdbSeriesProvider.cs index 920da9b10..51eec8668 100644 --- a/MediaBrowser.Providers/TV/TvdbSeriesProvider.cs +++ b/MediaBrowser.Providers/TV/TvdbSeriesProvider.cs @@ -175,23 +175,25 @@ namespace MediaBrowser.Providers.TV var download = false; var automaticUpdatesEnabled = _config.Configuration.EnableTvDbUpdates; + const int cacheDays = 3; + var seriesFile = files.FirstOrDefault(i => string.Equals(seriesXmlFilename, i.Name, StringComparison.OrdinalIgnoreCase)); // No need to check age if automatic updates are enabled - if (seriesFile == null || !seriesFile.Exists || (!automaticUpdatesEnabled && (DateTime.UtcNow - _fileSystem.GetLastWriteTimeUtc(seriesFile)).TotalDays > 7)) + if (seriesFile == null || !seriesFile.Exists || (!automaticUpdatesEnabled && (DateTime.UtcNow - _fileSystem.GetLastWriteTimeUtc(seriesFile)).TotalDays > cacheDays)) { download = true; } var actorsXml = files.FirstOrDefault(i => string.Equals("actors.xml", i.Name, StringComparison.OrdinalIgnoreCase)); // No need to check age if automatic updates are enabled - if (actorsXml == null || !actorsXml.Exists || (!automaticUpdatesEnabled && (DateTime.UtcNow - _fileSystem.GetLastWriteTimeUtc(actorsXml)).TotalDays > 7)) + if (actorsXml == null || !actorsXml.Exists || (!automaticUpdatesEnabled && (DateTime.UtcNow - _fileSystem.GetLastWriteTimeUtc(actorsXml)).TotalDays > cacheDays)) { download = true; } var bannersXml = files.FirstOrDefault(i => string.Equals("banners.xml", i.Name, StringComparison.OrdinalIgnoreCase)); // No need to check age if automatic updates are enabled - if (bannersXml == null || !bannersXml.Exists || (!automaticUpdatesEnabled && (DateTime.UtcNow - _fileSystem.GetLastWriteTimeUtc(bannersXml)).TotalDays > 7)) + if (bannersXml == null || !bannersXml.Exists || (!automaticUpdatesEnabled && (DateTime.UtcNow - _fileSystem.GetLastWriteTimeUtc(bannersXml)).TotalDays > cacheDays)) { download = true; } diff --git a/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs b/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs index 5bf6587a9..b91067dd7 100644 --- a/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs +++ b/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs @@ -239,10 +239,17 @@ namespace MediaBrowser.Server.Implementations.FileOrganization var folder = Path.GetDirectoryName(targetPath); var targetFileNameWithoutExtension = Path.GetFileNameWithoutExtension(targetPath); - var filesOfOtherExtensions = Directory.EnumerateFiles(folder, "*", SearchOption.TopDirectoryOnly) - .Where(i => EntityResolutionHelper.IsVideoFile(i) && string.Equals(Path.GetFileNameWithoutExtension(i), targetFileNameWithoutExtension, StringComparison.OrdinalIgnoreCase)); + try + { + var filesOfOtherExtensions = Directory.EnumerateFiles(folder, "*", SearchOption.TopDirectoryOnly) + .Where(i => EntityResolutionHelper.IsVideoFile(i) && string.Equals(Path.GetFileNameWithoutExtension(i), targetFileNameWithoutExtension, StringComparison.OrdinalIgnoreCase)); - episodePaths.AddRange(filesOfOtherExtensions); + episodePaths.AddRange(filesOfOtherExtensions); + } + catch (DirectoryNotFoundException) + { + // No big deal. Maybe the season folder doesn't already exist. + } return episodePaths.Where(i => !string.Equals(i, targetPath, StringComparison.OrdinalIgnoreCase)) .Distinct(StringComparer.OrdinalIgnoreCase) diff --git a/MediaBrowser.ServerApplication/MainStartup.cs b/MediaBrowser.ServerApplication/MainStartup.cs index 7621d8b4b..6afe9367e 100644 --- a/MediaBrowser.ServerApplication/MainStartup.cs +++ b/MediaBrowser.ServerApplication/MainStartup.cs @@ -216,11 +216,7 @@ namespace MediaBrowser.ServerApplication var initProgress = new Progress(); - if (runService) - { - StartService(logManager); - } - else + if (!runService) { ShowSplashScreen(_appHost.ApplicationVersion, initProgress, logManager.GetLogger("Splash")); @@ -235,18 +231,22 @@ namespace MediaBrowser.ServerApplication task = _appHost.RunStartupTasks(); Task.WaitAll(task); - if (!runService) + SystemEvents.SessionEnding += SystemEvents_SessionEnding; + SystemEvents.SessionSwitch += SystemEvents_SessionSwitch; + + if (runService) + { + StartService(logManager); + } + else { HideSplashScreen(); ShowTrayIcon(); + + task = ApplicationTaskCompletionSource.Task; + Task.WaitAll(task); } - - SystemEvents.SessionEnding += SystemEvents_SessionEnding; - SystemEvents.SessionSwitch += SystemEvents_SessionSwitch; - - task = ApplicationTaskCompletionSource.Task; - Task.WaitAll(task); } private static ServerNotifyIcon _serverNotifyIcon;