Ejemplo n.º 1
0
        private void ParseAndVerifyQuality(string title, Quality quality, bool proper)
        {
            var result = QualityParser.ParseQuality(title);

            result.Quality.Should().Be(quality);

            var version = proper ? 2 : 1;

            result.Revision.Version.Should().Be(version);
        }
Ejemplo n.º 2
0
        private ManualImportItem ProcessFile(string file, string downloadId, string folder = null)
        {
            if (folder.IsNullOrWhiteSpace())
            {
                folder = new FileInfo(file).Directory.FullName;
            }

            DownloadClientItem downloadClientItem = null;
            var relativeFile = folder.GetRelativePath(file);
            var series       = _parsingService.GetSeries(relativeFile.Split('\\', '/')[0]);

            if (series == null)
            {
                series = _parsingService.GetSeries(relativeFile);
            }

            if (downloadId.IsNotNullOrWhiteSpace())
            {
                var trackedDownload = _trackedDownloadService.Find(downloadId);
                downloadClientItem = trackedDownload.DownloadItem;

                if (series == null)
                {
                    series = trackedDownload.RemoteEpisode.Series;
                }
            }

            if (series == null)
            {
                var localEpisode = new LocalEpisode();
                localEpisode.Path    = file;
                localEpisode.Quality = QualityParser.ParseQuality(file);
                localEpisode.Size    = _diskProvider.GetFileSize(file);

                return(MapItem(new ImportDecision(localEpisode, new Rejection("Unknown Series")), folder, downloadId));
            }

            var importDecisions = _importDecisionMaker.GetImportDecisions(new List <string> {
                file
            },
                                                                          series, downloadClientItem, null, SceneSource(series, folder));

            return(importDecisions.Any() ? MapItem(importDecisions.First(), folder, downloadId) : new ManualImportItem
            {
                DownloadId = downloadId,
                Path = file,
                RelativePath = folder.GetRelativePath(file),
                Name = Path.GetFileNameWithoutExtension(file),
                Rejections = new List <Rejection>
                {
                    new Rejection("Unable to process file")
                }
            });
        }
Ejemplo n.º 3
0
        public ManualImportItem ReprocessItem(string path, string downloadId, int seriesId, int?seasonNumber, List <int> episodeIds, string releaseGroup, QualityModel quality, Language language)
        {
            var rootFolder = Path.GetDirectoryName(path);
            var series     = _seriesService.GetSeries(seriesId);

            if (episodeIds.Any())
            {
                var downloadClientItem = GetTrackedDownload(downloadId)?.DownloadItem;

                var localEpisode = new LocalEpisode();
                localEpisode.Series                    = series;
                localEpisode.Episodes                  = _episodeService.GetEpisodes(episodeIds);
                localEpisode.FileEpisodeInfo           = Parser.Parser.ParsePath(path);
                localEpisode.DownloadClientEpisodeInfo = downloadClientItem == null ? null : Parser.Parser.ParseTitle(downloadClientItem.Title);
                localEpisode.Path         = path;
                localEpisode.SceneSource  = SceneSource(series, rootFolder);
                localEpisode.ExistingFile = series.Path.IsParentPath(path);
                localEpisode.Size         = _diskProvider.GetFileSize(path);
                localEpisode.ReleaseGroup = releaseGroup.IsNullOrWhiteSpace() ? Parser.Parser.ParseReleaseGroup(path) : releaseGroup;
                localEpisode.Language     = language == Language.Unknown ? LanguageParser.ParseLanguage(path) : language;
                localEpisode.Quality      = quality.Quality == Quality.Unknown ? QualityParser.ParseQuality(path) : quality;

                return(MapItem(_importDecisionMaker.GetDecision(localEpisode, downloadClientItem), rootFolder, downloadId, null));
            }

            // This case will happen if the user selected a season, but didn't select the episodes in the season then changed the language or quality.
            // Instead of overriding their season selection let it persist and reject it with an appropriate error.

            if (seasonNumber.HasValue)
            {
                var downloadClientItem = GetTrackedDownload(downloadId)?.DownloadItem;

                var localEpisode = new LocalEpisode
                {
                    Series                    = series,
                    Episodes                  = new List <Episode>(),
                    FileEpisodeInfo           = Parser.Parser.ParsePath(path),
                    DownloadClientEpisodeInfo = downloadClientItem == null
                                           ? null
                                           : Parser.Parser.ParseTitle(downloadClientItem.Title),
                    Path         = path,
                    SceneSource  = SceneSource(series, rootFolder),
                    ExistingFile = series.Path.IsParentPath(path),
                    Size         = _diskProvider.GetFileSize(path),
                    ReleaseGroup = releaseGroup.IsNullOrWhiteSpace() ? Parser.Parser.ParseReleaseGroup(path) : releaseGroup,
                    Language     = language == Language.Unknown ? LanguageParser.ParseLanguage(path) : language,
                    Quality      = quality.Quality == Quality.Unknown ? QualityParser.ParseQuality(path) : quality
                };

                return(MapItem(new ImportDecision(localEpisode, new Rejection("Episodes not selected")), rootFolder, downloadId, null));
            }

            return(ProcessFile(rootFolder, rootFolder, path, downloadId, series));
        }
