Exemple #1
0
        /// <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>
        /// Normalizes the FF probe result.
        /// </summary>
        /// <param name="result">The result.</param>
        public static void NormalizeFFProbeResult(InternalMediaInfoResult result)
        {
            if (result == null)
            {
                throw new ArgumentNullException(nameof(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);
                    }
                }
            }
        }
Exemple #3
0
        private void SetAudioRuntimeTicks(InternalMediaInfoResult result, Model.MediaInfo.MediaInfo data)
        {
            if (result.streams != null)
            {
                // Get the first audio stream
                var stream = result.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 = result.format.duration;
                    }

                    // If we got something, parse it
                    if (!string.IsNullOrEmpty(duration))
                    {
                        data.RunTimeTicks = TimeSpan.FromSeconds(double.Parse(duration, _usCulture)).Ticks;
                    }
                }
            }
        }
Exemple #4
0
 private void SetSize(InternalMediaInfoResult data, Model.MediaInfo.MediaInfo info)
 {
     if (data.format != null)
     {
         if (!string.IsNullOrEmpty(data.format.size))
         {
             info.Size = long.Parse(data.format.size, _usCulture);
         }
         else
         {
             info.Size = null;
         }
     }
 }
        private const int MaxSubtitleDescriptionExtractionLength = 100; // When extracting subtitles, the maximum length to consider (to avoid invalid filenames)

        private void FetchWtvInfo(Model.MediaInfo.MediaInfo video, InternalMediaInfoResult data)
        {
            if (data.format == null || data.format.tags == null)
            {
                return;
            }

            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();
            }

            var officialRating = FFProbeHelpers.GetDictionaryValue(data.format.tags, "WM/ParentalRating");

            if (!string.IsNullOrWhiteSpace(officialRating))
            {
                video.OfficialRating = officialRating;
            }

            var people = FFProbeHelpers.GetDictionaryValue(data.format.tags, "WM/MediaCredits");

            if (!string.IsNullOrEmpty(people))
            {
                video.People = people.Split(new[] { ';', '/' }, StringSplitOptions.RemoveEmptyEntries)
                    .Where(i => !string.IsNullOrWhiteSpace(i))
                    .Select(i => new BaseItemPerson { Name = i.Trim(), Type = PersonType.Actor })
                    .ToList();
            }

            var year = FFProbeHelpers.GetDictionaryValue(data.format.tags, "WM/OriginalReleaseTime");
            if (!string.IsNullOrWhiteSpace(year))
            {
                int val;

                if (int.TryParse(year, NumberStyles.Integer, _usCulture, out val))
                {
                    video.ProductionYear = val;
                }
            }

            var premiereDateString = FFProbeHelpers.GetDictionaryValue(data.format.tags, "WM/MediaOriginalBroadcastDateTime");
            if (!string.IsNullOrWhiteSpace(premiereDateString))
            {
                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))
                {
                    video.PremiereDate = val.ToUniversalTime();
                }
            }

            var description = FFProbeHelpers.GetDictionaryValue(data.format.tags, "WM/SubTitleDescription");

            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(' ');
                            video.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
                    }
                }
            }

            if (!string.IsNullOrWhiteSpace(description))
            {
                video.Overview = description;
            }
        }
 private void SetSize(InternalMediaInfoResult data, Model.MediaInfo.MediaInfo info)
 {
     if (data.format != null)
     {
         if (!string.IsNullOrEmpty(data.format.size))
         {
             info.Size = long.Parse(data.format.size, _usCulture);
         }
         else
         {
             info.Size = null;
         }
     }
 }
        private void SetAudioRuntimeTicks(InternalMediaInfoResult result, Model.MediaInfo.MediaInfo data)
        {
            if (result.streams != null)
            {
                // Get the first audio stream
                var stream = result.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 = result.format.duration;
                    }

                    // If we got something, parse it
                    if (!string.IsNullOrEmpty(duration))
                    {
                        data.RunTimeTicks = TimeSpan.FromSeconds(double.Parse(duration, _usCulture)).Ticks;
                    }
                }
            }
        }
        public MediaInfo GetMediaInfo(InternalMediaInfoResult data, VideoType videoType, bool isAudio, string path, MediaProtocol protocol)
        {
            var info = new Model.MediaInfo.MediaInfo
            {
                Path = path,
                Protocol = protocol
            };

            FFProbeHelpers.NormalizeFFProbeResult(data);
            SetSize(data, info);

            var internalStreams = data.streams ?? new MediaStreamInfo[] { };

            info.MediaStreams = internalStreams.Select(s => GetMediaStream(isAudio, s, data.format))
                .Where(i => i != null)
                .ToList();

            if (data.format != null)
            {
                info.Container = data.format.format_name;

                if (!string.IsNullOrEmpty(data.format.bit_rate))
                {
                    int value;
                    if (int.TryParse(data.format.bit_rate, NumberStyles.Any, _usCulture, out value))
                    {
                        info.Bitrate = value;
                    }
                }
            }

            if (isAudio)
            {
                SetAudioRuntimeTicks(data, info);

                var tags = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);

                // tags are normally located under data.format, but we've seen some cases with ogg where they're part of the audio stream
                // so let's create a combined list of both

                if (data.streams != null)
                {
                    var audioStream = data.streams.FirstOrDefault(i => string.Equals(i.codec_type, "audio", StringComparison.OrdinalIgnoreCase));

                    if (audioStream != null && audioStream.tags != null)
                    {
                        foreach (var pair in audioStream.tags)
                        {
                            tags[pair.Key] = pair.Value;
                        }
                    }
                }

                if (data.format != null && data.format.tags != null)
                {
                    foreach (var pair in data.format.tags)
                    {
                        tags[pair.Key] = pair.Value;
                    }
                }

                SetAudioInfoFromTags(info, tags);
            }
            else
            {
                if (data.format != null && !string.IsNullOrEmpty(data.format.duration))
                {
                    info.RunTimeTicks = TimeSpan.FromSeconds(double.Parse(data.format.duration, _usCulture)).Ticks;
                }

                FetchWtvInfo(info, data);

                if (data.Chapters != null)
                {
                    info.Chapters = data.Chapters.Select(GetChapterInfo).ToList();
                }

                ExtractTimestamp(info);
            }

            return info;
        }
