public void Populate(CrossRef_File_Episode cfe) { this.FileName = cfe.FileName; this.FileSize = cfe.FileSize; this.Hash = cfe.Hash; DateTimeUpdated = DateTime.Now; }
public void Populate(CrossRef_File_Episode cfe) { this.FileName = cfe.FileName; this.FileSize = cfe.FileSize; this.Hash = cfe.Hash; DateTimeUpdated = DateTime.Now; }
public void CreateCrossEpisodes(string localFileName) { if (episodesRAW != null) //Only create relations if the origin of the data if from Raw (AniDB) { CrossRef_File_EpisodeRepository repFileEpisodes = new CrossRef_File_EpisodeRepository(); List <CrossRef_File_Episode> fileEps = repFileEpisodes.GetByHash(this.Hash); foreach (CrossRef_File_Episode fileEp in fileEps) { repFileEpisodes.Delete(fileEp.CrossRef_File_EpisodeID); } char apostrophe = "'".ToCharArray()[0]; char epiSplit = ','; if (episodesRAW.Contains(apostrophe)) { epiSplit = apostrophe; } char eppSplit = ','; if (episodesPercentRAW.Contains(apostrophe)) { eppSplit = apostrophe; } string[] epi = episodesRAW.Split(epiSplit); string[] epp = episodesPercentRAW.Split(eppSplit); for (int x = 0; x < epi.Length; x++) { string epis = epi[x].Trim(); string epps = epp[x].Trim(); if (epis.Length > 0) { int epid = 0; int.TryParse(epis, out epid); int eppp = 100; int.TryParse(epps, out eppp); if (epid != 0) { CrossRef_File_Episode cross = new CrossRef_File_Episode(); cross.Hash = Hash; cross.CrossRefSource = (int)CrossRefSource.AniDB; cross.AnimeID = this.AnimeID; cross.EpisodeID = epid; cross.Percentage = eppp; cross.EpisodeOrder = x + 1; cross.FileName = localFileName; cross.FileSize = FileSize; repFileEpisodes.Save(cross); } } } } }
public static void Send_CrossRefFileEpisode(JMMServer.Entities.CrossRef_File_Episode data) { if (!ServerSettings.WebCache_XRefFileEpisode_Send) { return; } string uri = string.Format(@"http://{0}/api/CrossRef_File_Episode", azureHostBaseAddress); CrossRef_File_EpisodeInput input = new CrossRef_File_EpisodeInput(data); string json = JSONHelper.Serialize <CrossRef_File_EpisodeInput>(input); SendData(uri, json, "POST"); }
// default constructor public CrossRef_File_EpisodeRequest(CrossRef_File_Episode data) { this.AnimeID = data.AnimeID; this.EpisodeID = data.EpisodeID; this.Percentage = data.Percentage; this.EpisodeOrder = data.EpisodeOrder; this.hash = data.Hash; string username = ServerSettings.AniDB_Username; if (ServerSettings.WebCache_Anonymous) username = Constants.AnonWebCacheUsername; this.uname = username; }
public void Save(CrossRef_File_Episode obj) { using (var session = JMMService.SessionFactory.OpenSession()) { // populate the database using (var transaction = session.BeginTransaction()) { session.SaveOrUpdate(obj); transaction.Commit(); } } logger.Trace("Updating group stats by file from CrossRef_File_EpisodeRepository.Save: {0}", obj.Hash); StatsCache.Instance.UpdateUsingAniDBFile(obj.Hash); }
public void CreateCrossEpisodes(string localFileName) { if (episodesRAW != null) //Only create relations if the origin of the data if from Raw (AniDB) { CrossRef_File_EpisodeRepository repFileEpisodes = new CrossRef_File_EpisodeRepository(); List<CrossRef_File_Episode> fileEps = repFileEpisodes.GetByHash(this.Hash); foreach (CrossRef_File_Episode fileEp in fileEps) repFileEpisodes.Delete(fileEp.CrossRef_File_EpisodeID); char apostrophe = ("'").ToCharArray()[0]; char epiSplit = ','; if (episodesRAW.Contains(apostrophe)) epiSplit = apostrophe; char eppSplit = ','; if (episodesPercentRAW.Contains(apostrophe)) eppSplit = apostrophe; string[] epi = episodesRAW.Split(epiSplit); string[] epp = episodesPercentRAW.Split(eppSplit); for (int x = 0; x < epi.Length; x++) { string epis = epi[x].Trim(); string epps = epp[x].Trim(); if (epis.Length > 0) { int epid = 0; int.TryParse(epis, out epid); int eppp = 100; int.TryParse(epps, out eppp); if (epid != 0) { CrossRef_File_Episode cross = new CrossRef_File_Episode(); cross.Hash = Hash; cross.CrossRefSource = (int)CrossRefSource.AniDB; cross.AnimeID = this.AnimeID; cross.EpisodeID = epid; cross.Percentage = eppp; cross.EpisodeOrder = x + 1; cross.FileName = localFileName; cross.FileSize = FileSize; repFileEpisodes.Save(cross); } } } } }
/// <summary> /// Current only handling one file containing file /// </summary> /// <param name="vid"></param> /// <returns></returns> public static List<CrossRef_File_Episode> Get_CrossRef_File_Episode(VideoLocal vid) { List<CrossRef_File_Episode> crossRefs = new List<CrossRef_File_Episode>(); if (!ServerSettings.WebCache_XRefFileEpisode_Get) return null; try { string username = ServerSettings.AniDB_Username; if (ServerSettings.WebCache_Anonymous) username = Constants.AnonWebCacheUsername; string uri = string.Format("http://{0}/GetCrossRef_File_Episode.aspx?uname={1}&hash={2}", ServerSettings.WebCache_Address, username, vid.Hash); string xml = GetData(uri); if (xml.Trim().Length == 0) return null; XmlDocument docFile = new XmlDocument(); docFile.LoadXml(xml); string sAnimeID = TryGetProperty(docFile, "CrossRef_File_EpisodeResultCollection", "AnimeID").ToUpper(); string sEpisodeID = TryGetProperty(docFile, "CrossRef_File_EpisodeResultCollection", "EpisodeIDs").ToUpper(); string sEpisodeOrder = TryGetProperty(docFile, "CrossRef_File_EpisodeResultCollection", "EpisodeOrders").ToUpper(); string sPercentages = TryGetProperty(docFile, "CrossRef_File_EpisodeResultCollection", "EpisodePercentages").ToUpper(); int animeID = 0; int.TryParse(sAnimeID, out animeID); if (animeID <= 0) return null; string[] epids = sEpisodeID.Split('|'); string[] eporders = sEpisodeOrder.Split('|'); string[] eppcts = sPercentages.Split('|'); for (int i=0;i < epids.Length; i++) { int episodeID = 0, percentage = 0, episodeOrder = 0; int.TryParse(epids[i], out episodeID); int.TryParse(eporders[i], out episodeOrder); int.TryParse(eppcts[i], out percentage); CrossRef_File_Episode xref = new CrossRef_File_Episode(); xref.Hash = vid.ED2KHash; xref.FileName = Path.GetFileName(vid.FullServerPath); xref.FileSize = vid.FileSize; xref.CrossRefSource = (int)JMMServer.CrossRefSource.WebCache; xref.AnimeID = animeID; xref.EpisodeID = episodeID; xref.Percentage = percentage; xref.EpisodeOrder = episodeOrder; crossRefs.Add(xref); } return crossRefs; } catch (Exception ex) { logger.ErrorException("Error in XMLService.Get_FileHash:: {0}", ex); return null; } }
public static void Send_CrossRef_File_Episode(CrossRef_File_Episode data) { if (!ServerSettings.WebCache_XRefFileEpisode_Send) return; string uri = string.Format("http://{0}/AddCrossRef_File_Episode.aspx", ServerSettings.WebCache_Address); CrossRef_File_EpisodeRequest fhr = new CrossRef_File_EpisodeRequest(data); string xml = fhr.ToXML(); SendData(uri, xml); }
public string AssociateSingleFile(int videoLocalID, int animeEpisodeID) { try { VideoLocalRepository repVids = new VideoLocalRepository(); VideoLocal vid = repVids.GetByID(videoLocalID); if (vid == null) return "Could not find video record"; AnimeEpisodeRepository repEps = new AnimeEpisodeRepository(); AnimeEpisode ep = repEps.GetByID(animeEpisodeID); if (ep == null) return "Could not find episode record"; CrossRef_File_EpisodeRepository repXRefs = new CrossRef_File_EpisodeRepository(); CrossRef_File_Episode xref = new CrossRef_File_Episode(); try { xref.PopulateManually(vid, ep); } catch (Exception ex) { string msg = string.Format("Error populating XREF: {0}", vid.ToStringDetailed()); throw; } repXRefs.Save(xref); vid.RenameIfRequired(); vid.MoveFileIfRequired(); CommandRequest_WebCacheSendXRefFileEpisode cr = new CommandRequest_WebCacheSendXRefFileEpisode(xref.CrossRef_File_EpisodeID); cr.Save(); AnimeSeries ser = ep.GetAnimeSeries(); ser.QueueUpdateStats(); // update epidsode added stats AnimeSeriesRepository repSeries = new AnimeSeriesRepository(); ser.EpisodeAddedDate = DateTime.Now; repSeries.Save(ser); AnimeGroupRepository repGroups = new AnimeGroupRepository(); foreach (AnimeGroup grp in ser.AllGroupsAbove) { grp.EpisodeAddedDate = DateTime.Now; repGroups.Save(grp); } CommandRequest_AddFileToMyList cmdAddFile = new CommandRequest_AddFileToMyList(vid.Hash); cmdAddFile.Save(); return ""; } catch (Exception ex) { logger.ErrorException(ex.ToString(), ex); } return ""; }
public string AssociateSingleFileWithMultipleEpisodes(int videoLocalID, int animeSeriesID, int startEpNum, int endEpNum) { try { VideoLocalRepository repVids = new VideoLocalRepository(); VideoLocal vid = repVids.GetByID(videoLocalID); if (vid == null) return "Could not find video record"; AnimeEpisodeRepository repEps = new AnimeEpisodeRepository(); AnimeSeriesRepository repSeries = new AnimeSeriesRepository(); AniDB_EpisodeRepository repAniEps = new AniDB_EpisodeRepository(); CrossRef_File_EpisodeRepository repXRefs = new CrossRef_File_EpisodeRepository(); AnimeSeries ser = repSeries.GetByID(animeSeriesID); if (ser == null) return "Could not find anime series record"; for (int i = startEpNum; i <= endEpNum; i++) { List<AniDB_Episode> anieps = repAniEps.GetByAnimeIDAndEpisodeNumber(ser.AniDB_ID, i); if (anieps.Count == 0) return "Could not find the AniDB episode record"; AniDB_Episode aniep = anieps[0]; List<AnimeEpisode> eps = repEps.GetByAniEpisodeIDAndSeriesID(aniep.EpisodeID, ser.AnimeSeriesID); if (eps.Count == 0) return "Could not find episode record"; AnimeEpisode ep = eps[0]; CrossRef_File_Episode xref = new CrossRef_File_Episode(); xref.PopulateManually(vid, ep); repXRefs.Save(xref); CommandRequest_WebCacheSendXRefFileEpisode cr = new CommandRequest_WebCacheSendXRefFileEpisode(xref.CrossRef_File_EpisodeID); cr.Save(); } vid.RenameIfRequired(); vid.MoveFileIfRequired(); ser.QueueUpdateStats(); // update epidsode added stats ser.EpisodeAddedDate = DateTime.Now; repSeries.Save(ser); AnimeGroupRepository repGroups = new AnimeGroupRepository(); foreach (AnimeGroup grp in ser.AllGroupsAbove) { grp.EpisodeAddedDate = DateTime.Now; repGroups.Save(grp); } return ""; } catch (Exception ex) { logger.ErrorException(ex.ToString(), ex); } return ""; }
private void ProcessFile_AniDB(VideoLocal vidLocal) { logger.Trace("Checking for AniDB_File record for: {0} --- {1}", vidLocal.Hash, vidLocal.FilePath); // check if we already have this AniDB_File info in the database AniDB_FileRepository repAniFile = new AniDB_FileRepository(); AniDB_EpisodeRepository repAniEps = new AniDB_EpisodeRepository(); AniDB_AnimeRepository repAniAnime = new AniDB_AnimeRepository(); AnimeSeriesRepository repSeries = new AnimeSeriesRepository(); VideoLocalRepository repVidLocals = new VideoLocalRepository(); AnimeEpisodeRepository repEps = new AnimeEpisodeRepository(); CrossRef_File_EpisodeRepository repXrefFE = new CrossRef_File_EpisodeRepository(); AniDB_File aniFile = null; if (!ForceAniDB) { aniFile = repAniFile.GetByHashAndFileSize(vidLocal.Hash, vlocal.FileSize); if (aniFile == null) logger.Trace("AniDB_File record not found"); } int animeID = 0; if (aniFile == null) { // get info from AniDB logger.Debug("Getting AniDB_File record from AniDB...."); Raw_AniDB_File fileInfo = JMMService.AnidbProcessor.GetFileInfo(vidLocal); if (fileInfo != null) { // check if we already have a record aniFile = repAniFile.GetByHashAndFileSize(vidLocal.Hash, vlocal.FileSize); if (aniFile == null) aniFile = new AniDB_File(); aniFile.Populate(fileInfo); //overwrite with local file name string localFileName = Path.GetFileName(vidLocal.FilePath); aniFile.FileName = localFileName; repAniFile.Save(aniFile, false); aniFile.CreateLanguages(); aniFile.CreateCrossEpisodes(localFileName); if (!string.IsNullOrEmpty(fileInfo.OtherEpisodesRAW)) { string[] epIDs = fileInfo.OtherEpisodesRAW.Split(','); foreach (string epid in epIDs) { int id = 0; if (int.TryParse(epid, out id)) { CommandRequest_GetEpisode cmdEp = new CommandRequest_GetEpisode(id); cmdEp.Save(); } } } animeID = aniFile.AnimeID; } } bool missingEpisodes = false; // if we still haven't got the AniDB_File Info we try the web cache or local records if (aniFile == null) { // check if we have any records from previous imports List<CrossRef_File_Episode> crossRefs = repXrefFE.GetByHash(vidLocal.Hash); if (crossRefs == null || crossRefs.Count == 0) { // lets see if we can find the episode/anime info from the web cache if (ServerSettings.WebCache_XRefFileEpisode_Get) { List<JMMServer.Providers.Azure.CrossRef_File_Episode> xrefs = JMMServer.Providers.Azure.AzureWebAPI.Get_CrossRefFileEpisode(vidLocal); crossRefs = new List<CrossRef_File_Episode>(); if (xrefs == null || xrefs.Count == 0) { logger.Debug("Cannot find AniDB_File record or get cross ref from web cache record so exiting: {0}", vidLocal.ED2KHash); return; } else { foreach (JMMServer.Providers.Azure.CrossRef_File_Episode xref in xrefs) { CrossRef_File_Episode xrefEnt = new CrossRef_File_Episode(); xrefEnt.Hash = vidLocal.ED2KHash; xrefEnt.FileName = Path.GetFileName(vidLocal.FullServerPath); xrefEnt.FileSize = vidLocal.FileSize; xrefEnt.CrossRefSource = (int)JMMServer.CrossRefSource.WebCache; xrefEnt.AnimeID = animeID; xrefEnt.EpisodeID = xref.EpisodeID; xrefEnt.Percentage = xref.Percentage; xrefEnt.EpisodeOrder = xref.EpisodeOrder; crossRefs.Add(xrefEnt); // in this case we need to save the cross refs manually as AniDB did not provide them repXrefFE.Save(xrefEnt); } } } else { logger.Debug("Cannot get AniDB_File record so exiting: {0}", vidLocal.ED2KHash); return; } } // we assume that all episodes belong to the same anime foreach (CrossRef_File_Episode xref in crossRefs) { animeID = xref.AnimeID; AniDB_Episode ep = repAniEps.GetByEpisodeID(xref.EpisodeID); if (ep == null) missingEpisodes = true; } } else { // check if we have the episode info // if we don't, we will need to re-download the anime info (which also has episode info) if (aniFile.EpisodeCrossRefs.Count == 0) { animeID = aniFile.AnimeID; // if we have the anidb file, but no cross refs it means something has been broken logger.Debug("Could not find any cross ref records for: {0}", vidLocal.ED2KHash); missingEpisodes = true; } else { foreach (CrossRef_File_Episode xref in aniFile.EpisodeCrossRefs) { AniDB_Episode ep = repAniEps.GetByEpisodeID(xref.EpisodeID); if (ep == null) missingEpisodes = true; animeID = xref.AnimeID; } } } // get from DB AniDB_Anime anime = repAniAnime.GetByAnimeID(animeID); bool animeRecentlyUpdated = false; if (anime != null) { TimeSpan ts = DateTime.Now - anime.DateTimeUpdated; if (ts.TotalHours < 4) animeRecentlyUpdated = true; } // even if we are missing episode info, don't get data more than once every 4 hours // this is to prevent banning if (missingEpisodes && !animeRecentlyUpdated) { logger.Debug("Getting Anime record from AniDB...."); anime = JMMService.AnidbProcessor.GetAnimeInfoHTTP(animeID, true, ServerSettings.AutoGroupSeries); } // create the group/series/episode records if needed AnimeSeries ser = null; if (anime != null) { logger.Debug("Creating groups, series and episodes...."); // check if there is an AnimeSeries Record associated with this AnimeID ser = repSeries.GetByAnimeID(animeID); if (ser == null) { // create a new AnimeSeries record ser = anime.CreateAnimeSeriesAndGroup(); } ser.CreateAnimeEpisodes(); // check if we have any group status data for this associated anime // if not we will download it now AniDB_GroupStatusRepository repStatus = new AniDB_GroupStatusRepository(); if (repStatus.GetByAnimeID(anime.AnimeID).Count == 0) { CommandRequest_GetReleaseGroupStatus cmdStatus = new CommandRequest_GetReleaseGroupStatus(anime.AnimeID, false); cmdStatus.Save(); } // update stats ser.EpisodeAddedDate = DateTime.Now; repSeries.Save(ser); AnimeGroupRepository repGroups = new AnimeGroupRepository(); foreach (AnimeGroup grp in ser.AllGroupsAbove) { grp.EpisodeAddedDate = DateTime.Now; repGroups.Save(grp); } } vidLocal.RenameIfRequired(); vidLocal.MoveFileIfRequired(); // update stats for groups and series if (ser != null) { // update all the groups above this series in the heirarchy ser.QueueUpdateStats(); //StatsCache.Instance.UpdateUsingSeries(ser.AnimeSeriesID); } // Add this file to the users list if (ServerSettings.AniDB_MyList_AddFiles) { CommandRequest_AddFileToMyList cmd = new CommandRequest_AddFileToMyList(vidLocal.ED2KHash); cmd.Save(); } }
public string AssociateMultipleFiles(List<int> videoLocalIDs, int animeSeriesID, int startingEpisodeNumber, bool singleEpisode) { try { CrossRef_File_EpisodeRepository repXRefs = new CrossRef_File_EpisodeRepository(); AnimeSeriesRepository repSeries = new AnimeSeriesRepository(); VideoLocalRepository repVids = new VideoLocalRepository(); AniDB_EpisodeRepository repAniEps = new AniDB_EpisodeRepository(); AnimeEpisodeRepository repEps = new AnimeEpisodeRepository(); AnimeSeries ser = repSeries.GetByID(animeSeriesID); if (ser == null) return "Could not find anime series record"; int epNumber = startingEpisodeNumber; int count = 1; foreach (int videoLocalID in videoLocalIDs) { VideoLocal vid = repVids.GetByID(videoLocalID); if (vid == null) return "Could not find video local record"; List<AniDB_Episode> anieps = repAniEps.GetByAnimeIDAndEpisodeNumber(ser.AniDB_ID, epNumber); if (anieps.Count == 0) return "Could not find the AniDB episode record"; AniDB_Episode aniep = anieps[0]; List<AnimeEpisode> eps = repEps.GetByAniEpisodeIDAndSeriesID(aniep.EpisodeID, ser.AnimeSeriesID); if (eps.Count == 0) return "Could not find episode record"; AnimeEpisode ep = eps[0]; CrossRef_File_Episode xref = new CrossRef_File_Episode(); xref.PopulateManually(vid, ep); // TODO do this properly if (singleEpisode) { xref.EpisodeOrder = count; if (videoLocalIDs.Count > 5) xref.Percentage = 100; else xref.Percentage = GetEpisodePercentages(videoLocalIDs.Count)[count - 1]; } repXRefs.Save(xref); vid.RenameIfRequired(); vid.MoveFileIfRequired(); CommandRequest_WebCacheSendXRefFileEpisode cr = new CommandRequest_WebCacheSendXRefFileEpisode(xref.CrossRef_File_EpisodeID); cr.Save(); count++; if (!singleEpisode) epNumber++; } ser.QueueUpdateStats(); // update epidsode added stats ser.EpisodeAddedDate = DateTime.Now; repSeries.Save(ser); AnimeGroupRepository repGroups = new AnimeGroupRepository(); foreach (AnimeGroup grp in ser.AllGroupsAbove) { grp.EpisodeAddedDate = DateTime.Now; repGroups.Save(grp); } } catch (Exception ex) { logger.ErrorException(ex.ToString(), ex); } return ""; }
void workerMyAnime2_DoWork(object sender, DoWorkEventArgs e) { MA2Progress ma2Progress = new MA2Progress(); ma2Progress.CurrentFile = 0; ma2Progress.ErrorMessage = ""; ma2Progress.MigratedFiles = 0; ma2Progress.TotalFiles = 0; try { string databasePath = e.Argument as string; string connString = string.Format(@"data source={0};useutf16encoding=True", databasePath); SQLiteConnection myConn = new SQLiteConnection(connString); myConn.Open(); // get a list of unlinked files VideoLocalRepository repVids = new VideoLocalRepository(); AniDB_EpisodeRepository repAniEps = new AniDB_EpisodeRepository(); AniDB_AnimeRepository repAniAnime = new AniDB_AnimeRepository(); AnimeSeriesRepository repSeries = new AnimeSeriesRepository(); AnimeEpisodeRepository repEps = new AnimeEpisodeRepository(); List<VideoLocal> vids = repVids.GetVideosWithoutEpisode(); ma2Progress.TotalFiles = vids.Count; foreach (VideoLocal vid in vids) { ma2Progress.CurrentFile = ma2Progress.CurrentFile + 1; workerMyAnime2.ReportProgress(0, ma2Progress); // search for this file in the XrossRef table in MA2 string sql = string.Format("SELECT AniDB_EpisodeID from CrossRef_Episode_FileHash WHERE Hash = '{0}' AND FileSize = {1}", vid.ED2KHash, vid.FileSize); SQLiteCommand sqCommand = new SQLiteCommand(sql); sqCommand.Connection = myConn; SQLiteDataReader myReader = sqCommand.ExecuteReader(); while (myReader.Read()) { int episodeID = 0; if (!int.TryParse(myReader.GetValue(0).ToString(), out episodeID)) continue; if (episodeID <= 0) continue; sql = string.Format("SELECT AnimeID from AniDB_Episode WHERE EpisodeID = {0}", episodeID); sqCommand = new SQLiteCommand(sql); sqCommand.Connection = myConn; SQLiteDataReader myReader2 = sqCommand.ExecuteReader(); while (myReader2.Read()) { int animeID = myReader2.GetInt32(0); // so now we have all the needed details we can link the file to the episode // as long as wehave the details in JMM AniDB_Anime anime = null; AniDB_Episode ep = repAniEps.GetByEpisodeID(episodeID); if (ep == null) { logger.Debug("Getting Anime record from AniDB...."); anime = JMMService.AnidbProcessor.GetAnimeInfoHTTP(animeID, true, ServerSettings.AutoGroupSeries); } else anime = repAniAnime.GetByAnimeID(animeID); // create the group/series/episode records if needed AnimeSeries ser = null; if (anime == null) continue; logger.Debug("Creating groups, series and episodes...."); // check if there is an AnimeSeries Record associated with this AnimeID ser = repSeries.GetByAnimeID(animeID); if (ser == null) { // create a new AnimeSeries record ser = anime.CreateAnimeSeriesAndGroup(); } ser.CreateAnimeEpisodes(); // check if we have any group status data for this associated anime // if not we will download it now AniDB_GroupStatusRepository repStatus = new AniDB_GroupStatusRepository(); if (repStatus.GetByAnimeID(anime.AnimeID).Count == 0) { CommandRequest_GetReleaseGroupStatus cmdStatus = new CommandRequest_GetReleaseGroupStatus(anime.AnimeID, false); cmdStatus.Save(); } // update stats ser.EpisodeAddedDate = DateTime.Now; repSeries.Save(ser); AnimeGroupRepository repGroups = new AnimeGroupRepository(); foreach (AnimeGroup grp in ser.AllGroupsAbove) { grp.EpisodeAddedDate = DateTime.Now; repGroups.Save(grp); } AnimeEpisode epAnime = repEps.GetByAniDBEpisodeID(episodeID); if (epAnime == null) continue; CrossRef_File_EpisodeRepository repXRefs = new CrossRef_File_EpisodeRepository(); JMMServer.Entities.CrossRef_File_Episode xref = new JMMServer.Entities.CrossRef_File_Episode(); try { xref.PopulateManually(vid, epAnime); } catch (Exception ex) { string msg = string.Format("Error populating XREF: {0} - {1}", vid.ToStringDetailed(), ex.ToString()); throw; } repXRefs.Save(xref); vid.RenameIfRequired(); vid.MoveFileIfRequired(); // update stats for groups and series if (ser != null) { // update all the groups above this series in the heirarchy ser.QueueUpdateStats(); //StatsCache.Instance.UpdateUsingSeries(ser.AnimeSeriesID); } // Add this file to the users list if (ServerSettings.AniDB_MyList_AddFiles) { CommandRequest_AddFileToMyList cmd = new CommandRequest_AddFileToMyList(vid.ED2KHash); cmd.Save(); } ma2Progress.MigratedFiles = ma2Progress.MigratedFiles + 1; workerMyAnime2.ReportProgress(0, ma2Progress); } myReader2.Close(); //Console.WriteLine(myReader.GetString(0)); } myReader.Close(); } myConn.Close(); ma2Progress.CurrentFile = ma2Progress.CurrentFile + 1; workerMyAnime2.ReportProgress(0, ma2Progress); } catch (Exception ex) { logger.ErrorException(ex.ToString(), ex); ma2Progress.ErrorMessage = ex.Message; workerMyAnime2.ReportProgress(0, ma2Progress); } }
public void MoveFileIfRequired() { // check if this file is in the drop folder // otherwise we don't need to move it if (this.ImportFolder.IsDropSource == 0) { return; } if (!File.Exists(this.FullServerPath)) { return; } // find the default destination ImportFolder destFolder = null; ImportFolderRepository repFolders = new ImportFolderRepository(); foreach (ImportFolder fldr in repFolders.GetAll()) { if (fldr.IsDropDestination == 1) { destFolder = fldr; break; } } if (destFolder == null) { return; } if (!Directory.Exists(destFolder.ImportFolderLocation)) { return; } // we can only move the file if it has an anime associated with it List <CrossRef_File_Episode> xrefs = this.EpisodeCrossRefs; if (xrefs.Count == 0) { return; } CrossRef_File_Episode xref = xrefs[0]; // find the series associated with this episode AnimeSeriesRepository repSeries = new AnimeSeriesRepository(); AnimeSeries series = repSeries.GetByAnimeID(xref.AnimeID); if (series == null) { return; } // find where the other files are stored for this series // if there are no other files except for this one, it means we need to create a new location bool foundLocation = false; string newFullPath = ""; // sort the episodes by air date, so that we will move the file to the location of the latest episode List <AnimeEpisode> allEps = series.GetAnimeEpisodes(); List <SortPropOrFieldAndDirection> sortCriteria = new List <SortPropOrFieldAndDirection>(); sortCriteria.Add(new SortPropOrFieldAndDirection("AniDB_EpisodeID", true, SortType.eInteger)); allEps = Sorting.MultiSort <AnimeEpisode>(allEps, sortCriteria); foreach (AnimeEpisode ep in allEps) { foreach (VideoLocal vid in ep.GetVideoLocals()) { if (vid.VideoLocalID != this.VideoLocalID) { // make sure this folder is not the drop source if (vid.ImportFolder.IsDropSource == 1) { continue; } string thisFileName = vid.FullServerPath; string folderName = Path.GetDirectoryName(thisFileName); if (Directory.Exists(folderName)) { newFullPath = folderName; foundLocation = true; break; } } } if (foundLocation) { break; } } if (!foundLocation) { // we need to create a new folder string newFolderName = Utils.RemoveInvalidFolderNameCharacters(series.GetAnime().MainTitle); newFullPath = Path.Combine(destFolder.ImportFolderLocation, newFolderName); if (!Directory.Exists(newFullPath)) { Directory.CreateDirectory(newFullPath); } } int newFolderID = 0; string newPartialPath = ""; string newFullServerPath = Path.Combine(newFullPath, Path.GetFileName(this.FullServerPath)); DataAccessHelper.GetShareAndPath(newFullServerPath, repFolders.GetAll(), ref newFolderID, ref newPartialPath); logger.Info("Moving file from {0} to {1}", this.FullServerPath, newFullServerPath); if (File.Exists(newFullServerPath)) { // if the file already exists, we can just delete the source file instead // this is safer than deleting and moving File.Delete(this.FullServerPath); this.ImportFolderID = newFolderID; this.FilePath = newPartialPath; VideoLocalRepository repVids = new VideoLocalRepository(); repVids.Save(this); } else { string originalFileName = this.FullServerPath; FileInfo fi = new FileInfo(originalFileName); // now move the file File.Move(this.FullServerPath, newFullServerPath); this.ImportFolderID = newFolderID; this.FilePath = newPartialPath; VideoLocalRepository repVids = new VideoLocalRepository(); repVids.Save(this); try { // move any subtitle files foreach (string subtitleFile in Utils.GetPossibleSubtitleFiles(originalFileName)) { if (File.Exists(subtitleFile)) { FileInfo fiSub = new FileInfo(subtitleFile); string newSubPath = Path.Combine(Path.GetDirectoryName(newFullServerPath), fiSub.Name); if (File.Exists(newSubPath)) { // if the file already exists, we can just delete the source file instead // this is safer than deleting and moving File.Delete(newSubPath); } else { File.Move(subtitleFile, newSubPath); } } } } catch (Exception ex) { logger.ErrorException(ex.ToString(), ex); } // check for any empty folders in drop folder // only for the drop folder if (this.ImportFolder.IsDropSource == 1) { foreach (string folderName in Directory.GetDirectories(this.ImportFolder.ImportFolderLocation, "*", SearchOption.AllDirectories)) { if (Directory.Exists(folderName)) { if (Directory.GetFiles(folderName, "*", SearchOption.AllDirectories).Length == 0) { try { Directory.Delete(folderName, true); } /*catch (IOException) * { * Thread.Sleep(0); * Directory.Delete(folderName, false); * }*/ catch (Exception ex) { logger.ErrorException(ex.ToString(), ex); } } } } } } }
public void MoveFileIfRequired() { try { logger.Trace("Attempting to move file: {0}", this.FullServerPath); // check if this file is in the drop folder // otherwise we don't need to move it if (this.ImportFolder.IsDropSource == 0) { logger.Trace("Not moving file as it is NOT in the drop folder: {0}", this.FullServerPath); return; } if (!File.Exists(this.FullServerPath)) { logger.Error("Could not find the file to move: {0}", this.FullServerPath); return; } // find the default destination ImportFolder destFolder = null; ImportFolderRepository repFolders = new ImportFolderRepository(); foreach (ImportFolder fldr in repFolders.GetAll()) { if (fldr.IsDropDestination == 1) { destFolder = fldr; break; } } if (destFolder == null) { return; } if (!System.IO.Directory.Exists(destFolder.ImportFolderLocation)) { return; } // keep the original drop folder for later (take a copy, not a reference) ImportFolder dropFolder = this.ImportFolder; // we can only move the file if it has an anime associated with it List <CrossRef_File_Episode> xrefs = this.EpisodeCrossRefs; if (xrefs.Count == 0) { return; } CrossRef_File_Episode xref = xrefs[0]; // find the series associated with this episode AnimeSeriesRepository repSeries = new AnimeSeriesRepository(); AnimeSeries series = repSeries.GetByAnimeID(xref.AnimeID); if (series == null) { return; } // find where the other files are stored for this series // if there are no other files except for this one, it means we need to create a new location bool foundLocation = false; string newFullPath = ""; // sort the episodes by air date, so that we will move the file to the location of the latest episode List <AnimeEpisode> allEps = series.GetAnimeEpisodes().OrderByDescending(a => a.AniDB_EpisodeID).ToList(); AniDB_AnimeRepository repAnime = new AniDB_AnimeRepository(); CrossRef_File_EpisodeRepository repFileEpXref = new CrossRef_File_EpisodeRepository(); foreach (AnimeEpisode ep in allEps) { // check if this episode belongs to more than one anime // if it does we will ignore it List <CrossRef_File_Episode> fileEpXrefs = repFileEpXref.GetByEpisodeID(ep.AniDB_EpisodeID); int? animeID = null; bool crossOver = false; foreach (CrossRef_File_Episode fileEpXref in fileEpXrefs) { if (!animeID.HasValue) { animeID = fileEpXref.AnimeID; } else { if (animeID.Value != fileEpXref.AnimeID) { crossOver = true; } } } if (crossOver) { continue; } foreach (VideoLocal vid in ep.GetVideoLocals()) { if (vid.VideoLocalID != this.VideoLocalID) { // make sure this folder is not the drop source if (vid.ImportFolder.IsDropSource == 1) { continue; } string thisFileName = vid.FullServerPath; string folderName = Path.GetDirectoryName(thisFileName); if (Directory.Exists(folderName)) { newFullPath = folderName; foundLocation = true; break; } } } if (foundLocation) { break; } } if (!foundLocation) { // we need to create a new folder string newFolderName = Utils.RemoveInvalidFolderNameCharacters(series.GetAnime().PreferredTitle); newFullPath = Path.Combine(destFolder.ImportFolderLocation, newFolderName); if (!Directory.Exists(newFullPath)) { Directory.CreateDirectory(newFullPath); } } int newFolderID = 0; string newPartialPath = ""; string newFullServerPath = Path.Combine(newFullPath, Path.GetFileName(this.FullServerPath)); DataAccessHelper.GetShareAndPath(newFullServerPath, repFolders.GetAll(), ref newFolderID, ref newPartialPath); logger.Info("Moving file from {0} to {1}", this.FullServerPath, newFullServerPath); if (File.Exists(newFullServerPath)) { logger.Trace( "Not moving file as it already exists at the new location, deleting source file instead: {0} --- {1}", this.FullServerPath, newFullServerPath); // if the file already exists, we can just delete the source file instead // this is safer than deleting and moving File.Delete(this.FullServerPath); this.ImportFolderID = newFolderID; this.FilePath = newPartialPath; VideoLocalRepository repVids = new VideoLocalRepository(); repVids.Save(this, true); } else { string originalFileName = this.FullServerPath; FileInfo fi = new FileInfo(originalFileName); // now move the file File.Move(this.FullServerPath, newFullServerPath); this.ImportFolderID = newFolderID; this.FilePath = newPartialPath; VideoLocalRepository repVids = new VideoLocalRepository(); repVids.Save(this, true); try { // move any subtitle files foreach (string subtitleFile in Utils.GetPossibleSubtitleFiles(originalFileName)) { if (File.Exists(subtitleFile)) { FileInfo fiSub = new FileInfo(subtitleFile); string newSubPath = Path.Combine(Path.GetDirectoryName(newFullServerPath), fiSub.Name); if (File.Exists(newSubPath)) { // if the file already exists, we can just delete the source file instead // this is safer than deleting and moving File.Delete(newSubPath); } else { File.Move(subtitleFile, newSubPath); } } } } catch (Exception ex) { logger.ErrorException(ex.ToString(), ex); } // check for any empty folders in drop folder // only for the drop folder if (dropFolder.IsDropSource == 1) { foreach ( string folderName in Directory.GetDirectories(dropFolder.ImportFolderLocation, "*", SearchOption.AllDirectories)) { if (Directory.Exists(folderName)) { if (Directory.GetFiles(folderName, "*", SearchOption.AllDirectories).Length == 0) { try { Directory.Delete(folderName, true); } catch (Exception ex) { logger.ErrorException(ex.ToString(), ex); } } } } } } } catch (Exception ex) { string msg = string.Format("Could not move file: {0} -- {1}", this.FullServerPath, ex.ToString()); logger.ErrorException(msg, ex); } }
public void MoveFileIfRequired() { try { logger.Trace("Attempting to MOVE file: {0}", this.FullServerPath); // check if this file is in the drop folder // otherwise we don't need to move it if (ImportFolder.IsDropSource == 0) { logger.Trace("Not moving file as it is NOT in the drop folder: {0}", this.FullServerPath); return; } IFileSystem f = this.ImportFolder.FileSystem; if (f == null) { logger.Trace("Unable to MOVE, filesystem not working: {0}", this.FullServerPath); return; } FileSystemResult <IObject> fsrresult = f.Resolve(FullServerPath); if (!fsrresult.IsOk) { logger.Error("Could not find the file to move: {0}", this.FullServerPath); return; } IFile source_file = fsrresult.Result as IFile; if (source_file == null) { logger.Error("Could not find the file to move: {0}", this.FullServerPath); return; } // find the default destination ImportFolder destFolder = null; foreach (ImportFolder fldr in RepoFactory.ImportFolder.GetAll().Where(a => a.CloudID == ImportFolder.CloudID)) { if (fldr.IsDropDestination == 1) { destFolder = fldr; break; } } if (destFolder == null) { return; } FileSystemResult <IObject> re = f.Resolve(destFolder.ImportFolderLocation); if (!re.IsOk) { return; } // keep the original drop folder for later (take a copy, not a reference) ImportFolder dropFolder = this.ImportFolder; // we can only move the file if it has an anime associated with it List <CrossRef_File_Episode> xrefs = this.VideoLocal.EpisodeCrossRefs; if (xrefs.Count == 0) { return; } CrossRef_File_Episode xref = xrefs[0]; // find the series associated with this episode AnimeSeries series = RepoFactory.AnimeSeries.GetByAnimeID(xref.AnimeID); if (series == null) { return; } // find where the other files are stored for this series // if there are no other files except for this one, it means we need to create a new location bool foundLocation = false; string newFullPath = ""; // sort the episodes by air date, so that we will move the file to the location of the latest episode List <AnimeEpisode> allEps = series.GetAnimeEpisodes().OrderByDescending(a => a.AniDB_EpisodeID).ToList(); IDirectory destination = null; foreach (AnimeEpisode ep in allEps) { // check if this episode belongs to more than one anime // if it does we will ignore it List <CrossRef_File_Episode> fileEpXrefs = RepoFactory.CrossRef_File_Episode.GetByEpisodeID(ep.AniDB_EpisodeID); int? animeID = null; bool crossOver = false; foreach (CrossRef_File_Episode fileEpXref in fileEpXrefs) { if (!animeID.HasValue) { animeID = fileEpXref.AnimeID; } else { if (animeID.Value != fileEpXref.AnimeID) { crossOver = true; } } } if (crossOver) { continue; } foreach (VideoLocal vid in ep.GetVideoLocals().Where(a => a.Places.Any(b => b.ImportFolder.CloudID == destFolder.CloudID && b.ImportFolder.IsDropSource == 0))) { if (vid.VideoLocalID != this.VideoLocalID) { VideoLocal_Place place = vid.Places.FirstOrDefault(a => a.ImportFolder.CloudID == destFolder.CloudID); string thisFileName = place?.FullServerPath; string folderName = Path.GetDirectoryName(thisFileName); FileSystemResult <IObject> dir = f.Resolve(folderName); if (dir.IsOk) { destination = (IDirectory)dir.Result; newFullPath = folderName; foundLocation = true; break; } } } if (foundLocation) { break; } } if (!foundLocation) { // we need to create a new folder string newFolderName = Utils.RemoveInvalidFolderNameCharacters(series.GetAnime().PreferredTitle); newFullPath = Path.Combine(destFolder.ParsedImportFolderLocation, newFolderName); FileSystemResult <IObject> dirn = f.Resolve(newFullPath); if (!dirn.IsOk) { dirn = f.Resolve(destFolder.ImportFolderLocation); if (dirn.IsOk) { IDirectory d = (IDirectory)dirn.Result; FileSystemResult <IDirectory> d2 = Task.Run(async() => await d.CreateDirectoryAsync(newFolderName, null)).Result; destination = d2.Result; } } else if (dirn.Result is IFile) { logger.Error("Destination folder is a file: {0}", newFolderName); } else { destination = (IDirectory)dirn.Result; } } string newFullServerPath = Path.Combine(newFullPath, Path.GetFileName(this.FullServerPath)); Tuple <ImportFolder, string> tup = VideoLocal_PlaceRepository.GetFromFullPath(newFullServerPath); if (tup == null) { logger.Error($"Unable to LOCATE file {newFullServerPath} inside the import folders"); return; } logger.Info("Moving file from {0} to {1}", this.FullServerPath, newFullServerPath); FileSystemResult <IObject> dst = f.Resolve(newFullServerPath); if (dst.IsOk) { logger.Trace("Not moving file as it already exists at the new location, deleting source file instead: {0} --- {1}", this.FullServerPath, newFullServerPath); // if the file already exists, we can just delete the source file instead // this is safer than deleting and moving FileSystemResult fr = new FileSystemResult(); try { fr = source_file.Delete(false); if (!fr.IsOk) { logger.Warn("Unable to DELETE file: {0} error {1}", this.FullServerPath, fr?.Error ?? String.Empty); } this.ImportFolderID = tup.Item1.ImportFolderID; this.FilePath = tup.Item2; RepoFactory.VideoLocalPlace.Save(this); // check for any empty folders in drop folder // only for the drop folder if (dropFolder.IsDropSource == 1) { FileSystemResult <IObject> dd = f.Resolve(dropFolder.ImportFolderLocation); if (dd != null && dd.IsOk && dd.Result is IDirectory) { RecursiveDeleteEmptyDirectories((IDirectory)dd.Result, true); } } } catch { logger.Error("Unable to DELETE file: {0} error {1}", this.FullServerPath, fr?.Error ?? String.Empty); } } else { FileSystemResult fr = source_file.Move(destination); if (!fr.IsOk) { logger.Error("Unable to MOVE file: {0} to {1} error {2)", this.FullServerPath, newFullServerPath, fr?.Error ?? String.Empty); return; } string originalFileName = this.FullServerPath; this.ImportFolderID = tup.Item1.ImportFolderID; this.FilePath = tup.Item2; RepoFactory.VideoLocalPlace.Save(this); try { // move any subtitle files foreach (string subtitleFile in Utils.GetPossibleSubtitleFiles(originalFileName)) { FileSystemResult <IObject> src = f.Resolve(subtitleFile); if (src.IsOk && src.Result is IFile) { string newSubPath = Path.Combine(Path.GetDirectoryName(newFullServerPath), ((IFile)src.Result).Name); dst = f.Resolve(newSubPath); if (dst.IsOk && dst.Result is IFile) { FileSystemResult fr2 = src.Result.Delete(true); if (!fr2.IsOk) { logger.Warn("Unable to DELETE file: {0} error {1}", subtitleFile, fr2?.Error ?? String.Empty); } } else { FileSystemResult fr2 = ((IFile)src.Result).Move(destination); if (!fr2.IsOk) { logger.Error("Unable to MOVE file: {0} to {1} error {2)", subtitleFile, newSubPath, fr2?.Error ?? String.Empty); } } } } } catch (Exception ex) { logger.Error(ex, ex.ToString()); } // check for any empty folders in drop folder // only for the drop folder if (dropFolder.IsDropSource == 1) { FileSystemResult <IObject> dd = f.Resolve(dropFolder.ImportFolderLocation); if (dd != null && dd.IsOk && dd.Result is IDirectory) { RecursiveDeleteEmptyDirectories((IDirectory)dd.Result, true); } } } } catch (Exception ex) { string msg = $"Could not MOVE file: {this.FullServerPath} -- {ex.ToString()}"; logger.Error(ex, msg); } }
public string AssociateMultipleFiles(List<int> videoLocalIDs, int animeSeriesID, int startingEpisodeNumber, bool singleEpisode) { try { AnimeSeries ser = RepoFactory.AnimeSeries.GetByID(animeSeriesID); if (ser == null) return "Could not find anime series record"; int epNumber = startingEpisodeNumber; int count = 1; foreach (int videoLocalID in videoLocalIDs) { VideoLocal vid = RepoFactory.VideoLocal.GetByID(videoLocalID); if (vid == null) return "Could not find video local record"; if (vid.Hash == null) return "Could not associate a cloud file without hash, hash it locally first"; List<AniDB_Episode> anieps = RepoFactory.AniDB_Episode.GetByAnimeIDAndEpisodeNumber(ser.AniDB_ID, epNumber); if (anieps.Count == 0) return "Could not find the AniDB episode record"; AniDB_Episode aniep = anieps[0]; AnimeEpisode ep = RepoFactory.AnimeEpisode.GetByAniDBEpisodeID(aniep.EpisodeID); if (ep == null) return "Could not find episode record"; CrossRef_File_Episode xref = new CrossRef_File_Episode(); xref.PopulateManually(vid, ep); // TODO do this properly if (singleEpisode) { xref.EpisodeOrder = count; if (videoLocalIDs.Count > 5) xref.Percentage = 100; else xref.Percentage = GetEpisodePercentages(videoLocalIDs.Count)[count - 1]; } RepoFactory.CrossRef_File_Episode.Save(xref); CommandRequest_WebCacheSendXRefFileEpisode cr = new CommandRequest_WebCacheSendXRefFileEpisode(xref.CrossRef_File_EpisodeID); cr.Save(); vid.Places.ForEach(a => { a.RenameIfRequired(); a.MoveFileIfRequired(); }); count++; if (!singleEpisode) epNumber++; } ser.EpisodeAddedDate = DateTime.Now; RepoFactory.AnimeSeries.Save(ser, false, true); foreach (AnimeGroup grp in ser.AllGroupsAbove) { grp.EpisodeAddedDate = DateTime.Now; RepoFactory.AnimeGroup.Save(grp, false, false); } // update epidsode added stats ser.QueueUpdateStats(); } catch (Exception ex) { logger.Error( ex,ex.ToString()); } return ""; }
public string AssociateSingleFileWithMultipleEpisodes(int videoLocalID, int animeSeriesID, int startEpNum, int endEpNum) { try { VideoLocal vid = RepoFactory.VideoLocal.GetByID(videoLocalID); if (vid == null) return "Could not find video record"; if (vid.Hash == null) return "Could not associate a cloud file without hash, hash it locally first"; AnimeSeries ser = RepoFactory.AnimeSeries.GetByID(animeSeriesID); if (ser == null) return "Could not find anime series record"; for (int i = startEpNum; i <= endEpNum; i++) { List<AniDB_Episode> anieps = RepoFactory.AniDB_Episode.GetByAnimeIDAndEpisodeNumber(ser.AniDB_ID, i); if (anieps.Count == 0) return "Could not find the AniDB episode record"; AniDB_Episode aniep = anieps[0]; AnimeEpisode ep = RepoFactory.AnimeEpisode.GetByAniDBEpisodeID(aniep.EpisodeID); if (ep == null) return "Could not find episode record"; CrossRef_File_Episode xref = new CrossRef_File_Episode(); xref.PopulateManually(vid, ep); RepoFactory.CrossRef_File_Episode.Save(xref); CommandRequest_WebCacheSendXRefFileEpisode cr = new CommandRequest_WebCacheSendXRefFileEpisode(xref.CrossRef_File_EpisodeID); cr.Save(); } vid.Places.ForEach(a => { a.RenameIfRequired(); a.MoveFileIfRequired(); }); ser.EpisodeAddedDate = DateTime.Now; RepoFactory.AnimeSeries.Save(ser, false, true); foreach (AnimeGroup grp in ser.AllGroupsAbove) { grp.EpisodeAddedDate = DateTime.Now; RepoFactory.AnimeGroup.Save(grp, false, false); } //Update will re-save ser.QueueUpdateStats(); return ""; } catch (Exception ex) { logger.Error( ex,ex.ToString()); } return ""; }
public string AssociateSingleFile(int videoLocalID, int animeEpisodeID) { try { VideoLocal vid = RepoFactory.VideoLocal.GetByID(videoLocalID); if (vid == null) return "Could not find video record"; if (string.IsNullOrEmpty(vid.Hash)) return "Could not associate a cloud file without hash, hash it locally first"; AnimeEpisode ep = RepoFactory.AnimeEpisode.GetByID(animeEpisodeID); if (ep == null) return "Could not find episode record"; CrossRef_File_Episode xref = new CrossRef_File_Episode(); try { xref.PopulateManually(vid, ep); } catch (Exception ex) { string msg = string.Format("Error populating XREF: {0}", vid.ToStringDetailed()); throw; } RepoFactory.CrossRef_File_Episode.Save(xref); CommandRequest_WebCacheSendXRefFileEpisode cr = new CommandRequest_WebCacheSendXRefFileEpisode(xref.CrossRef_File_EpisodeID); cr.Save(); vid.Places.ForEach(a => { a.RenameIfRequired(); a.MoveFileIfRequired(); }); AnimeSeries ser = ep.GetAnimeSeries(); ser.EpisodeAddedDate = DateTime.Now; RepoFactory.AnimeSeries.Save(ser, false, true); //Update will re-save ser.QueueUpdateStats(); foreach (AnimeGroup grp in ser.AllGroupsAbove) { grp.EpisodeAddedDate = DateTime.Now; RepoFactory.AnimeGroup.Save(grp, false, false); } CommandRequest_AddFileToMyList cmdAddFile = new CommandRequest_AddFileToMyList(vid.Hash); cmdAddFile.Save(); return ""; } catch (Exception ex) { logger.Error( ex,ex.ToString()); } return ""; }