private Series CreateNewSeries(
            EpisodeFileOrganizationRequest request,
            BaseItem targetFolder,
            RemoteSearchResult result,
            TvFileOrganizationOptions options,
            CancellationToken cancellationToken)
        {
            Series series;

            series = GetMatchingSeries(request.NewSeriesName, request.NewSeriesYear, targetFolder, null);

            if (series != null)
            {
                return(series);
            }

            var seriesFolderName = GetSeriesDirectoryName(request.NewSeriesName, request.NewSeriesYear, options);

            var seriesName = request.NewSeriesName;
            var seriesPath = Path.Combine(request.TargetFolder, seriesFolderName);

            return(new Series
            {
                Name = seriesName,
                Path = seriesPath,
                ProviderIds = request.NewSeriesProviderIds,
                ProductionYear = request.NewSeriesYear
            });
        }
        public async Task PerformEpisodeOrganization(EpisodeFileOrganizationRequest request)
        {
            var organizer = new EpisodeFileOrganizer(this, _config, _fileSystem, _logger, _libraryManager,
                                                     _libraryMonitor, _providerManager);

            await organizer.OrganizeWithCorrection(request, _config.Configuration.TvFileOrganizationOptions, CancellationToken.None).ConfigureAwait(false);
        }
        public async Task PerformOrganization(EpisodeFileOrganizationRequest request)
        {
            var organizer = new EpisodeFileOrganizer(this, _config, _fileSystem, _logger, _libraryManager,
                                                     _libraryMonitor, _providerManager);

            var options = GetAutoOrganizeOptions();
            var result  = await organizer.OrganizeWithCorrection(request, options.TvOptions, CancellationToken.None).ConfigureAwait(false);
        }
예제 #4
0
        public async Task <FileOrganizationResult> OrganizeWithCorrection(EpisodeFileOrganizationRequest request, AutoOrganizeOptions options, CancellationToken cancellationToken)
        {
            var result = _organizationService.GetResult(request.ResultId);

            Series series = null;

            if (request.NewSeriesProviderIds.Count > 0)
            {
                // We're having a new series here
                SeriesInfo seriesRequest = new SeriesInfo();
                seriesRequest.ProviderIds = request.NewSeriesProviderIds;

                var refreshOptions = new MetadataRefreshOptions(_fileSystem);
                series      = new Series();
                series.Id   = Guid.NewGuid();
                series.Name = request.NewSeriesName;

                int year;
                if (int.TryParse(request.NewSeriesYear, out year))
                {
                    series.ProductionYear = year;
                }

                var seriesFolderName = series.Name;
                if (series.ProductionYear.HasValue)
                {
                    seriesFolderName = string.Format("{0} ({1})", seriesFolderName, series.ProductionYear);
                }

                series.Path = Path.Combine(request.TargetFolder, seriesFolderName);

                series.ProviderIds = request.NewSeriesProviderIds;

                await series.RefreshMetadata(refreshOptions, cancellationToken);
            }

            if (series == null)
            {
                // Existing Series
                series = (Series)_libraryManager.GetItemById(new Guid(request.SeriesId));
            }

            await OrganizeEpisode(result.OriginalPath,
                                  series,
                                  request.SeasonNumber,
                                  request.EpisodeNumber,
                                  request.EndingEpisodeNumber,
                                  null,
                                  options,
                                  true,
                                  request.RememberCorrection,
                                  result,
                                  cancellationToken).ConfigureAwait(false);

            await _organizationService.SaveResult(result, CancellationToken.None).ConfigureAwait(false);

            return(result);
        }
