diff options
Diffstat (limited to 'MediaBrowser.Providers')
16 files changed, 213 insertions, 852 deletions
diff --git a/MediaBrowser.Providers/BoxSets/BoxSetMetadataService.cs b/MediaBrowser.Providers/BoxSets/BoxSetMetadataService.cs index 3ac3cccb3d..92327c9bc3 100644 --- a/MediaBrowser.Providers/BoxSets/BoxSetMetadataService.cs +++ b/MediaBrowser.Providers/BoxSets/BoxSetMetadataService.cs @@ -3,7 +3,6 @@ using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Library; -using MediaBrowser.Controller.Localization; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; @@ -16,11 +15,8 @@ namespace MediaBrowser.Providers.BoxSets { public class BoxSetMetadataService : MetadataService<BoxSet, BoxSetInfo> { - private readonly ILocalizationManager _iLocalizationManager; - - public BoxSetMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IProviderRepository providerRepo, IFileSystem fileSystem, IUserDataManager userDataManager, ILocalizationManager iLocalizationManager) : base(serverConfigurationManager, logger, providerManager, providerRepo, fileSystem, userDataManager) + public BoxSetMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IProviderRepository providerRepo, IFileSystem fileSystem, IUserDataManager userDataManager) : base(serverConfigurationManager, logger, providerManager, providerRepo, fileSystem, userDataManager) { - _iLocalizationManager = iLocalizationManager; } /// <summary> diff --git a/MediaBrowser.Providers/FolderImages/DefaultImageProvider.cs b/MediaBrowser.Providers/FolderImages/DefaultImageProvider.cs deleted file mode 100644 index 3550ee6885..0000000000 --- a/MediaBrowser.Providers/FolderImages/DefaultImageProvider.cs +++ /dev/null @@ -1,153 +0,0 @@ -using MediaBrowser.Common.Net; -using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Providers; -using MediaBrowser.Model.Entities; -using MediaBrowser.Model.Providers; -using MediaBrowser.Providers.Genres; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; - -namespace MediaBrowser.Providers.FolderImages -{ - public class DefaultImageProvider : IRemoteImageProvider, IHasItemChangeMonitor, IHasOrder - { - private readonly IHttpClient _httpClient; - - public DefaultImageProvider(IHttpClient httpClient) - { - _httpClient = httpClient; - } - - public IEnumerable<ImageType> GetSupportedImages(IHasImages item) - { - return new List<ImageType> - { - ImageType.Primary, - ImageType.Thumb - }; - } - - public Task<IEnumerable<RemoteImageInfo>> GetImages(IHasImages item, CancellationToken cancellationToken) - { - var view = item as UserView; - - if (view != null) - { - return GetImages(view.ViewType, view.ParentId != Guid.Empty, cancellationToken); - } - - var folder = (ICollectionFolder)item; - return GetImages(folder.CollectionType, false, cancellationToken); - } - - private Task<IEnumerable<RemoteImageInfo>> GetImages(string viewType, bool isSubView, CancellationToken cancellationToken) - { - var url = GetImageUrl(viewType, isSubView); - var list = new List<RemoteImageInfo>(); - - if (!string.IsNullOrWhiteSpace(url)) - { - list.AddRange(new List<RemoteImageInfo> - { - new RemoteImageInfo - { - ProviderName = Name, - Url = url, - Type = ImageType.Primary - }, - - new RemoteImageInfo - { - ProviderName = Name, - Url = url, - Type = ImageType.Thumb - } - }); - } - - return Task.FromResult<IEnumerable<RemoteImageInfo>>(list); - } - - private string GetImageUrl(string viewType, bool isSubView) - { - const string urlPrefix = "https://raw.githubusercontent.com/MediaBrowser/MediaBrowser.Resources/master/images/folders/"; - - if (string.Equals(viewType, CollectionType.Books, StringComparison.OrdinalIgnoreCase)) - { - return null; - } - if (string.Equals(viewType, CollectionType.Games, StringComparison.OrdinalIgnoreCase)) - { - return null; - } - if (string.Equals(viewType, CollectionType.Music, StringComparison.OrdinalIgnoreCase)) - { - return null; - } - if (string.Equals(viewType, CollectionType.Photos, StringComparison.OrdinalIgnoreCase)) - { - return null; - } - if (string.Equals(viewType, CollectionType.TvShows, StringComparison.OrdinalIgnoreCase)) - { - return null; - } - if (string.Equals(viewType, CollectionType.Channels, StringComparison.OrdinalIgnoreCase)) - { - return null; - } - if (string.Equals(viewType, CollectionType.LiveTv, StringComparison.OrdinalIgnoreCase)) - { - return null; - } - if (string.Equals(viewType, CollectionType.Movies, StringComparison.OrdinalIgnoreCase)) - { - return null; - } - - if (isSubView) - { - return null; - } - - return urlPrefix + "generic.png"; - } - - public string Name - { - get { return "Default Image Provider"; } - } - - public bool Supports(IHasImages item) - { - return item is ICollectionFolder || item is UserView; - } - - public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken) - { - return _httpClient.GetResponse(new HttpRequestOptions - { - CancellationToken = cancellationToken, - Url = url, - ResourcePool = GenreImageProvider.ImageDownloadResourcePool - }); - } - - public bool HasChanged(IHasMetadata item, MetadataStatus status, IDirectoryService directoryService) - { - return GetSupportedImages(item).Any(i => !item.HasImage(i)); - } - - public int Order - { - get - { - // Run after the dynamic image provider - return 1; - } - } - } -} diff --git a/MediaBrowser.Providers/Manager/ItemImageProvider.cs b/MediaBrowser.Providers/Manager/ItemImageProvider.cs index 533e843ea8..fc47b0259a 100644 --- a/MediaBrowser.Providers/Manager/ItemImageProvider.cs +++ b/MediaBrowser.Providers/Manager/ItemImageProvider.cs @@ -36,16 +36,15 @@ namespace MediaBrowser.Providers.Manager public bool ValidateImages(IHasImages item, IEnumerable<IImageProvider> providers, IDirectoryService directoryService) { - var hasChanges = item.ValidateImages(directoryService); + var hasChanges = false; - foreach (var provider in providers.OfType<ILocalImageFileProvider>()) - { - var images = provider.GetImages(item, directoryService); + var images = providers.OfType<ILocalImageFileProvider>() + .SelectMany(i => i.GetImages(item, directoryService)) + .ToList(); - if (MergeImages(item, images)) - { - hasChanges = true; - } + if (MergeImages(item, images)) + { + hasChanges = true; } return hasChanges; @@ -377,8 +376,7 @@ namespace MediaBrowser.Providers.Manager item.SetImagePath(type, image.FileInfo); changed = true; } - else if (!string.Equals(currentImage.Path, image.FileInfo.FullName, - StringComparison.OrdinalIgnoreCase)) + else if (!string.Equals(currentImage.Path, image.FileInfo.FullName, StringComparison.OrdinalIgnoreCase)) { item.SetImagePath(type, image.FileInfo); changed = true; @@ -386,7 +384,15 @@ namespace MediaBrowser.Providers.Manager else { currentImage.DateModified = _fileSystem.GetLastWriteTimeUtc(image.FileInfo); - currentImage.Length = ((FileInfo) image.FileInfo).Length; + } + } + else + { + var existing = item.GetImageInfo(type, 0); + if (existing != null && !File.Exists(existing.Path)) + { + item.RemoveImage(existing); + changed = true; } } } @@ -412,16 +418,16 @@ namespace MediaBrowser.Providers.Manager { var changed = false; - var backdrops = images.Where(i => i.Type == type).ToList(); - if (backdrops.Count > 0) + var newImages = images.Where(i => i.Type == type).ToList(); + if (newImages.Count > 0) { - var foundImages = images.Where(i => i.Type == type) + var newImageFileInfos = images.Where(i => i.Type == type) .Select(i => i.FileInfo) .ToList(); - if (foundImages.Count > 0) + if (newImageFileInfos.Count > 0) { - if (item.AddImages(type, foundImages)) + if (item.AddImages(type, newImageFileInfos)) { changed = true; } diff --git a/MediaBrowser.Providers/Manager/MetadataService.cs b/MediaBrowser.Providers/Manager/MetadataService.cs index 62def8b8bb..334e148506 100644 --- a/MediaBrowser.Providers/Manager/MetadataService.cs +++ b/MediaBrowser.Providers/Manager/MetadataService.cs @@ -141,7 +141,6 @@ namespace MediaBrowser.Providers.Manager updateType = updateType | result.UpdateType; refreshResult.AddStatus(result.Status, result.ErrorMessage); refreshResult.SetDateLastMetadataRefresh(DateTime.UtcNow); - refreshResult.AddMetadataProvidersRefreshed(result.Providers); MergeIdentities(itemOfType, id); } @@ -159,7 +158,6 @@ namespace MediaBrowser.Providers.Manager updateType = updateType | result.UpdateType; refreshResult.AddStatus(result.Status, result.ErrorMessage); refreshResult.SetDateLastImagesRefresh(DateTime.UtcNow); - refreshResult.AddImageProvidersRefreshed(result.Providers); } } @@ -484,6 +482,11 @@ namespace MediaBrowser.Providers.Manager protected virtual bool IsFullLocalMetadata(TItemType item) { + if (string.IsNullOrWhiteSpace(item.Name)) + { + return false; + } + return true; } diff --git a/MediaBrowser.Providers/Manager/ProviderManager.cs b/MediaBrowser.Providers/Manager/ProviderManager.cs index c9ae47ad0b..01a89bf26d 100644 --- a/MediaBrowser.Providers/Manager/ProviderManager.cs +++ b/MediaBrowser.Providers/Manager/ProviderManager.cs @@ -148,6 +148,13 @@ namespace MediaBrowser.Providers.Manager return new ImageSaver(ConfigurationManager, _libraryMonitor, _fileSystem, _logger).SaveImage(item, source, mimeType, type, imageIndex, internalCacheKey, cancellationToken); } + public Task SaveImage(IHasImages item, string source, string mimeType, ImageType type, int? imageIndex, string internalCacheKey, CancellationToken cancellationToken) + { + var fileStream = _fileSystem.GetFileStream(source, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, true); + + return new ImageSaver(ConfigurationManager, _libraryMonitor, _fileSystem, _logger).SaveImage(item, fileStream, mimeType, type, imageIndex, internalCacheKey, cancellationToken); + } + public async Task<IEnumerable<RemoteImageInfo>> GetAvailableRemoteImages(IHasImages item, RemoteImageQuery query, CancellationToken cancellationToken) { var providers = GetRemoteImageProviders(item, query.IncludeDisabledProviders); diff --git a/MediaBrowser.Providers/MediaBrowser.Providers.csproj b/MediaBrowser.Providers/MediaBrowser.Providers.csproj index 3b5103f209..444567afaf 100644 --- a/MediaBrowser.Providers/MediaBrowser.Providers.csproj +++ b/MediaBrowser.Providers/MediaBrowser.Providers.csproj @@ -83,7 +83,6 @@ <Compile Include="BoxSets\MovieDbBoxSetProvider.cs" /> <Compile Include="Channels\ChannelMetadataService.cs" /> <Compile Include="Chapters\ChapterManager.cs" /> - <Compile Include="FolderImages\DefaultImageProvider.cs" /> <Compile Include="Folders\FolderMetadataService.cs" /> <Compile Include="Channels\AudioChannelItemMetadataService.cs" /> <Compile Include="Folders\UserViewMetadataService.cs" /> @@ -102,7 +101,6 @@ <Compile Include="Manager\MetadataService.cs" /> <Compile Include="Manager\SeriesOrderManager.cs" /> <Compile Include="MediaInfo\FFProbeAudioInfo.cs" /> - <Compile Include="MediaInfo\FFProbeHelpers.cs" /> <Compile Include="MediaInfo\FFProbeProvider.cs" /> <Compile Include="MediaInfo\FFProbeVideoInfo.cs" /> <Compile Include="MediaInfo\SubtitleDownloader.cs" /> @@ -198,10 +196,6 @@ <Project>{17E1F4E6-8ABD-4FE5-9ECF-43D4B6087BA2}</Project> <Name>MediaBrowser.Controller</Name> </ProjectReference> - <ProjectReference Include="..\MediaBrowser.MediaInfo\MediaBrowser.MediaInfo.csproj"> - <Project>{6e4145e4-c6d4-4e4d-94f2-87188db6e239}</Project> - <Name>MediaBrowser.MediaInfo</Name> - </ProjectReference> <ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj"> <Project>{7EEEB4BB-F3E8-48FC-B4C5-70F0FFF8329B}</Project> <Name>MediaBrowser.Model</Name> @@ -214,9 +208,6 @@ <ItemGroup> <None Include="packages.config" /> </ItemGroup> - <ItemGroup> - <EmbeddedResource Include="MediaInfo\whitelist.txt" /> - </ItemGroup> <ItemGroup /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <!-- To modify your build process, add your task inside one of the targets below and uncomment it. diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs b/MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs index ea191dd08f..d78f1b48e6 100644 --- a/MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs +++ b/MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs @@ -1,15 +1,13 @@ using MediaBrowser.Common.Configuration; -using MediaBrowser.Model.Extensions; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Controller.Persistence; +using MediaBrowser.Model.Dlna; using MediaBrowser.Model.Entities; using MediaBrowser.Model.MediaInfo; using MediaBrowser.Model.Serialization; -using System; -using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; @@ -49,18 +47,14 @@ namespace MediaBrowser.Providers.MediaInfo cancellationToken.ThrowIfCancellationRequested(); - FFProbeHelpers.NormalizeFFProbeResult(result); - - cancellationToken.ThrowIfCancellationRequested(); - await Fetch(item, cancellationToken, result).ConfigureAwait(false); return ItemUpdateType.MetadataImport; } - private const string SchemaVersion = "1"; + private const string SchemaVersion = "2"; - private async Task<InternalMediaInfoResult> GetMediaInfo(BaseItem item, CancellationToken cancellationToken) + private async Task<Model.MediaInfo.MediaInfo> GetMediaInfo(BaseItem item, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); @@ -71,7 +65,7 @@ namespace MediaBrowser.Providers.MediaInfo try { - return _json.DeserializeFromFile<InternalMediaInfoResult>(cachePath); + return _json.DeserializeFromFile<Model.MediaInfo.MediaInfo>(cachePath); } catch (FileNotFoundException) { @@ -81,9 +75,13 @@ namespace MediaBrowser.Providers.MediaInfo { } - var inputPath = new[] { item.Path }; + var result = await _mediaEncoder.GetMediaInfo(new MediaInfoRequest + { + InputPath = item.Path, + MediaType = DlnaProfileType.Audio, + Protocol = MediaProtocol.File - var result = await _mediaEncoder.GetMediaInfo(inputPath, MediaProtocol.File, false, cancellationToken).ConfigureAwait(false); + }, cancellationToken).ConfigureAwait(false); Directory.CreateDirectory(Path.GetDirectoryName(cachePath)); _json.SerializeToFile(result, cachePath); @@ -96,61 +94,23 @@ namespace MediaBrowser.Providers.MediaInfo /// </summary> /// <param name="audio">The audio.</param> /// <param name="cancellationToken">The cancellation token.</param> - /// <param name="data">The data.</param> + /// <param name="mediaInfo">The media information.</param> /// <returns>Task.</returns> - protected Task Fetch(Audio audio, CancellationToken cancellationToken, InternalMediaInfoResult data) + protected Task Fetch(Audio audio, CancellationToken cancellationToken, Model.MediaInfo.MediaInfo mediaInfo) { - var mediaInfo = MediaEncoderHelpers.GetMediaInfo(data); var mediaStreams = mediaInfo.MediaStreams; - audio.FormatName = mediaInfo.Format; - audio.TotalBitrate = mediaInfo.TotalBitrate; + audio.FormatName = mediaInfo.Container; + audio.TotalBitrate = mediaInfo.Bitrate; audio.HasEmbeddedImage = mediaStreams.Any(i => i.Type == MediaStreamType.EmbeddedImage); - if (data.streams != null) - { - // Get the first audio stream - var stream = data.streams.FirstOrDefault(s => string.Equals(s.codec_type, "audio", StringComparison.OrdinalIgnoreCase)); - - if (stream != null) - { - // Get duration from stream properties - var duration = stream.duration; - - // If it's not there go into format properties - if (string.IsNullOrEmpty(duration)) - { - duration = data.format.duration; - } - - // If we got something, parse it - if (!string.IsNullOrEmpty(duration)) - { - audio.RunTimeTicks = TimeSpan.FromSeconds(double.Parse(duration, _usCulture)).Ticks; - } - } - } - - if (data.format != null) - { - var extension = (Path.GetExtension(audio.Path) ?? string.Empty).TrimStart('.'); - - audio.Container = extension; + audio.RunTimeTicks = mediaInfo.RunTimeTicks; + audio.Size = mediaInfo.Size; - if (!string.IsNullOrEmpty(data.format.size)) - { - audio.Size = long.Parse(data.format.size, _usCulture); - } - else - { - audio.Size = null; - } + var extension = (Path.GetExtension(audio.Path) ?? string.Empty).TrimStart('.'); + audio.Container = extension; - if (data.format.tags != null) - { - FetchDataFromTags(audio, data.format.tags); - } - } + FetchDataFromTags(audio, mediaInfo); return _itemRepo.SaveMediaStreams(audio.Id, mediaStreams, cancellationToken); } @@ -159,92 +119,37 @@ namespace MediaBrowser.Providers.MediaInfo /// Fetches data from the tags dictionary /// </summary> /// <param name="audio">The audio.</param> - /// <param name="tags">The tags.</param> - private void FetchDataFromTags(Audio audio, Dictionary<string, string> tags) + /// <param name="data">The data.</param> + private void FetchDataFromTags(Audio audio, Model.MediaInfo.MediaInfo data) { - var title = FFProbeHelpers.GetDictionaryValue(tags, "title"); - // Only set Name if title was found in the dictionary - if (!string.IsNullOrEmpty(title)) + if (!string.IsNullOrEmpty(data.Title)) { - audio.Name = title; + audio.Name = data.Title; } if (!audio.LockedFields.Contains(MetadataFields.Cast)) { audio.People.Clear(); - var composer = FFProbeHelpers.GetDictionaryValue(tags, "composer"); - - if (!string.IsNullOrWhiteSpace(composer)) + foreach (var person in data.People) { - foreach (var person in Split(composer, false)) + audio.AddPerson(new PersonInfo { - audio.AddPerson(new PersonInfo { Name = person, Type = PersonType.Composer }); - } + Name = person.Name, + Type = person.Type, + Role = person.Role + }); } } - audio.Album = FFProbeHelpers.GetDictionaryValue(tags, "album"); - - var artists = FFProbeHelpers.GetDictionaryValue(tags, "artists"); - - if (!string.IsNullOrWhiteSpace(artists)) - { - audio.Artists = artists.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries) - .Distinct(StringComparer.OrdinalIgnoreCase) - .ToList(); - } - else - { - var artist = FFProbeHelpers.GetDictionaryValue(tags, "artist"); - if (string.IsNullOrWhiteSpace(artist)) - { - audio.Artists.Clear(); - } - else - { - audio.Artists = SplitArtists(artist) - .Distinct(StringComparer.OrdinalIgnoreCase) - .ToList(); - } - } - - var albumArtist = FFProbeHelpers.GetDictionaryValue(tags, "albumartist"); - if (string.IsNullOrWhiteSpace(albumArtist)) - { - albumArtist = FFProbeHelpers.GetDictionaryValue(tags, "album artist"); - } - if (string.IsNullOrWhiteSpace(albumArtist)) - { - albumArtist = FFProbeHelpers.GetDictionaryValue(tags, "album_artist"); - } - - if (string.IsNullOrWhiteSpace(albumArtist)) - { - audio.AlbumArtists = new List<string>(); - } - else - { - audio.AlbumArtists = SplitArtists(albumArtist) - .Distinct(StringComparer.OrdinalIgnoreCase) - .ToList(); - - } - - // Track number - audio.IndexNumber = GetDictionaryDiscValue(tags, "track"); - - // Disc number - audio.ParentIndexNumber = GetDictionaryDiscValue(tags, "disc"); - - audio.ProductionYear = FFProbeHelpers.GetDictionaryNumericValue(tags, "date"); - - // Several different forms of retaildate - audio.PremiereDate = FFProbeHelpers.GetDictionaryDateTime(tags, "retaildate") ?? - FFProbeHelpers.GetDictionaryDateTime(tags, "retail date") ?? - FFProbeHelpers.GetDictionaryDateTime(tags, "retail_date") ?? - FFProbeHelpers.GetDictionaryDateTime(tags, "date"); + audio.Album = data.Album; + audio.Artists = data.Artists; + audio.AlbumArtists = data.AlbumArtists; + audio.IndexNumber = data.IndexNumber; + audio.ParentIndexNumber = data.ParentIndexNumber; + audio.ProductionYear = data.ProductionYear; + audio.PremiereDate = data.PremiereDate; // If we don't have a ProductionYear try and get it from PremiereDate if (audio.PremiereDate.HasValue && !audio.ProductionYear.HasValue) @@ -254,192 +159,29 @@ namespace MediaBrowser.Providers.MediaInfo if (!audio.LockedFields.Contains(MetadataFields.Genres)) { - FetchGenres(audio, tags); - } - - if (!audio.LockedFields.Contains(MetadataFields.Studios)) - { - audio.Studios.Clear(); - - // There's several values in tags may or may not be present - FetchStudios(audio, tags, "organization"); - FetchStudios(audio, tags, "ensemble"); - FetchStudios(audio, tags, "publisher"); - } - - // These support mulitple values, but for now we only store the first. - audio.SetProviderId(MetadataProviders.MusicBrainzAlbumArtist, GetMultipleMusicBrainzId(FFProbeHelpers.GetDictionaryValue(tags, "MusicBrainz Album Artist Id"))); - audio.SetProviderId(MetadataProviders.MusicBrainzArtist, GetMultipleMusicBrainzId(FFProbeHelpers.GetDictionaryValue(tags, "MusicBrainz Artist Id"))); - - audio.SetProviderId(MetadataProviders.MusicBrainzAlbum, GetMultipleMusicBrainzId(FFProbeHelpers.GetDictionaryValue(tags, "MusicBrainz Album Id"))); - audio.SetProviderId(MetadataProviders.MusicBrainzReleaseGroup, GetMultipleMusicBrainzId(FFProbeHelpers.GetDictionaryValue(tags, "MusicBrainz Release Group Id"))); - audio.SetProviderId(MetadataProviders.MusicBrainzTrack, GetMultipleMusicBrainzId(FFProbeHelpers.GetDictionaryValue(tags, "MusicBrainz Release Track Id"))); - } - - private string GetMultipleMusicBrainzId(string value) - { - if (string.IsNullOrWhiteSpace(value)) - { - return null; - } - - return value.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries) - .Select(i => i.Trim()) - .FirstOrDefault(i => !string.IsNullOrWhiteSpace(i)); - } - - private readonly char[] _nameDelimiters = { '/', '|', ';', '\\' }; - - /// <summary> - /// Splits the specified val. - /// </summary> - /// <param name="val">The val.</param> - /// <param name="allowCommaDelimiter">if set to <c>true</c> [allow comma delimiter].</param> - /// <returns>System.String[][].</returns> - private IEnumerable<string> Split(string val, bool allowCommaDelimiter) - { - // Only use the comma as a delimeter if there are no slashes or pipes. - // We want to be careful not to split names that have commas in them - var delimeter = !allowCommaDelimiter || _nameDelimiters.Any(i => val.IndexOf(i) != -1) ? - _nameDelimiters : - new[] { ',' }; - - return val.Split(delimeter, StringSplitOptions.RemoveEmptyEntries) - .Where(i => !string.IsNullOrWhiteSpace(i)) - .Select(i => i.Trim()); - } - - private const string ArtistReplaceValue = " | "; - - private IEnumerable<string> SplitArtists(string val) - { - val = val.Replace(" featuring ", ArtistReplaceValue, StringComparison.OrdinalIgnoreCase) - .Replace(" feat. ", ArtistReplaceValue, StringComparison.OrdinalIgnoreCase); - - var artistsFound = new List<string>(); - - foreach (var whitelistArtist in GetSplitWhitelist()) - { - var originalVal = val; - val = val.Replace(whitelistArtist, "|", StringComparison.OrdinalIgnoreCase); - - if (!string.Equals(originalVal, val, StringComparison.OrdinalIgnoreCase)) - { - artistsFound.Add(whitelistArtist); - } - } - - // Only use the comma as a delimeter if there are no slashes or pipes. - // We want to be careful not to split names that have commas in them - var delimeter = _nameDelimiters; - - var artists = val.Split(delimeter, StringSplitOptions.RemoveEmptyEntries) - .Where(i => !string.IsNullOrWhiteSpace(i)) - .Select(i => i.Trim()); - - artistsFound.AddRange(artists); - return artistsFound; - } - - - private List<string> _splitWhiteList = null; - - private IEnumerable<string> GetSplitWhitelist() - { - if (_splitWhiteList == null) - { - var file = GetType().Namespace + ".whitelist.txt"; - - using (var stream = GetType().Assembly.GetManifestResourceStream(file)) - { - using (var reader = new StreamReader(stream)) - { - var list = new List<string>(); - - while (!reader.EndOfStream) - { - var val = reader.ReadLine(); - - if (!string.IsNullOrWhiteSpace(val)) - { - list.Add(val); - } - } - - _splitWhiteList = list; - } - } - } - - return _splitWhiteList; - } - - /// <summary> - /// Gets the studios from the tags collection - /// </summary> - /// <param name="audio">The audio.</param> - /// <param name="tags">The tags.</param> - /// <param name="tagName">Name of the tag.</param> - private void FetchStudios(Audio audio, Dictionary<string, string> tags, string tagName) - { - var val = FFProbeHelpers.GetDictionaryValue(tags, tagName); - - if (!string.IsNullOrEmpty(val)) - { - // Sometimes the artist name is listed here, account for that - var studios = Split(val, true).Where(i => !audio.HasAnyArtist(i)); - - foreach (var studio in studios) - { - audio.AddStudio(studio); - } - } - } - - /// <summary> - /// Gets the genres from the tags collection - /// </summary> - /// <param name="audio">The audio.</param> - /// <param name="tags">The tags.</param> - private void FetchGenres(Audio audio, Dictionary<string, string> tags) - { - var val = FFProbeHelpers.GetDictionaryValue(tags, "genre"); - - if (!string.IsNullOrEmpty(val)) - { audio.Genres.Clear(); - foreach (var genre in Split(val, true)) + foreach (var genre in data.Genres) { audio.AddGenre(genre); } } - } - - /// <summary> - /// Gets the disc number, which is sometimes can be in the form of '1', or '1/3' - /// </summary> - /// <param name="tags">The tags.</param> - /// <param name="tagName">Name of the tag.</param> - /// <returns>System.Nullable{System.Int32}.</returns> - private int? GetDictionaryDiscValue(Dictionary<string, string> tags, string tagName) - { - var disc = FFProbeHelpers.GetDictionaryValue(tags, tagName); - if (!string.IsNullOrEmpty(disc)) + if (!audio.LockedFields.Contains(MetadataFields.Studios)) { - disc = disc.Split('/')[0]; - - int num; + audio.Studios.Clear(); - if (int.TryParse(disc, out num)) + foreach (var studio in data.Studios) { - return num; + audio.AddStudio(studio); } } - return null; + audio.SetProviderId(MetadataProviders.MusicBrainzAlbumArtist, data.GetProviderId(MetadataProviders.MusicBrainzAlbumArtist)); + audio.SetProviderId(MetadataProviders.MusicBrainzArtist, data.GetProviderId(MetadataProviders.MusicBrainzArtist)); + audio.SetProviderId(MetadataProviders.MusicBrainzAlbum, data.GetProviderId(MetadataProviders.MusicBrainzAlbum)); + audio.SetProviderId(MetadataProviders.MusicBrainzReleaseGroup, data.GetProviderId(MetadataProviders.MusicBrainzReleaseGroup)); + audio.SetProviderId(MetadataProviders.MusicBrainzTrack, data.GetProviderId(MetadataProviders.MusicBrainzTrack)); } - } } diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeHelpers.cs b/MediaBrowser.Providers/MediaInfo/FFProbeHelpers.cs deleted file mode 100644 index 2044979e4e..0000000000 --- a/MediaBrowser.Providers/MediaInfo/FFProbeHelpers.cs +++ /dev/null @@ -1,118 +0,0 @@ -using MediaBrowser.Controller.MediaEncoding; -using System; -using System.Collections.Generic; - -namespace MediaBrowser.Providers.MediaInfo -{ - public static class FFProbeHelpers - { - /// <summary> - /// Normalizes the FF probe result. - /// </summary> - /// <param name="result">The result.</param> - public static void NormalizeFFProbeResult(InternalMediaInfoResult result) - { - if (result == null) - { - throw new ArgumentNullException("result"); - } - - if (result.format != null && result.format.tags != null) - { - result.format.tags = ConvertDictionaryToCaseInSensitive(result.format.tags); - } - - if (result.streams != null) - { - // Convert all dictionaries to case insensitive - foreach (var stream in result.streams) - { - if (stream.tags != null) - { - stream.tags = ConvertDictionaryToCaseInSensitive(stream.tags); - } - - if (stream.disposition != null) - { - stream.disposition = ConvertDictionaryToCaseInSensitive(stream.disposition); - } - } - } - } - - /// <summary> - /// Gets a string from an FFProbeResult tags dictionary - /// </summary> - /// <param name="tags">The tags.</param> - /// <param name="key">The key.</param> - /// <returns>System.String.</returns> - public static string GetDictionaryValue(Dictionary<string, string> tags, string key) - { - if (tags == null) - { - return null; - } - - string val; - - tags.TryGetValue(key, out val); - return val; - } - - /// <summary> - /// Gets an int from an FFProbeResult tags dictionary - /// </summary> - /// <param name="tags">The tags.</param> - /// <param name="key">The key.</param> - /// <returns>System.Nullable{System.Int32}.</returns> - public static int? GetDictionaryNumericValue(Dictionary<string, string> tags, string key) - { - var val = GetDictionaryValue(tags, key); - - if (!string.IsNullOrEmpty(val)) - { - int i; - - if (int.TryParse(val, out i)) - { - return i; - } - } - - return null; - } - - /// <summary> - /// Gets a DateTime from an FFProbeResult tags dictionary - /// </summary> - /// <param name="tags">The tags.</param> - /// <param name="key">The key.</param> - /// <returns>System.Nullable{DateTime}.</returns> - public static DateTime? GetDictionaryDateTime(Dictionary<string, string> tags, string key) - { - var val = GetDictionaryValue(tags, key); - - if (!string.IsNullOrEmpty(val)) - { - DateTime i; - - if (DateTime.TryParse(val, out i)) - { - return i.ToUniversalTime(); - } - } - - return null; - } - - /// <summary> - /// Converts a dictionary to case insensitive - /// </summary> - /// <param name="dict">The dict.</param> - /// <returns>Dictionary{System.StringSystem.String}.</returns> - private static Dictionary<string, string> ConvertDictionaryToCaseInSensitive(Dictionary<string, string> dict) - { - return new Dictionary<string, string>(dict, StringComparer.OrdinalIgnoreCase); - } - } -} diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs index ca11f858af..b53e313168 100644 --- a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs +++ b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs @@ -1,5 +1,6 @@ using DvdLib.Ifo; using MediaBrowser.Common.Configuration; +using MediaBrowser.Model.Dlna; using MediaBrowser.Model.Extensions; using MediaBrowser.Common.IO; using MediaBrowser.Controller.Chapters; @@ -13,7 +14,6 @@ using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Controller.Persistence; using MediaBrowser.Controller.Providers; using MediaBrowser.Controller.Subtitles; -using MediaBrowser.MediaInfo; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Entities; using MediaBrowser.Model.IO; @@ -116,10 +116,6 @@ namespace MediaBrowser.Providers.MediaInfo cancellationToken.ThrowIfCancellationRequested(); - FFProbeHelpers.NormalizeFFProbeResult(result); - - cancellationToken.ThrowIfCancellationRequested(); - await Fetch(item, cancellationToken, result, isoMount, blurayDiscInfo, options).ConfigureAwait(false); } @@ -134,9 +130,9 @@ namespace MediaBrowser.Providers.MediaInfo return ItemUpdateType.MetadataImport; } - private const string SchemaVersion = "1"; + private const string SchemaVersion = "4"; - private async Task<InternalMediaInfoResult> GetMediaInfo(Video item, + private async Task<Model.MediaInfo.MediaInfo> GetMediaInfo(Video item, IIsoMount isoMount, CancellationToken cancellationToken) { @@ -149,7 +145,7 @@ namespace MediaBrowser.Providers.MediaInfo try { - return _json.DeserializeFromFile<InternalMediaInfoResult>(cachePath); + return _json.DeserializeFromFile<Model.MediaInfo.MediaInfo>(cachePath); } catch (FileNotFoundException) { @@ -163,9 +159,18 @@ namespace MediaBrowser.Providers.MediaInfo ? MediaProtocol.Http : MediaProtocol.File; - var inputPath = MediaEncoderHelpers.GetInputArgument(item.Path, protocol, isoMount, item.PlayableStreamFileNames); + var result = await _mediaEncoder.GetMediaInfo(new MediaInfoRequest + { + PlayableStreamFileNames = item.PlayableStreamFileNames, + MountedIso = isoMount, + ExtractChapters = true, + VideoType = item.VideoType, + MediaType = DlnaProfileType.Video, + InputPath = item.Path, + Protocol = protocol, + ExtractKeyFrameInterval = true - var result = await _mediaEncoder.GetMediaInfo(inputPath, protocol, false, cancellationToken).ConfigureAwait(false); + }, cancellationToken).ConfigureAwait(false); Directory.CreateDirectory(Path.GetDirectoryName(cachePath)); _json.SerializeToFile(result, cachePath); @@ -175,52 +180,37 @@ namespace MediaBrowser.Providers.MediaInfo protected async Task Fetch(Video video, CancellationToken cancellationToken, - InternalMediaInfoResult data, + Model.MediaInfo.MediaInfo mediaInfo, IIsoMount isoMount, BlurayDiscInfo blurayInfo, MetadataRefreshOptions options) { - var mediaInfo = MediaEncoderHelpers.GetMediaInfo(data); var mediaStreams = mediaInfo.MediaStreams; - video.TotalBitrate = mediaInfo.TotalBitrate; - video.FormatName = (mediaInfo.Format ?? string.Empty) + video.TotalBitrate = mediaInfo.Bitrate; + video.FormatName = (mediaInfo.Container ?? string.Empty) .Replace("matroska", "mkv", StringComparison.OrdinalIgnoreCase); - if (data.format != null) - { - // For dvd's this may not always be accurate, so don't set the runtime if the item already has one - var needToSetRuntime = video.VideoType != VideoType.Dvd || video.RunTimeTicks == null || video.RunTimeTicks.Value == 0; - - if (needToSetRuntime && !string.IsNullOrEmpty(data.format.duration)) - { - video.RunTimeTicks = TimeSpan.FromSeconds(double.Parse(data.format.duration, _usCulture)).Ticks; - } + // For dvd's this may not always be accurate, so don't set the runtime if the item already has one + var needToSetRuntime = video.VideoType != VideoType.Dvd || video.RunTimeTicks == null || video.RunTimeTicks.Value == 0; - if (video.VideoType == VideoType.VideoFile) - { - var extension = (Path.GetExtension(video.Path) ?? string.Empty).TrimStart('.'); + if (needToSetRuntime) + { + video.RunTimeTicks = mediaInfo.RunTimeTicks; + } - video.Container = extension; - } - else - { - video.Container = null; - } + if (video.VideoType == VideoType.VideoFile) + { + var extension = (Path.GetExtension(video.Path) ?? string.Empty).TrimStart('.'); - if (!string.IsNullOrEmpty(data.format.size)) - { - video.Size = long.Parse(data.format.size, _usCulture); - } - else - { - video.Size = null; - } + video.Container = extension; + } + else + { + video.Container = null; } - var mediaChapters = (data.Chapters ?? new MediaChapter[] { }).ToList(); - var chapters = mediaChapters.Select(GetChapterInfo).ToList(); - + var chapters = mediaInfo.Chapters ?? new List<ChapterInfo>(); if (video.VideoType == VideoType.BluRay || (video.IsoType.HasValue && video.IsoType.Value == IsoType.BluRay)) { FetchBdInfo(video, chapters, mediaStreams, blurayInfo); @@ -228,7 +218,7 @@ namespace MediaBrowser.Providers.MediaInfo await AddExternalSubtitles(video, mediaStreams, options, cancellationToken).ConfigureAwait(false); - FetchWtvInfo(video, data); + FetchEmbeddedInfo(video, mediaInfo, options); video.IsHD = mediaStreams.Any(i => i.Type == MediaStreamType.Video && i.Width.HasValue && i.Width.Value >= 1270); @@ -238,9 +228,7 @@ namespace MediaBrowser.Providers.MediaInfo video.DefaultVideoStreamIndex = videoStream == null ? (int?)null : videoStream.Index; video.HasSubtitles = mediaStreams.Any(i => i.Type == MediaStreamType.Subtitle); - - ExtractTimestamp(video); - UpdateFromMediaInfo(video, videoStream); + video.Timestamp = mediaInfo.Timestamp; await _itemRepo.SaveMediaStreams(video.Id, mediaStreams, cancellationToken).ConfigureAwait(false); @@ -283,29 +271,6 @@ namespace MediaBrowser.Providers.MediaInfo } } - private void UpdateFromMediaInfo(Video video, MediaStream videoStream) - { - if (video.VideoType == VideoType.VideoFile && video.LocationType != LocationType.Remote && video.LocationType != LocationType.Virtual) - { - if (videoStream != null) - { - try - { - var result = new MediaInfoLib().GetVideoInfo(video.Path); - - videoStream.IsCabac = result.IsCabac ?? videoStream.IsCabac; - videoStream.IsInterlaced = result.IsInterlaced ?? videoStream.IsInterlaced; - videoStream.BitDepth = result.BitDepth ?? videoStream.BitDepth; - videoStream.RefFrames = result.RefFrames; - } - catch (Exception ex) - { - _logger.ErrorException("Error running MediaInfo on {0}", ex, video.Path); - } - } - } - } - private void NormalizeChapterNames(List<ChapterInfo> chapters) { var index = 1; @@ -325,32 +290,6 @@ namespace MediaBrowser.Providers.MediaInfo } } - private ChapterInfo GetChapterInfo(MediaChapter chapter) - { - var info = new ChapterInfo(); - - if (chapter.tags != null) - { - string name; - if (chapter.tags.TryGetValue("title", out name)) - { - info.Name = name; - } - } - - // Limit accuracy to milliseconds to match xml saving - var secondsString = chapter.start_time; - double seconds; - - if (double.TryParse(secondsString, NumberStyles.Any, CultureInfo.InvariantCulture, out seconds)) - { - var ms = Math.Round(TimeSpan.FromSeconds(seconds).TotalMilliseconds); - info.StartPositionTicks = TimeSpan.FromMilliseconds(ms).Ticks; - } - - return info; - } - private void FetchBdInfo(BaseItem item, List<ChapterInfo> chapters, List<MediaStream> mediaStreams, BlurayDiscInfo blurayInfo) { var video = (Video)item; @@ -419,129 +358,102 @@ namespace MediaBrowser.Providers.MediaInfo return _blurayExaminer.GetDiscInfo(path); } - public const int MaxSubtitleDescriptionExtractionLength = 100; // When extracting subtitles, the maximum length to consider (to avoid invalid filenames) - - private void FetchWtvInfo(Video video, InternalMediaInfoResult data) + private void FetchEmbeddedInfo(Video video, Model.MediaInfo.MediaInfo data, MetadataRefreshOptions options) { - if (data.format == null || data.format.tags == null) + var isFullRefresh = options.MetadataRefreshMode == MetadataRefreshMode.FullRefresh; + + if (!video.LockedFields.Contains(MetadataFields.OfficialRating)) { - return; + if (!string.IsNullOrWhiteSpace(data.OfficialRating) || isFullRefresh) + { + video.OfficialRating = data.OfficialRating; + } } - if (!video.LockedFields.Contains(MetadataFields.Genres)) + if (!video.LockedFields.Contains(MetadataFields.Cast)) { - var genres = FFProbeHelpers.GetDictionaryValue(data.format.tags, "WM/Genre"); - - if (!string.IsNullOrWhiteSpace(genres)) + if (video.People.Count == 0 || isFullRefresh) { - //genres = FFProbeHelpers.GetDictionaryValue(data.format.tags, "genre"); + video.People.Clear(); + + foreach (var person in data.People) + { + video.AddPerson(new PersonInfo + { + Name = person.Name, + Type = person.Type, + Role = person.Role + }); + } } + } - if (!string.IsNullOrWhiteSpace(genres)) + if (!video.LockedFields.Contains(MetadataFields.Genres)) + { + if (video.Genres.Count == 0 || isFullRefresh) { - video.Genres = genres.Split(new[] { ';', '/', ',' }, StringSplitOptions.RemoveEmptyEntries) - .Where(i => !string.IsNullOrWhiteSpace(i)) - .Select(i => i.Trim()) - .ToList(); + video.Genres.Clear(); + + foreach (var genre in data.Genres) + { + video.AddGenre(genre); + } } } - if (!video.LockedFields.Contains(MetadataFields.OfficialRating)) + if (!video.LockedFields.Contains(MetadataFields.Studios)) { - var officialRating = FFProbeHelpers.GetDictionaryValue(data.format.tags, "WM/ParentalRating"); - - if (!string.IsNullOrWhiteSpace(officialRating)) + if (video.Studios.Count == 0 || isFullRefresh) { - video.OfficialRating = officialRating; + video.Studios.Clear(); + + foreach (var studio in data.Studios) + { + video.AddStudio(studio); + } } } - if (!video.LockedFields.Contains(MetadataFields.Cast)) + if (data.ProductionYear.HasValue) { - var people = FFProbeHelpers.GetDictionaryValue(data.format.tags, "WM/MediaCredits"); - - if (!string.IsNullOrEmpty(people)) + if (!video.ProductionYear.HasValue || isFullRefresh) { - video.People = people.Split(new[] { ';', '/' }, StringSplitOptions.RemoveEmptyEntries) - .Where(i => !string.IsNullOrWhiteSpace(i)) - .Select(i => new PersonInfo { Name = i.Trim(), Type = PersonType.Actor }) - .ToList(); + video.ProductionYear = data.ProductionYear; } } - - var year = FFProbeHelpers.GetDictionaryValue(data.format.tags, "WM/OriginalReleaseTime"); - if (!string.IsNullOrWhiteSpace(year)) + if (data.PremiereDate.HasValue) { - int val; - - if (int.TryParse(year, NumberStyles.Integer, _usCulture, out val)) + if (!video.PremiereDate.HasValue || isFullRefresh) { - video.ProductionYear = val; + video.PremiereDate = data.PremiereDate; } } - - var premiereDateString = FFProbeHelpers.GetDictionaryValue(data.format.tags, "WM/MediaOriginalBroadcastDateTime"); - if (!string.IsNullOrWhiteSpace(premiereDateString)) + if (data.IndexNumber.HasValue) { - DateTime val; - - // Credit to MCEBuddy: https://mcebuddy2x.codeplex.com/ - // DateTime is reported along with timezone info (typically Z i.e. UTC hence assume None) - if (DateTime.TryParse(year, null, DateTimeStyles.None, out val)) + if (!video.IndexNumber.HasValue || isFullRefresh) { - video.PremiereDate = val.ToUniversalTime(); + video.IndexNumber = data.IndexNumber; } } - - var description = FFProbeHelpers.GetDictionaryValue(data.format.tags, "WM/SubTitleDescription"); - - var episode = video as Episode; - if (episode != null) + if (data.ParentIndexNumber.HasValue) { - var subTitle = FFProbeHelpers.GetDictionaryValue(data.format.tags, "WM/SubTitle"); - - // For below code, credit to MCEBuddy: https://mcebuddy2x.codeplex.com/ - - // Sometimes for TV Shows the Subtitle field is empty and the subtitle description contains the subtitle, extract if possible. See ticket https://mcebuddy2x.codeplex.com/workitem/1910 - // The format is -> EPISODE/TOTAL_EPISODES_IN_SEASON. SUBTITLE: DESCRIPTION - // OR -> COMMENT. SUBTITLE: DESCRIPTION - // e.g. -> 4/13. The Doctor's Wife: Science fiction drama. When he follows a Time Lord distress signal, the Doctor puts Amy, Rory and his beloved TARDIS in grave danger. Also in HD. [AD,S] - // e.g. -> CBeebies Bedtime Hour. The Mystery: Animated adventures of two friends who live on an island in the middle of the big city. Some of Abney and Teal's favourite objects are missing. [S] - if (String.IsNullOrWhiteSpace(subTitle) && !String.IsNullOrWhiteSpace(description) && description.Substring(0, Math.Min(description.Length, MaxSubtitleDescriptionExtractionLength)).Contains(":")) // Check within the Subtitle size limit, otherwise from description it can get too long creating an invalid filename + if (!video.ParentIndexNumber.HasValue || isFullRefresh) { - string[] parts = description.Split(':'); - if (parts.Length > 0) - { - string subtitle = parts[0]; - try - { - if (subtitle.Contains("/")) // It contains a episode number and season number - { - string[] numbers = subtitle.Split(' '); - episode.IndexNumber = int.Parse(numbers[0].Replace(".", "").Split('/')[0]); - int totalEpisodesInSeason = int.Parse(numbers[0].Replace(".", "").Split('/')[1]); - - description = String.Join(" ", numbers, 1, numbers.Length - 1).Trim(); // Skip the first, concatenate the rest, clean up spaces and save it - } - else - throw new Exception(); // Switch to default parsing - } - catch // Default parsing - { - if (subtitle.Contains(".")) // skip the comment, keep the subtitle - description = String.Join(".", subtitle.Split('.'), 1, subtitle.Split('.').Length - 1).Trim(); // skip the first - else - description = subtitle.Trim(); // Clean up whitespaces and save it - } - } + video.ParentIndexNumber = data.ParentIndexNumber; } } + // If we don't have a ProductionYear try and get it from PremiereDate + if (video.PremiereDate.HasValue && !video.ProductionYear.HasValue) + { + video.ProductionYear = video.PremiereDate.Value.ToLocalTime().Year; + } + if (!video.LockedFields.Contains(MetadataFields.Overview)) { - if (!string.IsNullOrWhiteSpace(description)) + if (string.IsNullOrWhiteSpace(video.Overview) || isFullRefresh) { - video.Overview = description; + video.Overview = data.Overview; } } } @@ -709,56 +621,6 @@ namespace MediaBrowser.Providers.MediaInfo } } - private void ExtractTimestamp(Video video) - { - if (video.VideoType == VideoType.VideoFile) - { - if (string.Equals(video.Container, "mpeg2ts", StringComparison.OrdinalIgnoreCase) || - string.Equals(video.Container, "m2ts", StringComparison.OrdinalIgnoreCase) || - string.Equals(video.Container, "ts", StringComparison.OrdinalIgnoreCase)) - { - try - { - video.Timestamp = GetMpegTimestamp(video.Path); - - _logger.Debug("Video has {0} timestamp", video.Timestamp); - } - catch (Exception ex) - { - _logger.ErrorException("Error extracting timestamp info from {0}", ex, video.Path); - video.Timestamp = null; - } - } - } - } - - private TransportStreamTimestamp GetMpegTimestamp(string path) - { - var packetBuffer = new byte['Å']; - - using (var fs = _fileSystem.GetFileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read)) - { - fs.Read(packetBuffer, 0, packetBuffer.Length); - } - - if (packetBuffer[0] == 71) - { - return TransportStreamTimestamp.None; - } - - if ((packetBuffer[4] == 71) && (packetBuffer['Ä'] == 71)) - { - if ((packetBuffer[0] == 0) && (packetBuffer[1] == 0) && (packetBuffer[2] == 0) && (packetBuffer[3] == 0)) - { - return TransportStreamTimestamp.Zero; - } - - return TransportStreamTimestamp.Valid; - } - - return TransportStreamTimestamp.None; - } - private void FetchFromDvdLib(Video item, IIsoMount mount) { var path = mount == null ? item.Path : mount.MountedPath; diff --git a/MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs b/MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs index 7c32432251..bcea66662e 100644 --- a/MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs +++ b/MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs @@ -6,6 +6,7 @@ using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Drawing; using MediaBrowser.Model.Entities; using MediaBrowser.Model.IO; +using MediaBrowser.Model.Logging; using MediaBrowser.Model.MediaInfo; using System; using System.Collections.Generic; @@ -20,13 +21,15 @@ namespace MediaBrowser.Providers.MediaInfo private readonly IMediaEncoder _mediaEncoder; private readonly IServerConfigurationManager _config; private readonly ILibraryManager _libraryManager; + private readonly ILogger _logger; - public VideoImageProvider(IIsoManager isoManager, IMediaEncoder mediaEncoder, IServerConfigurationManager config, ILibraryManager libraryManager) + public VideoImageProvider(IIsoManager isoManager, IMediaEncoder mediaEncoder, IServerConfigurationManager config, ILibraryManager libraryManager, ILogger logger) { _isoManager = isoManager; _mediaEncoder = mediaEncoder; _config = config; _libraryManager = libraryManager; + _logger = logger; } /// <summary> @@ -74,6 +77,7 @@ namespace MediaBrowser.Providers.MediaInfo // Can't extract if we didn't find a video stream in the file if (!video.DefaultVideoStreamIndex.HasValue) { + _logger.Debug("Skipping image extraction due to missing DefaultVideoStreamIndex for {0}.", video.Path ?? string.Empty); return Task.FromResult(new DynamicImageResponse { HasImage = false }); } diff --git a/MediaBrowser.Providers/MediaInfo/whitelist.txt b/MediaBrowser.Providers/MediaInfo/whitelist.txt deleted file mode 100644 index 1fd3665512..0000000000 --- a/MediaBrowser.Providers/MediaInfo/whitelist.txt +++ /dev/null @@ -1 +0,0 @@ -AC/DC
\ No newline at end of file diff --git a/MediaBrowser.Providers/Movies/FanArtMovieUpdatesPostScanTask.cs b/MediaBrowser.Providers/Movies/FanArtMovieUpdatesPostScanTask.cs index 6e57ddb01c..f133f74db4 100644 --- a/MediaBrowser.Providers/Movies/FanArtMovieUpdatesPostScanTask.cs +++ b/MediaBrowser.Providers/Movies/FanArtMovieUpdatesPostScanTask.cs @@ -6,6 +6,7 @@ using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Logging; using MediaBrowser.Model.Serialization; using MediaBrowser.Providers.Music; +using MediaBrowser.Providers.TV; using System; using System.Collections.Generic; using System.Globalization; @@ -14,7 +15,6 @@ using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Providers.TV; namespace MediaBrowser.Providers.Movies { diff --git a/MediaBrowser.Providers/Movies/MovieMetadataService.cs b/MediaBrowser.Providers/Movies/MovieMetadataService.cs index 172ae6814c..f886deb007 100644 --- a/MediaBrowser.Providers/Movies/MovieMetadataService.cs +++ b/MediaBrowser.Providers/Movies/MovieMetadataService.cs @@ -36,10 +36,6 @@ namespace MediaBrowser.Providers.Movies protected override bool IsFullLocalMetadata(Movie item) { - if (string.IsNullOrWhiteSpace(item.Name)) - { - return false; - } if (string.IsNullOrWhiteSpace(item.Overview)) { return false; diff --git a/MediaBrowser.Providers/Music/ArtistMetadataService.cs b/MediaBrowser.Providers/Music/ArtistMetadataService.cs index 2497cc1ec7..7905293717 100644 --- a/MediaBrowser.Providers/Music/ArtistMetadataService.cs +++ b/MediaBrowser.Providers/Music/ArtistMetadataService.cs @@ -54,7 +54,7 @@ namespace MediaBrowser.Providers.Music var currentList = item.Genres.ToList(); item.Genres = taggedItems.SelectMany(i => i.Genres) - .Distinct(StringComparer.OrdinalIgnoreCase) + .DistinctNames() .ToList(); if (currentList.Count != item.Genres.Count || !currentList.OrderBy(i => i).SequenceEqual(item.Genres.OrderBy(i => i), StringComparer.OrdinalIgnoreCase)) diff --git a/MediaBrowser.Providers/TV/SeriesMetadataService.cs b/MediaBrowser.Providers/TV/SeriesMetadataService.cs index a5959f0b75..b0cd7382a1 100644 --- a/MediaBrowser.Providers/TV/SeriesMetadataService.cs +++ b/MediaBrowser.Providers/TV/SeriesMetadataService.cs @@ -77,10 +77,6 @@ namespace MediaBrowser.Providers.TV protected override bool IsFullLocalMetadata(Series item) { - if (string.IsNullOrWhiteSpace(item.Name)) - { - return false; - } if (string.IsNullOrWhiteSpace(item.Overview)) { return false; diff --git a/MediaBrowser.Providers/TV/TvdbSeriesProvider.cs b/MediaBrowser.Providers/TV/TvdbSeriesProvider.cs index c644da0b82..a31cc1e0c1 100644 --- a/MediaBrowser.Providers/TV/TvdbSeriesProvider.cs +++ b/MediaBrowser.Providers/TV/TvdbSeriesProvider.cs @@ -10,6 +10,7 @@ using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Entities; using MediaBrowser.Model.IO; using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Net; using MediaBrowser.Model.Providers; using System; using System.Collections.Generic; @@ -191,6 +192,27 @@ namespace MediaBrowser.Providers.TV /// <returns>Task.</returns> internal async Task DownloadSeriesZip(string seriesId, string seriesDataPath, long? lastTvDbUpdateTime, string preferredMetadataLanguage, CancellationToken cancellationToken) { + try + { + await DownloadSeriesZip(seriesId, seriesDataPath, lastTvDbUpdateTime, preferredMetadataLanguage, preferredMetadataLanguage, cancellationToken).ConfigureAwait(false); + return; + } + catch (HttpException ex) + { + if (!ex.StatusCode.HasValue || ex.StatusCode.Value != HttpStatusCode.NotFound) + { + throw; + } + } + + if (!string.Equals(preferredMetadataLanguage, "en", StringComparison.OrdinalIgnoreCase)) + { + await DownloadSeriesZip(seriesId, seriesDataPath, lastTvDbUpdateTime, "en", preferredMetadataLanguage, cancellationToken).ConfigureAwait(false); + } + } + + private async Task DownloadSeriesZip(string seriesId, string seriesDataPath, long? lastTvDbUpdateTime, string preferredMetadataLanguage, string saveAsMetadataLanguage, CancellationToken cancellationToken) + { var url = string.Format(SeriesGetZip, TVUtils.TvdbApiKey, seriesId, preferredMetadataLanguage); using (var zipStream = await _httpClient.Get(new HttpRequestOptions @@ -221,7 +243,15 @@ namespace MediaBrowser.Providers.TV await SanitizeXmlFile(file).ConfigureAwait(false); } - await ExtractEpisodes(seriesDataPath, Path.Combine(seriesDataPath, preferredMetadataLanguage + ".xml"), lastTvDbUpdateTime).ConfigureAwait(false); + var downloadLangaugeXmlFile = Path.Combine(seriesDataPath, preferredMetadataLanguage + ".xml"); + var saveAsLanguageXmlFile = Path.Combine(seriesDataPath, saveAsMetadataLanguage + ".xml"); + + if (!string.Equals(downloadLangaugeXmlFile, saveAsLanguageXmlFile, StringComparison.OrdinalIgnoreCase)) + { + File.Copy(downloadLangaugeXmlFile, saveAsLanguageXmlFile, true); + } + + await ExtractEpisodes(seriesDataPath, downloadLangaugeXmlFile, lastTvDbUpdateTime).ConfigureAwait(false); } public TvdbOptions GetTvDbOptions() |
