protected override void DoCheck(SetProgressDelegate prog, ICollection <ShowItem> showList,
                                        TVDoc.ScanSettings settings)
        {
            ItemList newList  = new ItemList();
            ItemList toRemove = new ItemList();

            int fileCount = CountFilesInDownloadDirs();

            DirCache dirCache = new DirCache();

            foreach (string s in TVSettings.Instance.DownloadFolders.ToList())
            {
                if (settings.Token.IsCancellationRequested)
                {
                    return;
                }

                dirCache.AddFolder(prog, 0, fileCount, s, true);
            }

            int currentItem = 0;
            int totalN      = ActionList.MissingItems().Count() + 1;

            UpdateStatus(currentItem, totalN, "Starting searching through files");

            foreach (ItemMissing me in ActionList.MissingItems().ToList())
            {
                if (settings.Token.IsCancellationRequested)
                {
                    return;
                }

                UpdateStatus(currentItem++, totalN, me.Filename);

                ItemList        thisRound    = new ItemList();
                List <FileInfo> matchedFiles = FindMatchedFiles(settings, dirCache, me, thisRound);

                ProcessMissingItem(settings, newList, toRemove, me, thisRound, matchedFiles, TVSettings.Instance.UseFullPathNameToMatchSearchFolders);
            }

            if (TVSettings.Instance.KeepTogether)
            {
                KeepTogether(newList, false);
            }

            if (!TVSettings.Instance.LeaveOriginals)
            {
                ReorganiseToLeaveOriginals(newList);
            }

            ActionList.Replace(toRemove, newList);
        }
Beispiel #2
0
        private void ExtractShowDetails(StringBuilder txt)
        {
            foreach (ShowConfiguration si in mDoc.TvLibrary.GetSortedShowItems())
            {
                foreach (KeyValuePair <int, List <ProcessedEpisode> > kvp in si.ActiveSeasons)
                {
                    int snum = kvp.Key;
                    if (snum == 0 && !si.CountSpecials)
                    {
                        continue; // skip specials
                    }

                    if (!si.AllExistngFolderLocations().ContainsKey(snum))
                    {
                        continue; // skip non seen seasons
                    }

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

                    foreach (string folder in si.AllExistngFolderLocations()[snum])
                    {
                        txt.AppendLine(si.TvdbCode + " : " + si.ShowName + " : S" + snum);
                        txt.AppendLine("Folder: " + folder);

                        DirCache files = new DirCache();
                        if (Directory.Exists(folder))
                        {
                            files.AddFolder(null, 0, 0, folder, true);
                        }

                        foreach (DirCacheEntry fi in files)
                        {
                            bool r      = FinderHelper.FindSeasEp(fi.TheFile, out int seas, out int ep, out int maxEp, si);
                            bool useful = fi.TheFile.IsMovieFile();
                            txt.AppendLine(fi.TheFile.FullName + " (" + (r ? "OK" : "No") + " " + seas + "," + ep + "," +
                                           maxEp + " " + (useful ? fi.TheFile.Extension : "-") + ")");
                        }

                        txt.AppendLine();
                    }
                }

                txt.AppendLine();
            }
        }
        private List <FileInfo> FindMatchedFiles(TVDoc.ScanSettings settings, [NotNull] DirCache dirCache, ItemMissing me, ItemList thisRound)
        {
            List <FileInfo> matchedFiles = new List <FileInfo>();

            foreach (DirCacheEntry dce in dirCache)
            {
                if (!ReviewFile(me, thisRound, dce.TheFile, settings, TVSettings.Instance.AutoMergeDownloadEpisodes, TVSettings.Instance.PreventMove, true, TVSettings.Instance.UseFullPathNameToMatchSearchFolders))
                {
                    continue;
                }

                matchedFiles.Add(dce.TheFile);
            }

            return(matchedFiles);
        }
