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); }
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") } }); }
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)); }
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); }
//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); }); }
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") } }); }
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)); }
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); }
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)); }
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); }
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); }
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(); }
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>() }); }
public void should_parse_quality_from_name(string title) { QualityParser.ParseQuality(title, null, 0).QualityDetectionSource.Should().Be(QualityDetectionSource.Name); }
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>() }; }
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)); }
public void should_parse_ultrahd_from_title(string title, int version) { QualityParser.ParseQuality(title).Quality.Id.Should().Be(version); }
public void should_parse_hardcoded_subs(string postTitle, string sub) { QualityParser.ParseQuality(postTitle).HardcodedSubs.Should().Be(sub); }
public void should_parse_version_from_title(string title, int version) { QualityParser.ParseQuality(title).Revision.Version.Should().Be(version); }
private void ParseAndVerifyQuality(string name, string desc, int bitrate, Quality quality, int sampleSize = 0) { var result = QualityParser.ParseQuality(name); result.Quality.Should().Be(quality); }
public void should_parse_quality_from_name(string title) { QualityParser.ParseQuality(title).QualitySource.Should().Be(QualitySource.Name); }
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); }
public void should_parse_ultrahd_from_title(string title, int version) { var parsed = QualityParser.ParseQuality(title); parsed.Resolution.Should().Be(Resolution.R2160P); }
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); } } }
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); } } }
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>() }); }
public void should_parse_quality_from_extension(string title) { QualityParser.ParseQuality(title).QualitySource.Should().Be(QualitySource.Extension); }
public void should_parse_reality_from_title(string title, int reality) { QualityParser.ParseQuality(title).Revision.Real.Should().Be(reality); }