private void ProcessFolder(TVDoc.ScanSettings settings, [NotNull] ItemMissing me, [NotNull] string folderName, [NotNull] DirFilesCache dfc,
                                   ItemList thisRound, [NotNull] List <FileInfo> matchedFiles)
        {
            LOGGER.Info($"Starting to look for {me.Filename} in the library folder: {folderName}");
            FileInfo[] files = dfc.GetFiles(folderName);
            if (files is null)
            {
                return;
            }

            foreach (FileInfo testFile in files)
            {
                if (!ReviewFile(me, thisRound, testFile, settings, false, false, false,
                                TVSettings.Instance.UseFullPathNameToMatchLibraryFolders))
                {
                    continue;
                }

                if (!matchedFiles.Contains(testFile))
                {
                    matchedFiles.Add(testFile);
                    LOGGER.Info($"Found {me.Filename} at: {testFile}");
                }
            }
        }
Пример #2
0
        private void TestShouldMove(string sourceFolder, string targetFolder, DirFilesCache dfc, ItemList newList, ItemList toRemove, MovieItemMissing mim)
        {
            if (sourceFolder == targetFolder)
            {
                return;
            }

            if (dfc.GetFiles(targetFolder).Length > 0)
            {
                //do not want to copy any files over new location
                return;
            }

            if (!Directory.Exists(sourceFolder) || dfc.GetFiles(sourceFolder).Length == 0)
            {
                return;
            }
            LOGGER.Info($"Have identified that {sourceFolder} can be copied to {targetFolder}");

            toRemove.Add(mim);
            newList.Add(new ActionMoveRenameDirectory(sourceFolder, targetFolder, mim.MovieConfig));
        }
Пример #3
0
        public static List <FileInfo> FindEpOnDisk([CanBeNull] DirFilesCache dfc, [NotNull] ShowItem si, [NotNull] Episode epi,
                                                   bool checkDirectoryExist = true)
        {
            DirFilesCache cache = dfc ?? new DirFilesCache();

            List <FileInfo> ret = new List <FileInfo>();

            int seasWanted = si.DvdOrder ? epi.TheDvdSeason.SeasonNumber : epi.TheAiredSeason.SeasonNumber;
            int epWanted   = si.DvdOrder ? epi.DvdEpNum : epi.AiredEpNum;

            int snum = seasWanted;

            Dictionary <int, List <string> > dirs = si.AllFolderLocationsEpCheck(checkDirectoryExist);

            if (!dirs.ContainsKey(snum))
            {
                return(ret);
            }

            foreach (string folder in dirs[snum])
            {
                FileInfo[] files = cache.GetFiles(folder);
                if (files is null)
                {
                    continue;
                }

                foreach (FileInfo fiTemp in files.Where(fiTemp => fiTemp.IsMovieFile()))
                {
                    if (!FindSeasEp(fiTemp, out int seasFound, out int epFound, out int _, si))
                    {
                        continue;
                    }

                    if (seasFound == -1)
                    {
                        seasFound = seasWanted;
                    }

                    if ((seasFound == seasWanted) && (epFound == epWanted))
                    {
                        ret.Add(fiTemp);
                    }
                }
            }

            return(ret);
        }
Пример #4
0
        private static List <FileInfo> FindEpOnDisk(DirFilesCache?dfc, ShowConfiguration si, ProcessedEpisode epi,
                                                    bool checkDirectoryExist = true)
        {
            DirFilesCache cache = dfc ?? new DirFilesCache();

            List <FileInfo> ret = new List <FileInfo>();

            int seasWanted = epi.AppropriateSeasonNumber;
            int epWanted   = epi.AppropriateEpNum;

            int snum = seasWanted;

            Dictionary <int, SafeList <string> > dirs = si.AllFolderLocationsEpCheck(checkDirectoryExist);

            if (!dirs.ContainsKey(snum))
            {
                return(ret);
            }

            foreach (string folder in dirs[snum])
            {
                FileInfo[] files = cache.GetFiles(folder);

                foreach (FileInfo fiTemp in files.Where(fiTemp => fiTemp.IsMovieFile()))
                {
                    if (!FindSeasEp(fiTemp, out int seasFound, out int epFound, out int _, si))
                    {
                        continue;
                    }

                    if (seasFound == -1)
                    {
                        seasFound = seasWanted;
                    }

                    if (seasFound == seasWanted && epFound == epWanted)
                    {
                        ret.Add(fiTemp);
                    }
                }
            }

            return(ret);
        }