Beispiel #4
0
        private static void ExtractDownloadFolders(StringBuilder txt)
        {
            DirCache dirC = new DirCache();

            foreach (string efi in TVSettings.Instance.DownloadFolders)
            {
                dirC.AddFolder(null, 0, 0, efi, true);
            }

            foreach (DirCacheEntry fi in dirC)
            {
                bool r      = FinderHelper.FindSeasEp(fi.TheFile, out int seas, out int ep, out int maxEp, null);
                bool useful = fi.TheFile.IsMovieFile();
                txt.AppendLine(fi.TheFile.FullName + " (" + (r ? "OK" : "No") + " " + seas + "," + ep + "," + maxEp + " " +
                               (useful ? fi.TheFile.Extension : "-") + ")");
            }
        }
Beispiel #5
0
        private void bnCreate_Click(object sender, System.EventArgs e)
        {
            this.txtEmailText.Text = "Working... This may take a while.";
            this.txtEmailText.Update();

            string txt = "";

            txt += "From: " + this.txtName.Text + " <" + this.txtEmail.Text + ">" + "\r\n";
            txt += "Subject: TVRename bug report" + "\r\n";
            txt += "\r\n";
            txt += "TVRename version: " + Version.DisplayVersionString() + "\r\n";
            txt += "UserAppDataPath is " + System.Windows.Forms.Application.UserAppDataPath + "\r\n";
            txt += "EpGuidePath is " + UI.EpGuidePath() + "\r\n";
            txt += "\r\n";
            txt += "==== Brief Description ====" + "\r\n";
            txt += this.txtDesc1.Text + "\r\n";
            txt += "\r\n";
            txt += "==== Description ====" + "\r\n";
            txt += this.txtDesc2.Text + "\r\n";
            txt += "\r\n";
            txt += "==== Frequency ====" + "\r\n";
            txt += this.txtFreq.Text + "\r\n";
            txt += "\r\n";
            txt += "==== Notes and Comments ====" + "\r\n";
            txt += this.txtComments.Text + "\r\n";
            txt += "\r\n";

            if (this.cbSettings.Checked)
            {
                txt += "==== Settings Files ====" + "\r\n";
                txt += "\r\n";
                txt += "---- TVRenameSettings.xml" + "\r\n";
                txt += "\r\n";
                try
                {
                    StreamReader sr = new StreamReader(PathManager.TVDocSettingsFile.FullName);
                    txt += sr.ReadToEnd();
                    sr.Close();
                    txt += "\r\n";
                }
                catch
                {
                    txt += "Error reading TVRenameSettings.xml\r\n";
                }
                txt += "\r\n";
            }

            if (this.cbFOScan.Checked || this.cbFolderScan.Checked)
            {
                txt += "==== Filename processors ====\r\n";
                foreach (FilenameProcessorRE s in this.mDoc.Settings.FNPRegexs)
                {
                    txt += (s.Enabled ? "Enabled" : "Disabled") + " \"" + s.RE + "\" " + (s.UseFullPath ? "(FullPath)" : "") + "\r\n";
                }
                txt += "\r\n";
            }

            if (this.cbFOScan.Checked)
            {
                txt += "==== Finding & Organising Directory Scan ====" + "\r\n";
                txt += "\r\n";

                DirCache dirC = new DirCache();
                foreach (string efi in this.mDoc.SearchFolders)
                {
                    dirC.AddFolder(null, 0, 0, efi, true, this.mDoc.Settings);
                }

                foreach (DirCacheEntry fi in dirC)
                {
                    int  seas;
                    int  ep;
                    bool r      = this.mDoc.FindSeasEp(fi.TheFile, out seas, out ep, null);
                    bool useful = fi.HasUsefulExtension_NotOthersToo;
                    txt += fi.TheFile.FullName + " (" + (r ? "OK" : "No") + " " + seas + "," + ep + " " + (useful ? fi.TheFile.Extension : "-") + ")" + "\r\n";
                }
                txt += "\r\n";
            }

            if (this.cbFolderScan.Checked)
            {
                txt += "==== Media Folders Directory Scan ====" + "\r\n";

                foreach (ShowItem si in this.mDoc.GetShowItems(true))
                {
                    foreach (System.Collections.Generic.KeyValuePair <int, List <ProcessedEpisode> > kvp in si.SeasonEpisodes)
                    {
                        int snum = kvp.Key;
                        if (((snum == 0) && (si.CountSpecials)) || !si.AllFolderLocations(this.mDoc.Settings).ContainsKey(snum))
                        {
                            continue; // skip specials
                        }
                        foreach (string folder in si.AllFolderLocations(this.mDoc.Settings)[snum])
                        {
                            txt += si.TVDBCode + " : " + si.ShowName + " : S" + snum + "\r\n";
                            txt += "Folder: " + folder;
                            txt += "\r\n";
                            DirCache files = new DirCache();
                            if (Directory.Exists(folder))
                            {
                                files.AddFolder(null, 0, 0, folder, true, this.mDoc.Settings);
                            }
                            foreach (DirCacheEntry fi in files)
                            {
                                int  seas;
                                int  ep;
                                bool r      = this.mDoc.FindSeasEp(fi.TheFile, out seas, out ep, si);
                                bool useful = fi.HasUsefulExtension_NotOthersToo;
                                txt += fi.TheFile.FullName + " (" + (r ? "OK" : "No") + " " + seas + "," + ep + " " + (useful ? fi.TheFile.Extension : "-") + ")" + "\r\n";
                            }
                            txt += "\r\n";
                        }
                    }
                    txt += "\r\n";
                }
                this.mDoc.UnlockShowItems();

                txt += "\r\n";
            }

            this.txtEmailText.Text = txt;
        }
