예제 #1
0
        public void CustomFormatMappingTest()
        {
            var customorder = new Order
            {
                BurnInLogo        = false,
                BurnInSubtitles   = false,
                DestinationFormat = StateFormat.h264_od_standard,
                DestinationPath   = "\\\\ondnas01\\MediaCache\\Test\\WfsJob\\Marvin",
                DueDate           = DateTime.Now,
                FilePath          = "\\\\ondnas01\\MediaCache\\Test\\detkommernaermere.dif",
                LogoPath          = "",
                Priority          = Priority.medium,
                SubtitlesPath     = "",
                CallbackUrl       = "http://some/system",
            };

            _videoMediaFileMetadata = new MediaInfoResult {
                Video = new Video {
                    CodecId = "custom42", DisplayAspectRatioRawValue = 16f / 9f, Width = 640
                }
            };
            mockMediaInfoFacade.Setup(m => m.Read(It.IsAny <string>()))
            .Returns(_videoMediaFileMetadata);
            customorder.Validate(mockMediaInfoFacade.Object, mockTimeProvider.Object);
            var source = MappingHelper.GetSource(customorder);

            Assert.That(source.Format, Is.EqualTo(StateFormat.custom));
            Assert.That(source.CustomFormat, Is.EqualTo("custom42"));
        }
예제 #2
0
        public static MediaInfoResult GetMediaInfo(string fileName, bool forceRefresh)
        {
            MediaInfoResult vidInfo = new MediaInfoResult();

            MediaInfoReader.ReadMediaInfo(fileName, forceRefresh, ref vidInfo);
            return(vidInfo);
        }
예제 #3
0
        public void NullResponseFromMediaInfoThrowsCorrectOrderException()
        {
            _videoMediaFileMetadata = null;
            mockMediaInfoFacade.Setup(m => m.Read(It.Is <string>(x => !x.EndsWith("wav")))).Returns(_videoMediaFileMetadata);
            var ex = Assert.Throws <OrderException>(() => sut.Validate(mockMediaInfoFacade.Object, mockTimeProvider.Object));

            Assert.That(ex.Message, Is.EqualTo("File is not a valid media file. Source file must be dv5p or xd5c for video or wma, mpeg or pcm for audio format or wav for alternate audio."));
        }
예제 #4
0
        /// <summary>
        /// Fetches the WTV info.
        /// </summary>
        /// <param name="video">The video.</param>
        /// <param name="data">The data.</param>
        private void FetchWtvInfo(Video video, MediaInfoResult data)
        {
            if (data.format == null || data.format.tags == null)
            {
                return;
            }

            if (!video.LockedFields.Contains(MetadataFields.Genres))
            {
                var genres = GetDictionaryValue(data.format.tags, "genre");

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

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

            if (!string.IsNullOrWhiteSpace(overview))
            {
                video.Overview = overview;
            }

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

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

            var people = 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 PersonInfo {
                    Name = i.Trim(), Type = PersonType.Actor
                })
                               .ToList();
            }

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

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

                if (int.TryParse(year, NumberStyles.Integer, UsCulture, out val))
                {
                    video.ProductionYear = val;
                }
            }
        }
예제 #5
0
 /// <summary>
 /// Get all the hash info and video/audio info for a video file
 /// </summary>
 /// <param name="fileName"></param>
 /// <param name="hashInfo"></param>
 /// <param name="vidInfo"></param>
 public static void GetVideoInfo(string fileName, ref Hashes hashInfo, ref MediaInfoResult vidInfo, bool forceRefresh)
 {
     hashInfo = Hasher.CalculateHashes(fileName, null);
     if (vidInfo == null)
     {
         vidInfo = new MediaInfoResult();
     }
     MediaInfoReader.ReadMediaInfo(fileName, forceRefresh, ref vidInfo);
 }
예제 #6
0
        /// <summary>
        /// Adds the chapters.
        /// </summary>
        /// <param name="result">The result.</param>
        /// <param name="standardError">The standard error.</param>
        private void AddChapters(MediaInfoResult result, string standardError)
        {
            var lines = standardError.Split('\n').Select(l => l.TrimStart());

            var chapters = new List <ChapterInfo>();

            ChapterInfo lastChapter = null;

            foreach (var line in lines)
            {
                if (line.StartsWith("Chapter", StringComparison.OrdinalIgnoreCase))
                {
                    // Example:
                    // Chapter #0.2: start 400.534, end 4565.435
                    const string srch  = "start ";
                    var          start = line.IndexOf(srch, StringComparison.OrdinalIgnoreCase);

                    if (start == -1)
                    {
                        continue;
                    }

                    var subString = line.Substring(start + srch.Length);
                    subString = subString.Substring(0, subString.IndexOf(','));

                    double seconds;

                    if (double.TryParse(subString, NumberStyles.Any, UsCulture, out seconds))
                    {
                        lastChapter = new ChapterInfo
                        {
                            StartPositionTicks = TimeSpan.FromSeconds(seconds).Ticks
                        };

                        chapters.Add(lastChapter);
                    }
                }

                else if (line.StartsWith("title", StringComparison.OrdinalIgnoreCase))
                {
                    if (lastChapter != null && string.IsNullOrEmpty(lastChapter.Name))
                    {
                        var index = line.IndexOf(':');

                        if (index != -1)
                        {
                            lastChapter.Name = line.Substring(index + 1).Trim().TrimEnd('\r');
                        }
                    }
                }
            }

            result.Chapters = chapters;
        }
