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}");
                }
            }
        }
Example #2
0
        private bool OtherActionsMatch(DirCacheEntry matchedFile, ItemMissing me, ItemList actionList)
        //This is used to check whether the selected file may match any other files we are looking for
        {
            foreach (Item testAction in actionList)
            {
                if (!(testAction is ItemMissing testMissingAction))
                {
                    continue;
                }
                if (testMissingAction.SameAs(me))
                {
                    continue;
                }

                if (ReviewFile(testMissingAction, new ItemList(), matchedFile))
                {
                    //We have 2 options that match  me and testAction - See whether one is subset of the other

                    if (me.Episode.SI.ShowName.Contains(testMissingAction.Episode.SI.ShowName))
                    {
                        continue;                                                                         //'me' is a better match, so don't worry about the new one
                    }
                    return(true);
                }
            }

            return(false);
        }
Example #3
0
        private void WarnPathTooLong([NotNull] ItemMissing me, [NotNull] FileInfo dce, [NotNull] Exception e, bool matched)
        {
            int season = me.Episode.AppropriateSeasonNumber;
            int epnum  = me.Episode.AppropriateEpNum;

            string t = "Path too long. " + dce.FullName + ", " + e.Message;

            LOGGER.Error(e, "Path too long. " + dce.FullName);

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

            t  = "DirectoryName " + dce.DirectoryName + ", File name: " + dce.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);
        }
Example #4
0
 public ActionTDownload([NotNull] RSSItem rss, string theFileNoExt, ProcessedEpisode pe, ItemMissing me)
 {
     SourceName        = rss.Title;
     url               = rss.URL;
     this.theFileNoExt = theFileNoExt;
     Episode           = pe;
     UndoItemMissing   = me;
 }
Example #5
0
        public override void Check(SetProgressDelegate prog, int startpct, int totPct)
        {
            int c = this.TheActionList.Count + 2;
            int n = 1;

            prog.Invoke(100 * n / c);
            RSSItemList RSSList = new RSSItemList();

            foreach (string s in TVSettings.Instance.RSSURLs)
            {
                RSSList.DownloadRSS(s, TVSettings.Instance.FNPRegexs);
            }

            ItemList newItems = new ItemList();
            ItemList toRemove = new ItemList();

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

                n++;
                prog.Invoke(100 * n / c);

                if (!(Action1 is ItemMissing))
                {
                    continue;
                }

                ItemMissing Action = (ItemMissing)(Action1);

                ProcessedEpisode pe               = Action.Episode;
                string           simpleShowName   = Helpers.SimplifyName(pe.SI.ShowName);
                string           simpleSeriesName = Helpers.SimplifyName(pe.TheSeries.Name);

                foreach (RSSItem rss in RSSList)
                {
                    if ((FileHelper.SimplifyAndCheckFilename(rss.ShowName, simpleShowName, true, false) || (string.IsNullOrEmpty(rss.ShowName) && FileHelper.SimplifyAndCheckFilename(rss.Title, simpleSeriesName, true, false))) && (rss.Season == pe.SeasonNumber) && (rss.Episode == pe.EpNum))
                    {
                        newItems.Add(new ActionRSS(rss, Action.TheFileNoExt, pe));
                        toRemove.Add(Action1);
                    }
                }
            }
            foreach (Item i in toRemove)
            {
                this.TheActionList.Remove(i);
            }

            foreach (Item Action in newItems)
            {
                this.TheActionList.Add(Action);
            }

            prog.Invoke(100);
        }
Example #6
0
 public ActionTDownload(string name, long sizeBytes, string url, string toWhereNoExt, ProcessedEpisode pe, ItemMissing me)
 {
     Episode         = pe;
     SourceName      = name;
     this.url        = url;
     theFileNoExt    = toWhereNoExt;
     UndoItemMissing = me;
     this.sizeBytes  = sizeBytes;
 }
Example #7
0
        public static FileInfo GenerateTargetName(ItemMissing mi, FileInfo from)
        {
            if (mi.DoRename && TVSettings.Instance.RenameCheck)
            {
                return(new FileInfo(mi.TheFileNoExt + @from.Extension));
            }

            return(new FileInfo(mi.DestinationFolder.EnsureEndsWithSeparator() + @from.Name));
        }
 public ActionCopyMoveRename(Op operation, FileInfo from, FileInfo to, ProcessedEpisode ep, bool doTidyup, ItemMissing undoItem)
 {
     Tidyup          = doTidyup? TVSettings.Instance.Tidyup:null;
     PercentDone     = 0;
     Episode         = ep;
     Operation       = operation;
     From            = from;
     To              = to;
     UndoItemMissing = undoItem;
 }