Beispiel #6
0
        public override void Check(SetProgressDelegate prog, int startpct, int totPct)
        {
            prog.Invoke(startpct);

            ItemList newList  = new ItemList();
            ItemList toRemove = new ItemList();

            int fileCount = 0;

            foreach (string s in TVSettings.Instance.DownloadFolders)
            {
                fileCount += DirCache.CountFiles(s, true);
            }

            DirCache dirCache = new DirCache();

            foreach (string s in TVSettings.Instance.DownloadFolders)
            {
                if (ActionCancel)
                {
                    return;
                }

                dirCache.AddFolder(prog, 0, fileCount, s, true);
            }

            int currentItem = 0;
            int totalN      = ActionList.Count;

            foreach (ItemMissing me in ActionList.MissingItems())
            {
                if (ActionCancel)
                {
                    return;
                }

                prog.Invoke(startpct + ((totPct - startpct) * (++currentItem) / (totalN + 1)));

                ItemList             thisRound    = new ItemList();
                List <DirCacheEntry> matchedFiles = new List <DirCacheEntry>();

                foreach (DirCacheEntry dce in dirCache)
                {
                    if (!ReviewFile(me, thisRound, dce))
                    {
                        continue;
                    }

                    matchedFiles.Add(dce);
                }

                if (matchedFiles.Count == 1)
                {
                    if (!OtherActionsMatch(matchedFiles[0], me))
                    {
                        toRemove.Add(me);
                        newList.AddRange(thisRound);
                    }
                    else
                    {
                        LOGGER.Warn($"Ignoring potential match for {me.Episode.Show.ShowName} S{me.Episode.AppropriateSeasonNumber} E{me.Episode.AppropriateEpNum}: with file {matchedFiles[0]?.TheFile.FullName} as there are multiple actions for that file");
                        me.AddComment(
                            $"Ignoring potential match with file {matchedFiles[0]?.TheFile.FullName} as there are multiple actions for that file");
                    }
                }
                else if (matchedFiles.Count > 1)
                {
                    List <DirCacheEntry> bestMatchedFiles = IdentifyBestMatches(matchedFiles);

                    if (bestMatchedFiles.Count == 1)
                    {
                        //We have one file that is better, lets use it
                        toRemove.Add(me);
                        newList.AddRange(thisRound);
                    }
                    else
                    {
                        foreach (DirCacheEntry matchedFile in matchedFiles)
                        {
                            LOGGER.Warn(
                                $"Ignoring potential match for {me.Episode.Show.ShowName} S{me.Episode.AppropriateSeasonNumber} E{me.Episode.AppropriateEpNum}: with file {matchedFile?.TheFile.FullName} as there are multiple files for that action");

                            me.AddComment(
                                $"Ignoring potential match with file {matchedFile?.TheFile.FullName} as there are multiple files for that action");
                        }
                    }
                }
            }

            if (TVSettings.Instance.KeepTogether)
            {
                KeepTogether(newList);
            }

            prog.Invoke(totPct);

            if (!TVSettings.Instance.LeaveOriginals)
            {
                // go through and change last of each operation on a given source file to a 'Move'
                // ideally do that move within same filesystem

                // sort based on source file, and destination drive, putting last if destdrive == sourcedrive
                newList.Sort(new ActionItemSorter());

                // sort puts all the CopyMoveRenames together
                // then set the last of each source file to be a move
                for (int i = 0; i < newList.Count; i++)
                {
                    ActionCopyMoveRename cmr1 = newList[i] as ActionCopyMoveRename;
                    bool ok1 = cmr1 != null;

                    if (!ok1)
                    {
                        continue;
                    }

                    bool last = i == (newList.Count - 1);
                    ActionCopyMoveRename cmr2 = !last ? newList[i + 1] as ActionCopyMoveRename : null;
                    bool ok2 = cmr2 != null;

                    if (ok2)
                    {
                        ActionCopyMoveRename a1 = cmr1;
                        ActionCopyMoveRename a2 = cmr2;
                        if (!FileHelper.Same(a1.From, a2.From))
                        {
                            a1.Operation = ActionCopyMoveRename.Op.move;
                        }
                    }
                    else
                    {
                        // last item, or last copymoverename item in the list
                        ActionCopyMoveRename a1 = cmr1;
                        a1.Operation = ActionCopyMoveRename.Op.move;
                    }
                }
            }

            foreach (Item i in toRemove)
            {
                ActionList.Remove(i);
            }

            foreach (Item i in newList)
            {
                ActionList.Add(i);
            }
        }