예제 #7
0
        public void Setup()
        {
            mockMediaInfoFacade     = new Mock <IMediaInfoFacade>(MockBehavior.Strict);
            _videoMediaFileMetadata = new MediaInfoResult
            {
                Duration = 42,
                Video    = new Video {
                    CodecId = "xd5c", DisplayAspectRatioRawValue = 16f / 9f, Width = 640
                },
                Audio = new Audio {
                    Format = "pcm", Channel = "2"
                }
            };
            _audioMediaFileMetadata = new MediaInfoResult {
                Duration = 42, Audio = new Audio {
                    Format = "mpeg_audio", Channel = "2"
                }
            };

            ObjectFactory.Configure(configure => configure.For <IMediaInfoFacade>().Use(mockMediaInfoFacade.Object));

            mockTimeProvider.Setup(m => m.GetUtcNow()).Returns(DateTime.Now);
            ObjectFactory.Configure(configure => configure.For <ITimeProvider>().Use(mockTimeProvider.Object));

            sut = new Order
            {
                BurnInLogo          = true,
                BurnInSubtitles     = false,
                DestinationFormat   = StateFormat.h264_od_single,
                DestinationPath     = "\\\\ondnas01\\MediaCache\\Test\\WfsJob\\Marvin",
                DueDate             = mockTimeProvider.Object.GetUtcNow(),
                FilePath            = "\\\\ondnas01\\MediaCache\\Test\\detkommernaermere.dif",
                LogoPath            = @"\\ondnas01\MediaCache\Test\pepe30.png",
                AlternateAudioPath  = "\\\\ondnas01\\MediaCache\\Test\\WavFileTest.wav",
                Priority            = Priority.medium,
                SubtitlesPath       = "",
                CallbackUrl         = "http://some/system",
                DestinationFilename = "destinationFilename"
            };

            mockMediaInfoFacade.Setup(m => m.Read(It.Is <string>(x => x.EndsWith("wav")))).Returns(_audioMediaFileMetadata);
            mockMediaInfoFacade.Setup(m => m.Read(It.Is <string>(x => !x.EndsWith("wav")))).Returns(_videoMediaFileMetadata);
        }
예제 #8
0
        private static void ValidateAudioInVideo(MediaInfoResult mi)
        {
            if (mi?.Audio == null)
            {
                return;
            }

            var audioStream = mi.Audio;

            //TODO: Reject unsupported audio
            //if (!Enum.IsDefined(typeof(StateFormat),audioStream.Format))
            //    throw new OrderException("Audio is not in a valid format.");

            var allowedChannelCount = new[] { "1" };

            if (Array.Exists(allowedChannelCount, element => element.Equals(audioStream.Channel)))
            {
                throw new OrderException("Only audio with more than 1 channel is supported.");
            }
        }
