예제 #1
0
        public async Task <bool> process(
            string filePath,
            Action <string> setPath,
            Action <string, MessageType> setStatus,
            Func <List <Tuple <string, string> >, int> selectResult,
            AutoTagConfig config
            )
        {
            if (tvdb.Authentication.Token == null)
            {
                await tvdb.Authentication.AuthenticateAsync(apiKey);
            }

            FileMetadata result = new FileMetadata(FileMetadata.Types.TV);

            #region Filename parsing
            FileMetadata episodeData;

            if (string.IsNullOrEmpty(config.parsePattern))
            {
                try {
                    episodeData = EpisodeParser.ParseEpisodeInfo(Path.GetFileName(filePath)); // Parse info from filename
                } catch (FormatException ex) {
                    setStatus($"Error: {ex.Message}", MessageType.Error);
                    return(false);
                }
            }
            else
            {
                try {
                    var match = Regex.Match(Path.GetFullPath(filePath), config.parsePattern, RegexOptions.IgnoreCase | RegexOptions.CultureInvariant);

                    episodeData            = new FileMetadata(FileMetadata.Types.TV);
                    episodeData.SeriesName = match.Groups["SeriesName"].Value;
                    episodeData.Season     = int.Parse(match.Groups["Season"].Value);
                    episodeData.Episode    = int.Parse(match.Groups["Episode"].Value);
                } catch (FormatException ex) {
                    if (config.verbose)
                    {
                        setStatus($"Error: Unable to parse required information from filename ({ex.GetType().Name}: {ex.Message})", MessageType.Error);
                    }
                    else
                    {
                        setStatus($"Error: Unable to parse required information from filename", MessageType.Error);
                    }
                    return(false);
                }
            }

            result.Season  = episodeData.Season;
            result.Episode = episodeData.Episode;

            setStatus($"Parsed file as {episodeData}", MessageType.Information);
            #endregion

            #region TVDB API searching
            if (!seriesResultCache.ContainsKey(episodeData.SeriesName))   // if not already searched for series
            {
                TvDbResponse <SeriesSearchResult[]> seriesIdResponse;
                try {
                    seriesIdResponse = await tvdb.Search.SearchSeriesByNameAsync(episodeData.SeriesName);
                } catch (TvDbServerException ex) {
                    if (config.verbose)
                    {
                        setStatus($"Error: Cannot find series {episodeData.SeriesName} ({ex.GetType().Name}: {ex.Message})", MessageType.Error);
                    }
                    else
                    {
                        setStatus($"Error: Cannot find series {episodeData.SeriesName} on TheTVDB", MessageType.Error);
                    }
                    return(false);
                }

                // sort results by similarity to parsed series name
                List <SeriesSearchResult> seriesResults = seriesIdResponse.Data
                                                          .OrderByDescending(seriesResult => SeriesNameSimilarity(episodeData.SeriesName, seriesResult.SeriesName))
                                                          .ToList();

                if (config.manualMode && seriesResults.Count > 1)
                {
                    int chosen = selectResult(seriesResults.Select(
                                                  r => new Tuple <string, string>(r.SeriesName, r.FirstAired ?? "Unknown")
                                                  ).ToList()
                                              );

                    // add only the chosen series to cache if in manual mode
                    seriesResultCache.Add(episodeData.SeriesName, new List <SeriesSearchResult> {
                        seriesResults[chosen]
                    });
                }
                else
                {
                    seriesResultCache.Add(episodeData.SeriesName, seriesResults);
                }
            }

            // try searching for each series search result
            foreach (var series in seriesResultCache[episodeData.SeriesName])
            {
                result.Id         = series.Id;
                result.SeriesName = series.SeriesName;

                try {
                    TvDbResponse <EpisodeRecord[]> episodeResponse = await tvdb.Series.GetEpisodesAsync(series.Id, 1,
                                                                                                        new EpisodeQuery {
                        AiredSeason  = episodeData.Season,
                        AiredEpisode = episodeData.Episode
                    }
                                                                                                        );

                    result.Title    = episodeResponse.Data[0].EpisodeName;
                    result.Overview = episodeResponse.Data[0].Overview;

                    break;
                } catch (TvDbServerException ex) {
                    if (series.Id == seriesResultCache[episodeData.SeriesName].Last().Id)
                    {
                        if (config.verbose)
                        {
                            setStatus($"Error: Cannot find {episodeData} ({ex.GetType().Name}: {ex.Message})", MessageType.Error);
                        }
                        else
                        {
                            setStatus($"Error: Cannot find {episodeData} on TheTVDB", MessageType.Error);
                        }
                        return(false);
                    }
                }
            }

            setStatus($"Found {episodeData} ({result.Title}) on TheTVDB", MessageType.Information);

            TvDbResponse <TvDbSharper.Dto.Image[]> imagesResponse = null;

            if (config.addCoverArt)
            {
                try {
                    imagesResponse = await tvdb.Series.GetImagesAsync(result.Id, new ImagesQuery {
                        KeyType = KeyType.Season,
                        SubKey  = episodeData.Season.ToString()
                    });
                } catch (TvDbServerException) {
                    try {
                        // use a series image if a season-specific image is not available
                        imagesResponse = await tvdb.Series.GetImagesAsync(result.Id, new ImagesQuery {
                            KeyType = KeyType.Series
                        });
                    } catch (TvDbServerException ex) {
                        if (config.verbose)
                        {
                            setStatus($"Error: Failed to find episode cover ({ex.GetType().Name}: {ex.Message})", MessageType.Error);
                        }
                        else
                        {
                            setStatus("Error: Failed to find episode cover", MessageType.Error);
                        }
                        result.Complete = false;
                    }
                }
            }

            string imageFilename = "";
            if (imagesResponse != null)
            {
                imageFilename = imagesResponse.Data
                                .OrderByDescending(img => img.RatingsInfo.Average)
                                .First().FileName; // Find highest rated image
            }
            #endregion

            result.CoverURL = (String.IsNullOrEmpty(imageFilename)) ? null : $"https://artworks.thetvdb.com/banners/{imageFilename}";

            result.CoverFilename = imageFilename.Split('/').Last();

            bool taggingSuccess = FileWriter.write(filePath, result, setPath, setStatus, config);

            return(taggingSuccess && result.Success && result.Complete);
        }