Beispiel #7
0
        protected override void DoCheck(SetProgressDelegate prog,
                                        TVDoc.ScanSettings settings)
        {
            ItemList newList  = new ItemList();
            ItemList toRemove = new ItemList();

            int fileCount = CountFilesInDownloadDirs();

            DirCache dirCache = new DirCache();

            foreach (string s in TVSettings.Instance.DownloadFolders.ToList())
            {
                if (settings.Token.IsCancellationRequested)
                {
                    return;
                }

                dirCache.AddFolder(prog, 0, fileCount, s, true);
            }

            int currentItem = 0;
            int totalN      = ActionList.Missing.Count + 1;

            UpdateStatus(currentItem, totalN, "Starting searching through files");

            foreach (var action in ActionList.Missing.ToList())
            {
                if (settings.Token.IsCancellationRequested)
                {
                    return;
                }

                UpdateStatus(currentItem++, totalN, action.Filename);

                ItemList thisRound = new ItemList();

                if (action is ShowItemMissing showMissingAction)
                {
                    List <FileInfo> matchedFiles = FindMatchedFiles(settings, dirCache, showMissingAction, thisRound);

                    ProcessMissingItem(settings, newList, toRemove, showMissingAction, thisRound, matchedFiles,
                                       TVSettings.Instance.UseFullPathNameToMatchSearchFolders);
                }
                else if (action is MovieItemMissing movieMissingAction)
                {
                    List <FileInfo> matchedFiles = new List <FileInfo>();

                    foreach (DirCacheEntry dce in dirCache)
                    {
                        if (!ReviewFile(movieMissingAction, thisRound, dce.TheFile, settings, TVSettings.Instance.PreventMove, true, TVSettings.Instance.UseFullPathNameToMatchSearchFolders))
                        {
                            continue;
                        }

                        matchedFiles.Add(dce.TheFile);
                    }

                    ProcessMissingItem(settings, newList, toRemove, movieMissingAction, thisRound, matchedFiles,
                                       TVSettings.Instance.UseFullPathNameToMatchSearchFolders);
                }
            }

            if (TVSettings.Instance.KeepTogether)
            {
                KeepTogether(newList, false);
            }

            if (!TVSettings.Instance.LeaveOriginals)
            {
                ReorganiseToLeaveOriginals(newList);
            }

            ActionList.Replace(toRemove, newList);
        }
