public bool AlreadyExists(string url, string path) { if (!_diskProvider.FileExists(path)) { return(false); } var headers = _httpClient.Head(new HttpRequest(url)).Headers; var fileSize = _diskProvider.GetFileSize(path); return(fileSize == headers.ContentLength); }
public List <ImportDecision> Import(List <ImportDecision> decisions, bool newDownload = false) { var qualifiedImports = GetQualifiedImports(decisions); var imported = new List <ImportDecision>(); foreach (var importDecision in qualifiedImports) { var localEpisode = importDecision.LocalEpisode; try { if (imported.SelectMany(r => r.LocalEpisode.Episodes) .Select(e => e.Id) .ToList() .Intersect(localEpisode.Episodes.Select(e => e.Id)) .Any()) { continue; } var episodeFile = new EpisodeFile(); episodeFile.DateAdded = DateTime.UtcNow; episodeFile.SeriesId = localEpisode.Series.Id; episodeFile.Path = localEpisode.Path.CleanFilePath(); episodeFile.Size = _diskProvider.GetFileSize(localEpisode.Path); episodeFile.Quality = localEpisode.Quality; episodeFile.SeasonNumber = localEpisode.SeasonNumber; episodeFile.Episodes = localEpisode.Episodes; if (newDownload) { episodeFile.SceneName = Path.GetFileNameWithoutExtension(localEpisode.Path.CleanFilePath()); episodeFile.Path = _episodeFileUpgrader.UpgradeEpisodeFile(episodeFile, localEpisode); } _mediaFileService.Add(episodeFile); imported.Add(importDecision); if (newDownload) { _eventAggregator.PublishEvent(new EpisodeImportedEvent(localEpisode, episodeFile)); _eventAggregator.PublishEvent(new EpisodeDownloadedEvent(localEpisode)); } } catch (Exception e) { _logger.WarnException("Couldn't import episode " + localEpisode, e); } } return(imported); }
private ImportDecision GetDecision(LocalMovie localMovie, DownloadClientItem downloadClientItem, bool otherFiles) { ImportDecision decision = null; var fileMovieInfo = Parser.Parser.ParseMoviePath(localMovie.Path); if (fileMovieInfo != null) { fileMovieInfo = _parsingService.EnhanceMovieInfo(fileMovieInfo); } localMovie.FileMovieInfo = fileMovieInfo; localMovie.Size = _diskProvider.GetFileSize(localMovie.Path); try { _aggregationService.Augment(localMovie, downloadClientItem, otherFiles); if (localMovie.Movie == null) { decision = new ImportDecision(localMovie, new Rejection("Invalid movie")); } else { decision = GetDecision(localMovie, downloadClientItem); } } catch (AugmentingFailedException) { decision = new ImportDecision(localMovie, new Rejection("Unable to parse file")); } catch (Exception ex) { _logger.Error(ex, "Couldn't import file. {0}", localMovie.Path); decision = new ImportDecision(localMovie, new Rejection("Unexpected error processing file")); } if (decision == null) { _logger.Error("Unable to make a decision on {0}", localMovie.Path); } else if (decision.Rejections.Any()) { _logger.Debug("File rejected for the following reasons: {0}", string.Join(", ", decision.Rejections)); } else { _logger.Debug("File accepted"); } return(decision); }
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); }
private ManualImportItem MapItem(ImportDecision decision, string rootFolder, string downloadId, string folderName) { var item = new ManualImportItem(); item.Path = decision.LocalMovie.Path; item.FolderName = folderName; item.RelativePath = rootFolder.GetRelativePath(decision.LocalMovie.Path); item.Name = Path.GetFileNameWithoutExtension(decision.LocalMovie.Path); item.DownloadId = downloadId; if (decision.LocalMovie.Movie != null) { item.Movie = decision.LocalMovie.Movie; } item.Quality = decision.LocalMovie.Quality; item.Size = _diskProvider.GetFileSize(decision.LocalMovie.Path); item.Languages = decision.LocalMovie.Languages; item.Rejections = decision.Rejections; return item; }
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)); }
public bool IsXbmcNfoFile(string path) { // Lets make sure we're not reading huge files. if (_diskProvider.GetFileSize(path) > 10.Megabytes()) { return(false); } // Check if it contains some of the kodi/xbmc xml tags var content = _diskProvider.ReadAllText(path); return(_regex.IsMatch(content)); }
private string GetHash(string file) { var data = new StringBuilder(); data.Append(file); try { data.Append(_diskProvider.FileGetLastWrite(file).ToBinary()); data.Append(_diskProvider.GetFileSize(file)); } catch (Exception ex) { _logger.Trace(ex, "Ignored hashing error during scan for {0}", file); } return(HashConverter.GetHash(data.ToString()).ToHexString()); }
public bool ShouldDeleteFolder(DirectoryInfo directoryInfo, Series series) { try { var videoFiles = _diskScanService.GetVideoFiles(directoryInfo.FullName); var rarFiles = _diskProvider.GetFiles(directoryInfo.FullName, SearchOption.AllDirectories).Where(f => Path.GetExtension(f).Equals(".rar", StringComparison.OrdinalIgnoreCase)); foreach (var videoFile in videoFiles) { var episodeParseResult = Parser.Parser.ParseTitle(Path.GetFileName(videoFile)); if (episodeParseResult == null) { _logger.Warn("Unable to parse file on import: [{0}]", videoFile); return(false); } if (_detectSample.IsSample(series, videoFile, episodeParseResult.IsPossibleSpecialEpisode) != DetectSampleResult.Sample) { _logger.Warn("Non-sample file detected: [{0}]", videoFile); return(false); } } if (rarFiles.Any(f => _diskProvider.GetFileSize(f) > 10.Megabytes())) { _logger.Warn("RAR file detected, will require manual cleanup"); return(false); } return(true); } catch (DirectoryNotFoundException e) { _logger.Debug(e, "Folder {0} has already been removed", directoryInfo.FullName); return(false); } catch (Exception e) { _logger.Debug(e, "Unable to determine whether folder {0} should be removed", directoryInfo.FullName); return(false); } }
private Response GetMediaCover(int seriesId, string filename) { var filePath = Path.Combine(_appFolderInfo.GetAppDataPath(), "MediaCover", seriesId.ToString(), filename); if (!_diskProvider.FileExists(filePath) || _diskProvider.GetFileSize(filePath) == 0) { // Return the full sized image if someone requests a non-existing resized one. // TODO: This code can be removed later once everyone had the update for a while. var basefilePath = RegexResizedImage.Replace(filePath, ".jpg"); if (basefilePath == filePath || !_diskProvider.FileExists(basefilePath)) { return(new NotFoundResponse()); } filePath = basefilePath; } return(new StreamResponse(() => File.OpenRead(filePath), MimeTypes.GetMimeType(filePath))); }
private void EnsureResizedCovers(Movie movie, MediaCover cover, bool forceResize) { int[] heights; switch (cover.CoverType) { default: return; case MediaCoverTypes.Poster: case MediaCoverTypes.Headshot: heights = new[] { 500, 250 }; break; case MediaCoverTypes.Banner: heights = new[] { 70, 35 }; break; case MediaCoverTypes.Fanart: case MediaCoverTypes.Screenshot: heights = new[] { 360, 180 }; break; } foreach (var height in heights) { var mainFileName = GetCoverPath(movie.Id, cover.CoverType); var resizeFileName = GetCoverPath(movie.Id, cover.CoverType, height); if (forceResize || !_diskProvider.FileExists(resizeFileName) || _diskProvider.GetFileSize(resizeFileName) == 0) { _logger.Debug("Resizing {0}-{1} for {2}", cover.CoverType, height, movie); try { _resizer.Resize(mainFileName, resizeFileName, height); } catch { _logger.Debug("Couldn't resize media cover {0}-{1} for {2}, using full size image instead.", cover.CoverType, height, movie); } } } }
public override string Map(string resourceUrl) { var path = resourceUrl.Replace('/', Path.DirectorySeparatorChar); path = path.Trim(Path.DirectorySeparatorChar); var resourcePath = Path.Combine(_appFolderInfo.GetAppDataPath(), path); if (!_diskProvider.FileExists(resourcePath) || _diskProvider.GetFileSize(resourcePath) == 0) { var baseResourcePath = RegexResizedImage.Replace(resourcePath, ".jpg$1"); if (baseResourcePath != resourcePath) { return(baseResourcePath); } } return(resourcePath); }
public IActionResult GetMediaCover(int movieId, string filename) { var filePath = Path.Combine(_appFolderInfo.GetAppDataPath(), "MediaCover", movieId.ToString(), filename); if (!_diskProvider.FileExists(filePath) || _diskProvider.GetFileSize(filePath) == 0) { // Return the full sized image if someone requests a non-existing resized one. // TODO: This code can be removed later once everyone had the update for a while. var basefilePath = RegexResizedImage.Replace(filePath, ".jpg"); if (basefilePath == filePath || !_diskProvider.FileExists(basefilePath)) { return(NotFound()); } filePath = basefilePath; } return(PhysicalFile(filePath, GetContentType(filePath))); }
private IEnumerable <ImportDecision> GetDecisions(IEnumerable <String> videoFiles, Series series, bool sceneSource, QualityModel quality = null) { foreach (var file in videoFiles) { ImportDecision decision = null; try { var parsedEpisode = _parsingService.GetLocalEpisode(file, series, sceneSource); if (parsedEpisode != null) { if (quality != null && new QualityModelComparer(parsedEpisode.Series.QualityProfile).Compare(quality, parsedEpisode.Quality) > 0) { _logger.Debug("Using quality from folder: {0}", quality); parsedEpisode.Quality = quality; } parsedEpisode.Size = _diskProvider.GetFileSize(file); _logger.Debug("Size: {0}", parsedEpisode.Size); decision = GetDecision(parsedEpisode); } else { parsedEpisode = new LocalEpisode(); parsedEpisode.Path = file; decision = new ImportDecision(parsedEpisode, "Unable to parse file"); } } catch (Exception e) { _logger.ErrorException("Couldn't import file." + file, e); } if (decision != null) { yield return(decision); } } }
private bool CompareFiles(string sourceFile, string targetFile) { if (!_diskProvider.FileExists(sourceFile) || !_diskProvider.FileExists(targetFile)) { return(false); } if (_diskProvider.GetFileSize(sourceFile) != _diskProvider.GetFileSize(targetFile)) { return(false); } var sourceBuffer = new byte[64 * 1024]; var targetBuffer = new byte[64 * 1024]; using (var sourceStream = _diskProvider.OpenReadStream(sourceFile)) using (var targetStream = _diskProvider.OpenReadStream(targetFile)) { while (true) { var sourceLength = sourceStream.Read(sourceBuffer, 0, sourceBuffer.Length); var targetLength = targetStream.Read(targetBuffer, 0, targetBuffer.Length); if (sourceLength != targetLength) { return(false); } if (sourceLength == 0) { return(true); } for (var i = 0; i < sourceLength; i++) { if (sourceBuffer[i] != targetBuffer[i]) { return(false); } } } } }
public List <Backup> GetBackups() { var backups = new List <Backup>(); foreach (var backupType in Enum.GetValues(typeof(BackupType)).Cast <BackupType>()) { var folder = GetBackupFolder(backupType); if (_diskProvider.FolderExists(folder)) { backups.AddRange(GetBackupFiles(folder).Select(b => new Backup { Name = Path.GetFileName(b), Type = backupType, Size = _diskProvider.GetFileSize(b), Time = _diskProvider.FileGetLastWrite(b) })); } } return(backups); }
public bool AlreadyExists(DateTime?serverModifiedDate, long?serverContentLength, string localPath) { if (!_diskProvider.FileExists(localPath)) { return(false); } if (serverContentLength.HasValue && serverContentLength.Value > 0) { var fileSize = _diskProvider.GetFileSize(localPath); return(fileSize == serverContentLength); } if (serverModifiedDate.HasValue) { DateTime?lastModifiedLocal = _diskProvider.FileGetLastWrite(localPath); return(lastModifiedLocal.Value.ToUniversalTime() == serverModifiedDate.Value.ToUniversalTime()); } return(false); }
public LocalEpisode Augment(LocalEpisode localEpisode, DownloadClientItem downloadClientItem) { var isMediaFile = MediaFileExtensions.Extensions.Contains(Path.GetExtension(localEpisode.Path)); if (localEpisode.DownloadClientEpisodeInfo == null && localEpisode.FolderEpisodeInfo == null && localEpisode.FileEpisodeInfo == null) { if (isMediaFile) { throw new AugmentingFailedException("Unable to parse episode info from path: {0}", localEpisode.Path); } } localEpisode.Size = _diskProvider.GetFileSize(localEpisode.Path); localEpisode.SceneName = localEpisode.SceneSource ? SceneNameCalculator.GetSceneName(localEpisode) : null; if (isMediaFile && (!localEpisode.ExistingFile || _configService.EnableMediaInfo)) { localEpisode.MediaInfo = _videoFileInfoReader.GetMediaInfo(localEpisode.Path); } foreach (var augmenter in _augmenters) { try { augmenter.Aggregate(localEpisode, downloadClientItem); } catch (Exception ex) { _logger.Warn(ex, ex.Message); } } return(localEpisode); }
private void EnsureResizedCovers(Author author, MediaCover cover, bool forceResize, Book book = null) { int[] heights = GetDefaultHeights(cover.CoverType); foreach (var height in heights) { var mainFileName = GetCoverPath(author.Id, MediaCoverEntity.Author, cover.CoverType, cover.Extension); var resizeFileName = GetCoverPath(author.Id, MediaCoverEntity.Author, cover.CoverType, cover.Extension, height); if (forceResize || !_diskProvider.FileExists(resizeFileName) || _diskProvider.GetFileSize(resizeFileName) == 0) { _logger.Debug("Resizing {0}-{1} for {2}", cover.CoverType, height, author); try { _resizer.Resize(mainFileName, resizeFileName, height); } catch { _logger.Debug("Couldn't resize media cover {0}-{1} for author {2}, using full size image instead.", cover.CoverType, height, author); } } } }
public bool AlreadyExists(string url, string path) { if (!_diskProvider.FileExists(path)) { return(false); } var headers = _httpProvider.GetHeader(url); string sizeString; if (headers.TryGetValue(HttpProvider.CONTENT_LENGTH_HEADER, out sizeString)) { int size; int.TryParse(sizeString, out size); var fileSize = _diskProvider.GetFileSize(path); return(fileSize == size); } _logger.Warn("Couldn't find content-length header {0}", headers.ToJson()); return(false); }
private ManualImportItem MapItem(ImportDecision <LocalTrack> decision, string folder, string downloadId, bool replaceExistingFiles, bool disableReleaseSwitching) { var item = new ManualImportItem(); item.Id = HashConverter.GetHashInt31(decision.Item.Path); item.Path = decision.Item.Path; item.RelativePath = folder.GetRelativePath(decision.Item.Path); item.Name = Path.GetFileNameWithoutExtension(decision.Item.Path); item.DownloadId = downloadId; if (decision.Item.Artist != null) { item.Artist = decision.Item.Artist; } if (decision.Item.Album != null) { item.Album = decision.Item.Album; item.Release = decision.Item.Release; } if (decision.Item.Tracks.Any()) { item.Tracks = decision.Item.Tracks; } item.Quality = decision.Item.Quality; item.Size = _diskProvider.GetFileSize(decision.Item.Path); item.Rejections = decision.Rejections; item.Tags = decision.Item.FileTrackInfo; item.AdditionalFile = decision.Item.AdditionalFile; item.ReplaceExistingFiles = replaceExistingFiles; item.DisableReleaseSwitching = disableReleaseSwitching; return(item); }
private IEnumerable <WatchFolderItem> GetDownloadItems(string watchFolder, Dictionary <string, WatchFolderItem> lastWatchItems, TimeSpan waitPeriod) { // get a fresh naming config each time, in case the user has made changes foreach (var folder in _diskProvider.GetDirectories(watchFolder)) { var title = FileNameBuilder.CleanFileName(Path.GetFileName(folder)); var newWatchItem = new WatchFolderItem { DownloadId = Path.GetFileName(folder) + "_" + _diskProvider.FolderGetCreationTime(folder).Ticks, Title = title, OutputPath = new OsPath(folder), Status = DownloadItemStatus.Completed, RemainingTime = TimeSpan.Zero }; var oldWatchItem = lastWatchItems.GetValueOrDefault(newWatchItem.DownloadId); if (PreCheckWatchItemExpiry(newWatchItem, oldWatchItem)) { var files = _diskProvider.GetFiles(folder, SearchOption.AllDirectories); newWatchItem.TotalSize = files.Select(_diskProvider.GetFileSize).Sum(); newWatchItem.Hash = GetHash(folder, files); if (files.Any(_diskProvider.IsFileLocked)) { newWatchItem.Status = DownloadItemStatus.Downloading; newWatchItem.RemainingTime = null; } UpdateWatchItemExpiry(newWatchItem, oldWatchItem, waitPeriod); } yield return(newWatchItem); } foreach (var videoFile in _diskScanService.GetVideoFiles(watchFolder, false)) { var title = FileNameBuilder.CleanFileName(Path.GetFileName(videoFile)); var newWatchItem = new WatchFolderItem { DownloadId = Path.GetFileName(videoFile) + "_" + _diskProvider.FileGetLastWrite(videoFile).Ticks, Title = title, OutputPath = new OsPath(videoFile), Status = DownloadItemStatus.Completed, RemainingTime = TimeSpan.Zero }; var oldWatchItem = lastWatchItems.GetValueOrDefault(newWatchItem.DownloadId); if (PreCheckWatchItemExpiry(newWatchItem, oldWatchItem)) { newWatchItem.TotalSize = _diskProvider.GetFileSize(videoFile); newWatchItem.Hash = GetHash(videoFile); if (_diskProvider.IsFileLocked(videoFile)) { newWatchItem.Status = DownloadItemStatus.Downloading; } UpdateWatchItemExpiry(newWatchItem, oldWatchItem, waitPeriod); } yield return(newWatchItem); } }
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 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")), 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") } }); }
private ImportDecision GetDecision(string file, Movie movie, DownloadClientItem downloadClientItem, ParsedMovieInfo folderInfo, bool sceneSource, bool shouldUseFolderName, bool shouldCheckQuality = false) { ImportDecision decision = null; try { ParsedMovieInfo modifiedFolderInfo = null; if (folderInfo != null) { modifiedFolderInfo = folderInfo.JsonClone(); // We want the filename to be used for parsing quality, etc. even if we didn't get any movie info from there. modifiedFolderInfo.SimpleReleaseTitle = Path.GetFileName(file); } var minimalInfo = _parsingService.ParseMinimalPathMovieInfo(file) ?? modifiedFolderInfo; LocalMovie localMovie = null; if (minimalInfo != null) { //TODO: make it so media info doesn't ruin the import process of a new movie var mediaInfo = (_config.EnableMediaInfo || !movie.Path?.IsParentPath(file) == true) ? _videoFileInfoReader.GetMediaInfo(file) : null; var size = _diskProvider.GetFileSize(file); var historyItems = _historyService.FindByDownloadId(downloadClientItem?.DownloadId ?? ""); var firstHistoryItem = historyItems?.OrderByDescending(h => h.Date)?.FirstOrDefault(); var sizeMovie = new LocalMovie(); sizeMovie.Size = size; localMovie = _parsingService.GetLocalMovie(file, minimalInfo, movie, new List <object> { mediaInfo, firstHistoryItem, sizeMovie, folderInfo }, sceneSource); localMovie.Quality = GetQuality(folderInfo, localMovie.Quality, movie); localMovie.Size = size; _logger.Debug("Size: {0}", localMovie.Size); decision = GetDecision(localMovie, downloadClientItem); } else { localMovie = new LocalMovie(); localMovie.Path = file; if (MediaFileExtensions.Extensions.Contains(Path.GetExtension(file))) { if (_warnedFiles.Find(file) == null) { _warnedFiles.Set(file, "warned"); _logger.Warn("Unable to parse movie info from path {0}", file); } else { _logger.Trace("Already warned user that we are unable to parse movie info from path: {0}", file); } } decision = new ImportDecision(localMovie, new Rejection("Unable to parse file")); } } catch (Exception e) { _logger.Error(e, "Couldn't import file. {0}", file); var localMovie = new LocalMovie { Path = file }; decision = new ImportDecision(localMovie, new Rejection("Unexpected error processing file")); } //LocalMovie nullMovie = null; //decision = new ImportDecision(nullMovie, new Rejection("IMPLEMENTATION MISSING!!!")); return(decision); }
private ManualImportItem ProcessFile(string rootFolder, string baseFolder, string file, string downloadId, Series series = null) { try { DownloadClientItem downloadClientItem = null; var relativeFile = baseFolder.GetRelativePath(file); if (series == null) { _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.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, downloadClientItem, 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 List <ImportResult> Import(List <ImportDecision> decisions, bool newDownload, DownloadClientItem downloadClientItem = null, ImportMode importMode = ImportMode.Auto) { var qualifiedImports = decisions.Where(c => c.Approved) .GroupBy(c => c.LocalEpisode.Series.Id, (i, s) => s .OrderByDescending(c => c.LocalEpisode.Quality, new QualityModelComparer(s.First().LocalEpisode.Series.QualityProfile)) .ThenByDescending(c => c.LocalEpisode.Language, new LanguageComparer(s.First().LocalEpisode.Series.LanguageProfile)) .ThenByDescending(c => c.LocalEpisode.Size)) .SelectMany(c => c) .ToList(); var importResults = new List <ImportResult>(); foreach (var importDecision in qualifiedImports.OrderBy(e => e.LocalEpisode.Episodes.Select(episode => episode.EpisodeNumber).MinOrDefault()) .ThenByDescending(e => e.LocalEpisode.Size)) { var localEpisode = importDecision.LocalEpisode; var oldFiles = new List <EpisodeFile>(); try { //check if already imported if (importResults.SelectMany(r => r.ImportDecision.LocalEpisode.Episodes) .Select(e => e.Id) .Intersect(localEpisode.Episodes.Select(e => e.Id)) .Any()) { importResults.Add(new ImportResult(importDecision, "Episode has already been imported")); continue; } var episodeFile = new EpisodeFile(); episodeFile.DateAdded = DateTime.UtcNow; episodeFile.SeriesId = localEpisode.Series.Id; episodeFile.Path = localEpisode.Path.CleanFilePath(); episodeFile.Size = _diskProvider.GetFileSize(localEpisode.Path); episodeFile.Quality = localEpisode.Quality; episodeFile.MediaInfo = localEpisode.MediaInfo; episodeFile.SeasonNumber = localEpisode.SeasonNumber; episodeFile.Episodes = localEpisode.Episodes; episodeFile.ReleaseGroup = localEpisode.ReleaseGroup; episodeFile.Language = localEpisode.Language; bool copyOnly; switch (importMode) { default: case ImportMode.Auto: copyOnly = downloadClientItem != null && !downloadClientItem.CanMoveFiles; break; case ImportMode.Move: copyOnly = false; break; case ImportMode.Copy: copyOnly = true; break; } if (newDownload) { episodeFile.OriginalFilePath = GetOriginalFilePath(downloadClientItem, localEpisode); episodeFile.SceneName = GetSceneName(downloadClientItem, localEpisode); var moveResult = _episodeFileUpgrader.UpgradeEpisodeFile(episodeFile, localEpisode, copyOnly); oldFiles = moveResult.OldFiles; } else { episodeFile.RelativePath = localEpisode.Series.Path.GetRelativePath(episodeFile.Path); // Delete existing files from the DB mapped to this path var previousFiles = _mediaFileService.GetFilesWithRelativePath(localEpisode.Series.Id, episodeFile.RelativePath); foreach (var previousFile in previousFiles) { _mediaFileService.Delete(previousFile, DeleteMediaFileReason.ManualOverride); } } _mediaFileService.Add(episodeFile); importResults.Add(new ImportResult(importDecision)); if (newDownload) { _extraService.ImportEpisode(localEpisode, episodeFile, copyOnly); } _eventAggregator.PublishEvent(new EpisodeImportedEvent(localEpisode, episodeFile, oldFiles, newDownload, downloadClientItem)); } catch (RootFolderNotFoundException e) { _logger.Warn(e, "Couldn't import episode " + localEpisode); _eventAggregator.PublishEvent(new EpisodeImportFailedEvent(e, localEpisode, newDownload, downloadClientItem)); importResults.Add(new ImportResult(importDecision, "Failed to import episode, Root folder missing.")); } catch (DestinationAlreadyExistsException e) { _logger.Warn(e, "Couldn't import episode " + localEpisode); importResults.Add(new ImportResult(importDecision, "Failed to import episode, Destination already exists.")); } catch (Exception e) { _logger.Warn(e, "Couldn't import episode " + localEpisode); importResults.Add(new ImportResult(importDecision, "Failed to import episode")); } } //Adding all the rejected decisions importResults.AddRange(decisions.Where(c => !c.Approved) .Select(d => new ImportResult(d, d.Rejections.Select(r => r.Reason).ToArray()))); return(importResults); }
public List <ImportResult> Import(List <ImportDecision> decisions, bool newDownload, DownloadClientItem downloadClientItem = null) { var qualifiedImports = decisions.Where(c => c.Approved) .GroupBy(c => c.LocalEpisode.Series.Id, (i, s) => s .OrderByDescending(c => c.LocalEpisode.Quality, new QualityModelComparer(s.First().LocalEpisode.Series.Profile)) .ThenByDescending(c => c.LocalEpisode.Size)) .SelectMany(c => c) .ToList(); var importResults = new List <ImportResult>(); foreach (var importDecision in qualifiedImports.OrderBy(e => e.LocalEpisode.Episodes.Select(episode => episode.EpisodeNumber).MinOrDefault()) .ThenByDescending(e => e.LocalEpisode.Size)) { var localEpisode = importDecision.LocalEpisode; var oldFiles = new List <EpisodeFile>(); try { //check if already imported if (importResults.SelectMany(r => r.ImportDecision.LocalEpisode.Episodes) .Select(e => e.Id) .Intersect(localEpisode.Episodes.Select(e => e.Id)) .Any()) { importResults.Add(new ImportResult(importDecision, "Episode has already been imported")); continue; } var episodeFile = new EpisodeFile(); episodeFile.DateAdded = DateTime.UtcNow; episodeFile.SeriesId = localEpisode.Series.Id; episodeFile.Path = localEpisode.Path.CleanFilePath(); episodeFile.Size = _diskProvider.GetFileSize(localEpisode.Path); episodeFile.Quality = localEpisode.Quality; episodeFile.MediaInfo = localEpisode.MediaInfo; episodeFile.SeasonNumber = localEpisode.SeasonNumber; episodeFile.Episodes = localEpisode.Episodes; episodeFile.ReleaseGroup = localEpisode.ParsedEpisodeInfo.ReleaseGroup; if (newDownload) { bool copyOnly = downloadClientItem != null && downloadClientItem.IsReadOnly; episodeFile.SceneName = GetSceneName(downloadClientItem, localEpisode); var moveResult = _episodeFileUpgrader.UpgradeEpisodeFile(episodeFile, localEpisode, copyOnly); oldFiles = moveResult.OldFiles; } else { episodeFile.RelativePath = localEpisode.Series.Path.GetRelativePath(episodeFile.Path); } _mediaFileService.Add(episodeFile); importResults.Add(new ImportResult(importDecision)); if (newDownload) { _extraService.ImportExtraFiles(localEpisode, episodeFile, downloadClientItem != null && downloadClientItem.IsReadOnly); } if (downloadClientItem != null) { _eventAggregator.PublishEvent(new EpisodeImportedEvent(localEpisode, episodeFile, newDownload, downloadClientItem.DownloadClient, downloadClientItem.DownloadId, downloadClientItem.IsReadOnly)); } else { _eventAggregator.PublishEvent(new EpisodeImportedEvent(localEpisode, episodeFile, newDownload)); } if (newDownload) { _eventAggregator.PublishEvent(new EpisodeDownloadedEvent(localEpisode, episodeFile, oldFiles)); } } catch (Exception e) { _logger.Warn(e, "Couldn't import episode " + localEpisode); importResults.Add(new ImportResult(importDecision, "Failed to import episode")); } } //Adding all the rejected decisions importResults.AddRange(decisions.Where(c => !c.Approved) .Select(d => new ImportResult(d, d.Rejections.Select(r => r.Reason).ToArray()))); return(importResults); }
private ImportDecision GetDecision(string file, Movie movie, DownloadClientItem downloadClientItem, ParsedMovieInfo folderInfo, bool sceneSource, bool shouldUseFolderName, bool shouldCheckQuality = false) { ImportDecision decision = null; try { var minimalInfo = shouldUseFolderName ? folderInfo.JsonClone() : _parsingService.ParseMinimalPathMovieInfo(file); LocalMovie localMovie = null; //var localMovie = _parsingService.GetLocalMovie(file, movie, shouldUseFolderName ? folderInfo : null, sceneSource); if (minimalInfo != null) { //TODO: make it so media info doesn't ruin the import process of a new movie var mediaInfo = _config.EnableMediaInfo ? _videoFileInfoReader.GetMediaInfo(file) : null; var size = _diskProvider.GetFileSize(file); var historyItems = _historyService.FindByDownloadId(downloadClientItem?.DownloadId ?? ""); var firstHistoryItem = historyItems.OrderByDescending(h => h.Date).FirstOrDefault(); var sizeMovie = new LocalMovie(); sizeMovie.Size = size; localMovie = _parsingService.GetLocalMovie(file, minimalInfo, movie, new List <object> { mediaInfo, firstHistoryItem, sizeMovie }, sceneSource); localMovie.Quality = GetQuality(folderInfo, localMovie.Quality, movie); localMovie.Size = size; _logger.Debug("Size: {0}", localMovie.Size); decision = GetDecision(localMovie, downloadClientItem); } else { localMovie = new LocalMovie(); localMovie.Path = file; if (MediaFileExtensions.Extensions.Contains(Path.GetExtension(file))) { _logger.Warn("Unable to parse movie info from path {0}", file); } decision = new ImportDecision(localMovie, new Rejection("Unable to parse file")); } } catch (Exception e) { _logger.Error(e, "Couldn't import file. " + file); var localMovie = new LocalMovie { Path = file }; decision = new ImportDecision(localMovie, new Rejection("Unexpected error processing file")); } //LocalMovie nullMovie = null; //decision = new ImportDecision(nullMovie, new Rejection("IMPLEMENTATION MISSING!!!")); return(decision); }
public List <ImportResult> Import(List <ImportDecision> decisions, bool newDownload, DownloadClientItem downloadClientItem = null, ImportMode importMode = ImportMode.Auto) { _logger.Debug("Decisions: {0}", decisions.Count); var qualifiedImports = decisions.Where(c => c.Approved) .GroupBy(c => c.LocalMovie.Movie.Id, (i, s) => s .OrderByDescending(c => c.LocalMovie.Quality, new QualityModelComparer(s.First().LocalMovie.Movie.Profile)) .ThenByDescending(c => c.LocalMovie.Size)) .SelectMany(c => c) .ToList(); var importResults = new List <ImportResult>(); foreach (var importDecision in qualifiedImports.OrderBy(e => e.LocalMovie.Size) .ThenByDescending(e => e.LocalMovie.Size)) { var localMovie = importDecision.LocalMovie; var oldFiles = new List <MovieFile>(); try { //check if already imported if (importResults.Select(r => r.ImportDecision.LocalMovie.Movie) .Select(m => m.Id).Contains(localMovie.Movie.Id)) { importResults.Add(new ImportResult(importDecision, "Movie has already been imported")); continue; } var movieFile = new MovieFile(); movieFile.DateAdded = DateTime.UtcNow; movieFile.MovieId = localMovie.Movie.Id; movieFile.Path = localMovie.Path.CleanFilePath(); movieFile.Size = _diskProvider.GetFileSize(localMovie.Path); movieFile.Quality = localMovie.Quality; movieFile.MediaInfo = localMovie.MediaInfo; movieFile.Movie = localMovie.Movie; movieFile.ReleaseGroup = localMovie.ParsedMovieInfo.ReleaseGroup; movieFile.Edition = localMovie.ParsedMovieInfo.Edition; bool copyOnly; switch (importMode) { default: case ImportMode.Auto: copyOnly = downloadClientItem != null && downloadClientItem.IsReadOnly; break; case ImportMode.Move: copyOnly = false; break; case ImportMode.Copy: copyOnly = true; break; } if (newDownload) { movieFile.SceneName = GetSceneName(downloadClientItem, localMovie); var moveResult = _episodeFileUpgrader.UpgradeMovieFile(movieFile, localMovie, copyOnly); //TODO: Check if this works oldFiles = moveResult.OldFiles; } else { movieFile.RelativePath = localMovie.Movie.Path.GetRelativePath(movieFile.Path); } _mediaFileService.Add(movieFile); importResults.Add(new ImportResult(importDecision)); if (newDownload) { //_extraService.ImportExtraFiles(localMovie, episodeFile, copyOnly); TODO update for movie } if (downloadClientItem != null) { _eventAggregator.PublishEvent(new MovieImportedEvent(localMovie, movieFile, newDownload, downloadClientItem.DownloadClient, downloadClientItem.DownloadId, downloadClientItem.IsReadOnly)); } else { _eventAggregator.PublishEvent(new MovieImportedEvent(localMovie, movieFile, newDownload)); } if (newDownload) { _eventAggregator.PublishEvent(new MovieDownloadedEvent(localMovie, movieFile, oldFiles)); } } catch (Exception e) { _logger.Warn(e, "Couldn't import movie " + localMovie); importResults.Add(new ImportResult(importDecision, "Failed to import movie")); } } //Adding all the rejected decisions importResults.AddRange(decisions.Where(c => !c.Approved) .Select(d => new ImportResult(d, d.Rejections.Select(r => r.Reason).ToArray()))); return(importResults); }
private ImportDecision GetDecision(string file, Movie movie, ParsedMovieInfo folderInfo, bool sceneSource, bool shouldUseFolderName, bool shouldCheckQuality = false) { ImportDecision decision = null; try { var localMovie = _parsingService.GetLocalMovie(file, movie, shouldUseFolderName ? folderInfo : null, sceneSource); if (localMovie != null) { localMovie.Quality = GetQuality(folderInfo, localMovie.Quality, movie); localMovie.Size = _diskProvider.GetFileSize(file); _logger.Debug("Size: {0}", localMovie.Size); var current = localMovie.Quality; //TODO: make it so media info doesn't ruin the import process of a new series if (sceneSource && ShouldCheckQualityForParsedQuality(current.Quality)) { localMovie.MediaInfo = _videoFileInfoReader.GetMediaInfo(file); if (shouldCheckQuality) { _logger.Debug("Checking quality for this video file to make sure nothing mismatched."); var width = localMovie.MediaInfo.Width; var qualityName = current.Quality.Name.ToLower(); QualityModel updated = null; if (width > 2000) { if (qualityName.Contains("bluray")) { updated = new QualityModel(Quality.Bluray2160p); } else if (qualityName.Contains("webdl")) { updated = new QualityModel(Quality.WEBDL2160p); } else if (qualityName.Contains("hdtv")) { updated = new QualityModel(Quality.HDTV2160p); } else { var def = _qualitiesService.Get(Quality.HDTV2160p); if (localMovie.Size > def.MinSize && def.MaxSize > localMovie.Size) { updated = new QualityModel(Quality.HDTV2160p); } def = _qualitiesService.Get(Quality.WEBDL2160p); if (localMovie.Size > def.MinSize && def.MaxSize > localMovie.Size) { updated = new QualityModel(Quality.WEBDL2160p); } def = _qualitiesService.Get(Quality.Bluray2160p); if (localMovie.Size > def.MinSize && def.MaxSize > localMovie.Size) { updated = new QualityModel(Quality.Bluray2160p); } if (updated == null) { updated = new QualityModel(Quality.Bluray2160p); } } } else if (width > 1400) { if (qualityName.Contains("bluray")) { updated = new QualityModel(Quality.Bluray1080p); } else if (qualityName.Contains("webdl")) { updated = new QualityModel(Quality.WEBDL1080p); } else if (qualityName.Contains("hdtv")) { updated = new QualityModel(Quality.HDTV1080p); } else { var def = _qualitiesService.Get(Quality.HDTV1080p); if (localMovie.Size > def.MinSize && def.MaxSize > localMovie.Size) { updated = new QualityModel(Quality.HDTV1080p); } def = _qualitiesService.Get(Quality.WEBDL1080p); if (localMovie.Size > def.MinSize && def.MaxSize > localMovie.Size) { updated = new QualityModel(Quality.WEBDL1080p); } def = _qualitiesService.Get(Quality.Bluray1080p); if (localMovie.Size > def.MinSize && def.MaxSize > localMovie.Size) { updated = new QualityModel(Quality.Bluray1080p); } if (updated == null) { updated = new QualityModel(Quality.Bluray1080p); } } } else if (width > 900) { if (qualityName.Contains("bluray")) { updated = new QualityModel(Quality.Bluray720p); } else if (qualityName.Contains("webdl")) { updated = new QualityModel(Quality.WEBDL720p); } else if (qualityName.Contains("hdtv")) { updated = new QualityModel(Quality.HDTV720p); } else { var def = _qualitiesService.Get(Quality.HDTV720p); if (localMovie.Size > def.MinSize && def.MaxSize > localMovie.Size) { updated = new QualityModel(Quality.HDTV720p); } def = _qualitiesService.Get(Quality.WEBDL720p); if (localMovie.Size > def.MinSize && def.MaxSize > localMovie.Size) { updated = new QualityModel(Quality.WEBDL720p); } def = _qualitiesService.Get(Quality.Bluray720p); if (localMovie.Size > def.MinSize && def.MaxSize > localMovie.Size) { updated = new QualityModel(Quality.Bluray720p); } if (updated == null) { updated = new QualityModel(Quality.Bluray720p); } } } if (updated != null && updated != current) { _logger.Debug("Quality ({0}) of the file is different than the one we have ({1})", updated, current); updated.QualitySource = QualitySource.MediaInfo; localMovie.Quality = updated; } } decision = GetDecision(localMovie); } else { decision = GetDecision(localMovie); } } else { localMovie = new LocalMovie(); localMovie.Path = file; decision = new ImportDecision(localMovie, new Rejection("Unable to parse file")); } } catch (Exception e) { _logger.Error(e, "Couldn't import file. " + file); var localMovie = new LocalMovie { Path = file }; decision = new ImportDecision(localMovie, new Rejection("Unexpected error processing file")); } //LocalMovie nullMovie = null; //decision = new ImportDecision(nullMovie, new Rejection("IMPLEMENTATION MISSING!!!")); return(decision); }