aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.Providers/Manager
diff options
context:
space:
mode:
Diffstat (limited to 'MediaBrowser.Providers/Manager')
-rw-r--r--MediaBrowser.Providers/Manager/ImageSaver.cs1
-rw-r--r--MediaBrowser.Providers/Manager/ItemImageProvider.cs17
-rw-r--r--MediaBrowser.Providers/Manager/MetadataService.cs118
-rw-r--r--MediaBrowser.Providers/Manager/ProviderManager.cs61
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/>