aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.Providers
diff options
context:
space:
mode:
authorLuke Pulverenti <luke.pulverenti@gmail.com>2015-04-04 15:35:29 -0400
committerLuke Pulverenti <luke.pulverenti@gmail.com>2015-04-04 15:35:29 -0400
commit2b7a80cfb5b9212260734c095a5b3439af7d64e2 (patch)
treeab746cd05a2244b4c8c8432a30090b85c9d4d986 /MediaBrowser.Providers
parent8c61abf6d23510da8eaddf3894f9e14f88dc5f22 (diff)
improve direct play of live streams
Diffstat (limited to 'MediaBrowser.Providers')
-rw-r--r--MediaBrowser.Providers/MediaBrowser.Providers.csproj5
-rw-r--r--MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs342
-rw-r--r--MediaBrowser.Providers/MediaInfo/FFProbeHelpers.cs118
-rw-r--r--MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs297
4 files changed, 102 insertions, 660 deletions
diff --git a/MediaBrowser.Providers/MediaBrowser.Providers.csproj b/MediaBrowser.Providers/MediaBrowser.Providers.csproj
index 3b5103f209..b58c6648ab 100644
--- a/MediaBrowser.Providers/MediaBrowser.Providers.csproj
+++ b/MediaBrowser.Providers/MediaBrowser.Providers.csproj
@@ -102,7 +102,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 +197,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>
diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs b/MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs
index ea191dd08f..b1bed73109 100644
--- a/MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs
+++ b/MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs
@@ -1,5 +1,4 @@
using MediaBrowser.Common.Configuration;
-using MediaBrowser.Model.Extensions;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Library;
@@ -8,8 +7,6 @@ using MediaBrowser.Controller.Persistence;
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 +46,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.Entities.MediaInfo> GetMediaInfo(BaseItem item, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
@@ -71,7 +64,7 @@ namespace MediaBrowser.Providers.MediaInfo
try
{
- return _json.DeserializeFromFile<InternalMediaInfoResult>(cachePath);
+ return _json.DeserializeFromFile<Model.Entities.MediaInfo>(cachePath);
}
catch (FileNotFoundException)
{
@@ -83,7 +76,7 @@ namespace MediaBrowser.Providers.MediaInfo
var inputPath = new[] { item.Path };
- var result = await _mediaEncoder.GetMediaInfo(inputPath, MediaProtocol.File, false, cancellationToken).ConfigureAwait(false);
+ var result = await _mediaEncoder.GetMediaInfo(inputPath, item.Path, MediaProtocol.File, true, false, cancellationToken).ConfigureAwait(false);
Directory.CreateDirectory(Path.GetDirectoryName(cachePath));
_json.SerializeToFile(result, cachePath);
@@ -96,61 +89,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.Entities.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));
+ audio.RunTimeTicks = mediaInfo.RunTimeTicks;
+ audio.Size = mediaInfo.Size;
- if (stream != null)
- {
- // Get duration from stream properties
- var duration = stream.duration;
+ var extension = (Path.GetExtension(audio.Path) ?? string.Empty).TrimStart('.');
+ audio.Container = extension;
- // 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;
-
- if (!string.IsNullOrEmpty(data.format.size))
- {
- audio.Size = long.Parse(data.format.size, _usCulture);
- }
- else
- {
- audio.Size = null;
- }
-
- if (data.format.tags != null)
- {
- FetchDataFromTags(audio, data.format.tags);
- }
- }
+ FetchDataFromTags(audio, mediaInfo);
return _itemRepo.SaveMediaStreams(audio.Id, mediaStreams, cancellationToken);
}
@@ -159,92 +114,36 @@ 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.Entities.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 });
- }
- }
- }
-
- 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();
+ Name = person.Name,
+ Type = person.Type,
+ Role = person.Role
+ });
}
- 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.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 +153,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..cec66f3c14 100644
--- a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs
+++ b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs
@@ -13,7 +13,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 +115,6 @@ namespace MediaBrowser.Providers.MediaInfo
cancellationToken.ThrowIfCancellationRequested();
- FFProbeHelpers.NormalizeFFProbeResult(result);
-
- cancellationToken.ThrowIfCancellationRequested();
-
await Fetch(item, cancellationToken, result, isoMount, blurayDiscInfo, options).ConfigureAwait(false);
}
@@ -136,7 +131,7 @@ namespace MediaBrowser.Providers.MediaInfo
private const string SchemaVersion = "1";
- private async Task<InternalMediaInfoResult> GetMediaInfo(Video item,
+ private async Task<Model.Entities.MediaInfo> GetMediaInfo(Video item,
IIsoMount isoMount,
CancellationToken cancellationToken)
{
@@ -149,7 +144,7 @@ namespace MediaBrowser.Providers.MediaInfo
try
{
- return _json.DeserializeFromFile<InternalMediaInfoResult>(cachePath);
+ return _json.DeserializeFromFile<Model.Entities.MediaInfo>(cachePath);
}
catch (FileNotFoundException)
{
@@ -165,7 +160,7 @@ namespace MediaBrowser.Providers.MediaInfo
var inputPath = MediaEncoderHelpers.GetInputArgument(item.Path, protocol, isoMount, item.PlayableStreamFileNames);
- var result = await _mediaEncoder.GetMediaInfo(inputPath, protocol, false, cancellationToken).ConfigureAwait(false);
+ var result = await _mediaEncoder.GetMediaInfo(inputPath, item.Path, protocol, false, true, cancellationToken).ConfigureAwait(false);
Directory.CreateDirectory(Path.GetDirectoryName(cachePath));
_json.SerializeToFile(result, cachePath);
@@ -175,52 +170,37 @@ namespace MediaBrowser.Providers.MediaInfo
protected async Task Fetch(Video video,
CancellationToken cancellationToken,
- InternalMediaInfoResult data,
+ Model.Entities.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 +208,7 @@ namespace MediaBrowser.Providers.MediaInfo
await AddExternalSubtitles(video, mediaStreams, options, cancellationToken).ConfigureAwait(false);
- FetchWtvInfo(video, data);
+ FetchEmbeddedInfo(video, mediaInfo);
video.IsHD = mediaStreams.Any(i => i.Type == MediaStreamType.Video && i.Width.HasValue && i.Width.Value >= 1270);
@@ -238,9 +218,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 +261,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 +280,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 +348,79 @@ 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.Entities.MediaInfo data)
{
- if (data.format == null || data.format.tags == null)
- {
- return;
- }
-
- if (!video.LockedFields.Contains(MetadataFields.Genres))
- {
- var genres = FFProbeHelpers.GetDictionaryValue(data.format.tags, "WM/Genre");
-
- if (!string.IsNullOrWhiteSpace(genres))
- {
- //genres = FFProbeHelpers.GetDictionaryValue(data.format.tags, "genre");
- }
-
- if (!string.IsNullOrWhiteSpace(genres))
- {
- video.Genres = genres.Split(new[] { ';', '/', ',' }, StringSplitOptions.RemoveEmptyEntries)
- .Where(i => !string.IsNullOrWhiteSpace(i))
- .Select(i => i.Trim())
- .ToList();
- }
- }
-
if (!video.LockedFields.Contains(MetadataFields.OfficialRating))
{
- var officialRating = FFProbeHelpers.GetDictionaryValue(data.format.tags, "WM/ParentalRating");
-
- if (!string.IsNullOrWhiteSpace(officialRating))
+ if (!string.IsNullOrWhiteSpace(data.OfficialRating))
{
- video.OfficialRating = officialRating;
+ video.OfficialRating = data.OfficialRating;
}
}
if (!video.LockedFields.Contains(MetadataFields.Cast))
{
- var people = FFProbeHelpers.GetDictionaryValue(data.format.tags, "WM/MediaCredits");
+ video.People.Clear();
- if (!string.IsNullOrEmpty(people))
+ foreach (var person in data.People)
{
- video.People = people.Split(new[] { ';', '/' }, StringSplitOptions.RemoveEmptyEntries)
- .Where(i => !string.IsNullOrWhiteSpace(i))
- .Select(i => new PersonInfo { Name = i.Trim(), Type = PersonType.Actor })
- .ToList();
+ video.AddPerson(new PersonInfo
+ {
+ Name = person.Name,
+ Type = person.Type,
+ Role = person.Role
+ });
}
}
- var year = FFProbeHelpers.GetDictionaryValue(data.format.tags, "WM/OriginalReleaseTime");
- if (!string.IsNullOrWhiteSpace(year))
+ if (!video.LockedFields.Contains(MetadataFields.Genres))
{
- int val;
+ video.Genres.Clear();
- if (int.TryParse(year, NumberStyles.Integer, _usCulture, out val))
+ foreach (var genre in data.Genres)
{
- video.ProductionYear = val;
+ video.AddGenre(genre);
}
}
- var premiereDateString = FFProbeHelpers.GetDictionaryValue(data.format.tags, "WM/MediaOriginalBroadcastDateTime");
- if (!string.IsNullOrWhiteSpace(premiereDateString))
+ if (!video.LockedFields.Contains(MetadataFields.Studios))
{
- DateTime val;
+ video.Studios.Clear();
- // 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))
+ foreach (var studio in data.Studios)
{
- video.PremiereDate = val.ToUniversalTime();
+ video.AddStudio(studio);
}
}
- var description = FFProbeHelpers.GetDictionaryValue(data.format.tags, "WM/SubTitleDescription");
-
- var episode = video as Episode;
- if (episode != null)
+ if (data.ProductionYear.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
- {
- 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]);
+ video.ProductionYear = data.ProductionYear;
+ }
+ if (data.PremiereDate.HasValue)
+ {
+ video.PremiereDate = data.PremiereDate;
+ }
+ if (data.IndexNumber.HasValue)
+ {
+ video.IndexNumber = data.IndexNumber;
+ }
+ if (data.ParentIndexNumber.HasValue)
+ {
+ video.ParentIndexNumber = data.ParentIndexNumber;
+ }
- 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
- }
- }
- }
+ // 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(data.Overview))
{
- video.Overview = description;
+ video.Overview = data.Overview;
}
}
}
@@ -709,56 +588,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;