Ejemplo n.º 4
0
        public void should_use_file_quality_if_file_quality_was_determined_by_name()
        {
            GivenSpecifications(_pass1, _pass2, _pass3);
            var expectedQuality = QualityParser.ParseQuality(_videoFiles.Single());

            var result = Subject.GetImportDecisions(_videoFiles, _series, new ParsedEpisodeInfo {
                Quality = new QualityModel(Quality.SDTV)
            }, true);

            result.Single().LocalEpisode.Quality.Should().Be(expectedQuality);
        }
Ejemplo n.º 5
0
 //Used for tests that rely on parsing working correctly. Does some minimal parsing using the old static methods.
 protected void ParseMovieTitle()
 {
     Mocker.GetMock <IParsingService>().Setup(c => c.ParseMovieInfo(It.IsAny <string>(), It.IsAny <System.Collections.Generic.List <object> >()))
     .Returns <string, System.Collections.Generic.List <object> >((title, helpers) =>
     {
         var result = Parser.Parser.ParseMovieTitle(title, false);
         if (result != null)
         {
             result.Quality = QualityParser.ParseQuality(title);
         }
         return(result);
     });
 }
Ejemplo n.º 6
0
        private ManualImportItem ProcessFile(string file, string downloadId, string folder = null)
        {
            if (folder.IsNullOrWhiteSpace())
            {
                folder = new FileInfo(file).Directory.FullName;
            }

            var relativeFile = folder.GetRelativePath(file);

            var movie = _parsingService.GetMovie(relativeFile.Split('\\', '/')[0]);

            if (movie == null)
            {
                movie = _parsingService.GetMovie(relativeFile);
            }

            if (movie == null && downloadId.IsNotNullOrWhiteSpace())
            {
                var trackedDownload = _trackedDownloadService.Find(downloadId);
                movie = trackedDownload.RemoteMovie.Movie;
            }

            if (movie == null)
            {
                var localMovie = new LocalMovie()
                {
                    Path    = file,
                    Quality = QualityParser.ParseQuality(file),
                    Size    = _diskProvider.GetFileSize(file)
                };

                return(MapItem(new ImportDecision(localMovie, new Rejection("Unknown Movie")), folder, downloadId));
            }

            var importDecisions = _importDecisionMaker.GetImportDecisions(new List <string> {
                file
            },
                                                                          movie, null, SceneSource(movie, folder), true);

            return(importDecisions.Any() ? MapItem(importDecisions.First(), folder, downloadId) : new ManualImportItem
            {
                DownloadId = downloadId,
                Path = file,
                RelativePath = folder.GetRelativePath(file),
                Name = Path.GetFileNameWithoutExtension(file),
                Rejections = new List <Rejection>
                {
                    new Rejection("Unable to process file")
                }
            });
        }
Ejemplo n.º 7
0
        public List <ImportResult> ProcessFolder(DirectoryInfo directoryInfo, DownloadClientItem downloadClientItem = null)
        {
            if (_seriesService.SeriesPathExists(directoryInfo.FullName))
            {
                _logger.Warn("Unable to process folder that contains sorted TV Shows");
                return(new List <ImportResult>());
            }

            var cleanedUpName = GetCleanedUpFolderName(directoryInfo.Name);
            var series        = _parsingService.GetSeries(cleanedUpName);
            var quality       = QualityParser.ParseQuality(cleanedUpName);

            _logger.Debug("{0} folder quality: {1}", cleanedUpName, quality);

            if (series == null)
            {
                _logger.Debug("Unknown Series {0}", cleanedUpName);
                return(new List <ImportResult>
                {
                    new ImportResult(new ImportDecision(null, "Unknown Series"), "Unknown Series")
                });
            }

            var videoFiles = _diskScanService.GetVideoFiles(directoryInfo.FullName);

            foreach (var videoFile in videoFiles)
            {
                if (_diskProvider.IsFileLocked(videoFile))
                {
                    _logger.Debug("[{0}] is currently locked by another process, skipping", videoFile);
                    return(new List <ImportResult>
                    {
                        new ImportResult(new ImportDecision(new LocalEpisode {
                            Path = videoFile
                        }, "Locked file, try again later"), "Locked file, try again later")
                    });
                }
            }

            var decisions = _importDecisionMaker.GetImportDecisions(videoFiles.ToList(), series, true, quality);

            var importResults = _importApprovedEpisodes.Import(decisions, true, downloadClientItem);

            if ((downloadClientItem == null || !downloadClientItem.IsReadOnly) && importResults.Any() && ShouldDeleteFolder(directoryInfo))
            {
                _logger.Debug("Deleting folder after importing valid files");
                _diskProvider.DeleteFolder(directoryInfo.FullName, true);
            }

            return(importResults);
        }
        private List <ImportDecision> ProcessFolder(DirectoryInfo directoryInfo)
        {
            var cleanedUpName = GetCleanedUpFolderName(directoryInfo.Name);
            var series        = _parsingService.GetSeries(cleanedUpName);
            var quality       = QualityParser.ParseQuality(cleanedUpName);

            _logger.Debug("{0} folder quality: {1}", cleanedUpName, quality);

            if (series == null)
            {
                _logger.Debug("Unknown Series {0}", cleanedUpName);
                return(new List <ImportDecision>());
            }

            var videoFiles = _diskScanService.GetVideoFiles(directoryInfo.FullName);

            return(ProcessFiles(series, quality, videoFiles));
        }