Example #9
0
 public ActionCopyMoveRename(Op operation, FileInfo from, FileInfo to, ProcessedEpisode ep, TVSettings.TidySettings tidyup, ItemMissing undoItem)
 {
     Tidyup          = tidyup;
     PercentDone     = 0;
     Episode         = ep;
     Operation       = operation;
     From            = from;
     To              = to;
     UndoItemMissing = undoItem;
 }
Example #10
0
 public ActionCopyMoveRename(Op operation, FileInfo from, FileInfo to, ProcessedEpisode ep, TidySettings tidyup, ItemMissing undoItem)
 {
     this.Tidyup          = tidyup;
     this.PercentDone     = 0;
     this.Episode         = ep;
     this.Operation       = operation;
     this.From            = from;
     this.To              = to;
     this.UndoItemMissing = undoItem;
 }
Example #11
0
 public ActionTDownload(string name, long sizeBytes, int seeders, string url, string toWhereNoExt, ProcessedEpisode?pe, ItemMissing me, string upstreamSource)
 {
     Episode         = pe;
     SourceName      = name;
     this.url        = url;
     theFileNoExt    = toWhereNoExt;
     UpstreamSource  = upstreamSource;
     UndoItemMissing = me;
     this.sizeBytes  = sizeBytes;
     Seeders         = seeders;
 }
Example #12
0
        public override void Run()
        {
            if (!Active()) return;

            try
            {
                XmlWriterSettings settings = new XmlWriterSettings
                {
                    Indent = true,
                    NewLineOnAttributes = true,
                    Encoding = Encoding.ASCII
                };
            
                using (XmlWriter writer = XmlWriter.Create(Location(), settings))
                {
                    writer.WriteStartDocument();
                    
                    writer.WriteStartElement("TVRename");
                    XmlHelper.WriteAttributeToXml(writer,"Version","2.1");
                    writer.WriteStartElement("MissingItems");

                    foreach (Item action in TheActionList)
                    {
                        if (!(action is ItemMissing)) continue;

                        ItemMissing missing = (ItemMissing)(action);
                        writer.WriteStartElement("MissingItem");

                        XmlHelper.WriteElementToXml(writer,"id",missing.Episode.Show.TvdbCode);
                        XmlHelper.WriteElementToXml(writer, "title",missing.Episode.TheSeries.Name);
                        XmlHelper.WriteElementToXml(writer, "season", Helpers.Pad(missing.Episode.AppropriateSeasonNumber));
                        XmlHelper.WriteElementToXml(writer, "episode", Helpers.Pad(missing.Episode.AppropriateEpNum));
                        XmlHelper.WriteElementToXml(writer, "episodeName",missing.Episode.Name);
                        XmlHelper.WriteElementToXml(writer, "description",missing.Episode.Overview);

                        writer.WriteStartElement("pubDate");
                        DateTime? dt = missing.Episode.GetAirDateDT(true);
                        if (dt != null)
                            writer.WriteValue(dt.Value.ToString("F"));
                        writer.WriteEndElement();
                            
                        writer.WriteEndElement(); // MissingItem
                    }
                    writer.WriteEndElement(); // MissingItems
                    writer.WriteEndElement(); // tvrename
                    writer.WriteEndDocument();
                }
            }
            catch (Exception e)
            {
                LOGGER.Error(e);
            }
        }
Example #13
0
 public ActionTDownload([NotNull] RSSItem rss, string theFileNoExt, ItemMissing me)
 {
     SourceName        = rss.Title;
     url               = rss.URL;
     this.theFileNoExt = theFileNoExt;
     UpstreamSource    = rss.UpstreamSource;
     Episode           = me.Episode;
     Movie             = me.Movie;
     UndoItemMissing   = me;
     Seeders           = rss.Seeders;
     sizeBytes         = rss.Bytes;
     UpstreamSource    = rss.UpstreamSource;
 }
Example #14
0
 private ItemDownloading(IDownloadInformation dl, string desiredLocationNoExt, DownloadingFinder.DownloadApp tApp, ItemMissing undoItem)
 {
     DesiredLocationNoExt = desiredLocationNoExt;
     entry           = dl;
     UndoItemMissing = undoItem;
     IconNumber      = tApp switch
     {
         DownloadingFinder.DownloadApp.uTorrent => 2,
         DownloadingFinder.DownloadApp.SABnzbd => 8,
         DownloadingFinder.DownloadApp.qBitTorrent => 10,
         _ => 0
     };
 }