Exemple #9
0
        public MediaInfo GetMediaInfo(InternalMediaInfoResult data, VideoType videoType, bool isAudio, string path, MediaProtocol protocol)
        {
            var info = new MediaInfo
            {
                Path     = path,
                Protocol = protocol
            };

            FFProbeHelpers.NormalizeFFProbeResult(data);
            SetSize(data, info);

            var internalStreams = data.streams ?? new MediaStreamInfo[] { };

            info.MediaStreams = internalStreams.Select(s => GetMediaStream(isAudio, s, data.format))
                                .Where(i => i != null)
                                .ToList();

            if (data.format != null)
            {
                info.Container = data.format.format_name;

                if (!string.IsNullOrEmpty(data.format.bit_rate))
                {
                    int value;
                    if (int.TryParse(data.format.bit_rate, NumberStyles.Any, _usCulture, out value))
                    {
                        info.Bitrate = value;
                    }
                }
            }

            var tags          = new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase);
            var tagStreamType = isAudio ? "audio" : "video";

            if (data.streams != null)
            {
                var tagStream = data.streams.FirstOrDefault(i => string.Equals(i.codec_type, tagStreamType, StringComparison.OrdinalIgnoreCase));

                if (tagStream != null && tagStream.tags != null)
                {
                    foreach (var pair in tagStream.tags)
                    {
                        tags[pair.Key] = pair.Value;
                    }
                }
            }

            if (data.format != null && data.format.tags != null)
            {
                foreach (var pair in data.format.tags)
                {
                    tags[pair.Key] = pair.Value;
                }
            }

            FetchGenres(info, tags);
            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))
            {
                info.Name = title;
            }

            info.ProductionYear = FFProbeHelpers.GetDictionaryNumericValue(tags, "date");

            // Several different forms of retaildate
            info.PremiereDate = FFProbeHelpers.GetDictionaryDateTime(tags, "retaildate") ??
                                FFProbeHelpers.GetDictionaryDateTime(tags, "retail date") ??
                                FFProbeHelpers.GetDictionaryDateTime(tags, "retail_date") ??
                                FFProbeHelpers.GetDictionaryDateTime(tags, "date");

            if (isAudio)
            {
                SetAudioRuntimeTicks(data, info);

                // 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))
                {
                    var parts = iTunEXTC.Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
                    // Example
                    // mpaa|G|100|For crude humor
                    if (parts.Length > 1)
                    {
                        info.OfficialRating = parts[1];

                        if (parts.Length > 3)
                        {
                            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;
                }

                FetchWtvInfo(info, data);

                if (data.Chapters != null)
                {
                    info.Chapters = data.Chapters.Select(GetChapterInfo).ToList();
                }

                ExtractTimestamp(info);
            }

            return(info);
        }
Exemple #10
0
        private const int MaxSubtitleDescriptionExtractionLength = 100; // When extracting subtitles, the maximum length to consider (to avoid invalid filenames)

        private void FetchWtvInfo(MediaInfo video, InternalMediaInfoResult data)
        {
            if (data.format == null || data.format.tags == null)
            {
                return;
            }

            var genres = FFProbeHelpers.GetDictionaryValue(data.format.tags, "WM/Genre");

            if (!string.IsNullOrWhiteSpace(genres))
            {
                var genreList = genres.Split(new[] { ';', '/', ',' }, StringSplitOptions.RemoveEmptyEntries)
                                .Where(i => !string.IsNullOrWhiteSpace(i))
                                .Select(i => i.Trim())
                                .ToList();

                // If this is empty then don't overwrite genres that might have been fetched earlier
                if (genreList.Count > 0)
                {
                    video.Genres = genreList;
                }
            }

            var officialRating = FFProbeHelpers.GetDictionaryValue(data.format.tags, "WM/ParentalRating");

            if (!string.IsNullOrWhiteSpace(officialRating))
            {
                video.OfficialRating = officialRating;
            }

            var people = FFProbeHelpers.GetDictionaryValue(data.format.tags, "WM/MediaCredits");

            if (!string.IsNullOrEmpty(people))
            {
                video.People = people.Split(new[] { ';', '/' }, StringSplitOptions.RemoveEmptyEntries)
                               .Where(i => !string.IsNullOrWhiteSpace(i))
                               .Select(i => new BaseItemPerson {
                    Name = i.Trim(), Type = PersonType.Actor
                })
                               .ToList();
            }

            var year = FFProbeHelpers.GetDictionaryValue(data.format.tags, "WM/OriginalReleaseTime");

            if (!string.IsNullOrWhiteSpace(year))
            {
                int val;

                if (int.TryParse(year, NumberStyles.Integer, _usCulture, out val))
                {
                    video.ProductionYear = val;
                }
            }

            var premiereDateString = FFProbeHelpers.GetDictionaryValue(data.format.tags, "WM/MediaOriginalBroadcastDateTime");

            if (!string.IsNullOrWhiteSpace(premiereDateString))
            {
                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))
                {
                    video.PremiereDate = val.ToUniversalTime();
                }
            }

            var description = FFProbeHelpers.GetDictionaryValue(data.format.tags, "WM/SubTitleDescription");

            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(' ');
                            video.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
                        }
                    }
                }
            }

            if (!string.IsNullOrWhiteSpace(description))
            {
                video.Overview = description;
            }
        }