예제 #9
0
        /// <summary>
        /// Fetches the specified video.
        /// </summary>
        /// <param name="video">The video.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <param name="data">The data.</param>
        /// <param name="isoMount">The iso mount.</param>
        /// <returns>Task.</returns>
        protected async Task Fetch(Video video, CancellationToken cancellationToken, MediaInfoResult data, IIsoMount isoMount)
        {
            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;
                }
            }

            if (data.streams != null)
            {
                video.MediaStreams = data.streams.Select(s => GetMediaStream(s, data.format))
                                     .Where(i => i != null)
                                     .ToList();
            }

            var chapters = data.Chapters ?? new List <ChapterInfo>();

            if (video.VideoType == VideoType.BluRay || (video.IsoType.HasValue && video.IsoType.Value == IsoType.BluRay))
            {
                var inputPath = isoMount != null ? isoMount.MountedPath : video.Path;
                FetchBdInfo(video, chapters, inputPath, cancellationToken);
            }

            AddExternalSubtitles(video);

            FetchWtvInfo(video, data);

            if (chapters.Count == 0 && video.MediaStreams.Any(i => i.Type == MediaStreamType.Video))
            {
                AddDummyChapters(video, chapters);
            }

            await Kernel.Instance.FFMpegManager.PopulateChapterImages(video, chapters, false, false, cancellationToken).ConfigureAwait(false);

            await _itemRepo.SaveChapters(video.Id, chapters, cancellationToken).ConfigureAwait(false);
        }
        /// <summary>
        /// Fetches the specified audio.
        /// </summary>
        /// <param name="audio">The audio.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <param name="data">The data.</param>
        /// <param name="isoMount">The iso mount.</param>
        /// <returns>Task.</returns>
        protected void Fetch(Audio audio, CancellationToken cancellationToken, MediaInfoResult data)
        {
            if (data.streams == null)
            {
                Logger.Error("Audio item has no streams: " + audio.Path);
                return;
            }

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

            // Get the first audio stream
            var stream = data.streams.FirstOrDefault(s => s.codec_type.Equals("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.tags != null)
            {
                FetchDataFromTags(audio, data.format.tags);
            }
        }
예제 #11
0
        /// <summary>
        /// Normalizes the FF probe result.
        /// </summary>
        /// <param name="result">The result.</param>
        protected void NormalizeFFProbeResult(MediaInfoResult 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);
                    }
                }
            }
        }
        public override void ProcessCommand()
        {
            logger.Info("Reading Media Info for File: {0}", VideoLocalID);


            try
            {
                VideoLocalRepository repVids = new VideoLocalRepository();
                VideoLocal           vlocal  = repVids.GetByID(VideoLocalID);
                if (vlocal == null)
                {
                    logger.Error("Cound not find Video: {0}", VideoLocalID);
                    return;
                }

                if (!File.Exists(vlocal.FullServerPath))
                {
                    logger.Error("Cound not find physical file: {0}", vlocal.FullServerPath);
                    return;
                }

                int nshareID = -1;

                VideoInfoRepository repVidInfo = new VideoInfoRepository();
                VideoInfo           vinfo      = repVidInfo.GetByHash(vlocal.Hash);

                ImportFolderRepository repNS  = new ImportFolderRepository();
                List <ImportFolder>    shares = repNS.GetAll();

                string fileName = vlocal.FullServerPath;
                string filePath = "";
                DataAccessHelper.GetShareAndPath(fileName, shares, ref nshareID, ref filePath);

                FileInfo fi = new FileInfo(fileName);

                if (vinfo == null)
                {
                    vinfo      = new VideoInfo();
                    vinfo.Hash = vlocal.Hash;

                    vinfo.Duration        = 0;
                    vinfo.FileSize        = fi.Length;
                    vinfo.DateTimeUpdated = DateTime.Now;
                    vinfo.FileName        = filePath;

                    vinfo.AudioBitrate    = "";
                    vinfo.AudioCodec      = "";
                    vinfo.VideoBitrate    = "";
                    vinfo.VideoBitDepth   = "";
                    vinfo.VideoCodec      = "";
                    vinfo.VideoFrameRate  = "";
                    vinfo.VideoResolution = "";
                }


                logger.Trace("Getting media info for: {0}", fileName);
                MediaInfoResult mInfo = FileHashHelper.GetMediaInfo(fileName, true);

                vinfo.AudioBitrate = string.IsNullOrEmpty(mInfo.AudioBitrate) ? "" : mInfo.AudioBitrate;
                vinfo.AudioCodec   = string.IsNullOrEmpty(mInfo.AudioCodec) ? "" : mInfo.AudioCodec;

                vinfo.DateTimeUpdated = vlocal.DateTimeUpdated;
                vinfo.Duration        = mInfo.Duration;
                vinfo.FileName        = filePath;
                vinfo.FileSize        = fi.Length;

                vinfo.VideoBitrate    = string.IsNullOrEmpty(mInfo.VideoBitrate) ? "" : mInfo.VideoBitrate;
                vinfo.VideoBitDepth   = string.IsNullOrEmpty(mInfo.VideoBitDepth) ? "" : mInfo.VideoBitDepth;
                vinfo.VideoCodec      = string.IsNullOrEmpty(mInfo.VideoCodec) ? "" : mInfo.VideoCodec;
                vinfo.VideoFrameRate  = string.IsNullOrEmpty(mInfo.VideoFrameRate) ? "" : mInfo.VideoFrameRate;
                vinfo.VideoResolution = string.IsNullOrEmpty(mInfo.VideoResolution) ? "" : mInfo.VideoResolution;
                vinfo.FullInfo        = string.IsNullOrEmpty(mInfo.FullInfo) ? "" : mInfo.FullInfo;
                repVidInfo.Save(vinfo);
            }
            catch (Exception ex)
            {
                logger.Error("Error processing CommandRequest_ReadMediaInfo: {0} - {1}", VideoLocalID, ex.ToString());
                return;
            }
        }
예제 #13
0
        public static Media GenerateMediaFromVideoLocal(VideoLocal v)
        {
            VideoInfo info = v.VideoInfo;
            Media     m    = null;

            if (info != null)
            {
                if (!string.IsNullOrEmpty(info.FullInfo))
                {
                    try
                    {
                        m = XmlDeserializeFromString <Media>(info.FullInfo);
                    }
                    catch (Exception)
                    {
                        info.FullInfo = null;
                    }
                }
                if (string.IsNullOrEmpty(info.FullInfo))
                {
                    try
                    {
                        VideoInfoRepository repo  = new VideoInfoRepository();
                        MediaInfoResult     mInfo = FileHashHelper.GetMediaInfo(v.FullServerPath, true);
                        info.AudioBitrate    = string.IsNullOrEmpty(mInfo.AudioBitrate) ? "" : mInfo.AudioBitrate;
                        info.AudioCodec      = string.IsNullOrEmpty(mInfo.AudioCodec) ? "" : mInfo.AudioCodec;
                        info.Duration        = mInfo.Duration;
                        info.VideoBitrate    = string.IsNullOrEmpty(mInfo.VideoBitrate) ? "" : mInfo.VideoBitrate;
                        info.VideoBitDepth   = string.IsNullOrEmpty(mInfo.VideoBitDepth) ? "" : mInfo.VideoBitDepth;
                        info.VideoCodec      = string.IsNullOrEmpty(mInfo.VideoCodec) ? "" : mInfo.VideoCodec;
                        info.VideoFrameRate  = string.IsNullOrEmpty(mInfo.VideoFrameRate) ? "" : mInfo.VideoFrameRate;
                        info.VideoResolution = string.IsNullOrEmpty(mInfo.VideoResolution) ? "" : mInfo.VideoResolution;
                        info.FullInfo        = string.IsNullOrEmpty(mInfo.FullInfo) ? "" : mInfo.FullInfo;
                        repo.Save(info);
                        m = XmlDeserializeFromString <Media>(info.FullInfo);
                    }
                    catch (Exception)
                    {
                        //FILE DO NOT EXIST
                    }
                }
            }
            if (m != null)
            {
                m.Id = v.VideoLocalID.ToString();
                List <Stream> subs = SubtitleHelper.GetSubtitleStreams(v.FullServerPath);
                if (subs.Count > 0)
                {
                    m.Parts[0].Streams.AddRange(subs);
                }
                foreach (Part p in m.Parts)
                {
                    p.Id         = null;
                    p.Accessible = "1";
                    p.Exists     = "1";
                    bool vid = false;
                    bool aud = false;
                    bool txt = false;
                    foreach (Stream ss in p.Streams.ToArray())
                    {
                        if ((ss.StreamType == "1") && !vid)
                        {
                            vid = true;
                        }
                        if ((ss.StreamType == "2") && !aud)
                        {
                            aud         = true;
                            ss.Selected = "1";
                        }
                        if ((ss.StreamType == "3") && !txt)
                        {
                            txt         = true;
                            ss.Selected = "1";
                        }
                    }
                }
            }
            return(m);
        }
