diff options
Diffstat (limited to 'MediaBrowser.Providers/Manager')
| -rw-r--r-- | MediaBrowser.Providers/Manager/ImageSaver.cs | 1 | ||||
| -rw-r--r-- | MediaBrowser.Providers/Manager/ItemImageProvider.cs | 17 | ||||
| -rw-r--r-- | MediaBrowser.Providers/Manager/MetadataService.cs | 118 | ||||
| -rw-r--r-- | MediaBrowser.Providers/Manager/ProviderManager.cs | 61 |
4 files changed, 93 insertions, 104 deletions
diff --git a/MediaBrowser.Providers/Manager/ImageSaver.cs b/MediaBrowser.Providers/Manager/ImageSaver.cs index 9a676cb2e..8f6aa2db3 100644 --- a/MediaBrowser.Providers/Manager/ImageSaver.cs +++ b/MediaBrowser.Providers/Manager/ImageSaver.cs @@ -291,6 +291,7 @@ namespace MediaBrowser.Providers.Manager var fileStreamOptions = AsyncFile.WriteOptions; fileStreamOptions.Mode = FileMode.Create; + fileStreamOptions.Options = FileOptions.WriteThrough; if (source.CanSeek) { fileStreamOptions.PreallocationSize = source.Length; diff --git a/MediaBrowser.Providers/Manager/ItemImageProvider.cs b/MediaBrowser.Providers/Manager/ItemImageProvider.cs index 64954818a..ee22b4bc6 100644 --- a/MediaBrowser.Providers/Manager/ItemImageProvider.cs +++ b/MediaBrowser.Providers/Manager/ItemImageProvider.cs @@ -6,6 +6,7 @@ using System.IO; using System.Linq; using System.Net; using System.Net.Http; +using System.Net.Mime; using System.Threading; using System.Threading.Tasks; using MediaBrowser.Controller.Entities; @@ -551,10 +552,16 @@ namespace MediaBrowser.Providers.Manager var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); await using (stream.ConfigureAwait(false)) { + var mimetype = response.Content.Headers.ContentType?.MediaType; + if (mimetype is null || mimetype.Equals(MediaTypeNames.Application.Octet, StringComparison.OrdinalIgnoreCase)) + { + mimetype = MimeTypes.GetMimeType(response.RequestMessage.RequestUri.GetLeftPart(UriPartial.Path)); + } + await _providerManager.SaveImage( item, stream, - response.Content.Headers.ContentType?.MediaType, + mimetype, type, null, cancellationToken).ConfigureAwait(false); @@ -677,10 +684,16 @@ namespace MediaBrowser.Providers.Manager var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); await using (stream.ConfigureAwait(false)) { + var mimetype = response.Content.Headers.ContentType?.MediaType; + if (mimetype is null || mimetype.Equals(MediaTypeNames.Application.Octet, StringComparison.OrdinalIgnoreCase)) + { + mimetype = MimeTypes.GetMimeType(response.RequestMessage.RequestUri.GetLeftPart(UriPartial.Path)); + } + await _providerManager.SaveImage( item, stream, - response.Content.Headers.ContentType?.MediaType, + mimetype, imageType, null, cancellationToken).ConfigureAwait(false); diff --git a/MediaBrowser.Providers/Manager/MetadataService.cs b/MediaBrowser.Providers/Manager/MetadataService.cs index 7203bf115..e8994693d 100644 --- a/MediaBrowser.Providers/Manager/MetadataService.cs +++ b/MediaBrowser.Providers/Manager/MetadataService.cs @@ -74,10 +74,11 @@ namespace MediaBrowser.Providers.Manager public virtual async Task<ItemUpdateType> RefreshMetadata(BaseItem item, MetadataRefreshOptions refreshOptions, CancellationToken cancellationToken) { var itemOfType = (TItemType)item; - var updateType = ItemUpdateType.None; - var libraryOptions = LibraryManager.GetLibraryOptions(item); + var isFirstRefresh = item.DateLastRefreshed == default; + var hasRefreshedMetadata = true; + var hasRefreshedImages = true; var requiresRefresh = libraryOptions.AutomaticRefreshIntervalDays > 0 && (DateTime.UtcNow - item.DateLastRefreshed).TotalDays >= libraryOptions.AutomaticRefreshIntervalDays; @@ -131,9 +132,10 @@ namespace MediaBrowser.Providers.Manager People = LibraryManager.GetPeople(item) }; - bool hasRefreshedMetadata = true; - bool hasRefreshedImages = true; - var isFirstRefresh = item.DateLastRefreshed == default; + var beforeSaveResult = BeforeSave(itemOfType, isFirstRefresh || refreshOptions.ReplaceAllMetadata || refreshOptions.MetadataRefreshMode == MetadataRefreshMode.FullRefresh || requiresRefresh || refreshOptions.ForceSave, updateType); + updateType |= beforeSaveResult; + + updateType = await SaveInternal(item, refreshOptions, updateType, isFirstRefresh, requiresRefresh, metadataResult, cancellationToken).ConfigureAwait(false); // Next run metadata providers if (refreshOptions.MetadataRefreshMode != MetadataRefreshMode.None) @@ -188,43 +190,43 @@ namespace MediaBrowser.Providers.Manager } } - var beforeSaveResult = BeforeSave(itemOfType, isFirstRefresh || refreshOptions.ReplaceAllMetadata || refreshOptions.MetadataRefreshMode == MetadataRefreshMode.FullRefresh || requiresRefresh || refreshOptions.ForceSave, updateType); - updateType |= beforeSaveResult; + if (hasRefreshedMetadata && hasRefreshedImages) + { + item.DateLastRefreshed = DateTime.UtcNow; + } - // Save if changes were made, or it's never been saved before - if (refreshOptions.ForceSave || updateType > ItemUpdateType.None || isFirstRefresh || refreshOptions.ReplaceAllMetadata || requiresRefresh) + updateType = await SaveInternal(item, refreshOptions, updateType, isFirstRefresh, requiresRefresh, metadataResult, cancellationToken).ConfigureAwait(false); + + await AfterMetadataRefresh(itemOfType, refreshOptions, cancellationToken).ConfigureAwait(false); + + return updateType; + + async Task<ItemUpdateType> SaveInternal(BaseItem item, MetadataRefreshOptions refreshOptions, ItemUpdateType updateType, bool isFirstRefresh, bool requiresRefresh, MetadataResult<TItemType> metadataResult, CancellationToken cancellationToken) { - if (item.IsFileProtocol) + // Save if changes were made, or it's never been saved before + if (refreshOptions.ForceSave || updateType > ItemUpdateType.None || isFirstRefresh || refreshOptions.ReplaceAllMetadata || requiresRefresh) { - var file = TryGetFile(item.Path, refreshOptions.DirectoryService); - if (file is not null) + if (item.IsFileProtocol) { - item.DateModified = file.LastWriteTimeUtc; + var file = TryGetFile(item.Path, refreshOptions.DirectoryService); + if (file is not null) + { + item.DateModified = file.LastWriteTimeUtc; + } } - } - // If any of these properties are set then make sure the updateType is not None, just to force everything to save - if (refreshOptions.ForceSave || refreshOptions.ReplaceAllMetadata) - { - updateType |= ItemUpdateType.MetadataDownload; - } + // If any of these properties are set then make sure the updateType is not None, just to force everything to save + if (refreshOptions.ForceSave || refreshOptions.ReplaceAllMetadata) + { + updateType |= ItemUpdateType.MetadataDownload; + } - if (hasRefreshedMetadata && hasRefreshedImages) - { - item.DateLastRefreshed = DateTime.UtcNow; - } - else - { - item.DateLastRefreshed = default; + // Save to database + await SaveItemAsync(metadataResult, updateType, cancellationToken).ConfigureAwait(false); } - // Save to database - await SaveItemAsync(metadataResult, updateType, cancellationToken).ConfigureAwait(false); + return updateType; } - - await AfterMetadataRefresh(itemOfType, refreshOptions, cancellationToken).ConfigureAwait(false); - - return updateType; } private void ApplySearchResult(ItemLookupInfo lookupInfo, RemoteSearchResult result) @@ -322,17 +324,17 @@ namespace MediaBrowser.Providers.Manager return false; } - protected virtual IList<BaseItem> GetChildrenForMetadataUpdates(TItemType item) + protected virtual IReadOnlyList<BaseItem> GetChildrenForMetadataUpdates(TItemType item) { if (item is Folder folder) { return folder.GetRecursiveChildren(); } - return Array.Empty<BaseItem>(); + return []; } - protected virtual ItemUpdateType UpdateMetadataFromChildren(TItemType item, IList<BaseItem> children, bool isFullRefresh, ItemUpdateType currentUpdateType) + protected virtual ItemUpdateType UpdateMetadataFromChildren(TItemType item, IReadOnlyList<BaseItem> children, bool isFullRefresh, ItemUpdateType currentUpdateType) { var updateType = ItemUpdateType.None; @@ -371,7 +373,7 @@ namespace MediaBrowser.Providers.Manager return updateType; } - private ItemUpdateType UpdateCumulativeRunTimeTicks(TItemType item, IList<BaseItem> children) + private ItemUpdateType UpdateCumulativeRunTimeTicks(TItemType item, IReadOnlyList<BaseItem> children) { if (item is Folder folder && folder.SupportsCumulativeRunTimeTicks) { @@ -395,7 +397,7 @@ namespace MediaBrowser.Providers.Manager return ItemUpdateType.None; } - private ItemUpdateType UpdateDateLastMediaAdded(TItemType item, IList<BaseItem> children) + private ItemUpdateType UpdateDateLastMediaAdded(TItemType item, IReadOnlyList<BaseItem> children) { var updateType = ItemUpdateType.None; @@ -429,7 +431,7 @@ namespace MediaBrowser.Providers.Manager return updateType; } - private ItemUpdateType UpdatePremiereDate(TItemType item, IList<BaseItem> children) + private ItemUpdateType UpdatePremiereDate(TItemType item, IReadOnlyList<BaseItem> children) { var updateType = ItemUpdateType.None; @@ -467,7 +469,7 @@ namespace MediaBrowser.Providers.Manager return updateType; } - private ItemUpdateType UpdateGenres(TItemType item, IList<BaseItem> children) + private ItemUpdateType UpdateGenres(TItemType item, IReadOnlyList<BaseItem> children) { var updateType = ItemUpdateType.None; @@ -488,7 +490,7 @@ namespace MediaBrowser.Providers.Manager return updateType; } - private ItemUpdateType UpdateStudios(TItemType item, IList<BaseItem> children) + private ItemUpdateType UpdateStudios(TItemType item, IReadOnlyList<BaseItem> children) { var updateType = ItemUpdateType.None; @@ -509,7 +511,7 @@ namespace MediaBrowser.Providers.Manager return updateType; } - private ItemUpdateType UpdateOfficialRating(TItemType item, IList<BaseItem> children) + private ItemUpdateType UpdateOfficialRating(TItemType item, IReadOnlyList<BaseItem> children) { var updateType = ItemUpdateType.None; @@ -1142,20 +1144,26 @@ namespace MediaBrowser.Providers.Manager } } - private static void MergePeople(List<PersonInfo> source, List<PersonInfo> target) + private static void MergePeople(IReadOnlyList<PersonInfo> source, IReadOnlyList<PersonInfo> target) { - if (target is null) - { - target = new List<PersonInfo>(); - } + var sourceByName = source.ToLookup(p => p.Name.RemoveDiacritics(), StringComparer.OrdinalIgnoreCase); + var targetByName = target.ToLookup(p => p.Name.RemoveDiacritics(), StringComparer.OrdinalIgnoreCase); - foreach (var person in target) + foreach (var name in targetByName.Select(g => g.Key)) { - var normalizedName = person.Name.RemoveDiacritics(); - var personInSource = source.FirstOrDefault(i => string.Equals(i.Name.RemoveDiacritics(), normalizedName, StringComparison.OrdinalIgnoreCase)); + var targetPeople = targetByName[name].ToArray(); + var sourcePeople = sourceByName[name].ToArray(); + + if (sourcePeople.Length == 0) + { + continue; + } - if (personInSource is not null) + for (int i = 0; i < targetPeople.Length; i++) { + var person = targetPeople[i]; + var personInSource = i < sourcePeople.Length ? sourcePeople[i] : sourcePeople[0]; + foreach (var providerId in personInSource.ProviderIds) { person.ProviderIds.TryAdd(providerId.Key, providerId.Value); @@ -1165,6 +1173,16 @@ namespace MediaBrowser.Providers.Manager { person.ImageUrl = personInSource.ImageUrl; } + + if (!string.IsNullOrWhiteSpace(personInSource.Role) && string.IsNullOrWhiteSpace(person.Role)) + { + person.Role = personInSource.Role; + } + + if (personInSource.SortOrder.HasValue && !person.SortOrder.HasValue) + { + person.SortOrder = personInSource.SortOrder; + } } } } diff --git a/MediaBrowser.Providers/Manager/ProviderManager.cs b/MediaBrowser.Providers/Manager/ProviderManager.cs index 010e9c3b6..856f33b49 100644 --- a/MediaBrowser.Providers/Manager/ProviderManager.cs +++ b/MediaBrowser.Providers/Manager/ProviderManager.cs @@ -48,7 +48,7 @@ namespace MediaBrowser.Providers.Manager /// </summary> public class ProviderManager : IProviderManager, IDisposable { - private readonly object _refreshQueueLock = new(); + private readonly Lock _refreshQueueLock = new(); private readonly ILogger<ProviderManager> _logger; private readonly IHttpClientFactory _httpClientFactory; private readonly ILibraryMonitor _libraryMonitor; @@ -205,27 +205,10 @@ namespace MediaBrowser.Providers.Manager { contentType = MediaTypeNames.Image.Png; } - else - { - // Deduce content type from file extension - contentType = MimeTypes.GetMimeType(new Uri(url).GetLeftPart(UriPartial.Path)); - } - - // Throw if we still can't determine the content type - if (string.IsNullOrEmpty(contentType)) - { - throw new HttpRequestException("Invalid image received: contentType not set.", null, response.StatusCode); - } - } - - // TVDb will sometimes serve a rubbish 404 html page with a 200 OK code, because reasons... - if (contentType.Equals(MediaTypeNames.Text.Html, StringComparison.OrdinalIgnoreCase)) - { - throw new HttpRequestException("Invalid image received.", null, HttpStatusCode.NotFound); } - // some iptv/epg providers don't correctly report media type, extract from url if no extension found - if (string.IsNullOrWhiteSpace(MimeTypes.ToExtension(contentType))) + // some providers don't correctly report media type, extract from url if no extension found + if (contentType is null || contentType.Equals(MediaTypeNames.Application.Octet, StringComparison.OrdinalIgnoreCase)) { // Strip query parameters from url to get actual path. contentType = MimeTypes.GetMimeType(new Uri(url).GetLeftPart(UriPartial.Path)); @@ -233,7 +216,7 @@ namespace MediaBrowser.Providers.Manager if (!contentType.StartsWith("image/", StringComparison.OrdinalIgnoreCase)) { - throw new HttpRequestException($"Request returned {contentType} instead of an image type", null, HttpStatusCode.NotFound); + throw new HttpRequestException($"Request returned '{contentType}' instead of an image type", null, HttpStatusCode.NotFound); } var responseBytes = await response.Content.ReadAsByteArrayAsync(cancellationToken).ConfigureAwait(false); @@ -270,7 +253,9 @@ namespace MediaBrowser.Providers.Manager try { var fileStream = AsyncFile.OpenRead(source); - await new ImageSaver(_configurationManager, _libraryMonitor, _fileSystem, _logger).SaveImage(item, fileStream, mimeType, type, imageIndex, saveLocallyWithMedia, cancellationToken).ConfigureAwait(false); + await new ImageSaver(_configurationManager, _libraryMonitor, _fileSystem, _logger) + .SaveImage(item, fileStream, mimeType, type, imageIndex, saveLocallyWithMedia, cancellationToken) + .ConfigureAwait(false); } finally { @@ -914,35 +899,10 @@ namespace MediaBrowser.Providers.Manager /// <inheritdoc/> public IEnumerable<ExternalUrl> GetExternalUrls(BaseItem item) { -#pragma warning disable CS0618 // Type or member is obsolete - Remove 10.11 - var legacyExternalIdUrls = GetExternalIds(item) - .Select(i => - { - var urlFormatString = i.UrlFormatString; - if (string.IsNullOrEmpty(urlFormatString) - || !item.TryGetProviderId(i.Key, out var providerId)) - { - return null; - } - - return new ExternalUrl - { - Name = i.ProviderName, - Url = string.Format( - CultureInfo.InvariantCulture, - urlFormatString, - providerId) - }; - }) - .OfType<ExternalUrl>(); -#pragma warning restore CS0618 // Type or member is obsolete - - var externalUrls = _externalUrlProviders + return _externalUrlProviders .SelectMany(p => p .GetExternalUrls(item) .Select(externalUrl => new ExternalUrl { Name = p.Name, Url = externalUrl })); - - return legacyExternalIdUrls.Concat(externalUrls).OrderBy(u => u.Name); } /// <inheritdoc/> @@ -952,10 +912,7 @@ namespace MediaBrowser.Providers.Manager .Select(i => new ExternalIdInfo( name: i.ProviderName, key: i.Key, - type: i.Type, -#pragma warning disable CS0618 // Type or member is obsolete - Remove 10.11 - urlFormatString: i.UrlFormatString)); -#pragma warning restore CS0618 // Type or member is obsolete + type: i.Type)); } /// <inheritdoc/> |