Exemple #11
0
        public Model.MediaInfo.MediaInfo GetMediaInfo(InternalMediaInfoResult data, VideoType videoType, bool isAudio, string path, MediaProtocol protocol)
        {
            var info = new Model.MediaInfo.MediaInfo
            {
                Path     = path,
                Protocol = protocol
            };

            FFProbeHelpers.NormalizeFFProbeResult(data);
            SetSize(data, info);

            var internalStreams = data.streams ?? new MediaStreamInfo[] { };

            info.MediaStreams = internalStreams.Select(s => GetMediaStream(s, data.format))
                                .Where(i => i != null)
                                .ToList();

            if (data.format != null)
            {
                info.Container = data.format.format_name;

                if (!string.IsNullOrEmpty(data.format.bit_rate))
                {
                    info.Bitrate = int.Parse(data.format.bit_rate, _usCulture);
                }
            }

            if (isAudio)
            {
                SetAudioRuntimeTicks(data, info);

                if (data.format != null && data.format.tags != null)
                {
                    SetAudioInfoFromTags(info, data.format.tags);
                }
            }
            else
            {
                if (data.format != null && !string.IsNullOrEmpty(data.format.duration))
                {
                    info.RunTimeTicks = TimeSpan.FromSeconds(double.Parse(data.format.duration, _usCulture)).Ticks;
                }

                FetchWtvInfo(info, data);

                if (data.Chapters != null)
                {
                    info.Chapters = data.Chapters.Select(GetChapterInfo).ToList();
                }

                ExtractTimestamp(info);

                var videoStream = info.MediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Video);

                if (videoStream != null && videoType == VideoType.VideoFile)
                {
                    UpdateFromMediaInfo(info, videoStream);
                }
            }

            return(info);
        }