Example #15
0
        public override void Run(ItemList TheActionList)
        {
            if (TVSettings.Instance.ExportMissingXML)
            {
                XmlWriterSettings settings = new XmlWriterSettings();
                //XmlWriterSettings settings = gcnew XmlWriterSettings();
                settings.Indent = true;
                settings.NewLineOnAttributes = true;
                using (XmlWriter writer = XmlWriter.Create(Location(), settings))
                {
                    writer.WriteStartDocument();

                    writer.WriteStartElement("TVRename");
                    XMLHelper.WriteAttributeToXML(writer, "Version", "2.1");
                    writer.WriteStartElement("MissingItems");

                    foreach (Item Action in TheActionList)
                    {
                        if (Action is ItemMissing)
                        {
                            ItemMissing Missing = (ItemMissing)(Action);
                            writer.WriteStartElement("MissingItem");

                            XMLHelper.WriteElementToXML(writer, "id", Missing.Episode.SI.TVDBCode);
                            XMLHelper.WriteElementToXML(writer, "title", Missing.Episode.TheSeries.Name);
                            XMLHelper.WriteElementToXML(writer, "season", Helpers.pad(Missing.Episode.SeasonNumber));
                            XMLHelper.WriteElementToXML(writer, "episode", Helpers.pad(Missing.Episode.EpNum));
                            XMLHelper.WriteElementToXML(writer, "episodeName", Missing.Episode.Name);
                            XMLHelper.WriteElementToXML(writer, "description", Missing.Episode.Overview);

                            writer.WriteStartElement("pubDate");
                            DateTime?dt = Missing.Episode.GetAirDateDT(true);
                            if (dt != null)
                            {
                                writer.WriteValue(dt.Value.ToString("F"));
                            }
                            writer.WriteEndElement();

                            writer.WriteEndElement(); // MissingItem
                        }
                    }
                    writer.WriteEndElement(); // MissingItems
                    writer.WriteEndElement(); // tvrename
                    writer.WriteEndDocument();
                    writer.Close();
                }
            }
        }
Example #16
0
        public override int Compare(Item o)
        {
            ItemMissing miss = o as ItemMissing;

            //return (o == null || miss == null) ? 0 : (this.TheFileNoExt + this.Episode.Name).CompareTo(miss.TheFileNoExt + miss.Episode.Name);
            if (o == null || miss == null)
            {
                return(0);
            }

            if (!this.Episode.SI.ShowName.Equals(miss.Episode.SI.ShowName))
            {
                return(this.Episode.SI.ShowName.CompareTo(miss.Episode.SI.ShowName));
            }

            if (!this.Episode.AppropriateSeasonNumber.Equals(miss.Episode.AppropriateSeasonNumber))
            {
                return(this.Episode.AppropriateSeasonNumber.CompareTo(miss.Episode.AppropriateSeasonNumber));
            }

            return(this.Episode.AppropriateEpNum.CompareTo(miss.Episode.AppropriateEpNum));
        }
