From 06f8047ee6a68fb5429b3d938b2916f1a17a63b5 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Thu, 21 Jan 2016 12:29:14 -0500 Subject: support system wake on recording schedule --- MediaBrowser.Controller/MediaBrowser.Controller.csproj | 1 + MediaBrowser.Controller/Power/IPowerManagement.cs | 13 +++++++++++++ 2 files changed, 14 insertions(+) create mode 100644 MediaBrowser.Controller/Power/IPowerManagement.cs (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index 2227df3f03..471aa38d4b 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -265,6 +265,7 @@ + diff --git a/MediaBrowser.Controller/Power/IPowerManagement.cs b/MediaBrowser.Controller/Power/IPowerManagement.cs new file mode 100644 index 0000000000..faa2896952 --- /dev/null +++ b/MediaBrowser.Controller/Power/IPowerManagement.cs @@ -0,0 +1,13 @@ +using System; + +namespace MediaBrowser.Controller.Power +{ + public interface IPowerManagement + { + /// + /// Schedules the wake. + /// + /// The UTC time. + void ScheduleWake(DateTime utcTime); + } +} -- cgit v1.2.3 From 5cd032d86b2b5cf34c2dda8b7650df4725a71ae7 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Thu, 21 Jan 2016 13:50:43 -0500 Subject: get people info during media refresh --- MediaBrowser.Controller/Entities/PeopleHelper.cs | 17 ++++++-- MediaBrowser.Controller/Entities/Person.cs | 12 +++++- MediaBrowser.Providers/Manager/MetadataService.cs | 43 ++++++++++++++++++++ .../Movies/GenericMovieDbInfo.cs | 47 ++++++++++++++++++++-- MediaBrowser.Providers/TV/TvdbSeriesProvider.cs | 15 +++++++ 5 files changed, 126 insertions(+), 8 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/Entities/PeopleHelper.cs b/MediaBrowser.Controller/Entities/PeopleHelper.cs index 3468ca2d58..40a93d9e6f 100644 --- a/MediaBrowser.Controller/Entities/PeopleHelper.cs +++ b/MediaBrowser.Controller/Entities/PeopleHelper.cs @@ -45,7 +45,7 @@ namespace MediaBrowser.Controller.Entities if (existing != null) { existing.Type = PersonType.GuestStar; - existing.SortOrder = person.SortOrder ?? existing.SortOrder; + MergeExisting(existing, person); return; } } @@ -67,7 +67,7 @@ namespace MediaBrowser.Controller.Entities existing.Role = person.Role; } - existing.SortOrder = person.SortOrder ?? existing.SortOrder; + MergeExisting(existing, person); } } else @@ -83,11 +83,22 @@ namespace MediaBrowser.Controller.Entities } else { - existing.SortOrder = person.SortOrder ?? existing.SortOrder; + MergeExisting(existing, person); } } } + private static void MergeExisting(PersonInfo existing, PersonInfo person) + { + existing.SortOrder = person.SortOrder ?? existing.SortOrder; + existing.ImageUrl = person.ImageUrl ?? existing.ImageUrl; + + foreach (var id in person.ProviderIds) + { + existing.SetProviderId(id.Key, id.Value); + } + } + public static bool ContainsPerson(List people, string name) { if (string.IsNullOrWhiteSpace(name)) diff --git a/MediaBrowser.Controller/Entities/Person.cs b/MediaBrowser.Controller/Entities/Person.cs index 6c277da565..a365b99c67 100644 --- a/MediaBrowser.Controller/Entities/Person.cs +++ b/MediaBrowser.Controller/Entities/Person.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; using System.Linq; using System.Runtime.Serialization; +using MediaBrowser.Model.Entities; namespace MediaBrowser.Controller.Entities { @@ -106,8 +107,13 @@ namespace MediaBrowser.Controller.Entities /// /// This is the small Person stub that is attached to BaseItems /// - public class PersonInfo + public class PersonInfo : IHasProviderIds { + public PersonInfo() + { + ProviderIds = new Dictionary(StringComparer.OrdinalIgnoreCase); + } + public Guid ItemId { get; set; } /// @@ -132,6 +138,10 @@ namespace MediaBrowser.Controller.Entities /// The sort order. public int? SortOrder { get; set; } + public string ImageUrl { get; set; } + + public Dictionary ProviderIds { get; set; } + /// /// Returns a that represents this instance. /// diff --git a/MediaBrowser.Providers/Manager/MetadataService.cs b/MediaBrowser.Providers/Manager/MetadataService.cs index 083c8f1f3d..d9f5c30fd5 100644 --- a/MediaBrowser.Providers/Manager/MetadataService.cs +++ b/MediaBrowser.Providers/Manager/MetadataService.cs @@ -254,10 +254,53 @@ namespace MediaBrowser.Providers.Manager if (result.Item.SupportsPeople && result.People != null) { await LibraryManager.UpdatePeople(result.Item as BaseItem, result.People.ToList()); + await SavePeopleMetadata(result.People, cancellationToken).ConfigureAwait(false); } await result.Item.UpdateToRepository(reason, cancellationToken).ConfigureAwait(false); } + private async Task SavePeopleMetadata(List people, CancellationToken cancellationToken) + { + foreach (var person in people) + { + cancellationToken.ThrowIfCancellationRequested(); + + if (person.ProviderIds.Any() || !string.IsNullOrWhiteSpace(person.ImageUrl)) + { + var updateType = ItemUpdateType.MetadataDownload; + + var saveEntity = false; + var personEntity = LibraryManager.GetPerson(person.Name); + foreach (var id in person.ProviderIds) + { + if (!string.Equals(personEntity.GetProviderId(id.Key), id.Value, StringComparison.OrdinalIgnoreCase)) + { + personEntity.SetProviderId(id.Key, id.Value); + saveEntity = true; + } + } + + if (!string.IsNullOrWhiteSpace(person.ImageUrl) && !personEntity.HasImage(ImageType.Primary)) + { + personEntity.SetImage(new ItemImageInfo + { + Path = person.ImageUrl, + Type = ImageType.Primary, + IsPlaceholder = true + }, 0); + + saveEntity = true; + updateType = updateType | ItemUpdateType.ImageUpdate; + } + + if (saveEntity) + { + await personEntity.UpdateToRepository(updateType, cancellationToken).ConfigureAwait(false); + } + } + } + } + private readonly Task _cachedTask = Task.FromResult(true); protected virtual Task AfterMetadataRefresh(TItemType item, MetadataRefreshOptions refreshOptions, CancellationToken cancellationToken) { diff --git a/MediaBrowser.Providers/Movies/GenericMovieDbInfo.cs b/MediaBrowser.Providers/Movies/GenericMovieDbInfo.cs index 3c2d9c82fc..abd4a62029 100644 --- a/MediaBrowser.Providers/Movies/GenericMovieDbInfo.cs +++ b/MediaBrowser.Providers/Movies/GenericMovieDbInfo.cs @@ -104,7 +104,9 @@ namespace MediaBrowser.Providers.Movies dataFilePath = dataFilePath ?? MovieDbProvider.Current.GetDataFilePath(tmdbId, language); movieInfo = movieInfo ?? _jsonSerializer.DeserializeFromFile(dataFilePath); - ProcessMainInfo(item, preferredCountryCode, movieInfo); + var settings = await MovieDbProvider.Current.GetTmdbSettings(cancellationToken).ConfigureAwait(false); + + ProcessMainInfo(item, settings, preferredCountryCode, movieInfo); item.HasMetadata = true; } @@ -115,9 +117,10 @@ namespace MediaBrowser.Providers.Movies /// Processes the main info. /// /// The result item. + /// The settings. /// The preferred country code. /// The movie data. - private void ProcessMainInfo(MetadataResult resultItem, string preferredCountryCode, MovieDbProvider.CompleteMovieData movieData) + private void ProcessMainInfo(MetadataResult resultItem, TmdbSettingsResult settings, string preferredCountryCode, MovieDbProvider.CompleteMovieData movieData) { var movie = resultItem.Item; @@ -247,6 +250,7 @@ namespace MediaBrowser.Providers.Movies } resultItem.ResetPeople(); + var tmdbImageUrl = settings.images.base_url + "original"; //Actors, Directors, Writers - all in People //actors come from cast @@ -254,7 +258,25 @@ namespace MediaBrowser.Providers.Movies { foreach (var actor in movieData.casts.cast.OrderBy(a => a.order)) { - resultItem.AddPerson(new PersonInfo { Name = actor.name.Trim(), Role = actor.character, Type = PersonType.Actor, SortOrder = actor.order }); + var personInfo = new PersonInfo + { + Name = actor.name.Trim(), + Role = actor.character, + Type = PersonType.Actor, + SortOrder = actor.order + }; + + if (!string.IsNullOrWhiteSpace(actor.profile_path)) + { + personInfo.ImageUrl = tmdbImageUrl + actor.profile_path; + } + + if (actor.id > 0) + { + personInfo.SetProviderId(MetadataProviders.Tmdb, actor.id.ToString(CultureInfo.InvariantCulture)); + } + + resultItem.AddPerson(personInfo); } } @@ -270,7 +292,24 @@ namespace MediaBrowser.Providers.Movies type = PersonType.Writer; } - resultItem.AddPerson(new PersonInfo { Name = person.name.Trim(), Role = person.job, Type = type }); + var personInfo = new PersonInfo + { + Name = person.name.Trim(), + Role = person.job, + Type = type + }; + + if (!string.IsNullOrWhiteSpace(person.profile_path)) + { + personInfo.ImageUrl = tmdbImageUrl + person.profile_path; + } + + if (person.id > 0) + { + personInfo.SetProviderId(MetadataProviders.Tmdb, person.id.ToString(CultureInfo.InvariantCulture)); + } + + resultItem.AddPerson(personInfo); } } diff --git a/MediaBrowser.Providers/TV/TvdbSeriesProvider.cs b/MediaBrowser.Providers/TV/TvdbSeriesProvider.cs index 9452438cb1..00bc032ca7 100644 --- a/MediaBrowser.Providers/TV/TvdbSeriesProvider.cs +++ b/MediaBrowser.Providers/TV/TvdbSeriesProvider.cs @@ -826,6 +826,21 @@ namespace MediaBrowser.Providers.TV break; } + case "id": + { + break; + } + + case "Image": + { + var url = (reader.ReadElementContentAsString() ?? string.Empty).Trim(); + if (!string.IsNullOrWhiteSpace(url)) + { + personInfo.ImageUrl = TVUtils.BannerUrl + url; + } + break; + } + case "SortOrder": { var val = reader.ReadElementContentAsString(); -- cgit v1.2.3 From 3f0927fb60560b0fb4aed7ef7215a688f2f548da Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Fri, 22 Jan 2016 21:32:14 -0500 Subject: throttle people requests --- MediaBrowser.Api/ItemRefreshService.cs | 3 +- .../Providers/ImageRefreshOptions.cs | 2 ++ .../Providers/ItemLookupInfo.cs | 4 ++- MediaBrowser.Providers/Manager/MetadataService.cs | 1 + .../People/MovieDbPersonProvider.cs | 38 +++++++++++++++++++++- 5 files changed, 45 insertions(+), 3 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Api/ItemRefreshService.cs b/MediaBrowser.Api/ItemRefreshService.cs index af1f1c90ad..1e912c92d6 100644 --- a/MediaBrowser.Api/ItemRefreshService.cs +++ b/MediaBrowser.Api/ItemRefreshService.cs @@ -76,7 +76,8 @@ namespace MediaBrowser.Api ImageRefreshMode = request.ImageRefreshMode, ReplaceAllImages = request.ReplaceAllImages, ReplaceAllMetadata = request.ReplaceAllMetadata, - ForceSave = true + ForceSave = true, + IsAutomated = false }; } } diff --git a/MediaBrowser.Controller/Providers/ImageRefreshOptions.cs b/MediaBrowser.Controller/Providers/ImageRefreshOptions.cs index a66cc6f222..9b21a29724 100644 --- a/MediaBrowser.Controller/Providers/ImageRefreshOptions.cs +++ b/MediaBrowser.Controller/Providers/ImageRefreshOptions.cs @@ -11,6 +11,7 @@ namespace MediaBrowser.Controller.Providers public bool ReplaceAllImages { get; set; } public List ReplaceImages { get; set; } + public bool IsAutomated { get; set; } public ImageRefreshOptions(IDirectoryService directoryService) { @@ -18,6 +19,7 @@ namespace MediaBrowser.Controller.Providers DirectoryService = directoryService; ReplaceImages = new List(); + IsAutomated = true; } public bool IsReplacingImage(ImageType type) diff --git a/MediaBrowser.Controller/Providers/ItemLookupInfo.cs b/MediaBrowser.Controller/Providers/ItemLookupInfo.cs index 7114cde3e2..dc7a04135a 100644 --- a/MediaBrowser.Controller/Providers/ItemLookupInfo.cs +++ b/MediaBrowser.Controller/Providers/ItemLookupInfo.cs @@ -33,10 +33,12 @@ namespace MediaBrowser.Controller.Providers public int? Year { get; set; } public int? IndexNumber { get; set; } public int? ParentIndexNumber { get; set; } - public DateTime? PremiereDate { get; set; } + public DateTime? PremiereDate { get; set; } + public bool IsAutomated { get; set; } public ItemLookupInfo() { + IsAutomated = true; ProviderIds = new Dictionary(StringComparer.OrdinalIgnoreCase); } } diff --git a/MediaBrowser.Providers/Manager/MetadataService.cs b/MediaBrowser.Providers/Manager/MetadataService.cs index d9f5c30fd5..e18da565df 100644 --- a/MediaBrowser.Providers/Manager/MetadataService.cs +++ b/MediaBrowser.Providers/Manager/MetadataService.cs @@ -138,6 +138,7 @@ namespace MediaBrowser.Providers.Manager var id = itemOfType.GetLookupInfo(); //await FindIdentities(id, cancellationToken).ConfigureAwait(false); + id.IsAutomated = refreshOptions.IsAutomated; var result = await RefreshWithProviders(metadataResult, id, refreshOptions, providers, itemImageProvider, cancellationToken).ConfigureAwait(false); diff --git a/MediaBrowser.Providers/People/MovieDbPersonProvider.cs b/MediaBrowser.Providers/People/MovieDbPersonProvider.cs index 4e652a4285..0dab24b11a 100644 --- a/MediaBrowser.Providers/People/MovieDbPersonProvider.cs +++ b/MediaBrowser.Providers/People/MovieDbPersonProvider.cs @@ -10,6 +10,7 @@ using MediaBrowser.Model.Providers; using MediaBrowser.Model.Serialization; using MediaBrowser.Providers.Movies; using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Globalization; using System.IO; @@ -18,6 +19,7 @@ using System.Net; using System.Threading; using System.Threading.Tasks; using CommonIO; +using MediaBrowser.Model.Logging; using MediaBrowser.Model.Net; namespace MediaBrowser.Providers.People @@ -32,14 +34,30 @@ namespace MediaBrowser.Providers.People private readonly IFileSystem _fileSystem; private readonly IServerConfigurationManager _configurationManager; private readonly IHttpClient _httpClient; + private readonly ILogger _logger; - public MovieDbPersonProvider(IFileSystem fileSystem, IServerConfigurationManager configurationManager, IJsonSerializer jsonSerializer, IHttpClient httpClient) + private int _requestCount; + private readonly object _requestCountLock = new object(); + private Timer _requestCountReset; + + public MovieDbPersonProvider(IFileSystem fileSystem, IServerConfigurationManager configurationManager, IJsonSerializer jsonSerializer, IHttpClient httpClient, ILogger logger) { _fileSystem = fileSystem; _configurationManager = configurationManager; _jsonSerializer = jsonSerializer; _httpClient = httpClient; + _logger = logger; Current = this; + + _requestCountReset = new Timer(OnRequestThrottleTimerFired, null, TimeSpan.FromHours(1), TimeSpan.FromHours(1)); + } + + private void OnRequestThrottleTimerFired(object state) + { + lock (_requestCountLock) + { + _requestCount = 0; + } } public string Name @@ -79,6 +97,24 @@ namespace MediaBrowser.Providers.People return new[] { result }; } + if (searchInfo.IsAutomated) + { + lock (_requestCountLock) + { + var requestCount = _requestCount; + + if (requestCount >= 5) + { + _logger.Debug("Throttling Tmdb people"); + + // This needs to be throttled + return new List(); + } + + _requestCount = requestCount + 1; + } + } + var url = string.Format(@"http://api.themoviedb.org/3/search/person?api_key={1}&query={0}", WebUtility.UrlEncode(searchInfo.Name), MovieDbProvider.ApiKey); using (var json = await MovieDbProvider.Current.GetMovieDbResponse(new HttpRequestOptions -- cgit v1.2.3 From 0297d8f7d3bbb774749d627508849fc00d9a4c71 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sun, 31 Jan 2016 19:57:40 -0500 Subject: update locking --- .../ScheduledTasks/ScheduledTaskWorker.cs | 8 ++++---- MediaBrowser.Controller/Entities/User.cs | 4 ++-- MediaBrowser.Server.Implementations/Library/LibraryManager.cs | 4 ++-- MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs | 6 +++++- .../LiveTv/EmbyTV/ItemDataProvider.cs | 2 +- 5 files changed, 14 insertions(+), 10 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Common.Implementations/ScheduledTasks/ScheduledTaskWorker.cs b/MediaBrowser.Common.Implementations/ScheduledTasks/ScheduledTaskWorker.cs index 95f29915db..a4ccbb6f84 100644 --- a/MediaBrowser.Common.Implementations/ScheduledTasks/ScheduledTaskWorker.cs +++ b/MediaBrowser.Common.Implementations/ScheduledTasks/ScheduledTaskWorker.cs @@ -233,7 +233,7 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks /// /// The _triggers /// - private IEnumerable _triggers; + private volatile List _triggers; /// /// The _triggers sync lock /// @@ -532,7 +532,7 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks /// Loads the triggers. /// /// IEnumerable{BaseTaskTrigger}. - private IEnumerable LoadTriggers() + private List LoadTriggers() { try { @@ -543,12 +543,12 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks catch (FileNotFoundException) { // File doesn't exist. No biggie. Return defaults. - return ScheduledTask.GetDefaultTriggers(); + return ScheduledTask.GetDefaultTriggers().ToList(); } catch (DirectoryNotFoundException) { // File doesn't exist. No biggie. Return defaults. - return ScheduledTask.GetDefaultTriggers(); + return ScheduledTask.GetDefaultTriggers().ToList(); } } diff --git a/MediaBrowser.Controller/Entities/User.cs b/MediaBrowser.Controller/Entities/User.cs index a9e314ede1..be8521a5c4 100644 --- a/MediaBrowser.Controller/Entities/User.cs +++ b/MediaBrowser.Controller/Entities/User.cs @@ -109,7 +109,7 @@ namespace MediaBrowser.Controller.Entities /// The last activity date. public DateTime? LastActivityDate { get; set; } - private UserConfiguration _config; + private volatile UserConfiguration _config; private readonly object _configSyncLock = new object(); [IgnoreDataMember] public UserConfiguration Configuration @@ -132,7 +132,7 @@ namespace MediaBrowser.Controller.Entities set { _config = value; } } - private UserPolicy _policy; + private volatile UserPolicy _policy; private readonly object _policySyncLock = new object(); [IgnoreDataMember] public UserPolicy Policy diff --git a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs index 0cb5174c9a..b0b2680cac 100644 --- a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs +++ b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs @@ -222,7 +222,7 @@ namespace MediaBrowser.Server.Implementations.Library /// /// The _root folder /// - private AggregateFolder _rootFolder; + private volatile AggregateFolder _rootFolder; /// /// The _root folder sync lock /// @@ -743,7 +743,7 @@ namespace MediaBrowser.Server.Implementations.Library return rootFolder; } - private UserRootFolder _userRootFolder; + private volatile UserRootFolder _userRootFolder; private readonly object _syncLock = new object(); public Folder GetUserRootFolder() { diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index ea64950abe..cd91684ce1 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -239,7 +239,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV public Task CancelSeriesTimerAsync(string timerId, CancellationToken cancellationToken) { - var timers = _timerProvider.GetAll().Where(i => string.Equals(i.SeriesTimerId, timerId, StringComparison.OrdinalIgnoreCase)); + var timers = _timerProvider + .GetAll() + .Where(i => string.Equals(i.SeriesTimerId, timerId, StringComparison.OrdinalIgnoreCase)) + .ToList(); + foreach (var timer in timers) { CancelTimerInternal(timer.Id); diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs index f46daa6d50..b29a7562cf 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs @@ -13,7 +13,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV where T : class { private readonly object _fileDataLock = new object(); - private List _items; + private volatile List _items; private readonly IJsonSerializer _jsonSerializer; protected readonly ILogger Logger; private readonly string _dataPath; -- cgit v1.2.3 From 865e2babfa70809a165ddc7070ffd80b5ee3d87e Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Mon, 1 Feb 2016 12:22:02 -0500 Subject: album refresh fixes --- .../Entities/Audio/MusicAlbum.cs | 61 +++++++++++++++++++++- 1 file changed, 59 insertions(+), 2 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs index 98d1eb4ce2..654c9abd3f 100644 --- a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs +++ b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs @@ -1,17 +1,21 @@ -using MediaBrowser.Controller.Providers; +using System; +using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Users; using System.Collections.Generic; using System.Linq; using System.Runtime.Serialization; +using System.Threading; +using System.Threading.Tasks; +using MediaBrowser.Controller.Library; namespace MediaBrowser.Controller.Entities.Audio { /// /// Class MusicAlbum /// - public class MusicAlbum : Folder, IHasAlbumArtist, IHasArtist, IHasMusicGenres, IHasLookupInfo + public class MusicAlbum : Folder, IHasAlbumArtist, IHasArtist, IHasMusicGenres, IHasLookupInfo, IMetadataContainer { public MusicAlbum() { @@ -139,5 +143,58 @@ namespace MediaBrowser.Controller.Entities.Audio return id; } + + public async Task RefreshAllMetadata(MetadataRefreshOptions refreshOptions, IProgress progress, CancellationToken cancellationToken) + { + var items = GetRecursiveChildren().ToList(); + + var songs = items.OfType