private static (int seas, int ep, int maxEp) IdentifyEpisode(ShowConfiguration?si, [NotNull] Match m, TVSettings.FilenameProcessorRE re) { if (!int.TryParse(m.Groups["s"].ToString(), out int seas)) { if (!re.RegExpression.Contains("<s>") && (si?.AppropriateSeasons().Count ?? 0) == 1) { seas = 1; } else { seas = -1; } } if (!int.TryParse(m.Groups["e"].ToString(), out int ep)) { ep = -1; } if (!int.TryParse(m.Groups["f"].ToString(), out int maxEp)) { maxEp = -1; } return(seas, ep, maxEp); }
private List <ProcessedEpisode>?MatchEpisodes(FileInfo droppedFile) { ShowConfiguration?bestShow = FinderHelper.FindBestMatchingShow(droppedFile, MDoc.TvLibrary.Shows); if (bestShow is null) { return(null); } if (!FinderHelper.FindSeasEp(droppedFile, out int seasonNum, out int episodeNum, out int _, bestShow, out TVSettings.FilenameProcessorRE _)) { return(null); } try { ProcessedEpisode episode = bestShow.GetEpisode(seasonNum, episodeNum); return(new List <ProcessedEpisode> { episode }); } catch (ShowConfiguration.EpisodeNotFoundException) { return(null); } }
public static bool FindSeasEpNameCheck(FileInfo?fi, ShowConfiguration?si, out int seas, out int ep) { ep = -1; seas = -1; if (fi is null || si is null) { return(false); } CachedSeriesInfo?ser = si.CachedShow; if (ser is null) { return(false); } string simplifiedFilename = fi.Name.CompareName(); foreach (Episode epi in si.EpisodesToUse()) { string simplifiedEpName = epi.Name.CompareName(); if (simplifiedFilename.Contains(simplifiedEpName)) { seas = epi.GetSeasonNumber(si.Order); ep = epi.GetEpisodeNumber(si.Order); return(true); } } return(false); }
private static void TvdbFor(ShowConfiguration?si) { if (si?.WebsiteUrl is null) { return; } Helpers.OpenUrl(si.WebsiteUrl); }
private static void TvSourceFor(ShowConfiguration?si) { if (si != null) { if (si.WebsiteUrl.HasValue()) { Helpers.OpenUrl(si.WebsiteUrl !); } else if (si.CachedShow?.WebUrl.HasValue() ?? false) { Helpers.OpenUrl(si.CachedShow?.WebUrl !); } } }
public static bool FindSeasEp(string directory, string filename, out int seas, out int ep, out int maxEp, ShowConfiguration?si, IEnumerable <TVSettings.FilenameProcessorRE> rexps, out TVSettings.FilenameProcessorRE?rex) { string showNameHint = si != null ? si.ShowName : string.Empty; maxEp = -1; seas = -1; ep = -1; rex = null; filename = SimplifyFilename(filename, showNameHint); string fullPath = directory.HasValue() ? directory + Path.DirectorySeparatorChar + filename : filename; // construct full path with sanitised filename fullPath = fullPath.ToLower() + " "; foreach (TVSettings.FilenameProcessorRE re in rexps.Where(re => re.Enabled)) { try { string pathToTest = re.UseFullPath ? fullPath : filename.ToLower() + " "; Match m = Regex.Match(pathToTest, re.RegExpression, RegexOptions.IgnoreCase); if (m.Success) { (seas, ep, maxEp) = IdentifyEpisode(si, m, re); rex = re; if (seas != -1 && ep != -1) { return(true); } } } catch (FormatException fe) { Logger.Warn($"Please check for the regex {re.RegExpression} as it's causing an FormatException error {fe.Message}"); } catch (ArgumentException ae) { Logger.Warn($"Please check for the regex {re.RegExpression} as it's causing an ArgumentException error {ae.Message}"); } } return(seas != -1 && ep != -1); }
public ItemList ProcessShow(ShowConfiguration?si) { ItemList theActionList = new ItemList(); if (si is null) { return(theActionList); } foreach (DownloadIdentifier di in identifiers) { theActionList.Add(di.ProcessShow(si)); } return(theActionList); }
public ItemList ProcessSeason(ShowConfiguration?si, string folder, int snum) { ItemList theActionList = new ItemList(); if (si is null) { return(theActionList); } foreach (DownloadIdentifier di in identifiers) { theActionList.Add(di.ProcessSeason(si, folder, snum)); } return(theActionList); }
private void GotoEpGuide(ShowConfiguration?si, PossibleMergedEpisode?mlastSelected) { if (mlastSelected != null) { mainUi.GotoEpguideFor(mlastSelected.Episode, true); } else { if (si != null) { mainUi.GotoEpguideFor(si, true); } } Close(); }
public ItemList ForceUpdateSeason(DownloadIdentifier.DownloadType dt, ShowConfiguration?si, string folder, int snum) { ItemList theActionList = new ItemList(); if (si is null) { return(theActionList); } foreach (DownloadIdentifier di in identifiers) { if (dt == di.GetDownloadType()) { theActionList.Add(di.ProcessSeason(si, folder, snum, true)); } } return(theActionList); }
public static bool FileNeeded(DirectoryInfo?di, ShowConfiguration?si, DirFilesCache dfc) { if (di is null) { throw new ArgumentNullException(nameof(di)); } if (si is null) { throw new ArgumentNullException(nameof(si)); } if (FindSeasEp(di, out int seasF, out int epF, si, out _)) { return(EpisodeNeeded(si, dfc, seasF, epF, di)); } //We may need the file return(true); }
private void lvDuplicates_MouseClick(object sender, [NotNull] MouseEventArgs e) { if (e.Button != MouseButtons.Right) { return; } if (lvMergedEpisodes.SelectedItems.Count == 0) { return; } PossibleMergedEpisode?mlastSelected = (PossibleMergedEpisode)lvMergedEpisodes.SelectedItems[0].Tag; ListViewItem? mlastClicked = lvMergedEpisodes.SelectedItems[0]; ShowConfiguration? si = mlastSelected?.ShowConfiguration; if (si == null) { return; } Point pt = lvMergedEpisodes.PointToScreen(new Point(e.X, e.Y)); possibleMergedEpisodeRightClickMenu.Items.Clear(); AddRcMenuItem("Episode Guide", (o, args) => GotoEpGuide(si, mlastSelected)); AddRcMenuItem("Force Refresh", (o, args) => mainUi.ForceRefresh(si, false)); AddRcMenuItem("Edit Show", (o, args) => mainUi.EditShow(si)); AddRcMenuItem("Edit " + ProcessedSeason.UIFullSeasonWord(mlastSelected.SeasonNumber), (o, args) => mainUi.EditSeason(si, mlastSelected.SeasonNumber)); possibleMergedEpisodeRightClickMenu.Items.Add(new ToolStripSeparator()); AddRcMenuItem("Add Rule", (o, args) => AddRule(mlastSelected, si, mlastClicked)); possibleMergedEpisodeRightClickMenu.Show(pt); }
protected readonly ShowConfiguration?SelectedShow; // if for an entire show, rather than specific episode protected ActionWriteMetadata(FileInfo where, ShowConfiguration sI) { Where = where; SelectedShow = sI; }
private void ProcessFile([NotNull] FileInfo droppedFile, IDialogParent owner) { if ((droppedFile.Attributes & FileAttributes.Directory) == FileAttributes.Directory) { Logger.Error($"{droppedFile.FullName} is a directory, ignoring."); return; } if (!droppedFile.IsMovieFile()) { Logger.Info($"{droppedFile.FullName} is not a movie file, ignoring."); return; } // Note that the extension of the file may not be fi.extension as users can put ".mkv.t" for example as an extension string otherExtension = TVSettings.Instance.FileHasUsefulExtensionDetails(droppedFile, true); ShowConfiguration?bestShow = (string)cbShowList.SelectedItem == "<Auto>" ? FinderHelper.FindBestMatchingShow(droppedFile.FullName, mDoc.TvLibrary.Shows) : mDoc.TvLibrary.Shows.FirstOrDefault(item => item.ShowName == (string)cbShowList.SelectedItem); if (bestShow is null) { if (TVSettings.Instance.AutoAddAsPartOfQuickRename) { List <MediaConfiguration> addedShows = FinderHelper.FindMedia(new List <FileInfo> { droppedFile }, mDoc, owner); bestShow = addedShows.OfType <ShowConfiguration>().FirstOrDefault(); if (bestShow != null) { mDoc.Add(bestShow); mDoc.TvAddedOrEdited(true, false, false, parent, bestShow); Logger.Info($"Added new show called: {bestShow.ShowName}"); } } if (bestShow is null) { Logger.Info($"Cannot find show for {droppedFile.FullName}, ignoring this file."); return; } } if (!FinderHelper.FindSeasEp(droppedFile, out int seasonNum, out int episodeNum, out int _, bestShow, out TVSettings.FilenameProcessorRE _)) { Logger.Info($"Cannot find episode for {bestShow.ShowName} for {droppedFile.FullName}, ignoring this file."); return; } try { ProcessedEpisode episode = bestShow.GetEpisode(seasonNum, episodeNum); string filename = TVSettings.Instance.FilenameFriendly( TVSettings.Instance.NamingStyle.NameFor(episode, otherExtension, droppedFile.DirectoryName.Length)); FileInfo targetFile = new FileInfo(droppedFile.DirectoryName.EnsureEndsWithSeparator() + filename); if (droppedFile.FullName == targetFile.FullName) { Logger.Info( $"Can't rename file for {bestShow.ShowName} for {droppedFile.FullName}, as it already has the appropriate name."); return; } mDoc.TheActionList.Add(new ActionCopyMoveRename(droppedFile, targetFile, episode, mDoc)); // if we're copying/moving a file across, we might also want to make a thumbnail or NFO for it mDoc.TheActionList.AddNullableRange(new DownloadIdentifiersController().ProcessEpisode(episode, targetFile)); //If keep together is active then we may want to copy over related files too if (TVSettings.Instance.KeepTogether) { FileFinder.KeepTogether(mDoc.TheActionList, false, true, mDoc); } } catch (ShowConfiguration.EpisodeNotFoundException) { Logger.Info( $"Can't rename file for {bestShow.ShowName} for {droppedFile.FullName}, as it does not have Episode {episodeNum} for Season {seasonNum}."); } }
public AddEditSeasEpFinders(List <TVSettings.FilenameProcessorRE> rex, List <ShowConfiguration> sil, ShowConfiguration?initialShow, string initialFolder) { OutputRegularExpressions = rex; shows = sil; InitializeComponent(); SetupGrid(); FillGrid(OutputRegularExpressions); foreach (ShowConfiguration si in shows) { cbShowList.Items.Add(si.ShowName); if (si == initialShow) { cbShowList.SelectedIndex = cbShowList.Items.Count - 1; } } txtFolder.Text = initialFolder; }
public static bool FindSeasEp(FileInfo?fi, out int seas, out int ep, out int maxEp, ShowConfiguration?si, IEnumerable <TVSettings.FilenameProcessorRE> rexps, out TVSettings.FilenameProcessorRE?re) { if (fi is null) { re = null; seas = -1; ep = -1; maxEp = -1; return(false); } return(FindSeasEp(fi.Directory.FullName, fi.RemoveExtension(), out seas, out ep, out maxEp, si, rexps, out re)); }
public static bool FindSeasEp(string itemName, out int seas, out int ep, out int maxEp, ShowConfiguration?si, IEnumerable <TVSettings.FilenameProcessorRE> rexps, out TVSettings.FilenameProcessorRE?re) { return(FindSeasEp(string.Empty, itemName, out seas, out ep, out maxEp, si, rexps, out re)); }
public static bool FindSeasEp(FileInfo fi, out int seas, out int ep, out int maxEp, ShowConfiguration?si, out TVSettings.FilenameProcessorRE?re) { return(FindSeasEp(fi, out seas, out ep, out maxEp, si, TVSettings.Instance.FNPRegexs, out re)); }
public static bool FindSeasEp(FileInfo theFile, out int seasF, out int epF, out int maxEp, ShowConfiguration?sI) { return(FindSeasEp(theFile, out seasF, out epF, out maxEp, sI, out TVSettings.FilenameProcessorRE _)); }
public static bool FindSeasEp(string itemName, out int seas, out int ep, out int maxEp, ShowConfiguration?show) { return(FindSeasEp(string.Empty, itemName, out seas, out ep, out maxEp, show, TVSettings.Instance.FNPRegexs, out TVSettings.FilenameProcessorRE _)); }
public static bool FindSeasEpDateCheck(string?filename, out int seas, out int ep, ShowConfiguration?si) { ep = -1; seas = -1; if (filename is null || si is null) { return(false); } // look for a valid airdate in the filename // check for YMD, DMY, and MDY // only check against airdates we expect for the given show CachedSeriesInfo ser = si.CachedShow; if (ser is null) { return(false); } string[] dateFormats = { "yyyy-MM-dd", "dd-MM-yyyy", "MM-dd-yyyy", "yy-MM-dd", "dd-MM-yy", "MM-dd-yy" }; // force possible date separators to a dash filename = filename.Replace("/", "-"); filename = filename.Replace(".", "-"); filename = filename.Replace(",", "-"); filename = filename.Replace(" ", "-"); foreach (Episode epi in si.EpisodesToUse()) { LocalDateTime?dt = epi.GetAirDateDt(); // file will have local timezone date, not ours if (dt is null) { continue; } TimeSpan closestDate = TimeSpan.MaxValue; foreach (string dateFormat in dateFormats) { string datestr = dt.Value.ToString(dateFormat, CultureInfo.CurrentCulture); if (filename.Contains(datestr) && DateTime.TryParseExact(datestr, dateFormat, new CultureInfo("en-GB"), DateTimeStyles.None, out DateTime dtInFilename)) { TimeSpan timeAgo = DateTime.Now.Subtract(dtInFilename); if (timeAgo < closestDate) { seas = epi.GetSeasonNumber(si.Order); ep = epi.GetEpisodeNumber(si.Order); closestDate = timeAgo; } } } } return(ep != -1 && seas != -1); }
private static void UpdateEpisodeFields([NotNull] Episode episode, ShowConfiguration?show, [NotNull] XElement root, bool isMultiPart) { root.UpdateElement("title", episode.Name, true); root.UpdateElement("id", episode.EpisodeId, true); root.UpdateElement("plot", episode.Overview, true); UpdateAmongstElements(root, "studio", episode.TheCachedSeries.Network); UpdateId(root, "tvdb", "true", episode.EpisodeId); UpdateId(root, "imdb", "false", episode.ImdbCode); string showRating = episode.EpisodeRating; if (showRating != null) { UpdateRatings(root, showRating, episode.SiteRatingCount ?? 0); } if (!(show is null)) { root.UpdateElement("originaltitle", show.ShowName, true); root.UpdateElement("showtitle", show.ShowName, true); root.UpdateElement("season", episode.GetSeasonNumber(show.Order), true); root.UpdateElement("episode", episode.GetEpisodeNumber(show.Order), true); root.UpdateElement("mpaa", show.CachedShow?.ContentRating, true); //actor(s) and guest actor(s) CachedSeriesInfo s = show.CachedShow; if (s != null) { ReplaceActors(root, episode.AllActors(s)); } } if (episode.FirstAired.HasValue) { root.UpdateElement("aired", episode.FirstAired.Value.ToString("yyyy-MM-dd"), true); } //Director(s) string?epDirector = episode.EpisodeDirector; if (!string.IsNullOrEmpty(epDirector)) { string[] dirs = epDirector.Split('|'); if (dirs.Any()) { root.ReplaceElements("director", dirs); } } //Writers(s) string?epWriter = episode.Writer; if (!string.IsNullOrEmpty(epWriter)) { string[] writers = epWriter.Split('|'); if (writers.Any()) { root.ReplaceElements("credits", writers); } } if (isMultiPart && show != null) { XElement resumeElement = root.GetOrCreateElement("resume"); //we have to put 0 as we don't know where the multipart episode starts/ends resumeElement.UpdateElement("position", 0); resumeElement.UpdateElement("total", 0); //For now we only put art in for multipart episodes. Kodi finds the art appropriately //without our help for the others string filename = TVSettings.Instance.FilenameFriendly(show, episode); string thumbFilename = filename + ".jpg"; UpdateAmongstElements(root, "thumb", thumbFilename); //Should be able to do this using the local filename, but only seems to work if you provide a URL //XMLHelper.WriteElementToXML(writer, "thumb", LocalCache.Instance.GetTVDBDownloadURL(episode.GetFilename())) } }