public override void ProcessCommand() { logger.Info("Get AniDB episode info: {0}", EpisodeID); try { // we don't use this command to update episode info // we actually use it to update the cross ref info instead // and we only use it for the "Other Episodes" section of the FILE command // because that field doesn't tell you what anime it belongs to CrossRef_File_EpisodeRepository repCrossRefs = new CrossRef_File_EpisodeRepository(); List<CrossRef_File_Episode> xrefs = repCrossRefs.GetByEpisodeID(EpisodeID); if (xrefs.Count == 0) return; Raw_AniDB_Episode epInfo = JMMService.AnidbProcessor.GetEpisodeInfo(EpisodeID); if (epInfo != null) { AnimeSeriesRepository repSeries = new AnimeSeriesRepository(); foreach (CrossRef_File_Episode xref in xrefs) { int oldAnimeID = xref.AnimeID; xref.AnimeID = epInfo.AnimeID; repCrossRefs.Save(xref); AnimeSeries ser = repSeries.GetByAnimeID(oldAnimeID); if (ser != null) ser.UpdateStats(true, true, true); StatsCache.Instance.UpdateUsingAnime(oldAnimeID); ser = repSeries.GetByAnimeID(epInfo.AnimeID); if (ser != null) ser.UpdateStats(true, true, true); StatsCache.Instance.UpdateUsingAnime(epInfo.AnimeID); } } } catch (Exception ex) { logger.Error("Error processing CommandRequest_GetEpisode: {0} - {1}", EpisodeID, ex.ToString()); return; } }
public override void ProcessCommand() { try { CrossRef_File_EpisodeRepository repVids = new CrossRef_File_EpisodeRepository(); CrossRef_File_Episode xref = repVids.GetByID(CrossRef_File_EpisodeID); if (xref == null) return; JMMServer.Providers.Azure.AzureWebAPI.Send_CrossRefFileEpisode(xref); } catch (Exception ex) { logger.Error("Error processing CommandRequest_WebCacheSendXRefFileEpisode: {0} - {1}", CrossRef_File_EpisodeID, ex.ToString()); return; } }
public string RemoveAssociationOnFile(int videoLocalID, int aniDBEpisodeID) { try { VideoLocalRepository repVids = new VideoLocalRepository(); CrossRef_File_EpisodeRepository repXRefs = new CrossRef_File_EpisodeRepository(); VideoLocal vid = repVids.GetByID(videoLocalID); if (vid == null) return "Could not find video record"; int? animeSeriesID = null; foreach (AnimeEpisode ep in vid.GetAnimeEpisodes()) { if (ep.AniDB_EpisodeID != aniDBEpisodeID) continue; animeSeriesID = ep.AnimeSeriesID; CrossRef_File_Episode xref = repXRefs.GetByHashAndEpisodeID(vid.Hash, ep.AniDB_EpisodeID); if (xref != null) { if (xref.CrossRefSource == (int)CrossRefSource.AniDB) return "Cannot remove associations created from AniDB data"; // delete cross ref from web cache CommandRequest_WebCacheDeleteXRefFileEpisode cr = new CommandRequest_WebCacheDeleteXRefFileEpisode(vid.Hash, ep.AniDB_EpisodeID); cr.Save(); repXRefs.Delete(xref.CrossRef_File_EpisodeID); } } if (animeSeriesID.HasValue) { AnimeSeriesRepository repSeries = new AnimeSeriesRepository(); AnimeSeries ser = repSeries.GetByID(animeSeriesID.Value); if (ser != null) ser.QueueUpdateStats(); } return ""; } catch (Exception ex) { logger.ErrorException(ex.ToString(), ex); return ex.Message; } }
public List<Contract_MissingFile> GetMyListFilesForRemoval(int userID) { List<Contract_MissingFile> contracts = new List<Contract_MissingFile>(); /*Contract_MissingFile missingFile2 = new Contract_MissingFile(); missingFile2.AnimeID = 1; missingFile2.AnimeTitle = "Gundam Age"; missingFile2.EpisodeID = 2; missingFile2.EpisodeNumber = 7; missingFile2.FileID = 8; missingFile2.AnimeSeries = null; contracts.Add(missingFile2); Thread.Sleep(5000); return contracts;*/ AniDB_FileRepository repAniFile = new AniDB_FileRepository(); CrossRef_File_EpisodeRepository repFileEp = new CrossRef_File_EpisodeRepository(); AniDB_AnimeRepository repAnime = new AniDB_AnimeRepository(); AniDB_EpisodeRepository repEpisodes = new AniDB_EpisodeRepository(); VideoLocalRepository repVids = new VideoLocalRepository(); AnimeSeriesRepository repSeries = new AnimeSeriesRepository(); Dictionary<int, AniDB_Anime> animeCache = new Dictionary<int, AniDB_Anime>(); Dictionary<int, AnimeSeries> animeSeriesCache = new Dictionary<int, AnimeSeries>(); try { AniDBHTTPCommand_GetMyList cmd = new AniDBHTTPCommand_GetMyList(); cmd.Init(ServerSettings.AniDB_Username, ServerSettings.AniDB_Password); enHelperActivityType ev = cmd.Process(); if (ev == enHelperActivityType.GotMyListHTTP) { foreach (Raw_AniDB_MyListFile myitem in cmd.MyListItems) { // let's check if the file on AniDB actually exists in the user's local collection string hash = string.Empty; AniDB_File anifile = repAniFile.GetByFileID(myitem.FileID); if (anifile != null) hash = anifile.Hash; else { // look for manually linked files List<CrossRef_File_Episode> xrefs = repFileEp.GetByEpisodeID(myitem.EpisodeID); foreach (CrossRef_File_Episode xref in xrefs) { if (xref.CrossRefSource != (int)CrossRefSource.AniDB) { hash = xref.Hash; break; } } } bool fileMissing = false; if (string.IsNullOrEmpty(hash)) fileMissing = true; else { // now check if the file actually exists on disk VideoLocal vid = repVids.GetByHash(hash); if (vid != null && !File.Exists(vid.FullServerPath)) fileMissing = true; } if (fileMissing) { // this means we can't find the file AniDB_Anime anime = null; if (animeCache.ContainsKey(myitem.AnimeID)) anime = animeCache[myitem.AnimeID]; else { anime = repAnime.GetByAnimeID(myitem.AnimeID); animeCache[myitem.AnimeID] = anime; } AnimeSeries ser = null; if (animeSeriesCache.ContainsKey(myitem.AnimeID)) ser = animeSeriesCache[myitem.AnimeID]; else { ser = repSeries.GetByAnimeID(myitem.AnimeID); animeSeriesCache[myitem.AnimeID] = ser; } Contract_MissingFile missingFile = new Contract_MissingFile(); missingFile.AnimeID = myitem.AnimeID; missingFile.AnimeTitle = "Data Missing"; if (anime != null) missingFile.AnimeTitle = anime.MainTitle; missingFile.EpisodeID = myitem.EpisodeID; AniDB_Episode ep = repEpisodes.GetByEpisodeID(myitem.EpisodeID); missingFile.EpisodeNumber = -1; missingFile.EpisodeType = 1; if (ep != null) { missingFile.EpisodeNumber = ep.EpisodeNumber; missingFile.EpisodeType = ep.EpisodeType; } missingFile.FileID = myitem.FileID; if (ser == null) missingFile.AnimeSeries = null; else missingFile.AnimeSeries = ser.ToContract(ser.GetUserRecord(userID)); contracts.Add(missingFile); } } } if (contracts.Count > 0) { List<SortPropOrFieldAndDirection> sortCriteria = new List<SortPropOrFieldAndDirection>(); sortCriteria.Add(new SortPropOrFieldAndDirection("AnimeTitle", false, SortType.eString)); sortCriteria.Add(new SortPropOrFieldAndDirection("EpisodeID", false, SortType.eInteger)); contracts = Sorting.MultiSort<Contract_MissingFile>(contracts, sortCriteria); } } catch (Exception ex) { logger.ErrorException(ex.ToString(), ex); } return contracts; }
public List<Contract_AnimeEpisode> GetEpisodesForSeriesOld(int animeSeriesID) { List<Contract_AnimeEpisode> eps = new List<Contract_AnimeEpisode>(); try { DateTime start = DateTime.Now; AnimeEpisodeRepository repEps = new AnimeEpisodeRepository(); AnimeSeriesRepository repAnimeSer = new AnimeSeriesRepository(); CrossRef_File_EpisodeRepository repCrossRefs = new CrossRef_File_EpisodeRepository(); // get all the data first // we do this to reduce the amount of database calls, which makes it a lot faster AnimeSeries series = repAnimeSer.GetByID(animeSeriesID); if (series == null) return eps; List<AnimeEpisode> epList = repEps.GetBySeriesID(animeSeriesID); AniDB_EpisodeRepository repAniEps = new AniDB_EpisodeRepository(); List<AniDB_Episode> aniEpList = repAniEps.GetByAnimeID(series.AniDB_ID); Dictionary<int, AniDB_Episode> dictAniEps = new Dictionary<int, AniDB_Episode>(); foreach (AniDB_Episode aniep in aniEpList) dictAniEps[aniep.EpisodeID] = aniep; List<CrossRef_File_Episode> crossRefList = repCrossRefs.GetByAnimeID(series.AniDB_ID); TimeSpan ts = DateTime.Now - start; logger.Info("GetEpisodesForSeries: {0} (Database) in {1} ms", series.GetAnime().MainTitle, ts.TotalMilliseconds); start = DateTime.Now; foreach (AnimeEpisode ep in epList) { List<CrossRef_File_Episode> xrefs = new List<CrossRef_File_Episode>(); foreach (CrossRef_File_Episode xref in crossRefList) { if (ep.AniDB_EpisodeID == xref.EpisodeID) xrefs.Add(xref); } if (dictAniEps.ContainsKey(ep.AniDB_EpisodeID)) eps.Add(ep.ToContractOld(dictAniEps[ep.AniDB_EpisodeID])); } ts = DateTime.Now - start; logger.Info("GetEpisodesForSeries: {0} (Contracts) in {1} ms", series.GetAnime().MainTitle, ts.TotalMilliseconds); } catch (Exception ex) { logger.ErrorException(ex.ToString(), ex); } return eps; }
public List<Contract_AnimeEpisode> GetEpisodesForSeries(int animeSeriesID, int userID) { List<Contract_AnimeEpisode> eps = new List<Contract_AnimeEpisode>(); try { DateTime start = DateTime.Now; AnimeEpisodeRepository repEps = new AnimeEpisodeRepository(); AnimeEpisode_UserRepository repEpUsers = new AnimeEpisode_UserRepository(); AnimeSeriesRepository repAnimeSer = new AnimeSeriesRepository(); VideoLocalRepository repVids = new VideoLocalRepository(); CrossRef_File_EpisodeRepository repCrossRefs = new CrossRef_File_EpisodeRepository(); // get all the data first // we do this to reduce the amount of database calls, which makes it a lot faster AnimeSeries series = repAnimeSer.GetByID(animeSeriesID); if (series == null) return eps; List<AnimeEpisode> epList = repEps.GetBySeriesID(animeSeriesID); List<AnimeEpisode_User> userRecordList = repEpUsers.GetByUserIDAndSeriesID(userID, animeSeriesID); Dictionary<int, AnimeEpisode_User> dictUserRecords = new Dictionary<int, AnimeEpisode_User>(); foreach (AnimeEpisode_User epuser in userRecordList) dictUserRecords[epuser.AnimeEpisodeID] = epuser; AniDB_EpisodeRepository repAniEps = new AniDB_EpisodeRepository(); List<AniDB_Episode> aniEpList = repAniEps.GetByAnimeID(series.AniDB_ID); Dictionary<int, AniDB_Episode> dictAniEps = new Dictionary<int, AniDB_Episode>(); foreach (AniDB_Episode aniep in aniEpList) dictAniEps[aniep.EpisodeID] = aniep; // get all the video local records and cross refs List<VideoLocal> vids = repVids.GetByAniDBAnimeID(series.AniDB_ID); List<CrossRef_File_Episode> crossRefs = repCrossRefs.GetByAnimeID(series.AniDB_ID); TimeSpan ts = DateTime.Now - start; logger.Info("GetEpisodesForSeries: {0} (Database) in {1} ms", series.GetAnime().MainTitle, ts.TotalMilliseconds); start = DateTime.Now; foreach (AnimeEpisode ep in epList) { if (dictAniEps.ContainsKey(ep.AniDB_EpisodeID)) { List<VideoLocal> epVids = new List<VideoLocal>(); foreach (CrossRef_File_Episode xref in crossRefs) { if (xref.EpisodeID == dictAniEps[ep.AniDB_EpisodeID].EpisodeID) { // don't add the same file twice, this will occur when // one file appears over more than one episodes Dictionary<string, string> addedFiles = new Dictionary<string, string>(); foreach (VideoLocal vl in vids) { if (string.Equals(xref.Hash, vl.Hash, StringComparison.InvariantCultureIgnoreCase)) { if (!addedFiles.ContainsKey(xref.Hash.Trim().ToUpper())) { addedFiles[xref.Hash.Trim().ToUpper()] = xref.Hash.Trim().ToUpper(); epVids.Add(vl); } } } } } AnimeEpisode_User epuser = null; if (dictUserRecords.ContainsKey(ep.AnimeEpisodeID)) epuser = dictUserRecords[ep.AnimeEpisodeID]; eps.Add(ep.ToContract(dictAniEps[ep.AniDB_EpisodeID], epVids, epuser, null)); } } ts = DateTime.Now - start; logger.Info("GetEpisodesForSeries: {0} (Contracts) in {1} ms", series.GetAnime().MainTitle, ts.TotalMilliseconds); } catch (Exception ex) { logger.ErrorException(ex.ToString(), ex); } return eps; }
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 ""; }
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 ""; }
private VideoLocal ProcessFile_LocalInfo() { // hash and read media info for file int nshareID = -1; string filePath = ""; ImportFolderRepository repNS = new ImportFolderRepository(); List<ImportFolder> shares = repNS.GetAll(); DataAccessHelper.GetShareAndPath(FileName, shares, ref nshareID, ref filePath); if (!File.Exists(FileName)) { logger.Error("File does not exist: {0}", FileName); return null; } int numAttempts = 0; // Wait 3 minutes seconds before giving up on trying to access the file while ((!CanAccessFile(FileName)) && (numAttempts < 180)) { numAttempts++; Thread.Sleep(1000); Console.WriteLine("Attempt # " + numAttempts.ToString()); } // if we failed to access the file, get ouuta here if (numAttempts == 180) { logger.Error("Could not access file: " + FileName); return null; } // check if we have already processed this file VideoLocal vlocal = null; VideoLocalRepository repVidLocal = new VideoLocalRepository(); FileNameHashRepository repFNHash = new FileNameHashRepository(); List<VideoLocal> vidLocals = repVidLocal.GetByFilePathAndShareID(filePath, nshareID); FileInfo fi = new FileInfo(FileName); if (vidLocals.Count > 0) { vlocal = vidLocals[0]; logger.Trace("VideoLocal record found in database: {0}", vlocal.VideoLocalID); if (ForceHash) { vlocal.FileSize = fi.Length; vlocal.DateTimeUpdated = DateTime.Now; } } else { logger.Trace("VideoLocal, creating new record"); vlocal = new VideoLocal(); vlocal.DateTimeUpdated = DateTime.Now; vlocal.DateTimeCreated = vlocal.DateTimeUpdated; vlocal.FilePath = filePath; vlocal.FileSize = fi.Length; vlocal.ImportFolderID = nshareID; vlocal.Hash = ""; vlocal.CRC32 = ""; vlocal.MD5 = ""; vlocal.SHA1 = ""; vlocal.IsIgnored = 0; vlocal.IsVariation = 0; } // check if we need to get a hash this file Hashes hashes = null; if (string.IsNullOrEmpty(vlocal.Hash) || ForceHash) { // try getting the hash from the CrossRef if (!ForceHash) { CrossRef_File_EpisodeRepository repCrossRefs = new CrossRef_File_EpisodeRepository(); List<CrossRef_File_Episode> crossRefs = repCrossRefs.GetByFileNameAndSize(Path.GetFileName(vlocal.FilePath), vlocal.FileSize); if (crossRefs.Count == 1) { vlocal.Hash = crossRefs[0].Hash; vlocal.HashSource = (int)HashSource.DirectHash; } } // try getting the hash from the LOCAL cache if (!ForceHash && string.IsNullOrEmpty(vlocal.Hash)) { List<FileNameHash> fnhashes = repFNHash.GetByFileNameAndSize(Path.GetFileName(vlocal.FilePath), vlocal.FileSize); if (fnhashes != null && fnhashes.Count > 1) { // if we have more than one record it probably means there is some sort of corruption // lets delete the local records foreach (FileNameHash fnh in fnhashes) { repFNHash.Delete(fnh.FileNameHashID); } } if (fnhashes != null && fnhashes.Count == 1) { logger.Trace("Got hash from LOCAL cache: {0} ({1})", FileName, fnhashes[0].Hash); vlocal.Hash = fnhashes[0].Hash; vlocal.HashSource = (int)HashSource.WebCacheFileName; } } // hash the file if (string.IsNullOrEmpty(vlocal.Hash) || ForceHash) { DateTime start = DateTime.Now; logger.Trace("Calculating hashes for: {0}", FileName); // update the VideoLocal record with the Hash hashes = FileHashHelper.GetHashInfo(FileName, true, MainWindow.OnHashProgress, ServerSettings.Hash_CRC32, ServerSettings.Hash_MD5, ServerSettings.Hash_SHA1); TimeSpan ts = DateTime.Now - start; logger.Trace("Hashed file in {0} seconds --- {1} ({2})", ts.TotalSeconds.ToString("#0.0"), FileName, Utils.FormatByteSize(vlocal.FileSize)); vlocal.Hash = hashes.ed2k; vlocal.CRC32 = hashes.crc32; vlocal.MD5 = hashes.md5; vlocal.SHA1 = hashes.sha1; vlocal.HashSource = (int)HashSource.DirectHash; } // We should have a hash by now // before we save it, lets make sure there is not any other record with this hash (possible duplicate file) VideoLocal vidTemp = repVidLocal.GetByHash(vlocal.Hash); if (vidTemp != null) { // don't delete it, if it is actually the same record if (vidTemp.VideoLocalID != vlocal.VideoLocalID) { // delete the VideoLocal record logger.Warn("Deleting duplicate video file record"); logger.Warn("---------------------------------------------"); logger.Warn("Keeping record for: {0}", vlocal.FullServerPath); logger.Warn("Deleting record for: {0}", vidTemp.FullServerPath); logger.Warn("---------------------------------------------"); // check if we have a record of this in the database, if not create one DuplicateFileRepository repDups = new DuplicateFileRepository(); List<DuplicateFile> dupFiles = repDups.GetByFilePathsAndImportFolder(vlocal.FilePath, vidTemp.FilePath, vlocal.ImportFolderID, vidTemp.ImportFolderID); if (dupFiles.Count == 0) dupFiles = repDups.GetByFilePathsAndImportFolder(vidTemp.FilePath, vlocal.FilePath, vidTemp.ImportFolderID, vlocal.ImportFolderID); if (dupFiles.Count == 0) { DuplicateFile dup = new DuplicateFile(); dup.DateTimeUpdated = DateTime.Now; dup.FilePathFile1 = vlocal.FilePath; dup.FilePathFile2 = vidTemp.FilePath; dup.ImportFolderIDFile1 = vlocal.ImportFolderID; dup.ImportFolderIDFile2 = vidTemp.ImportFolderID; dup.Hash = vlocal.Hash; repDups.Save(dup); } repVidLocal.Delete(vidTemp.VideoLocalID); } } repVidLocal.Save(vlocal); // also save the filename to hash record // replace the existing records just in case it was corrupt FileNameHash fnhash = null; List<FileNameHash> fnhashes2 = repFNHash.GetByFileNameAndSize(Path.GetFileName(vlocal.FilePath), vlocal.FileSize); if (fnhashes2 != null && fnhashes2.Count > 1) { // if we have more than one record it probably means there is some sort of corruption // lets delete the local records foreach (FileNameHash fnh in fnhashes2) { repFNHash.Delete(fnh.FileNameHashID); } } if (fnhashes2 != null && fnhashes2.Count == 1) fnhash = fnhashes2[0]; else fnhash = new FileNameHash(); fnhash.FileName = Path.GetFileName(vlocal.FilePath); fnhash.FileSize = vlocal.FileSize; fnhash.Hash = vlocal.Hash; fnhash.DateTimeUpdated = DateTime.Now; repFNHash.Save(fnhash); } // now check if we have stored a VideoInfo record bool refreshMediaInfo = false; VideoInfoRepository repVidInfo = new VideoInfoRepository(); VideoInfo vinfo = repVidInfo.GetByHash(vlocal.Hash); if (vinfo == null) { refreshMediaInfo = true; vinfo = new VideoInfo(); vinfo.Hash = vlocal.Hash; vinfo.Duration = 0; vinfo.FileSize = fi.Length; vinfo.DateTimeUpdated = DateTime.Now; vinfo.FileName = filePath; vinfo.AudioBitrate = ""; vinfo.AudioCodec = ""; vinfo.VideoBitrate = ""; vinfo.VideoBitDepth = ""; vinfo.VideoCodec = ""; vinfo.VideoFrameRate = ""; vinfo.VideoResolution = ""; repVidInfo.Save(vinfo); } else { // check if we need to update the media info if (vinfo.VideoCodec.Trim().Length == 0) refreshMediaInfo = true; else refreshMediaInfo = false; } if (refreshMediaInfo) { logger.Trace("Getting media info for: {0}", FileName); MediaInfoResult mInfo = FileHashHelper.GetMediaInfo(FileName, true); vinfo.AudioBitrate = string.IsNullOrEmpty(mInfo.AudioBitrate) ? "" : mInfo.AudioBitrate; vinfo.AudioCodec = string.IsNullOrEmpty(mInfo.AudioCodec) ? "" : mInfo.AudioCodec; vinfo.DateTimeUpdated = vlocal.DateTimeUpdated; vinfo.Duration = mInfo.Duration; vinfo.FileName = filePath; vinfo.FileSize = fi.Length; vinfo.VideoBitrate = string.IsNullOrEmpty(mInfo.VideoBitrate) ? "" : mInfo.VideoBitrate; vinfo.VideoBitDepth = string.IsNullOrEmpty(mInfo.VideoBitDepth) ? "" : mInfo.VideoBitDepth; vinfo.VideoCodec = string.IsNullOrEmpty(mInfo.VideoCodec) ? "" : mInfo.VideoCodec; vinfo.VideoFrameRate = string.IsNullOrEmpty(mInfo.VideoFrameRate) ? "" : mInfo.VideoFrameRate; vinfo.VideoResolution = string.IsNullOrEmpty(mInfo.VideoResolution) ? "" : mInfo.VideoResolution; vinfo.FullInfo = string.IsNullOrEmpty(mInfo.FullInfo) ? "" : mInfo.FullInfo; repVidInfo.Save(vinfo); } // now add a command to process the file CommandRequest_ProcessFile cr_procfile = new CommandRequest_ProcessFile(vlocal.VideoLocalID, false); cr_procfile.Save(); return vlocal; }
public void ToggleWatchedStatus(bool watched, bool updateOnline, DateTime? watchedDate, bool updateStats, bool updateStatsCache, int userID, bool scrobbleTrakt, bool updateWatchedDate) { VideoLocalRepository repVids = new VideoLocalRepository(); AnimeEpisodeRepository repEpisodes = new AnimeEpisodeRepository(); AniDB_FileRepository repAniFile = new AniDB_FileRepository(); CrossRef_File_EpisodeRepository repCross = new CrossRef_File_EpisodeRepository(); VideoLocal_UserRepository repVidUsers = new VideoLocal_UserRepository(); JMMUserRepository repUsers = new JMMUserRepository(); AnimeEpisode_UserRepository repEpisodeUsers = new AnimeEpisode_UserRepository(); JMMUser user = repUsers.GetByID(userID); if (user == null) return; List<JMMUser> aniDBUsers = repUsers.GetAniDBUsers(); // update the video file to watched int mywatched = watched ? 1 : 0; if (user.IsAniDBUser == 0) SaveWatchedStatus(watched, userID, watchedDate, updateWatchedDate); else { // if the user is AniDB user we also want to update any other AniDB // users to keep them in sync foreach (JMMUser juser in aniDBUsers) { if (juser.IsAniDBUser == 1) SaveWatchedStatus(watched, juser.JMMUserID, watchedDate, updateWatchedDate); } } // now lets find all the associated AniDB_File record if there is one if (user.IsAniDBUser == 1) { AniDB_File aniFile = repAniFile.GetByHash(this.Hash); if (aniFile != null) { aniFile.IsWatched = mywatched; if (watched) { if (watchedDate.HasValue) aniFile.WatchedDate = watchedDate; else aniFile.WatchedDate = DateTime.Now; } else aniFile.WatchedDate = null; repAniFile.Save(aniFile, false); } if (updateOnline) { if ((watched && ServerSettings.AniDB_MyList_SetWatched) || (!watched && ServerSettings.AniDB_MyList_SetUnwatched)) { CommandRequest_UpdateMyListFileStatus cmd = new CommandRequest_UpdateMyListFileStatus(this.Hash, watched, false, watchedDate.HasValue ? Utils.GetAniDBDateAsSeconds(watchedDate) : 0); cmd.Save(); } } } // now find all the episode records associated with this video file // but we also need to check if theer are any other files attached to this episode with a watched // status, AnimeSeries ser = null; // get all files associated with this episode List<CrossRef_File_Episode> xrefs = repCross.GetByHash(this.Hash); if (watched) { // find the total watched percentage // eg one file can have a % = 100 // or if 2 files make up one episodes they will each have a % = 50 foreach (CrossRef_File_Episode xref in xrefs) { // get the episode for this file AnimeEpisode ep = repEpisodes.GetByAniDBEpisodeID(xref.EpisodeID); if (ep == null) continue; // get all the files for this episode int epPercentWatched = 0; foreach (CrossRef_File_Episode filexref in ep.FileCrossRefs) { VideoLocal_User vidUser = filexref.GetVideoLocalUserRecord(userID); if (vidUser != null) { // if not null means it is watched epPercentWatched += filexref.Percentage; } if (epPercentWatched > 95) break; } if (epPercentWatched > 95) { ser = ep.GetAnimeSeries(); if (user.IsAniDBUser == 0) ep.SaveWatchedStatus(true, userID, watchedDate, updateWatchedDate); else { // if the user is AniDB user we also want to update any other AniDB // users to keep them in sync foreach (JMMUser juser in aniDBUsers) { if (juser.IsAniDBUser == 1) ep.SaveWatchedStatus(true, juser.JMMUserID, watchedDate, updateWatchedDate); } } if (scrobbleTrakt && !string.IsNullOrEmpty(ServerSettings.Trakt_Username) && !string.IsNullOrEmpty(ServerSettings.Trakt_Password)) { CommandRequest_TraktShowScrobble cmdScrobble = new CommandRequest_TraktShowScrobble(ep.AnimeEpisodeID); cmdScrobble.Save(); } if (!string.IsNullOrEmpty(ServerSettings.MAL_Username) && !string.IsNullOrEmpty(ServerSettings.MAL_Password)) { CommandRequest_MALUpdatedWatchedStatus cmdMAL = new CommandRequest_MALUpdatedWatchedStatus(ser.AniDB_ID); cmdMAL.Save(); } } } } else { // if setting a file to unwatched only set the episode unwatched, if ALL the files are unwatched foreach (CrossRef_File_Episode xrefEp in xrefs) { AnimeEpisode ep = repEpisodes.GetByAniDBEpisodeID(xrefEp.EpisodeID); if (ep == null) continue; ser = ep.GetAnimeSeries(); // get all the files for this episode int epPercentWatched = 0; foreach (CrossRef_File_Episode filexref in ep.FileCrossRefs) { VideoLocal_User vidUser = filexref.GetVideoLocalUserRecord(userID); if (vidUser != null) epPercentWatched += filexref.Percentage; if (epPercentWatched > 95) break; } if (epPercentWatched < 95) { if (user.IsAniDBUser == 0) ep.SaveWatchedStatus(false, userID, watchedDate, true); else { // if the user is AniDB user we also want to update any other AniDB // users to keep them in sync foreach (JMMUser juser in aniDBUsers) { if (juser.IsAniDBUser == 1) ep.SaveWatchedStatus(false, juser.JMMUserID, watchedDate, true); } } CommandRequest_TraktShowEpisodeUnseen cmdUnseen = new CommandRequest_TraktShowEpisodeUnseen(ep.AnimeEpisodeID); cmdUnseen.Save(); } } if (!string.IsNullOrEmpty(ServerSettings.MAL_Username) && !string.IsNullOrEmpty(ServerSettings.MAL_Password)) { CommandRequest_MALUpdatedWatchedStatus cmdMAL = new CommandRequest_MALUpdatedWatchedStatus(ser.AniDB_ID); cmdMAL.Save(); } } // update stats for groups and series if (ser != null && updateStats) { // update all the groups above this series in the heirarchy ser.UpdateStats(true, true, true); //ser.TopLevelAnimeGroup.UpdateStatsFromTopLevel(true, true, true); } if (ser != null && updateStatsCache) StatsCache.Instance.UpdateUsingSeries(ser.AnimeSeriesID); }
public void UpdateUsingGroup(ISession session, int animeGroupID) { try { DateTime start = DateTime.Now; AnimeGroupRepository repGroups = new AnimeGroupRepository(); AnimeGroup thisgrp = repGroups.GetByID(session, animeGroupID); if (thisgrp == null) return; AdhocRepository repAdHoc = new AdhocRepository(); // get a list of all the groups including this one and everthing above it the heirarchy List<AnimeGroup> allgroups = new List<AnimeGroup>(); allgroups.Add(thisgrp); int? groupID = thisgrp.AnimeGroupParentID; while (groupID.HasValue) { AnimeGroup grpTemp = repGroups.GetByID(session, groupID.Value); if (grpTemp != null) { allgroups.Add(grpTemp); groupID = grpTemp.AnimeGroupParentID; } else groupID = null; } TimeSpan ts = DateTime.Now - start; logger.Trace("Updating cached stats for GROUP - STEP 1 ({0}) in {1} ms", thisgrp.GroupName, ts.TotalMilliseconds); start = DateTime.Now; VideoLocalRepository repVids = new VideoLocalRepository(); CrossRef_File_EpisodeRepository repXrefs = new CrossRef_File_EpisodeRepository(); foreach (AnimeGroup grp in allgroups) { StatGroupCategories[grp.AnimeGroupID] = grp.CategoriesString; StatGroupTitles[grp.AnimeGroupID] = grp.TitlesString; StatGroupVideoQuality[grp.AnimeGroupID] = grp.VideoQualityString; ts = DateTime.Now - start; logger.Trace("Updating cached stats for GROUP - STEP 2 ({0}) in {1} ms", grp.GroupName, ts.TotalMilliseconds); start = DateTime.Now; DateTime? airDate_Min = null; DateTime? airDate_Max = null; DateTime? endDate = new DateTime(1980, 1, 1); DateTime? seriesCreatedDate = null; bool isComplete = false; bool hasFinishedAiring = false; bool isCurrentlyAiring = false; string videoQualityEpisodes = ""; List<string> audioLanguages = new List<string>(); List<string> subtitleLanguages = new List<string>(); bool hasTvDB = true; bool hasMAL = true; bool hasMovieDB = true; bool hasMovieDBOrTvDB = true; int seriesCount = 0; int epCount = 0; foreach (AnimeSeries series in grp.GetAllSeries(session)) { seriesCount++; List<VideoLocal> vidsTemp = repVids.GetByAniDBAnimeID(session, series.AniDB_ID); List<CrossRef_File_Episode> crossRefs = repXrefs.GetByAnimeID(session, series.AniDB_ID); Dictionary<int, List<CrossRef_File_Episode>> dictCrossRefs = new Dictionary<int, List<CrossRef_File_Episode>>(); foreach (CrossRef_File_Episode xref in crossRefs) { if (!dictCrossRefs.ContainsKey(xref.EpisodeID)) dictCrossRefs[xref.EpisodeID] = new List<CrossRef_File_Episode>(); dictCrossRefs[xref.EpisodeID].Add(xref); } Dictionary<string, VideoLocal> dictVids = new Dictionary<string, VideoLocal>(); foreach (VideoLocal vid in vidsTemp) dictVids[vid.Hash] = vid; // All Video Quality Episodes // Try to determine if this anime has all the episodes available at a certain video quality // e.g. the series has all episodes in blu-ray // Also look at languages Dictionary<string, int> vidQualEpCounts = new Dictionary<string,int>(); // video quality, count of episodes foreach (AnimeEpisode ep in series.GetAnimeEpisodes(session)) { if (ep.EpisodeTypeEnum != AniDBAPI.enEpisodeType.Episode) continue; List<VideoLocal> epVids = new List<VideoLocal>(); if (dictCrossRefs.ContainsKey(ep.AniDB_EpisodeID)) { foreach (CrossRef_File_Episode xref in dictCrossRefs[ep.AniDB_EpisodeID]) { if (xref.EpisodeID == ep.AniDB_EpisodeID) { if (dictVids.ContainsKey(xref.Hash)) epVids.Add(dictVids[xref.Hash]); } } } List<string> qualityAddedSoFar = new List<string>(); // handle mutliple files of the same quality for one episode foreach (VideoLocal vid in epVids) { AniDB_File anifile = vid.GetAniDBFile(session); if (anifile == null) continue; if (!qualityAddedSoFar.Contains(anifile.File_Source)) { if (!vidQualEpCounts.ContainsKey(anifile.File_Source)) vidQualEpCounts[anifile.File_Source] = 1; else vidQualEpCounts[anifile.File_Source]++; qualityAddedSoFar.Add(anifile.File_Source); } } } ts = DateTime.Now - start; logger.Trace("Updating cached stats for GROUP/Series - STEP 3 ({0}/{1}) in {2} ms",grp.GroupName, series.AnimeSeriesID, ts.TotalMilliseconds); start = DateTime.Now; AniDB_Anime anime = series.GetAnime(session); epCount = epCount + anime.EpisodeCountNormal; foreach (KeyValuePair<string, int> kvp in vidQualEpCounts) { int index = videoQualityEpisodes.IndexOf(kvp.Key, 0, StringComparison.InvariantCultureIgnoreCase); if (index > -1) continue; // don't add if we already have it if (anime.EpisodeCountNormal == kvp.Value) { if (videoQualityEpisodes.Length > 0) videoQualityEpisodes += ","; videoQualityEpisodes += kvp.Key; } } ts = DateTime.Now - start; logger.Trace("Updating cached stats for GROUP/Series - STEP 4 ({0}/{1}) in {2} ms", grp.GroupName, series.AnimeSeriesID, ts.TotalMilliseconds); start = DateTime.Now; // audio languages Dictionary<int, LanguageStat> dicAudio = repAdHoc.GetAudioLanguageStatsByAnime(session, anime.AnimeID); foreach (KeyValuePair<int, LanguageStat> kvp in dicAudio) { foreach (string lanName in kvp.Value.LanguageNames) { if (!audioLanguages.Contains(lanName)) audioLanguages.Add(lanName); } } ts = DateTime.Now - start; logger.Trace("Updating cached stats for GROUP/Series - STEP 5 ({0}/{1}) in {2} ms", grp.GroupName, series.AnimeSeriesID, ts.TotalMilliseconds); start = DateTime.Now; // subtitle languages Dictionary<int, LanguageStat> dicSubtitle = repAdHoc.GetSubtitleLanguageStatsByAnime(session, anime.AnimeID); foreach (KeyValuePair<int, LanguageStat> kvp in dicSubtitle) { foreach (string lanName in kvp.Value.LanguageNames) { if (!subtitleLanguages.Contains(lanName)) subtitleLanguages.Add(lanName); } } ts = DateTime.Now - start; logger.Trace("Updating cached stats for GROUP/Series - STEP 6 ({0}/{1}) in {2} ms", grp.GroupName, series.AnimeSeriesID, ts.TotalMilliseconds); start = DateTime.Now; // Calculate Air Date DateTime? thisDate = series.AirDate; if (thisDate.HasValue) { if (airDate_Min.HasValue) { if (thisDate.Value < airDate_Min.Value) airDate_Min = thisDate; } else airDate_Min = thisDate; if (airDate_Max.HasValue) { if (thisDate.Value > airDate_Max.Value) airDate_Max = thisDate; } else airDate_Max = thisDate; } // calculate end date // if the end date is NULL it actually means it is ongoing, so this is the max possible value thisDate = series.EndDate; if (thisDate.HasValue && endDate.HasValue) { if (thisDate.Value > endDate.Value) endDate = thisDate; } else endDate = null; // Note - only one series has to be finished airing to qualify if (series.EndDate.HasValue && series.EndDate.Value < DateTime.Now) hasFinishedAiring = true; // Note - only one series has to be finished airing to qualify if (!series.EndDate.HasValue || series.EndDate.Value > DateTime.Now) isCurrentlyAiring = true; // We evaluate IsComplete as true if // 1. series has finished airing // 2. user has all episodes locally // Note - only one series has to be complete for the group to be considered complete if (series.EndDate.HasValue) { if (series.EndDate.Value < DateTime.Now && series.MissingEpisodeCount == 0 && series.MissingEpisodeCountGroups == 0) { isComplete = true; } } // Calculate Series Created Date thisDate = series.DateTimeCreated; if (thisDate.HasValue) { if (seriesCreatedDate.HasValue) { if (thisDate.Value < seriesCreatedDate.Value) seriesCreatedDate = thisDate; } else seriesCreatedDate = thisDate; } ts = DateTime.Now - start; logger.Trace("Updating cached stats for GROUP/Series - STEP 7 ({0}/{1}) in {2} ms", grp.GroupName, series.AnimeSeriesID, ts.TotalMilliseconds); start = DateTime.Now; // for the group, if any of the series don't have a tvdb link // we will consider the group as not having a tvdb link List<CrossRef_AniDB_TvDBV2> tvXrefs = series.GetCrossRefTvDBV2(); if (tvXrefs == null || tvXrefs.Count == 0) hasTvDB = false; if (series.CrossRefMovieDB == null) hasMovieDB = false; if (series.CrossRefMAL == null) hasMAL = false; if ((tvXrefs == null || tvXrefs.Count == 0) && series.CrossRefMovieDB == null) hasMovieDBOrTvDB = false; } StatGroupIsComplete[grp.AnimeGroupID] = isComplete; StatGroupIsFinishedAiring[grp.AnimeGroupID] = hasFinishedAiring; StatGroupIsCurrentlyAiring[grp.AnimeGroupID] = isCurrentlyAiring; StatGroupHasTvDB[grp.AnimeGroupID] = hasTvDB; StatGroupHasMAL[grp.AnimeGroupID] = hasMAL; StatGroupHasMovieDB[grp.AnimeGroupID] = hasMovieDB; StatGroupHasMovieDBOrTvDB[grp.AnimeGroupID] = hasMovieDBOrTvDB; StatGroupSeriesCount[grp.AnimeGroupID] = seriesCount; StatGroupEpisodeCount[grp.AnimeGroupID] = epCount; StatGroupVideoQualityEpisodes[grp.AnimeGroupID] = videoQualityEpisodes; StatGroupAirDate_Min[grp.AnimeGroupID] = airDate_Min; StatGroupAirDate_Max[grp.AnimeGroupID] = airDate_Max; StatGroupEndDate[grp.AnimeGroupID] = endDate; StatGroupSeriesCreatedDate[grp.AnimeGroupID] = seriesCreatedDate; StatGroupUserVoteOverall[grp.AnimeGroupID] = grp.UserVote; StatGroupUserVotePermanent[grp.AnimeGroupID] = grp.UserVotePermanent; StatGroupUserVoteTemporary[grp.AnimeGroupID] = grp.UserVoteTemporary; StatGroupAniDBRating[grp.AnimeGroupID] = grp.AniDBRating; ts = DateTime.Now - start; logger.Trace("Updating cached stats for GROUP - STEP 8 ({0}) in {1} ms", grp.GroupName, ts.TotalMilliseconds); start = DateTime.Now; string Stat_AudioLanguages = ""; foreach (string audioLan in audioLanguages) { if (Stat_AudioLanguages.Length > 0) Stat_AudioLanguages += ","; Stat_AudioLanguages += audioLan; } this.StatGroupAudioLanguages[grp.AnimeGroupID] = Stat_AudioLanguages; string Stat_SubtitleLanguages = ""; foreach (string subLan in subtitleLanguages) { if (Stat_SubtitleLanguages.Length > 0) Stat_SubtitleLanguages += ","; Stat_SubtitleLanguages += subLan; } this.StatGroupSubtitleLanguages[grp.AnimeGroupID] = Stat_SubtitleLanguages; ts = DateTime.Now - start; logger.Trace("Updating cached stats for GROUP - STEP 9 ({0}) in {1} ms", grp.GroupName, ts.TotalMilliseconds); start = DateTime.Now; UpdateGroupFilterUsingGroup(grp.AnimeGroupID); UpdatePlexAnimeGroup(session, grp,grp.GetAllSeries()); ts = DateTime.Now - start; logger.Trace("Updating cached stats for GROUP - END ({0}) in {1} ms", grp.GroupName, ts.TotalMilliseconds); } } catch (Exception ex) { logger.ErrorException(ex.ToString(), ex); } }
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 RemoveRecordsWithoutPhysicalFiles() { VideoLocalRepository repVidLocals = new VideoLocalRepository(); CrossRef_File_EpisodeRepository repXRefs = new CrossRef_File_EpisodeRepository(); // get a full list of files List<VideoLocal> filesAll = repVidLocals.GetAll(); foreach (VideoLocal vl in filesAll) { if (!File.Exists(vl.FullServerPath)) { // delete video local record logger.Info("RemoveRecordsWithoutPhysicalFiles : {0}", vl.FullServerPath); repVidLocals.Delete(vl.VideoLocalID); CommandRequest_DeleteFileFromMyList cmdDel = new CommandRequest_DeleteFileFromMyList(vl.Hash, vl.FileSize); cmdDel.Save(); } } UpdateAllStats(); }
public override void ProcessCommand() { logger.Info("Processing CommandRequest_SyncMyList"); try { // we will always assume that an anime was downloaded via http first ScheduledUpdateRepository repSched = new ScheduledUpdateRepository(); AniDB_FileRepository repAniFile = new AniDB_FileRepository(); VideoLocalRepository repVidLocals = new VideoLocalRepository(); ScheduledUpdate sched = repSched.GetByUpdateType((int)ScheduledUpdateType.AniDBMyListSync); if (sched == null) { sched = new ScheduledUpdate(); sched.UpdateType = (int)ScheduledUpdateType.AniDBMyListSync; sched.UpdateDetails = ""; } else { int freqHours = Utils.GetScheduledHours(ServerSettings.AniDB_MyList_UpdateFrequency); // if we have run this in the last 24 hours and are not forcing it, then exit TimeSpan tsLastRun = DateTime.Now - sched.LastUpdate; if (tsLastRun.TotalHours < freqHours) { if (!ForceRefresh) return; } } AniDBHTTPCommand_GetMyList cmd = new AniDBHTTPCommand_GetMyList(); cmd.Init(ServerSettings.AniDB_Username, ServerSettings.AniDB_Password); enHelperActivityType ev = cmd.Process(); if (ev == enHelperActivityType.GotMyListHTTP && cmd.MyListItems.Count > 1) { int totalItems = 0; int watchedItems = 0; int modifiedItems = 0; double pct = 0; // 2. find files locally for the user, which are not recorded on anidb // and then add them to anidb Dictionary<int, Raw_AniDB_MyListFile> onlineFiles = new Dictionary<int, Raw_AniDB_MyListFile>(); foreach (Raw_AniDB_MyListFile myitem in cmd.MyListItems) onlineFiles[myitem.FileID] = myitem; Dictionary<string, AniDB_File> dictAniFiles = new Dictionary<string, AniDB_File>(); List<AniDB_File> allAniFiles = repAniFile.GetAll(); foreach (AniDB_File anifile in allAniFiles) dictAniFiles[anifile.Hash] = anifile; int missingFiles = 0; foreach (VideoLocal vid in repVidLocals.GetAll()) { if (!dictAniFiles.ContainsKey(vid.Hash)) continue; int fileID = dictAniFiles[vid.Hash].FileID; if (!onlineFiles.ContainsKey(fileID)) { // means we have found a file in our local collection, which is not recorded online CommandRequest_AddFileToMyList cmdAddFile = new CommandRequest_AddFileToMyList(vid.Hash); cmdAddFile.Save(); missingFiles++; } } logger.Info(string.Format("MYLIST Missing Files: {0} Added to queue for inclusion", missingFiles)); JMMUserRepository repUsers = new JMMUserRepository(); List<JMMUser> aniDBUsers = repUsers.GetAniDBUsers(); VideoLocal_UserRepository repVidUsers = new VideoLocal_UserRepository(); CrossRef_File_EpisodeRepository repFileEp = new CrossRef_File_EpisodeRepository(); // 1 . sync mylist items foreach (Raw_AniDB_MyListFile myitem in cmd.MyListItems) { // ignore files mark as deleted by the user if (myitem.State == (int)AniDBFileStatus.Deleted) continue; totalItems++; if (myitem.IsWatched) watchedItems++; //calculate percentage pct = (double)totalItems / (double)cmd.MyListItems.Count * (double)100; string spct = pct.ToString("#0.0"); string hash = string.Empty; AniDB_File anifile = repAniFile.GetByFileID(myitem.FileID); if (anifile != null) hash = anifile.Hash; else { // look for manually linked files List<CrossRef_File_Episode> xrefs = repFileEp.GetByEpisodeID(myitem.EpisodeID); foreach (CrossRef_File_Episode xref in xrefs) { if (xref.CrossRefSource != (int)CrossRefSource.AniDB) { hash = xref.Hash; break; } } } if (!string.IsNullOrEmpty(hash)) { // find the video associated with this record VideoLocal vl = repVidLocals.GetByHash(hash); if (vl == null) continue; foreach (JMMUser juser in aniDBUsers) { bool localStatus = false; int? jmmUserID = null; // doesn't matter which anidb user we use jmmUserID = juser.JMMUserID; VideoLocal_User userRecord = vl.GetUserRecord(juser.JMMUserID); if (userRecord != null) localStatus = true; string action = ""; if (localStatus != myitem.IsWatched) { if (localStatus == true) { // local = watched, anidb = unwatched if (ServerSettings.AniDB_MyList_ReadUnwatched) { modifiedItems++; if (jmmUserID.HasValue) vl.ToggleWatchedStatus(myitem.IsWatched, false, myitem.WatchedDate, false, false, jmmUserID.Value, false, true); action = "Used AniDB Status"; } } else { // means local is un-watched, and anidb is watched if (ServerSettings.AniDB_MyList_ReadWatched) { modifiedItems++; if (jmmUserID.HasValue) vl.ToggleWatchedStatus(true, false, myitem.WatchedDate, false, false, jmmUserID.Value, false, true); action = "Updated Local record to Watched"; } } string msg = string.Format("MYLISTDIFF:: File {0} - Local Status = {1}, AniDB Status = {2} --- {3}", vl.FullServerPath, localStatus, myitem.IsWatched, action); logger.Info(msg); } } //string msg = string.Format("MYLIST:: File {0} - Local Status = {1}, AniDB Status = {2} --- {3}", // vl.FullServerPath, localStatus, myitem.IsWatched, action); //logger.Info(msg); } } // now update all stats Importer.UpdateAllStats(); logger.Info("Process MyList: {0} Items, {1} Watched, {2} Modified", totalItems, watchedItems, modifiedItems); sched.LastUpdate = DateTime.Now; repSched.Save(sched); } } catch (Exception ex) { logger.Error("Error processing CommandRequest_SyncMyList: {0} ", ex.ToString()); 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(); CrossRef_File_Episode xref = new 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.UpdateStats(true, true, true); 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 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 ""; }
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) { crossRefs = XMLService.Get_CrossRef_File_Episode(vidLocal); if (crossRefs == null || crossRefs.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 (CrossRef_File_Episode xref in crossRefs) { // in this case we need to save the cross refs manually as AniDB did not provide them repXrefFE.Save(xref); } } } 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...."); // try using the cache first using (var session = JMMService.SessionFactory.OpenSession()) { anime = JMMService.AnidbProcessor.GetAnimeInfoHTTPFromCache(session, animeID, ServerSettings.AutoGroupSeries); } // if not in cache try from AniDB if (anime == null) 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.UpdateStats(true, true, true); 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(); } // lets also try adding to the users trakt collecion by sync'ing the series if (ser != null) { CommandRequest_TraktSyncCollectionSeries cmdTrakt = new CommandRequest_TraktSyncCollectionSeries(ser.AnimeSeriesID, ser.GetAnime().MainTitle); cmdTrakt.Save(); } // sync the series on MAL if (ser != null) { CommandRequest_MALUpdatedWatchedStatus cmdMAL = new CommandRequest_MALUpdatedWatchedStatus(ser.AniDB_ID); cmdMAL.Save(); } }
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 (!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(); List<SortPropOrFieldAndDirection> sortCriteria = new List<SortPropOrFieldAndDirection>(); sortCriteria.Add(new SortPropOrFieldAndDirection("AniDB_EpisodeID", true, SortType.eInteger)); allEps = Sorting.MultiSort<AnimeEpisode>(allEps, sortCriteria); 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().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)) { 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); } 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 (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); } }