Example #1
0
 private string GetMovieFileName(string sourcePath, Movie movie, MovieFileOrganizationOptions options)
 {
     return(GetMovieNameInternal(sourcePath, movie, options.MoviePattern));
 }
Example #2
0
        private async Task <Tuple <Movie, RemoteSearchResult> > AutoDetectMovie(string movieName, int?movieYear, FileOrganizationResult result, MovieFileOrganizationOptions options, CancellationToken cancellationToken)
        {
            if (options.AutoDetectMovie)
            {
                var parsedName = _libraryManager.ParseName(movieName);

                var yearInName                 = parsedName.Year;
                var nameWithoutYear            = parsedName.Name;
                RemoteSearchResult finalResult = null;

                if (string.IsNullOrWhiteSpace(nameWithoutYear))
                {
                    nameWithoutYear = movieName;
                }

                if (!yearInName.HasValue)
                {
                    yearInName = movieYear;
                }

                // Perform remote search
                var movieInfo = new MovieInfo {
                    Name = nameWithoutYear, Year = yearInName,
                };
                var searchResultsTask = await _providerManager.GetRemoteSearchResults <Movie, MovieInfo>(
                    new RemoteSearchQuery <MovieInfo> {
                    SearchInfo = movieInfo
                },
                    cancellationToken).ConfigureAwait(false);

                // Group movies by name and year (if 2 movie with the exact same name, the same year ...)
                var groupedResult = searchResultsTask.GroupBy(
                    p => new { p.Name, p.ProductionYear },
                    p => p,
                    (key, g) => new { Key = key, Result = g.ToList() }).ToList();

                if (groupedResult.Count == 1)
                {
                    finalResult = groupedResult.First().Result.First();
                }
                else if (groupedResult.Count > 1)
                {
                    var filtredResult = groupedResult
                                        .Select(i => new { Ref = i, Score = NameUtils.GetMatchScore(nameWithoutYear, yearInName, i.Key.Name, i.Key.ProductionYear) })
                                        .Where(i => i.Score > 0)
                                        .OrderByDescending(i => i.Score)
                                        .Select(i => i.Ref)
                                        .FirstOrDefault();
                    finalResult = filtredResult?.Result.First();
                }

                if (finalResult != null)
                {
                    // We are in the good position, we can create the item
                    var organizationRequest = new MovieFileOrganizationRequest
                    {
                        NewMovieName        = finalResult.Name,
                        NewMovieProviderIds = finalResult.ProviderIds,
                        NewMovieYear        = finalResult.ProductionYear,
                        TargetFolder        = options.DefaultMovieLibraryPath
                    };

                    var movie = CreateNewMovie(organizationRequest, result, options);

                    return(new Tuple <Movie, RemoteSearchResult>(movie, finalResult));
                }
            }

            return(null);
        }
Example #3
0
        private Task OrganizeMovie(
            string sourcePath,
            Movie movie,
            MovieFileOrganizationOptions options,
            bool overwriteExisting,
            FileOrganizationResult result,
            CancellationToken cancellationToken)
        {
            _logger.LogInformation("Sorting file {0} into movie {1}", sourcePath, movie.Path);

            bool isNew = string.IsNullOrWhiteSpace(result.Id);

            if (isNew)
            {
                _organizationService.SaveResult(result, cancellationToken);
            }

            if (!_organizationService.AddToInProgressList(result, isNew))
            {
                throw new OrganizationException("File is currently processed otherwise. Please try again later.");
            }

            try
            {
                // Proceed to sort the file
                var newPath = movie.Path;
                _logger.LogInformation("Sorting file {0} to new path {1}", sourcePath, newPath);
                result.TargetPath = newPath;

                var fileExists = File.Exists(result.TargetPath);

                if (!overwriteExisting)
                {
                    if (options.CopyOriginalFile && fileExists && IsSameMovie(sourcePath, newPath))
                    {
                        var msg = $"File '{sourcePath}' already copied to new path '{newPath}', stopping organization";
                        _logger.LogInformation(msg);
                        result.Status        = FileSortingStatus.SkippedExisting;
                        result.StatusMessage = msg;
                        return(Task.CompletedTask);
                    }

                    if (fileExists)
                    {
                        var msg = $"File '{sourcePath}' already exists as '{newPath}', stopping organization";
                        _logger.LogInformation(msg);
                        result.Status        = FileSortingStatus.SkippedExisting;
                        result.StatusMessage = msg;
                        result.TargetPath    = newPath;
                        return(Task.CompletedTask);
                    }
                }

                PerformFileSorting(options, result);
            }
            catch (OrganizationException ex)
            {
                result.Status        = FileSortingStatus.Failure;
                result.StatusMessage = ex.Message;
            }
            catch (Exception ex)
            {
                result.Status        = FileSortingStatus.Failure;
                result.StatusMessage = ex.Message;
                _logger.LogError(ex, "Caught a generic exception while organizing {0}", sourcePath);
            }
            finally
            {
                _organizationService.RemoveFromInprogressList(result);
            }

            return(Task.CompletedTask);
        }