Example #17
0
 private static int TypeNumber(Item a)
 {
     return(a switch
     { //todo fix this for new types
         ItemMissing _ => 1,
         ActionCopyMoveRename _ => 2,
         ActionTDownload _ => 3,
         ActionDownloadImage _ => 4,
         ActionMede8erViewXML _ => 5,
         ActionMede8erXML _ => 6,
         ActionNfo _ => 7,
         ActionPyTivoMeta _ => 8,
         ActionWdtvMeta _ => 9,
         ItemDownloading _ => 10,
         ActionDeleteFile _ => 11,
         ActionDeleteDirectory _ => 12,
         ActionDateTouchEpisode _ => 13,
         ActionDateTouchSeason _ => 14,
         ActionDateTouchMedia _ => 15,
         ActionDateTouchMovie _ => 16,
         ActionTRemove _ => 17,
         _ => throw new NotSupportedException()
     });
Example #18
0
        private static ItemMissing UpdateMissingItem([NotNull] ItemMissing me, [NotNull] FileInfo dce, int epF, int maxEp, int seasF)
        {
            if (me.Episode.Show is null)
            {
                return(me);
            }
            ShowRule sr = new ShowRule
            {
                DoWhatNow = RuleAction.kMerge,
                First     = epF,
                Second    = maxEp
            };

            me.Episode.Show?.AddSeasonRule(seasF, sr);

            LOGGER.Info(
                $"Looking at {me.Episode.Show.ShowName} and have identified that episode {epF} and {maxEp} of season {seasF} have been merged into one file {dce.FullName}");

            LOGGER.Info($"Added new rule automatically for {sr}");

            //Regenerate the episodes with the new rule added
            ShowLibrary.GenerateEpisodeDict(me.Episode.Show);

            //Get the newly created processed episode we are after
            // ReSharper disable once InconsistentNaming
            ProcessedEpisode newPE = me.Episode;

            foreach (ProcessedEpisode pe in me.Episode.Show.SeasonEpisodes[seasF])
            {
                if (pe.AppropriateEpNum == epF && pe.EpNum2 == maxEp)
                {
                    newPE = pe;
                }
            }

            return(new ItemMissing(newPE, me.TargetFolder));
        }
        private static void FindMissingEpisode([NotNull] ItemMissing action, ItemList toRemove, ItemList newItems, UrlCache cache)
        {
            ProcessedEpisode pe = action.Episode;

            string imdbId = pe.TheSeries.GetImdbNumber();

            if (string.IsNullOrWhiteSpace(imdbId))
            {
                return;
            }

            string   simpleShowName   = Helpers.SimplifyName(pe.Show.ShowName);
            string   simpleSeriesName = Helpers.SimplifyName(pe.TheSeries.Name);
            ItemList newItemsForThisMissingEpisode = new ItemList();

            string response = cache.GetUrl($"{TVSettings.Instance.SearchJSONURL}{imdbId}", TVSettings.Instance.SearchJSONUseCloudflare);

            if (string.IsNullOrWhiteSpace(response))
            {
                LOGGER.Warn(
                    $"Got no response from {TVSettings.Instance.SearchJSONURL}{imdbId} for {action.Episode.TheSeries.Name}");

                return;
            }

            JObject jsonResponse = JObject.Parse(response);

            if (jsonResponse.ContainsKey(TVSettings.Instance.SearchJSONRootNode))
            {
                foreach (JToken item in jsonResponse[TVSettings.Instance.SearchJSONRootNode])
                {
                    if (item is null || !(item is JObject episodeResponse))
                    {
                        continue;
                    }

                    if (episodeResponse.ContainsKey(TVSettings.Instance.SearchJSONFilenameToken) &&
                        episodeResponse.ContainsKey(TVSettings.Instance.SearchJSONURLToken))
                    {
                        string itemName      = (string)item[TVSettings.Instance.SearchJSONFilenameToken];
                        string itemUrl       = (string)item[TVSettings.Instance.SearchJSONURLToken];
                        long   itemSizeBytes = CalculateItemSizeBytes(item);

                        if (TVSettings.Instance.DetailedRSSJSONLogging)
                        {
                            LOGGER.Info("Processing JSON Item");
                            LOGGER.Info(episodeResponse.ToString);
                            LOGGER.Info("Extracted");
                            LOGGER.Info($"Name:        {itemName}");
                            LOGGER.Info($"URL:         {itemUrl}");
                            LOGGER.Info($"Size:        {itemSizeBytes}");
                        }

                        if (!FileHelper.SimplifyAndCheckFilename(itemName, simpleShowName, true, false) &&
                            !FileHelper.SimplifyAndCheckFilename(itemName, simpleSeriesName, true, false))
                        {
                            continue;
                        }

                        if (!FinderHelper.FindSeasEp(itemName, out int seas, out int ep, out int _, pe.Show))
                        {
                            continue;
                        }

                        if (TVSettings.Instance.DetailedRSSJSONLogging)
                        {
                            LOGGER.Info($"Season:      {seas}");
                            LOGGER.Info($"Episode:     {ep}");
                        }

                        if (seas != pe.AppropriateSeasonNumber)
                        {
                            continue;
                        }

                        if (ep != pe.AppropriateEpNum)
                        {
                            continue;
                        }

                        LOGGER.Info(
                            $"Adding {itemUrl} from JSON page as it appears to be match for {pe.Show.ShowName} S{pe.AppropriateSeasonNumber}E{pe.AppropriateEpNum}");

                        newItemsForThisMissingEpisode.Add(new ActionTDownload(itemName, itemSizeBytes, itemUrl,
                                                                              action.TheFileNoExt, pe, action));

                        toRemove.Add(action);
                    }
                    else
                    {
                        LOGGER.Info(
                            $"{TVSettings.Instance.SearchJSONFilenameToken} or {TVSettings.Instance.SearchJSONURLToken} not found in {TVSettings.Instance.SearchJSONURL}{imdbId} for {action.Episode.TheSeries.Name}");
                    }
                }
            }
            else
            {
                LOGGER.Info(
                    $"{TVSettings.Instance.SearchJSONRootNode} not found in {TVSettings.Instance.SearchJSONURL}{imdbId} for {action.Episode.TheSeries.Name}");
            }

            RemoveDuplicates(newItemsForThisMissingEpisode);

            newItems.AddNullableRange(newItemsForThisMissingEpisode);
        }
        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);
        }