예제 #14
0
        private static void PopulateVideoEpisodeFromVideoLocal(Video l, VideoLocal v, JMMType type)
        {
            l.Type                  = "episode";
            l.Summary               = "Episode Overview Not Available";
            l.Title                 = Path.GetFileNameWithoutExtension(v.FilePath);
            l.Key                   = l.PrimaryExtraKey = ServerUrl(int.Parse(ServerSettings.JMMServerPort), MainWindow.PathAddressKodi + "/GetMetadata/0/" + (int)type + "/" + v.VideoLocalID);
            l.AddedAt               = v.DateTimeCreated.Year.ToString("0000") + "-" + v.DateTimeCreated.Month.ToString("00") + "-" + v.DateTimeCreated.Day.ToString("00") + " " + v.DateTimeCreated.Hour.ToString("00") + ":" + v.DateTimeCreated.Minute.ToString("00") + ":" + v.DateTimeCreated.Millisecond.ToString("00");
            l.UpdatedAt             = v.DateTimeUpdated.Year.ToString("0000") + "-" + v.DateTimeUpdated.Month.ToString("00") + "-" + v.DateTimeUpdated.Day.ToString("00") + " " + v.DateTimeUpdated.Hour.ToString("00") + ":" + v.DateTimeUpdated.Minute.ToString("00") + ":" + v.DateTimeUpdated.Millisecond.ToString("00");
            l.OriginallyAvailableAt = v.DateTimeCreated.Year.ToString("0000") + "-" + v.DateTimeCreated.Month.ToString("00") + "-" + v.DateTimeCreated.Day.ToString("00");
            l.Year                  = v.DateTimeCreated.Year.ToString();

            VideoInfo info = v.VideoInfo;

            Media m = null;

            if (info != null)
            {
                if (!string.IsNullOrEmpty(info.FullInfo))
                {
                    try
                    {
                        m = XmlDeserializeFromString <Media>(info.FullInfo);
                    }
                    catch (Exception)
                    {
                        info.FullInfo = null;
                    }
                }
                if (string.IsNullOrEmpty(info.FullInfo))
                {
                    VideoInfoRepository repo  = new VideoInfoRepository();
                    MediaInfoResult     mInfo = FileHashHelper.GetMediaInfo(v.FullServerPath, true, true);
                    info.AudioBitrate    = string.IsNullOrEmpty(mInfo.AudioBitrate) ? "" : mInfo.AudioBitrate;
                    info.AudioCodec      = string.IsNullOrEmpty(mInfo.AudioCodec) ? "" : mInfo.AudioCodec;
                    info.Duration        = mInfo.Duration;
                    info.VideoBitrate    = string.IsNullOrEmpty(mInfo.VideoBitrate) ? "" : mInfo.VideoBitrate;
                    info.VideoBitDepth   = string.IsNullOrEmpty(mInfo.VideoBitDepth) ? "" : mInfo.VideoBitDepth;
                    info.VideoCodec      = string.IsNullOrEmpty(mInfo.VideoCodec) ? "" : mInfo.VideoCodec;
                    info.VideoFrameRate  = string.IsNullOrEmpty(mInfo.VideoFrameRate) ? "" : mInfo.VideoFrameRate;
                    info.VideoResolution = string.IsNullOrEmpty(mInfo.VideoResolution) ? "" : mInfo.VideoResolution;
                    info.FullInfo        = string.IsNullOrEmpty(mInfo.FullInfo) ? "" : mInfo.FullInfo;
                    repo.Save(info);
                    m = XmlDeserializeFromString <Media>(info.FullInfo);
                }
            }
            l.Medias = new List <Media>();
            if (m != null)
            {
                m.Id = null;
                List <JMMContracts.KodiContracts.Stream> subs = SubtitleHelper.GetSubtitleStreamsKodi(v.FullServerPath);
                if (subs.Count > 0)
                {
                    foreach (JMMContracts.KodiContracts.Stream s in subs)
                    {
                        s.Key = ServerUrl(int.Parse(ServerSettings.JMMServerFilePort), "file/0/" + Base64EncodeUrl(s.File), KodiObject.IsExternalRequest);
                    }
                    m.Parts[0].Streams.AddRange(subs);
                }
                foreach (Part p in m.Parts)
                {
                    p.Id = null;

                    p.File = v.FullServerPath;
                    string ff = Path.GetExtension(v.FullServerPath);
                    p.Key        = ServerUrl(int.Parse(ServerSettings.JMMServerFilePort), "videolocal/0/" + v.VideoLocalID + "/file" + ff, KodiObject.IsExternalRequest);
                    p.Accessible = "1";
                    p.Exists     = "1";
                    bool vid = false;
                    bool aud = false;
                    bool txt = false;
                    foreach (JMMContracts.KodiContracts.Stream ss in p.Streams.ToArray())
                    {
                        if ((ss.StreamType == "1") && (!vid))
                        {
                            vid = true;
                        }
                        if ((ss.StreamType == "2") && (!aud))
                        {
                            aud         = true;
                            ss.Selected = "1";
                        }
                        if ((ss.StreamType == "3") && (!txt))
                        {
                            txt         = true;
                            ss.Selected = "1";
                        }
                    }
                }

                l.Medias.Add(m);
                l.Duration = m.Duration;
            }
        }