Пример #5
0
        private void CheckMovieFolder(MovieConfiguration si, DirFilesCache dfc, TVDoc.ScanSettings settings, string folder)
        {
            if (settings.Token.IsCancellationRequested)
            {
                return;
            }

            FileInfo[] files = dfc.GetFiles(folder);

            bool renCheck = TVSettings.Instance.RenameCheck && si.DoRename && Directory.Exists(folder); // renaming check needs the folder to exist

            bool missCheck = TVSettings.Instance.MissingCheck && si.DoMissingCheck;

            if (!renCheck && !missCheck)
            {
                return;
            }

            FileInfo[] movieFiles = files.Where(f => f.IsMovieFile()).ToArray();

            if (movieFiles.Length == 0)
            {
                FileIsMissing(si, folder, missCheck);
                return;
            }

            if (settings.Token.IsCancellationRequested)
            {
                return;
            }

            List <string> bases   = movieFiles.Select(GetBase).Distinct().ToList();
            string        newBase = TVSettings.Instance.FilenameFriendly(CustomMovieName.NameFor(si, TVSettings.Instance.MovieFilenameFormat));

            if (bases.Count == 1 && bases[0].Equals(newBase))
            {
                //All Seems OK

                //This is the code that will iterate over the DownloadIdentifiers and ask each to ensure that
                //it has all the required files for that show
                Doc.TheActionList.Add(downloadIdentifiers.ProcessMovie(si, movieFiles.First(m => m.Name.StartsWith(newBase, StringComparison.Ordinal))));

                return;
            }

            if (renCheck && bases.Count == 1 && !bases[0].Equals(newBase, StringComparison.CurrentCultureIgnoreCase))
            {
                foreach (FileInfo fi in files)
                {
                    if (settings.Token.IsCancellationRequested)
                    {
                        return;
                    }
                    string baseString = bases[0];

                    if (fi.Name.StartsWith(baseString, StringComparison.CurrentCultureIgnoreCase))
                    {
                        string   newName = fi.Name.Replace(baseString, newBase);
                        FileInfo newFile = FileHelper.FileInFolder(folder, newName); // rename updates the filename

                        if (newFile.IsMovieFile())
                        {
                            //This is the code that will iterate over the DownloadIdentifiers and ask each to ensure that
                            //it has all the required files for that show
                            Doc.TheActionList.Add(downloadIdentifiers.ProcessMovie(si, newFile));
                        }

                        if (newFile.FullName != fi.FullName)
                        {
                            //Check that the file does not already exist
                            //if (FileHelper.FileExistsCaseSensitive(newFile.FullName))
                            if (FileHelper.FileExistsCaseSensitive(files, newFile))
                            {
                                LOGGER.Warn(
                                    $"Identified that {fi.FullName} should be renamed to {newName}, but it already exists.");
                            }
                            else
                            {
                                LOGGER.Info($"Identified that {fi.FullName} should be renamed to {newName}.");
                                Doc.TheActionList.Add(new ActionCopyMoveRename(ActionCopyMoveRename.Op.rename, fi,
                                                                               newFile, si, false, null, Doc));

                                //The following section informs the DownloadIdentifers that we already plan to
                                //copy a file in the appropriate place and they do not need to worry about downloading
                                //one for that purpose
                                downloadIdentifiers.NotifyComplete(newFile);
                            }
                        }
                        else
                        {
                            if (fi.IsMovieFile())
                            {
                                //File is correct name
                                LOGGER.Debug($"Identified that {fi.FullName} is in the right place. Marking it as 'seen'.");
                                //Record this movie as seen

                                TVSettings.Instance.PreviouslySeenMovies.EnsureAdded(si);
                                if (TVSettings.Instance.IgnorePreviouslySeenMovies)
                                {
                                    Doc.SetDirty();
                                }
                            }
                        }
                    }
                } // foreach file in folder
            }
            else
            {
                if (movieFiles.First().IsMovieFile())
                {
                    //File is correct name
                    LOGGER.Debug($"Identified that {movieFiles.First().FullName} is in the right place. Marking it as 'seen'.");
                    //Record this movie as seen

                    TVSettings.Instance.PreviouslySeenMovies.EnsureAdded(si);
                    if (TVSettings.Instance.IgnorePreviouslySeenMovies)
                    {
                        Doc.SetDirty();
                    }
                }
            }
        }