Exemple #12
0
        public MediaInfo GetMediaInfo(InternalMediaInfoResult data, VideoType videoType, bool isAudio, string path, MediaProtocol protocol)
        {
            var info = new MediaInfo
            {
                Path = path,
                Protocol = protocol
            };

            FFProbeHelpers.NormalizeFFProbeResult(data);
            SetSize(data, info);

            var internalStreams = data.streams ?? new MediaStreamInfo[] { };

            info.MediaStreams = internalStreams.Select(s => GetMediaStream(isAudio, s, data.format))
                .Where(i => i != null)
                .ToList();

            if (data.format != null)
            {
                info.Container = data.format.format_name;

                if (!string.IsNullOrEmpty(data.format.bit_rate))
                {
                    int value;
                    if (int.TryParse(data.format.bit_rate, NumberStyles.Any, _usCulture, out value))
                    {
                        info.Bitrate = value;
                    }
                }
            }

            var tags = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
            var tagStreamType = isAudio ? "audio" : "video";

            if (data.streams != null)
            {
                var tagStream = data.streams.FirstOrDefault(i => string.Equals(i.codec_type, tagStreamType, StringComparison.OrdinalIgnoreCase));

                if (tagStream != null && tagStream.tags != null)
                {
                    foreach (var pair in tagStream.tags)
                    {
                        tags[pair.Key] = pair.Value;
                    }
                }
            }

            if (data.format != null && data.format.tags != null)
            {
                foreach (var pair in data.format.tags)
                {
                    tags[pair.Key] = pair.Value;
                }
            }

            FetchGenres(info, tags);
            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))
            {
                info.Name = title;
            }

            info.ProductionYear = FFProbeHelpers.GetDictionaryNumericValue(tags, "date");

            // Several different forms of retaildate
            info.PremiereDate = FFProbeHelpers.GetDictionaryDateTime(tags, "retaildate") ??
                FFProbeHelpers.GetDictionaryDateTime(tags, "retail date") ??
                FFProbeHelpers.GetDictionaryDateTime(tags, "retail_date") ??
                FFProbeHelpers.GetDictionaryDateTime(tags, "date");

            if (isAudio)
            {
                SetAudioRuntimeTicks(data, info);

                // 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))
                {
                    var parts = iTunEXTC.Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
                    // Example 
                    // mpaa|G|100|For crude humor
                    if (parts.Length > 1)
                    {
                        info.OfficialRating = parts[1];

                        if (parts.Length > 3)
                        {
                            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;
                }

                FetchWtvInfo(info, data);

                if (data.Chapters != null)
                {
                    info.Chapters = data.Chapters.Select(GetChapterInfo).ToList();
                }

                ExtractTimestamp(info);

                var stereoMode = GetDictionaryValue(tags, "stereo_mode");
                if (string.Equals(stereoMode, "left_right", StringComparison.OrdinalIgnoreCase))
                {
                    info.Video3DFormat = Video3DFormat.FullSideBySide;
                }
            }

            return info;
        }
Exemple #13
0
        public Model.MediaInfo.MediaInfo GetMediaInfo(InternalMediaInfoResult data, VideoType videoType, bool isAudio, string path, MediaProtocol protocol)
        {
            var info = new Model.MediaInfo.MediaInfo
            {
                Path     = path,
                Protocol = protocol
            };

            FFProbeHelpers.NormalizeFFProbeResult(data);
            SetSize(data, info);

            var internalStreams = data.streams ?? new MediaStreamInfo[] { };

            info.MediaStreams = internalStreams.Select(s => GetMediaStream(isAudio, s, data.format))
                                .Where(i => i != null)
                                .ToList();

            if (data.format != null)
            {
                info.Container = data.format.format_name;

                if (!string.IsNullOrEmpty(data.format.bit_rate))
                {
                    info.Bitrate = int.Parse(data.format.bit_rate, _usCulture);
                }
            }

            if (isAudio)
            {
                SetAudioRuntimeTicks(data, info);

                var tags = new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase);

                // tags are normally located under data.format, but we've seen some cases with ogg where they're part of the audio stream
                // so let's create a combined list of both

                if (data.streams != null)
                {
                    var audioStream = data.streams.FirstOrDefault(i => string.Equals(i.codec_type, "audio", StringComparison.OrdinalIgnoreCase));

                    if (audioStream != null && audioStream.tags != null)
                    {
                        foreach (var pair in audioStream.tags)
                        {
                            tags[pair.Key] = pair.Value;
                        }
                    }
                }

                if (data.format != null && data.format.tags != null)
                {
                    foreach (var pair in data.format.tags)
                    {
                        tags[pair.Key] = pair.Value;
                    }
                }

                SetAudioInfoFromTags(info, tags);
            }
            else
            {
                if (data.format != null && !string.IsNullOrEmpty(data.format.duration))
                {
                    info.RunTimeTicks = TimeSpan.FromSeconds(double.Parse(data.format.duration, _usCulture)).Ticks;
                }

                FetchWtvInfo(info, data);

                if (data.Chapters != null)
                {
                    info.Chapters = data.Chapters.Select(GetChapterInfo).ToList();
                }

                ExtractTimestamp(info);

                var videoStream = info.MediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Video);

                if (videoStream != null && videoType == VideoType.VideoFile)
                {
                    UpdateFromMediaInfo(info, videoStream);
                }
            }

            return(info);
        }