예제 #15
0
 public static bool ReadMediaInfo(string fileNameFull, bool forceRefresh, ref MediaInfoResult info)
 {
     return(ReadMediaInfo(fileNameFull, forceRefresh, ref info, false));
 }
예제 #16
0
        private static void PopulateVideoEpisodeFromVideoLocal(Video l, VideoLocal v, JMMType type, int userid)
        {
            l.Type                  = "episode";
            l.Summary               = "Episode Overview Not Available"; //TODO Intenationalization
            l.Title                 = Path.GetFileNameWithoutExtension(v.FilePath);
            l.Key                   = ContructVideoLocalIdUrl(userid, v.VideoLocalID, type);
            l.AddedAt               = v.DateTimeCreated.ToUnixTime();
            l.UpdatedAt             = v.DateTimeUpdated.ToUnixTime();
            l.OriginallyAvailableAt = v.DateTimeCreated.ToPlexDate();
            l.Year                  = v.DateTimeCreated.Year.ToString();
            VideoInfo info = v.VideoInfo;

            Media m = null;

            if (info != null)
            {
                if (!string.IsNullOrEmpty(info.FullInfo))
                {
                    try
                    {
                        m = XmlDeserializeFromString <Media>(info.FullInfo);
                    }
                    catch (Exception)
                    {
                        info.FullInfo = null;
                    }
                }
                if (string.IsNullOrEmpty(info.FullInfo))
                {
                    VideoInfoRepository repo  = new VideoInfoRepository();
                    MediaInfoResult     mInfo = FileHashHelper.GetMediaInfo(v.FullServerPath, true);
                    info.AudioBitrate    = string.IsNullOrEmpty(mInfo.AudioBitrate) ? "" : mInfo.AudioBitrate;
                    info.AudioCodec      = string.IsNullOrEmpty(mInfo.AudioCodec) ? "" : mInfo.AudioCodec;
                    info.Duration        = mInfo.Duration;
                    info.VideoBitrate    = string.IsNullOrEmpty(mInfo.VideoBitrate) ? "" : mInfo.VideoBitrate;
                    info.VideoBitDepth   = string.IsNullOrEmpty(mInfo.VideoBitDepth) ? "" : mInfo.VideoBitDepth;
                    info.VideoCodec      = string.IsNullOrEmpty(mInfo.VideoCodec) ? "" : mInfo.VideoCodec;
                    info.VideoFrameRate  = string.IsNullOrEmpty(mInfo.VideoFrameRate) ? "" : mInfo.VideoFrameRate;
                    info.VideoResolution = string.IsNullOrEmpty(mInfo.VideoResolution) ? "" : mInfo.VideoResolution;
                    info.FullInfo        = string.IsNullOrEmpty(mInfo.FullInfo) ? "" : mInfo.FullInfo;
                    repo.Save(info);
                    m = XmlDeserializeFromString <Media>(info.FullInfo);
                }
            }
            l.Medias = new List <Media>();
            if (m != null)
            {
                m.Id = null;
                List <JMMContracts.PlexContracts.Stream> subs = SubtitleHelper.GetSubtitleStreams(v.FullServerPath);
                if (subs.Count > 0)
                {
                    foreach (JMMContracts.PlexContracts.Stream s in subs)
                    {
                        s.Key = ConstructFileStream(userid, s.File);
                    }
                    m.Parts[0].Streams.AddRange(subs);
                }
                foreach (Part p in m.Parts)
                {
                    p.Id = null;
                    string ff = Path.GetExtension(v.FullServerPath);
                    p.Key        = ConstructVideoLocalStream(userid, v.VideoLocalID, ff);
                    p.Accessible = "1";
                    p.Exists     = "1";
                    bool vid = false;
                    bool aud = false;
                    bool txt = false;
                    foreach (JMMContracts.PlexContracts.Stream ss in p.Streams.ToArray())
                    {
                        if ((ss.StreamType == "1") && (!vid))
                        {
                            vid = true;
                        }
                        if ((ss.StreamType == "2") && (!aud))
                        {
                            aud         = true;
                            ss.Selected = "1";
                        }
                        if ((ss.StreamType == "3") && (!txt))
                        {
                            txt         = true;
                            ss.Selected = "1";
                        }
                    }
                }

                l.Medias.Add(m);
                l.Duration = m.Duration;
            }
        }