Beispiel #8
0
 private static int CountFilesInDownloadDirs()
 {
     return(TVSettings.Instance.DownloadFolders.ToArray().Sum(s => DirCache.CountFiles(s, true)));
 }
Beispiel #9
0
        public override void Check(SetProgressDelegate prog, int startpct, int totPct)
        {
            prog.Invoke(0);

            ItemList newList  = new ItemList();
            ItemList toRemove = new ItemList();

            int fileCount = 0;

            foreach (string s in this.mDoc.SearchFolders)
            {
                fileCount += DirCache.CountFiles(s, true);
            }

            int c = 0;

            DirCache dirCache = new DirCache();

            foreach (String s in this.mDoc.SearchFolders)
            {
                if (this.ActionCancel)
                {
                    return;
                }

                c = dirCache.AddFolder(prog, c, fileCount, s, true);
            }

            c = 0;
            int totalN = this.TheActionList.Count;

            foreach (Item action1 in this.TheActionList)
            {
                if (this.ActionCancel)
                {
                    return;
                }

                prog.Invoke(50 + 50 * (++c) / (totalN + 1)); // second 50% of progress bar

                if (action1 is ItemMissing)
                {
                    if (this.FindMissingEp(dirCache, (ItemMissing)(action1), newList, ActionCopyMoveRename.Op.Copy))
                    {
                        toRemove.Add(action1);
                    }
                }
            }

            if (TVSettings.Instance.KeepTogether)
            {
                this.KeepTogether(newList);
            }

            prog.Invoke(100);

            if (!TVSettings.Instance.LeaveOriginals)
            {
                // go through and change last of each operation on a given source file to a 'Move'
                // ideally do that move within same filesystem

                // sort based on source file, and destination drive, putting last if destdrive == sourcedrive
                newList.Sort(new ActionItemSorter());

                // sort puts all the CopyMoveRenames together

                // then set the last of each source file to be a move
                for (int i = 0; i < newList.Count; i++)
                {
                    ActionCopyMoveRename cmr1 = newList[i] as ActionCopyMoveRename;
                    bool ok1 = cmr1 != null;

                    if (!ok1)
                    {
                        continue;
                    }

                    bool last = i == (newList.Count - 1);
                    ActionCopyMoveRename cmr2 = !last ? newList[i + 1] as ActionCopyMoveRename : null;
                    bool ok2 = cmr2 != null;

                    if (ok2)
                    {
                        ActionCopyMoveRename a1 = cmr1;
                        ActionCopyMoveRename a2 = cmr2;
                        if (!FileHelper.Same(a1.From, a2.From))
                        {
                            a1.Operation = ActionCopyMoveRename.Op.Move;
                        }
                    }
                    else
                    {
                        // last item, or last copymoverename item in the list
                        ActionCopyMoveRename a1 = cmr1;
                        a1.Operation = ActionCopyMoveRename.Op.Move;
                    }
                }
            }

            foreach (Item i in toRemove)
            {
                this.TheActionList.Remove(i);
            }

            foreach (Item i in newList)
            {
                this.TheActionList.Add(i);
            }

            //                 if (Settings->ExportFOXML)
            //				ExportFOXML(Settings->ExportFOXMLTo);
        }