예제 #5
0
        private async Task <Series> AutoDetectSeries(
            string seriesName,
            int?seriesYear,
            TvFileOrganizationOptions options,
            CancellationToken cancellationToken)
        {
            if (options.AutoDetectSeries)
            {
                RemoteSearchResult finalResult = null;

                // Perform remote search
                var seriesInfo = new SeriesInfo {
                    Name = seriesName, Year = seriesYear
                };
                var searchQuery = new RemoteSearchQuery <SeriesInfo> {
                    SearchInfo = seriesInfo
                };
                var searchResults = await _providerManager.GetRemoteSearchResults <Series, SeriesInfo>(searchQuery, cancellationToken).ConfigureAwait(false);

                // Group series by name and year (if 2 series with the exact same name, the same year ...)
                var groupedResult = searchResults.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(seriesName, seriesYear, 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 EpisodeFileOrganizationRequest
                    {
                        NewSeriesName        = finalResult.Name,
                        NewSeriesProviderIds = finalResult.ProviderIds,
                        NewSeriesYear        = finalResult.ProductionYear,
                        TargetFolder         = options.DefaultSeriesLibraryPath
                    };

                    return(await CreateNewSeries(organizationRequest, finalResult, options, cancellationToken).ConfigureAwait(false));
                }
            }

            return(null);
        }
        private async Task <Series> AutoDetectSeries(
            string seriesName,
            int?seriesYear,
            TvFileOrganizationOptions options,
            CancellationToken cancellationToken)
        {
            if (options.AutoDetectSeries)
            {
                string   metadataLanguage    = null;
                string   metadataCountryCode = null;
                BaseItem targetFolder        = null;

                if (!string.IsNullOrEmpty(options.DefaultSeriesLibraryPath))
                {
                    targetFolder = _libraryManager.FindByPath(options.DefaultSeriesLibraryPath, true);
                }

                if (targetFolder != null)
                {
                    metadataLanguage    = targetFolder.GetPreferredMetadataLanguage();
                    metadataCountryCode = targetFolder.GetPreferredMetadataCountryCode();
                }

                var seriesInfo = new SeriesInfo
                {
                    Name = seriesName,
                    Year = seriesYear,
                    MetadataCountryCode = metadataCountryCode,
                    MetadataLanguage    = metadataLanguage
                };

                var searchResultsTask = await _providerManager.GetRemoteSearchResults <Series, SeriesInfo>(new RemoteSearchQuery <SeriesInfo>
                {
                    SearchInfo = seriesInfo
                }, targetFolder, cancellationToken);

                var finalResult = searchResultsTask.FirstOrDefault();

                if (finalResult != null)
                {
                    // We are in the good position, we can create the item
                    var organizationRequest = new EpisodeFileOrganizationRequest
                    {
                        NewSeriesName        = finalResult.Name,
                        NewSeriesProviderIds = finalResult.ProviderIds,
                        NewSeriesYear        = finalResult.ProductionYear,
                        TargetFolder         = options.DefaultSeriesLibraryPath
                    };

                    return(CreateNewSeries(organizationRequest, targetFolder, finalResult, options, cancellationToken));
                }
            }

            return(null);
        }
예제 #7
0
        public async Task <FileOrganizationResult> OrganizeWithCorrection(
            EpisodeFileOrganizationRequest request,
            TvFileOrganizationOptions options,
            CancellationToken cancellationToken)
        {
            var result = _organizationService.GetResult(request.ResultId);

            try
            {
                Series series = null;

                if (request.NewSeriesProviderIds.Count > 0)
                {
                    BaseItem targetFolder = null;

                    if (!string.IsNullOrEmpty(options.DefaultSeriesLibraryPath))
                    {
                        targetFolder = _libraryManager.FindByPath(options.DefaultSeriesLibraryPath, true);
                    }

                    series = CreateNewSeries(request, targetFolder, null, options, cancellationToken);
                }

                if (series == null)
                {
                    // Existing Series
                    series = (Series)_libraryManager.GetItemById(request.SeriesId);
                }

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

                await OrganizeEpisode(result.OriginalPath,
                                      series,
                                      request.SeasonNumber,
                                      request.EpisodeNumber,
                                      request.EndingEpisodeNumber,
                                      null,
                                      options,
                                      request.RememberCorrection,
                                      result,
                                      cancellationToken).ConfigureAwait(false);

                _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);
        }