예제 #17
0
        public static bool ReadMediaInfo(string fileNameFull, bool forceRefresh, ref MediaInfoResult info)
        {
            try
            {
                if (!forceRefresh)
                {
                    // if we have populated the full info, we have already read the data
                    if (!string.IsNullOrEmpty(info.FullInfo))
                    {
                        return(false);
                    }
                }
                Media m = PlexMediaInfo.MediaConvert.Convert(fileNameFull);
                if (m != null)
                {
                    string xml = XmlSerializeToString(m);
                    if (!string.IsNullOrEmpty(m.Width) && !string.IsNullOrEmpty(m.Height))
                    {
                        info.VideoResolution = m.Width + "x" + m.Height;
                    }
                    if (!string.IsNullOrEmpty(m.VideoCodec))
                    {
                        info.VideoCodec = m.VideoCodec;
                    }
                    if (!string.IsNullOrEmpty(m.AudioCodec))
                    {
                        info.AudioCodec = m.AudioCodec;
                    }
                    if (!string.IsNullOrEmpty(m.Duration))
                    {
                        info.Duration = int.Parse(m.Duration);
                    }
                    List <JMMContracts.PlexContracts.Stream> vparts = m.Parts[0].Streams.Where(a => a.StreamType == "1").ToList();
                    if (vparts.Count > 0)
                    {
                        if (!string.IsNullOrEmpty(vparts[0].Bitrate))
                        {
                            info.VideoBitrate = vparts[0].Bitrate;
                        }
                        if (!string.IsNullOrEmpty(vparts[0].BitDepth))
                        {
                            info.VideoBitDepth = vparts[0].BitDepth;
                        }
                        if (!string.IsNullOrEmpty(vparts[0].FrameRate))
                        {
                            info.VideoFrameRate = vparts[0].FrameRate;
                        }
                    }
                    List <JMMContracts.PlexContracts.Stream> aparts = m.Parts[0].Streams.Where(a => a.StreamType == "2").ToList();
                    if (aparts.Count > 0)
                    {
                        if (!string.IsNullOrEmpty(aparts[0].Bitrate))
                        {
                            info.AudioBitrate = aparts[0].Bitrate;
                        }
                    }
                    info.FullInfo = xml;
                }
                else
                {
                    logger.Error("ERROR getting media info:: {0}", fileNameFull);
                }
            }
            catch (Exception ex)
            {
                logger.Error("Error reading Media Info for: {0} --- {1}", fileNameFull, ex.ToString());
            }

            return(true);
        }