Ejemplo n.º 9
0
        private void ParseAndVerifyQuality(string title, Source source, bool proper, Resolution resolution, Modifier modifier = Modifier.NONE)
        {
            var result = QualityParser.ParseQuality(title);

            if (resolution != Resolution.Unknown)
            {
                result.Resolution.Should().Be(resolution);
            }
            result.Source.Should().Be(source);
            if (modifier != Modifier.NONE)
            {
                result.Modifier.Should().Be(modifier);
            }

            var version = proper ? 2 : 1;

            result.Revision.Version.Should().Be(version);
        }
        private List <ImportResult> ProcessFolder(DirectoryInfo directoryInfo, Series series,
                                                  DownloadClientItem downloadClientItem = null)
        {
            if (_seriesService.SeriesPathExists(directoryInfo.FullName))
            {
                _logger.Warn("Unable to process folder that is mapped to an existing show");
                return(new List <ImportResult>());
            }

            var cleanedUpName = GetCleanedUpFolderName(directoryInfo.Name);
            var quality       = QualityParser.ParseQuality(cleanedUpName);

            _logger.Debug("{0} folder quality: {1}", cleanedUpName, quality);

            var videoFiles = _diskScanService.GetVideoFiles(directoryInfo.FullName);

            if (downloadClientItem == null)
            {
                foreach (var videoFile in videoFiles)
                {
                    if (_diskProvider.IsFileLocked(videoFile))
                    {
                        return(new List <ImportResult>
                        {
                            FileIsLockedResult(videoFile)
                        });
                    }
                }
            }

            var decisions     = _importDecisionMaker.GetImportDecisions(videoFiles.ToList(), series, true, quality);
            var importResults = _importApprovedEpisodes.Import(decisions, true, downloadClientItem);

            if ((downloadClientItem == null || !downloadClientItem.IsReadOnly) && importResults.Any() && ShouldDeleteFolder(directoryInfo, series))
            {
                _logger.Debug("Deleting folder after importing valid files");
                _diskProvider.DeleteFolder(directoryInfo.FullName, true);
            }

            return(importResults);
        }
Ejemplo n.º 11
0
        public ManualImportItem ReprocessItem(string path, string downloadId, int movieId, QualityModel quality, List <Language> languages)
        {
            var rootFolder = Path.GetDirectoryName(path);
            var movie      = _movieService.GetMovie(movieId);

            var downloadClientItem = GetTrackedDownload(downloadId)?.DownloadItem;

            var localEpisode = new LocalMovie
            {
                Movie                   = movie,
                FileMovieInfo           = Parser.Parser.ParseMoviePath(path),
                DownloadClientMovieInfo = downloadClientItem == null ? null : Parser.Parser.ParseMovieTitle(downloadClientItem.Title),
                Path         = path,
                SceneSource  = SceneSource(movie, rootFolder),
                ExistingFile = movie.Path.IsParentPath(path),
                Size         = _diskProvider.GetFileSize(path),
                Languages    = (languages?.SingleOrDefault() ?? Language.Unknown) == Language.Unknown ? LanguageParser.ParseLanguages(path) : languages,
                Quality      = quality.Quality == Quality.Unknown ? QualityParser.ParseQuality(path) : quality
            };

            return(MapItem(_importDecisionMaker.GetDecision(localEpisode, downloadClientItem), rootFolder, downloadId, null));
        }
Ejemplo n.º 12
0
        private ManualImportItem ProcessFile(string file, string downloadId, string folder = null)
        {
            if (folder.IsNullOrWhiteSpace())
            {
                folder = new FileInfo(file).Directory.FullName;
            }

            Series series = null;

            var parsedEpisodeInfo = Parser.Parser.ParsePath(folder.GetRelativePath(file));

            if (parsedEpisodeInfo != null)
            {
                series = _parsingService.GetSeries(parsedEpisodeInfo.SeriesTitle);
            }

            if (series == null && downloadId.IsNotNullOrWhiteSpace())
            {
                var trackedDownload = _trackedDownloadService.Find(downloadId);
                series = trackedDownload.RemoteEpisode.Series;
            }

            if (series == null)
            {
                var localEpisode = new LocalEpisode();
                localEpisode.Path    = file;
                localEpisode.Quality = QualityParser.ParseQuality(file);
                localEpisode.Size    = _diskProvider.GetFileSize(file);

                return(MapItem(new ImportDecision(localEpisode, new Rejection("Unknown Series")), folder, downloadId));
            }

            var importDecisions = _importDecisionMaker.GetImportDecisions(new List <string> {
                file
            },
                                                                          series, null, SceneSource(series, folder));

            return(importDecisions.Any() ? MapItem(importDecisions.First(), folder, downloadId) : null);
        }
Ejemplo n.º 13
0
        public void should_not_parse_opus_quality(string title, string desc, int bitrate)
        {
            var result = QualityParser.ParseQuality(title, desc, bitrate);

            result.Quality.Should().Be(Quality.FLAC);
        }