Example #21
0
        private bool ReviewFile(ItemMissing me, ItemList addTo, DirCacheEntry dce)
        {
            if (ActionCancel)
            {
                return(true);
            }

            int  season  = me.Episode.AppropriateSeasonNumber;
            int  epnum   = me.Episode.AppropriateEpNum;
            bool matched = false;

            try
            {
                if (FileHelper.IgnoreFile(dce.TheFile))
                {
                    return(false);
                }

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

                if (matched)
                {
                    bool regularMatch = TVDoc.FindSeasEp(dce.TheFile, out int seasF, out int epF, out int maxEp, me.Episode.Show) &&
                                        seasF == season &&
                                        epF == epnum;

                    bool sequentialMatch = me.Episode.Show.UseSequentialMatch &&
                                           TVDoc.MatchesSequentialNumber(dce.TheFile.Name, ref seasF, ref epF, me.Episode) &&
                                           seasF == season &&
                                           epF == epnum;

                    if (regularMatch || sequentialMatch)
                    {
                        if (maxEp != -1 && TVSettings.Instance.AutoMergeDownloadEpisodes)
                        {
                            ShowRule sr = new ShowRule
                            {
                                DoWhatNow = RuleAction.kMerge,
                                First     = epF,
                                Second    = maxEp
                            };
                            me.Episode.Show?.AddSeasonRule(seasF, sr);

                            LOGGER.Info(
                                $"Looking at {me.Episode.Show.ShowName} and have identified that episode {epF} and {maxEp} of season {seasF} have been merged into one file {dce.TheFile.FullName}");
                            LOGGER.Info($"Added new rule automatically for {sr}");

                            //Regenerate the episodes with the new rule added
                            ShowLibrary.GenerateEpisodeDict(me.Episode.Show);

                            //Get the newly created processed episode we are after
                            // ReSharper disable once InconsistentNaming
                            ProcessedEpisode newPE = me.Episode;
                            foreach (ProcessedEpisode pe in me.Episode.Show.SeasonEpisodes[seasF])
                            {
                                if (pe.AppropriateEpNum == epF && pe.EpNum2 == maxEp)
                                {
                                    newPE = pe;
                                }
                            }

                            me = new ItemMissing(newPE, me.TargetFolder,
                                                 TVSettings.Instance.FilenameFriendly(TVSettings.Instance.NamingStyle.NameFor(newPE)));
                        }
                        FileInfo fi = new FileInfo(me.TheFileNoExt + dce.TheFile.Extension);

                        if (TVSettings.Instance.PreventMove)
                        {
                            //We do not want to move the file, just rename it
                            fi = new FileInfo(dce.TheFile.DirectoryName + System.IO.Path.DirectorySeparatorChar + me.Filename +
                                              dce.TheFile.Extension);
                        }

                        // don't remove the base search folders
                        bool doTidyup = true;
                        foreach (string folder in TVSettings.Instance.DownloadFolders)
                        {
                            if (folder.SameDirectoryLocation(fi.Directory.FullName))
                            {
                                doTidyup = false;
                                break;
                            }
                        }

                        if (dce.TheFile.FullName != fi.FullName)
                        {
                            addTo.Add(new ActionCopyMoveRename(ActionCopyMoveRename.Op.copy, dce.TheFile, fi, me.Episode,
                                                               doTidyup ? TVSettings.Instance.Tidyup : null, me));
                        }

                        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 ((!Doc.Args.Unattended) && (!Doc.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);
        }
Example #22
0
        public override void Check(SetProgressDelegate prog, int startpct, int totPct)
        {
            if (string.IsNullOrEmpty(TVSettings.Instance.SABAPIKey) || String.IsNullOrEmpty(TVSettings.Instance.SABHostPort))
            {
                prog.Invoke(totPct);
                return;
            }

            // get list of files being downloaded by SABnzbd

            // Something like:
            // http://localhost:8080/sabnzbd/api?mode=queue&apikey=xxx&start=0&limit=8888&output=xml
            string theURL = "http://" + TVSettings.Instance.SABHostPort +
                            "/sabnzbd/api?mode=queue&start=0&limit=8888&output=xml&apikey=" + TVSettings.Instance.SABAPIKey;

            WebClient wc = new WebClient();

            byte[] r = null;
            try
            {
                r = wc.DownloadData(theURL);
            }
            catch (WebException)
            {
                logger.Warn("Failed to obtain SABnzbd, please recheck settings: " + theURL);
            }

            if (r == null)
            {
                prog.Invoke(totPct);
                return;
            }

            try
            {
                SAB.result res = SAB.result.Deserialize(r);
                if (res != null && res.status == "False")
                {
                    logger.Error("Error processing data from SABnzbd (Queue Check): {0}", res.error);
                    prog.Invoke(totPct);
                    return;
                }
            }
            catch
            {
                // wasn't a result/error combo.  this is good!
            }

            SAB.queue sq = null;
            try
            {
                sq = SAB.queue.Deserialize(r);
            }
            catch (Exception e)
            {
                logger.Error(e, "Error processing data from SABnzbd (Queue Check)");
                prog.Invoke(totPct);
                return;
            }

            System.Diagnostics.Debug.Assert(sq != null);   // shouldn't happen
            if (sq?.slots == null || sq.slots.Length == 0) // empty queue
            {
                return;
            }

            ItemList newList  = new ItemList();
            ItemList toRemove = new ItemList();
            int      c        = this.ActionList.Count + 2;
            int      n        = 1;

            foreach (Item Action1 in this.ActionList)
            {
                if (this.ActionCancel)
                {
                    return;
                }

                prog.Invoke(startpct + (totPct - startpct) * (++n) / (c));


                if (!(Action1 is ItemMissing))
                {
                    continue;
                }

                ItemMissing Action = (ItemMissing)(Action1);

                string showname = Helpers.SimplifyName(Action.Episode.SI.ShowName);

                foreach (SAB.queueSlotsSlot te in sq.slots)
                {
                    //foreach (queueSlotsSlot te in qs)
                    {
                        FileInfo file = new FileInfo(te.filename);
                        //if (!TVSettings.Instance.UsefulExtension(file.Extension, false)) // not a usefile file extension
                        //    continue;

                        if (!FileHelper.SimplifyAndCheckFilename(file.FullName, showname, true, false))
                        {
                            continue;
                        }
                        if (!TVDoc.FindSeasEp(file, out int seasF, out int epF, out int maxEp, Action.Episode.SI) ||
                            (seasF != Action.Episode.AppropriateSeasonNumber) || (epF != Action.Episode.AppropriateEpNum))
                        {
                            continue;
                        }
                        toRemove.Add(Action1);
                        newList.Add(new ItemSABnzbd(te, Action.Episode, Action.TheFileNoExt));
                        break;
                    }
                }
            }

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

            foreach (Item Action in newList)
            {
                this.ActionList.Add(Action);
            }

            prog.Invoke(totPct);
        }
Example #23
0
        public int Compare(Item o)
        {
            ItemMissing miss = o as ItemMissing;

            return((o == null || miss == null) ? 0 : (this.TheFileNoExt + this.Episode.Name).CompareTo(miss.TheFileNoExt + miss.Episode.Name));
        }
        private List <FileInfo> GetMatchingFilesFromFolder([CanBeNull] string baseFolder, DirFilesCache dfc, ItemMissing me, TVDoc.ScanSettings settings,
                                                           ItemList thisRound)
        {
            List <FileInfo> matchedFiles;

            if (string.IsNullOrWhiteSpace(baseFolder))
            {
                matchedFiles = new List <FileInfo>();
            }
            else
            {
                FileInfo[] testFiles = dfc.GetFilesIncludeSubDirs(baseFolder);
                matchedFiles = testFiles is null
                    ? new List <FileInfo>()
                    : testFiles.Where(testFile => ReviewFile(me, thisRound, testFile, settings, false, false, false,
                                                             TVSettings.Instance.UseFullPathNameToMatchLibraryFolders)).ToList();
            }

            return(matchedFiles);
        }
Example #25
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)
        {
            string showname = me.Episode.SI.ShowName;
            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 ?

            showname = Helpers.SimplifyName(showname);

            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 (this.Settings.IgnoreSamples && dce.LowerName.Contains("sample") && ((dce.Length / (1024 * 1024)) < this.Settings.SampleFileMaxSizeMB))
                        continue;

                    matched = Regex.Match(dce.SimplifiedFullName, "\\b" + showname + "\\b", RegexOptions.IgnoreCase).Success;

                    // if we don't match the main name, then test the aliases
                    if (!matched)
                    {
                        foreach (string alias in me.Episode.SI.AliasNames)
                        {
                            string aliasName = Helpers.SimplifyName(alias);
                            matched = Regex.Match(dce.SimplifiedFullName, "\\b" + aliasName + "\\b", RegexOptions.IgnoreCase).Success;
                            if (matched)
                                break;
                        }
                    }

                    if (matched)
                    {
                        int seasF;
                        int epF;
                        // String ^fn = file->Name;

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

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

                            return true;
                        }
                    }
                }
                catch (System.IO.PathTooLongException e)
                {
                    string t = "Path too long. " + dce.TheFile.FullName + ", " + e.Message;
                    t += ".  Try to display more info?";
                    DialogResult dr = MessageBox.Show(t, "Path too long", MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation);
                    if (dr == DialogResult.Yes)
                    {
                        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;
                        }

                        MessageBox.Show(t, "Path too long", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                    }
                }
            }

            return false;
        }