예제 #2
0
        public async Task <bool> process(
            string filePath,
            Action <string> setPath,
            Action <string, MessageType> setStatus,
            Func <List <Tuple <string, string> >, int> selectResult,
            AutoTagConfig config
            )
        {
            FileMetadata result = new FileMetadata(FileMetadata.Types.Movie);

            #region "Filename parsing"
            string pattern =
                "^((?<Title>.+?)[\\. _-]?)" +                                                                                                                                                                // get title by reading from start to a field (whichever field comes first)
                "?(" +
                "([\\(]?(?<Year>(19|20)[0-9]{2})[\\)]?)|" +                                                                                                                                                  // year - extract for use in searching
                "([0-9]{3,4}(p|i))|" +                                                                                                                                                                       // resolution (e.g. 1080p, 720i)
                "((?:PPV\\.)?[HPS]DTV|[. ](?:HD)?CAM[| ]|B[DR]Rip|[.| ](?:HD-?)?TS[.| ]|(?:PPV )?WEB-?DL(?: DVDRip)?|HDRip|DVDRip|CamRip|W[EB]Rip|BluRay|DvDScr|hdtv|REMUX|3D|Half-(OU|SBS)+|4K|NF|AMZN)|" + // rip type
                "(xvid|[hx]\\.?26[45]|AVC)|" +                                                                                                                                                               // video codec
                "(MP3|DD5\\.?1|Dual[\\- ]Audio|LiNE|DTS[-HD]+|AAC[.-]LC|AAC(?:\\.?2\\.0)?|AC3(?:\\.5\\.1)?|7\\.1|DDP5.1)|" +                                                                                 // audio codec
                "(REPACK|INTERNAL|PROPER)|" +                                                                                                                                                                // scene tags
                "\\.(mp4|m4v|mkv)$" +                                                                                                                                                                        // file extensions
                ")";

            Match  match = Regex.Match(Path.GetFileName(filePath), pattern);
            string title, year;
            if (match.Success)
            {
                title = match.Groups["Title"].ToString();
                year  = match.Groups["Year"].ToString();
            }
            else
            {
                setStatus("Error: Failed to parse required information from filename", MessageType.Error);
                return(false);
            }

            title = title.Replace('.', ' '); // change dots to spaces

            if (String.IsNullOrWhiteSpace(title))
            {
                setStatus("Error: Failed to parse required information from filename", MessageType.Error);
                return(false);
            }

            setStatus($"Parsed file as {title}", MessageType.Information);
            #endregion

            #region "TMDB API Searching"
            SearchContainer <SearchMovie> searchResults;
            if (!String.IsNullOrWhiteSpace(year))
            {
                searchResults = await tmdb.SearchMovieAsync(query : title, year : int.Parse(year)); // if year was parsed, use it to narrow down search further
            }
            else
            {
                searchResults = await tmdb.SearchMovieAsync(query : title);
            }

            int selected = 0;

            if (searchResults.Results.Count > 1 && (searchResults.Results[0].Title != title || config.manualMode))
            {
                selected = selectResult(
                    searchResults.Results
                    .Select(m => new Tuple <string, string>(
                                m.Title,
                                m.ReleaseDate == null ? "Unknown" : m.ReleaseDate.Value.Year.ToString()
                                )).ToList()
                    );
            }
            else if (searchResults.Results.Count == 0)
            {
                setStatus($"Error: failed to find title {title} on TheMovieDB", MessageType.Error);
                result.Success = false;
                return(false);
            }

            SearchMovie selectedResult = searchResults.Results[selected];

            setStatus($"Found {selectedResult.Title} ({selectedResult.ReleaseDate.Value.Year}) on TheMovieDB", MessageType.Information);
            #endregion

            result.Title         = selectedResult.Title;
            result.Overview      = selectedResult.Overview;
            result.CoverURL      = (String.IsNullOrEmpty(selectedResult.PosterPath)) ? null : $"https://image.tmdb.org/t/p/original{selectedResult.PosterPath}";
            result.CoverFilename = selectedResult.PosterPath.Replace("/", "");
            result.Date          = selectedResult.ReleaseDate.Value;

            if (String.IsNullOrEmpty(result.CoverURL))
            {
                setStatus("Error: failed to fetch movie cover", MessageType.Error);
                result.Complete = false;
            }

            bool taggingSuccess = FileWriter.write(filePath, result, setPath, setStatus, config);

            return(taggingSuccess && result.Success && result.Complete);
        }