Ejemplo n.º 14
0
        public void Read(string path)
        {
            Logger.Debug($"Starting tag read for {path}");

            IsValid = false;
            TagLib.File file = null;
            try
            {
                file = TagLib.File.Create(path);
                var tag = file.Tag;

                Title        = tag.Title ?? tag.TitleSort;
                Performers   = tag.Performers ?? tag.PerformersSort;
                AlbumArtists = tag.AlbumArtists ?? tag.AlbumArtistsSort;
                Track        = tag.Track;
                TrackCount   = tag.TrackCount;
                Album        = tag.Album ?? tag.AlbumSort;
                Disc         = tag.Disc;
                DiscCount    = tag.DiscCount;
                Year         = tag.Year;
                Publisher    = tag.Publisher;
                Duration     = file.Properties.Duration;
                Genres       = tag.Genres;
                ImageSize    = tag.Pictures.FirstOrDefault()?.Data.Count ?? 0;

                DateTime tempDate;

                // Do the ones that aren't handled by the generic taglib implementation
                if (file.TagTypesOnDisk.HasFlag(TagTypes.Id3v2))
                {
                    var id3tag = (TagLib.Id3v2.Tag)file.GetTag(TagTypes.Id3v2);
                    Media = id3tag.GetTextAsString("TMED");
                    Date  = ReadId3Date(id3tag, "TDRC");
                    OriginalReleaseDate = ReadId3Date(id3tag, "TDOR");
                }
                else if (file.TagTypesOnDisk.HasFlag(TagTypes.Xiph))
                {
                    // while publisher is handled by taglib, it seems to be mapped to 'ORGANIZATION' and not 'LABEL' like Picard is
                    // https://picard.musicbrainz.org/docs/mappings/
                    var flactag = (TagLib.Ogg.XiphComment)file.GetTag(TagLib.TagTypes.Xiph);
                    Media = flactag.GetField("MEDIA").ExclusiveOrDefault();
                    Date  = DateTime.TryParse(flactag.GetField("DATE").ExclusiveOrDefault(), out tempDate) ? tempDate : default(DateTime?);
                    OriginalReleaseDate = DateTime.TryParse(flactag.GetField("ORIGINALDATE").ExclusiveOrDefault(), out tempDate) ? tempDate : default(DateTime?);
                    Publisher           = flactag.GetField("LABEL").ExclusiveOrDefault();
                }
                else if (file.TagTypesOnDisk.HasFlag(TagTypes.Ape))
                {
                    var apetag = (TagLib.Ape.Tag)file.GetTag(TagTypes.Ape);
                    Media = apetag.GetItem("Media")?.ToString();
                    Date  = DateTime.TryParse(apetag.GetItem("Year")?.ToString(), out tempDate) ? tempDate : default(DateTime?);
                    OriginalReleaseDate = DateTime.TryParse(apetag.GetItem("Original Date")?.ToString(), out tempDate) ? tempDate : default(DateTime?);
                    Publisher           = apetag.GetItem("Label")?.ToString();
                }
                else if (file.TagTypesOnDisk.HasFlag(TagTypes.Asf))
                {
                    var asftag = (TagLib.Asf.Tag)file.GetTag(TagTypes.Asf);
                    Media = asftag.GetDescriptorString("WM/Media");
                    Date  = DateTime.TryParse(asftag.GetDescriptorString("WM/Year"), out tempDate) ? tempDate : default(DateTime?);
                    OriginalReleaseDate = DateTime.TryParse(asftag.GetDescriptorString("WM/OriginalReleaseTime"), out tempDate) ? tempDate : default(DateTime?);
                    Publisher           = asftag.GetDescriptorString("WM/Publisher");
                }
                else if (file.TagTypesOnDisk.HasFlag(TagTypes.Apple))
                {
                    var appletag = (TagLib.Mpeg4.AppleTag)file.GetTag(TagTypes.Apple);
                    Media = appletag.GetDashBox("com.apple.iTunes", "MEDIA");
                    Date  = DateTime.TryParse(appletag.DataBoxes(FixAppleId("day")).FirstOrDefault()?.Text, out tempDate) ? tempDate : default(DateTime?);
                    OriginalReleaseDate = DateTime.TryParse(appletag.GetDashBox("com.apple.iTunes", "Original Date"), out tempDate) ? tempDate : default(DateTime?);
                }

                OriginalYear = OriginalReleaseDate.HasValue ? (uint)OriginalReleaseDate?.Year : 0;

                foreach (ICodec codec in file.Properties.Codecs)
                {
                    IAudioCodec acodec = codec as IAudioCodec;

                    if (acodec != null && (acodec.MediaTypes & MediaTypes.Audio) != MediaTypes.None)
                    {
                        int bitrate = acodec.AudioBitrate;
                        if (bitrate == 0)
                        {
                            // Taglib can't read bitrate for Opus.
                            bitrate = EstimateBitrate(file, path);
                        }

                        Logger.Debug("Audio Properties: " + acodec.Description + ", Bitrate: " + bitrate + ", Sample Size: " +
                                     file.Properties.BitsPerSample + ", SampleRate: " + acodec.AudioSampleRate + ", Channels: " + acodec.AudioChannels);

                        Quality = QualityParser.ParseQuality(file.Name, acodec.Description);
                        Logger.Debug($"Quality parsed: {Quality}, Source: {Quality.QualityDetectionSource}");

                        MediaInfo = new MediaInfoModel
                        {
                            AudioFormat     = acodec.Description,
                            AudioBitrate    = bitrate,
                            AudioChannels   = acodec.AudioChannels,
                            AudioBits       = file.Properties.BitsPerSample,
                            AudioSampleRate = acodec.AudioSampleRate
                        };
                    }
                }

                IsValid = true;
            }
            catch (Exception ex)
            {
                if (ex is CorruptFileException)
                {
                    Logger.Warn(ex, $"Tag reading failed for {path}.  File is corrupt");
                }
                else
                {
                    // Log as error so it goes to sentry with correct fingerprint
                    Logger.Error(ex, "Tag reading failed for {0}", path);
                }
            }
            finally
            {
                file?.Dispose();
            }

            // make sure these are initialized to avoid errors later on
            if (Quality == null)
            {
                Quality = QualityParser.ParseQuality(path);
                Logger.Debug($"Unable to parse qulity from tag, Quality parsed from file path: {Quality}, Source: {Quality.QualityDetectionSource}");
            }

            MediaInfo = MediaInfo ?? new MediaInfoModel();
        }