예제 #8
0
        public async Task <FileOrganizationResult> OrganizeWithCorrection(EpisodeFileOrganizationRequest request, TvFileOrganizationOptions options, CancellationToken cancellationToken)
        {
            var result = _organizationService.GetResult(request.ResultId);

            var series = (Series)_libraryManager.GetItemById(new Guid(request.SeriesId));

            await OrganizeEpisode(result.OriginalPath, series, request.SeasonNumber, request.EpisodeNumber, request.EndingEpisodeNumber, options, true, result, cancellationToken).ConfigureAwait(false);

            await _organizationService.SaveResult(result, CancellationToken.None).ConfigureAwait(false);

            return(result);
        }
예제 #9
0
        public async Task PerformEpisodeOrganization(EpisodeFileOrganizationRequest request)
        {
            var organizer = new EpisodeFileOrganizer(this, _config, _fileSystem, _logger, _libraryManager,
                                                     _libraryMonitor, _providerManager);

            var result = await organizer.OrganizeWithCorrection(request, GetAutoOrganizeOptions(), CancellationToken.None).ConfigureAwait(false);

            if (result.Status != FileSortingStatus.Success)
            {
                throw new Exception(result.StatusMessage);
            }
        }
예제 #10
0
        private async Task <Series> CreateNewSeries(
            EpisodeFileOrganizationRequest request,
            RemoteSearchResult result,
            TvFileOrganizationOptions options,
            CancellationToken cancellationToken)
        {
            Series series;

            // Ensure that we don't create the same series multiple time
            // We create series one at a time
            var seriesCreationLock = new Object();

            lock (seriesCreationLock)
            {
                series = GetMatchingSeries(request.NewSeriesName, request.NewSeriesYear, request.TargetFolder, null);

                if (series == null)
                {
                    // We're having a new series here

                    series = new Series
                    {
                        Id             = Guid.NewGuid(),
                        Name           = request.NewSeriesName,
                        ProductionYear = request.NewSeriesYear
                    };

                    var seriesFolderName = GetSeriesDirectoryName(series, options);

                    series.Path = Path.Combine(request.TargetFolder, seriesFolderName);

                    // Create the folder
                    _fileSystem.CreateDirectory(series.Path);

                    series.ProviderIds = request.NewSeriesProviderIds;

                    _libraryManager.CreateItem(series, null);
                }
            }

            // async outside of the lock for perfs
            var refreshOptions = new MetadataRefreshOptions(_fileSystem)
            {
                SearchResult = result
            };
            await series.RefreshMetadata(refreshOptions, cancellationToken).ConfigureAwait(false);

            return(series);
        }
예제 #11
0
        /// <summary>
        /// Organize an episode file with parameters provided by the end-user.
        /// </summary>
        /// <param name="request">The parameters provided by the user via API request.</param>
        /// <param name="options">The organization options to use.</param>
        /// <param name="cancellationToken">A cancellation token for the operation.</param>
        /// <returns>A task representing the organization operation and containing the operation result.</returns>
        public async Task <FileOrganizationResult> OrganizeWithCorrection(
            EpisodeFileOrganizationRequest request,
            TvFileOrganizationOptions options,
            CancellationToken cancellationToken)
        {
            var result = _organizationService.GetResult(request.ResultId);

            try
            {
                Series series = null;

                if (request.NewSeriesProviderIds.Count > 0)
                {
                    series = await CreateNewSeries(request, null, options, cancellationToken).ConfigureAwait(false);
                }

                if (series == null)
                {
                    // Existing Series
                    series = (Series)_libraryManager.GetItemById(request.SeriesId);
                }

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

                await OrganizeEpisode(
                    result.OriginalPath,
                    series,
                    request.SeasonNumber,
                    request.EpisodeNumber,
                    request.EndingEpisodeNumber,
                    null,
                    options,
                    request.RememberCorrection,
                    result,
                    cancellationToken).ConfigureAwait(false);

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

            return(result);
        }