예제 #18
0
        private VideoLocal ProcessFile_LocalInfo()
        {
            // hash and read media info for file
            int    nshareID = -1;
            string filePath = "";

            ImportFolderRepository repNS  = new ImportFolderRepository();
            List <ImportFolder>    shares = repNS.GetAll();

            DataAccessHelper.GetShareAndPath(FileName, shares, ref nshareID, ref filePath);

            if (!File.Exists(FileName))
            {
                logger.Error("File does not exist: {0}", FileName);
                return(null);
            }

            int numAttempts = 0;

            // Wait 3 minutes seconds before giving up on trying to access the file
            while ((!CanAccessFile(FileName)) && (numAttempts < 180))
            {
                numAttempts++;
                Thread.Sleep(1000);
                Console.WriteLine("Attempt # " + numAttempts.ToString());
            }

            // if we failed to access the file, get ouuta here
            if (numAttempts == 180)
            {
                logger.Error("Could not access file: " + FileName);
                return(null);
            }


            // check if we have already processed this file
            VideoLocal             vlocal      = null;
            VideoLocalRepository   repVidLocal = new VideoLocalRepository();
            FileNameHashRepository repFNHash   = new FileNameHashRepository();

            List <VideoLocal> vidLocals = repVidLocal.GetByFilePathAndShareID(filePath, nshareID);
            FileInfo          fi        = new FileInfo(FileName);

            if (vidLocals.Count > 0)
            {
                vlocal = vidLocals[0];
                logger.Trace("VideoLocal record found in database: {0}", vlocal.VideoLocalID);

                if (ForceHash)
                {
                    vlocal.FileSize        = fi.Length;
                    vlocal.DateTimeUpdated = DateTime.Now;
                }
            }
            else
            {
                logger.Trace("VideoLocal, creating new record");
                vlocal = new VideoLocal();
                vlocal.DateTimeUpdated = DateTime.Now;
                vlocal.DateTimeCreated = vlocal.DateTimeUpdated;
                vlocal.FilePath        = filePath;
                vlocal.FileSize        = fi.Length;
                vlocal.ImportFolderID  = nshareID;
                vlocal.Hash            = "";
                vlocal.CRC32           = "";
                vlocal.MD5             = "";
                vlocal.SHA1            = "";
                vlocal.IsIgnored       = 0;
                vlocal.IsVariation     = 0;
            }

            // check if we need to get a hash this file
            Hashes hashes = null;

            if (string.IsNullOrEmpty(vlocal.Hash) || ForceHash)
            {
                // try getting the hash from the CrossRef
                if (!ForceHash)
                {
                    CrossRef_File_EpisodeRepository repCrossRefs = new CrossRef_File_EpisodeRepository();
                    List <CrossRef_File_Episode>    crossRefs    = repCrossRefs.GetByFileNameAndSize(Path.GetFileName(vlocal.FilePath), vlocal.FileSize);
                    if (crossRefs.Count == 1)
                    {
                        vlocal.Hash       = crossRefs[0].Hash;
                        vlocal.HashSource = (int)HashSource.DirectHash;
                    }
                }

                // try getting the hash from the LOCAL cache
                if (!ForceHash && string.IsNullOrEmpty(vlocal.Hash))
                {
                    List <FileNameHash> fnhashes = repFNHash.GetByFileNameAndSize(Path.GetFileName(vlocal.FilePath), vlocal.FileSize);
                    if (fnhashes != null && fnhashes.Count > 1)
                    {
                        // if we have more than one record it probably means there is some sort of corruption
                        // lets delete the local records
                        foreach (FileNameHash fnh in fnhashes)
                        {
                            repFNHash.Delete(fnh.FileNameHashID);
                        }
                    }

                    if (fnhashes != null && fnhashes.Count == 1)
                    {
                        logger.Trace("Got hash from LOCAL cache: {0} ({1})", FileName, fnhashes[0].Hash);
                        vlocal.Hash       = fnhashes[0].Hash;
                        vlocal.HashSource = (int)HashSource.WebCacheFileName;
                    }
                }

                // hash the file
                if (string.IsNullOrEmpty(vlocal.Hash) || ForceHash)
                {
                    DateTime start = DateTime.Now;
                    logger.Trace("Calculating hashes for: {0}", FileName);
                    // update the VideoLocal record with the Hash
                    hashes = FileHashHelper.GetHashInfo(FileName, true, MainWindow.OnHashProgress, ServerSettings.Hash_CRC32, ServerSettings.Hash_MD5, ServerSettings.Hash_SHA1);
                    TimeSpan ts = DateTime.Now - start;
                    logger.Trace("Hashed file in {0} seconds --- {1} ({2})", ts.TotalSeconds.ToString("#0.0"), FileName, Utils.FormatByteSize(vlocal.FileSize));

                    vlocal.Hash       = hashes.ed2k;
                    vlocal.CRC32      = hashes.crc32;
                    vlocal.MD5        = hashes.md5;
                    vlocal.SHA1       = hashes.sha1;
                    vlocal.HashSource = (int)HashSource.DirectHash;
                }

                // We should have a hash by now
                // before we save it, lets make sure there is not any other record with this hash (possible duplicate file)
                VideoLocal vidTemp = repVidLocal.GetByHash(vlocal.Hash);
                if (vidTemp != null)
                {
                    // don't delete it, if it is actually the same record
                    if (vidTemp.VideoLocalID != vlocal.VideoLocalID)
                    {
                        // delete the VideoLocal record
                        logger.Warn("Deleting duplicate video file record");
                        logger.Warn("---------------------------------------------");
                        logger.Warn("Keeping record for: {0}", vlocal.FullServerPath);
                        logger.Warn("Deleting record for: {0}", vidTemp.FullServerPath);
                        logger.Warn("---------------------------------------------");

                        // check if we have a record of this in the database, if not create one
                        DuplicateFileRepository repDups  = new DuplicateFileRepository();
                        List <DuplicateFile>    dupFiles = repDups.GetByFilePathsAndImportFolder(vlocal.FilePath, vidTemp.FilePath, vlocal.ImportFolderID, vidTemp.ImportFolderID);
                        if (dupFiles.Count == 0)
                        {
                            dupFiles = repDups.GetByFilePathsAndImportFolder(vidTemp.FilePath, vlocal.FilePath, vidTemp.ImportFolderID, vlocal.ImportFolderID);
                        }

                        if (dupFiles.Count == 0)
                        {
                            DuplicateFile dup = new DuplicateFile();
                            dup.DateTimeUpdated     = DateTime.Now;
                            dup.FilePathFile1       = vlocal.FilePath;
                            dup.FilePathFile2       = vidTemp.FilePath;
                            dup.ImportFolderIDFile1 = vlocal.ImportFolderID;
                            dup.ImportFolderIDFile2 = vidTemp.ImportFolderID;
                            dup.Hash = vlocal.Hash;
                            repDups.Save(dup);
                        }

                        repVidLocal.Delete(vidTemp.VideoLocalID);
                    }
                }

                repVidLocal.Save(vlocal);

                // also save the filename to hash record
                // replace the existing records just in case it was corrupt
                FileNameHash        fnhash    = null;
                List <FileNameHash> fnhashes2 = repFNHash.GetByFileNameAndSize(Path.GetFileName(vlocal.FilePath), vlocal.FileSize);
                if (fnhashes2 != null && fnhashes2.Count > 1)
                {
                    // if we have more than one record it probably means there is some sort of corruption
                    // lets delete the local records
                    foreach (FileNameHash fnh in fnhashes2)
                    {
                        repFNHash.Delete(fnh.FileNameHashID);
                    }
                }

                if (fnhashes2 != null && fnhashes2.Count == 1)
                {
                    fnhash = fnhashes2[0];
                }
                else
                {
                    fnhash = new FileNameHash();
                }

                fnhash.FileName        = Path.GetFileName(vlocal.FilePath);
                fnhash.FileSize        = vlocal.FileSize;
                fnhash.Hash            = vlocal.Hash;
                fnhash.DateTimeUpdated = DateTime.Now;
                repFNHash.Save(fnhash);
            }


            // now check if we have stored a VideoInfo record
            bool refreshMediaInfo = false;

            VideoInfoRepository repVidInfo = new VideoInfoRepository();
            VideoInfo           vinfo      = repVidInfo.GetByHash(vlocal.Hash);

            if (vinfo == null)
            {
                refreshMediaInfo = true;

                vinfo      = new VideoInfo();
                vinfo.Hash = vlocal.Hash;

                vinfo.Duration        = 0;
                vinfo.FileSize        = fi.Length;
                vinfo.DateTimeUpdated = DateTime.Now;
                vinfo.FileName        = filePath;

                vinfo.AudioBitrate    = "";
                vinfo.AudioCodec      = "";
                vinfo.VideoBitrate    = "";
                vinfo.VideoBitDepth   = "";
                vinfo.VideoCodec      = "";
                vinfo.VideoFrameRate  = "";
                vinfo.VideoResolution = "";

                repVidInfo.Save(vinfo);
            }
            else
            {
                // check if we need to update the media info
                if (vinfo.VideoCodec.Trim().Length == 0)
                {
                    refreshMediaInfo = true;
                }
                else
                {
                    refreshMediaInfo = false;
                }
            }



            if (refreshMediaInfo)
            {
                logger.Trace("Getting media info for: {0}", FileName);
                MediaInfoResult mInfo = FileHashHelper.GetMediaInfo(FileName, true);

                vinfo.AudioBitrate = string.IsNullOrEmpty(mInfo.AudioBitrate) ? "" : mInfo.AudioBitrate;
                vinfo.AudioCodec   = string.IsNullOrEmpty(mInfo.AudioCodec) ? "" : mInfo.AudioCodec;

                vinfo.DateTimeUpdated = vlocal.DateTimeUpdated;
                vinfo.Duration        = mInfo.Duration;
                vinfo.FileName        = filePath;
                vinfo.FileSize        = fi.Length;

                vinfo.VideoBitrate    = string.IsNullOrEmpty(mInfo.VideoBitrate) ? "" : mInfo.VideoBitrate;
                vinfo.VideoBitDepth   = string.IsNullOrEmpty(mInfo.VideoBitDepth) ? "" : mInfo.VideoBitDepth;
                vinfo.VideoCodec      = string.IsNullOrEmpty(mInfo.VideoCodec) ? "" : mInfo.VideoCodec;
                vinfo.VideoFrameRate  = string.IsNullOrEmpty(mInfo.VideoFrameRate) ? "" : mInfo.VideoFrameRate;
                vinfo.VideoResolution = string.IsNullOrEmpty(mInfo.VideoResolution) ? "" : mInfo.VideoResolution;
                vinfo.FullInfo        = string.IsNullOrEmpty(mInfo.FullInfo) ? "" : mInfo.FullInfo;
                repVidInfo.Save(vinfo);
            }

            // now add a command to process the file
            CommandRequest_ProcessFile cr_procfile = new CommandRequest_ProcessFile(vlocal.VideoLocalID, false);

            cr_procfile.Save();

            return(vlocal);
        }