Beispiel #10
0
        // consider each of the files, see if it is suitable for series "ser" and episode "epi"
        // if so, add a rcitem for copy to "fi"
        public bool FindMissingEp(DirCache dirCache, ItemMissing me, ItemList addTo, ActionCopyMoveRename.Op whichOp)
        {
            int season = me.Episode.SeasonNumber;

            //String ^toName = FilenameFriendly(Settings->NamingStyle->NameFor(me->PE));
            int epnum = me.Episode.EpNum;

            // TODO: find a 'best match', or use first ?

            foreach (DirCacheEntry dce in dirCache)
            {
                if (this.ActionCancel)
                {
                    return(true);
                }

                bool matched = false;

                try
                {
                    if (!dce.HasUsefulExtension_NotOthersToo) // not a usefile file extension
                    {
                        continue;
                    }
                    if (TVSettings.Instance.IgnoreSamples && dce.LowerName.Contains("sample") && ((dce.Length / (1024 * 1024)) < TVSettings.Instance.SampleFileMaxSizeMB))
                    {
                        continue;
                    }

                    //do any of the possible names for the series match the filename?
                    matched = (me.Episode.SI.getSimplifiedPossibleShowNames().Any(name => FileHelper.SimplifyAndCheckFilename(dce.SimplifiedFullName, name)));

                    if (matched)
                    {
                        int seasF;
                        int epF;

                        if ((TVDoc.FindSeasEp(dce.TheFile, out seasF, out epF, me.Episode.SI) && (seasF == season) && (epF == epnum)) || (me.Episode.SI.UseSequentialMatch && TVDoc.MatchesSequentialNumber(dce.TheFile.Name, ref seasF, ref epF, me.Episode) && (seasF == season) && (epF == epnum)))
                        {
                            FileInfo fi = new FileInfo(me.TheFileNoExt + dce.TheFile.Extension);

                            // don't remove the base search folders
                            bool doTidyup = true;
                            foreach (String folder in this.mDoc.SearchFolders)
                            {
                                // http://stackoverflow.com/questions/1794025/how-to-check-whether-2-directoryinfo-objects-are-pointing-to-the-same-directory
                                if (String.Compare(folder.ToLower().TrimEnd('\\'), fi.Directory.FullName.ToLower().TrimEnd('\\'), StringComparison.InvariantCultureIgnoreCase) == 0)
                                {
                                    doTidyup = false;
                                    break;
                                }
                            }
                            addTo.Add(new ActionCopyMoveRename(whichOp, dce.TheFile, fi, me.Episode, doTidyup ? TVSettings.Instance.Tidyup : null));

                            DownloadIdentifiersController di = new DownloadIdentifiersController();

                            // if we're copying/moving a file across, we might also want to make a thumbnail or NFO for it
                            addTo.Add(di.ProcessEpisode(me.Episode, fi));

                            return(true);
                        }
                    }
                }
                catch (System.IO.PathTooLongException e)
                {
                    string t = "Path too long. " + dce.TheFile.FullName + ", " + e.Message;
                    logger.Warn(e, "Path too long. " + dce.TheFile.FullName);

                    t += ".  More information is available in the log file";
                    if ((!this.mDoc.Args.Unattended) && (!this.mDoc.Args.Hide))
                    {
                        MessageBox.Show(t, "Path too long", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                    }

                    t  = "DirectoryName " + dce.TheFile.DirectoryName + ", File name: " + dce.TheFile.Name;
                    t += matched ? ", matched.  " : ", no match.  ";
                    if (matched)
                    {
                        t += "Show: " + me.Episode.TheSeries.Name + ", Season " + season + ", Ep " + epnum + ".  ";
                        t += "To: " + me.TheFileNoExt;
                    }
                    logger.Warn(t);
                }
            }

            return(false);
        }
Beispiel #11
0
        private void bnCreate_Click(object sender, System.EventArgs e)
        {
            this.txtEmailText.Text = "Working... This may take a while.";
            this.txtEmailText.Update();

            StringBuilder txt = new StringBuilder();

            if (this.cbSettings.Checked)
            {
                txt.AppendLine("==== Settings Files ====");
                txt.AppendLine();
                txt.AppendLine("---- TVRenameSettings.xml");
                txt.AppendLine();
                try
                {
                    using (StreamReader sr = new StreamReader(PathManager.TVDocSettingsFile.FullName))
                        txt.AppendLine(sr.ReadToEnd());
                }
                catch
                {
                    txt.AppendLine("Error reading TVRenameSettings.xml");
                }
                txt.AppendLine("");
            }

            if (this.cbFOScan.Checked || this.cbFolderScan.Checked)
            {
                txt.AppendLine("==== Filename processors ====");
                foreach (FilenameProcessorRE s in TVSettings.Instance.FNPRegexs)
                {
                    txt.AppendLine((s.Enabled ? "Enabled" : "Disabled") + " \"" + s.RE + "\" " + (s.UseFullPath ? "(FullPath)" : ""));
                }
                txt.AppendLine();
            }

            if (this.cbFOScan.Checked)
            {
                txt.AppendLine("==== Finding & Organising Directory Scan ====");
                txt.AppendLine();

                DirCache dirC = new DirCache();
                foreach (string efi in TVSettings.Instance.DownloadFolders)
                {
                    dirC.AddFolder(null, 0, 0, efi, true);
                }

                foreach (DirCacheEntry fi in dirC)
                {
                    bool r      = TVDoc.FindSeasEp(fi.TheFile, out int seas, out int ep, out int maxEp, null);
                    bool useful = TVSettings.Instance.UsefulExtension(fi.TheFile.Extension, false);
                    txt.AppendLine(fi.TheFile.FullName + " (" + (r ? "OK" : "No") + " " + seas + "," + ep + "," + maxEp + " " + (useful ? fi.TheFile.Extension : "-") + ")");
                }
                txt.AppendLine();
            }

            if (this.cbFolderScan.Checked)
            {
                txt.AppendLine("==== Media Folders Directory Scan ====");

                foreach (ShowItem si in this.mDoc.Library.GetShowItems())
                {
                    foreach (KeyValuePair <int, List <ProcessedEpisode> > kvp in si.SeasonEpisodes)
                    {
                        int snum = kvp.Key;
                        if (((snum == 0) && (si.CountSpecials)) || !si.AllFolderLocations().ContainsKey(snum))
                        {
                            continue; // skip specials
                        }
                        foreach (string folder in si.AllFolderLocations()[snum])
                        {
                            txt.AppendLine(si.TVDBCode + " : " + si.ShowName + " : S" + snum);
                            txt.AppendLine("Folder: " + folder);

                            DirCache files = new DirCache();
                            if (Directory.Exists(folder))
                            {
                                files.AddFolder(null, 0, 0, folder, true);
                            }
                            foreach (DirCacheEntry fi in files)
                            {
                                bool r      = TVDoc.FindSeasEp(fi.TheFile, out int seas, out int ep, out int maxEp, si);
                                bool useful = TVSettings.Instance.UsefulExtension(fi.TheFile.Extension, false);
                                txt.AppendLine(fi.TheFile.FullName + " (" + (r ? "OK" : "No") + " " + seas + "," + ep + "," + maxEp + " " + (useful ? fi.TheFile.Extension : "-") + ")");
                            }
                            txt.AppendLine();
                        }
                    }
                    txt.AppendLine();
                }

                txt.AppendLine();
            }

            this.txtEmailText.Text = txt.ToString();
        }