public static Video VideoFromVideoLocal(IProvider prov, SVR_VideoLocal v, int userid) { Video l = new Video { AnimeType = AnimeTypes.AnimeFile.ToString(), Id = v.VideoLocalID, Type = "episode", Summary = "Episode Overview Not Available", //TODO Internationalization Title = Path.GetFileNameWithoutExtension(v.FileName), AddedAt = v.DateTimeCreated.ToUnixTime(), UpdatedAt = v.DateTimeUpdated.ToUnixTime(), OriginallyAvailableAt = v.DateTimeCreated.ToPlexDate(), Year = v.DateTimeCreated.Year, Medias = new List <Media>() }; VideoLocal_User vlr = v.GetUserRecord(userid); if (vlr?.WatchedDate != null) { l.LastViewedAt = vlr.WatchedDate.Value.ToUnixTime(); } if (vlr?.ResumePosition > 0) { l.ViewOffset = vlr.ResumePosition; } if (v.Media != null) { Media m = new Media(v.VideoLocalID, v.Media); l.Medias.Add(m); l.Duration = m.Duration; } AddLinksToAnimeEpisodeVideo(prov, l, userid); return(l); }
private void SaveWatchedStatus(bool watched, int userID, DateTime?watchedDate, bool updateWatchedDate) { VideoLocal_User vidUserRecord = GetUserRecord(userID); if (watched) { if (vidUserRecord == null) { vidUserRecord = new VideoLocal_User(); } vidUserRecord.WatchedDate = DateTime.Now; vidUserRecord.JMMUserID = userID; vidUserRecord.VideoLocalID = VideoLocalID; if (watchedDate.HasValue) { if (updateWatchedDate) { vidUserRecord.WatchedDate = watchedDate.Value; } } RepoFactory.VideoLocalUser.Save(vidUserRecord); } else { if (vidUserRecord != null) { vidUserRecord.WatchedDate = null; RepoFactory.VideoLocalUser.Save(vidUserRecord); } } }
public void Save(VideoLocal_User obj) { using (var session = JMMService.SessionFactory.OpenSession()) { // populate the database using (var transaction = session.BeginTransaction()) { session.SaveOrUpdate(obj); transaction.Commit(); } } }
public VideoLocal_User GetByUserIDAndVideoLocalID(int userid, int vidid) { using (var session = JMMService.SessionFactory.OpenSession()) { VideoLocal_User obj = session .CreateCriteria(typeof(VideoLocal_User)) .Add(Restrictions.Eq("JMMUserID", userid)) .Add(Restrictions.Eq("VideoLocalID", vidid)) .UniqueResult <VideoLocal_User>(); return(obj); } }
public static Video VideoFromVideoLocal(IProvider prov, SVR_VideoLocal v, int userid) { Video l = new Video { AnimeType = AnimeTypes.AnimeFile.ToString(), Id = v.VideoLocalID, Type = "episode", Summary = "Episode Overview Not Available", //TODO Intenationalization Title = Path.GetFileNameWithoutExtension(v.Info), AddedAt = v.DateTimeCreated.ToUnixTime(), UpdatedAt = v.DateTimeUpdated.ToUnixTime(), OriginallyAvailableAt = v.DateTimeCreated.ToPlexDate(), Year = v.DateTimeCreated.Year, Medias = new List <Media>() }; VideoLocal_User vlr = v.GetUserRecord(userid); if (vlr?.WatchedDate != null) { l.LastViewedAt = vlr.WatchedDate.Value.ToUnixTime(); } if (vlr?.ResumePosition > 0) { l.ViewOffset = vlr.ResumePosition; } Media m = v.Media; if (m?.Duration != 0) { SVR_VideoLocal_Place pl = v.GetBestVideoLocalPlace(); if (pl != null) { using (var upd = Repo.Instance.VideoLocal.BeginAddOrUpdate(v)) { if (pl.RefreshMediaInfo(upd.Entity)) { upd.Commit(true); } } } m = v.Media; } if (m != null) { l.Medias.Add(m); l.Duration = m.Duration; } AddLinksToAnimeEpisodeVideo(prov, l, userid); return(l); }
public static Video VideoFromVideoLocal(IProvider prov, SVR_VideoLocal v, int userid) { Video l = new Video(); l.AnimeType = AnimeTypes.AnimeFile.ToString(); l.Id = v.VideoLocalID.ToString(); l.Type = "episode"; l.Summary = "Episode Overview Not Available"; //TODO Intenationalization l.Title = Path.GetFileNameWithoutExtension(v.FileName); l.AddedAt = v.DateTimeCreated.ToUnixTime(); l.UpdatedAt = v.DateTimeUpdated.ToUnixTime(); l.OriginallyAvailableAt = v.DateTimeCreated.ToPlexDate(); l.Year = v.DateTimeCreated.Year.ToString(); l.Medias = new List <Media>(); VideoLocal_User vlr = v.GetUserRecord(userid); if (vlr != null) { if (vlr.WatchedDate.HasValue) { l.LastViewedAt = vlr.WatchedDate.Value.ToUnixTime(); } if (vlr.ResumePosition > 0) { l.ViewOffset = vlr.ResumePosition.ToString(); } } Media m = v.Media; if (string.IsNullOrEmpty(m?.Duration)) { SVR_VideoLocal_Place pl = v.GetBestVideoLocalPlace(); if (pl != null) { if (pl.RefreshMediaInfo()) { RepoFactory.VideoLocal.Save(v, true); } } m = v.Media; } if (m != null) { l.Medias.Add(m); l.Duration = m.Duration; } AddLinksToAnimeEpisodeVideo(prov, l, userid); return(l); }
public static VideoLocal_User GetVideoLocalUserRecord(this CrossRef_File_Episode cross, int userID) { SVR_VideoLocal vid = RepoFactory.VideoLocal.GetByHash(cross.Hash); if (vid != null) { VideoLocal_User vidUser = vid.GetUserRecord(userID); if (vidUser != null) { return(vidUser); } } return(null); }
public void Delete(int id) { using (var session = JMMService.SessionFactory.OpenSession()) { // populate the database using (var transaction = session.BeginTransaction()) { VideoLocal_User cr = GetByID(id); if (cr != null) { session.Delete(cr); transaction.Commit(); } } } }
public void SetResumePosition(long resumeposition, int userID) { VideoLocal_User vuser = GetUserRecord(userID); if (vuser == null) { vuser = new VideoLocal_User(); vuser.JMMUserID = userID; vuser.VideoLocalID = VideoLocalID; vuser.ResumePosition = resumeposition; } else { vuser.ResumePosition = resumeposition; } RepoFactory.VideoLocalUser.Save(vuser); }
public static void AddResumePosition(this Video v, IProvider prov, int userid) { switch ( (Shoko.Models.PlexAndKodi.AnimeTypes) Enum.Parse(typeof(Shoko.Models.PlexAndKodi.AnimeTypes), v.AnimeType, true)) { case Shoko.Models.PlexAndKodi.AnimeTypes.AnimeEpisode: if (v.Medias != null) { VideoLocal_User vl = v.Medias.Select(a => RepoFactory.VideoLocal.GetByID(int.Parse(a.Id))) .Where(a => a != null) .Select(a => a.GetUserRecord(userid)) .Where(a => a != null) .OrderByDescending(a => a.ResumePosition) .FirstOrDefault(); if (vl != null && vl.ResumePosition > 0) { v.ViewOffset = vl.ResumePosition.ToString(); if (vl.WatchedDate.HasValue) { v.LastViewedAt = vl.WatchedDate.Value.ToUnixTime(); } } } break; case Shoko.Models.PlexAndKodi.AnimeTypes.AnimeFile: int vid = int.Parse(v.Id); //This suxx, but adding regeneration at videolocal_user is worst. VideoLocal_User vl2 = RepoFactory.VideoLocal.GetByID(vid)?.GetUserRecord(userid); if (vl2 != null && vl2.ResumePosition > 0) { v.ViewOffset = vl2.ResumePosition.ToString(); if (vl2.WatchedDate.HasValue) { v.LastViewedAt = vl2.WatchedDate.Value.ToUnixTime(); } } break; } }
public static void AddResumePosition(this Video v, IProvider prov, int userid) { switch ( (AnimeTypes) Enum.Parse(typeof(AnimeTypes), v.AnimeType, true)) { case AnimeTypes.AnimeEpisode: if (v.Medias != null) { VideoLocal_User vl = v.Medias.Select(a => RepoFactory.VideoLocal.GetByID(a.Id)) .Where(a => a != null) .Select(a => a.GetUserRecord(userid)) .Where(a => a != null) .OrderByDescending(a => a.ResumePosition) .FirstOrDefault(); if (vl != null && vl.ResumePosition > 0) { v.ViewOffset = vl.ResumePosition; if (vl.WatchedDate.HasValue) { v.LastViewedAt = vl.WatchedDate.Value.ToUnixTime(); } } } break; case AnimeTypes.AnimeFile: VideoLocal_User vl2 = RepoFactory.VideoLocal.GetByID(v.Id)?.GetUserRecord(userid); if (vl2 != null && vl2.ResumePosition > 0) { v.ViewOffset = vl2.ResumePosition; if (vl2.WatchedDate.HasValue) { v.LastViewedAt = vl2.WatchedDate.Value.ToUnixTime(); } } break; } }
public CL_VideoLocal ToClient(int userID) { CL_VideoLocal cl = new CL_VideoLocal { CRC32 = CRC32, DateTimeUpdated = DateTimeUpdated, FileName = FileName, FileSize = FileSize, Hash = Hash, HashSource = HashSource, IsIgnored = IsIgnored, IsVariation = IsVariation, Duration = Duration, MD5 = MD5, SHA1 = SHA1, VideoLocalID = VideoLocalID, Places = Places.Select(a => a.ToClient()).ToList() }; VideoLocal_User userRecord = GetUserRecord(userID); if (userRecord?.WatchedDate == null) { cl.IsWatched = 0; cl.WatchedDate = null; } else { cl.IsWatched = 1; cl.WatchedDate = userRecord.WatchedDate; } if (userRecord != null) { cl.ResumePosition = userRecord.ResumePosition; } cl.Media = GetMediaFromUser(userID); return(cl); }
public CL_VideoLocal ToClient(int userID) { CL_VideoLocal cl = new CL_VideoLocal(); cl.CRC32 = this.CRC32; cl.DateTimeUpdated = this.DateTimeUpdated; cl.FileName = this.FileName; cl.FileSize = this.FileSize; cl.Hash = this.Hash; cl.HashSource = this.HashSource; cl.IsIgnored = this.IsIgnored; cl.IsVariation = this.IsVariation; cl.Duration = this.Duration; cl.MD5 = this.MD5; cl.SHA1 = this.SHA1; cl.VideoLocalID = this.VideoLocalID; cl.Places = Places.Select(a => a.ToClient()).ToList(); VideoLocal_User userRecord = this.GetUserRecord(userID); if (userRecord?.WatchedDate == null) { cl.IsWatched = 0; cl.WatchedDate = null; } else { cl.IsWatched = 1; cl.WatchedDate = userRecord.WatchedDate; } if (userRecord != null) { cl.ResumePosition = userRecord.ResumePosition; } cl.Media = GetMediaFromUser(userID); return(cl); }
public CL_VideoLocal_ManualLink ToContractManualLink(int userID) { CL_VideoLocal_ManualLink cl = new CL_VideoLocal_ManualLink(); cl.CRC32 = this.CRC32; cl.DateTimeUpdated = this.DateTimeUpdated; cl.FileName = this.FileName; cl.FileSize = this.FileSize; cl.Hash = this.Hash; cl.HashSource = this.HashSource; cl.IsIgnored = this.IsIgnored; cl.IsVariation = this.IsVariation; cl.MD5 = this.MD5; cl.SHA1 = this.SHA1; cl.VideoLocalID = this.VideoLocalID; cl.Places = Places.Select(a => a.ToClient()).ToList(); VideoLocal_User userRecord = this.GetUserRecord(userID); if (userRecord?.WatchedDate == null) { cl.IsWatched = 0; cl.WatchedDate = null; cl.ResumePosition = 0; } else { cl.IsWatched = userRecord.WatchedDate.HasValue ? 1 : 0; cl.WatchedDate = userRecord.WatchedDate; } if (userRecord != null) { cl.ResumePosition = userRecord.ResumePosition; } return(cl); }
public CL_VideoLocal_ManualLink ToContractManualLink(int userID) { CL_VideoLocal_ManualLink cl = new CL_VideoLocal_ManualLink { CRC32 = CRC32, DateTimeUpdated = DateTimeUpdated, FileName = FileName, FileSize = FileSize, Hash = Hash, HashSource = HashSource, IsIgnored = IsIgnored, IsVariation = IsVariation, MD5 = MD5, SHA1 = SHA1, VideoLocalID = VideoLocalID, Places = Places.Select(a => a.ToClient()).ToList() }; VideoLocal_User userRecord = GetUserRecord(userID); if (userRecord?.WatchedDate == null) { cl.IsWatched = 0; cl.WatchedDate = null; cl.ResumePosition = 0; } else { cl.IsWatched = userRecord.WatchedDate.HasValue ? 1 : 0; cl.WatchedDate = userRecord.WatchedDate; } if (userRecord != null) { cl.ResumePosition = userRecord.ResumePosition; } return(cl); }
public void ToggleWatchedStatus(bool watched, bool updateOnline, DateTime?watchedDate, bool updateStats, bool updateStatsCache, int userID, bool syncTrakt, bool updateWatchedDate) { SVR_JMMUser user = RepoFactory.JMMUser.GetByID(userID); if (user == null) { return; } List <SVR_JMMUser> aniDBUsers = RepoFactory.JMMUser.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 (SVR_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) { SVR_AniDB_File aniFile = RepoFactory.AniDB_File.GetByHash(Hash); if (aniFile != null) { aniFile.IsWatched = mywatched; if (watched) { if (watchedDate.HasValue) { aniFile.WatchedDate = watchedDate; } else { aniFile.WatchedDate = DateTime.Now; } } else { aniFile.WatchedDate = null; } RepoFactory.AniDB_File.Save(aniFile, false); } if (updateOnline) { if ((watched && ServerSettings.AniDB_MyList_SetWatched) || (!watched && ServerSettings.AniDB_MyList_SetUnwatched)) { CommandRequest_UpdateMyListFileStatus cmd = new CommandRequest_UpdateMyListFileStatus( Hash, watched, false, watchedDate.HasValue ? AniDB.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, SVR_AnimeSeries ser = null; // get all files associated with this episode List <CrossRef_File_Episode> xrefs = RepoFactory.CrossRef_File_Episode.GetByHash(Hash); Dictionary <int, SVR_AnimeSeries> toUpdateSeries = new Dictionary <int, SVR_AnimeSeries>(); 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 episodes for this file, may be more than one (One Piece x Toriko) SVR_AnimeEpisode ep = RepoFactory.AnimeEpisode.GetByAniDBEpisodeID(xref.EpisodeID); // 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 && vidUser.WatchedDate.HasValue) { // if not null means it is watched epPercentWatched += filexref.Percentage; } if (epPercentWatched > 95) { break; } } if (epPercentWatched > 95) { ser = ep.GetAnimeSeries(); if (!toUpdateSeries.ContainsKey(ser.AnimeSeriesID)) { toUpdateSeries.Add(ser.AnimeSeriesID, ser); } 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 (SVR_JMMUser juser in aniDBUsers) { if (juser.IsAniDBUser == 1) { ep.SaveWatchedStatus(true, juser.JMMUserID, watchedDate, updateWatchedDate); } } } if (syncTrakt && ServerSettings.Trakt_IsEnabled && !string.IsNullOrEmpty(ServerSettings.Trakt_AuthToken)) { CommandRequest_TraktHistoryEpisode cmdSyncTrakt = new CommandRequest_TraktHistoryEpisode(ep.AnimeEpisodeID, TraktSyncAction.Add); cmdSyncTrakt.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) { // get the episodes for this file, may be more than one (One Piece x Toriko) SVR_AnimeEpisode ep = RepoFactory.AnimeEpisode.GetByAniDBEpisodeID(xrefEp.EpisodeID); ser = ep.GetAnimeSeries(); if (!toUpdateSeries.ContainsKey(ser.AnimeSeriesID)) { toUpdateSeries.Add(ser.AnimeSeriesID, ser); } // 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 && vidUser.WatchedDate.HasValue) { 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 (SVR_JMMUser juser in aniDBUsers) { if (juser.IsAniDBUser == 1) { ep.SaveWatchedStatus(false, juser.JMMUserID, watchedDate, true); } } } if (syncTrakt && ServerSettings.Trakt_IsEnabled && !string.IsNullOrEmpty(ServerSettings.Trakt_AuthToken)) { CommandRequest_TraktHistoryEpisode cmdSyncTrakt = new CommandRequest_TraktHistoryEpisode(ep.AnimeEpisodeID, TraktSyncAction.Remove); cmdSyncTrakt.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 (toUpdateSeries.Count > 0 && updateStats) { foreach (SVR_AnimeSeries s in toUpdateSeries.Values) { // update all the groups above this series in the heirarchy s.UpdateStats(true, true, true); } //ser.TopLevelAnimeGroup.UpdateStatsFromTopLevel(true, true, true); } //if (ser != null && updateStatsCache) //StatsCache.Instance.UpdateUsingSeries(ser.AnimeSeriesID); }
public RawFile(NancyContext ctx, SVR_VideoLocal vl, int level, int uid) { if (vl != null) { id = vl.VideoLocalID; crc32 = vl.CRC32; ed2khash = vl.ED2KHash; md5 = vl.MD5; sha1 = vl.SHA1; created = vl.DateTimeCreated; updated = vl.DateTimeUpdated; duration = vl.Duration; if (vl.ReleaseGroup != null) { group_full = vl.ReleaseGroup.GroupName; group_short = vl.ReleaseGroup.GroupNameShort; group_id = vl.ReleaseGroup.AniDB_ReleaseGroupID; } size = vl.FileSize; hash = vl.Hash; hash_source = vl.HashSource; is_ignored = vl.IsIgnored; VideoLocal_User vl_user = vl.GetUserRecord(uid); if (vl_user != null) { offset = vl_user.ResumePosition; } else { offset = 0; } VideoLocal_Place place = vl.GetBestVideoLocalPlace(); if (place != null) { filename = place.FilePath; videolocal_place_id = place.VideoLocal_Place_ID; import_folder_id = place.ImportFolderID; } if (vl.EpisodeCrossRefs.Count == 0) { recognized = false; } else { recognized = true; } if (vl.Media != null && (level > 1 || level == 0)) { media = new MediaInfo(); url = APIHelper.ConstructVideoLocalStream(ctx, uid, vl.Media.Id, "file." + vl.Media.Container, false); MediaInfo new_media = new MediaInfo(); new_media.AddGeneral(MediaInfo.General.format, vl.Media.Container); new_media.AddGeneral(MediaInfo.General.duration, vl.Media.Duration); new_media.AddGeneral(MediaInfo.General.id, vl.Media.Id); new_media.AddGeneral(MediaInfo.General.overallbitrate, vl.Media.Bitrate); if (vl.Media.Parts != null) { new_media.AddGeneral(MediaInfo.General.size, vl.Media.Parts[0].Size); foreach (Shoko.Models.PlexAndKodi.Stream p in vl.Media.Parts[0].Streams) { switch (p.StreamType) { //video case "1": new_media.AddVideo(p); break; //audio case "2": new_media.AddAudio(p); break; //subtitle case "3": new_media.AddSubtitle(p); break; //menu case "4": Dictionary <string, string> mdict = new Dictionary <string, string>(); //TODO APIv2: menu object could be usefull for external players new_media.AddMenu(mdict); break; } } } media = new_media; } } }
public CL_VideoDetailed ToClientDetailed(int userID) { CL_VideoDetailed cl = new CL_VideoDetailed(); // get the cross ref episode List <CrossRef_File_Episode> xrefs = EpisodeCrossRefs; if (xrefs.Count == 0) { return(null); } cl.Percentage = xrefs[0].Percentage; cl.EpisodeOrder = xrefs[0].EpisodeOrder; cl.CrossRefSource = xrefs[0].CrossRefSource; cl.AnimeEpisodeID = xrefs[0].EpisodeID; cl.VideoLocal_FileName = FileName; cl.VideoLocal_Hash = Hash; cl.VideoLocal_FileSize = FileSize; cl.VideoLocalID = VideoLocalID; cl.VideoLocal_IsIgnored = IsIgnored; cl.VideoLocal_IsVariation = IsVariation; cl.Places = Places.Select(a => a.ToClient()).ToList(); cl.VideoLocal_MD5 = MD5; cl.VideoLocal_SHA1 = SHA1; cl.VideoLocal_CRC32 = CRC32; cl.VideoLocal_HashSource = HashSource; VideoLocal_User userRecord = GetUserRecord(userID); if (userRecord?.WatchedDate == null) { cl.VideoLocal_IsWatched = 0; cl.VideoLocal_WatchedDate = null; cl.VideoLocal_ResumePosition = 0; } else { cl.VideoLocal_IsWatched = userRecord.WatchedDate.HasValue ? 1 : 0; cl.VideoLocal_WatchedDate = userRecord.WatchedDate; } if (userRecord != null) { cl.VideoLocal_ResumePosition = userRecord.ResumePosition; } cl.VideoInfo_AudioBitrate = AudioBitrate; cl.VideoInfo_AudioCodec = AudioCodec; cl.VideoInfo_Duration = Duration; cl.VideoInfo_VideoBitrate = VideoBitrate; cl.VideoInfo_VideoBitDepth = VideoBitDepth; cl.VideoInfo_VideoCodec = VideoCodec; cl.VideoInfo_VideoFrameRate = VideoFrameRate; cl.VideoInfo_VideoResolution = VideoResolution; // AniDB File SVR_AniDB_File anifile = GetAniDBFile(); // to prevent multiple db calls if (anifile != null) { cl.AniDB_Anime_GroupName = anifile.Anime_GroupName; cl.AniDB_Anime_GroupNameShort = anifile.Anime_GroupNameShort; cl.AniDB_AnimeID = anifile.AnimeID; cl.AniDB_CRC = anifile.CRC; cl.AniDB_Episode_Rating = anifile.Episode_Rating; cl.AniDB_Episode_Votes = anifile.Episode_Votes; cl.AniDB_File_AudioCodec = anifile.File_AudioCodec; cl.AniDB_File_Description = anifile.File_Description; cl.AniDB_File_FileExtension = anifile.File_FileExtension; cl.AniDB_File_LengthSeconds = anifile.File_LengthSeconds; cl.AniDB_File_ReleaseDate = anifile.File_ReleaseDate; cl.AniDB_File_Source = anifile.File_Source; cl.AniDB_File_VideoCodec = anifile.File_VideoCodec; cl.AniDB_File_VideoResolution = anifile.File_VideoResolution; cl.AniDB_FileID = anifile.FileID; cl.AniDB_GroupID = anifile.GroupID; cl.AniDB_MD5 = anifile.MD5; cl.AniDB_SHA1 = anifile.SHA1; cl.AniDB_File_FileVersion = anifile.FileVersion; cl.AniDB_File_IsCensored = anifile.IsCensored; cl.AniDB_File_IsChaptered = anifile.IsChaptered; cl.AniDB_File_IsDeprecated = anifile.IsDeprecated; cl.AniDB_File_InternalVersion = anifile.InternalVersion; // languages cl.LanguagesAudio = anifile.LanguagesRAW; cl.LanguagesSubtitle = anifile.SubtitlesRAW; } else { cl.AniDB_Anime_GroupName = string.Empty; cl.AniDB_Anime_GroupNameShort = string.Empty; cl.AniDB_CRC = string.Empty; cl.AniDB_File_AudioCodec = string.Empty; cl.AniDB_File_Description = string.Empty; cl.AniDB_File_FileExtension = string.Empty; cl.AniDB_File_Source = string.Empty; cl.AniDB_File_VideoCodec = string.Empty; cl.AniDB_File_VideoResolution = string.Empty; cl.AniDB_MD5 = string.Empty; cl.AniDB_SHA1 = string.Empty; cl.AniDB_File_FileVersion = 1; // languages cl.LanguagesAudio = string.Empty; cl.LanguagesSubtitle = string.Empty; } AniDB_ReleaseGroup relGroup = ReleaseGroup; // to prevent multiple db calls if (relGroup != null) { cl.ReleaseGroup = relGroup; } else { cl.ReleaseGroup = null; } cl.Media = GetMediaFromUser(userID); return(cl); }
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; } }
public override void ProcessCommand() { logger.Info("Processing CommandRequest_SyncMyList"); try { // we will always assume that an anime was downloaded via http first ScheduledUpdate sched = RepoFactory.ScheduledUpdate.GetByUpdateType((int)ScheduledUpdateType.AniDBMyListSync); if (sched == null) { sched = new ScheduledUpdate { UpdateType = (int)ScheduledUpdateType.AniDBMyListSync, UpdateDetails = string.Empty }; } else { int freqHours = Utils.GetScheduledHours(ServerSettings.Instance.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; } } } // Get the list from AniDB AniDBHTTPCommand_GetMyList cmd = new AniDBHTTPCommand_GetMyList(); cmd.Init(ServerSettings.Instance.AniDb.Username, ServerSettings.Instance.AniDb.Password); AniDBUDPResponseCode ev = cmd.Process(); if (ev != AniDBUDPResponseCode.GotMyListHTTP) { logger.Warn("AniDB did not return a successful code: " + ev); return; } int totalItems = 0; int watchedItems = 0; int modifiedItems = 0; // Add missing files on AniDB var onlineFiles = cmd.MyListItems.ToLookup(a => a.FileID); var dictAniFiles = RepoFactory.AniDB_File.GetAll().ToLookup(a => a.Hash); int missingFiles = 0; foreach (SVR_VideoLocal vid in RepoFactory.VideoLocal.GetAll() .Where(a => !string.IsNullOrEmpty(a.Hash)).ToList()) { // Does it have a linked AniFile if (!dictAniFiles.Contains(vid.Hash)) { continue; } int fileID = dictAniFiles[vid.Hash].FirstOrDefault()?.FileID ?? 0; if (fileID == 0) { continue; } // Is it in MyList if (onlineFiles.Contains(fileID)) { Raw_AniDB_MyListFile file = onlineFiles[fileID].FirstOrDefault(a => a != null); if (file != null) { if (vid.MyListID == 0) { vid.MyListID = file.ListID; RepoFactory.VideoLocal.Save(vid); } // Update file state if deleted if (file.State != (int)ServerSettings.Instance.AniDb.MyList_StorageState) { int seconds = Commons.Utils.AniDB.GetAniDBDateAsSeconds(file.WatchedDate); CommandRequest_UpdateMyListFileStatus cmdUpdateFile = new CommandRequest_UpdateMyListFileStatus(vid.Hash, file.WatchedDate.HasValue, false, seconds); cmdUpdateFile.Save(); } continue; } } // means we have found a file in our local collection, which is not recorded online if (ServerSettings.Instance.AniDb.MyList_AddFiles) { CommandRequest_AddFileToMyList cmdAddFile = new CommandRequest_AddFileToMyList(vid.Hash); cmdAddFile.Save(); } missingFiles++; } logger.Info($"MYLIST Missing Files: {missingFiles} Added to queue for inclusion"); List <SVR_JMMUser> aniDBUsers = RepoFactory.JMMUser.GetAniDBUsers(); LinkedHashSet <SVR_AnimeSeries> modifiedSeries = new LinkedHashSet <SVR_AnimeSeries>(); // Remove Missing Files and update watched states (single loop) List <int> filesToRemove = new List <int>(); foreach (Raw_AniDB_MyListFile myitem in cmd.MyListItems) { try { totalItems++; if (myitem.IsWatched) { watchedItems++; } string hash = string.Empty; SVR_AniDB_File anifile = RepoFactory.AniDB_File.GetByFileID(myitem.FileID); if (anifile != null) { hash = anifile.Hash; } else { // look for manually linked files List <CrossRef_File_Episode> xrefs = RepoFactory.CrossRef_File_Episode.GetByEpisodeID(myitem.EpisodeID); foreach (CrossRef_File_Episode xref in xrefs) { if (xref.CrossRefSource == (int)CrossRefSource.AniDB) { continue; } hash = xref.Hash; break; } } // We couldn't evem find a hash, so remove it if (string.IsNullOrEmpty(hash)) { filesToRemove.Add(myitem.ListID); continue; } // If there's no video local, we don't have it SVR_VideoLocal vl = RepoFactory.VideoLocal.GetByHash(hash); if (vl == null) { filesToRemove.Add(myitem.ListID); continue; } foreach (SVR_JMMUser juser in aniDBUsers) { bool localStatus = false; // doesn't matter which anidb user we use int jmmUserID = juser.JMMUserID; VideoLocal_User userRecord = vl.GetUserRecord(juser.JMMUserID); if (userRecord != null) { localStatus = userRecord.WatchedDate.HasValue; } string action = string.Empty; if (localStatus == myitem.IsWatched) { continue; } // localStatus and AniDB Status are different DateTime?watchedDate = myitem.WatchedDate ?? DateTime.Now; if (localStatus) { // local = watched, anidb = unwatched if (ServerSettings.Instance.AniDb.MyList_ReadUnwatched) { modifiedItems++; vl.ToggleWatchedStatus(false, false, watchedDate, false, jmmUserID, false, true); action = "Used AniDB Status"; } else if (ServerSettings.Instance.AniDb.MyList_SetWatched) { vl.ToggleWatchedStatus(true, true, userRecord.WatchedDate, false, jmmUserID, false, true); } } else { // means local is un-watched, and anidb is watched if (ServerSettings.Instance.AniDb.MyList_ReadWatched) { modifiedItems++; vl.ToggleWatchedStatus(true, false, watchedDate, false, jmmUserID, false, true); action = "Updated Local record to Watched"; } else if (ServerSettings.Instance.AniDb.MyList_SetUnwatched) { vl.ToggleWatchedStatus(false, true, watchedDate, false, jmmUserID, false, true); } } vl.GetAnimeEpisodes().Select(a => a.GetAnimeSeries()).Where(a => a != null) .DistinctBy(a => a.AnimeSeriesID).ForEach(a => modifiedSeries.Add(a)); logger.Info( $"MYLISTDIFF:: File {vl.FileName} - Local Status = {localStatus}, AniDB Status = {myitem.IsWatched} --- {action}"); } } catch (Exception ex) { logger.Error($"A MyList Item threw an error while syncing: {ex}"); } } // Actually remove the files if (filesToRemove.Count > 0) { foreach (int listID in filesToRemove) { CommandRequest_DeleteFileFromMyList deleteCommand = new CommandRequest_DeleteFileFromMyList(listID); deleteCommand.Save(); } logger.Info($"MYLIST Missing Files: {filesToRemove.Count} Added to queue for deletion"); } modifiedSeries.ForEach(a => a.QueueUpdateStats()); logger.Info($"Process MyList: {totalItems} Items, {missingFiles} Added, {filesToRemove.Count} Deleted, {watchedItems} Watched, {modifiedItems} Modified"); sched.LastUpdate = DateTime.Now; RepoFactory.ScheduledUpdate.Save(sched); } catch (Exception ex) { logger.Error(ex, "Error processing CommandRequest_SyncMyList: {0} ", ex); } }