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}"); } } }
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 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); }
public ActionTDownload([NotNull] RSSItem rss, string theFileNoExt, ProcessedEpisode pe, ItemMissing me) { SourceName = rss.Title; url = rss.URL; this.theFileNoExt = theFileNoExt; Episode = pe; UndoItemMissing = me; }
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); }
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; }
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; }
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; }
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; }
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; }
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); } }
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; }
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 }; }
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(); } } }
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)); }
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() });
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); }
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) { 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); }
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); }
// 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; }
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 }); }
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); }
// 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); }
// 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; }
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"); } } } }
// 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); }
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); }