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); }
private Movie CreateNewMovie(MovieFileOrganizationRequest request, BaseItem targetFolder, FileOrganizationResult result, MovieFileOrganizationOptions options, CancellationToken cancellationToken) { // To avoid Movie duplicate by mistake (Missing SmartMatch and wrong selection in UI) var movie = GetMatchingMovie(request.NewMovieName, request.NewMovieYear, targetFolder, result, options); if (movie == null) { // We're having a new movie here movie = new Movie { Name = request.NewMovieName, ProductionYear = request.NewMovieYear, IsInMixedFolder = !options.MovieFolder, ProviderIds = request.NewMovieProviderIds, }; var newPath = GetMoviePath(result.OriginalPath, movie, options); if (string.IsNullOrEmpty(newPath)) { var msg = string.Format("Unable to sort {0} because target path could not be determined.", result.OriginalPath); throw new OrganizationException(msg); } movie.Path = Path.Combine(request.TargetFolder, newPath); } return(movie); }
public void PerformOrganization(MovieFileOrganizationRequest request) { var organizer = new MovieFileOrganizer(this, _config, _fileSystem, _logger, _libraryManager, _libraryMonitor, _providerManager); var options = GetAutoOrganizeOptions(); var result = organizer.OrganizeWithCorrection(request, options.MovieOptions, CancellationToken.None); }
public FileOrganizationResult OrganizeWithCorrection(MovieFileOrganizationRequest request, MovieFileOrganizationOptions options, CancellationToken cancellationToken) { var result = _organizationService.GetResult(request.ResultId); try { Movie movie = null; if (request.NewMovieProviderIds.Count > 0) { BaseItem targetFolder = null; if (!string.IsNullOrEmpty(options.DefaultMovieLibraryPath)) { targetFolder = _libraryManager.FindByPath(options.DefaultMovieLibraryPath, true); } // To avoid Series duplicate by mistake (Missing SmartMatch and wrong selection in UI) movie = CreateNewMovie(request, targetFolder, result, options, cancellationToken); } if (movie == null) { // Existing movie movie = (Movie)_libraryManager.GetItemById(request.MovieId); var newPath = GetMoviePath(result.OriginalPath, movie, options); var targetFolder = _libraryManager .GetVirtualFolders() .Where(i => string.Equals(i.CollectionType, CollectionType.Movies.ToString(), StringComparison.OrdinalIgnoreCase)) .FirstOrDefault() .Locations .Where(i => movie.Path.Contains(i)) .FirstOrDefault(); movie.Path = Path.Combine(targetFolder, newPath); } // We manually set the media as Movie result.Type = CurrentFileOrganizerType; OrganizeMovie(result.OriginalPath, movie, options, null, result, cancellationToken); _organizationService.SaveResult(result, CancellationToken.None); } catch (Exception ex) { result.Status = FileSortingStatus.Failure; result.StatusMessage = ex.Message; _logger.ErrorException("Error organizing file {0}", ex, result.OriginalPath); } return(result); }
/// <inheritdoc/> public async Task PerformOrganization(MovieFileOrganizationRequest request) { var organizer = new MovieFileOrganizer(this, _fileSystem, _logger, _libraryManager, _libraryMonitor, _providerManager); var options = _config.GetAutoOrganizeOptions(); var result = await organizer.OrganizeWithCorrection(request, options.MovieOptions, CancellationToken.None).ConfigureAwait(false); if (result.Status != FileSortingStatus.Success) { throw new Exception(result.StatusMessage); } }
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, cancellationToken); } if (movie == null) { // Existing movie movie = (Movie)_libraryManager.GetItemById(request.MovieId); var newPath = GetMoviePath(result.OriginalPath, movie, options); var targetFolder = _libraryManager .GetVirtualFolders() .Where(i => i.CollectionType == CollectionType.Movies) .FirstOrDefault() .Locations .Where(i => movie.Path.Contains(i)) .FirstOrDefault(); movie.Path = Path.Combine(targetFolder, newPath); } // We manually set the media as Movie result.Type = CurrentFileOrganizerType; await OrganizeMovie(result.OriginalPath, movie, options, null, result, cancellationToken).ConfigureAwait(false); _organizationService.SaveResult(result, CancellationToken.None); } catch (Exception ex) { result.Status = FileSortingStatus.Failure; result.StatusMessage = ex.Message; } return(result); }
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.OriginalPath, options, cancellationToken); } if (movie == null) { // Existing movie movie = (Movie)_libraryManager.GetItemById(new Guid(request.MovieId)); } // We manually set the media as Movie result.Type = CurrentFileOrganizerType; await OrganizeMovie(result.OriginalPath, movie, options, null, true, result, cancellationToken).ConfigureAwait(false); await _organizationService.SaveResult(result, CancellationToken.None).ConfigureAwait(false); } catch (Exception ex) { result.Status = FileSortingStatus.Failure; result.StatusMessage = ex.Message; } return(result); }
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.AsSpan()); var yearInName = parsedName.Year; var nameWithoutYear = parsedName.Name; if (string.IsNullOrWhiteSpace(nameWithoutYear)) { nameWithoutYear = movieName; } if (!yearInName.HasValue) { yearInName = movieYear; } string metadataLanguage = null; string metadataCountryCode = null; BaseItem targetFolder = null; if (!string.IsNullOrEmpty(options.DefaultMovieLibraryPath)) { targetFolder = _libraryManager.FindByPath(options.DefaultMovieLibraryPath, true); } if (targetFolder != null) { metadataLanguage = targetFolder.GetPreferredMetadataLanguage(); metadataCountryCode = targetFolder.GetPreferredMetadataCountryCode(); } var movieInfo = new MovieInfo { Name = nameWithoutYear, Year = yearInName, MetadataCountryCode = metadataCountryCode, MetadataLanguage = metadataLanguage }; var searchResultsTask = await _providerManager.GetRemoteSearchResults <Movie, MovieInfo>(new RemoteSearchQuery <MovieInfo> { SearchInfo = movieInfo }, targetFolder, cancellationToken); var finalResult = searchResultsTask.FirstOrDefault(); 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, targetFolder, result, options, cancellationToken); return(new Tuple <Movie, RemoteSearchResult>(movie, finalResult)); } } return(null); }
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; } #region Search One var movieInfo = new MovieInfo { Name = nameWithoutYear, Year = yearInName, }; var searchResultsTask = await _providerManager.GetRemoteSearchResults <Movie, MovieInfo>(new RemoteSearchQuery <MovieInfo> { SearchInfo = movieInfo }, cancellationToken); #endregion // 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.OriginalPath, options, cancellationToken); return(new Tuple <Movie, RemoteSearchResult>(movie, finalResult)); } } return(null); }