private ActionOutcome ReplaceMultipartFile() { ShowConfiguration si = Episode?.Show ?? SelectedShow; //We will replace the file as too difficult to update multiparts //We can't use XDocument as it's not fully valid XML List <XElement> episodeXmLs = new List <XElement>(); if (Episode != null) { foreach (Episode ep in Episode.SourceEpisodes) { XElement epNode = new XElement("episodedetails"); UpdateEpisodeFields(ep, si, epNode, true); episodeXmLs.Add(epNode); } } try { using (StreamWriter writer = File.CreateText(Where.FullName)) { foreach (XElement ep in episodeXmLs) { writer.WriteLine(ep); } } } catch (IOException e) { return(new ActionOutcome(e)); } return(ActionOutcome.Success()); }
public override ActionOutcome Go(TVRenameStats stats) { //if the directory is the root download folder do not delete if (TVSettings.Instance.MonitorFolders && TVSettings.Instance.DownloadFolders.Contains(toRemove.FullName)) { return(new ActionOutcome($@"Not removing {toRemove.FullName} as it is a Search Folder")); } try { if (toRemove.Exists) { DeleteOrRecycleFolder(toRemove); if (Tidyup != null && Tidyup.DeleteEmpty) { LOGGER.Info($"Testing {toRemove.Parent.FullName } to see whether it should be tidied up"); DoTidyUp(toRemove.Parent); } } return(ActionOutcome.Success()); } catch (Exception e) { return(new ActionOutcome(e)); } }
public override ActionOutcome Go(TVRenameStats stats) { try { byte[]? theData = si.Provider == TVDoc.ProviderType.TheTVDB ? TheTVDB.LocalCache.Instance.GetTvdbDownload(path) : HttpHelper.Download(path, false); if (theData is null || theData.Length == 0) { return(new ActionOutcome("Unable to download " + path)); } if (shrinkLargeMede8ErImage) { theData = ConvertBytes(theData); } System.IO.FileStream fs = new System.IO.FileStream(destination.FullName, System.IO.FileMode.Create); fs.Write(theData, 0, theData.Length); fs.Close(); } catch (Exception e) { return(new ActionOutcome(e)); } return(ActionOutcome.Success()); }
private ActionOutcome UpdateFile() { //We will replace the file as too difficult to update multiparts //We can't use XDocument as it's not fully valid XML if (Episode != null && Episode.Type == ProcessedEpisode.ProcessedEpisodeType.merged) { return(ReplaceMultipartFile()); } XDocument doc = XDocument.Load(Where.FullName); XElement root = doc.Root; if (root is null) { return(new ActionOutcome($"Could not load {Where.FullName}")); } if (Episode != null) // specific episode { ShowItem si = Episode.Show ?? SelectedShow; UpdateEpisodeFields(Episode, si, root, false); } else if (SelectedShow != null) // show overview (tvshow.nfo) { UpdateShowFields(root); } doc.Save(Where.FullName); return(ActionOutcome.Success()); }
public override ActionOutcome Go(TVRenameStats stats) { try { if (whereFile != null) { ProcessFile(whereFile, updateTime); } if (whereDirectory != null) { System.IO.Directory.SetLastWriteTimeUtc(whereDirectory.FullName, updateTime); } } catch (UnauthorizedAccessException uae) { return(new ActionOutcome(uae)); } catch (Exception e) { return(new ActionOutcome(e)); } return(ActionOutcome.Success()); }
public override ActionOutcome Go(TVRenameStats stats) { return(Episode != null?WriteEpisodeMetaDataFile() : SelectedShow != null?WriteSeriesXml() : ActionOutcome.Success()); //todo WDTV Movie support WriteMovieXml(); }
private ActionOutcome WriteSeriesXml() { try { XmlWriterSettings settings = new XmlWriterSettings { Indent = true, NewLineOnAttributes = true }; using (XmlWriter writer = XmlWriter.Create(Where.FullName, settings)) { writer.WriteStartElement("details"); writer.WriteStartElement("show"); writer.WriteElement("title", SelectedShow !.ShowName); writer.WriteElement("premiered", SelectedShow.CachedShow?.FirstAired); writer.WriteElement("year", SelectedShow.CachedShow?.Year); writer.WriteElement("status", SelectedShow.CachedShow?.Status); writer.WriteElement("mpaa", SelectedShow.CachedShow?.ContentRating); writer.WriteElement("tvdbid", SelectedShow.CachedShow?.TvdbCode); writer.WriteElement("plot", SelectedShow.CachedShow?.Overview); foreach (string genre in SelectedShow.Genres) { writer.WriteElement("genre", genre); } float siteRating = SelectedShow.CachedShow?.SiteRating ?? 0 * 10; int intSiteRating = (int)siteRating; if (intSiteRating > 0) { writer.WriteElement("rating", intSiteRating); } writer.WriteInfo("moviedb", "imdb", "id", SelectedShow.CachedShow?.Imdb); string rt = SelectedShow.CachedShow?.Runtime; if (!string.IsNullOrEmpty(rt)) { writer.WriteElement("runtime", rt + " min"); } writer.WriteEndElement(); // show writer.WriteEndElement(); // tvshow } return(ActionOutcome.Success()); } catch (Exception e) { return(new ActionOutcome(e)); } }
public override ActionOutcome Go(TVRenameStats stats) { try { client.RemoveCompletedDownload(name); return(ActionOutcome.Success()); } catch (Exception e) { return(new ActionOutcome(e)); } }
public override ActionOutcome Go(TVRenameStats stats) { if (Episode is null) { return(new ActionOutcome("PyTivoMetaData Go called with no Episode Set")); } try { // create folder if it does not exist. (Only really applies when .meta\ folder is being used.) if (!Where.Directory.Exists) { Directory.CreateDirectory(Where.Directory.FullName); } using ( System.IO.StreamWriter writer = new System.IO.StreamWriter(Where.FullName, false, System.Text.Encoding.GetEncoding(1252))) { // See: http://pytivo.sourceforge.net/wiki/index.php/Metadata writer.WriteLine($"title : {Episode.Show.ShowName}"); writer.WriteLine($"seriesTitle : {Episode.Show.ShowName}"); writer.WriteLine($"episodeTitle : {Episode.Name}"); writer.WriteLine( $"episodeNumber : {Episode.AppropriateSeasonNumber}{Episode.AppropriateEpNum:0#}"); writer.WriteLine("isEpisode : true"); writer.WriteLine($"description : {Episode.Overview}"); if (Episode.FirstAired != null) { writer.WriteLine($"originalAirDate : {Episode.FirstAired.Value:yyyy-MM-dd}T00:00:00Z"); } writer.WriteLine($"callsign : {Episode.Show.CachedShow?.Network}"); WriteEntries(writer, "vDirector", Episode.EpisodeDirector); WriteEntries(writer, "vWriter", Episode.Writer); WriteEntries(writer, "vActor", string.Join("|", Episode.Show.GetActorNames())); WriteEntries(writer, "vGuestStar", Episode.EpisodeGuestStars); // not worrying about actors being repeated WriteEntries(writer, "vProgramGenre", string.Join("|", Episode.Show.Genres)); } return(ActionOutcome.Success()); } catch (Exception e) { return(new ActionOutcome(e)); } }
public override ActionOutcome Go(TVRenameStats stats) { bool isDownloadable = url.IsWebLink(); try { try { if (TVSettings.Instance.CheckuTorrent && isDownloadable) { FileInfo downloadedFile = DownloadFile(); new uTorrent().StartTorrentDownload(downloadedFile); return(ActionOutcome.Success()); } if (TVSettings.Instance.CheckqBitTorrent) { if (isDownloadable && TVSettings.Instance.qBitTorrentDownloadFilesFirst) { FileInfo downloadedFile = DownloadFile(); new qBitTorrent().StartTorrentDownload(downloadedFile); return(ActionOutcome.Success()); } else { new qBitTorrent().StartUrlDownload(url); return(ActionOutcome.Success()); } } } catch (DownloadFailedException e) { //Don't worry about this error, we'll retry below } if (Helpers.OpenUrl(url)) { return(ActionOutcome.Success()); } return(new ActionOutcome("No torrent clients enabled to download RSS - Tried to use system open, but failed")); } catch (Exception e) { return(new ActionOutcome(e)); } }
public override ActionOutcome Go(TVRenameStats stats) { try { ProcessFile(WhereFile, UpdateTime); } catch (UnauthorizedAccessException uae) { return(new ActionOutcome(uae)); } catch (Exception e) { return(new ActionOutcome(e)); } return(ActionOutcome.Success()); }
public override ActionOutcome Go(TVRenameStats stats) { DirectoryInfo source = new DirectoryInfo(sourceFolder); DirectoryInfo target = new DirectoryInfo(targetFolder); if (target.Exists && source.Exists && !target.EnumerateFiles().Any()) { target.Delete(); source.MoveTo(targetFolder); LOGGER.Info($"Moved whole directory {sourceFolder } to {targetFolder}"); return(ActionOutcome.Success()); } if (target.Exists) { if (target.GetFiles().Any(x => x.IsMovieFile())) { throw new ActionFailedException("Target location has movie files - not copying just in case"); } //Copy files foreach (FileInfo file in source.EnumerateFiles()) { string destFile = Path.Combine(targetFolder, file.Name); if (!File.Exists(destFile)) { file.MoveTo(destFile); LOGGER.Info($"Moved {file.FullName} to {destFile}"); } } if (Directory.IsEmpty(source.FullName)) { source.Delete(false); LOGGER.Info($"Deleted empty directory {source.FullName}"); } return(ActionOutcome.Success()); } source.MoveTo(targetFolder); LOGGER.Info($"Moved whole directory {sourceFolder } to {targetFolder}"); return(ActionOutcome.Success()); }
/// <summary> /// Processes an Action by running it. /// </summary> /// <param name="infoIn">A ProcessActionInfo to be processed. It will contain the Action to be processed</param> private void ProcessSingleAction(object infoIn) { if (!(infoIn is ProcessActionInfo info)) { return; } try { info.Sem.WaitOne(); // don't start until we're allowed to actionStarting = false; // let our creator know we're started ok Action action = info.TheAction; if (action == null) { return; } Logger.Trace("Triggering Action: {0} - {1} - {2}", action.Name, action.Produces, action.ToString()); action.Outcome = action.Go(mStats); if (action.Outcome.Error) { action.ErrorText = action.Outcome.LastError.Message; } if (!action.Outcome.Done) { Logger.Error("Hlep"); } } catch (ThreadAbortException) { //Thread has been killed off } catch (Exception e) { Logger.Fatal(e, "Unhandled Exception in Process Single Action"); info.TheAction.Outcome = ActionOutcome.CompleteFail(); } finally { info.Sem.Release(); } }
public override ActionOutcome Go(TVRenameStats stats) { try { if (toRemove.Exists) { DeleteOrRecycleFile(toRemove); if (Tidyup != null && Tidyup.DeleteEmpty) { LOGGER.Info($"Testing {toRemove.Directory.FullName } to see whether it should be tidied up"); DoTidyUp(toRemove.Directory); } } } catch (Exception e) { return(new ActionOutcome(e)); } return(ActionOutcome.Success()); }
public override ActionOutcome Go(TVRenameStats stats) { try { if (Episode != null) // specific episode { WriteEpisodeXml(); } else if (SelectedShow != null) // show overview (Series.xml) { WriteSeriesXml(); } return(ActionOutcome.Success()); } catch (Exception e) { return(new ActionOutcome(e)); } }
public override ActionOutcome Go(TVRenameStats stats) { try { if (!(TVSettings.Instance.CheckuTorrent || TVSettings.Instance.CheckqBitTorrent)) { return(new ActionOutcome("No torrent clients enabled to download RSS")); } if (!TVSettings.Instance.qBitTorrentDownloadFilesFirst && TVSettings.Instance.CheckqBitTorrent) { qBitTorrentFinder.StartTorrentDownload(url, null, false); return(ActionOutcome.Success()); } byte[] r = HttpHelper.GetUrlBytes(url, true); if (r is null || r.Length == 0) { return(new ActionOutcome($"No data downloaded from {url}")); } string saveTemp = SaveDownloadedData(r, SourceName); if (TVSettings.Instance.CheckuTorrent) { uTorrentFinder.StartTorrentDownload(saveTemp, theFileNoExt); } if (TVSettings.Instance.CheckqBitTorrent) { qBitTorrentFinder.StartTorrentDownload(url, saveTemp, TVSettings.Instance.qBitTorrentDownloadFilesFirst); } return(ActionOutcome.Success()); } catch (Exception e) { return(new ActionOutcome(e)); } }
public override ActionOutcome Go(TVRenameStats stats) { try { if (!Where.Exists) { CreateBlankFile(); } ActionOutcome actionOutcome = UpdateFile(); Where.LastWriteTime = DateTimeOffset.FromUnixTimeSeconds(UpdateTime() ?? 0).UtcDateTime; return(actionOutcome); } catch (IOException ex) { return(new ActionOutcome(ex)); } catch (UnauthorizedAccessException ex) { return(new ActionOutcome(ex)); } catch (XmlException) { //Assume that the file needs to be recreated try { Where.Delete(true); return(Go(stats)); } catch (IOException ex) { return(new ActionOutcome(ex)); } catch (UnauthorizedAccessException ex) { return(new ActionOutcome(ex)); } } }
public override ActionOutcome Go(TVRenameStats stats) { XmlWriterSettings settings = new XmlWriterSettings { Indent = true, NewLineOnAttributes = true }; try { using (XmlWriter writer = XmlWriter.Create(Where.FullName, settings)) { writer.WriteStartElement("FolderTag"); writer.WriteElement("ViewMode", "Movie"); writer.WriteElement("ViewType", "Video"); writer.WriteEndElement(); } } catch (Exception e) { return(new ActionOutcome(e)); } return(ActionOutcome.Success()); }
protected override ActionOutcome UpdateFile() { //We will replace the file as too difficult to update multiparts //We can't use XDocument as it's not fully valid XML if (Episode != null && Episode.Type == ProcessedEpisode.ProcessedEpisodeType.merged) { return(ReplaceMultipartFile()); } XDocument doc = XDocument.Load(Where.FullName); XElement? root = doc.Root; if (root is null) { return(new ActionOutcome($"Could not load {Where.FullName}")); } ShowConfiguration si = Episode !.Show; UpdateEpisodeFields(Episode, si, root, false); doc.Save(Where.FullName); return(ActionOutcome.Success()); }
public override ActionOutcome Go(TVRenameStats stats) { // read NTFS permissions (if any) FileSecurity security = null; try { security = From.GetAccessControl(); } catch { // ignored } try { //we use a temp name just in case we are interrupted or some other problem occurs string tempName = TempFor(To); if (!Directory.Exists(To.Directory.FullName)) { Directory.CreateDirectory(To.Directory.FullName); } // If both full filenames are the same then we want to move it away and back //This deals with an issue on some systems (XP?) that case insensitive moves did not occur if (IsMoveRename() || FileHelper.Same(From, To)) { // This step could be slow, so report progress CopyMoveResult moveResult = File.Move(From.FullName, tempName, MoveOptions.CopyAllowed | MoveOptions.ReplaceExisting, CopyProgressCallback, null); if (moveResult.ErrorCode != 0) { throw new ActionFailedException(moveResult.ErrorMessage); } } else { //we are copying Debug.Assert(Operation == Op.copy); // This step could be slow, so report progress CopyMoveResult copyResult = File.Copy(From.FullName, tempName, CopyOptions.None, true, CopyProgressCallback, null); if (copyResult.ErrorCode != 0) { throw new ActionFailedException(copyResult.ErrorMessage); } } // Copying the temp file into the correct name is very quick, so no progress reporting File.Move(tempName, To.FullName, MoveOptions.ReplaceExisting); LOGGER.Info($"{Name} completed: {From.FullName} to {To.FullName } "); UpdateStats(stats); if (To.IsMovieFile()) { //File is correct name LOGGER.Debug($"Just copied {To.FullName} to the right place. Marking it as 'seen'."); if (Episode != null) { //Record this episode as seen TVSettings.Instance.PreviouslySeenEpisodes.EnsureAdded(SourceEpisode); if (TVSettings.Instance.IgnorePreviouslySeen) { doc.SetDirty(); } } if (Movie != null) { //Record this movie as seen TVSettings.Instance.PreviouslySeenMovies.EnsureAdded(Movie); if (TVSettings.Instance.IgnorePreviouslySeenMovies) { doc.SetDirty(); } } } } catch (Exception e) { LOGGER.Warn(e, $"Error occurred while {Name}: {From.FullName} to {To.FullName } "); return(new ActionOutcome(e)); } // set NTFS permissions try { if (security != null) { To.SetAccessControl(security); } } catch { // ignored } try { if (Operation == Op.move && Tidyup != null && Tidyup.DeleteEmpty) { LOGGER.Info($"Testing {From.Directory.FullName} to see whether it should be tidied up"); DoTidyUp(From.Directory); } } catch (Exception e) { return(new ActionOutcome(e)); } return(ActionOutcome.Success()); }
private ActionOutcome WriteEpisodeMetaDataFile() { if (Episode != null) { // "try" and silently fail. eg. when file is use by other... try { XmlWriterSettings settings = new XmlWriterSettings { Indent = true, NewLineOnAttributes = true }; using (XmlWriter writer = XmlWriter.Create(Where.FullName, settings)) { writer.WriteStartElement("details"); writer.WriteElement("title", TVSettings.Instance.NamingStyle.NameFor(Episode)); writer.WriteElement("mpaa", Episode.TheCachedSeries.ContentRating); if (Episode.FirstAired.HasValue) { writer.WriteElement("year", Episode.FirstAired.Value.ToString("yyyy-MM-dd")); writer.WriteElement("firstaired", Episode.FirstAired.Value.ToString("yyyy-MM-dd")); } writer.WriteElement("runtime", Episode.TheCachedSeries.Runtime, true); writer.WriteElement("rating", Episode.EpisodeRating); writer.WriteElement("studio", Episode.TheCachedSeries.Network); writer.WriteElement("plot", Episode.TheCachedSeries.Overview); writer.WriteElement("overview", Episode.Overview); foreach (string director in Episode.Directors) { writer.WriteElement("directors", director); } foreach (string epwriter in Episode.Writers) { writer.WriteElement("writers", epwriter); } foreach (string genre in Episode.TheCachedSeries.Genres) { writer.WriteElement("genre", genre); } // actors... foreach (Actor aa in Episode.TheCachedSeries.GetActors() .Where(aa => !string.IsNullOrEmpty(aa.ActorName))) { writer.WriteStartElement("actor"); writer.WriteElement("name", aa.ActorName); writer.WriteElement("role", aa.ActorRole); writer.WriteEndElement(); // actor } // guest stars... foreach (string guest in Episode.GuestStars) { writer.WriteElement("guest", guest); } writer.WriteElement("thumbnail", TheTVDB.API.GetImageURL(Episode.Filename)); writer.WriteElement("banner", TheTVDB.API.GetImageURL(Episode.AppropriateProcessedSeason.GetWideBannerPath())); writer.WriteElement("backdrop", TheTVDB.API.GetImageURL(Episode.TheCachedSeries.GetSeriesFanartPath())); writer.WriteEndElement(); // details } return(ActionOutcome.Success()); } catch (Exception e) { return(new ActionOutcome(e)); } } return(new ActionOutcome("Write WDTV Metadata called with no Episode provided")); }
protected override ActionOutcome UpdateFile() { XDocument doc = XDocument.Load(Where.FullName); XElement? root = doc.Root; if (root is null) { return(new ActionOutcome($"Could not load {Where.FullName}")); } CachedSeriesInfo cachedSeries = SelectedShow !.CachedShow; root.UpdateElement("title", SelectedShow.ShowName); float?showRating = cachedSeries?.SiteRating; if (showRating.HasValue) { UpdateRatings(root, showRating.Value.ToString(CultureInfo.InvariantCulture), cachedSeries.SiteRatingVotes); } string lang = TVSettings.Instance.PreferredLanguageCode; if (SelectedShow.UseCustomLanguage && SelectedShow.PreferredLanguage != null) { lang = SelectedShow.PreferredLanguage.Abbreviation; } //https://forum.kodi.tv/showthread.php?tid=323588 //says that we need a format like this: //<episodeguide><url post="yes" cache="auth.json">https://api.thetvdb.com/login?{"apikey":"((API-KEY))","id":((ID))}|Content-Type=application/json</url></episodeguide> XElement episodeGuideNode = root.GetOrCreateElement("episodeguide"); XElement urlNode = episodeGuideNode.GetOrCreateElement("url"); urlNode.UpdateAttribute("post", "yes"); urlNode.UpdateAttribute("cache", "auth.json"); urlNode.SetValue(TheTVDB.API.BuildUrl(SelectedShow.TvdbCode, lang)); if (!(cachedSeries is null)) { root.UpdateElement("originaltitle", SelectedShow.ShowName); UpdateAmongstElements(root, "studio", cachedSeries.Network); root.UpdateElement("id", cachedSeries.TvdbCode); root.UpdateElement("runtime", cachedSeries.Runtime, true); root.UpdateElement("mpaa", cachedSeries.ContentRating, true); root.UpdateElement("premiered", cachedSeries.FirstAired); root.UpdateElement("year", cachedSeries.Year); root.UpdateElement("status", cachedSeries.Status); root.UpdateElement("plot", cachedSeries.Overview); UpdateId(root, "tvdb", "true", cachedSeries.TvdbCode); UpdateId(root, "imdb", "false", cachedSeries.Imdb); } root.ReplaceElements("genre", SelectedShow.Genres); ReplaceActors(root, SelectedShow.Actors); doc.Save(Where.FullName); return(ActionOutcome.Success()); }