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); }
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); }
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); } int c = 0; DirCache dirCache = new DirCache(); foreach (string s in TVSettings.Instance.DownloadFolders) { if (this.ActionCancel) { return; } dirCache.AddFolder(prog, c, fileCount, s, true); } int currentItem = 0; int totalN = this.ActionList.Count; foreach (Item action1 in this.ActionList) { if (this.ActionCancel) { return; } prog.Invoke(startpct + (totPct - startpct) * (++currentItem) / (totalN + 1)); if (!(action1 is ItemMissing me)) { continue; } int numberMatched = 0; ItemList thisRound = new ItemList(); DirCacheEntry matchedFile = null; foreach (DirCacheEntry dce in dirCache) { if (!ReviewFile(me, thisRound, dce)) { continue; } numberMatched++; matchedFile = dce; } if (numberMatched == 1) { if (!OtherActionsMatch(matchedFile, me, this.ActionList)) { toRemove.Add(action1); newList.AddRange(thisRound); } else { Logger.Warn($"Ignoring potential match for {action1.Episode.SI.ShowName} S{action1.Episode.AppropriateSeasonNumber} E{action1.Episode.AppropriateEpNum}: with file {matchedFile?.TheFile.FullName} as there are multiple actions for that file"); } } else if (numberMatched > 1) { Logger.Warn($"Ignoring potential match for {action1.Episode.SI.ShowName} S{action1.Episode.AppropriateSeasonNumber} E{action1.Episode.AppropriateEpNum}: 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) { this.ActionList.Remove(i); } foreach (Item i in newList) { this.ActionList.Add(i); } }