Ejemplo n.º 15
0
        private ManualImportItem ProcessFile(string rootFolder, string baseFolder, string file, string downloadId, Series series = null)
        {
            try
            {
                var trackedDownload = GetTrackedDownload(downloadId);
                var relativeFile    = baseFolder.GetRelativePath(file);

                if (series == null)
                {
                    _parsingService.GetSeries(relativeFile.Split('\\', '/')[0]);
                }

                if (series == null)
                {
                    series = _parsingService.GetSeries(relativeFile);
                }

                if (trackedDownload != null && series == null)
                {
                    series = trackedDownload?.RemoteEpisode?.Series;
                }

                if (series == null)
                {
                    var relativeParseInfo = Parser.Parser.ParsePath(relativeFile);

                    if (relativeParseInfo != null)
                    {
                        series = _seriesService.FindByTitle(relativeParseInfo.SeriesTitle);
                    }
                }

                if (series == null)
                {
                    var localEpisode = new LocalEpisode();
                    localEpisode.Path         = file;
                    localEpisode.ReleaseGroup = Parser.Parser.ParseReleaseGroup(file);
                    localEpisode.Quality      = QualityParser.ParseQuality(file);
                    localEpisode.Language     = LanguageParser.ParseLanguage(file);
                    localEpisode.Size         = _diskProvider.GetFileSize(file);

                    return(MapItem(new ImportDecision(localEpisode, new Rejection("Unknown Series")), rootFolder,
                                   downloadId, null));
                }

                var importDecisions = _importDecisionMaker.GetImportDecisions(new List <string> {
                    file
                }, series,
                                                                              trackedDownload?.DownloadItem, null, SceneSource(series, baseFolder));

                if (importDecisions.Any())
                {
                    return(MapItem(importDecisions.First(), rootFolder, downloadId, null));
                }
            }
            catch (Exception ex)
            {
                _logger.Warn(ex, "Failed to process file: {0}", file);
            }

            return(new ManualImportItem
            {
                DownloadId = downloadId,
                Path = file,
                RelativePath = rootFolder.GetRelativePath(file),
                Name = Path.GetFileNameWithoutExtension(file),
                Rejections = new List <Rejection>()
            });
        }
Ejemplo n.º 16
0
 public void should_parse_quality_from_name(string title)
 {
     QualityParser.ParseQuality(title, null, 0).QualityDetectionSource.Should().Be(QualityDetectionSource.Name);
 }
Ejemplo n.º 17
0
        private ManualImportItem ProcessFile(string rootFolder, string baseFolder, string file, string downloadId, Movie movie = null)
        {
            DownloadClientItem downloadClientItem = null;
            var relativeFile = baseFolder.GetRelativePath(file);

            if (movie == null)
            {
                _parsingService.GetMovie(relativeFile.Split('\\', '/')[0]);
            }

            if (movie == null)
            {
                movie = _parsingService.GetMovie(relativeFile);
            }

            if (downloadId.IsNotNullOrWhiteSpace())
            {
                var trackedDownload = _trackedDownloadService.Find(downloadId);
                downloadClientItem = trackedDownload?.DownloadItem;

                if (movie == null)
                {
                    movie = trackedDownload?.RemoteMovie?.Movie;
                }
            }

            if (movie == null)
            {
                var relativeParseInfo = Parser.Parser.ParseMoviePath(relativeFile);

                if (relativeParseInfo != null)
                {
                    movie = _movieService.FindByTitle(relativeParseInfo.MovieTitle, relativeParseInfo.Year);
                }
            }

            if (movie == null)
            {
                var localMovie = new LocalMovie();
                localMovie.Path = file;
                localMovie.Quality = QualityParser.ParseQuality(file);
                localMovie.Languages = LanguageParser.ParseLanguages(file);
                localMovie.Size = _diskProvider.GetFileSize(file);

                return MapItem(new ImportDecision(localMovie, new Rejection("Unknown Movie")), rootFolder, downloadId, null);
            }

            var importDecisions = _importDecisionMaker.GetImportDecisions(new List<string> { file }, movie, downloadClientItem, null, SceneSource(movie, baseFolder));

            if (importDecisions.Any())
            {
                return MapItem(importDecisions.First(), rootFolder, downloadId, null);
            }

            return new ManualImportItem
            {
                DownloadId = downloadId,
                Path = file,
                RelativePath = rootFolder.GetRelativePath(file),
                Name = Path.GetFileNameWithoutExtension(file),
                Rejections = new List<Rejection>()
            };
        }