Example #4
0
        /// <summary>
        /// Organize a movie media file with user-supplied parameters.
        /// </summary>
        /// <param name="request">The user supplied parameters provided via API request.</param>
        /// <param name="options">The organize options to use.</param>
        /// <param name="cancellationToken">A cancellation token for the operation.</param>
        /// <returns>A task representing the operation completion and containing the operation result.</returns>
        public async Task <FileOrganizationResult> OrganizeWithCorrection(MovieFileOrganizationRequest request, MovieFileOrganizationOptions options, CancellationToken cancellationToken)
        {
            var result = _organizationService.GetResult(request.ResultId);

            try
            {
                Movie movie = null;

                if (request.NewMovieProviderIds.Count > 0)
                {
                    // To avoid Series duplicate by mistake (Missing SmartMatch and wrong selection in UI)
                    movie = CreateNewMovie(request, result, options);
                }

                if (movie == null)
                {
                    // Existing movie
                    movie = (Movie)_libraryManager.GetItemById(request.MovieId);
                }

                // We manually set the media as Movie
                result.Type = CurrentFileOrganizerType;

                await OrganizeMovie(
                    result.OriginalPath,
                    movie,
                    options,
                    true,
                    result,
                    cancellationToken).ConfigureAwait(false);

                _organizationService.SaveResult(result, CancellationToken.None);
            }
            catch (Exception ex)
            {
                result.Status        = FileSortingStatus.Failure;
                result.StatusMessage = ex.Message;
            }

            return(result);
        }
Example #5
0
        private Movie CreateNewMovie(MovieFileOrganizationRequest request, FileOrganizationResult result, MovieFileOrganizationOptions options)
        {
            // To avoid Movie duplicate by mistake (Missing SmartMatch and wrong selection in UI)
            var movie = GetMatchingMovie(request.NewMovieName, request.NewMovieYear, request.TargetFolder, result);

            if (movie == null)
            {
                // We're having a new movie here
                movie = new Movie
                {
                    Id              = Guid.NewGuid(),
                    Name            = request.NewMovieName,
                    ProductionYear  = request.NewMovieYear,
                    IsInMixedFolder = !options.MovieFolder,
                    ProviderIds     = request.NewMovieProviderIds.ToDictionary(x => x.Key, x => x.Value),
                };

                var newPath = GetMoviePath(result.OriginalPath, movie, options);

                if (string.IsNullOrEmpty(newPath))
                {
                    var msg = $"Unable to sort {result.OriginalPath} because target path could not be determined.";
                    throw new OrganizationException(msg);
                }

                movie.Path = Path.Combine(request.TargetFolder, newPath);
            }

            return(movie);
        }
Example #6
0
        /// <summary>
        /// Organize a movie media file.
        /// </summary>
        /// <param name="path">The filepath of the movie.</param>
        /// <param name="options">The organize options to use.</param>
        /// <param name="overwriteExisting">If true, any existing file at the same destination path will be overwritten.</param>
        /// <param name="cancellationToken">A cancellation token for the operation.</param>
        /// <returns>A task representing the operation completion and containing the operation result.</returns>
        public async Task <FileOrganizationResult> OrganizeMovieFile(
            string path,
            MovieFileOrganizationOptions options,
            bool overwriteExisting,
            CancellationToken cancellationToken)
        {
            _logger.LogInformation("Sorting file {0}", path);

            var result = new FileOrganizationResult
            {
                Date             = DateTime.UtcNow,
                OriginalPath     = path,
                OriginalFileName = Path.GetFileName(path),
                Type             = FileOrganizerType.Unknown,
                FileSize         = _fileSystem.GetFileInfo(path).Length
            };

            try
            {
                if (_libraryMonitor.IsPathLocked(path))
                {
                    result.Status        = FileSortingStatus.Failure;
                    result.StatusMessage = "Path is locked by other processes. Please try again later.";
                    _logger.LogInformation("Auto-organize Path is locked by other processes. Please try again later.");
                    return(result);
                }

                _namingOptions = _namingOptions ?? new NamingOptions();
                var resolver = new VideoResolver(_namingOptions);

                var movieInfo = resolver.Resolve(path, false) ??
                                new VideoFileInfo();

                var movieName = movieInfo.Name;

                if (!string.IsNullOrEmpty(movieName))
                {
                    var movieYear = movieInfo.Year;

                    _logger.LogDebug("Extracted information from {0}. Movie {1}, Year {2}", path, movieName, movieYear);

                    await OrganizeMovie(
                        path,
                        movieName,
                        movieYear,
                        options,
                        overwriteExisting,
                        result,
                        cancellationToken).ConfigureAwait(false);
                }
                else
                {
                    var msg = "Unable to determine movie name from " + path;
                    result.Status        = FileSortingStatus.Failure;
                    result.StatusMessage = msg;
                    _logger.LogWarning(msg);
                }

                // Handle previous result
                var previousResult = _organizationService.GetResultBySourcePath(path);

                if ((previousResult != null && result.Type == FileOrganizerType.Unknown) || (previousResult?.Status == result.Status &&
                                                                                             previousResult?.StatusMessage == result.StatusMessage &&
                                                                                             result.Status != FileSortingStatus.Success))
                {
                    // Don't keep saving the same result over and over if nothing has changed
                    return(previousResult);
                }
            }
            catch (Exception ex)
            {
                result.Status        = FileSortingStatus.Failure;
                result.StatusMessage = ex.Message;
                _logger.LogError(ex, "Error organizing file {0}", path);
            }

            _organizationService.SaveResult(result, CancellationToken.None);

            return(result);
        }