private void WarnPathTooLong([NotNull] ShowItemMissing me, [NotNull] FileInfo dce, [NotNull] Exception e, bool matched) { int season = me.MissingEpisode.AppropriateSeasonNumber; int epnum = me.MissingEpisode.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.MissingEpisode.TheCachedSeries.Name + ", Season " + season + ", Ep " + epnum + ". "; t += "To: " + me.TheFileNoExt; } LOGGER.Warn(t); }
private static ShowItemMissing UpdateMissingItem([NotNull] ShowItemMissing me, [NotNull] FileInfo dce, int epF, int maxEp, int seasF) { ShowRule sr = new ShowRule { DoWhatNow = RuleAction.kMerge, First = epF, Second = maxEp }; me.MissingEpisode.Show.AddSeasonRule(seasF, sr); LOGGER.Info( $"Looking at {me.MissingEpisode.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.MissingEpisode.Show); //Get the newly created processed episode we are after // ReSharper disable once InconsistentNaming ProcessedEpisode newPE = me.MissingEpisode; foreach (ProcessedEpisode pe in me.MissingEpisode.Show.SeasonEpisodes[seasF]) { if (pe.AppropriateEpNum == epF && pe.EpNum2 == maxEp) { newPE = pe; } } return(new ShowItemMissing(newPE, me.TargetFolder)); }
private static void FindMissingEpisode([NotNull] ShowItemMissing action, ItemList toRemove, ItemList newItems) { ProcessedEpisode processedEpisode = action.MissingEpisode; string url = TVSettings.Instance.UseJackettTextSearch ? TextJackettUrl(processedEpisode) : NormalJackettUrl(processedEpisode); RssItemList rssList = new RssItemList(); rssList.DownloadRSS(url, false, "Jackett"); ItemList newItemsForThisMissingEpisode = new ItemList(); foreach (RSSItem rss in rssList.Where(rss => RssMatch(rss, processedEpisode))) { if (TVSettings.Instance.DetailedRSSJSONLogging) { LOGGER.Info( $"Adding {rss.URL} from RSS feed as it appears to be match for {processedEpisode.Show.ShowName} S{processedEpisode.AppropriateSeasonNumber}E{processedEpisode.AppropriateEpNum}"); } newItemsForThisMissingEpisode.Add(new ActionTDownload(rss, action.TheFileNoExt, action)); toRemove.Add(action); } foreach (ActionTDownload x in FindDuplicates(newItemsForThisMissingEpisode)) { newItemsForThisMissingEpisode.Remove(x); } newItems.AddNullableRange(newItemsForThisMissingEpisode); }
private static int TypeNumber(Item a) { return(a switch { ShowItemMissing _ => 1, MovieItemMissing _ => 2, ActionCopyMoveRename _ => 3, ActionMoveRenameDirectory _ => 4, ActionTDownload _ => 5, ActionDownloadImage _ => 6, ActionMede8erViewXML _ => 7, ActionMede8erXML _ => 8, ActionNfo _ => 9, ActionPyTivoMeta _ => 10, ActionWdtvMeta _ => 11, ItemDownloading _ => 12, ActionDeleteFile _ => 13, ActionDeleteDirectory _ => 14, ActionDateTouchEpisode _ => 15, ActionDateTouchSeason _ => 16, ActionDateTouchMedia _ => 17, ActionDateTouchMovie _ => 18, ActionTRemove _ => 19, _ => throw new NotSupportedException() });
private void ProcessFolder(TVDoc.ScanSettings settings, [NotNull] ShowItemMissing 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); foreach (FileInfo testFile in files) { if (!ReviewFile(me, thisRound, testFile, settings, false, false, false, TVSettings.Instance.UseFullPathNameToMatchLibraryFolders)) { continue; } if (matchedFiles.Contains(testFile)) { continue; } matchedFiles.Add(testFile); LOGGER.Info($"Found {me.Filename} at: {testFile}"); } }
private void FindEpisode(TVDoc.ScanSettings settings, ShowItemMissing me, DirFilesCache dfc, ItemList newList, ItemList toRemove) { ItemList thisRound = new ItemList(); string baseFolder = me.Episode.Show.AutoAddFolderBase; LOGGER.Info($"Starting to look for {me.Filename} in the library: {baseFolder}"); List <FileInfo> matchedFiles = GetMatchingFilesFromFolder(baseFolder, dfc, me, settings, thisRound); foreach (string folderName in me.Episode.Show.AllFolderLocationsEpCheck(false) .Where(folders => folders.Value != null) .Where(folders => folders.Key == me.Episode.AppropriateProcessedSeason.SeasonNumber) .SelectMany(seriesFolders => seriesFolders.Value .Where(f => !string.IsNullOrWhiteSpace(f)) //No point looking here .Where(f => f != baseFolder))) { ProcessFolder(settings, me, folderName, dfc, thisRound, matchedFiles); } ProcessMissingItem(settings, newList, toRemove, me, thisRound, matchedFiles, TVSettings.Instance.UseFullPathNameToMatchLibraryFolders); }
private List <FileInfo> FindMatchedFiles(TVDoc.ScanSettings settings, [NotNull] DirCache dirCache, ShowItemMissing 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 static QueueSlotsSlot?CreateQueueSlotsSlot([NotNull] XElement slot, string simpleShowName, ShowItemMissing 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.MissingEpisode.Show) || seasF != action.MissingEpisode.AppropriateSeasonNumber || epF != action.MissingEpisode.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 }); }
private List <FileInfo> GetMatchingFilesFromFolder(string?baseFolder, DirFilesCache dfc, ShowItemMissing me, TVDoc.ScanSettings settings, ItemList thisRound) { List <FileInfo> matchedFiles; if (string.IsNullOrWhiteSpace(baseFolder)) { matchedFiles = new List <FileInfo>(); } else { IEnumerable <FileInfo> testFiles = dfc.GetFilesIncludeSubDirs(baseFolder); matchedFiles = testFiles.Where(testFile => ReviewFile(me, thisRound, testFile, settings, false, false, false, TVSettings.Instance.UseFullPathNameToMatchLibraryFolders)).ToList(); } return(matchedFiles); }
// ReSharper disable once FunctionComplexityOverflow protected bool ReviewFile(ShowItemMissing 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 cachedSeries match the filename? matched = me.MissingEpisode.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 = FinderHelper.GenerateTargetName(me, dce); if (preventMove) { //We do not want to move the file, just rename it fi = new FileInfo(dce.DirectoryName.EnsureEndsWithSeparator() + 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.MissingEpisode, 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 foundSeason, int foundEpisode, int maxEp) IdentifyFile([NotNull] ShowItemMissing me, [NotNull] FileInfo dce) { int season = me.MissingEpisode.AppropriateSeasonNumber; int epnum = me.MissingEpisode.AppropriateEpNum; bool regularMatch = FinderHelper.FindSeasEp(dce, out int foundSeason, out int foundEpisode, out int maxEp, me.MissingEpisode.Show) && foundSeason == season && foundEpisode == epnum; if (regularMatch) { return(true, foundSeason, foundEpisode, maxEp); } if (me.MissingEpisode.Show.UseSequentialMatch) { if (FinderHelper.MatchesSequentialNumber(dce.RemoveExtension(false), me.MissingEpisode)) { return(true, season, epnum, me.MissingEpisode.EpNum2); } } if (me.MissingEpisode.Show.UseAirDateMatch) { if (FinderHelper.FindSeasEpDateCheck(dce.Name, out foundSeason, out foundEpisode, me.MissingEpisode.Show)) { if (foundEpisode == epnum && foundSeason == season) { return(true, foundSeason, foundEpisode, -1); } } } if (me.MissingEpisode.Show.UseEpNameMatch) { if (FinderHelper.FindSeasEpNameCheck(dce, me.MissingEpisode.Show, out foundSeason, out foundEpisode)) { if (foundEpisode == epnum && foundSeason == season) { return(true, foundSeason, foundEpisode, -1); } } } return(false, 0, 0, 0); }
private static void FindMissingEpisode([NotNull] ShowItemMissing action, ItemList toRemove, ItemList newItems, UrlCache cache) { ProcessedEpisode pe = action.MissingEpisode; string imdbId = pe.TheCachedSeries.GetImdbNumber(); if (string.IsNullOrWhiteSpace(imdbId)) { return; } string simpleShowName = pe.Show.ShowName.CompareName(); string simpleSeriesName = pe.TheCachedSeries.Name.CompareName(); 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.MissingEpisode.TheCachedSeries.Name}"); return; } JObject jsonResponse = JObject.Parse(response); if (jsonResponse.ContainsKey(TVSettings.Instance.SearchJSONRootNode)) { JToken?x = jsonResponse[TVSettings.Instance.SearchJSONRootNode]; if (x is null) { LOGGER.Warn($"Could not find {TVSettings.Instance.SearchJSONRootNode} in JSON Repsonse {jsonResponse}"); return; } foreach (JToken item in x) { 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]; int seeders = (int)item[TVSettings.Instance.SearchJSONSeedersToken]; 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}"); LOGGER.Info($"Seeds: {seeders}"); } if (itemName is null || itemUrl is null) { continue; } 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}"); ItemDownloading becomes = new ItemDownloading(new FutureTorrentEntry(itemUrl, action.TheFileNoExt), action.MissingEpisode, action.TheFileNoExt, DownloadingFinder.DownloadApp.qBitTorrent, action); newItemsForThisMissingEpisode.Add(new ActionTDownload(itemName, itemSizeBytes, seeders, itemUrl, action.TheFileNoExt, pe, action, $"JSON WebPage: {TVSettings.Instance.SearchJSONURL}{imdbId}", becomes)); toRemove.Add(action); } else { LOGGER.Info( $"{TVSettings.Instance.SearchJSONFilenameToken} or {TVSettings.Instance.SearchJSONURLToken} not found in {TVSettings.Instance.SearchJSONURL}{imdbId} for {action.MissingEpisode.TheCachedSeries.Name}"); } } } else { LOGGER.Info( $"{TVSettings.Instance.SearchJSONRootNode} not found in {TVSettings.Instance.SearchJSONURL}{imdbId} for {action.MissingEpisode.TheCachedSeries.Name}"); } RemoveDuplicates(newItemsForThisMissingEpisode); newItems.AddNullableRange(newItemsForThisMissingEpisode); }