Ejemplo n.º 18
0
        public Tuple <List <LocalBook>, List <ImportDecision <LocalBook> > > GetLocalTracks(List <IFileInfo> musicFiles, DownloadClientItem downloadClientItem, ParsedTrackInfo folderInfo, FilterFilesType filter)
        {
            var watch = new System.Diagnostics.Stopwatch();

            watch.Start();

            var files = _mediaFileService.FilterUnchangedFiles(musicFiles, filter);

            var localTracks = new List <LocalBook>();
            var decisions   = new List <ImportDecision <LocalBook> >();

            _logger.Debug("Analyzing {0}/{1} files.", files.Count, musicFiles.Count);

            if (!files.Any())
            {
                return(Tuple.Create(localTracks, decisions));
            }

            ParsedBookInfo downloadClientItemInfo = null;

            if (downloadClientItem != null)
            {
                downloadClientItemInfo = Parser.Parser.ParseBookTitle(downloadClientItem.Title);
            }

            string[] audiobookQualities = new string[] { "MP3-320", "FLAC", "Unknown" };

            var i = 1;

            foreach (var file in files)
            {
                LocalBook localTrack;
                var       quality = QualityParser.ParseQuality(file.Name);
                _logger.ProgressInfo($"Reading file {i++}/{files.Count}");
                if (audiobookQualities.Contains(quality.Quality.Name) || quality.Quality.Id >= 10)
                {
                    _logger.Debug("Reading {0} audio file", quality.Quality.Name);
                    localTrack = new LocalBook
                    {
                        DownloadClientAlbumInfo = downloadClientItemInfo,
                        FolderTrackInfo         = folderInfo,
                        Path           = file.FullName,
                        Size           = file.Length,
                        Modified       = file.LastWriteTimeUtc,
                        FileTrackInfo  = _audioTagService.ReadTags(file.FullName),
                        AdditionalFile = false
                    };
                }
                else
                {
                    _logger.Debug("Reading {0} ebook file", quality.Quality.Name);
                    localTrack = new LocalBook
                    {
                        DownloadClientAlbumInfo = downloadClientItemInfo,
                        FolderTrackInfo         = folderInfo,
                        Path           = file.FullName,
                        Size           = file.Length,
                        Modified       = file.LastWriteTimeUtc,
                        FileTrackInfo  = _eBookTagService.ReadTags(file),
                        AdditionalFile = false
                    };
                }

                try
                {
                    // TODO fix otherfiles?
                    _augmentingService.Augment(localTrack, true);
                    localTracks.Add(localTrack);
                }
                catch (AugmentingFailedException)
                {
                    decisions.Add(new ImportDecision <LocalBook>(localTrack, new Rejection("Unable to parse file")));
                }
                catch (Exception e)
                {
                    _logger.Error(e, "Couldn't import file. {0}", localTrack.Path);

                    decisions.Add(new ImportDecision <LocalBook>(localTrack, new Rejection("Unexpected error processing file")));
                }
            }

            _logger.Debug($"Tags parsed for {files.Count} files in {watch.ElapsedMilliseconds}ms");

            return(Tuple.Create(localTracks, decisions));
        }
Ejemplo n.º 19
0
 public void should_parse_ultrahd_from_title(string title, int version)
 {
     QualityParser.ParseQuality(title).Quality.Id.Should().Be(version);
 }
Ejemplo n.º 20
0
 public void should_parse_hardcoded_subs(string postTitle, string sub)
 {
     QualityParser.ParseQuality(postTitle).HardcodedSubs.Should().Be(sub);
 }
Ejemplo n.º 21
0
 public void should_parse_version_from_title(string title, int version)
 {
     QualityParser.ParseQuality(title).Revision.Version.Should().Be(version);
 }
Ejemplo n.º 22
0
        private void ParseAndVerifyQuality(string name, string desc, int bitrate, Quality quality, int sampleSize = 0)
        {
            var result = QualityParser.ParseQuality(name);

            result.Quality.Should().Be(quality);
        }
Ejemplo n.º 23
0
 public void should_parse_quality_from_name(string title)
 {
     QualityParser.ParseQuality(title).QualitySource.Should().Be(QualitySource.Name);
 }
Ejemplo n.º 24
0
 public void should_parse_reality_from_title(string title, int reality)
 {
     //TODO: re-enable this when we have a reliable way to determine real
     QualityParser.ParseQuality(title).Revision.Real.Should().Be(reality);
 }
Ejemplo n.º 25
0
        public void should_parse_ultrahd_from_title(string title, int version)
        {
            var parsed = QualityParser.ParseQuality(title);

            parsed.Resolution.Should().Be(Resolution.R2160P);
        }
