ItemRefreshService.cs 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. using MediaBrowser.Controller.Entities;
  2. using MediaBrowser.Controller.Entities.Audio;
  3. using MediaBrowser.Controller.Library;
  4. using MediaBrowser.Controller.Net;
  5. using MediaBrowser.Controller.Providers;
  6. using ServiceStack;
  7. using System;
  8. using System.Linq;
  9. using System.Threading;
  10. using System.Threading.Tasks;
  11. namespace MediaBrowser.Api
  12. {
  13. public class BaseRefreshRequest : IReturnVoid
  14. {
  15. [ApiMember(Name = "Forced", Description = "Indicates if a normal or forced refresh should occur.", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "POST")]
  16. public bool Forced { get; set; }
  17. [ApiMember(Name = "ReplaceAllImages", Description = "Determines if images should be replaced during the refresh.", IsRequired = true, DataType = "boolean", ParameterType = "query", Verb = "POST")]
  18. public bool ReplaceAllImages { get; set; }
  19. }
  20. [Route("/Items/{Id}/Refresh", "POST")]
  21. [Api(Description = "Refreshes metadata for an item")]
  22. public class RefreshItem : BaseRefreshRequest
  23. {
  24. [ApiMember(Name = "Recursive", Description = "Indicates if the refresh should occur recursively.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "POST")]
  25. public bool Recursive { get; set; }
  26. [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
  27. public string Id { get; set; }
  28. }
  29. [Authenticated]
  30. public class ItemRefreshService : BaseApiService
  31. {
  32. private readonly ILibraryManager _libraryManager;
  33. public ItemRefreshService(ILibraryManager libraryManager)
  34. {
  35. _libraryManager = libraryManager;
  36. }
  37. private async Task RefreshArtist(RefreshItem request, MusicArtist item)
  38. {
  39. var cancellationToken = CancellationToken.None;
  40. var albums = _libraryManager.RootFolder
  41. .RecursiveChildren
  42. .OfType<MusicAlbum>()
  43. .Where(i => i.HasArtist(item.Name))
  44. .ToList();
  45. var musicArtists = albums
  46. .Select(i => i.Parent)
  47. .OfType<MusicArtist>()
  48. .ToList();
  49. var options = GetRefreshOptions(request);
  50. var musicArtistRefreshTasks = musicArtists.Select(i => i.ValidateChildren(new Progress<double>(), cancellationToken, options, true));
  51. await Task.WhenAll(musicArtistRefreshTasks).ConfigureAwait(false);
  52. try
  53. {
  54. await item.RefreshMetadata(options, CancellationToken.None).ConfigureAwait(false);
  55. }
  56. catch (Exception ex)
  57. {
  58. Logger.ErrorException("Error refreshing library", ex);
  59. }
  60. }
  61. /// <summary>
  62. /// Posts the specified request.
  63. /// </summary>
  64. /// <param name="request">The request.</param>
  65. public void Post(RefreshItem request)
  66. {
  67. var item = _libraryManager.GetItemById(request.Id);
  68. var task = item is MusicArtist ? RefreshArtist(request, (MusicArtist)item) : RefreshItem(request, item);
  69. Task.WaitAll(task);
  70. }
  71. /// <summary>
  72. /// Refreshes the item.
  73. /// </summary>
  74. /// <param name="request">The request.</param>
  75. /// <returns>Task.</returns>
  76. private async Task RefreshItem(RefreshItem request, BaseItem item)
  77. {
  78. var options = GetRefreshOptions(request);
  79. try
  80. {
  81. await item.RefreshMetadata(options, CancellationToken.None).ConfigureAwait(false);
  82. if (item.IsFolder)
  83. {
  84. // Collection folders don't validate their children so we'll have to simulate that here
  85. var collectionFolder = item as CollectionFolder;
  86. if (collectionFolder != null)
  87. {
  88. await RefreshCollectionFolderChildren(request, collectionFolder).ConfigureAwait(false);
  89. }
  90. else
  91. {
  92. var folder = (Folder)item;
  93. await folder.ValidateChildren(new Progress<double>(), CancellationToken.None, options, request.Recursive).ConfigureAwait(false);
  94. }
  95. }
  96. }
  97. catch (Exception ex)
  98. {
  99. Logger.ErrorException("Error refreshing library", ex);
  100. }
  101. }
  102. /// <summary>
  103. /// Refreshes the collection folder children.
  104. /// </summary>
  105. /// <param name="request">The request.</param>
  106. /// <param name="collectionFolder">The collection folder.</param>
  107. /// <returns>Task.</returns>
  108. private async Task RefreshCollectionFolderChildren(RefreshItem request, CollectionFolder collectionFolder)
  109. {
  110. var options = GetRefreshOptions(request);
  111. foreach (var child in collectionFolder.Children.ToList())
  112. {
  113. await child.RefreshMetadata(options, CancellationToken.None).ConfigureAwait(false);
  114. if (child.IsFolder)
  115. {
  116. var folder = (Folder)child;
  117. await folder.ValidateChildren(new Progress<double>(), CancellationToken.None, options, request.Recursive).ConfigureAwait(false);
  118. }
  119. }
  120. }
  121. private MetadataRefreshOptions GetRefreshOptions(BaseRefreshRequest request)
  122. {
  123. return new MetadataRefreshOptions
  124. {
  125. MetadataRefreshMode = MetadataRefreshMode.FullRefresh,
  126. ImageRefreshMode = ImageRefreshMode.FullRefresh,
  127. ReplaceAllMetadata = request.Forced,
  128. ReplaceAllImages = request.ReplaceAllImages
  129. };
  130. }
  131. }
  132. }