From b52e9091bbfe3294d92ae56b67a1bb2f0ebeb4c0 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Wed, 24 Feb 2016 14:29:49 -0500 Subject: improve support for embedded mp4 info --- .../Probing/ProbeResultNormalizer.cs | 49 +++++++++++++++------- 1 file changed, 34 insertions(+), 15 deletions(-) (limited to 'MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs') diff --git a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs index 7936a824a..fb0253f0b 100644 --- a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs +++ b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs @@ -57,7 +57,7 @@ namespace MediaBrowser.MediaEncoding.Probing } var tags = new Dictionary(StringComparer.OrdinalIgnoreCase); - var tagStreamType = isAudio ? "audio" : "video"; + var tagStreamType = isAudio ? "info" : "video"; if (data.streams != null) { @@ -81,12 +81,29 @@ namespace MediaBrowser.MediaEncoding.Probing } FetchGenres(info, tags); - var overview = FFProbeHelpers.GetDictionaryValue(tags, "description"); + var shortOverview = FFProbeHelpers.GetDictionaryValue(tags, "description"); + var overview = FFProbeHelpers.GetDictionaryValue(tags, "synopsis"); + + if (string.IsNullOrWhiteSpace(overview)) + { + overview = shortOverview; + shortOverview = null; + } + if (string.IsNullOrWhiteSpace(overview)) + { + overview = FFProbeHelpers.GetDictionaryValue(tags, "desc"); + } + if (!string.IsNullOrWhiteSpace(overview)) { info.Overview = overview; } + if (!string.IsNullOrWhiteSpace(shortOverview)) + { + info.ShortOverview = shortOverview; + } + var title = FFProbeHelpers.GetDictionaryValue(tags, "title"); if (!string.IsNullOrWhiteSpace(title)) { @@ -105,13 +122,15 @@ namespace MediaBrowser.MediaEncoding.Probing { SetAudioRuntimeTicks(data, info); - // tags are normally located under data.format, but we've seen some cases with ogg where they're part of the audio stream + // tags are normally located under data.format, but we've seen some cases with ogg where they're part of the info stream // so let's create a combined list of both SetAudioInfoFromTags(info, tags); } else { + FetchStudios(info, tags, "copyright"); + var iTunEXTC = FFProbeHelpers.GetDictionaryValue(tags, "iTunEXTC"); if (!string.IsNullOrWhiteSpace(iTunEXTC)) { @@ -124,13 +143,13 @@ namespace MediaBrowser.MediaEncoding.Probing info.OfficialRatingDescription = parts[3]; } } - + var itunesXml = FFProbeHelpers.GetDictionaryValue(tags, "iTunMOVI"); if (!string.IsNullOrWhiteSpace(itunesXml)) { FetchFromItunesInfo(itunesXml, info); } - + if (data.format != null && !string.IsNullOrEmpty(data.format.duration)) { info.RunTimeTicks = TimeSpan.FromSeconds(double.Parse(data.format.duration, _usCulture)).Ticks; @@ -157,7 +176,7 @@ namespace MediaBrowser.MediaEncoding.Probing /// /// Converts ffprobe stream info to our MediaStream class /// - /// if set to true [is audio]. + /// if set to true [is info]. /// The stream info. /// The format info. /// MediaStream. @@ -190,7 +209,7 @@ namespace MediaBrowser.MediaEncoding.Probing stream.Comment = GetDictionaryValue(streamInfo.tags, "comment"); } - if (string.Equals(streamInfo.codec_type, "audio", StringComparison.OrdinalIgnoreCase)) + if (string.Equals(streamInfo.codec_type, "info", StringComparison.OrdinalIgnoreCase)) { stream.Type = MediaStreamType.Audio; @@ -438,8 +457,8 @@ namespace MediaBrowser.MediaEncoding.Probing { if (result.streams != null) { - // Get the first audio stream - var stream = result.streams.FirstOrDefault(s => string.Equals(s.codec_type, "audio", StringComparison.OrdinalIgnoreCase)); + // Get the first info stream + var stream = result.streams.FirstOrDefault(s => string.Equals(s.codec_type, "info", StringComparison.OrdinalIgnoreCase)); if (stream != null) { @@ -703,10 +722,10 @@ namespace MediaBrowser.MediaEncoding.Probing /// /// Gets the studios from the tags collection /// - /// The audio. + /// The info. /// The tags. /// Name of the tag. - private void FetchStudios(Model.MediaInfo.MediaInfo audio, Dictionary tags, string tagName) + private void FetchStudios(MediaInfo info, Dictionary tags, string tagName) { var val = FFProbeHelpers.GetDictionaryValue(tags, tagName); @@ -717,19 +736,19 @@ namespace MediaBrowser.MediaEncoding.Probing foreach (var studio in studios) { // Sometimes the artist name is listed here, account for that - if (audio.Artists.Contains(studio, StringComparer.OrdinalIgnoreCase)) + if (info.Artists.Contains(studio, StringComparer.OrdinalIgnoreCase)) { continue; } - if (audio.AlbumArtists.Contains(studio, StringComparer.OrdinalIgnoreCase)) + if (info.AlbumArtists.Contains(studio, StringComparer.OrdinalIgnoreCase)) { continue; } - audio.Studios.Add(studio); + info.Studios.Add(studio); } - audio.Studios = audio.Studios + info.Studios = info.Studios .Where(i => !string.IsNullOrWhiteSpace(i)) .Distinct(StringComparer.OrdinalIgnoreCase) .ToList(); -- cgit v1.2.3 From 5ca2ae6395acc88d0f322a041afd9a25437938af Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Wed, 24 Feb 2016 15:20:22 -0500 Subject: support parsing itunes info --- .../Probing/ProbeResultNormalizer.cs | 211 +++++++++++++++++++++ 1 file changed, 211 insertions(+) (limited to 'MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs') diff --git a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs index fb0253f0b..bfc86b10e 100644 --- a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs +++ b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs @@ -7,7 +7,10 @@ using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; +using System.Text; +using System.Xml; using CommonIO; +using MediaBrowser.Controller.Entities; using MediaBrowser.Model.Logging; using MediaBrowser.Model.MediaInfo; @@ -170,7 +173,215 @@ namespace MediaBrowser.MediaEncoding.Probing private void FetchFromItunesInfo(string xml, MediaInfo info) { + // Make things simpler and strip out the dtd + xml = xml.Substring(xml.IndexOf("" + xml; + // \n\n\n\n\tcast\n\t\n\t\t\n\t\t\tname\n\t\t\tBlender Foundation\n\t\t\n\t\t\n\t\t\tname\n\t\t\tJanus Bager Kristensen\n\t\t\n\t\n\tdirectors\n\t\n\t\t\n\t\t\tname\n\t\t\tSacha Goedegebure\n\t\t\n\t\n\tstudio\n\tBlender Foundation\n\n\n + using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(xml))) + { + using (var streamReader = new StreamReader(stream)) + { + // Use XmlReader for best performance + using (var reader = XmlReader.Create(streamReader)) + { + reader.MoveToContent(); + + // Loop through each element + while (reader.Read()) + { + if (reader.NodeType == XmlNodeType.Element) + { + switch (reader.Name) + { + case "dict": + using (var subtree = reader.ReadSubtree()) + { + ReadFromDictNode(subtree, info); + } + break; + default: + reader.Skip(); + break; + } + } + } + } + } + } + } + + private void ReadFromDictNode(XmlReader reader, MediaInfo info) + { + reader.MoveToContent(); + + string currentKey = null; + List pairs = new List(); + + // Loop through each element + while (reader.Read()) + { + if (reader.NodeType == XmlNodeType.Element) + { + switch (reader.Name) + { + case "key": + if (!string.IsNullOrWhiteSpace(currentKey)) + { + ProcessPairs(currentKey, pairs, info); + } + currentKey = reader.ReadElementContentAsString(); + pairs = new List(); + break; + case "string": + var value = reader.ReadElementContentAsString(); + if (!string.IsNullOrWhiteSpace(value)) + { + pairs.Add(new NameValuePair + { + Name = value, + Value = value + }); + } + break; + case "array": + if (!string.IsNullOrWhiteSpace(currentKey)) + { + using (var subtree = reader.ReadSubtree()) + { + pairs.AddRange(ReadValueArray(subtree)); + } + } + break; + default: + reader.Skip(); + break; + } + } + } + } + + private List ReadValueArray(XmlReader reader) + { + reader.MoveToContent(); + + List pairs = new List(); + + // Loop through each element + while (reader.Read()) + { + if (reader.NodeType == XmlNodeType.Element) + { + switch (reader.Name) + { + case "dict": + using (var subtree = reader.ReadSubtree()) + { + var dict = GetNameValuePair(subtree); + if (dict != null) + { + pairs.Add(dict); + } + } + break; + default: + reader.Skip(); + break; + } + } + } + + return pairs; + } + + private void ProcessPairs(string key, List pairs, MediaInfo info) + { + if (string.Equals(key, "studio", StringComparison.OrdinalIgnoreCase)) + { + foreach (var pair in pairs) + { + info.Studios.Add(pair.Value); + } + + info.Studios = info.Studios + .Where(i => !string.IsNullOrWhiteSpace(i)) + .Distinct(StringComparer.OrdinalIgnoreCase) + .ToList(); + + } + else if (string.Equals(key, "screenwriters", StringComparison.OrdinalIgnoreCase)) + { + foreach (var pair in pairs) + { + info.People.Add(new BaseItemPerson + { + Name = pair.Value, + Type = PersonType.Writer + }); + } + } + else if (string.Equals(key, "producers", StringComparison.OrdinalIgnoreCase)) + { + foreach (var pair in pairs) + { + info.People.Add(new BaseItemPerson + { + Name = pair.Value, + Type = PersonType.Producer + }); + } + } + else if (string.Equals(key, "directors", StringComparison.OrdinalIgnoreCase)) + { + foreach (var pair in pairs) + { + info.People.Add(new BaseItemPerson + { + Name = pair.Value, + Type = PersonType.Director + }); + } + } + } + + private NameValuePair GetNameValuePair(XmlReader reader) + { + reader.MoveToContent(); + + string name = null; + string value = null; + + // Loop through each element + while (reader.Read()) + { + if (reader.NodeType == XmlNodeType.Element) + { + switch (reader.Name) + { + case "key": + name = reader.ReadElementContentAsString(); + break; + case "string": + value = reader.ReadElementContentAsString(); + break; + default: + reader.Skip(); + break; + } + } + } + + if (string.IsNullOrWhiteSpace(name) || + string.IsNullOrWhiteSpace(value)) + { + return null; + } + + return new NameValuePair + { + Name = name, + Value = value + }; } /// -- cgit v1.2.3 From d4dd1cbf7fdb5db561039a7cf1a4c4707f6273bc Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Thu, 25 Feb 2016 01:09:10 -0500 Subject: fix audio tracks --- MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs') diff --git a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs index bfc86b10e..57c2f75cc 100644 --- a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs +++ b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs @@ -60,7 +60,7 @@ namespace MediaBrowser.MediaEncoding.Probing } var tags = new Dictionary(StringComparer.OrdinalIgnoreCase); - var tagStreamType = isAudio ? "info" : "video"; + var tagStreamType = isAudio ? "audio" : "video"; if (data.streams != null) { @@ -420,7 +420,7 @@ namespace MediaBrowser.MediaEncoding.Probing stream.Comment = GetDictionaryValue(streamInfo.tags, "comment"); } - if (string.Equals(streamInfo.codec_type, "info", StringComparison.OrdinalIgnoreCase)) + if (string.Equals(streamInfo.codec_type, "audio", StringComparison.OrdinalIgnoreCase)) { stream.Type = MediaStreamType.Audio; @@ -664,12 +664,12 @@ namespace MediaBrowser.MediaEncoding.Probing return null; } - private void SetAudioRuntimeTicks(InternalMediaInfoResult result, Model.MediaInfo.MediaInfo data) + private void SetAudioRuntimeTicks(InternalMediaInfoResult result, MediaInfo data) { if (result.streams != null) { // Get the first info stream - var stream = result.streams.FirstOrDefault(s => string.Equals(s.codec_type, "info", StringComparison.OrdinalIgnoreCase)); + var stream = result.streams.FirstOrDefault(s => string.Equals(s.codec_type, "audio", StringComparison.OrdinalIgnoreCase)); if (stream != null) { -- cgit v1.2.3