Ejemplo n.º 26
0
        private IEnumerable <DownloadDecision> GetDecisions(List <ReleaseInfo> reports, SearchCriteriaBase searchCriteria = null)
        {
            if (reports.Any())
            {
                _logger.ProgressInfo("Processing {0} releases", reports.Count);
            }

            else
            {
                _logger.ProgressInfo("No results found");
            }

            var reportNumber = 1;

            foreach (var report in reports)
            {
                DownloadDecision decision = null;
                _logger.ProgressTrace("Processing release {0}/{1}", reportNumber, reports.Count);
                _logger.Debug("Processing release '{0}' from '{1}'", report.Title, report.Indexer);

                try
                {
                    var parsedEpisodeInfo = Parser.Parser.ParseTitle(report.Title);

                    if (parsedEpisodeInfo == null || parsedEpisodeInfo.IsPossibleSpecialEpisode)
                    {
                        var specialEpisodeInfo = _parsingService.ParseSpecialEpisodeTitle(parsedEpisodeInfo, report.Title, report.TvdbId, report.TvRageId, searchCriteria);

                        if (specialEpisodeInfo != null)
                        {
                            parsedEpisodeInfo = specialEpisodeInfo;
                        }
                    }

                    if (parsedEpisodeInfo != null && !parsedEpisodeInfo.SeriesTitle.IsNullOrWhiteSpace())
                    {
                        var remoteEpisode = _parsingService.Map(parsedEpisodeInfo, report.TvdbId, report.TvRageId, searchCriteria);
                        remoteEpisode.Release = report;

                        if (remoteEpisode.Series == null)
                        {
                            var reason         = "Unknown Series";
                            var matchingTvdbId = _sceneMappingService.FindTvdbId(parsedEpisodeInfo.SeriesTitle, parsedEpisodeInfo.ReleaseTitle, parsedEpisodeInfo.SeasonNumber);

                            if (matchingTvdbId.HasValue)
                            {
                                reason = $"{parsedEpisodeInfo.SeriesTitle} matches an alias for series with TVDB ID: {matchingTvdbId}";
                            }

                            decision = new DownloadDecision(remoteEpisode, new Rejection(reason));
                        }
                        else if (remoteEpisode.Episodes.Empty())
                        {
                            decision = new DownloadDecision(remoteEpisode, new Rejection("Unable to identify correct episode(s) using release name and scene mappings"));
                        }
                        else
                        {
                            _aggregationService.Augment(remoteEpisode);
                            remoteEpisode.DownloadAllowed = remoteEpisode.Episodes.Any();
                            decision = GetDecisionForReport(remoteEpisode, searchCriteria);
                        }
                    }

                    if (searchCriteria != null)
                    {
                        if (parsedEpisodeInfo == null)
                        {
                            parsedEpisodeInfo = new ParsedEpisodeInfo
                            {
                                Language = LanguageParser.ParseLanguage(report.Title),
                                Quality  = QualityParser.ParseQuality(report.Title)
                            };
                        }

                        if (parsedEpisodeInfo.SeriesTitle.IsNullOrWhiteSpace())
                        {
                            var remoteEpisode = new RemoteEpisode
                            {
                                Release           = report,
                                ParsedEpisodeInfo = parsedEpisodeInfo
                            };

                            decision = new DownloadDecision(remoteEpisode, new Rejection("Unable to parse release"));
                        }
                    }
                }
                catch (Exception e)
                {
                    _logger.Error(e, "Couldn't process release.");

                    var remoteEpisode = new RemoteEpisode {
                        Release = report
                    };
                    decision = new DownloadDecision(remoteEpisode, new Rejection("Unexpected error processing release"));
                }

                reportNumber++;

                if (decision != null)
                {
                    if (decision.Rejections.Any())
                    {
                        _logger.Debug("Release rejected for the following reasons: {0}", string.Join(", ", decision.Rejections));
                    }

                    else
                    {
                        _logger.Debug("Release accepted");
                    }

                    yield return(decision);
                }
            }
        }