Example #26
0
        private static QueueSlotsSlot CreateQueueSlotsSlot([NotNull] XElement slot, string simpleShowName, ItemMissing action)
        {
            string filename = slot.Attribute("filename")?.Value;

            if (string.IsNullOrWhiteSpace(filename))
            {
                return(null);
            }

            FileInfo file = new FileInfo(filename);

            if (!FileHelper.SimplifyAndCheckFilename(file.FullName, simpleShowName, true, false))
            {
                return(null);
            }

            if (!FinderHelper.FindSeasEp(file, out int seasF, out int epF, out int _,
                                         action.Episode.Show) ||
                (seasF != action.Episode.AppropriateSeasonNumber) ||
                (epF != action.Episode.AppropriateEpNum))
            {
                return(null);
            }

            return(new QueueSlotsSlot
            {
                Filename = filename,
                Mb = slot.Attribute("mb")?.Value,
                Sizeleft = slot.Attribute("sizeleft")?.Value,
                Status = slot.Attribute("status")?.Value,
                Timeleft = slot.Attribute("timeleft")?.Value
            });
        }
Example #27
0
        public override void Check(SetProgressDelegate prog, int startpct, int totPct)
        {
            if (String.IsNullOrEmpty(TVSettings.Instance.SABAPIKey) || String.IsNullOrEmpty(TVSettings.Instance.SABHostPort))
            {
                prog.Invoke(startpct + totPct);
                return;
            }

            // get list of files being downloaded by SABnzbd

            // Something like:
            // http://localhost:8080/sabnzbd/api?mode=queue&apikey=xxx&start=0&limit=8888&output=xml
            String theURL = "http://" + TVSettings.Instance.SABHostPort +
                            "/sabnzbd/api?mode=queue&start=0&limit=8888&output=xml&apikey=" + TVSettings.Instance.SABAPIKey;

            WebClient wc = new WebClient();

            byte[] r = null;
            try
            {
                r = wc.DownloadData(theURL);
            }
            catch (WebException)
            {
            }

            if (r == null)
            {
                prog.Invoke(startpct + totPct);
                return;
            }

            try
            {
                SAB.result res = SAB.result.Deserialize(r);
                if (res.status == "False")
                {
                    MessageBox.Show(res.error, "SABnzbd Queue Check", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    prog.Invoke(startpct + totPct);
                    return;
                }
            }
            catch
            {
                // wasn't a result/error combo.  this is good!
            }

            SAB.queue sq = null;
            try
            {
                sq = SAB.queue.Deserialize(r);
            }
            catch (Exception)
            {
                MessageBox.Show("Error processing data from SABnzbd", "SABnzbd Queue Check", MessageBoxButtons.OK, MessageBoxIcon.Error);
                prog.Invoke(startpct + totPct);
                return;
            }

            System.Diagnostics.Debug.Assert(sq != null);                // shouldn't happen
            if (sq == null || sq.slots == null || sq.slots.Length == 0) // empty queue
            {
                return;
            }

            ItemList newList  = new ItemList();
            ItemList toRemove = new ItemList();
            int      c        = this.TheActionList.Count + 2;
            int      n        = 1;

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

                n++;
                prog.Invoke(startpct + totPct * n / c);

                if (!(Action1 is ItemMissing))
                {
                    continue;
                }

                ItemMissing Action = (ItemMissing)(Action1);

                string showname = Helpers.SimplifyName(Action.Episode.SI.ShowName);

                foreach (SAB.queueSlotsSlot te in sq.slots)
                {
                    //foreach (queueSlotsSlot te in qs)
                    {
                        FileInfo file = new FileInfo(te.filename);
                        //if (!TVSettings.Instance.UsefulExtension(file.Extension, false)) // not a usefile file extension
                        //    continue;

                        if (FileHelper.SimplifyAndCheckFilename(file.FullName, showname, true, false))
                        // if (Regex::Match(simplifiedfname,"\\b"+showname+"\\b",RegexOptions::IgnoreCase)->Success)
                        {
                            int seasF;
                            int epF;
                            if (TVDoc.FindSeasEp(file, out seasF, out epF, Action.Episode.SI) &&
                                (seasF == Action.Episode.SeasonNumber) && (epF == Action.Episode.EpNum))
                            {
                                toRemove.Add(Action1);
                                newList.Add(new ItemSABnzbd(te, Action.Episode, Action.TheFileNoExt));
                                break;
                            }
                        }
                    }
                }
            }

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

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

            prog.Invoke(startpct + totPct);
        }