예제 #19
0
        /// <summary>
        /// Fetches the specified video.
        /// </summary>
        /// <param name="video">The video.</param>
        /// <param name="force">if set to <c>true</c> [force].</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <param name="data">The data.</param>
        /// <param name="isoMount">The iso mount.</param>
        /// <returns>Task.</returns>
        protected async Task Fetch(Video video, bool force, CancellationToken cancellationToken, MediaInfoResult data, IIsoMount isoMount)
        {
            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;
                }
            }

            if (data.streams != null)
            {
                video.MediaStreams = data.streams.Select(s => GetMediaStream(s, data.format))
                                     .Where(i => i != null)
                                     .ToList();
            }

            var chapters = data.Chapters ?? new List <ChapterInfo>();

            if (video.VideoType == VideoType.BluRay || (video.IsoType.HasValue && video.IsoType.Value == IsoType.BluRay))
            {
                var inputPath = isoMount != null ? isoMount.MountedPath : video.Path;
                FetchBdInfo(video, chapters, inputPath, cancellationToken);
            }

            AddExternalSubtitles(video);

            FetchWtvInfo(video, force, data);

            video.IsHD = video.MediaStreams.Any(i => i.Type == MediaStreamType.Video && i.Width.HasValue && i.Width.Value >= 1270);

            if (chapters.Count == 0 && video.MediaStreams.Any(i => i.Type == MediaStreamType.Video))
            {
                AddDummyChapters(video, chapters);
            }

            await Kernel.Instance.FFMpegManager.PopulateChapterImages(video, chapters, false, false, cancellationToken).ConfigureAwait(false);


            BaseProviderInfo providerInfo;
            var videoFileChanged = false;

            if (video.ProviderData.TryGetValue(Id, out providerInfo))
            {
                videoFileChanged = CompareDate(video) > providerInfo.LastRefreshed;
            }

            // Only save chapters if forcing, if the video changed, or if there are not already any saved ones
            if (force || videoFileChanged || _itemRepo.GetChapter(video.Id, 0) == null)
            {
                await _itemRepo.SaveChapters(video.Id, chapters, cancellationToken).ConfigureAwait(false);
            }
        }