Пример #6
0
        private static void MergeShowEpisodes([NotNull] ShowItem si, DirFilesCache dfc, CancellationToken token, int snum, IEnumerable <string> folders)
        {
            if (snum == 0 && si.CountSpecials)
            {
                return;
            }

            if (snum == 0 && TVSettings.Instance.IgnoreAllSpecials)
            {
                return;
            }

            List <ProcessedEpisode> eps = si.SeasonEpisodes[snum];

            List <ShowRule> rulesToAdd = new List <ShowRule>();

            foreach (string folder in folders)
            {
                if (token.IsCancellationRequested)
                {
                    throw new TVRenameOperationInterruptedException();
                }

                FileInfo[] files = dfc.GetFiles(folder);
                if (files is null)
                {
                    continue;
                }

                foreach (FileInfo fi in files)
                {
                    if (token.IsCancellationRequested)
                    {
                        throw new TVRenameOperationInterruptedException();
                    }

                    if (!fi.IsMovieFile())
                    {
                        continue; //not a video file, so ignore
                    }

                    if (!FinderHelper.FindSeasEp(fi, out int seasNum, out int epNum, out int maxEp, si,
                                                 out TVSettings.FilenameProcessorRE _))
                    {
                        continue; // can't find season & episode, so this file is of no interest to us
                    }

                    if (seasNum == -1)
                    {
                        seasNum = snum;
                    }

                    int epIdx = eps.FindIndex(x =>
                                              x.AppropriateEpNum == epNum && x.AppropriateSeasonNumber == seasNum);

                    if (epIdx == -1)
                    {
                        continue; // season+episode number don't correspond to any episode we know of from thetvdb
                    }

                    ProcessedEpisode ep = eps[epIdx];

                    if (ep.Type == ProcessedEpisode.ProcessedEpisodeType.merged || maxEp == -1)
                    {
                        continue;
                    }

                    LOGGER.Info(
                        $"Looking at {ep.Show.ShowName} and have identified that episode {epNum} and {maxEp} of season {seasNum} should be merged into one file {fi.FullName}");

                    ShowRule sr = new ShowRule
                    {
                        DoWhatNow = RuleAction.kMerge,
                        First     = epNum,
                        Second    = maxEp
                    };

                    rulesToAdd.Add(sr);
                } // foreach file in folder
            }     // for each folder for this season of this show

            foreach (ShowRule sr in rulesToAdd)
            {
                si.AddSeasonRule(snum, sr);
                LOGGER.Info($"Added new rule automatically for {sr}");
            }

            if (rulesToAdd.Any())
            {
                //Regenerate the episodes with the new rule added
                ShowLibrary.GenerateEpisodeDict(si);
            }
        }