Example #28
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);
        }
Example #29
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)
        {
            string showname = me.Episode.SI.ShowName;
            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 ?

            showname = Helpers.SimplifyName(showname);

            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;

                    matched = Regex.Match(dce.SimplifiedFullName, "\\b" + showname + "\\b", RegexOptions.IgnoreCase).Success;

                    // if we don't match the main name, then test the aliases
                    if (!matched)
                    {
                        foreach (string alias in me.Episode.SI.AliasNames)
                        {
                            string aliasName = Helpers.SimplifyName(alias);
                            matched = Regex.Match(dce.SimplifiedFullName, "\\b" + aliasName + "\\b", RegexOptions.IgnoreCase).Success;
                            if (matched)
                                break;
                        }
                    }

                    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;
                    t += ".  Try to display more info?";
                    DialogResult dr = MessageBox.Show(t, "Path too long", MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation);
                    if (dr == DialogResult.Yes)
                    {
                        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;
                        }

                        MessageBox.Show(t, "Path too long", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                    }
                }
            }

            return false;
        }
Example #30
0
        protected void ProcessMissingItem(TVDoc.ScanSettings settings, ItemList newList, ItemList toRemove, ItemMissing me, ItemList thisRound, [NotNull] List <FileInfo> matchedFiles, bool useFullPath)
        {
            if (matchedFiles.Count == 1)
            {
                if (!OtherActionsMatch(matchedFiles[0], me, settings, useFullPath))
                {
                    if (!FinderHelper.BetterShowsMatch(matchedFiles[0], me.Episode.Show, useFullPath, MDoc))
                    {
                        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]?.FullName} as there are multiple shows that match for that file");
                        me.AddComment(
                            $"Ignoring potential match with file {matchedFiles[0]?.FullName} as there are multiple shows for that file");
                    }
                }
                else
                {
                    LOGGER.Warn($"Ignoring potential match for {me.Episode.Show.ShowName} S{me.Episode.AppropriateSeasonNumber} E{me.Episode.AppropriateEpNum}: with file {matchedFiles[0]?.FullName} as there are multiple actions for that file");
                    me.AddComment(
                        $"Ignoring potential match with file {matchedFiles[0]?.FullName} as there are multiple actions for that file");
                }
            }

            if (matchedFiles.Count > 1)
            {
                List <FileInfo> 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 (FileInfo matchedFile in matchedFiles)
                    {
                        LOGGER.Warn(
                            $"Ignoring potential match for {me.Episode.Show.ShowName} S{me.Episode.AppropriateSeasonNumber} E{me.Episode.AppropriateEpNum}: with file {matchedFile?.FullName} as there are multiple files for that action");

                        me.AddComment(
                            $"Ignoring potential match with file {matchedFile?.FullName} as there are multiple files for that action");
                    }
                }
            }
        }