Ejemplo n.º 27
0
        private IEnumerable <DownloadDecision> GetBookDecisions(List <ReleaseInfo> reports, SearchCriteriaBase searchCriteria = null)
        {
            if (reports.Any())
            {
                _logger.ProgressInfo("Processing {0} releases", reports.Count);
            }
            else
            {
                _logger.ProgressInfo("No results found");
            }

            var reportNumber = 1;

            foreach (var report in reports)
            {
                DownloadDecision decision = null;
                _logger.ProgressTrace("Processing release {0}/{1}", reportNumber, reports.Count);
                _logger.Debug("Processing release '{0}' from '{1}'", report.Title, report.Indexer);

                try
                {
                    var parsedBookInfo = Parser.Parser.ParseBookTitle(report.Title);

                    if (parsedBookInfo == null)
                    {
                        if (searchCriteria != null)
                        {
                            parsedBookInfo = Parser.Parser.ParseBookTitleWithSearchCriteria(report.Title,
                                                                                            searchCriteria.Author,
                                                                                            searchCriteria.Books);
                        }
                        else
                        {
                            // try parsing fuzzy
                            parsedBookInfo = _parsingService.ParseAlbumTitleFuzzy(report.Title);
                        }
                    }

                    if (parsedBookInfo != null && !parsedBookInfo.AuthorName.IsNullOrWhiteSpace())
                    {
                        var remoteBook = _parsingService.Map(parsedBookInfo, searchCriteria);

                        // try parsing again using the search criteria, in case it parsed but parsed incorrectly
                        if ((remoteBook.Author == null || remoteBook.Books.Empty()) && searchCriteria != null)
                        {
                            _logger.Debug("Author/Book null for {0}, reparsing with search criteria", report.Title);
                            var parsedBookInfoWithCriteria = Parser.Parser.ParseBookTitleWithSearchCriteria(report.Title,
                                                                                                            searchCriteria.Author,
                                                                                                            searchCriteria.Books);

                            if (parsedBookInfoWithCriteria != null && parsedBookInfoWithCriteria.AuthorName.IsNotNullOrWhiteSpace())
                            {
                                remoteBook = _parsingService.Map(parsedBookInfoWithCriteria, searchCriteria);
                            }
                        }

                        remoteBook.Release = report;

                        if (remoteBook.Author == null)
                        {
                            decision = new DownloadDecision(remoteBook, new Rejection("Unknown Author"));

                            // shove in the searched author in case of forced download in interactive search
                            if (searchCriteria != null)
                            {
                                remoteBook.Author = searchCriteria.Author;
                                remoteBook.Books  = searchCriteria.Books;
                            }
                        }
                        else if (remoteBook.Books.Empty())
                        {
                            decision = new DownloadDecision(remoteBook, new Rejection("Unable to parse books from release name"));
                            if (searchCriteria != null)
                            {
                                remoteBook.Books = searchCriteria.Books;
                            }
                        }
                        else
                        {
                            _aggregationService.Augment(remoteBook);
                            remoteBook.DownloadAllowed = remoteBook.Books.Any();
                            decision = GetDecisionForReport(remoteBook, searchCriteria);
                        }
                    }

                    if (searchCriteria != null)
                    {
                        if (parsedBookInfo == null)
                        {
                            parsedBookInfo = new ParsedBookInfo
                            {
                                Quality = QualityParser.ParseQuality(report.Title)
                            };
                        }

                        if (parsedBookInfo.AuthorName.IsNullOrWhiteSpace())
                        {
                            var remoteBook = new RemoteBook
                            {
                                Release        = report,
                                ParsedBookInfo = parsedBookInfo
                            };

                            decision = new DownloadDecision(remoteBook, new Rejection("Unable to parse release"));
                        }
                    }
                }
                catch (Exception e)
                {
                    _logger.Error(e, "Couldn't process release.");

                    var remoteBook = new RemoteBook {
                        Release = report
                    };
                    decision = new DownloadDecision(remoteBook, new Rejection("Unexpected error processing release"));
                }

                reportNumber++;

                if (decision != null)
                {
                    if (decision.Rejections.Any())
                    {
                        _logger.Debug("Release rejected for the following reasons: {0}", string.Join(", ", decision.Rejections));
                    }
                    else
                    {
                        _logger.Debug("Release accepted");
                    }

                    yield return(decision);
                }
            }
        }
Ejemplo n.º 28
0
        private ManualImportItem ProcessFile(string rootFolder, string baseFolder, string file, string downloadId)
        {
            DownloadClientItem downloadClientItem = null;
            var relativeFile = baseFolder.GetRelativePath(file);
            var series       = _parsingService.GetSeries(relativeFile.Split('\\', '/')[0]);

            if (series == null)
            {
                series = _parsingService.GetSeries(relativeFile);
            }

            if (downloadId.IsNotNullOrWhiteSpace())
            {
                var trackedDownload = _trackedDownloadService.Find(downloadId);
                downloadClientItem = trackedDownload.DownloadItem;

                if (series == null)
                {
                    series = trackedDownload.RemoteEpisode.Series;
                }
            }

            if (series == null)
            {
                var relativeParseInfo = Parser.Parser.ParsePath(relativeFile);

                if (relativeParseInfo != null)
                {
                    series = _seriesService.FindByTitle(relativeParseInfo.SeriesTitle);
                }
            }

            if (series == null)
            {
                var localEpisode = new LocalEpisode();
                localEpisode.Path    = file;
                localEpisode.Quality = QualityParser.ParseQuality(file);
                localEpisode.Size    = _diskProvider.GetFileSize(file);

                return(MapItem(new ImportDecision(localEpisode, new Rejection("Unknown Series")), rootFolder, downloadId, null));
            }

            var importDecisions = _importDecisionMaker.GetImportDecisions(new List <string> {
                file
            },
                                                                          series, downloadClientItem, null, SceneSource(series, baseFolder));

            if (importDecisions.Any())
            {
                return(MapItem(importDecisions.First(), rootFolder, downloadId, null));
            }

            return(new ManualImportItem
            {
                DownloadId = downloadId,
                Path = file,
                RelativePath = rootFolder.GetRelativePath(file),
                Name = Path.GetFileNameWithoutExtension(file),
                Rejections = new List <Rejection>()
            });
        }
Ejemplo n.º 29
0
 public void should_parse_quality_from_extension(string title)
 {
     QualityParser.ParseQuality(title).QualitySource.Should().Be(QualitySource.Extension);
 }
Ejemplo n.º 30
0
 public void should_parse_reality_from_title(string title, int reality)
 {
     QualityParser.ParseQuality(title).Revision.Real.Should().Be(reality);
 }