Пример #7
0
        private void CheckSeasonFolder(ShowConfiguration si, DirFilesCache dfc, TVDoc.ScanSettings settings, int snum,
                                       bool timeForBannerUpdate, string folder)
        {
            if (settings.Token.IsCancellationRequested)
            {
                return;
            }

            if (TVSettings.Instance.NeedToDownloadBannerFile() && timeForBannerUpdate)
            {
                //Image cachedSeries checks here
                Doc.TheActionList.Add(
                    downloadIdentifiers.ForceUpdateSeason(DownloadIdentifier.DownloadType.downloadImage, si,
                                                          folder, snum));
            }

            //Image cachedSeries checks here
            Doc.TheActionList.Add(downloadIdentifiers.ProcessSeason(si, folder, snum));

            FileInfo[] files = dfc.GetFiles(folder);

            bool renCheck =
                TVSettings.Instance.RenameCheck && si.DoRename &&
                Directory.Exists(folder); // renaming check needs the folder to exist

            bool missCheck = TVSettings.Instance.MissingCheck && si.DoMissingCheck;

            if (!renCheck && !missCheck)
            {
                return;
            }

            Dictionary <int, FileInfo> localEps = new Dictionary <int, FileInfo>();
            int maxEpNumFound = 0;

            if (!si.SeasonEpisodes.ContainsKey(snum))
            {
                return;
            }

            List <ProcessedEpisode> eps = si.SeasonEpisodes[snum];

            foreach (FileInfo fi in files)
            {
                if (settings.Token.IsCancellationRequested)
                {
                    return;
                }

                if (!FinderHelper.FindSeasEp(fi, out int seasNum, out int epNum, out int _, si,
                                             out TVSettings.FilenameProcessorRE _))
                {
                    continue; // can't find season & episode, so this file is of no interest to us
                }

                if (seasNum == -1)
                {
                    seasNum = snum;
                }

                ProcessedEpisode ep = eps.Find(x => x.AppropriateEpNum == epNum && x.AppropriateSeasonNumber == seasNum);

                if (ep is null)
                {
                    continue; // season+episode number don't correspond to any episode we know of from thetvdb
                }

                FileInfo actualFile = fi;

                // == RENAMING CHECK ==
                if (renCheck && TVSettings.Instance.FileHasUsefulExtension(fi, true))
                {
                    // Note that the extension of the file may not be fi.extension as users can put ".mkv.t" for example as an extension
                    string otherExtension = TVSettings.Instance.FileHasUsefulExtensionDetails(fi, true);

                    string newName = TVSettings.Instance.FilenameFriendly(
                        TVSettings.Instance.NamingStyle.NameFor(ep, otherExtension, folder.Length));

                    FileInfo fileWorthAdding = CheckFile(folder, fi, actualFile, newName, ep, files);

                    if (fileWorthAdding != null)
                    {
                        localEps[epNum] = fileWorthAdding;
                    }
                }

                // == MISSING CHECK part 1/2 ==
                if (missCheck && fi.IsMovieFile())
                {
                    // first pass of missing check is to tally up the episodes we do have
                    if (!localEps.ContainsKey(epNum))
                    {
                        localEps[epNum] = actualFile;
                    }

                    if (epNum > maxEpNumFound)
                    {
                        maxEpNumFound = epNum;
                    }
                }
            } // foreach file in folder

            // == MISSING CHECK part 2/2 (includes NFO and Thumbnails) ==
            // look at the official list of episodes, and look to see if we have any gaps

            DateTime today = DateTime.Now;

            foreach (ProcessedEpisode episode in eps)
            {
                if (!localEps.ContainsKey(episode.AppropriateEpNum)) // not here locally
                {
                    // second part of missing check is to see what is missing!
                    if (missCheck)
                    {
                        DateTime?dt   = episode.GetAirDateDt(true);
                        bool     dtOk = dt != null;

                        bool notFuture =
                            dtOk && dt.Value.CompareTo(today) < 0; // isn't an episode yet to be aired

                        // only add to the missing list if, either:
                        // - force check is on
                        // - there are no aired dates at all, for up to and including this season
                        // - there is an aired date, and it isn't in the future
                        bool noAirdatesUntilNow    = si.NoAirdatesUntilNow(snum);
                        bool siForceCheckFuture    = (si.ForceCheckFuture || notFuture) && dtOk;
                        bool siForceCheckNoAirdate = si.ForceCheckNoAirdate && !dtOk;

                        if (noAirdatesUntilNow || siForceCheckFuture || siForceCheckNoAirdate)
                        {
                            // then add it as officially missing
                            Doc.TheActionList.Add(new ShowItemMissing(episode, folder));
                        }
                    }// if doing missing check
                }
                else
                {
                    if (settings.Type == TVSettings.ScanType.Full)
                    {
                        Doc.CurrentStats.NsNumberOfEpisodes++;
                    }

                    // do NFO and thumbnail checks if required
                    FileInfo
                        filo = localEps[episode.AppropriateEpNum]; // filename (or future filename) of the file

                    Doc.TheActionList.Add(downloadIdentifiers.ProcessEpisode(episode, filo));
                }
            } // up to date check, for each episode in thetvdb
        }