Example #31
0
        // ReSharper disable once FunctionComplexityOverflow
        protected bool ReviewFile(ItemMissing me, ItemList addTo, FileInfo dce, TVDoc.ScanSettings settings, bool addMergeRules, bool preventMove, bool doExtraFiles, bool useFullPath)
        {
            if (settings.Token.IsCancellationRequested)
            {
                return(false);
            }

            bool matched = false;

            try
            {
                if (dce.IgnoreFile())
                {
                    return(false);
                }

                //do any of the possible names for the series match the filename?
                matched = me.Episode.Show.NameMatch(dce, useFullPath);

                if (!matched)
                {
                    return(false);
                }

                (bool identifySuccess, int seasF, int epF, int maxEp) = IdentifyFile(me, dce);

                if (!identifySuccess)
                {
                    return(false);
                }

                if (maxEp != -1 && addMergeRules)
                {
                    me = UpdateMissingItem(me, dce, epF, maxEp, seasF);
                }

                FileInfo fi = new FileInfo(me.TheFileNoExt + dce.Extension);

                if (preventMove)
                {
                    //We do not want to move the file, just rename it
                    fi = new FileInfo(dce.DirectoryName + Path.DirectorySeparatorChar + me.Filename +
                                      dce.Extension);
                }

                if (dce.FullName != fi.FullName && !FindExistingActionFor(addTo, dce))
                {
                    // don't remove the base search folders
                    bool doTidyup =
                        !TVSettings.Instance.DownloadFolders.Any(folder =>
                                                                 folder.SameDirectoryLocation(fi.Directory.FullName));

                    addTo.Add(new ActionCopyMoveRename(ActionCopyMoveRename.Op.copy, dce, fi, me.Episode, doTidyup,
                                                       me, MDoc));
                }

                if (doExtraFiles)
                {
                    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 (PathTooLongException e)
            {
                WarnPathTooLong(me, dce, e, matched);
            }
            return(false);
        }
Example #32
0
        private static (bool identifysuccess, int seasF, int epF, int maxEp)  IdentifyFile([NotNull] ItemMissing me, [NotNull] FileInfo dce)
        {
            int season = me.Episode.AppropriateSeasonNumber;
            int epnum  = me.Episode.AppropriateEpNum;

            bool regularMatch =
                FinderHelper.FindSeasEp(dce, out int seasF, out int epF, out int maxEp, me.Episode.Show) &&
                seasF == season &&
                epF == epnum;

            if (regularMatch)
            {
                return(true, seasF, epF, maxEp);
            }

            if (me.Episode.Show.UseSequentialMatch)
            {
                bool sequentialMatch = TVDoc.MatchesSequentialNumber(dce.Name, me.Episode);

                if (sequentialMatch)
                {
                    return(true, season, epnum, me.Episode.EpNum2);
                }
            }

            return(false, 0, 0, 0);
        }