diff options
| author | Luke Pulverenti <luke.pulverenti@gmail.com> | 2013-08-12 15:18:31 -0400 |
|---|---|---|
| committer | Luke Pulverenti <luke.pulverenti@gmail.com> | 2013-08-12 15:18:31 -0400 |
| commit | d3acd04e66e6f45084f7d6f6a3fb6e26688e5b5b (patch) | |
| tree | bdef625491a24d6cc1c2eddad5d291cdb2c2b678 | |
| parent | d2ec5126f44e4701fd8d9c0462972f53843ada78 (diff) | |
store chapters in xml
10 files changed, 278 insertions, 144 deletions
diff --git a/MediaBrowser.Controller/Providers/BaseItemXmlParser.cs b/MediaBrowser.Controller/Providers/BaseItemXmlParser.cs index 357b38ecf..89bc9f2c2 100644 --- a/MediaBrowser.Controller/Providers/BaseItemXmlParser.cs +++ b/MediaBrowser.Controller/Providers/BaseItemXmlParser.cs @@ -1,5 +1,6 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; +using MediaBrowser.Controller.Persistence; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; using System; @@ -9,6 +10,7 @@ using System.IO; using System.Linq; using System.Text; using System.Threading; +using System.Threading.Tasks; using System.Xml; namespace MediaBrowser.Controller.Providers @@ -266,7 +268,10 @@ namespace MediaBrowser.Controller.Providers case "TagLines": { - FetchFromTaglinesNode(reader.ReadSubtree(), item); + using (var subtree = reader.ReadSubtree()) + { + FetchFromTaglinesNode(subtree, item); + } break; } @@ -591,28 +596,58 @@ namespace MediaBrowser.Controller.Providers break; case "Genres": - FetchFromGenresNode(reader.ReadSubtree(), item); - break; + { + using (var subtree = reader.ReadSubtree()) + { + FetchFromGenresNode(subtree, item); + } + break; + } case "Tags": - FetchFromTagsNode(reader.ReadSubtree(), item); - break; + { + using (var subtree = reader.ReadSubtree()) + { + FetchFromTagsNode(subtree, item); + } + break; + } case "Persons": - FetchDataFromPersonsNode(reader.ReadSubtree(), item); - break; + { + using (var subtree = reader.ReadSubtree()) + { + FetchDataFromPersonsNode(subtree, item); + } + break; + } case "ParentalRating": - FetchFromParentalRatingNode(reader.ReadSubtree(), item); - break; + { + using (var subtree = reader.ReadSubtree()) + { + FetchFromParentalRatingNode(subtree, item); + } + break; + } case "Studios": - FetchFromStudiosNode(reader.ReadSubtree(), item); - break; + { + using (var subtree = reader.ReadSubtree()) + { + FetchFromStudiosNode(subtree, item); + } + break; + } case "MediaInfo": - FetchFromMediaInfoNode(reader.ReadSubtree(), item); - break; + { + using (var subtree = reader.ReadSubtree()) + { + FetchFromMediaInfoNode(subtree, item); + } + break; + } default: reader.Skip(); @@ -636,8 +671,13 @@ namespace MediaBrowser.Controller.Providers switch (reader.Name) { case "Video": - FetchFromMediaInfoVideoNode(reader.ReadSubtree(), item); - break; + { + using (var subtree = reader.ReadSubtree()) + { + FetchFromMediaInfoVideoNode(subtree, item); + } + break; + } default: reader.Skip(); @@ -813,9 +853,12 @@ namespace MediaBrowser.Controller.Providers case "Person": case "Actor": { - foreach (var person in GetPersonsFromXmlNode(reader.ReadSubtree())) + using (var subtree = reader.ReadSubtree()) { - item.AddPerson(person); + foreach (var person in GetPersonsFromXmlNode(subtree)) + { + item.AddPerson(person); + } } break; } @@ -828,6 +871,86 @@ namespace MediaBrowser.Controller.Providers } } + protected async Task FetchChaptersFromXmlNode(Guid itemId, XmlReader reader, IItemRepository repository, CancellationToken cancellationToken) + { + using (reader) + { + var chapters = GetChaptersFromXmlNode(reader); + + await repository.SaveChapters(itemId, chapters, cancellationToken).ConfigureAwait(false); + } + } + + private IEnumerable<ChapterInfo> GetChaptersFromXmlNode(XmlReader reader) + { + var chapters = new List<ChapterInfo>(); + + reader.MoveToContent(); + + while (reader.Read()) + { + if (reader.NodeType == XmlNodeType.Element) + { + switch (reader.Name) + { + case "Chapter": + { + using (var subtree = reader.ReadSubtree()) + { + chapters.Add(GetChapterInfoFromXmlNode(subtree)); + } + break; + } + + default: + reader.Skip(); + break; + } + } + } + + return chapters; + } + + private ChapterInfo GetChapterInfoFromXmlNode(XmlReader reader) + { + var chapter = new ChapterInfo(); + + reader.MoveToContent(); + + while (reader.Read()) + { + if (reader.NodeType == XmlNodeType.Element) + { + switch (reader.Name) + { + case "StartPositionMs": + { + var val = reader.ReadElementContentAsString(); + + var ms = long.Parse(val, _usCulture); + + chapter.StartPositionTicks = TimeSpan.FromMilliseconds(ms).Ticks; + + break; + } + + case "Name": + { + chapter.Name = reader.ReadElementContentAsString(); + break; + } + + default: + reader.Skip(); + break; + } + } + } + + return chapter; + } + /// <summary> /// Fetches from studios node. /// </summary> diff --git a/MediaBrowser.Providers/MediaBrowser.Providers.csproj b/MediaBrowser.Providers/MediaBrowser.Providers.csproj index ad517cefd..806a2f113 100644 --- a/MediaBrowser.Providers/MediaBrowser.Providers.csproj +++ b/MediaBrowser.Providers/MediaBrowser.Providers.csproj @@ -58,6 +58,7 @@ <Compile Include="MediaInfo\FFProbeAudioInfoProvider.cs" /> <Compile Include="MediaInfo\FFProbeVideoInfoProvider.cs" /> <Compile Include="Movies\BoxSetProviderFromXml.cs" /> + <Compile Include="Movies\MovieXmlParser.cs" /> <Compile Include="Movies\FanArtMovieProvider.cs" /> <Compile Include="Movies\FanArtMovieUpdatesPrescanTask.cs" /> <Compile Include="Movies\MovieDbImagesProvider.cs" /> diff --git a/MediaBrowser.Providers/Movies/MovieProviderFromXml.cs b/MediaBrowser.Providers/Movies/MovieProviderFromXml.cs index 63b1bdb03..d6ab77881 100644 --- a/MediaBrowser.Providers/Movies/MovieProviderFromXml.cs +++ b/MediaBrowser.Providers/Movies/MovieProviderFromXml.cs @@ -1,9 +1,9 @@ using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Movies; +using MediaBrowser.Controller.Persistence; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Logging; -using MediaBrowser.Providers.Music; using System; using System.IO; using System.Threading; @@ -17,10 +17,12 @@ namespace MediaBrowser.Providers.Movies public class MovieProviderFromXml : BaseMetadataProvider { internal static MovieProviderFromXml Current { get; private set; } - - public MovieProviderFromXml(ILogManager logManager, IServerConfigurationManager configurationManager) + private readonly IItemRepository _itemRepo; + + public MovieProviderFromXml(ILogManager logManager, IServerConfigurationManager configurationManager, IItemRepository itemRepo) : base(logManager, configurationManager) { + _itemRepo = itemRepo; Current = this; } @@ -94,30 +96,9 @@ namespace MediaBrowser.Providers.Movies try { - var movie = item as Movie; - - if (movie != null) - { - new BaseItemXmlParser<Movie>(Logger).Fetch(movie, path, cancellationToken); - } - else - { - var musicVideo = item as MusicVideo; - - if (musicVideo != null) - { - new MusicVideoXmlParser(Logger).Fetch(musicVideo, path, cancellationToken); - } - else - { - var trailer = item as Trailer; - - if (trailer != null) - { - new BaseItemXmlParser<Trailer>(Logger).Fetch(trailer, path, cancellationToken); - } - } - } + var video = (Video) item; + + await new MovieXmlParser(Logger, _itemRepo).FetchAsync(video, path, cancellationToken).ConfigureAwait(false); } finally { diff --git a/MediaBrowser.Providers/Movies/MovieXmlParser.cs b/MediaBrowser.Providers/Movies/MovieXmlParser.cs new file mode 100644 index 000000000..e397e1d20 --- /dev/null +++ b/MediaBrowser.Providers/Movies/MovieXmlParser.cs @@ -0,0 +1,60 @@ +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Persistence; +using MediaBrowser.Controller.Providers; +using MediaBrowser.Model.Logging; +using System.Threading; +using System.Threading.Tasks; +using System.Xml; + +namespace MediaBrowser.Providers.Movies +{ + /// <summary> + /// Class EpisodeXmlParser + /// </summary> + public class MovieXmlParser : BaseItemXmlParser<Video> + { + private readonly IItemRepository _itemRepo; + + private Task _chaptersTask = null; + + public MovieXmlParser(ILogger logger, IItemRepository itemRepo) + : base(logger) + { + _itemRepo = itemRepo; + } + + public async Task FetchAsync(Video item, string metadataFile, CancellationToken cancellationToken) + { + _chaptersTask = null; + + Fetch(item, metadataFile, cancellationToken); + + cancellationToken.ThrowIfCancellationRequested(); + + if (_chaptersTask != null) + { + await _chaptersTask.ConfigureAwait(false); + } + } + + /// <summary> + /// Fetches the data from XML node. + /// </summary> + /// <param name="reader">The reader.</param> + /// <param name="item">The item.</param> + protected override void FetchDataFromXmlNode(XmlReader reader, Video item) + { + switch (reader.Name) + { + case "Chapters": + + _chaptersTask = FetchChaptersFromXmlNode(item.Id, reader.ReadSubtree(), _itemRepo, CancellationToken.None); + break; + + default: + base.FetchDataFromXmlNode(reader, item); + break; + } + } + } +} diff --git a/MediaBrowser.Providers/Savers/EpisodeXmlSaver.cs b/MediaBrowser.Providers/Savers/EpisodeXmlSaver.cs index 969732e39..b36f7966b 100644 --- a/MediaBrowser.Providers/Savers/EpisodeXmlSaver.cs +++ b/MediaBrowser.Providers/Savers/EpisodeXmlSaver.cs @@ -2,6 +2,7 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Persistence; using MediaBrowser.Providers.TV; using System; using System.Globalization; @@ -15,6 +16,7 @@ namespace MediaBrowser.Providers.Savers public class EpisodeXmlSaver : IMetadataSaver { private readonly IServerConfigurationManager _config; + private readonly IItemRepository _itemRepository; /// <summary> /// Determines whether [is enabled for] [the specified item]. @@ -38,9 +40,10 @@ namespace MediaBrowser.Providers.Savers private readonly CultureInfo _usCulture = new CultureInfo("en-US"); - public EpisodeXmlSaver(IServerConfigurationManager config) + public EpisodeXmlSaver(IServerConfigurationManager config, IItemRepository itemRepository) { _config = config; + _itemRepository = itemRepository; } /// <summary> @@ -79,6 +82,7 @@ namespace MediaBrowser.Providers.Savers XmlSaverHelpers.AddCommonNodes(item, builder); XmlSaverHelpers.AddMediaInfo(episode, builder); + XmlSaverHelpers.AddChapters((Video)item, builder, _itemRepository); builder.Append("</Item>"); diff --git a/MediaBrowser.Providers/Savers/MovieXmlSaver.cs b/MediaBrowser.Providers/Savers/MovieXmlSaver.cs index 7c95e9dc3..ef58bd740 100644 --- a/MediaBrowser.Providers/Savers/MovieXmlSaver.cs +++ b/MediaBrowser.Providers/Savers/MovieXmlSaver.cs @@ -2,6 +2,7 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Persistence; using MediaBrowser.Providers.Movies; using System; using System.Globalization; @@ -18,10 +19,12 @@ namespace MediaBrowser.Providers.Savers public class MovieXmlSaver : IMetadataSaver { private readonly IServerConfigurationManager _config; + private readonly IItemRepository _itemRepository; - public MovieXmlSaver(IServerConfigurationManager config) + public MovieXmlSaver(IServerConfigurationManager config, IItemRepository itemRepository) { _config = config; + _itemRepository = itemRepository; } /// <summary> @@ -94,6 +97,8 @@ namespace MediaBrowser.Providers.Savers XmlSaverHelpers.AddMediaInfo((Video)item, builder); + XmlSaverHelpers.AddChapters((Video)item, builder, _itemRepository); + builder.Append("</Title>"); var xmlFilePath = GetSavePath(item); diff --git a/MediaBrowser.Providers/Savers/XmlSaverHelpers.cs b/MediaBrowser.Providers/Savers/XmlSaverHelpers.cs index 455d579cc..07f4da342 100644 --- a/MediaBrowser.Providers/Savers/XmlSaverHelpers.cs +++ b/MediaBrowser.Providers/Savers/XmlSaverHelpers.cs @@ -1,5 +1,6 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.TV; +using MediaBrowser.Controller.Persistence; using MediaBrowser.Model.Entities; using System; using System.Collections.Generic; @@ -79,7 +80,8 @@ namespace MediaBrowser.Providers.Savers "GamesDbId", "BirthDate", "DeathDate", - "LockedFields" + "LockedFields", + "Chapters" }); var position = xml.ToString().LastIndexOf("</", StringComparison.OrdinalIgnoreCase); @@ -411,7 +413,27 @@ namespace MediaBrowser.Providers.Savers builder.Append("</Persons>"); } + } + + public static void AddChapters(Video item, StringBuilder builder, IItemRepository repository) + { + var chapters = repository.GetChapters(item.Id); + + builder.Append("<Chapters>"); + + foreach (var chapter in chapters) + { + builder.Append("<Chapter>"); + builder.Append("<Name>" + SecurityElement.Escape(chapter.Name) + "</Name>"); + + var time = TimeSpan.FromTicks(chapter.StartPositionTicks); + var ms = Convert.ToInt64(time.TotalMilliseconds); + + builder.Append("<StartPositionMs>" + SecurityElement.Escape(ms.ToString(UsCulture)) + "</StartPositionMs>"); + builder.Append("</Chapter>"); + } + builder.Append("</Chapters>"); } /// <summary> diff --git a/MediaBrowser.Providers/TV/EpisodeProviderFromXml.cs b/MediaBrowser.Providers/TV/EpisodeProviderFromXml.cs index 76deffa4e..2408b14ce 100644 --- a/MediaBrowser.Providers/TV/EpisodeProviderFromXml.cs +++ b/MediaBrowser.Providers/TV/EpisodeProviderFromXml.cs @@ -1,13 +1,14 @@ using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.TV; +using MediaBrowser.Controller.Persistence; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Logging; using System; using System.IO; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Model.Logging; namespace MediaBrowser.Providers.TV { @@ -17,10 +18,12 @@ namespace MediaBrowser.Providers.TV public class EpisodeProviderFromXml : BaseMetadataProvider { internal static EpisodeProviderFromXml Current { get; private set; } + private readonly IItemRepository _itemRepo; - public EpisodeProviderFromXml(ILogManager logManager, IServerConfigurationManager configurationManager) + public EpisodeProviderFromXml(ILogManager logManager, IServerConfigurationManager configurationManager, IItemRepository itemRepo) : base(logManager, configurationManager) { + _itemRepo = itemRepo; Current = this; } @@ -98,7 +101,7 @@ namespace MediaBrowser.Providers.TV try { - new EpisodeXmlParser(Logger).Fetch((Episode)item, metadataFile, cancellationToken); + await new EpisodeXmlParser(Logger, _itemRepo).FetchAsync((Episode)item, metadataFile, cancellationToken).ConfigureAwait(false); } finally { diff --git a/MediaBrowser.Providers/TV/EpisodeXmlParser.cs b/MediaBrowser.Providers/TV/EpisodeXmlParser.cs index a64006a93..9dad56a84 100644 --- a/MediaBrowser.Providers/TV/EpisodeXmlParser.cs +++ b/MediaBrowser.Providers/TV/EpisodeXmlParser.cs @@ -1,7 +1,10 @@ using MediaBrowser.Controller.Entities.TV; +using MediaBrowser.Controller.Persistence; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Logging; using System.IO; +using System.Threading; +using System.Threading.Tasks; using System.Xml; namespace MediaBrowser.Providers.TV @@ -11,13 +14,28 @@ namespace MediaBrowser.Providers.TV /// </summary> public class EpisodeXmlParser : BaseItemXmlParser<Episode> { - /// <summary> - /// Initializes a new instance of the <see cref="EpisodeXmlParser" /> class. - /// </summary> - /// <param name="logger">The logger.</param> - public EpisodeXmlParser(ILogger logger) + private readonly IItemRepository _itemRepo; + + private Task _chaptersTask = null; + + public EpisodeXmlParser(ILogger logger, IItemRepository itemRepo) : base(logger) { + _itemRepo = itemRepo; + } + + public async Task FetchAsync(Episode item, string metadataFile, CancellationToken cancellationToken) + { + _chaptersTask = null; + + Fetch(item, metadataFile, cancellationToken); + + cancellationToken.ThrowIfCancellationRequested(); + + if (_chaptersTask != null) + { + await _chaptersTask.ConfigureAwait(false); + } } /// <summary> @@ -29,7 +47,13 @@ namespace MediaBrowser.Providers.TV { switch (reader.Name) { + case "Chapters": + + _chaptersTask = FetchChaptersFromXmlNode(item.Id, reader.ReadSubtree(), _itemRepo, CancellationToken.None); + break; + case "Episode": + //MB generated metadata is within an "Episode" node using (var subTree = reader.ReadSubtree()) { diff --git a/MediaBrowser.Server.Implementations/Providers/ProviderManager.cs b/MediaBrowser.Server.Implementations/Providers/ProviderManager.cs index b7d73b515..59217bc17 100644 --- a/MediaBrowser.Server.Implementations/Providers/ProviderManager.cs +++ b/MediaBrowser.Server.Implementations/Providers/ProviderManager.cs @@ -2,16 +2,12 @@ using MediaBrowser.Common.Net; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Entities.Audio; -using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.IO; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; -using MediaBrowser.Model.Net; using System; -using System.Collections.Concurrent; using System.Collections.Generic; using System.IO; using System.Linq; @@ -26,12 +22,6 @@ namespace MediaBrowser.Server.Implementations.Providers public class ProviderManager : IProviderManager { /// <summary> - /// The currently running metadata providers - /// </summary> - private readonly ConcurrentDictionary<string, Tuple<BaseMetadataProvider, BaseItem, CancellationTokenSource>> _currentlyRunningProviders = - new ConcurrentDictionary<string, Tuple<BaseMetadataProvider, BaseItem, CancellationTokenSource>>(); - - /// <summary> /// The _logger /// </summary> private readonly ILogger _logger; @@ -72,19 +62,6 @@ namespace MediaBrowser.Server.Implementations.Providers _httpClient = httpClient; ConfigurationManager = configurationManager; _directoryWatchers = directoryWatchers; - - configurationManager.ConfigurationUpdated += configurationManager_ConfigurationUpdated; - } - - /// <summary> - /// Handles the ConfigurationUpdated event of the configurationManager control. - /// </summary> - /// <param name="sender">The source of the event.</param> - /// <param name="e">The <see cref="EventArgs" /> instance containing the event data.</param> - void configurationManager_ConfigurationUpdated(object sender, EventArgs e) - { - // Validate currently executing providers, in the background - Task.Run(() => ValidateCurrentlyRunningProviders()); } /// <summary> @@ -217,8 +194,6 @@ namespace MediaBrowser.Server.Implementations.Providers // This provides the ability to cancel just this one provider var innerCancellationTokenSource = new CancellationTokenSource(); - OnProviderRefreshBeginning(provider, item, innerCancellationTokenSource); - try { var changed = await provider.FetchAsync(item, force, CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, innerCancellationTokenSource.Token).Token).ConfigureAwait(false); @@ -253,70 +228,6 @@ namespace MediaBrowser.Server.Implementations.Providers finally { innerCancellationTokenSource.Dispose(); - - OnProviderRefreshCompleted(provider, item); - } - } - - /// <summary> - /// Notifies the kernal that a provider has begun refreshing - /// </summary> - /// <param name="provider">The provider.</param> - /// <param name="item">The item.</param> - /// <param name="cancellationTokenSource">The cancellation token source.</param> - public void OnProviderRefreshBeginning(BaseMetadataProvider provider, BaseItem item, CancellationTokenSource cancellationTokenSource) - { - var key = item.Id + provider.GetType().Name; - - Tuple<BaseMetadataProvider, BaseItem, CancellationTokenSource> current; - - if (_currentlyRunningProviders.TryGetValue(key, out current)) - { - try - { - current.Item3.Cancel(); - } - catch (ObjectDisposedException) - { - - } - } - - var tuple = new Tuple<BaseMetadataProvider, BaseItem, CancellationTokenSource>(provider, item, cancellationTokenSource); - - _currentlyRunningProviders.AddOrUpdate(key, tuple, (k, v) => tuple); - } - - /// <summary> - /// Notifies the kernal that a provider has completed refreshing - /// </summary> - /// <param name="provider">The provider.</param> - /// <param name="item">The item.</param> - public void OnProviderRefreshCompleted(BaseMetadataProvider provider, BaseItem item) - { - var key = item.Id + provider.GetType().Name; - - Tuple<BaseMetadataProvider, BaseItem, CancellationTokenSource> current; - - if (_currentlyRunningProviders.TryRemove(key, out current)) - { - current.Item3.Dispose(); - } - } - - /// <summary> - /// Validates the currently running providers and cancels any that should not be run due to configuration changes - /// </summary> - private void ValidateCurrentlyRunningProviders() - { - var enableInternetProviders = ConfigurationManager.Configuration.EnableInternetProviders; - var internetProviderExcludeTypes = ConfigurationManager.Configuration.InternetProviderExcludeTypes; - - foreach (var tuple in _currentlyRunningProviders.Values - .Where(p => p.Item1.RequiresInternet && (!enableInternetProviders || internetProviderExcludeTypes.Contains(p.Item2.GetType().Name, StringComparer.OrdinalIgnoreCase))) - .ToList()) - { - tuple.Item3.Cancel(); } } |