Пример #8
0
        protected override void Check(ShowItem si, DirFilesCache dfc, TVDoc.ScanSettings settings)
        {
            if (settings.Token.IsCancellationRequested)
            {
                throw new TVRenameOperationInterruptedException();
            }

            if (!TVSettings.Instance.AutoMergeLibraryEpisodes)
            {
                return;
            }

            Dictionary <int, List <string> > allFolders = si.AllExistngFolderLocations();

            if (allFolders.Count == 0) // no folders defined for this show
            {
                return;                // so, nothing to do.
            }

            int[] numbers = new int[si.SeasonEpisodes.Keys.Count];
            si.SeasonEpisodes.Keys.CopyTo(numbers, 0);

            // process each folder for each season...
            foreach (int snum in numbers)
            {
                if (settings.Token.IsCancellationRequested)
                {
                    throw new TVRenameOperationInterruptedException();
                }

                if ((si.IgnoreSeasons.Contains(snum)) || (!allFolders.ContainsKey(snum)))
                {
                    continue; // ignore/skip this season
                }

                if ((snum == 0) && (si.CountSpecials))
                {
                    continue; // don't process the specials season, as they're merged into the seasons themselves
                }

                if ((snum == 0) && TVSettings.Instance.IgnoreAllSpecials)
                {
                    continue;
                }

                // all the folders for this particular season
                List <string> folders = allFolders[snum];

                List <ProcessedEpisode> eps = si.SeasonEpisodes[snum];

                List <ShowRule> rulesToAdd = new List <ShowRule>();

                foreach (string folder in folders)
                {
                    if (settings.Token.IsCancellationRequested)
                    {
                        throw new TVRenameOperationInterruptedException();
                    }

                    FileInfo[] files = dfc.GetFiles(folder);
                    if (files is null)
                    {
                        continue;
                    }

                    foreach (FileInfo fi in files)
                    {
                        if (settings.Token.IsCancellationRequested)
                        {
                            throw new TVRenameOperationInterruptedException();
                        }

                        if (!fi.IsMovieFile())
                        {
                            continue; //not a video file, so ignore
                        }

                        if (!FinderHelper.FindSeasEp(fi, out int seasNum, out int epNum, out int maxEp, si,
                                                     out TVSettings.FilenameProcessorRE _))
                        {
                            continue; // can't find season & episode, so this file is of no interest to us
                        }

                        if (seasNum == -1)
                        {
                            seasNum = snum;
                        }

                        int epIdx = eps.FindIndex(x =>
                                                  ((x.AppropriateEpNum == epNum) && (x.AppropriateSeasonNumber == seasNum)));

                        if (epIdx == -1)
                        {
                            continue; // season+episode number don't correspond to any episode we know of from thetvdb
                        }

                        ProcessedEpisode ep = eps[epIdx];

                        if (ep.Type != ProcessedEpisode.ProcessedEpisodeType.merged && maxEp != -1)
                        {
                            LOGGER.Info(
                                $"Looking at {ep.Show.ShowName} and have identified that episode {epNum} and {maxEp} of season {seasNum} should be merged into one file {fi.FullName}");

                            ShowRule sr = new ShowRule
                            {
                                DoWhatNow = RuleAction.kMerge,
                                First     = epNum,
                                Second    = maxEp
                            };

                            rulesToAdd.Add(sr);
                        }
                    } // foreach file in folder
                }     // for each folder for this season of this show

                foreach (ShowRule sr in rulesToAdd)
                {
                    si.AddSeasonRule(snum, sr);
                    LOGGER.Info($"Added new rule automatically for {sr}");

                    //Regenerate the episodes with the new rule added
                    ShowLibrary.GenerateEpisodeDict(si);
                }
            } // for each season of this show
        }