diff --git a/Dependencies/Antlr3.Runtime.dll b/Dependencies/Antlr3.Runtime.dll new file mode 100644 index 000000000..fb3ac4e60 Binary files /dev/null and b/Dependencies/Antlr3.Runtime.dll differ diff --git a/Dependencies/Castle.Core.dll b/Dependencies/Castle.Core.dll new file mode 100644 index 000000000..0207baeae Binary files /dev/null and b/Dependencies/Castle.Core.dll differ diff --git a/Dependencies/FluentNHibernate.dll b/Dependencies/FluentNHibernate.dll new file mode 100644 index 000000000..14509ac73 Binary files /dev/null and b/Dependencies/FluentNHibernate.dll differ diff --git a/Dependencies/FluentNHibernate.pdb b/Dependencies/FluentNHibernate.pdb new file mode 100644 index 000000000..a83cd8002 Binary files /dev/null and b/Dependencies/FluentNHibernate.pdb differ diff --git a/Dependencies/ICSharpCode.SharpZipLib.dll b/Dependencies/ICSharpCode.SharpZipLib.dll new file mode 100644 index 000000000..e829ebf4b Binary files /dev/null and b/Dependencies/ICSharpCode.SharpZipLib.dll differ diff --git a/Dependencies/Iesi.Collections.dll b/Dependencies/Iesi.Collections.dll new file mode 100644 index 000000000..5658af79a Binary files /dev/null and b/Dependencies/Iesi.Collections.dll differ diff --git a/Dependencies/Iesi.Collections.pdb b/Dependencies/Iesi.Collections.pdb new file mode 100644 index 000000000..bff77d8be Binary files /dev/null and b/Dependencies/Iesi.Collections.pdb differ diff --git a/Dependencies/MediaInfo_DLL_0.7.41_Windows_i386_WithoutInstaller.7z b/Dependencies/MediaInfo_DLL_0.7.41_Windows_i386_WithoutInstaller.7z new file mode 100644 index 000000000..5f7e84b53 Binary files /dev/null and b/Dependencies/MediaInfo_DLL_0.7.41_Windows_i386_WithoutInstaller.7z differ diff --git a/Dependencies/MediaInfo_DLL_0.7.41_Windows_x64_WithoutInstaller.7z b/Dependencies/MediaInfo_DLL_0.7.41_Windows_x64_WithoutInstaller.7z new file mode 100644 index 000000000..bdc51e9f5 Binary files /dev/null and b/Dependencies/MediaInfo_DLL_0.7.41_Windows_x64_WithoutInstaller.7z differ diff --git a/Dependencies/NHibernate.ByteCode.Castle.dll b/Dependencies/NHibernate.ByteCode.Castle.dll new file mode 100644 index 000000000..6167e7d12 Binary files /dev/null and b/Dependencies/NHibernate.ByteCode.Castle.dll differ diff --git a/Dependencies/NHibernate.ByteCode.Castle.pdb b/Dependencies/NHibernate.ByteCode.Castle.pdb new file mode 100644 index 000000000..5d6fbca75 Binary files /dev/null and b/Dependencies/NHibernate.ByteCode.Castle.pdb differ diff --git a/Dependencies/NHibernate.dll b/Dependencies/NHibernate.dll new file mode 100644 index 000000000..6edb87868 Binary files /dev/null and b/Dependencies/NHibernate.dll differ diff --git a/Dependencies/NHibernate.pdb b/Dependencies/NHibernate.pdb new file mode 100644 index 000000000..ba153aebe Binary files /dev/null and b/Dependencies/NHibernate.pdb differ diff --git a/Dependencies/NLog.Extended.dll b/Dependencies/NLog.Extended.dll new file mode 100644 index 000000000..762a6a992 Binary files /dev/null and b/Dependencies/NLog.Extended.dll differ diff --git a/Dependencies/NLog.dll b/Dependencies/NLog.dll new file mode 100644 index 000000000..8a27b27f3 Binary files /dev/null and b/Dependencies/NLog.dll differ diff --git a/Dependencies/Remotion.Data.Linq.dll b/Dependencies/Remotion.Data.Linq.dll new file mode 100644 index 000000000..14aeb2ae6 Binary files /dev/null and b/Dependencies/Remotion.Data.Linq.dll differ diff --git a/Dependencies/System.Data.SQLite.dll b/Dependencies/System.Data.SQLite.dll new file mode 100644 index 000000000..080c74cd5 Binary files /dev/null and b/Dependencies/System.Data.SQLite.dll differ diff --git a/Dependencies/hasher.dll b/Dependencies/hasher.dll new file mode 100644 index 000000000..c6b8d00df Binary files /dev/null and b/Dependencies/hasher.dll differ diff --git a/JMMContracts/Contract_AniDBAnime.cs b/JMMContracts/Contract_AniDBAnime.cs new file mode 100644 index 000000000..e125c9eb1 --- /dev/null +++ b/JMMContracts/Contract_AniDBAnime.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace JMMContracts +{ + public class Contract_AniDBAnime + { + public int AnimeID { get; set; } + public int EpisodeCount { get; set; } + public DateTime? AirDate { get; set; } + public DateTime? EndDate { get; set; } + public string URL { get; set; } + public string Picname { get; set; } + public int BeginYear { get; set; } + public int EndYear { get; set; } + public int AnimeType { get; set; } + public string MainTitle { get; set; } + public string FormattedTitle { get; set; } + public string AllTitles { get; set; } + public string AllCategories { get; set; } + public string AllTags { get; set; } + public string Description { get; set; } + public int EpisodeCountNormal { get; set; } + public int EpisodeCountSpecial { get; set; } + public int Rating { get; set; } + public int VoteCount { get; set; } + public int TempRating { get; set; } + public int TempVoteCount { get; set; } + public int AvgReviewRating { get; set; } + public int ReviewCount { get; set; } + public DateTime DateTimeUpdated { get; set; } + public DateTime DateTimeDescUpdated { get; set; } + public int ImageEnabled { get; set; } + public string AwardList { get; set; } + public int Restricted { get; set; } + public int? AnimePlanetID { get; set; } + public int? ANNID { get; set; } + public int? AllCinemaID { get; set; } + public int? AnimeNfo { get; set; } + public int? LatestEpisodeNumber { get; set; } + + public Contract_AniDB_Anime_DefaultImage DefaultImagePoster { get; set; } + public Contract_AniDB_Anime_DefaultImage DefaultImageFanart { get; set; } + public Contract_AniDB_Anime_DefaultImage DefaultImageWideBanner { get; set; } + } +} diff --git a/JMMContracts/Contract_AniDBReleaseGroup.cs b/JMMContracts/Contract_AniDBReleaseGroup.cs new file mode 100644 index 000000000..f20e8e4ee --- /dev/null +++ b/JMMContracts/Contract_AniDBReleaseGroup.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace JMMContracts +{ + public class Contract_AniDBReleaseGroup + { + public int GroupID { get; set; } + public string GroupName { get; set; } + + public Contract_AniDBReleaseGroup() + { + } + } +} diff --git a/JMMContracts/Contract_AniDBVote.cs b/JMMContracts/Contract_AniDBVote.cs new file mode 100644 index 000000000..eec3935c1 --- /dev/null +++ b/JMMContracts/Contract_AniDBVote.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace JMMContracts +{ + public class Contract_AniDBVote + { + public int EntityID { get; set; } + public int VoteType { get; set; } + public decimal VoteValue { get; set; } // out of 10 + + public Contract_AniDBVote() + { + } + } +} diff --git a/JMMContracts/Contract_AniDB_AnimeCrossRefs.cs b/JMMContracts/Contract_AniDB_AnimeCrossRefs.cs new file mode 100644 index 000000000..dde27da33 --- /dev/null +++ b/JMMContracts/Contract_AniDB_AnimeCrossRefs.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace JMMContracts +{ + public class Contract_AniDB_AnimeCrossRefs + { + public int AnimeID { get; set; } + + // TvDB + public Contract_CrossRef_AniDB_TvDB CrossRef_AniDB_TvDB { get; set; } + public Contract_TvDB_Series TvDBSeries { get; set; } + public List TvDBEpisodes { get; set; } + public List TvDBImageFanarts { get; set; } + public List TvDBImagePosters { get; set; } + public List TvDBImageWideBanners { get; set; } + + // Trakt + public Contract_CrossRef_AniDB_Trakt CrossRef_AniDB_Trakt { get; set; } + public Contract_Trakt_Show TraktShow { get; set; } + public Contract_Trakt_ImageFanart TraktImageFanart { get; set; } + public Contract_Trakt_ImagePoster TraktImagePoster { get; set; } + + // MovieDB + public Contract_CrossRef_AniDB_Other CrossRef_AniDB_MovieDB { get; set; } + public Contract_MovieDB_Movie MovieDBMovie { get; set; } + public List MovieDBFanarts { get; set; } + public List MovieDBPosters { get; set; } + + public Contract_AniDB_AnimeCrossRefs() + { + CrossRef_AniDB_TvDB = null; + TvDBSeries = null; + TvDBEpisodes = new List(); + TvDBImageFanarts = new List(); + TvDBImagePosters = new List(); + TvDBImageWideBanners = new List(); + + CrossRef_AniDB_MovieDB = null; + MovieDBMovie = null; + MovieDBFanarts = new List(); + MovieDBPosters = new List(); + } + } +} diff --git a/JMMContracts/Contract_AniDB_AnimeDetailed.cs b/JMMContracts/Contract_AniDB_AnimeDetailed.cs new file mode 100644 index 000000000..6118bd587 --- /dev/null +++ b/JMMContracts/Contract_AniDB_AnimeDetailed.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace JMMContracts +{ + public class Contract_AniDB_AnimeDetailed + { + public Contract_AniDBAnime AniDBAnime { get; set; } + public List AnimeTitles { get; set; } + public List Categories { get; set; } + public List Tags { get; set; } + public Contract_AniDBVote UserVote { get; set; } + + public string Stat_AllVideoQuality { get; set; } + public string Stat_AllVideoQuality_Episodes { get; set; } + public string Stat_AudioLanguages { get; set; } + public string Stat_SubtitleLanguages { get; set; } + + } +} diff --git a/JMMContracts/Contract_AniDB_Anime_DefaultImage.cs b/JMMContracts/Contract_AniDB_Anime_DefaultImage.cs new file mode 100644 index 000000000..8633cdf07 --- /dev/null +++ b/JMMContracts/Contract_AniDB_Anime_DefaultImage.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace JMMContracts +{ + public class Contract_AniDB_Anime_DefaultImage + { + public int AniDB_Anime_DefaultImageID { get; set; } + public int AnimeID { get; set; } + public int ImageParentID { get; set; } + public int ImageParentType { get; set; } + public int ImageType { get; set; } + + public Contract_MovieDB_Poster MoviePoster { get; set; } + public Contract_MovieDB_Fanart MovieFanart { get; set; } + + public Contract_TvDB_ImagePoster TVPoster { get; set; } + public Contract_TvDB_ImageFanart TVFanart { get; set; } + public Contract_TvDB_ImageWideBanner TVWideBanner { get; set; } + + public Contract_Trakt_ImagePoster TraktPoster { get; set; } + public Contract_Trakt_ImageFanart TraktFanart { get; set; } + } +} diff --git a/JMMContracts/Contract_AnimeCategory.cs b/JMMContracts/Contract_AnimeCategory.cs new file mode 100644 index 000000000..b099f951a --- /dev/null +++ b/JMMContracts/Contract_AnimeCategory.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace JMMContracts +{ + public class Contract_AnimeCategory + { + public int CategoryID { get; set; } + public int ParentID { get; set; } + public int IsHentai { get; set; } + public string CategoryName { get; set; } + public string CategoryDescription { get; set; } + public int Weighting { get; set; } + } +} diff --git a/JMMContracts/Contract_AnimeEpisode.cs b/JMMContracts/Contract_AnimeEpisode.cs new file mode 100644 index 000000000..ccf0463d3 --- /dev/null +++ b/JMMContracts/Contract_AnimeEpisode.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace JMMContracts +{ + public class Contract_AnimeEpisode + { + // from AnimeEpisode + public int AnimeEpisodeID { get; set; } + public int EpisodeNumber { get; set; } + public string EpisodeNameRomaji { get; set; } + public string EpisodeNameEnglish { get; set; } + public int EpisodeType { get; set; } + public int AnimeSeriesID { get; set; } + public int AniDB_EpisodeID { get; set; } + public DateTime DateTimeUpdated { get; set; } + public int IsWatched { get; set; } + public DateTime? WatchedDate { get; set; } + public int PlayedCount { get; set; } + public int WatchedCount { get; set; } + public int StoppedCount { get; set; } + public int LocalFileCount { get; set; } + + // from AniDB_Episode + public int AniDB_LengthSeconds { get; set; } + public string AniDB_Rating { get; set; } + public string AniDB_Votes { get; set; } + public string AniDB_RomajiName { get; set; } + public string AniDB_EnglishName { get; set; } + public DateTime? AniDB_AirDate { get; set; } + + public List ReleaseGroups { get; set; } + } +} diff --git a/JMMContracts/Contract_AnimeGroup.cs b/JMMContracts/Contract_AnimeGroup.cs new file mode 100644 index 000000000..e13abac8e --- /dev/null +++ b/JMMContracts/Contract_AnimeGroup.cs @@ -0,0 +1,56 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace JMMContracts +{ + public class Contract_AnimeGroup : IComparable + { + // Data from AnimeGroup + public int AnimeGroupID { get; set; } + public int? AnimeGroupParentID { get; set; } + public string GroupName { get; set; } + public string Description { get; set; } + public int IsFave { get; set; } + public int IsManuallyNamed { get; set; } + public int UnwatchedEpisodeCount { get; set; } + public DateTime DateTimeUpdated { get; set; } + public int WatchedEpisodeCount { get; set; } + public string SortName { get; set; } + public DateTime? WatchedDate { get; set; } + public DateTime? EpisodeAddedDate { get; set; } + public int PlayedCount { get; set; } + public int WatchedCount { get; set; } + public int StoppedCount { get; set; } + public int OverrideDescription { get; set; } + + public int MissingEpisodeCount { get; set; } + public int MissingEpisodeCountGroups { get; set; } + + public DateTime? Stat_AirDate_Min { get; set; } + public DateTime? Stat_AirDate_Max { get; set; } + public DateTime? Stat_EndDate { get; set; } + public DateTime? Stat_SeriesCreatedDate { get; set; } + public decimal? Stat_UserVotePermanent { get; set; } + public decimal? Stat_UserVoteTemporary { get; set; } + public decimal? Stat_UserVoteOverall { get; set; } + public string Stat_AllCategories { get; set; } + public string Stat_AllTitles { get; set; } + public bool Stat_IsComplete { get; set; } + public bool Stat_HasFinishedAiring { get; set; } + public bool Stat_HasTvDBLink { get; set; } + public bool Stat_HasMovieDBLink { get; set; } + public bool Stat_HasMovieDBOrTvDBLink { get; set; } + public string Stat_AllVideoQuality { get; set; } + public string Stat_AllVideoQuality_Episodes { get; set; } + public string Stat_AudioLanguages { get; set; } + public string Stat_SubtitleLanguages { get; set; } + public int Stat_SeriesCount { get; set; } + + public int CompareTo(Contract_AnimeGroup obj) + { + return SortName.CompareTo(obj.SortName); + } + } +} diff --git a/JMMContracts/Contract_AnimeGroupDetailed.cs b/JMMContracts/Contract_AnimeGroupDetailed.cs new file mode 100644 index 000000000..099d85f09 --- /dev/null +++ b/JMMContracts/Contract_AnimeGroupDetailed.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace JMMContracts +{ + public class Contract_AnimeGroupDetailed + { + } +} diff --git a/JMMContracts/Contract_AnimeGroup_Save.cs b/JMMContracts/Contract_AnimeGroup_Save.cs new file mode 100644 index 000000000..e1ff1db40 --- /dev/null +++ b/JMMContracts/Contract_AnimeGroup_Save.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace JMMContracts +{ + public class Contract_AnimeGroup_Save + { + public int? AnimeGroupID { get; set; } // will be NULL for a new group + public int? AnimeGroupParentID { get; set; } + public string GroupName { get; set; } + public string Description { get; set; } + public int IsFave { get; set; } + public int IsManuallyNamed { get; set; } + public string SortName { get; set; } + public int OverrideDescription { get; set; } + } +} diff --git a/JMMContracts/Contract_AnimeGroup_SaveResponse.cs b/JMMContracts/Contract_AnimeGroup_SaveResponse.cs new file mode 100644 index 000000000..a910522de --- /dev/null +++ b/JMMContracts/Contract_AnimeGroup_SaveResponse.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace JMMContracts +{ + public class Contract_AnimeGroup_SaveResponse + { + public string ErrorMessage { get; set; } + public Contract_AnimeGroup AnimeGroup { get; set; } + } +} diff --git a/JMMContracts/Contract_AnimeSeries.cs b/JMMContracts/Contract_AnimeSeries.cs new file mode 100644 index 000000000..5a0fbf672 --- /dev/null +++ b/JMMContracts/Contract_AnimeSeries.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace JMMContracts +{ + public class Contract_AnimeSeries + { + public int AnimeSeriesID { get; set; } + public int AnimeGroupID { get; set; } + public int AniDB_ID { get; set; } + public int UnwatchedEpisodeCount { get; set; } + public DateTime DateTimeUpdated { get; set; } + public DateTime DateTimeCreated { get; set; } + public int WatchedEpisodeCount { get; set; } + public string DefaultAudioLanguage { get; set; } + public string DefaultSubtitleLanguage { get; set; } + public DateTime? WatchedDate { get; set; } + public DateTime? EpisodeAddedDate { get; set; } + public int PlayedCount { get; set; } + public int WatchedCount { get; set; } + public int StoppedCount { get; set; } + public int LatestLocalEpisodeNumber { get; set; } + + public int MissingEpisodeCount { get; set; } + public int MissingEpisodeCountGroups { get; set; } + + public Contract_AniDBAnime AniDBAnime { get; set; } + public Contract_CrossRef_AniDB_TvDB CrossRefAniDBTvDB { get; set; } + public Contract_CrossRef_AniDB_Other CrossRefAniDBMovieDB { get; set; } + } +} diff --git a/JMMContracts/Contract_AnimeSeries_Save.cs b/JMMContracts/Contract_AnimeSeries_Save.cs new file mode 100644 index 000000000..5948fc8f3 --- /dev/null +++ b/JMMContracts/Contract_AnimeSeries_Save.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace JMMContracts +{ + public class Contract_AnimeSeries_Save + { + public int? AnimeSeriesID { get; set; } + public int AnimeGroupID { get; set; } + public int AniDB_ID { get; set; } + public string DefaultAudioLanguage { get; set; } + public string DefaultSubtitleLanguage { get; set; } + } +} diff --git a/JMMContracts/Contract_AnimeSeries_SaveResponse.cs b/JMMContracts/Contract_AnimeSeries_SaveResponse.cs new file mode 100644 index 000000000..d12a482fc --- /dev/null +++ b/JMMContracts/Contract_AnimeSeries_SaveResponse.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace JMMContracts +{ + public class Contract_AnimeSeries_SaveResponse + { + public string ErrorMessage { get; set; } + public Contract_AnimeSeries AnimeSeries { get; set; } + } +} diff --git a/JMMContracts/Contract_AnimeTag.cs b/JMMContracts/Contract_AnimeTag.cs new file mode 100644 index 000000000..b3069925a --- /dev/null +++ b/JMMContracts/Contract_AnimeTag.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace JMMContracts +{ + public class Contract_AnimeTag + { + public int TagID { get; set; } + public int Spoiler { get; set; } + public int LocalSpoiler { get; set; } + public int GlobalSpoiler { get; set; } + public string TagName { get; set; } + public int TagCount { get; set; } + public string TagDescription { get; set; } + public int Approval { get; set; } + } +} diff --git a/JMMContracts/Contract_AnimeTitle.cs b/JMMContracts/Contract_AnimeTitle.cs new file mode 100644 index 000000000..c02cfc598 --- /dev/null +++ b/JMMContracts/Contract_AnimeTitle.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace JMMContracts +{ + public class Contract_AnimeTitle + { + public int AnimeID { get; set; } + public string TitleType { get; set; } + public string Language { get; set; } + public string Title { get; set; } + } +} diff --git a/JMMContracts/Contract_CrossRef_AniDB_Other.cs b/JMMContracts/Contract_CrossRef_AniDB_Other.cs new file mode 100644 index 000000000..ce248c600 --- /dev/null +++ b/JMMContracts/Contract_CrossRef_AniDB_Other.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace JMMContracts +{ + public class Contract_CrossRef_AniDB_Other + { + public int CrossRef_AniDB_OtherID { get; set; } + public int AnimeID { get; set; } + public string CrossRefID { get; set; } + public int CrossRefSource { get; set; } + public int CrossRefType { get; set; } + } +} diff --git a/JMMContracts/Contract_CrossRef_AniDB_OtherResult.cs b/JMMContracts/Contract_CrossRef_AniDB_OtherResult.cs new file mode 100644 index 000000000..ca29b89bc --- /dev/null +++ b/JMMContracts/Contract_CrossRef_AniDB_OtherResult.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace JMMContracts +{ + public class Contract_CrossRef_AniDB_OtherResult + { + public int AnimeID { get; set; } + public string CrossRefID { get; set; } + } +} diff --git a/JMMContracts/Contract_CrossRef_AniDB_Trakt.cs b/JMMContracts/Contract_CrossRef_AniDB_Trakt.cs new file mode 100644 index 000000000..1e89f229b --- /dev/null +++ b/JMMContracts/Contract_CrossRef_AniDB_Trakt.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace JMMContracts +{ + public class Contract_CrossRef_AniDB_Trakt + { + public int CrossRef_AniDB_TraktID { get; set; } + public int AnimeID { get; set; } + public string TraktID { get; set; } + public int TraktSeasonNumber { get; set; } + public int CrossRefSource { get; set; } + } +} diff --git a/JMMContracts/Contract_CrossRef_AniDB_TraktResult.cs b/JMMContracts/Contract_CrossRef_AniDB_TraktResult.cs new file mode 100644 index 000000000..e22d439b6 --- /dev/null +++ b/JMMContracts/Contract_CrossRef_AniDB_TraktResult.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace JMMContracts +{ + public class Contract_CrossRef_AniDB_TraktResult + { + public int AnimeID { get; set; } + public string TraktID { get; set; } + public int TraktSeasonNumber { get; set; } + public int AdminApproved { get; set; } + public string ShowName { get; set; } + } +} diff --git a/JMMContracts/Contract_CrossRef_AniDB_TvDB.cs b/JMMContracts/Contract_CrossRef_AniDB_TvDB.cs new file mode 100644 index 000000000..d7e6ff539 --- /dev/null +++ b/JMMContracts/Contract_CrossRef_AniDB_TvDB.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace JMMContracts +{ + public class Contract_CrossRef_AniDB_TvDB + { + public int CrossRef_AniDB_TvDBID { get; set; } + public int AnimeID { get; set; } + public int TvDBID { get; set; } + public int TvDBSeasonNumber { get; set; } + public int CrossRefSource { get; set; } + } +} diff --git a/JMMContracts/Contract_CrossRef_AniDB_TvDBResult.cs b/JMMContracts/Contract_CrossRef_AniDB_TvDBResult.cs new file mode 100644 index 000000000..50758a7f2 --- /dev/null +++ b/JMMContracts/Contract_CrossRef_AniDB_TvDBResult.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace JMMContracts +{ + public class Contract_CrossRef_AniDB_TvDBResult + { + public int AnimeID { get; set; } + public int TvDBID { get; set; } + public int TvDBSeasonNumber { get; set; } + public int AdminApproved { get; set; } + public string SeriesName { get; set; } + } +} diff --git a/JMMContracts/Contract_DuplicateFile.cs b/JMMContracts/Contract_DuplicateFile.cs new file mode 100644 index 000000000..474d9ea90 --- /dev/null +++ b/JMMContracts/Contract_DuplicateFile.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace JMMContracts +{ + public class Contract_DuplicateFile + { + public int DuplicateFileID { get; set; } + public string FilePathFile1 { get; set; } + public string FilePathFile2 { get; set; } + public string Hash { get; set; } + public int ImportFolderIDFile1 { get; set; } + public int ImportFolderIDFile2 { get; set; } + public DateTime DateTimeUpdated { get; set; } + + // data from other entities + public int? AnimeID { get; set; } + public string AnimeName { get; set; } + public int? EpisodeType { get; set; } + public int? EpisodeNumber { get; set; } + public string EpisodeName { get; set; } + + public Contract_ImportFolder ImportFolder1 { get; set; } + public Contract_ImportFolder ImportFolder2 { get; set; } + } +} diff --git a/JMMContracts/Contract_GroupFilter.cs b/JMMContracts/Contract_GroupFilter.cs new file mode 100644 index 000000000..afa1b4cd9 --- /dev/null +++ b/JMMContracts/Contract_GroupFilter.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace JMMContracts +{ + public class Contract_GroupFilter + { + public int? GroupFilterID { get; set; } + public string GroupFilterName { get; set; } + public int ApplyToSeries { get; set; } + public int BaseCondition { get; set; } + public string SortingCriteria { get; set; } + + public List FilterConditions { get; set; } + } +} diff --git a/JMMContracts/Contract_GroupFilterCondition.cs b/JMMContracts/Contract_GroupFilterCondition.cs new file mode 100644 index 000000000..75328b757 --- /dev/null +++ b/JMMContracts/Contract_GroupFilterCondition.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace JMMContracts +{ + public class Contract_GroupFilterCondition + { + public int? GroupFilterConditionID { get; set; } + public int? GroupFilterID { get; set; } + public int ConditionType { get; set; } + public int ConditionOperator { get; set; } + public string ConditionParameter { get; set; } + } +} diff --git a/JMMContracts/Contract_GroupFilterExtended.cs b/JMMContracts/Contract_GroupFilterExtended.cs new file mode 100644 index 000000000..9c9522199 --- /dev/null +++ b/JMMContracts/Contract_GroupFilterExtended.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace JMMContracts +{ + public class Contract_GroupFilterExtended + { + public Contract_GroupFilter GroupFilter { get; set; } + + public int SeriesCount { get; set; } + public int GroupCount { get; set; } + } +} diff --git a/JMMContracts/Contract_GroupFilter_SaveResponse.cs b/JMMContracts/Contract_GroupFilter_SaveResponse.cs new file mode 100644 index 000000000..9b53466f7 --- /dev/null +++ b/JMMContracts/Contract_GroupFilter_SaveResponse.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace JMMContracts +{ + public class Contract_GroupFilter_SaveResponse + { + public string ErrorMessage { get; set; } + public Contract_GroupFilter GroupFilter { get; set; } + } +} diff --git a/JMMContracts/Contract_GroupVideoQuality.cs b/JMMContracts/Contract_GroupVideoQuality.cs new file mode 100644 index 000000000..a68fde072 --- /dev/null +++ b/JMMContracts/Contract_GroupVideoQuality.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace JMMContracts +{ + public class Contract_GroupVideoQuality : IComparable + { + public string GroupName { get; set; } + public string GroupNameShort { get; set; } + public int Ranking { get; set; } + public string Resolution { get; set; } + public string VideoSource { get; set; } + public int FileCountNormal { get; set; } + public bool NormalComplete { get; set; } + public int FileCountSpecials { get; set; } + public bool SpecialsComplete { get; set; } + + public int CompareTo(Contract_GroupVideoQuality obj) + { + return Ranking.CompareTo(obj.Ranking) * -1; + } + + public override string ToString() + { + return string.Format("{0} - {1}/{2}", GroupNameShort, Resolution, VideoSource); + } + } +} diff --git a/JMMContracts/Contract_ImportFolder.cs b/JMMContracts/Contract_ImportFolder.cs new file mode 100644 index 000000000..c35d4d462 --- /dev/null +++ b/JMMContracts/Contract_ImportFolder.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace JMMContracts +{ + public class Contract_ImportFolder + { + public int? ImportFolderID { get; set; } + public int ImportFolderType { get; set; } + public string ImportFolderName { get; set; } + public string ImportFolderLocation { get; set; } + public int IsDropSource { get; set; } + public int IsDropDestination { get; set; } + } +} diff --git a/JMMContracts/Contract_ImportFolder_SaveResponse.cs b/JMMContracts/Contract_ImportFolder_SaveResponse.cs new file mode 100644 index 000000000..955f706ea --- /dev/null +++ b/JMMContracts/Contract_ImportFolder_SaveResponse.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace JMMContracts +{ + public class Contract_ImportFolder_SaveResponse + { + public string ErrorMessage { get; set; } + public Contract_ImportFolder ImportFolder { get; set; } + } +} diff --git a/JMMContracts/Contract_JMMUser.cs b/JMMContracts/Contract_JMMUser.cs new file mode 100644 index 000000000..6ea4d8590 --- /dev/null +++ b/JMMContracts/Contract_JMMUser.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace JMMContracts +{ + public class Contract_JMMUser + { + public int? JMMUserID { get; set; } + public string Username { get; set; } + public string Password { get; set; } + public int IsAdmin { get; set; } + public int IsAniDBUser { get; set; } + public int IsTraktUser { get; set; } + public string HideCategories { get; set; } + } +} diff --git a/JMMContracts/Contract_MovieDBMovieSearchResult.cs b/JMMContracts/Contract_MovieDBMovieSearchResult.cs new file mode 100644 index 000000000..bc69d725b --- /dev/null +++ b/JMMContracts/Contract_MovieDBMovieSearchResult.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace JMMContracts +{ + public class Contract_MovieDBMovieSearchResult + { + public int MovieID { get; set; } + public string MovieName { get; set; } + public string OriginalName { get; set; } + public string Overview { get; set; } + } +} diff --git a/JMMContracts/Contract_MovieDB_Fanart.cs b/JMMContracts/Contract_MovieDB_Fanart.cs new file mode 100644 index 000000000..f8b02856b --- /dev/null +++ b/JMMContracts/Contract_MovieDB_Fanart.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace JMMContracts +{ + public class Contract_MovieDB_Fanart + { + public int MovieDB_FanartID { get; set; } + public string ImageID { get; set; } + public int MovieId { get; set; } + public string ImageType { get; set; } + public string ImageSize { get; set; } + public string URL { get; set; } + public int ImageWidth { get; set; } + public int ImageHeight { get; set; } + public int Enabled { get; set; } + } +} diff --git a/JMMContracts/Contract_MovieDB_Movie.cs b/JMMContracts/Contract_MovieDB_Movie.cs new file mode 100644 index 000000000..39f76b132 --- /dev/null +++ b/JMMContracts/Contract_MovieDB_Movie.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace JMMContracts +{ + public class Contract_MovieDB_Movie + { + public int MovieDB_MovieID { get; set; } + public int MovieId { get; set; } + public string MovieName { get; set; } + public string OriginalName { get; set; } + public string Overview { get; set; } + } +} diff --git a/JMMContracts/Contract_MovieDB_Poster.cs b/JMMContracts/Contract_MovieDB_Poster.cs new file mode 100644 index 000000000..c326fd4c0 --- /dev/null +++ b/JMMContracts/Contract_MovieDB_Poster.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace JMMContracts +{ + public class Contract_MovieDB_Poster + { + public int MovieDB_PosterID { get; set; } + public string ImageID { get; set; } + public int MovieId { get; set; } + public string ImageType { get; set; } + public string ImageSize { get; set; } + public string URL { get; set; } + public int ImageWidth { get; set; } + public int ImageHeight { get; set; } + public int Enabled { get; set; } + } +} diff --git a/JMMContracts/Contract_ReleaseGroup.cs b/JMMContracts/Contract_ReleaseGroup.cs new file mode 100644 index 000000000..bbbe2550f --- /dev/null +++ b/JMMContracts/Contract_ReleaseGroup.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace JMMContracts +{ + public class Contract_ReleaseGroup + { + public int GroupID { get; set; } + public int Rating { get; set; } + public int Votes { get; set; } + public int AnimeCount { get; set; } + public int FileCount { get; set; } + public string GroupName { get; set; } + public string GroupNameShort { get; set; } + public string IRCChannel { get; set; } + public string IRCServer { get; set; } + public string URL { get; set; } + public string Picname { get; set; } + } +} diff --git a/JMMContracts/Contract_ServerSettings.cs b/JMMContracts/Contract_ServerSettings.cs new file mode 100644 index 000000000..272214dd7 --- /dev/null +++ b/JMMContracts/Contract_ServerSettings.cs @@ -0,0 +1,76 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace JMMContracts +{ + public class Contract_ServerSettings + { + public string AniDB_Username { get; set; } + public string AniDB_Password { get; set; } + public string AniDB_ServerAddress { get; set; } + public string AniDB_ServerPort { get; set; } + public string AniDB_ClientPort { get; set; } + + public bool AniDB_DownloadRelatedAnime { get; set; } + public bool AniDB_DownloadSimilarAnime { get; set; } + public bool AniDB_DownloadCharactersCreators { get; set; } + public bool AniDB_DownloadReviews { get; set; } + public bool AniDB_DownloadReleaseGroups { get; set; } + + public bool AniDB_MyList_AddFiles { get; set; } + public int AniDB_MyList_StorageState { get; set; } + // these two are used when you add a file on an import, or when you do a mylist sync + public bool AniDB_MyList_ReadWatched { get; set; } // update local to watched if anidb is watched + public bool AniDB_MyList_ReadUnwatched { get; set; } // update local to un-watched if anidb is un-watched + // these two are used when you watch a video, or manually mark a file as watched/unwatched + public bool AniDB_MyList_SetWatched { get; set; } // set anidb watched if local state is watched + public bool AniDB_MyList_SetUnwatched { get; set; } // set anidb un-watched if local state is un-watched + + public int AniDB_MyList_UpdateFrequency { get; set; } + public int AniDB_Calendar_UpdateFrequency { get; set; } + public int AniDB_Anime_UpdateFrequency { get; set; } + + // Web Cache + public string WebCache_Address { get; set; } + public bool WebCache_Anonymous { get; set; } + public bool WebCache_FileHashes_Get { get; set; } + public bool WebCache_FileHashes_Send { get; set; } + public bool WebCache_XRefFileEpisode_Get { get; set; } + public bool WebCache_XRefFileEpisode_Send { get; set; } + public bool WebCache_TvDB_Get { get; set; } + public bool WebCache_TvDB_Send { get; set; } + + // TvDB + public bool TvDB_AutoFanart { get; set; } + public int TvDB_AutoFanartAmount { get; set; } + public bool TvDB_AutoWideBanners { get; set; } + public bool TvDB_AutoPosters { get; set; } + public int TvDB_UpdateFrequency { get; set; } + + // MovieDB + public bool MovieDB_AutoFanart { get; set; } + public int MovieDB_AutoFanartAmount { get; set; } + public bool MovieDB_AutoPosters { get; set; } + + // Import settings + public string VideoExtensions { get; set; } + public bool WatchForNewFiles { get; set; } + public bool RunImportOnStart { get; set; } + public bool Hash_CRC32 { get; set; } + public bool Hash_MD5 { get; set; } + public bool Hash_SHA1 { get; set; } + public bool Import_UseExistingFileWatchedStatus { get; set; } + + // Language + public string LanguagePreference { get; set; } + public bool LanguageUseSynonyms { get; set; } + + // Trakt + public string Trakt_Username { get; set; } + public string Trakt_Password { get; set; } + public int Trakt_UpdateFrequency { get; set; } + public int Trakt_SyncFrequency { get; set; } + } +} diff --git a/JMMContracts/Contract_ServerSettings_SaveResponse.cs b/JMMContracts/Contract_ServerSettings_SaveResponse.cs new file mode 100644 index 000000000..d99c26a2f --- /dev/null +++ b/JMMContracts/Contract_ServerSettings_SaveResponse.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace JMMContracts +{ + public class Contract_ServerSettings_SaveResponse + { + public string ErrorMessage { get; set; } + } +} diff --git a/JMMContracts/Contract_ServerStatus.cs b/JMMContracts/Contract_ServerStatus.cs new file mode 100644 index 000000000..a3f2aaf83 --- /dev/null +++ b/JMMContracts/Contract_ServerStatus.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace JMMContracts +{ + public class Contract_ServerStatus + { + public int HashQueueCount { get; set; } + public string HashQueueState { get; set; } + public int GeneralQueueCount { get; set; } + public string GeneralQueueState { get; set; } + public int ImagesQueueCount { get; set; } + public string ImagesQueueState { get; set; } + public bool IsBanned { get; set; } + public string BanReason { get; set; } + } +} diff --git a/JMMContracts/Contract_TVDBSeriesSearchResult.cs b/JMMContracts/Contract_TVDBSeriesSearchResult.cs new file mode 100644 index 000000000..a68030ac0 --- /dev/null +++ b/JMMContracts/Contract_TVDBSeriesSearchResult.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace JMMContracts +{ + public class Contract_TVDBSeriesSearchResult + { + public string Id { get; set; } + public int SeriesID { get; set; } + public string Overview { get; set; } + public string SeriesName { get; set; } + public string Banner { get; set; } + public string Language { get; set; } + } +} diff --git a/JMMContracts/Contract_ToggleWatchedStatusOnEpisode_Response.cs b/JMMContracts/Contract_ToggleWatchedStatusOnEpisode_Response.cs new file mode 100644 index 000000000..71d944d52 --- /dev/null +++ b/JMMContracts/Contract_ToggleWatchedStatusOnEpisode_Response.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace JMMContracts +{ + public class Contract_ToggleWatchedStatusOnEpisode_Response + { + public string ErrorMessage { get; set; } + public Contract_AnimeEpisode AnimeEpisode { get; set; } + } +} diff --git a/JMMContracts/Contract_TraktTVShowResponse.cs b/JMMContracts/Contract_TraktTVShowResponse.cs new file mode 100644 index 000000000..717fe013c --- /dev/null +++ b/JMMContracts/Contract_TraktTVShowResponse.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace JMMContracts +{ + public class Contract_TraktTVShowResponse + { + public string title { get; set; } + public string year { get; set; } + public string url { get; set; } + public string first_aired { get; set; } + public string country { get; set; } + public string overview { get; set; } + public string tvdb_id { get; set; } + } +} diff --git a/JMMContracts/Contract_Trakt_Episode.cs b/JMMContracts/Contract_Trakt_Episode.cs new file mode 100644 index 000000000..d9a3f421a --- /dev/null +++ b/JMMContracts/Contract_Trakt_Episode.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace JMMContracts +{ + public class Contract_Trakt_Episode + { + public int Trakt_EpisodeID { get; set; } + public int Trakt_ShowID { get; set; } + public int Season { get; set; } + public int EpisodeNumber { get; set; } + public string Title { get; set; } + public string URL { get; set; } + public string Overview { get; set; } + public string EpisodeImage { get; set; } + } +} diff --git a/JMMContracts/Contract_Trakt_ImageFanart.cs b/JMMContracts/Contract_Trakt_ImageFanart.cs new file mode 100644 index 000000000..4bb87483b --- /dev/null +++ b/JMMContracts/Contract_Trakt_ImageFanart.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace JMMContracts +{ + public class Contract_Trakt_ImageFanart + { + public int Trakt_ImageFanartID { get; set; } + public int Trakt_ShowID { get; set; } + public int Season { get; set; } + public string ImageURL { get; set; } + public int Enabled { get; set; } + } +} diff --git a/JMMContracts/Contract_Trakt_ImagePoster.cs b/JMMContracts/Contract_Trakt_ImagePoster.cs new file mode 100644 index 000000000..4527cee9a --- /dev/null +++ b/JMMContracts/Contract_Trakt_ImagePoster.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace JMMContracts +{ + public class Contract_Trakt_ImagePoster + { + public int Trakt_ImagePosterID { get; set; } + public int Trakt_ShowID { get; set; } + public int Season { get; set; } + public string ImageURL { get; set; } + public int Enabled { get; set; } + } +} diff --git a/JMMContracts/Contract_Trakt_Season.cs b/JMMContracts/Contract_Trakt_Season.cs new file mode 100644 index 000000000..c353da689 --- /dev/null +++ b/JMMContracts/Contract_Trakt_Season.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace JMMContracts +{ + public class Contract_Trakt_Season + { + public int Trakt_SeasonID { get; set; } + public int Trakt_ShowID { get; set; } + public int Season { get; set; } + public string URL { get; set; } + public List Episodes { get; set; } + } +} diff --git a/JMMContracts/Contract_Trakt_Show.cs b/JMMContracts/Contract_Trakt_Show.cs new file mode 100644 index 000000000..5dacec68b --- /dev/null +++ b/JMMContracts/Contract_Trakt_Show.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace JMMContracts +{ + public class Contract_Trakt_Show + { + public int Trakt_ShowID { get; set; } + public string TraktID { get; set; } + public string Title { get; set; } + public string Year { get; set; } + public string URL { get; set; } + public string Overview { get; set; } + public int? TvDB_ID { get; set; } + public List Seasons { get; set; } + } +} diff --git a/JMMContracts/Contract_TvDB_Episode.cs b/JMMContracts/Contract_TvDB_Episode.cs new file mode 100644 index 000000000..ee949a5a5 --- /dev/null +++ b/JMMContracts/Contract_TvDB_Episode.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace JMMContracts +{ + public class Contract_TvDB_Episode + { + public int TvDB_EpisodeID { get; set; } + public int Id { get; set; } + public int SeriesID { get; set; } + public int SeasonID { get; set; } + public int SeasonNumber { get; set; } + public int EpisodeNumber { get; set; } + public string EpisodeName { get; set; } + public string Overview { get; set; } + public string Filename { get; set; } + public int EpImgFlag { get; set; } + public int? AbsoluteNumber { get; set; } + public int? AirsAfterSeason { get; set; } + public int? AirsBeforeEpisode { get; set; } + public int? AirsBeforeSeason { get; set; } + + } +} diff --git a/JMMContracts/Contract_TvDB_ImageFanart.cs b/JMMContracts/Contract_TvDB_ImageFanart.cs new file mode 100644 index 000000000..a82444315 --- /dev/null +++ b/JMMContracts/Contract_TvDB_ImageFanart.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace JMMContracts +{ + public class Contract_TvDB_ImageFanart + { + public int TvDB_ImageFanartID { get; set; } + public int Id { get; set; } + public int SeriesID { get; set; } + public string BannerPath { get; set; } + public string BannerType { get; set; } + public string BannerType2 { get; set; } + public string Colors { get; set; } + public string Language { get; set; } + public string ThumbnailPath { get; set; } + public string VignettePath { get; set; } + public int Enabled { get; set; } + public int Chosen { get; set; } + } +} diff --git a/JMMContracts/Contract_TvDB_ImagePoster.cs b/JMMContracts/Contract_TvDB_ImagePoster.cs new file mode 100644 index 000000000..c3ddefda1 --- /dev/null +++ b/JMMContracts/Contract_TvDB_ImagePoster.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace JMMContracts +{ + public class Contract_TvDB_ImagePoster + { + public int TvDB_ImagePosterID { get; set; } + public int Id { get; set; } + public int SeriesID { get; set; } + public string BannerPath { get; set; } + public string BannerType { get; set; } + public string BannerType2 { get; set; } + public string Language { get; set; } + public int Enabled { get; set; } + public int? SeasonNumber { get; set; } + } +} diff --git a/JMMContracts/Contract_TvDB_ImageWideBanner.cs b/JMMContracts/Contract_TvDB_ImageWideBanner.cs new file mode 100644 index 000000000..68656cf27 --- /dev/null +++ b/JMMContracts/Contract_TvDB_ImageWideBanner.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace JMMContracts +{ + public class Contract_TvDB_ImageWideBanner + { + public int TvDB_ImageWideBannerID { get; set; } + public int Id { get; set; } + public int SeriesID { get; set; } + public string BannerPath { get; set; } + public string BannerType { get; set; } + public string BannerType2 { get; set; } + public string Language { get; set; } + public int Enabled { get; set; } + public int? SeasonNumber { get; set; } + } +} diff --git a/JMMContracts/Contract_TvDB_Series.cs b/JMMContracts/Contract_TvDB_Series.cs new file mode 100644 index 000000000..035b79111 --- /dev/null +++ b/JMMContracts/Contract_TvDB_Series.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace JMMContracts +{ + public class Contract_TvDB_Series + { + public int TvDB_SeriesID { get; set; } + public int SeriesID { get; set; } + public string Overview { get; set; } + public string SeriesName { get; set; } + public string Status { get; set; } + public string Banner { get; set; } + public string Fanart { get; set; } + public string Lastupdated { get; set; } + public string Poster { get; set; } + } +} diff --git a/JMMContracts/Contract_VideoDetailed.cs b/JMMContracts/Contract_VideoDetailed.cs new file mode 100644 index 000000000..d45e6b354 --- /dev/null +++ b/JMMContracts/Contract_VideoDetailed.cs @@ -0,0 +1,66 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace JMMContracts +{ + public class Contract_VideoDetailed + { + public int AnimeEpisodeID { get; set; } + + // ImportFolder + public int ImportFolderID { get; set; } + public string ImportFolderName { get; set; } + public string ImportFolderLocation { get; set; } + + // CrossRef_File_Episode + public int Percentage { get; set; } + public int EpisodeOrder { get; set; } + public int CrossRefSource { get; set; } + + // VideoLocal + public int VideoLocalID { get; set; } + public string VideoLocal_FilePath { get; set; } + public string VideoLocal_Hash { get; set; } + public long VideoLocal_FileSize { get; set; } + public int VideoLocal_IsWatched { get; set; } + public int VideoLocal_IsIgnored { get; set; } + + // VideoInfo + public int VideoInfo_VideoInfoID { get; set; } + public string VideoInfo_VideoCodec { get; set; } + public string VideoInfo_VideoBitrate { get; set; } + public string VideoInfo_VideoFrameRate { get; set; } + public string VideoInfo_VideoResolution { get; set; } + public string VideoInfo_AudioCodec { get; set; } + public string VideoInfo_AudioBitrate { get; set; } + public long VideoInfo_Duration { get; set; } + + // AniDB_File + public int? AniDB_FileID { get; set; } + public int? AniDB_AnimeID { get; set; } + public int? AniDB_GroupID { get; set; } + public string AniDB_File_Source { get; set; } + public string AniDB_File_AudioCodec { get; set; } + public string AniDB_File_VideoCodec { get; set; } + public string AniDB_File_VideoResolution { get; set; } + public string AniDB_File_FileExtension { get; set; } + public int? AniDB_File_LengthSeconds { get; set; } + public string AniDB_File_Description { get; set; } + public int? AniDB_File_ReleaseDate { get; set; } + public string AniDB_Anime_GroupName { get; set; } + public string AniDB_Anime_GroupNameShort { get; set; } + public int? AniDB_Episode_Rating { get; set; } + public int? AniDB_Episode_Votes { get; set; } + public string AniDB_CRC { get; set; } + public string AniDB_MD5 { get; set; } + public string AniDB_SHA1 { get; set; } + + // Languages + public string LanguagesAudio { get; set; } + public string LanguagesSubtitle { get; set; } + + public Contract_ReleaseGroup ReleaseGroup { get; set; } + } +} diff --git a/JMMContracts/Contract_VideoLocal.cs b/JMMContracts/Contract_VideoLocal.cs new file mode 100644 index 000000000..7bfc04160 --- /dev/null +++ b/JMMContracts/Contract_VideoLocal.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace JMMContracts +{ + public class Contract_VideoLocal + { + public int VideoLocalID { get; set; } + public string FilePath { get; set; } + public int ImportFolderID { get; set; } + public string Hash { get; set; } + public string CRC32 { get; set; } + public string MD5 { get; set; } + public string SHA1 { get; set; } + public int HashSource { get; set; } + public long FileSize { get; set; } + public int IsWatched { get; set; } + public int IsIgnored { get; set; } + public DateTime? WatchedDate { get; set; } + public DateTime DateTimeUpdated { get; set; } + + public Contract_ImportFolder ImportFolder { get; set; } + } +} diff --git a/JMMContracts/Contract_VideoLocalManualLink.cs b/JMMContracts/Contract_VideoLocalManualLink.cs new file mode 100644 index 000000000..96da0b84a --- /dev/null +++ b/JMMContracts/Contract_VideoLocalManualLink.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace JMMContracts +{ + public class Contract_VideoLocalManualLink + { + public int VideoLocalID { get; set; } + public string FilePath { get; set; } + public int ImportFolderID { get; set; } + public string Hash { get; set; } + public string CRC32 { get; set; } + public string MD5 { get; set; } + public string SHA1 { get; set; } + public int HashSource { get; set; } + public long FileSize { get; set; } + public int IsWatched { get; set; } + public int IsIgnored { get; set; } + public DateTime? WatchedDate { get; set; } + public DateTime DateTimeUpdated { get; set; } + + public Contract_ImportFolder ImportFolder { get; set; } + + + } +} diff --git a/JMMContracts/Hashes.cs b/JMMContracts/Hashes.cs new file mode 100644 index 000000000..93e8a5fc6 --- /dev/null +++ b/JMMContracts/Hashes.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace JMMContracts +{ + public class Hashes + { + public string ed2k { get; set; } + public string sha1 { get; set; } + public string crc32 { get; set; } + public string md5 { get; set; } + } +} diff --git a/JMMContracts/IJMMServer.cs b/JMMContracts/IJMMServer.cs new file mode 100644 index 000000000..1518496eb --- /dev/null +++ b/JMMContracts/IJMMServer.cs @@ -0,0 +1,370 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.ServiceModel; +using System.IO; + +namespace JMMContracts +{ + [ServiceContract] + public interface IJMMServer + { + [OperationContract] + List GetEpisodesForSeriesOld(int animeSeriesID); + + [OperationContract] + Contract_AnimeEpisode GetEpisode(int animeEpisodeID, int userID); + + [OperationContract] + string RemoveAssociationOnFile(int videoLocalID, int animeEpisodeID); + + [OperationContract] + string SetIgnoreStatusOnFile(int videoLocalID, bool isIgnored); + + [OperationContract] + Contract_AnimeSeries_SaveResponse CreateSeriesFromAnime(int animeID, int? animeGroupID, int userID); + + [OperationContract] + string UpdateAnimeData(int animeID); + + [OperationContract] + string AssociateSingleFile(int videoLocalID, int animeEpisodeID); + + [OperationContract] + string AssociateSingleFileWithMultipleEpisodes(int videoLocalID, int animeSeriesID, int startEpNum, int endEpNum); + + [OperationContract] + string AssociateMultipleFiles(List videoLocalIDs, int animeSeriesID, int startingEpisodeNumber, bool singleEpisode); + + [OperationContract] + List GetAllGroups(int userID); + + [OperationContract] + Contract_AnimeGroup_SaveResponse SaveGroup(Contract_AnimeGroup_Save grp, int userID); + + [OperationContract] + Contract_AnimeGroup GetGroup(int animeGroupID, int userID); + + [OperationContract] + List GetAllGroupsAboveSeries(int animeSeriesID, int userID); + + [OperationContract] + List GetAllGroupsAboveGroupInclusive(int animeGroupID, int userID); + + [OperationContract] + List GetAllSeries(int userID); + + [OperationContract] + Contract_AnimeSeries_SaveResponse SaveSeries(Contract_AnimeSeries_Save contract, int userID); + + [OperationContract] + Contract_AnimeSeries_SaveResponse MoveSeries(int animeSeriesID, int newAnimeGroupID, int userID); + + [OperationContract] + List GetAllAnime(); + + [OperationContract] + List GetAllAnimeDetailed(); + + [OperationContract] + Contract_AniDB_AnimeDetailed GetAnimeDetailed(int animeID); + + [OperationContract] + List GetSeriesForGroup(int animeGroupID, int userID); + + [OperationContract] + List GetEpisodesForSeries(int animeSeriesID, int userID); + + [OperationContract] + List GetEpisodesForFile(int videoLocalID, int userID); + + [OperationContract] + List GetFilesForEpisode(int episodeID, int userID); + + + + [OperationContract] + List GetMyReleaseGroupsForAniDBEpisode(int aniDBEpisodeID); + + [OperationContract] + List GetImportFolders(); + + [OperationContract] + Contract_ServerStatus GetServerStatus(); + + [OperationContract] + Contract_ServerSettings GetServerSettings(); + + [OperationContract] + Contract_ServerSettings_SaveResponse SaveServerSettings(Contract_ServerSettings contractIn); + + [OperationContract] + string ToggleWatchedStatusOnVideo(int videoLocalID, bool watchedStatus, int userID); + + [OperationContract] + Contract_ToggleWatchedStatusOnEpisode_Response ToggleWatchedStatusOnEpisode(int animeEpisodeID, bool watchedStatus, int userID); + + [OperationContract] + Contract_VideoDetailed GetVideoDetailed(int videoLocalID); + + [OperationContract] + Contract_ImportFolder_SaveResponse SaveImportFolder(Contract_ImportFolder contract); + + [OperationContract] + string DeleteImportFolder(int importFolderID); + + [OperationContract] + Contract_AnimeSeries GetSeries(int animeSeriesID, int userID); + + [OperationContract] + void RunImport(); + + [OperationContract] + void RemoveMissingFiles(); + + [OperationContract] + void SyncMyList(); + + [OperationContract] + void RehashFile(int videoLocalID); + + [OperationContract] + void SetCommandProcessorHasherPaused(bool paused); + + [OperationContract] + void SetCommandProcessorGeneralPaused(bool paused); + + [OperationContract] + void SetCommandProcessorImagesPaused(bool paused); + + [OperationContract] + List GetUnrecognisedFiles(int userID); + + [OperationContract] + List GetManuallyLinkedFiles(int userID); + + [OperationContract] + List GetIgnoredFiles(int userID); + + [OperationContract] + string TestAniDBConnection(); + + [OperationContract] + string RenameAllGroups(); + + [OperationContract] + List GetAllGroupFilters(); + + [OperationContract] + Contract_GroupFilter_SaveResponse SaveGroupFilter(Contract_GroupFilter contract); + + [OperationContract] + string DeleteGroupFilter(int groupFilterID); + + [OperationContract] + List GetAllCategoryNames(); + + [OperationContract] + void ScanFolder(int importFolderID); + + [OperationContract] + void SyncVotes(); + + [OperationContract] + void VoteAnime(int animeID, decimal voteValue, int voteType); + + [OperationContract] + void VoteAnimeRevoke(int animeID); + + [OperationContract] + string SetWatchedStatusOnSeries(int animeSeriesID, bool watchedStatus, int maxEpisodeNumber, int episodeType, int userID); + + [OperationContract] + List GetAllUniqueVideoQuality(); + + [OperationContract] + List GetAllUniqueAudioLanguages(); + + [OperationContract] + List GetAllUniqueSubtitleLanguages(); + + [OperationContract] + List GetAllDuplicateFiles(); + + [OperationContract] + string DeleteDuplicateFile(int duplicateFileID, int fileNumber); + + [OperationContract] + List GetAllManuallyLinkedFiles(int userID); + + [OperationContract] + List GetAllEpisodesWithMultipleFiles(int userID); + + [OperationContract] + void ReevaluateDuplicateFiles(); + + [OperationContract] + List GetGroupVideoQualitySummary(int animeID); + + [OperationContract] + string DeleteVideoLocalAndFile(int videoLocalID); + + [OperationContract] + void RescanUnlinkedFiles(); + + [OperationContract] + List GetFilesByGroupAndResolution(int animeID, string relGroupName, string resolution, string videoSource, int userID); + + [OperationContract] + Contract_AniDB_AnimeCrossRefs GetCrossRefDetails(int animeID); + + [OperationContract] + Contract_CrossRef_AniDB_TvDBResult GetTVDBCrossRefWebCache(int animeID); + + [OperationContract] + Contract_CrossRef_AniDB_TvDB GetTVDBCrossRef(int animeID); + + [OperationContract] + List SearchTheTvDB(string criteria); + + [OperationContract] + List GetSeasonNumbersForSeries(int seriesID); + + [OperationContract] + string LinkAniDBTvDB(int animeID, int tvDBID, int seasonNumber); + + [OperationContract] + string RemoveLinkAniDBTvDB(int animeID); + + [OperationContract] + List GetAllTvDBPosters(int? tvDBID); + + [OperationContract] + List GetAllTvDBWideBanners(int? tvDBID); + + [OperationContract] + List GetAllTvDBFanart(int? tvDBID); + + [OperationContract] + List GetAllTvDBEpisodes(int? tvDBID); + + [OperationContract] + string UpdateTvDBData(int seriesID); + + [OperationContract] + string EnableDisableImage(bool enabled, int imageID, int imageType); + + [OperationContract] + Contract_CrossRef_AniDB_OtherResult GetOtherAnimeCrossRefWebCache(int animeID, int crossRefType); + + [OperationContract] + Contract_CrossRef_AniDB_Other GetOtherAnimeCrossRef(int animeID, int crossRefType); + + [OperationContract] + List SearchTheMovieDB(string criteria); + + [OperationContract] + string LinkAniDBOther(int animeID, int movieID, int crossRefType); + + [OperationContract] + string RemoveLinkAniDBOther(int animeID, int crossRefType); + + [OperationContract] + List GetAllMovieDBPosters(int? movieID); + + [OperationContract] + List GetAllMovieDBFanart(int? movieID); + + [OperationContract] + Contract_AniDBAnime GetAnime(int animeID); + + [OperationContract] + string SetDefaultImage(bool isDefault, int animeID, int imageID, int imageType, int imageSizeType); + + [OperationContract] + Contract_AnimeEpisode GetNextUnwatchedEpisode(int animeSeriesID, int userID); + + [OperationContract] + Contract_AnimeEpisode GetNextUnwatchedEpisodeForGroup(int animeGroupID, int userID); + + [OperationContract] + List GetEpisodesToWatch_RecentlyWatched(int maxRecords, int jmmuserID); + + [OperationContract] + string DeleteAnimeSeries(int animeSeriesID, bool deleteFiles); + + [OperationContract] + string DeleteAnimeGroup(int animeGroupID, bool deleteFiles); + + [OperationContract] + List GetSeriesWithMissingEpisodes(int maxRecords, int jmmuserID); + + [OperationContract] + List GetMiniCalendar(int jmmuserID, int numberOfDays); + + [OperationContract] + List GetAllUsers(); + + [OperationContract] + Contract_JMMUser AuthenticateUser(string username, string password); + + [OperationContract] + string SaveUser(Contract_JMMUser user); + + [OperationContract] + string DeleteUser(int userID); + + [OperationContract] + string TestTraktLogin(); + + [OperationContract] + List GetAllTraktFanart(int? traktShowID); + + [OperationContract] + List GetAllTraktPosters(int? traktShowID); + + [OperationContract] + List GetAllTraktEpisodes(int? traktShowID); + + [OperationContract] + Contract_CrossRef_AniDB_TraktResult GetTraktCrossRefWebCache(int animeID); + + [OperationContract] + Contract_CrossRef_AniDB_Trakt GetTraktCrossRef(int animeID); + + [OperationContract] + List SearchTrakt(string criteria); + + [OperationContract] + string LinkAniDBTrakt(int animeID, string traktID, int seasonNumber); + + [OperationContract] + string RemoveLinkAniDBTrakt(int animeID); + + [OperationContract] + List GetSeasonNumbersForTrakt(string traktID); + + [OperationContract] + string UpdateTraktData(string traktD); + + [OperationContract] + Contract_GroupFilterExtended GetGroupFilterExtended(int groupFilterID, int userID); + + [OperationContract] + List GetAnimeGroupsForFilter(int groupFilterID, int userID); + + [OperationContract] + List GetAllGroupFiltersExtended(int userID); + + [OperationContract] + List GetSubGroupsForGroup(int animeGroupID, int userID); + + [OperationContract] + List GetSeriesForGroupRecursive(int animeGroupID, int userID); + + [OperationContract] + bool GetSeriesExistingForAnime(int animeID); + } + +} diff --git a/JMMContracts/IJMMServerImage.cs b/JMMContracts/IJMMServerImage.cs new file mode 100644 index 000000000..5ca1e2b05 --- /dev/null +++ b/JMMContracts/IJMMServerImage.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.ServiceModel; + +namespace JMMContracts +{ + [ServiceContract] + public interface IJMMServerImage + { + [OperationContract] + byte[] GetImage(string entityID, int entityType, bool thumnbnailOnly); + } +} diff --git a/JMMContracts/JMMContracts.csproj b/JMMContracts/JMMContracts.csproj new file mode 100644 index 000000000..11491d3c2 --- /dev/null +++ b/JMMContracts/JMMContracts.csproj @@ -0,0 +1,132 @@ + + + + Debug + AnyCPU + 8.0.30703 + 2.0 + {D777636B-F927-4C7D-9D00-4A7858E75F3E} + Library + Properties + JMMContracts + JMMContracts + v3.5 + 512 + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + true + bin\x86\Debug\ + DEBUG;TRACE + full + x86 + prompt + true + true + + + bin\x86\Release\ + TRACE + true + pdbonly + x86 + prompt + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/JMMContracts/MediaInfoResult.cs b/JMMContracts/MediaInfoResult.cs new file mode 100644 index 000000000..d5453c0ac --- /dev/null +++ b/JMMContracts/MediaInfoResult.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace JMMContracts +{ + public class MediaInfoResult + { + public string VideoCodec { get; set; } + public string VideoBitrate { get; set; } + public string VideoFrameRate { get; set; } + public string VideoResolution { get; set; } + public string AudioCodec { get; set; } + public string AudioBitrate { get; set; } + public int Duration { get; set; } + } +} diff --git a/JMMContracts/Properties/AssemblyInfo.cs b/JMMContracts/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..09f739c1e --- /dev/null +++ b/JMMContracts/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("JMMContracts")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("JMMContracts")] +[assembly: AssemblyCopyright("")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("f76e09b0-a4e6-4fb3-92d3-58d52893af3b")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/JMMFileHelper/Crc32.cs b/JMMFileHelper/Crc32.cs new file mode 100644 index 000000000..d841311f4 --- /dev/null +++ b/JMMFileHelper/Crc32.cs @@ -0,0 +1,109 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Security.Cryptography; + +namespace JMMFileHelper +{ + public class Crc32 : HashAlgorithm + { + public const uint DefaultSeed = 0xffffffff; + + readonly static uint[] CrcTable = new uint[] { + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, + 0x706AF48F, 0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, + 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, + 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, + 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, + 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, + 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, + 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, + 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC, 0x51DE003A, + 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, + 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, + 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, + 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, + 0x9FBFE4A5, 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, + 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, + 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, + 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, + 0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, + 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, + 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, + 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA, 0xBE0B1010, + 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, + 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, + 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, + 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, + 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 0xF00F9344, + 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, + 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, + 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, + 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C, + 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, + 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, + 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, + 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, + 0x2CD99E8B, 0x5BDEAE1D, 0x9B64C2B0, 0xEC63F226, 0x756AA39C, + 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, + 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, + 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, + 0x18B74777, 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, + 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278, + 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, + 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, + 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, + 0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, + 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, + 0x2D02EF8D + }; + + uint crcValue; + + public override void Initialize() + { + crcValue = 0; + } + + protected override void HashCore(byte[] buffer, int start, int length) + { + crcValue ^= DefaultSeed; + + unchecked + { + while (--length >= 0) + { + crcValue = CrcTable[(crcValue ^ buffer[start++]) & 0xFF] ^ (crcValue >> 8); + } + } + + crcValue ^= DefaultSeed; + } + protected override byte[] HashFinal() + { + HashValue = new[] { (byte)((crcValue >> 24) & 0xff), + (byte)((crcValue >> 16) & 0xff), + (byte)((crcValue >> 8) & 0xff), + (byte)(crcValue & 0xff) }; + return HashValue; + } + public uint CrcValue + { + get + { + return (uint)((HashValue[0] << 24) | (HashValue[1] << 16) | (HashValue[2] << 8) | HashValue[3]); + } + } + public override int HashSize + { + get { return 32; } + } + } +} diff --git a/JMMFileHelper/FileHashHelper.cs b/JMMFileHelper/FileHashHelper.cs new file mode 100644 index 000000000..92c3e4e7e --- /dev/null +++ b/JMMFileHelper/FileHashHelper.cs @@ -0,0 +1,86 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Collections.Specialized; +using System.Configuration; +using NLog; +using System.IO; +using JMMContracts; + +namespace JMMFileHelper +{ + public class FileHashHelper + { + private static Logger logger = LogManager.GetCurrentClassLogger(); + + /// + /// Get all the hash info and video/audio info for a video file + /// + /// + /// + /// + public static void GetVideoInfo(string fileName, ref Hashes hashInfo, ref MediaInfoResult vidInfo, bool forceRefresh) + { + hashInfo = Hasher.CalculateHashes(fileName, null); + if (vidInfo == null) vidInfo = new MediaInfoResult(); + MediaInfoReader.ReadMediaInfo(fileName, forceRefresh, ref vidInfo); + } + + public static Hashes GetHashInfo(string fileName, bool forceRefresh, JMMFileHelper.Hasher.OnHashProgress hashProgress, bool getCRC32, bool getMD5, bool getSHA1) + { + return Hasher.CalculateHashes(fileName, hashProgress, true, getCRC32, getMD5, getSHA1); + } + + public static MediaInfoResult GetMediaInfo(string fileName, bool forceRefresh) + { + MediaInfoResult vidInfo = new MediaInfoResult(); + MediaInfoReader.ReadMediaInfo(fileName, forceRefresh, ref vidInfo); + return vidInfo; + } + + + + public static bool IsVideo(string fileName) + { + List videoExtensions = GetVideoExtensions(); + if (videoExtensions.Count == 0) return false; + + if (videoExtensions.Contains(Path.GetExtension(fileName).Replace(".", "").Trim().ToUpper())) + return true; + + return false; + } + + public static List GetVideoExtensions() + { + List extList = new List(); + + // Get the AppSettings section. + NameValueCollection appSettings = ConfigurationManager.AppSettings; + + try + { + string exts = appSettings["VideoExtensions"]; + + if (appSettings.Count == 0 || exts == null || exts.Trim().Length == 0) + { + logger.Error("Could not find VideoExtensions app setting in config file"); + return extList; + } + + string[] extArray = exts.Split(','); + foreach (string ext in extArray) + { + extList.Add(ext.Trim().ToUpper()); + } + } + catch (Exception ex) + { + logger.ErrorException("Error in GetVideoExtensions: " + ex.ToString(), ex); + } + + return extList; + } + } +} diff --git a/JMMFileHelper/Hasher.cs b/JMMFileHelper/Hasher.cs new file mode 100644 index 000000000..d0f30daaa --- /dev/null +++ b/JMMFileHelper/Hasher.cs @@ -0,0 +1,180 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Runtime.InteropServices; +using System.IO; +using System.Security.Cryptography; +using NLog; +using JMMContracts; + +namespace JMMFileHelper +{ + public class Hasher + { + private static Logger logger = LogManager.GetCurrentClassLogger(); + public delegate int OnHashProgress([MarshalAs(UnmanagedType.LPWStr)]string strFileName, int nProgressPct); + + #region DLL functions + [DllImport("hasher.dll", EntryPoint = "CalculateHashes_AsyncIO")] + private static extern int CalculateHashes_callback_dll( + [MarshalAs(UnmanagedType.LPWStr)] string szFileName, + [MarshalAs(UnmanagedType.LPArray)] byte[] hash, + [MarshalAs(UnmanagedType.FunctionPtr)] OnHashProgress lpHashProgressFunc, + [MarshalAs(UnmanagedType.Bool)] bool getCRC32, + [MarshalAs(UnmanagedType.Bool)] bool getMD5, + [MarshalAs(UnmanagedType.Bool)] bool getSHA1 + ); + + // Calculates hash immediately (with progress) + protected static bool CalculateHashes_dll(string strFileName, ref byte[] hash, OnHashProgress HashProgress, bool getCRC32, bool getMD5, bool getSHA1) + { + OnHashProgress pHashProgress = new OnHashProgress(HashProgress); + GCHandle gcHashProgress = GCHandle.Alloc(pHashProgress); //to make sure the GC doesn't dispose the delegate + + int nResult = CalculateHashes_callback_dll(strFileName, hash, pHashProgress, getCRC32, getMD5, getSHA1); + + return (nResult == 0); + } + + public static bool UseDll() + { + return File.Exists("hasher.dll"); + } + + public static string HashToString(byte[] hash, int start, int length) + { + if (hash == null || hash.Length == 0) + return string.Empty; + + StringBuilder hex = new StringBuilder(length * 2); + for (int x = start; x < start + length; x++) + { + hex.AppendFormat("{0:x2}", hash[x]); + } + return hex.ToString().ToUpper(); + } + + #endregion + + public static Hashes CalculateHashes(string strPath, OnHashProgress onHashProgress) + { + return CalculateHashes(strPath, onHashProgress, true, true, true, true); + } + + public static Hashes CalculateHashes(string strPath, OnHashProgress onHashProgress, bool getED2k, bool getCRC32, bool getMD5, bool getSHA1) + { + if (UseDll()) + { + byte[] hash = new byte[56]; + Hashes rhash = new Hashes(); + + if (CalculateHashes_dll(strPath, ref hash, onHashProgress, getCRC32, getMD5, getSHA1)) + { + rhash.ed2k = HashToString(hash, 0, 16); + if (getCRC32) rhash.crc32 = HashToString(hash, 16, 4); + if (getMD5) rhash.md5 = HashToString(hash, 20, 16); + if (getSHA1) rhash.sha1 = HashToString(hash, 36, 20); + + } + else + { + rhash.ed2k = string.Empty; + rhash.crc32 = string.Empty; + rhash.md5 = string.Empty; + rhash.sha1 = string.Empty; + } + return rhash; + } + return CalculateHashes_here(strPath, onHashProgress, getED2k, getCRC32, getMD5, getSHA1); + } + + protected static Hashes CalculateHashes_here(string strPath, OnHashProgress onHashProgress, bool getED2k, bool getCRC32, bool getMD5, bool getSHA1) + { + FileStream fs; + Hashes rhash = new Hashes(); + FileInfo fi = new FileInfo(strPath); + fs = fi.OpenRead(); + int lChunkSize = 9728000; + + long nBytes = (long)fs.Length; + + long nBytesRemaining = (long)fs.Length; + int nBytesToRead = 0; + + long nBlocks = nBytes / lChunkSize; + long nRemainder = nBytes % lChunkSize; //mod + if (nRemainder > 0) + nBlocks++; + + byte[] baED2KHash = new byte[16 * nBlocks]; + + if (nBytes > lChunkSize) + nBytesToRead = lChunkSize; + else + nBytesToRead = (int)nBytesRemaining; + + if (onHashProgress != null) + onHashProgress(strPath, 0); + + MD4 md4 = MD4.Create(); + MD5 md5 = MD5.Create(); + SHA1 sha1 = SHA1.Create(); + Crc32 crc32 = new Crc32(); + + byte[] ByteArray = new byte[nBytesToRead]; + + long iOffSet = 0; + long iChunkCount = 0; + while (nBytesRemaining > 0) + { + iChunkCount++; + + //logger.Trace("Hashing Chunk: " + iChunkCount.ToString()); + + int nBytesRead = fs.Read(ByteArray, 0, nBytesToRead); + + if (getED2k) + { + byte[] baHash = md4.ComputeHash(ByteArray, 0, nBytesRead); + int j = (int)((iChunkCount - 1) * 16); + for (int i = 0; i < 16; i++) + baED2KHash[j + i] = baHash[i]; + } + + if (getMD5) md5.TransformBlock(ByteArray, 0, nBytesRead, ByteArray, 0); + if (getSHA1) sha1.TransformBlock(ByteArray, 0, nBytesRead, ByteArray, 0); + if (getCRC32) crc32.TransformBlock(ByteArray, 0, nBytesRead, ByteArray, 0); + + int percentComplete = (int)((float)iChunkCount / (float)nBlocks * 100); + if (onHashProgress != null) + onHashProgress(strPath, percentComplete); + + iOffSet += lChunkSize; + nBytesRemaining = nBytes - iOffSet; + if (nBytesRemaining < lChunkSize) + nBytesToRead = (int)nBytesRemaining; + + } + if (getMD5) md5.TransformFinalBlock(ByteArray, 0, 0); + if (getSHA1) sha1.TransformFinalBlock(ByteArray, 0, 0); + if (getCRC32) crc32.TransformFinalBlock(ByteArray, 0, 0); + + + fs.Close(); + + if (onHashProgress != null) + onHashProgress(strPath, 100); + + if (getED2k) + { + byte[] baHashFinal = md4.ComputeHash(baED2KHash); + rhash.ed2k = BitConverter.ToString(baHashFinal).Replace("-", "").ToUpper(); + } + if (getCRC32) rhash.crc32 = BitConverter.ToString(crc32.Hash).Replace("-", "").ToUpper(); + if (getMD5) rhash.md5 = BitConverter.ToString(md5.Hash).Replace("-", "").ToUpper(); + if (getSHA1) rhash.sha1 = BitConverter.ToString(sha1.Hash).Replace("-", "").ToUpper(); + return rhash; + } + } +} diff --git a/JMMFileHelper/JMMFileHelper.csproj b/JMMFileHelper/JMMFileHelper.csproj new file mode 100644 index 000000000..eac52b81a --- /dev/null +++ b/JMMFileHelper/JMMFileHelper.csproj @@ -0,0 +1,86 @@ + + + + Debug + AnyCPU + 8.0.30703 + 2.0 + {73E4CFC4-291B-47A2-ACAA-78096CEBB7DF} + Library + Properties + JMMFileHelper + JMMFileHelper + v3.5 + 512 + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + true + bin\x86\Debug\ + DEBUG;TRACE + full + x86 + prompt + + + bin\x86\Release\ + TRACE + true + pdbonly + x86 + prompt + + + + False + ..\Dependencies\NLog.dll + + + + + + + + + + + + + + + + + + + + + {D777636B-F927-4C7D-9D00-4A7858E75F3E} + JMMContracts + + + + + \ No newline at end of file diff --git a/JMMFileHelper/MD4Managed.cs b/JMMFileHelper/MD4Managed.cs new file mode 100644 index 000000000..bcaf7a98c --- /dev/null +++ b/JMMFileHelper/MD4Managed.cs @@ -0,0 +1,284 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Security.Cryptography; + +namespace JMMFileHelper +{ + public abstract class MD4 : HashAlgorithm + { + + protected MD4() + { + // MD4 hash length are 128 bits long + HashSizeValue = 128; + } + + public static new MD4 Create() + { + // for this to work we must register ourself with CryptoConfig + return Create("MD4"); + } + + public static new MD4 Create(string hashName) + { + object obj = CryptoConfig.CreateFromName(hashName); + // in case machine.config isn't configured to use any MD4 implementation + if (obj == null) + obj = new MD4Managed(); + + return (MD4)obj; + } + } + + public class MD4Managed : MD4 + { + + private uint[] state; + private byte[] buffer; + private uint[] count; + private uint[] x; + + private const int S11 = 3; + private const int S12 = 7; + private const int S13 = 11; + private const int S14 = 19; + private const int S21 = 3; + private const int S22 = 5; + private const int S23 = 9; + private const int S24 = 13; + private const int S31 = 3; + private const int S32 = 9; + private const int S33 = 11; + private const int S34 = 15; + + private byte[] digest; + + //--- constructor ----------------------------------------------------------- + + public MD4Managed() + { + // we allocate the context memory + state = new uint[4]; + count = new uint[2]; + buffer = new byte[64]; + digest = new byte[16]; + // temporary buffer in MD4Transform that we don't want to keep allocate on each iteration + x = new uint[16]; + // the initialize our context + Initialize(); + } + + public override void Initialize() + { + count[0] = 0; + count[1] = 0; + state[0] = 0x67452301; + state[1] = 0xefcdab89; + state[2] = 0x98badcfe; + state[3] = 0x10325476; + // Zeroize sensitive information + Array.Clear(buffer, 0, 64); + Array.Clear(x, 0, 16); + } + + protected override void HashCore(byte[] array, int ibStart, int cbSize) + { + /* Compute number of bytes mod 64 */ + int index = (int)((count[0] >> 3) & 0x3F); + /* Update number of bits */ + count[0] += (uint)(cbSize << 3); + if (count[0] < (cbSize << 3)) + count[1]++; + count[1] += (uint)(cbSize >> 29); + + int partLen = 64 - index; + int i = 0; + /* Transform as many times as possible. */ + if (cbSize >= partLen) + { + //MD4_memcpy((POINTER)&context->buffer[index], (POINTER)input, partLen); + Buffer.BlockCopy(array, ibStart, buffer, index, partLen); + MD4Transform(state, buffer, 0); + + for (i = partLen; i + 63 < cbSize; i += 64) + { + // MD4Transform (context->state, &input[i]); + MD4Transform(state, array, i); + } + + index = 0; + } + + /* Buffer remaining input */ + //MD4_memcpy ((POINTER)&context->buffer[index], (POINTER)&input[i], inputLen-i); + Buffer.BlockCopy(array, ibStart + i, buffer, index, (cbSize - i)); + } + + protected override byte[] HashFinal() + { + /* Save number of bits */ + byte[] bits = new byte[8]; + Encode(bits, count); + + /* Pad out to 56 mod 64. */ + uint index = ((count[0] >> 3) & 0x3f); + int padLen = (int)((index < 56) ? (56 - index) : (120 - index)); + HashCore(Padding(padLen), 0, padLen); + + /* Append length (before padding) */ + HashCore(bits, 0, 8); + + /* Store state in digest */ + Encode(digest, state); + + // Zeroize sensitive information. + Initialize(); + + return digest; + } + + //--- private methods --------------------------------------------------- + + private byte[] Padding(int nLength) + { + if (nLength > 0) + { + byte[] padding = new byte[nLength]; + padding[0] = 0x80; + return padding; + } + return null; + } + + /* F, G and H are basic MD4 functions. */ + private uint F(uint x, uint y, uint z) + { + return (uint)(((x) & (y)) | ((~x) & (z))); + } + + private uint G(uint x, uint y, uint z) + { + return (uint)(((x) & (y)) | ((x) & (z)) | ((y) & (z))); + } + + private uint H(uint x, uint y, uint z) + { + return (uint)((x) ^ (y) ^ (z)); + } + + /* ROTATE_LEFT rotates x left n bits. */ + private uint ROL(uint x, byte n) + { + return (uint)(((x) << (n)) | ((x) >> (32 - (n)))); + } + + /* FF, GG and HH are transformations for rounds 1, 2 and 3 */ + /* Rotation is separate from addition to prevent recomputation */ + private void FF(ref uint a, uint b, uint c, uint d, uint x, byte s) + { + a += F(b, c, d) + x; + a = ROL(a, s); + } + + private void GG(ref uint a, uint b, uint c, uint d, uint x, byte s) + { + a += G(b, c, d) + x + 0x5a827999; + a = ROL(a, s); + } + + private void HH(ref uint a, uint b, uint c, uint d, uint x, byte s) + { + a += H(b, c, d) + x + 0x6ed9eba1; + a = ROL(a, s); + } + + private void Encode(byte[] output, uint[] input) + { + for (int i = 0, j = 0; j < output.Length; i++, j += 4) + { + output[j] = (byte)(input[i]); + output[j + 1] = (byte)(input[i] >> 8); + output[j + 2] = (byte)(input[i] >> 16); + output[j + 3] = (byte)(input[i] >> 24); + } + } + + private void Decode(uint[] output, byte[] input, int index) + { + for (int i = 0, j = index; i < output.Length; i++, j += 4) + { + output[i] = (uint)((input[j]) | (input[j + 1] << 8) | (input[j + 2] << 16) | (input[j + 3] << 24)); + } + } + + private void MD4Transform(uint[] state, byte[] block, int index) + { + uint a = state[0]; + uint b = state[1]; + uint c = state[2]; + uint d = state[3]; + + Decode(x, block, index); + + /* Round 1 */ + FF(ref a, b, c, d, x[0], S11); /* 1 */ + FF(ref d, a, b, c, x[1], S12); /* 2 */ + FF(ref c, d, a, b, x[2], S13); /* 3 */ + FF(ref b, c, d, a, x[3], S14); /* 4 */ + FF(ref a, b, c, d, x[4], S11); /* 5 */ + FF(ref d, a, b, c, x[5], S12); /* 6 */ + FF(ref c, d, a, b, x[6], S13); /* 7 */ + FF(ref b, c, d, a, x[7], S14); /* 8 */ + FF(ref a, b, c, d, x[8], S11); /* 9 */ + FF(ref d, a, b, c, x[9], S12); /* 10 */ + FF(ref c, d, a, b, x[10], S13); /* 11 */ + FF(ref b, c, d, a, x[11], S14); /* 12 */ + FF(ref a, b, c, d, x[12], S11); /* 13 */ + FF(ref d, a, b, c, x[13], S12); /* 14 */ + FF(ref c, d, a, b, x[14], S13); /* 15 */ + FF(ref b, c, d, a, x[15], S14); /* 16 */ + + /* Round 2 */ + GG(ref a, b, c, d, x[0], S21); /* 17 */ + GG(ref d, a, b, c, x[4], S22); /* 18 */ + GG(ref c, d, a, b, x[8], S23); /* 19 */ + GG(ref b, c, d, a, x[12], S24); /* 20 */ + GG(ref a, b, c, d, x[1], S21); /* 21 */ + GG(ref d, a, b, c, x[5], S22); /* 22 */ + GG(ref c, d, a, b, x[9], S23); /* 23 */ + GG(ref b, c, d, a, x[13], S24); /* 24 */ + GG(ref a, b, c, d, x[2], S21); /* 25 */ + GG(ref d, a, b, c, x[6], S22); /* 26 */ + GG(ref c, d, a, b, x[10], S23); /* 27 */ + GG(ref b, c, d, a, x[14], S24); /* 28 */ + GG(ref a, b, c, d, x[3], S21); /* 29 */ + GG(ref d, a, b, c, x[7], S22); /* 30 */ + GG(ref c, d, a, b, x[11], S23); /* 31 */ + GG(ref b, c, d, a, x[15], S24); /* 32 */ + + HH(ref a, b, c, d, x[0], S31); /* 33 */ + HH(ref d, a, b, c, x[8], S32); /* 34 */ + HH(ref c, d, a, b, x[4], S33); /* 35 */ + HH(ref b, c, d, a, x[12], S34); /* 36 */ + HH(ref a, b, c, d, x[2], S31); /* 37 */ + HH(ref d, a, b, c, x[10], S32); /* 38 */ + HH(ref c, d, a, b, x[6], S33); /* 39 */ + HH(ref b, c, d, a, x[14], S34); /* 40 */ + HH(ref a, b, c, d, x[1], S31); /* 41 */ + HH(ref d, a, b, c, x[9], S32); /* 42 */ + HH(ref c, d, a, b, x[5], S33); /* 43 */ + HH(ref b, c, d, a, x[13], S34); /* 44 */ + HH(ref a, b, c, d, x[3], S31); /* 45 */ + HH(ref d, a, b, c, x[11], S32); /* 46 */ + HH(ref c, d, a, b, x[7], S33); /* 47 */ + HH(ref b, c, d, a, x[15], S34); /* 48 */ + + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + } + } +} diff --git a/JMMFileHelper/MediaInfo.cs b/JMMFileHelper/MediaInfo.cs new file mode 100644 index 000000000..e931033a0 --- /dev/null +++ b/JMMFileHelper/MediaInfo.cs @@ -0,0 +1,128 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Runtime.InteropServices; + +namespace JMMFileHelper +{ + public enum StreamKind + { + General, + Video, + Audio, + Text, + Chapters, + Image + } + + public enum InfoKind + { + Name, + Text, + Measure, + Options, + NameText, + MeasureText, + Info, + HowTo + } + + public enum InfoOptions + { + ShowInInform, + Support, + ShowInSupported, + TypeOfValue + } + + + public class MediaInfo : IDisposable + { + //Import of DLL functions. DO NOT USE until you know what you do (MediaInfo DLL do NOT use CoTaskMemAlloc to allocate memory) + [DllImport("MediaInfo.dll")] + static extern IntPtr MediaInfo_New(); + [DllImport("MediaInfo.dll")] + static extern void MediaInfo_Delete(IntPtr Handle); + [DllImport("MediaInfo.dll")] + static extern int MediaInfo_Open(IntPtr Handle, [MarshalAs(UnmanagedType.LPWStr)] string FileName); + [DllImport("MediaInfo.dll")] + static extern void MediaInfo_Close(IntPtr Handle); + + [DllImport("MediaInfo.dll")] + static extern IntPtr MediaInfo_Get(IntPtr Handle, [MarshalAs(UnmanagedType.U4)] StreamKind StreamKind, uint StreamNumber, [MarshalAs(UnmanagedType.LPWStr)] string Parameter, [MarshalAs(UnmanagedType.U4)] InfoKind KindOfInfo, [MarshalAs(UnmanagedType.U4)] InfoKind KindOfSearch); + + + IntPtr Handle; + + static MediaInfo _instance; + public static MediaInfo GetInstance() + { + if (_instance == null) + return _instance = new MediaInfo(); + else return _instance; + } + + private MediaInfo() + { + try + { + Handle = MediaInfo_New(); + } + catch (Exception ex) + { + //BaseConfig.MyAnimeLog.Write("Error creating the MediaInfo Object, check that MediaInfo.dll is in the windows plugins directory: {0}", ex.Message); + } + } + ~MediaInfo() + { + try + { + if (Handle == IntPtr.Zero) return; + MediaInfo_Delete(Handle); + Handle = IntPtr.Zero; + } + catch (Exception ex) + { + //BaseConfig.MyAnimeLog.Write("Error deleting the MediaInfo Object: {0}", ex.Message); + } + } + + String Get(StreamKind StreamKind, uint StreamNumber, String Parameter, InfoKind KindOfInfo, InfoKind KindOfSearch) { return Marshal.PtrToStringUni(MediaInfo_Get(Handle, StreamKind, StreamNumber, Parameter, KindOfInfo, KindOfSearch)); } + + public String Get(StreamKind StreamKind, uint StreamNumber, String Parameter, InfoKind KindOfInfo) { return Get(StreamKind, StreamNumber, Parameter, KindOfInfo, InfoKind.Name); } + public String Get(StreamKind StreamKind, uint StreamNumber, String Parameter) { return Get(StreamKind, StreamNumber, Parameter, InfoKind.Text, InfoKind.Name); } + + public int Open(String FileName) { return MediaInfo_Open(Handle, FileName); } + public void Close() { MediaInfo_Close(Handle); } + public string getVidCodec() { return this.Get(StreamKind.Video, 0, "Codec"); } + public string getVidBitrate() { return this.Get(StreamKind.Video, 0, "BitRate"); } + public string getWidth() { return this.Get(StreamKind.Video, 0, "Width"); } + public string getHeight() { return this.Get(StreamKind.Video, 0, "Height"); } + public string getAR() { return this.Get(StreamKind.Video, 0, "AspectRatio"); } + public string getPlaytime() { return this.Get(StreamKind.Video, 0, "PlayTime"); } + public string getFPS() { return this.Get(StreamKind.Video, 0, "FrameRate"); } + public string getAudioCount() { return this.Get(StreamKind.Audio, 0, "StreamCount"); } + public string getAudioCodec() { return this.Get(StreamKind.Audio, 0, "Codec"); } + public string getAudioBitrate() { return this.Get(StreamKind.Audio, 0, "BitRate"); } + public string getAudioStreamCount() { return this.Get(StreamKind.Audio, 0, "StreamCount"); } + public string getAudioLanguages() { return this.Get(StreamKind.General, 0, "Audio_Language_List"); } + public string getNoChannels() { return getNoChannels(0); } + public string getNoChannels(int stream) { return this.Get(StreamKind.Audio, (uint)stream, "Channel(s)"); } + public string getTextCount() { return this.Get(StreamKind.General, 0, "TextCount"); } + public string getTextLanguages() { return this.Get(StreamKind.General, 0, "Text_Language_List"); } + public string getDuration() { return this.Get(StreamKind.General, 0, "Duration"); } + + + #region IDisposable Members + + public void Dispose() + { + if (Handle == IntPtr.Zero) return; + MediaInfo_Delete(Handle); + Handle = IntPtr.Zero; + } + + #endregion + } +} diff --git a/JMMFileHelper/MediaInfoReader.cs b/JMMFileHelper/MediaInfoReader.cs new file mode 100644 index 000000000..495160cc2 --- /dev/null +++ b/JMMFileHelper/MediaInfoReader.cs @@ -0,0 +1,75 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.IO; +using NLog; +using JMMContracts; + +namespace JMMFileHelper +{ + public class MediaInfoReader + { + private static Logger logger = LogManager.GetCurrentClassLogger(); + + public static bool ReadMediaInfo(string fileNameFull, bool forceRefresh, ref MediaInfoResult info) + { + try + { + + if (!forceRefresh) + { + // if we have populated the vid res, we have already read the data + if (info.VideoResolution.Length > 0) return false; + } + + MediaInfo mi = MediaInfo.GetInstance(); + + if (mi == null) return false; + if (!File.Exists(fileNameFull)) return false; + + mi.Open(fileNameFull); + string test = mi.getPlaytime(); + if (test.Length > 0) + { + + info.VideoResolution = mi.getWidth() + "x" + mi.getHeight(); + info.VideoCodec = mi.getVidCodec(); + info.VideoBitrate = mi.getVidBitrate(); + info.VideoFrameRate = mi.getFPS(); + info.AudioCodec = mi.getAudioCodec(); + info.AudioBitrate = mi.getAudioBitrate(); + // TODO CreateLanguages(mi.getAudioLanguages(), mi.getTextLanguages()); + int dur = 0; + int.TryParse(mi.getDuration(), out dur); + info.Duration = dur; + + info.VideoCodec = info.VideoCodec.Replace("V_MPEG4/ISO/AVC", "H264"); + info.VideoCodec = info.VideoCodec.Replace("V_MPEG2", "MPEG2"); + info.VideoCodec = info.VideoCodec.Replace("MPEG-2V", "MPEG2"); + info.VideoCodec = info.VideoCodec.Replace("DIV3", "DIVX"); + info.VideoCodec = info.VideoCodec.Replace("DX50", "DIVX"); + + info.AudioCodec = info.AudioCodec.Replace("MPA1L3", "MP3"); + info.AudioCodec = info.AudioCodec.Replace("MPA2L3", "MP3"); + info.AudioCodec = info.AudioCodec.Replace("A_FLAC", "FLAC"); + info.AudioCodec = info.AudioCodec.Replace("A_AAC/MPEG4/LC/SBR", "AAC"); + info.AudioCodec = info.AudioCodec.Replace("A_AAC", "AAC"); + info.AudioCodec = info.AudioCodec.Replace("A_AC3", "AC3"); + } + else + { + logger.Error("ERROR getting media info:: {0}", fileNameFull); + } + mi.Close(); + + } + catch (Exception ex) + { + logger.Error("Error reading Media Info for: {0} --- {1}", fileNameFull, ex.ToString()); + } + + return true; + } + } +} diff --git a/JMMFileHelper/Properties/AssemblyInfo.cs b/JMMFileHelper/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..ec3b5f0cb --- /dev/null +++ b/JMMFileHelper/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("JMMFileHelper")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Microsoft")] +[assembly: AssemblyProduct("JMMFileHelper")] +[assembly: AssemblyCopyright("Copyright © Microsoft 2010")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("20a7958d-a871-4757-9b7e-0ac2d22fb0f7")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/JMMServer.sln b/JMMServer.sln new file mode 100644 index 000000000..947887ab2 --- /dev/null +++ b/JMMServer.sln @@ -0,0 +1,80 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JMMServer", "JMMServer\JMMServer.csproj", "{DA8F0783-0F82-4106-9860-6F09BA2EA522}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Hasher", "hasher\Hasher.vcxproj", "{4AB1249D-D635-48A3-8F82-FAB34B69AE4C}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JMMContracts", "JMMContracts\JMMContracts.csproj", "{D777636B-F927-4C7D-9D00-4A7858E75F3E}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JMMFileHelper", "JMMFileHelper\JMMFileHelper.csproj", "{73E4CFC4-291B-47A2-ACAA-78096CEBB7DF}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|Mixed Platforms = Debug|Mixed Platforms + Debug|Win32 = Debug|Win32 + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|Mixed Platforms = Release|Mixed Platforms + Release|Win32 = Release|Win32 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {DA8F0783-0F82-4106-9860-6F09BA2EA522}.Debug|Any CPU.ActiveCfg = Debug|x86 + {DA8F0783-0F82-4106-9860-6F09BA2EA522}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {DA8F0783-0F82-4106-9860-6F09BA2EA522}.Debug|Mixed Platforms.Build.0 = Debug|x86 + {DA8F0783-0F82-4106-9860-6F09BA2EA522}.Debug|Win32.ActiveCfg = Debug|x86 + {DA8F0783-0F82-4106-9860-6F09BA2EA522}.Debug|x86.ActiveCfg = Debug|x86 + {DA8F0783-0F82-4106-9860-6F09BA2EA522}.Debug|x86.Build.0 = Debug|x86 + {DA8F0783-0F82-4106-9860-6F09BA2EA522}.Release|Any CPU.ActiveCfg = Release|x86 + {DA8F0783-0F82-4106-9860-6F09BA2EA522}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {DA8F0783-0F82-4106-9860-6F09BA2EA522}.Release|Mixed Platforms.Build.0 = Release|x86 + {DA8F0783-0F82-4106-9860-6F09BA2EA522}.Release|Win32.ActiveCfg = Release|x86 + {DA8F0783-0F82-4106-9860-6F09BA2EA522}.Release|x86.ActiveCfg = Release|x86 + {DA8F0783-0F82-4106-9860-6F09BA2EA522}.Release|x86.Build.0 = Release|x86 + {4AB1249D-D635-48A3-8F82-FAB34B69AE4C}.Debug|Any CPU.ActiveCfg = Debug|Win32 + {4AB1249D-D635-48A3-8F82-FAB34B69AE4C}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {4AB1249D-D635-48A3-8F82-FAB34B69AE4C}.Debug|Mixed Platforms.Build.0 = Debug|Win32 + {4AB1249D-D635-48A3-8F82-FAB34B69AE4C}.Debug|Win32.ActiveCfg = Debug|Win32 + {4AB1249D-D635-48A3-8F82-FAB34B69AE4C}.Debug|Win32.Build.0 = Debug|Win32 + {4AB1249D-D635-48A3-8F82-FAB34B69AE4C}.Debug|x86.ActiveCfg = Debug|Win32 + {4AB1249D-D635-48A3-8F82-FAB34B69AE4C}.Release|Any CPU.ActiveCfg = Release|Win32 + {4AB1249D-D635-48A3-8F82-FAB34B69AE4C}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {4AB1249D-D635-48A3-8F82-FAB34B69AE4C}.Release|Mixed Platforms.Build.0 = Release|Win32 + {4AB1249D-D635-48A3-8F82-FAB34B69AE4C}.Release|Win32.ActiveCfg = Release|Win32 + {4AB1249D-D635-48A3-8F82-FAB34B69AE4C}.Release|Win32.Build.0 = Release|Win32 + {4AB1249D-D635-48A3-8F82-FAB34B69AE4C}.Release|x86.ActiveCfg = Release|Win32 + {D777636B-F927-4C7D-9D00-4A7858E75F3E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D777636B-F927-4C7D-9D00-4A7858E75F3E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D777636B-F927-4C7D-9D00-4A7858E75F3E}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {D777636B-F927-4C7D-9D00-4A7858E75F3E}.Debug|Mixed Platforms.Build.0 = Debug|x86 + {D777636B-F927-4C7D-9D00-4A7858E75F3E}.Debug|Win32.ActiveCfg = Debug|x86 + {D777636B-F927-4C7D-9D00-4A7858E75F3E}.Debug|x86.ActiveCfg = Debug|x86 + {D777636B-F927-4C7D-9D00-4A7858E75F3E}.Debug|x86.Build.0 = Debug|x86 + {D777636B-F927-4C7D-9D00-4A7858E75F3E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D777636B-F927-4C7D-9D00-4A7858E75F3E}.Release|Any CPU.Build.0 = Release|Any CPU + {D777636B-F927-4C7D-9D00-4A7858E75F3E}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {D777636B-F927-4C7D-9D00-4A7858E75F3E}.Release|Mixed Platforms.Build.0 = Release|x86 + {D777636B-F927-4C7D-9D00-4A7858E75F3E}.Release|Win32.ActiveCfg = Release|x86 + {D777636B-F927-4C7D-9D00-4A7858E75F3E}.Release|x86.ActiveCfg = Release|x86 + {D777636B-F927-4C7D-9D00-4A7858E75F3E}.Release|x86.Build.0 = Release|x86 + {73E4CFC4-291B-47A2-ACAA-78096CEBB7DF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {73E4CFC4-291B-47A2-ACAA-78096CEBB7DF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {73E4CFC4-291B-47A2-ACAA-78096CEBB7DF}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {73E4CFC4-291B-47A2-ACAA-78096CEBB7DF}.Debug|Mixed Platforms.Build.0 = Debug|x86 + {73E4CFC4-291B-47A2-ACAA-78096CEBB7DF}.Debug|Win32.ActiveCfg = Debug|x86 + {73E4CFC4-291B-47A2-ACAA-78096CEBB7DF}.Debug|x86.ActiveCfg = Debug|x86 + {73E4CFC4-291B-47A2-ACAA-78096CEBB7DF}.Debug|x86.Build.0 = Debug|x86 + {73E4CFC4-291B-47A2-ACAA-78096CEBB7DF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {73E4CFC4-291B-47A2-ACAA-78096CEBB7DF}.Release|Any CPU.Build.0 = Release|Any CPU + {73E4CFC4-291B-47A2-ACAA-78096CEBB7DF}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {73E4CFC4-291B-47A2-ACAA-78096CEBB7DF}.Release|Mixed Platforms.Build.0 = Release|x86 + {73E4CFC4-291B-47A2-ACAA-78096CEBB7DF}.Release|Win32.ActiveCfg = Release|x86 + {73E4CFC4-291B-47A2-ACAA-78096CEBB7DF}.Release|x86.ActiveCfg = Release|x86 + {73E4CFC4-291B-47A2-ACAA-78096CEBB7DF}.Release|x86.Build.0 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/JMMServer/AniDBHelper.cs b/JMMServer/AniDBHelper.cs new file mode 100644 index 000000000..86b07cd00 --- /dev/null +++ b/JMMServer/AniDBHelper.cs @@ -0,0 +1,827 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Net; +using System.Net.Sockets; +using NLog; +using AniDBAPI; +using System.Threading; +using JMMServer.Entities; +using JMMServer.Repositories; +using System.IO; +using AniDBAPI.Commands; +using JMMServer.Commands; +using JMMServer.WebCache; + +namespace JMMServer +{ + public class AniDBHelper + { + private static Logger logger = LogManager.GetCurrentClassLogger(); + + // we use this lock to make don't try and access AniDB too much (UDP and HTTP) + private object lockAniDBConnections = new object(); + + private IPEndPoint localIpEndPoint = null; + private IPEndPoint remoteIpEndPoint = null; + private Socket soUdp = null; + private string curSessionID = string.Empty; + + private bool networkAvailable = true; + + private string userName = string.Empty; + private string password = string.Empty; + private string serverName = string.Empty; + private string serverPort = string.Empty; + private string clientPort = string.Empty; + private Encoding encoding; + + System.Timers.Timer logoutTimer = null; + + public static int AniDBDelay = 2500; + public int CurrentDelay; + + private DateTime? banTime = null; + public DateTime? BanTime + { + get { return banTime; } + set { banTime = value; } + + } + + private bool isBanned = false; + public bool IsBanned + { + get { return isBanned; } + + set + { + isBanned = value; + BanTime = DateTime.Now; + + ServerInfo.Instance.IsBanned = isBanned; + if (isBanned) + { + JMMService.CmdProcessorGeneral.Paused = true; + ServerInfo.Instance.BanReason = BanTime.ToString(); + } + else + ServerInfo.Instance.BanReason = ""; + } + + } + + private bool isLoggedOn = false; + public bool IsLoggedOn + { + get { return isLoggedOn; } + set { isLoggedOn = value; } + + } + + public AniDBHelper() + { + CurrentDelay = AniDBDelay; + } + + public void Init(string userName, string password, string serverName, string serverPort, string clientPort) + { + soUdp = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); + + this.userName = userName; + this.password = password; + this.serverName = serverName; + this.serverPort = serverPort; + this.clientPort = clientPort; + + this.isLoggedOn = false; + + if (!BindToLocalPort()) networkAvailable = false; + if (!BindToRemotePort()) networkAvailable = false; + + logoutTimer = new System.Timers.Timer(); + logoutTimer.Elapsed += new System.Timers.ElapsedEventHandler(logoutTimer_Elapsed); + logoutTimer.Interval = 5000; // Set the Interval to 5 seconds. + logoutTimer.Enabled = true; + logoutTimer.AutoReset = true; + + logger.Info("starting logout timer..."); + logoutTimer.Start(); + } + + public void Dispose() + { + logger.Info("ANIDBLIB DISPOSING..."); + + CloseConnections(); + } + + public void CloseConnections() + { + if (logoutTimer != null) logoutTimer.Stop(); + if (soUdp == null) return; + + soUdp.Shutdown(SocketShutdown.Both); + soUdp.Close(); + } + + void logoutTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) + { + if (!isLoggedOn) return; + + lock (lockAniDBConnections) + { + TimeSpan tsAniDBNonPing = DateTime.Now - JMMService.LastAniDBMessageNonPing; + TimeSpan tsPing = DateTime.Now - JMMService.LastAniDBPing; + TimeSpan tsAniDBUDP = DateTime.Now - JMMService.LastAniDBUDPMessage; + + // if we haven't sent a command for 20 seconds, send a ping just to keep the connection alive + if (tsAniDBUDP.TotalSeconds >= 20 && tsPing.TotalSeconds >= 20 && !IsBanned) + { + AniDBCommand_Ping ping = new AniDBCommand_Ping(); + ping.Init(); + ping.Process(ref soUdp, ref remoteIpEndPoint, curSessionID, new UnicodeEncoding(true, false)); + } + + string msg = string.Format("Last message sent {0} seconds ago", tsAniDBUDP.TotalSeconds); + + if (tsAniDBNonPing.TotalSeconds > 600) // after 10 minutes + { + ForceLogout(); + } + } + } + + private void Pause() + { + // do not send more than one message every 2 (2.4 to make sure) seconds + while (DateTime.Now < JMMService.LastAniDBMessage.AddMilliseconds(2400)) + { + // pretend to do something.... + Thread.Sleep(100); + } + } + + public bool Login() + { + // check if we are already logged in + if (isLoggedOn) return true; + + if (!ValidAniDBCredentials()) return false; + + AniDBCommand_Login login = new AniDBCommand_Login(); + login.Init(userName, password); + + string msg = login.commandText.Replace(userName, "******"); + msg = msg.Replace(password, "******"); + logger.Trace("udp command: {0}", msg); + enHelperActivityType ev = login.Process(ref soUdp, ref remoteIpEndPoint, curSessionID, new UnicodeEncoding(true, false)); + + if (login.errorOccurred) + logger.Trace("error in login: {0}", login.errorMessage); + //else + // logger.Info("socketResponse: {0}", login.socketResponse); + + Thread.Sleep(2200); + + if (ev != enHelperActivityType.LoggedIn) + { + //BaseConfig.MyAnimeLog.Write("ProcessCommands: Login Failed!"); + //OnAniDBStatusEvent(new AniDBStatusEventArgs(enHelperActivityType.LoginFailed, "")); + //aniDBCommands.Clear(); + //OnQueueUpdateEvent(new QueueUpdateEventArgs(this.QueueCount)); + // this will exit the thread + return false; + } + else + { + curSessionID = login.SessionID; + encoding = login.Encoding; + this.isLoggedOn = true; + return true; + } + + + } + + public void ForceLogout() + { + if (isLoggedOn) + { + AniDBCommand_Logout logout = new AniDBCommand_Logout(); + logout.Init(); + //logger.Info("udp command: {0}", logout.commandText); + logout.Process(ref soUdp, ref remoteIpEndPoint, curSessionID, new UnicodeEncoding(true, false)); + //logger.Info("socketResponse: {0}", logout.socketResponse); + isLoggedOn = false; + } + } + + public Raw_AniDB_File GetFileInfo(IHash vidLocal) + { + if (!Login()) return null; + + enHelperActivityType ev = enHelperActivityType.NoSuchFile; + AniDBCommand_GetFileInfo getInfoCmd = null; + + lock (lockAniDBConnections) + { + Pause(); + + getInfoCmd = new AniDBCommand_GetFileInfo(); + getInfoCmd.Init(vidLocal, true); + ev = getInfoCmd.Process(ref soUdp, ref remoteIpEndPoint, curSessionID, new UnicodeEncoding(true, false)); + } + + if (ev == enHelperActivityType.GotFileInfo && getInfoCmd != null && getInfoCmd.fileInfo != null) + { + try + { + logger.Trace("ProcessResult_GetFileInfo: {0}", getInfoCmd.fileInfo.ToString()); + + if (ServerSettings.AniDB_DownloadReleaseGroups) + { + CommandRequest_GetReleaseGroup cmdRelgrp = new CommandRequest_GetReleaseGroup(getInfoCmd.fileInfo.GroupID, false); + cmdRelgrp.Save(); + } + + return getInfoCmd.fileInfo; + } + catch (Exception ex) + { + logger.Error(ex.ToString()); + return null; + } + } + + return null; + } + + public void GetMyListFileStatus(int aniDBFileID) + { + if (!ServerSettings.AniDB_MyList_ReadWatched) return; + + if (!Login()) return; + + lock (lockAniDBConnections) + { + Pause(); + + AniDBCommand_GetMyListFileInfo cmdGetFileStatus = new AniDBCommand_GetMyListFileInfo(); + cmdGetFileStatus.Init(aniDBFileID); + enHelperActivityType ev = cmdGetFileStatus.Process(ref soUdp, ref remoteIpEndPoint, curSessionID, new UnicodeEncoding(true, false)); + } + } + + public bool GetUpdated(ref List updatedAnimeIDs, ref long startTime) + { + startTime = 0; + updatedAnimeIDs = new List(); + + if (!Login()) return false; + + lock (lockAniDBConnections) + { + Pause(); + + AniDBCommand_GetUpdated cmdUpdated = new AniDBCommand_GetUpdated(); + cmdUpdated.Init("1"); + enHelperActivityType ev = cmdUpdated.Process(ref soUdp, ref remoteIpEndPoint, curSessionID, new UnicodeEncoding(true, false)); + + if (ev == enHelperActivityType.GotUpdated && cmdUpdated != null && cmdUpdated.RecordCount > 0) + { + startTime = long.Parse(cmdUpdated.StartTime); + updatedAnimeIDs = cmdUpdated.AnimeIDList; + + // send the results to the web cache + XMLService.Send_AniDBUpdates(cmdUpdated.StartTime, cmdUpdated.AnimeIDListRaw); + + return true; + } + } + + + + return false; + + } + + public void UpdateMyListFileStatus(IHash fileDataLocal, bool watched) + { + if (!ServerSettings.AniDB_MyList_AddFiles) return; + + if (!Login()) return; + + lock (lockAniDBConnections) + { + Pause(); + + AniDBCommand_UpdateFile cmdUpdateFile = new AniDBCommand_UpdateFile(); + cmdUpdateFile.Init(fileDataLocal, watched); + enHelperActivityType ev = cmdUpdateFile.Process(ref soUdp, ref remoteIpEndPoint, curSessionID, new UnicodeEncoding(true, false)); + } + } + + public bool AddFileToMyList(IHash fileDataLocal, ref DateTime? watchedDate) + { + if (!ServerSettings.AniDB_MyList_AddFiles) return false; + + if (!Login()) return false; + + enHelperActivityType ev = enHelperActivityType.NoSuchMyListFile; + AniDBCommand_AddFile cmdAddFile = null; + + lock (lockAniDBConnections) + { + Pause(); + + cmdAddFile = new AniDBCommand_AddFile(); + cmdAddFile.Init(fileDataLocal, ServerSettings.AniDB_MyList_StorageState); + ev = cmdAddFile.Process(ref soUdp, ref remoteIpEndPoint, curSessionID, new UnicodeEncoding(true, false)); + } + + // if the user already has this file on + if (ev == enHelperActivityType.FileAlreadyExists && cmdAddFile.FileData != null) + { + watchedDate = cmdAddFile.WatchedDate; + return cmdAddFile.ReturnIsWatched; + + } + + return false; + } + + public bool DeleteFileFromMyList(string hash, long fileSize) + { + if (!ServerSettings.AniDB_MyList_AddFiles) return false; + + if (!Login()) return false; + + enHelperActivityType ev = enHelperActivityType.NoSuchMyListFile; + AniDBCommand_DeleteFile cmdDelFile = null; + + lock (lockAniDBConnections) + { + Pause(); + + cmdDelFile = new AniDBCommand_DeleteFile(); + cmdDelFile.Init(hash, fileSize); + ev = cmdDelFile.Process(ref soUdp, ref remoteIpEndPoint, curSessionID, new UnicodeEncoding(true, false)); + } + + return true; + } + + public AniDB_Anime GetAnimeInfoUDP(int animeID, bool forceRefresh) + { + AniDB_AnimeRepository repAnime = new AniDB_AnimeRepository(); + AniDB_Anime anime = null; + + bool skip = true; + if (forceRefresh) + skip = false; + else + { + anime = repAnime.GetByAnimeID(animeID); + if (anime == null) skip = false; + } + + if (skip) + { + if (anime == null) + anime = repAnime.GetByAnimeID(animeID); + + return anime; + + } + + if (!Login()) return null; + + enHelperActivityType ev = enHelperActivityType.NoSuchAnime; + AniDBCommand_GetAnimeInfo getAnimeCmd = null; + + lock (lockAniDBConnections) + { + Pause(); + + getAnimeCmd = new AniDBCommand_GetAnimeInfo(); + getAnimeCmd.Init(animeID, forceRefresh); + ev = getAnimeCmd.Process(ref soUdp, ref remoteIpEndPoint, curSessionID, new UnicodeEncoding(true, false)); + } + + if (ev == enHelperActivityType.GotAnimeInfo && getAnimeCmd.AnimeInfo != null) + { + // check for an existing record so we don't over write the description + anime = repAnime.GetByAnimeID(getAnimeCmd.AnimeInfo.AnimeID); + if (anime == null) anime = new AniDB_Anime(); + + anime.PopulateAndSaveFromUDP(getAnimeCmd.AnimeInfo); + } + + return anime; + } + + public AniDB_Character GetCharacterInfoUDP(int charID) + { + if (!Login()) return null; + + enHelperActivityType ev = enHelperActivityType.NoSuchChar; + AniDBCommand_GetCharacterInfo getCharCmd = null; + lock (lockAniDBConnections) + { + Pause(); + + getCharCmd = new AniDBCommand_GetCharacterInfo(); + getCharCmd.Init(charID, true); + ev = getCharCmd.Process(ref soUdp, ref remoteIpEndPoint, curSessionID, new UnicodeEncoding(true, false)); + } + + AniDB_Character chr = null; + if (ev == enHelperActivityType.GotCharInfo && getCharCmd.CharInfo != null) + { + AniDB_CharacterRepository repChar = new AniDB_CharacterRepository(); + chr = repChar.GetByCharID(charID); + if (chr == null) chr = new AniDB_Character(); + + chr.PopulateFromUDP(getCharCmd.CharInfo); + repChar.Save(chr); + } + + return chr; + } + + public AniDB_Creator GetCreatorInfoUDP(int creatorID) + { + if (!Login()) return null; + + enHelperActivityType ev = enHelperActivityType.NoSuchCreator; + AniDBCommand_GetCreatorInfo getCreatorCmd = null; + lock (lockAniDBConnections) + { + Pause(); + + getCreatorCmd = new AniDBCommand_GetCreatorInfo(); + getCreatorCmd.Init(creatorID, true); + ev = getCreatorCmd.Process(ref soUdp, ref remoteIpEndPoint, curSessionID, new UnicodeEncoding(true, false)); + } + + AniDB_Creator chr = null; + if (ev == enHelperActivityType.GotCreatorInfo && getCreatorCmd.CreatorInfo != null) + { + AniDB_CreatorRepository repCreator = new AniDB_CreatorRepository(); + chr = repCreator.GetByCreatorID(creatorID); + if (chr == null) chr = new AniDB_Creator(); + + chr.Populate(getCreatorCmd.CreatorInfo); + repCreator.Save(chr); + } + + return chr; + } + + public AniDB_ReleaseGroup GetReleaseGroupUDP(int groupID) + { + if (!Login()) return null; + + enHelperActivityType ev = enHelperActivityType.NoSuchGroup; + AniDBCommand_GetGroup getCmd = null; + lock (lockAniDBConnections) + { + Pause(); + + getCmd = new AniDBCommand_GetGroup(); + getCmd.Init(groupID); + ev = getCmd.Process(ref soUdp, ref remoteIpEndPoint, curSessionID, new UnicodeEncoding(true, false)); + } + + AniDB_ReleaseGroupRepository repRelGrp = new AniDB_ReleaseGroupRepository(); + AniDB_ReleaseGroup relGroup = null; + if (ev == enHelperActivityType.GotGroup && getCmd.Group != null) + { + relGroup = repRelGrp.GetByGroupID(groupID); + if (relGroup == null) relGroup = new AniDB_ReleaseGroup(); + + relGroup.Populate(getCmd.Group); + repRelGrp.Save(relGroup); + } + + return relGroup; + } + + public GroupStatusCollection GetReleaseGroupStatusUDP(int animeID) + { + if (!Login()) return null; + + enHelperActivityType ev = enHelperActivityType.NoSuchCreator; + AniDBCommand_GetGroupStatus getCmd = null; + lock (lockAniDBConnections) + { + Pause(); + + getCmd = new AniDBCommand_GetGroupStatus(); + getCmd.Init(animeID); + ev = getCmd.Process(ref soUdp, ref remoteIpEndPoint, curSessionID, new UnicodeEncoding(true, false)); + } + + if (ev == enHelperActivityType.GotGroupStatus && getCmd.GrpStatusCollection != null) + { + // delete existing records + AniDB_GroupStatusRepository repGrpStat = new AniDB_GroupStatusRepository(); + AniDB_AnimeRepository repAnime = new AniDB_AnimeRepository(); + AniDB_EpisodeRepository repAniEp = new AniDB_EpisodeRepository(); + AnimeSeriesRepository repSeries = new AnimeSeriesRepository(); + + repGrpStat.DeleteForAnime(animeID); + + // save the records + foreach (Raw_AniDB_GroupStatus raw in getCmd.GrpStatusCollection.Groups) + { + AniDB_GroupStatus grpstat = new AniDB_GroupStatus(raw); + repGrpStat.Save(grpstat); + } + + // updated cached stats + // we don't do it in the save method as it would be too many unecessary updates + logger.Trace("Updating group stats by anime from GetReleaseGroupStatusUDP: {0}", animeID); + StatsCache.Instance.UpdateUsingAnime(animeID); + + if (getCmd.GrpStatusCollection.LatestEpisodeNumber > 0) + { + // update the anime with a record of the latest subbed episode + AniDB_Anime anime = repAnime.GetByAnimeID(animeID); + if (anime != null) + { + anime.LatestEpisodeNumber = getCmd.GrpStatusCollection.LatestEpisodeNumber; + repAnime.Save(anime); + + // check if we have this episode in the database + // if not get it now by updating the anime record + List eps = repAniEp.GetByAnimeIDAndEpisodeNumber(animeID, getCmd.GrpStatusCollection.LatestEpisodeNumber); + if (eps.Count == 0) + { + CommandRequest_GetAnimeHTTP cr_anime = new CommandRequest_GetAnimeHTTP(animeID, true, false); + cr_anime.Save(); + } + + // update the missing episode stats on groups and children + AnimeSeries series = repSeries.GetByAnimeID(animeID); + if (series != null) + { + series.UpdateStats(true, true, true); + //series.TopLevelAnimeGroup.UpdateStatsFromTopLevel(true, true, true); + } + + } + } + } + + return getCmd.GrpStatusCollection; + } + + public CalendarCollection GetCalendarUDP() + { + if (!Login()) return null; + + enHelperActivityType ev = enHelperActivityType.CalendarEmpty; + AniDBCommand_GetCalendar cmd = null; + lock (lockAniDBConnections) + { + Pause(); + + cmd = new AniDBCommand_GetCalendar(); + cmd.Init(); + ev = cmd.Process(ref soUdp, ref remoteIpEndPoint, curSessionID, new UnicodeEncoding(true, false)); + } + + if (ev == enHelperActivityType.GotCalendar && cmd.Calendars != null) + return cmd.Calendars; + + return null; + } + + public AniDB_Review GetReviewUDP(int reviewID) + { + if (!Login()) return null; + + enHelperActivityType ev = enHelperActivityType.NoSuchReview; + AniDBCommand_GetReview cmd = null; + + lock (lockAniDBConnections) + { + Pause(); + + cmd = new AniDBCommand_GetReview(); + cmd.Init(reviewID); + ev = cmd.Process(ref soUdp, ref remoteIpEndPoint, curSessionID, new UnicodeEncoding(true, false)); + } + + AniDB_Review review = null; + if (ev == enHelperActivityType.GotReview && cmd.ReviewInfo != null) + { + AniDB_ReviewRepository repReview = new AniDB_ReviewRepository(); + review = repReview.GetByReviewID(reviewID); + if (review == null) review = new AniDB_Review(); + + review.Populate(cmd.ReviewInfo); + repReview.Save(review); + } + + return review; + } + + public bool VoteAnime(int animeID, decimal voteValue, enAniDBVoteType voteType) + { + if (!Login()) return false; + + enHelperActivityType ev = enHelperActivityType.NoSuchVote; + AniDBCommand_Vote cmdVote = null; + + AniDB_VoteRepository repVotes = new AniDB_VoteRepository(); + + lock (lockAniDBConnections) + { + Pause(); + + cmdVote = new AniDBCommand_Vote(); + cmdVote.Init(animeID, voteValue, voteType); + ev = cmdVote.Process(ref soUdp, ref remoteIpEndPoint, curSessionID, new UnicodeEncoding(true, false)); + if (ev == enHelperActivityType.Voted || ev == enHelperActivityType.VoteUpdated) + { + List dbVotes = repVotes.GetByEntity(cmdVote.EntityID); + AniDB_Vote thisVote = null; + foreach (AniDB_Vote dbVote in dbVotes) + { + // we can only have anime permanent or anime temp but not both + if (cmdVote.VoteType == enAniDBVoteType.Anime || cmdVote.VoteType == enAniDBVoteType.AnimeTemp) + { + if (dbVote.VoteType == (int)enAniDBVoteType.Anime || dbVote.VoteType == (int)enAniDBVoteType.AnimeTemp) + { + thisVote = dbVote; + } + } + else + { + thisVote = dbVote; + } + } + + if (thisVote == null) + { + thisVote = new AniDB_Vote(); + thisVote.EntityID = cmdVote.EntityID; + } + thisVote.VoteType = (int)cmdVote.VoteType; + thisVote.VoteValue = cmdVote.VoteValue; + repVotes.Save(thisVote); + } + } + + return false; + } + + public void VoteAnimeRevoke(int animeID, enAniDBVoteType voteType) + { + VoteAnime(animeID, -1, voteType); + } + + + public AniDB_Anime GetAnimeInfoHTTP(int animeID) + { + return GetAnimeInfoHTTP(animeID, false, true); + } + + public AniDB_Anime GetAnimeInfoHTTP(int animeID, bool forceRefresh, bool downloadRelations) + { + //if (!Login()) return null; + + AniDB_AnimeRepository repAnime = new AniDB_AnimeRepository(); + AniDB_Anime anime = null; + + bool skip = true; + if (forceRefresh) + skip = false; + else + { + anime = repAnime.GetByAnimeID(animeID); + if (anime == null) skip = false; + } + + if (skip) + { + if (anime == null) + anime = repAnime.GetByAnimeID(animeID); + + return anime; + + } + + AniDBHTTPCommand_GetFullAnime getAnimeCmd = null; + lock (lockAniDBConnections) + { + Pause(); + + getAnimeCmd = new AniDBHTTPCommand_GetFullAnime(); + getAnimeCmd.Init(animeID, false); + getAnimeCmd.Process(); + } + + if (getAnimeCmd.Anime != null) + { + //XMLService.Send_AniDB_Anime_Full(getAnimeCmd.AnimeID, getAnimeCmd.XmlResult); + + logger.Trace("cmdResult.Anime: {0}", getAnimeCmd.Anime); + + anime = repAnime.GetByAnimeID(animeID); + if (anime == null) + anime = new AniDB_Anime(); + anime.PopulateAndSaveFromHTTP(getAnimeCmd.Anime, getAnimeCmd.Episodes, getAnimeCmd.Titles, getAnimeCmd.Categories, getAnimeCmd.Tags, + getAnimeCmd.Characters, getAnimeCmd.Relations, getAnimeCmd.SimilarAnime, downloadRelations); + + CommandRequest_DownloadImage cmd = new CommandRequest_DownloadImage(anime.AniDB_AnimeID, JMMImageType.AniDB_Cover, false); + cmd.Save(); + // create AnimeEpisode records for all episodes in this anime + // only if we have a series + AnimeSeriesRepository repSeries = new AnimeSeriesRepository(); + AnimeSeries ser = repSeries.GetByAnimeID(animeID); + if (ser != null) + { + ser.CreateAnimeEpisodes(); + } + + // update cached stats + StatsCache.Instance.UpdateUsingAnime(anime.AnimeID); + + //OnGotAnimeInfoEvent(new GotAnimeInfoEventArgs(getAnimeCmd.Anime.AnimeID)); + + // Request an image download + //MainWindow.imageDownloader.DownloadAniDBCover(getAnimeCmd.Anime.AnimeID, false); + } + + + return anime; + } + + public bool ValidAniDBCredentials() + { + if (string.IsNullOrEmpty(this.userName) || string.IsNullOrEmpty(this.password) || string.IsNullOrEmpty(this.serverName) + || string.IsNullOrEmpty(this.serverPort) || string.IsNullOrEmpty(this.clientPort)) + { + //OnAniDBStatusEvent(new AniDBStatusEventArgs(enHelperActivityType.OtherError, "ERROR: Please enter valid AniDB credentials via Configuration first")); + return false; + } + + return true; + } + + private bool BindToLocalPort() + { + // only do once + //if (localIpEndPoint != null) return false; + localIpEndPoint = null; + + // Dont send Expect 100 requests. These requests arnt always supported by remote internet devices, in which case can cause failure. + System.Net.ServicePointManager.Expect100Continue = false; + + IPHostEntry localHostEntry; + localHostEntry = Dns.GetHostEntry(Dns.GetHostName()); + + + logger.Info("-------- Local IP Addresses --------"); + localIpEndPoint = new IPEndPoint(IPAddress.Any, Convert.ToInt32(clientPort)); + logger.Info("-------- End Local IP Addresses --------"); + + soUdp.Bind(localIpEndPoint); + soUdp.ReceiveTimeout = 30000; // 30 seconds + + logger.Info("BindToLocalPort: Bound to local address: {0} - Port: {1} ({2})", localIpEndPoint.ToString(), clientPort, localIpEndPoint.AddressFamily); + + return true; + } + + private bool BindToRemotePort() + { + // only do once + remoteIpEndPoint = null; + //if (remoteIpEndPoint != null) return true; + + try + { + IPHostEntry remoteHostEntry = Dns.GetHostEntry(serverName); + remoteIpEndPoint = new IPEndPoint(remoteHostEntry.AddressList[0], Convert.ToInt32(serverPort)); + + logger.Info("BindToRemotePort: Bound to local address: " + remoteIpEndPoint.Address.ToString() + " : " + + remoteIpEndPoint.Port.ToString()); + + return true; + } + catch (Exception ex) + { + logger.ErrorException(string.Format("Could not bind to remote port: {0}", ex.ToString()), ex); + return false; + } + + + } + } +} diff --git a/JMMServer/AniDB_API/AniDBHTTPHelper.cs b/JMMServer/AniDB_API/AniDBHTTPHelper.cs new file mode 100644 index 000000000..addc88260 --- /dev/null +++ b/JMMServer/AniDB_API/AniDBHTTPHelper.cs @@ -0,0 +1,759 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Xml; +using JMMServer; +using NLog; +using System.IO; +using JMMServer.AniDB_API.Raws; + +namespace AniDBAPI +{ + public class AniDBHTTPHelper + { + private static Logger logger = LogManager.GetCurrentClassLogger(); + + public static string AnimeURL + { + get + { + return "http://api.anidb.net:9001/httpapi?client=animeplugin&clientver=1&protover=1&request=anime&aid={0}"; // they have said now that this will never change + } + } + + public static string MyListURL + { + get + { + return "http://api.anidb.net:9001/httpapi?client=animeplugin&clientver=1&protover=1&request=mylist&user={0}&pass={1}"; // they have said now that this will never change + } + } + + public static string VotesURL + { + get + { + return "http://api.anidb.net:9001/httpapi?client=animeplugin&clientver=1&protover=1&request=votes&user={0}&pass={1}"; // they have said now that this will never change + } + } + + public static void GetAnime(int animeID, bool createSeriesRecord) + { + try + { + string uri = string.Format(AniDBHTTPHelper.AnimeURL, animeID); + //BaseConfig.MyAnimeLog.Write("GetAnime: {0}", uri); + string xml = APIUtils.DownloadWebPage(uri); + + //BaseConfig.MyAnimeLog.Write("AniDBHTTPHelper.GetAnime: {0}", xml); + + if (xml.Trim().Length == 0) return; + + XmlDocument docAnime = new XmlDocument(); + docAnime.LoadXml(xml); + + ProcessAnimeDetails(docAnime, animeID); + ProcessEpisodes(docAnime, animeID); + + } + catch (Exception ex) + { + //BaseConfig.MyAnimeLog.Write("Error in AniDBHTTPHelper.GetAnime: {0}", ex); + return; + } + } + + public static XmlDocument GetAnimeXMLFromAPI(int animeID, ref string rawXML) + { + try + { + string uri = string.Format(AniDBHTTPHelper.AnimeURL, animeID); + //APIUtils.WriteToLog("GetAnimeXMLFromAPI: " + uri); + rawXML = APIUtils.DownloadWebPage(uri); + + //APIUtils.WriteToLog("GetAnimeXMLFromAPI result: " + rawXML); + + if (rawXML.Trim().Length == 0) return null; + + XmlDocument docAnime = new XmlDocument(); + docAnime.LoadXml(rawXML); + + return docAnime; + } + catch (Exception ex) + { + logger.ErrorException("Error in AniDBHTTPHelper.GetAnimeXMLFromAPI: {0}", ex); + return null; + } + } + + public static XmlDocument GetMyListXMLFromAPI(string username, string password, ref string rawXML) + { + try + { + + //string fileName = @"C:\Projects\SVN\mylist.xml"; + //StreamReader re = File.OpenText(fileName); + //rawXML = re.ReadToEnd(); + //re.Close(); + + + string uri = string.Format(AniDBHTTPHelper.MyListURL, username, password); + rawXML = APIUtils.DownloadWebPage(uri); + + if (rawXML.Trim().Length == 0) return null; + + XmlDocument docAnime = new XmlDocument(); + docAnime.LoadXml(rawXML); + + return docAnime; + } + catch (Exception ex) + { + logger.ErrorException("Error in AniDBHTTPHelper.GetMyListXMLFromAPI: {0}", ex); + return null; + } + } + + public static XmlDocument GetVotesXMLFromAPI(string username, string password, ref string rawXML) + { + try + { + string uri = string.Format(AniDBHTTPHelper.VotesURL, username, password); + rawXML = APIUtils.DownloadWebPage(uri); + + if (rawXML.Trim().Length == 0) return null; + + XmlDocument docAnime = new XmlDocument(); + docAnime.LoadXml(rawXML); + + return docAnime; + } + catch (Exception ex) + { + //BaseConfig.MyAnimeLog.Write("Error in AniDBHTTPHelper.GetAnimeXMLFromAPI: {0}", ex); + return null; + } + } + + public static Raw_AniDB_Anime ProcessAnimeDetails(XmlDocument docAnime, int animeID) + { + // most of the genral anime data will be over written by the UDP command + Raw_AniDB_Anime anime = new Raw_AniDB_Anime(); + anime.AnimeID = animeID; + + // check if there is any data + try + { + string id = docAnime["anime"].Attributes["id"].Value; + } + catch (Exception ex) + { + //BaseConfig.MyAnimeLog.Write("Invalid xml document: {0}", animeID.ToString()); + return null; + } + + anime.Description = TryGetProperty(docAnime, "anime", "description"); + anime.AnimeTypeRAW = TryGetProperty(docAnime, "anime", "type"); + + + string episodecount = TryGetProperty(docAnime, "anime", "episodecount"); + int epCount = 0; + int.TryParse(episodecount, out epCount); + anime.EpisodeCount = epCount; + anime.EpisodeCountNormal = epCount; + + int convertedAirDate = Utils.GetAniDBDateAsSeconds(TryGetProperty(docAnime, "anime", "startdate")); + int convertedEndDate = Utils.GetAniDBDateAsSeconds(TryGetProperty(docAnime, "anime", "enddate")); + + //anime.AirDate = TryGetProperty(docAnime, "anime", "startdate"); + //anime.EndDate = TryGetProperty(docAnime, "anime", "enddate"); + + anime.AirDate = Utils.GetAniDBDateAsDate(convertedAirDate); + anime.EndDate = Utils.GetAniDBDateAsDate(convertedEndDate); + + anime.BeginYear = anime.AirDate.HasValue ? anime.AirDate.Value.Year : 0; + anime.EndYear = anime.EndDate.HasValue ? anime.EndDate.Value.Year : 0; + + //string enddate = TryGetProperty(docAnime, "anime", "enddate"); + + string restricted = docAnime["anime"].Attributes["restricted"].Value; + bool res = false; + bool.TryParse(restricted, out res); + anime.Restricted = res ? 1 : 0; + + anime.URL = TryGetProperty(docAnime, "anime", "url"); + anime.Picname = TryGetProperty(docAnime, "anime", "picture"); + + anime.DateTimeUpdated = DateTime.Now; + anime.DateTimeDescUpdated = anime.DateTimeUpdated; + anime.ImageEnabled = 1; + + #region Related Anime + if (docAnime["anime"]["relatedanime"] != null) + { + XmlNodeList raItems = docAnime["anime"]["relatedanime"].GetElementsByTagName("anime"); + if (raItems != null) + { + anime.RelatedAnimeIdsRAW = ""; + anime.RelatedAnimeTypesRAW = ""; + + foreach (XmlNode node in raItems) + { + try + { + int id = int.Parse(node.Attributes["id"].Value); + int relType = ConvertReltTypeTextToEnum(TryGetAttribute(node, "type")); + + if (anime.RelatedAnimeIdsRAW.Length > 0) anime.RelatedAnimeIdsRAW += "'"; + if (anime.RelatedAnimeTypesRAW.Length > 0) anime.RelatedAnimeTypesRAW += "'"; + + anime.RelatedAnimeIdsRAW += id.ToString(); + anime.RelatedAnimeTypesRAW += relType.ToString(); + + } + catch (Exception ex) + { + //BaseConfig.MyAnimeLog.Write("Error in GetEpisodes: {0}", ex); + } + } + } + } + #endregion + + #region Titles + if (docAnime["anime"]["titles"] != null) + { + XmlNodeList titleItems = docAnime["anime"]["titles"].GetElementsByTagName("title"); + if (titleItems != null) + { + foreach (XmlNode node in titleItems) + { + try + { + string titleType = node.Attributes["type"].Value.Trim().ToLower(); + string languageType = node.Attributes["xml:lang"].Value.Trim().ToLower(); + string titleValue = node.InnerText.Trim(); + + if (titleType.Trim().ToUpper() == "MAIN") + { + anime.MainTitle = titleValue; + } + } + catch (Exception ex) + { + //BaseConfig.MyAnimeLog.Write("Error in GetEpisodes: {0}", ex); + } + } + + } + } + #endregion + + #region Ratings + + // init ratings + anime.VoteCount = 0; + anime.TempVoteCount = 0; + anime.Rating = 0; + anime.TempRating = 0; + anime.ReviewCount = 0; + anime.AvgReviewRating = 0; + + if (docAnime["anime"]["ratings"] != null) + { + XmlNodeList ratingItems = docAnime["anime"]["ratings"].ChildNodes; + if (ratingItems != null) + { + foreach (XmlNode node in ratingItems) + { + try + { + if (node.Name.Trim().ToLower() == "permanent") + { + int iCount = 0; + int.TryParse(TryGetAttribute(node, "count"), out iCount); + anime.VoteCount = iCount; + + decimal iRating = 0; + decimal.TryParse(node.InnerText.Trim(), out iRating); + anime.Rating = (int)(iRating * 100); + } + if (node.Name.Trim().ToLower() == "temporary") + { + int iCount = 0; + int.TryParse(TryGetAttribute(node, "count"), out iCount); + anime.TempVoteCount = iCount; + + decimal iRating = 0; + decimal.TryParse(node.InnerText.Trim(), out iRating); + anime.TempRating = (int)(iRating * 100); + } + if (node.Name.Trim().ToLower() == "review") + { + int iCount = 0; + int.TryParse(TryGetAttribute(node, "count"), out iCount); + anime.ReviewCount = iCount; + + decimal iRating = 0; + decimal.TryParse(node.InnerText.Trim(), out iRating); + anime.AvgReviewRating = (int)(iRating * 100); + } + + } + catch (Exception ex) + { + //BaseConfig.MyAnimeLog.Write("Error in GetEpisodes: {0}", ex); + } + } + } + } + #endregion + + //anime.VersionNumber = Raw_AniDB_Anime.LastVersion; + //BaseConfig.MyAnimeLog.Write("Anime: {0}", anime.ToString()); + return anime; + //anime.Save(true, createSeriesRecord); + + //AniDB_Anime.UpdateDescription(anime.AnimeID, anime.Description); + } + + public static List GetEpisodes(int animeID) + { + string xmlResult = ""; + XmlDocument docAnime = GetAnimeXMLFromAPI(animeID, ref xmlResult); + if (docAnime == null) + return null; + return ProcessEpisodes(docAnime, animeID); + } + + public static List ProcessCategories(XmlDocument docAnime, int animeID) + { + List categories = new List(); + + try + { + if (docAnime["anime"]["categories"] != null) + { + XmlNodeList categoryItems = docAnime["anime"]["categories"].GetElementsByTagName("category"); + if (categoryItems != null) + { + foreach (XmlNode node in categoryItems) + { + try + { + Raw_AniDB_Category category = new Raw_AniDB_Category(); + category.ProcessFromHTTPResult(node, animeID); + categories.Add(category); + } + catch (Exception ex) + { + //BaseConfig.MyAnimeLog.Write("Error in GetEpisodes: {0}", ex); + } + } + } + } + } + catch (Exception ex) + { + logger.ErrorException("Error in AniDBHTTPHelper.ProcessCategories: {0}", ex); + return null; + } + + return categories; + } + + public static List ProcessTags(XmlDocument docAnime, int animeID) + { + List tags = new List(); + + try + { + if (docAnime["anime"]["tags"] != null) + { + XmlNodeList tagItems = docAnime["anime"]["tags"].GetElementsByTagName("tag"); + if (tagItems != null) + { + foreach (XmlNode node in tagItems) + { + try + { + Raw_AniDB_Tag tag = new Raw_AniDB_Tag(); + tag.ProcessFromHTTPResult(node, animeID); + tags.Add(tag); + } + catch (Exception ex) + { + //BaseConfig.MyAnimeLog.Write("Error in GetEpisodes: {0}", ex); + } + } + } + } + } + catch (Exception ex) + { + logger.ErrorException("Error in AniDBHTTPHelper.ProcessTags: {0}", ex); + return null; + } + + return tags; + } + + public static List ProcessCharacters(XmlDocument docAnime, int animeID) + { + List chars = new List(); + + try + { + if (docAnime["anime"]["characters"] != null) + { + XmlNodeList charItems = docAnime["anime"]["characters"].GetElementsByTagName("character"); + if (charItems != null) + { + foreach (XmlNode node in charItems) + { + try + { + Raw_AniDB_Character chr = new Raw_AniDB_Character(); + chr.ProcessFromHTTPResult(node, animeID); + chars.Add(chr); + } + catch (Exception ex) + { + //BaseConfig.MyAnimeLog.Write("Error in GetEpisodes: {0}", ex); + } + } + } + } + } + catch (Exception ex) + { + logger.ErrorException("Error in AniDBHTTPHelper.ProcessCharacters: {0}", ex); + return null; + } + + return chars; + } + + public static List ProcessTitles(XmlDocument docAnime, int animeID) + { + List titles = new List(); + + try + { + if (docAnime["anime"]["titles"] != null) + { + XmlNodeList titleItems = docAnime["anime"]["titles"].GetElementsByTagName("title"); + if (titleItems != null) + { + foreach (XmlNode node in titleItems) + { + try + { + Raw_AniDB_Anime_Title animeTitle = new Raw_AniDB_Anime_Title(); + animeTitle.ProcessFromHTTPResult(node, animeID); + titles.Add(animeTitle); + } + catch (Exception ex) + { + //BaseConfig.MyAnimeLog.Write("Error in GetEpisodes: {0}", ex); + } + } + } + } + } + catch (Exception ex) + { + string msg = string.Format("Error in AniDBHTTPHelper.ProcessTitles: {0} - {1}", animeID, ex.ToString()); + logger.ErrorException(msg, ex); + return null; + } + + return titles; + } + + public static List ProcessRelations(XmlDocument docAnime, int animeID) + { + List rels = new List(); + + try + { + if (docAnime["anime"]["relatedanime"] != null) + { + XmlNodeList relItems = docAnime["anime"]["relatedanime"].GetElementsByTagName("anime"); + if (relItems != null) + { + foreach (XmlNode node in relItems) + { + try + { + Raw_AniDB_RelatedAnime rel = new Raw_AniDB_RelatedAnime(); + rel.ProcessFromHTTPResult(node, animeID); + rels.Add(rel); + } + catch (Exception ex) + { + //BaseConfig.MyAnimeLog.Write("Error in GetEpisodes: {0}", ex); + } + } + } + } + } + catch (Exception ex) + { + logger.ErrorException("Error in AniDBHTTPHelper.ProcessRelations: {0}", ex); + return null; + } + + return rels; + } + + public static List ProcessSimilarAnime(XmlDocument docAnime, int animeID) + { + List rels = new List(); + + try + { + if (docAnime["anime"]["similaranime"] != null) + { + XmlNodeList simItems = docAnime["anime"]["similaranime"].GetElementsByTagName("anime"); + if (simItems != null) + { + foreach (XmlNode node in simItems) + { + try + { + Raw_AniDB_SimilarAnime sim = new Raw_AniDB_SimilarAnime(); + sim.ProcessFromHTTPResult(node, animeID); + rels.Add(sim); + } + catch (Exception ex) + { + //BaseConfig.MyAnimeLog.Write("Error in GetEpisodes: {0}", ex); + } + } + } + } + } + catch (Exception ex) + { + logger.ErrorException("Error in AniDBHTTPHelper.ProcessSimilarAnime: {0}", ex); + return null; + } + + return rels; + } + + public static List ProcessEpisodes(XmlDocument docAnime, int animeID) + { + List eps = new List(); + + try + { + if (docAnime != null && docAnime["anime"] != null && docAnime["anime"]["episodes"] != null) + { + XmlNodeList episodeItems = docAnime["anime"]["episodes"].GetElementsByTagName("episode"); + + foreach (XmlNode node in episodeItems) + { + try + { + Raw_AniDB_Episode ep = new Raw_AniDB_Episode(); + ep.ProcessEpisodeSource(node, animeID); + eps.Add(ep); + } + catch (Exception ex) + { + //BaseConfig.MyAnimeLog.Write("Error in ProcessEpisodes: {0}", ex); + } + } + } + } + catch (Exception ex) + { + logger.ErrorException("Error in AniDBHTTPHelper.ProcessEpisodes: {0}", ex); + return null; + } + + return eps; + } + + public static List ProcessMyList(XmlDocument docAnime) + { + List mylistentries = new List(); + + try + { + if (docAnime != null && docAnime["mylist"] != null) + { + XmlNodeList myitems = docAnime["mylist"].GetElementsByTagName("mylistitem"); + + foreach (XmlNode node in myitems) + { + try + { + Raw_AniDB_MyListFile mylistitem = new Raw_AniDB_MyListFile(); + mylistitem.ProcessHTTPSource(node); + mylistentries.Add(mylistitem); + } + catch (Exception ex) + { + + logger.ErrorException("Error in ProcessEpisodes: {0}" + ex.ToString(), ex); + } + } + } + } + catch (Exception ex) + { + logger.ErrorException("Error in AniDBHTTPHelper.ProcessMyList: {0}", ex); + return null; + } + + return mylistentries; + } + + public static List ProcessVotes(XmlDocument docAnime) + { + List myvotes = new List(); + + if (docAnime != null && docAnime["votes"] != null) + { + // get the permanent anime votes + XmlNodeList myitems = null; + try + { + myitems = docAnime["votes"]["anime"].GetElementsByTagName("vote"); + foreach (XmlNode node in myitems) + { + Raw_AniDB_Vote_HTTP thisVote = new Raw_AniDB_Vote_HTTP(); + thisVote.ProcessAnime(node); + myvotes.Add(thisVote); + } + } + catch { } + + // get the temporary anime votes + try + { + myitems = docAnime["votes"]["animetemporary"].GetElementsByTagName("vote"); + foreach (XmlNode node in myitems) + { + Raw_AniDB_Vote_HTTP thisVote = new Raw_AniDB_Vote_HTTP(); + thisVote.ProcessAnimeTemp(node); + myvotes.Add(thisVote); + } + } + catch { } + + // get the episode votes + try + { + myitems = docAnime["votes"]["episode"].GetElementsByTagName("vote"); + foreach (XmlNode node in myitems) + { + + Raw_AniDB_Vote_HTTP thisVote = new Raw_AniDB_Vote_HTTP(); + thisVote.ProcessEpisode(node); + myvotes.Add(thisVote); + + } + } + catch { } + } + + return myvotes; + } + + public static int ConvertReltTypeTextToEnum(string relType) + { + if (relType.Trim().ToLower() == "sequel") return 1; + if (relType.Trim().ToLower() == "prequel") return 2; + if (relType.Trim().ToLower() == "same setting") return 11; + if (relType.Trim().ToLower() == "alternative setting") return 21; + if (relType.Trim().ToLower() == "alternative version") return 32; + if (relType.Trim().ToLower() == "music video") return 41; + if (relType.Trim().ToLower() == "character") return 42; + if (relType.Trim().ToLower() == "side story") return 51; + if (relType.Trim().ToLower() == "parent story") return 52; + if (relType.Trim().ToLower() == "summary") return 61; + if (relType.Trim().ToLower() == "full story") return 62; + + return 100; + } + + public static string TryGetProperty(XmlDocument doc, string keyName, string propertyName) + { + try + { + string prop = doc[keyName][propertyName].InnerText.Trim(); + return prop; + } + catch { } + + return ""; + } + + public static string TryGetProperty(XmlNode node, string propertyName) + { + try + { + string prop = node[propertyName].InnerText.Trim(); + return prop; + } + catch { } + + return ""; + } + + + public static string TryGetPropertyWithAttribute(XmlNode node, string propertyName, string attName, string attValue) + { + try + { + string prop = ""; + foreach (XmlNode nodeChild in node.ChildNodes) + { + if (nodeChild.Name == propertyName) + { + if (nodeChild.Attributes[attName].Value == attValue) + { + prop = nodeChild.InnerText.Trim(); + } + } + } + + return prop; + } + catch { } + + return ""; + } + + public static string TryGetAttribute(XmlNode parentnode, string nodeName, string attName) + { + try + { + string prop = parentnode[nodeName].Attributes[attName].Value; + return prop; + } + catch { } + + return ""; + } + + public static string TryGetAttribute(XmlNode node, string attName) + { + try + { + string prop = node.Attributes[attName].Value; + return prop; + } + catch { } + + return ""; + } + + + } +} diff --git a/JMMServer/AniDB_API/AniDBLib.cs b/JMMServer/AniDB_API/AniDBLib.cs new file mode 100644 index 000000000..dfec55f54 --- /dev/null +++ b/JMMServer/AniDB_API/AniDBLib.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace AniDBAPI +{ + public class AniDBAPILib + { + public static int ProcessAniDBInt(string fld) + { + int iVal = 0; + int.TryParse(fld, out iVal); + return iVal; + } + + public static string ProcessAniDBString(string fld) + { + string ret = fld.Trim(); + + // remove any html + ret = ret.Replace(@"
", "."); + ret = ret.Replace(@"< /br>", "."); + ret = ret.Replace(@"", "."); + ret = ret.Replace(@"
", "."); + ret = ret.Replace(@"
", "."); + + return ret; + } + } + + +} diff --git a/JMMServer/AniDB_API/Calendar.cs b/JMMServer/AniDB_API/Calendar.cs new file mode 100644 index 000000000..9732017fa --- /dev/null +++ b/JMMServer/AniDB_API/Calendar.cs @@ -0,0 +1,110 @@ +using System; +using System.Collections.Generic; +using System.Text; +using JMMServer; + +namespace AniDBAPI +{ + public class Calendar + { + private int animeID; + public int AnimeID + { + get { return animeID; } + set { animeID = value; } + } + + private DateTime? releaseDate = DateTime.Now; + public DateTime? ReleaseDate + { + get { return releaseDate; } + set { releaseDate = value; } + } + + private string releaseDateRaw = ""; + public string ReleaseDateRaw + { + get { return releaseDateRaw; } + set { releaseDateRaw = value; } + } + + private int dateFlags = 0; + public int DateFlags + { + get { return dateFlags; } + set { dateFlags = value; } + } + + public override string ToString() + { + return string.Format("Calendar - AnimeID: {0}...Release Date: {1}({2})...Flags: {3}", animeID, releaseDateRaw, releaseDate, dateFlags); + } + } + + public class CalendarCollection + { + private List calendars = new List(); + public List Calendars + { + get { return calendars; } + } + public CalendarCollection(string sRecMessage) + { + /* + // 297 CALENDAR + 6622|1251417600|0 + 6551|1251417600|0 + 6652|1252108800|0 + 6635|1252540800|0 + 6698|1252627200|0 + 6489|1253145600|0 + 6653|1253750400|0 + 6684|1253836800|0 + 6781|1253836800|0 + 6763|1253923200|0 + */ + + // DateFlags + // 0 = normal start and end date (2010-01-31) + // 1 = start date is year-month (2010-01) + // 2 = start date is a year (2010) + // 4 = normal start date, year-month end date + // 8 = normal start date, year end date + // 10 = start date is a year (2010) + // 16 = normal start and end date (2010-01-31) + + + // remove the header info + string[] sDetails = sRecMessage.Substring(0).Split('\n'); + + if (sDetails.Length <= 2) return; + + for (int i = 1; i < sDetails.Length - 1; i++) // first item will be the status command, and last will be empty + { + //BaseConfig.MyAnimeLog.Write("s: {0}", sDetails[i]); + + Calendar cal = new Calendar(); + + string[] flds = sDetails[i].Substring(0).Split('|'); + cal.AnimeID = int.Parse(flds[0]); + cal.ReleaseDateRaw = flds[1]; + cal.DateFlags = int.Parse(flds[2]); + cal.ReleaseDate = Utils.GetAniDBDateAsDate(flds[1], cal.DateFlags); + + calendars.Add(cal); + + //BaseConfig.MyAnimeLog.Write("grp: {0}", grp); + } + } + + public override string ToString() + { + string ret = ""; + foreach (Calendar cal in calendars) + { + ret += cal.ToString() + Environment.NewLine; + } + return ret; + } + } +} diff --git a/JMMServer/AniDB_API/Commands/AniDBCommand_AddFile.cs b/JMMServer/AniDB_API/Commands/AniDBCommand_AddFile.cs new file mode 100644 index 000000000..0e170be0d --- /dev/null +++ b/JMMServer/AniDB_API/Commands/AniDBCommand_AddFile.cs @@ -0,0 +1,95 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Net.Sockets; +using System.Net; + +namespace AniDBAPI.Commands +{ + public class AniDBCommand_AddFile : AniDBUDPCommand, IAniDBUDPCommand + { + public IHash FileData = null; + public bool ReturnIsWatched = false; + public DateTime? WatchedDate = null; + + public string GetKey() + { + return "AniDBCommand_UpdateFile" + FileData.ED2KHash; + } + + public virtual enHelperActivityType GetStartEventType() + { + return enHelperActivityType.AddingFile; + } + + public virtual enHelperActivityType Process(ref Socket soUDP, + ref IPEndPoint remoteIpEndPoint, string sessionID, Encoding enc) + { + ProcessCommand(ref soUDP, ref remoteIpEndPoint, sessionID, enc); + + // handle 555 BANNED and 598 - UNKNOWN COMMAND + if (ResponseCode == 598) return enHelperActivityType.UnknownCommand; + if (ResponseCode == 555) return enHelperActivityType.Banned; + + if (errorOccurred) return enHelperActivityType.NoSuchFile; + + string sMsgType = socketResponse.Substring(0, 3); + switch (sMsgType) + { + case "210": + return enHelperActivityType.FileAdded; + case "310": + { + //file already exists: read 'watched' status + string[] arrResult = socketResponse.Split('\n'); + if (arrResult.Length >= 2) + { + string[] arrStatus = arrResult[1].Split('|'); + int viewdate = int.Parse(arrStatus[7]); + ReturnIsWatched = (viewdate > 0); + + DateTime utcDate = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); + utcDate = utcDate.AddSeconds(viewdate); + + WatchedDate = utcDate.ToLocalTime(); + } + } + return enHelperActivityType.FileAlreadyExists; + case "311": + return enHelperActivityType.UpdatingFile; + case "320": + return enHelperActivityType.NoSuchFile; + case "411": + return enHelperActivityType.NoSuchFile; + + case "502": + return enHelperActivityType.LoginFailed; + case "501": + { + return enHelperActivityType.LoginRequired; + } + + } + + return enHelperActivityType.FileDoesNotExist; + } + + public AniDBCommand_AddFile() + { + commandType = enAniDBCommandType.AddFile; + } + + public void Init(IHash fileData, AniDBFileStatus FileStatus) + { + FileData = fileData; + + commandID = fileData.Info; + + commandText = "MYLISTADD size=" + fileData.FileSize.ToString(); + commandText += "&ed2k=" + fileData.ED2KHash; + commandText += "&viewed=0"; + commandText += "&state=" + (int)FileStatus; + } + } +} diff --git a/JMMServer/AniDB_API/Commands/AniDBCommand_DeleteFile.cs b/JMMServer/AniDB_API/Commands/AniDBCommand_DeleteFile.cs new file mode 100644 index 000000000..3fc78b4de --- /dev/null +++ b/JMMServer/AniDB_API/Commands/AniDBCommand_DeleteFile.cs @@ -0,0 +1,69 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Net.Sockets; +using System.Net; + +namespace AniDBAPI.Commands +{ + public class AniDBCommand_DeleteFile : AniDBUDPCommand, IAniDBUDPCommand + { + public string Hash = ""; + public long FileSize = 0; + + public string GetKey() + { + return "AniDBCommand_DeleteFile" + Hash; + } + + public virtual enHelperActivityType GetStartEventType() + { + return enHelperActivityType.DeletingFile; + } + + public virtual enHelperActivityType Process(ref Socket soUDP, + ref IPEndPoint remoteIpEndPoint, string sessionID, Encoding enc) + { + ProcessCommand(ref soUDP, ref remoteIpEndPoint, sessionID, enc); + + // handle 555 BANNED and 598 - UNKNOWN COMMAND + if (ResponseCode == 598) return enHelperActivityType.UnknownCommand; + if (ResponseCode == 555) return enHelperActivityType.Banned; + + if (errorOccurred) return enHelperActivityType.NoSuchFile; + + string sMsgType = socketResponse.Substring(0, 3); + switch (sMsgType) + { + case "211": + return enHelperActivityType.FileDeleted; + case "411": + return enHelperActivityType.NoSuchFile; + case "502": + return enHelperActivityType.LoginFailed; + case "501": + return enHelperActivityType.LoginRequired; + + } + + return enHelperActivityType.NoSuchFile; + } + + public AniDBCommand_DeleteFile() + { + commandType = enAniDBCommandType.DeleteFile; + } + + public void Init(string hash, long fileSize) + { + Hash = hash; + FileSize = fileSize; + + commandID = "Deleting File: " + Hash; + + commandText = "MYLISTDEL size=" + FileSize.ToString(); + commandText += "&ed2k=" + Hash; + } + } +} diff --git a/JMMServer/AniDB_API/Commands/AniDBCommand_GetAnimeDescription.cs b/JMMServer/AniDB_API/Commands/AniDBCommand_GetAnimeDescription.cs new file mode 100644 index 000000000..40ac1e19b --- /dev/null +++ b/JMMServer/AniDB_API/Commands/AniDBCommand_GetAnimeDescription.cs @@ -0,0 +1,99 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Net.Sockets; +using System.Net; + +namespace AniDBAPI.Commands +{ + public class AniDBCommand_GetAnimeDescription : AniDBUDPCommand, IAniDBUDPCommand + { + private int animeID; + public int AnimeID + { + get { return animeID; } + set { animeID = value; } + } + + public string GetKey() + { + return "AniDBCommand_GetAnimeDescription" + AnimeID.ToString(); + } + + private Raw_AniDB_AnimeDesc animeDesc; + public Raw_AniDB_AnimeDesc AnimeDesc + { + get { return animeDesc; } + set { animeDesc = value; } + } + + public virtual enHelperActivityType GetStartEventType() + { + return enHelperActivityType.GettingAnimeDesc; + } + + public virtual enHelperActivityType Process(ref Socket soUDP, + ref IPEndPoint remoteIpEndPoint, string sessionID, Encoding enc) + { + ProcessCommand(ref soUDP, ref remoteIpEndPoint, sessionID, enc); + + // handle 555 BANNED and 598 - UNKNOWN COMMAND + if (ResponseCode == 598) return enHelperActivityType.UnknownCommand; + if (ResponseCode == 555) return enHelperActivityType.Banned; + + if (errorOccurred) return enHelperActivityType.NoSuchAnime; + + //BaseConfig.MyAnimeLog.Write("AniDBCommand_GetAnimeDescription.Process: Response: {0}", socketResponse); + + // Process Response + string sMsgType = socketResponse.Substring(0, 3); + + + switch (sMsgType) + { + case "233": + { + // 233 ANIMEDESC + // the first 11 characters should be "240 EPISODE" + // the rest of the information should be the data list + + animeDesc = new Raw_AniDB_AnimeDesc(socketResponse); + return enHelperActivityType.GotAnimeDesc; + + } + case "330": + { + return enHelperActivityType.NoSuchAnime; + } + case "333": // no such description + { + return enHelperActivityType.NoSuchAnime; + } + case "501": + { + return enHelperActivityType.LoginRequired; + } + } + + return enHelperActivityType.FileDoesNotExist; + + } + + public AniDBCommand_GetAnimeDescription() + { + commandType = enAniDBCommandType.GetAnimeDescription; + } + + public void Init(int animeID) + { + this.animeID = animeID; + commandText = "ANIMEDESC aid=" + animeID.ToString(); + commandText += "&part=0"; + + //BaseConfig.MyAnimeLog.Write("AniDBCommand_GetAnimeDescription.Process: Request: {0}", commandText); + + commandID = animeID.ToString(); + } + } +} diff --git a/JMMServer/AniDB_API/Commands/AniDBCommand_GetAnimeInfo.cs b/JMMServer/AniDB_API/Commands/AniDBCommand_GetAnimeInfo.cs new file mode 100644 index 000000000..a7533b6e2 --- /dev/null +++ b/JMMServer/AniDB_API/Commands/AniDBCommand_GetAnimeInfo.cs @@ -0,0 +1,140 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Net; +using System.Net.Sockets; + +namespace AniDBAPI.Commands +{ + public class AniDBCommand_GetAnimeInfo : AniDBUDPCommand, IAniDBUDPCommand + { + private Raw_AniDB_Anime animeInfo = null; //AniDB_Anime + public Raw_AniDB_Anime AnimeInfo + { + get { return animeInfo; } + set { animeInfo = value; } + } + + private int animeID; + public int AnimeID + { + get { return animeID; } + set { animeID = value; } + } + + private bool forceRefresh = false; + public bool ForceRefresh + { + get { return forceRefresh; } + set { forceRefresh = value; } + } + + public string GetKey() + { + return "AniDBCommand_GetAnimeInfo_" + AnimeID.ToString(); + } + + public virtual enHelperActivityType GetStartEventType() + { + return enHelperActivityType.GettingAnimeInfo; + } + + public virtual enHelperActivityType Process(ref Socket soUDP, + ref IPEndPoint remoteIpEndPoint, string sessionID, Encoding enc) + { + ProcessCommand(ref soUDP, ref remoteIpEndPoint, sessionID, enc); + + // handle 555 BANNED and 598 - UNKNOWN COMMAND + if (ResponseCode == 598) return enHelperActivityType.UnknownCommand; + if (ResponseCode == 555) return enHelperActivityType.Banned; + + if (errorOccurred) return enHelperActivityType.NoSuchAnime; + + //BaseConfig.MyAnimeLog.Write("AniDBCommand_GetAnimeInfo.Process: Response: {0}", socketResponse); + + // Process Response + string sMsgType = socketResponse.Substring(0, 3); + + + switch (sMsgType) + { + case "230": + { + // 230 FILE INFO + // the first 9 characters should be "230 ANIME " + // the rest of the information should be the data list + animeInfo = new Raw_AniDB_Anime(socketResponse); + return enHelperActivityType.GotAnimeInfo; + } + case "330": + { + return enHelperActivityType.NoSuchAnime; + } + case "501": + { + return enHelperActivityType.LoginRequired; + } + } + + return enHelperActivityType.FileDoesNotExist; + + } + + public AniDBCommand_GetAnimeInfo() + { + commandType = enAniDBCommandType.GetAnimeInfo; + } + + public void Init(int animeID, bool force) + { + /* + // 1 int4 aid + // 2 int4 episodes + // 4 int4 normal ep count + // 16 int4 rating + // 32 int4 vote count + // 64 int4 temp rating + // 128 int4 temp vote count + // 1024 int4 air date + // 2048 int4 end date + // 65536 str url + // 131072 str picname + // 262144 str year + // 524288 str type + // 1048576 str romaji name + // 4194304 str english name + // 67108864 str category list + // 1073741824 str award list + + commandText = "ANIME aid=" + animeID.ToString(); + commandText += "&acode=1147079927"; + + BaseConfig.MyAnimeLog.Write("AniDBCommand_GetAnimeInfo.Process: Request: {0}", commandText); + + commandID = animeID.ToString(); + */ + + this.animeID = animeID; + this.forceRefresh = force; + + + //v0.3 + int aByte1 = 191; // amask - byte1 + int aByte2 = 252; // amask - byte2 old 188 new 252 Added Kanji Name + int aByte3 = 255; // amask - byte3 + int aByte4 = 255; // amask - byte4 old 252 new 255 Added Award List and 18+ Restricted + int aByte5 = 241; // amask - byte5 old 0 new 241 (Added AnimePlanetID/ANN ID/AllCinema ID/AnimeNfo ID/LastUpdate + int aByte6 = 136; // amask - byte6 + + + commandID = animeID.ToString(); + + commandText = "ANIME aid=" + animeID.ToString(); + commandText += string.Format("&amask={0}{1}{2}{3}{4}{5}", aByte1.ToString("X").PadLeft(2, '0'), aByte2.ToString("X").PadLeft(2, '0'), + aByte3.ToString("X").PadLeft(2, '0'), aByte4.ToString("X").PadLeft(2, '0'), aByte5.ToString("X").PadLeft(2, '0'), aByte6.ToString("X").PadLeft(2, '0')); + + //BaseConfig.MyAnimeLog.Write(commandText); + } + } +} diff --git a/JMMServer/AniDB_API/Commands/AniDBCommand_GetCalendar.cs b/JMMServer/AniDB_API/Commands/AniDBCommand_GetCalendar.cs new file mode 100644 index 000000000..3445d5f51 --- /dev/null +++ b/JMMServer/AniDB_API/Commands/AniDBCommand_GetCalendar.cs @@ -0,0 +1,83 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Net.Sockets; +using System.Net; + +namespace AniDBAPI.Commands +{ + public class AniDBCommand_GetCalendar : AniDBUDPCommand, IAniDBUDPCommand + { + public string GetKey() + { + return "AniDBCommand_GetCalendar"; + } + + private CalendarCollection calendars = null; + public CalendarCollection Calendars + { + get { return calendars; } + set { calendars = value; } + } + + public virtual enHelperActivityType GetStartEventType() + { + return enHelperActivityType.GettingCalendar; + } + + public virtual enHelperActivityType Process(ref Socket soUDP, + ref IPEndPoint remoteIpEndPoint, string sessionID, Encoding enc) + { + ProcessCommand(ref soUDP, ref remoteIpEndPoint, sessionID, enc); + + // handle 555 BANNED and 598 - UNKNOWN COMMAND + if (ResponseCode == 598) return enHelperActivityType.UnknownCommand; + if (ResponseCode == 555) return enHelperActivityType.Banned; + + if (errorOccurred) return enHelperActivityType.CalendarEmpty; + + //BaseConfig.MyAnimeLog.Write("AniDBCommand_GetCalendar: Response: {0}", socketResponse); + + // Process Response + string sMsgType = socketResponse.Substring(0, 3); + + + switch (sMsgType) + { + case "297": + { + + calendars = new CalendarCollection(socketResponse); + return enHelperActivityType.GotCalendar; + + } + case "397": + { + return enHelperActivityType.CalendarEmpty; + } + case "501": + { + return enHelperActivityType.LoginRequired; + } + } + + return enHelperActivityType.CalendarEmpty; + + } + + public AniDBCommand_GetCalendar() + { + commandType = enAniDBCommandType.GetCalendar; + } + + public void Init() + { + commandText = "CALENDAR "; + + //BaseConfig.MyAnimeLog.Write("AniDBCommand_GetCalendar: Request: {0}", commandText); + + commandID = "CALENDAR "; + } + } +} diff --git a/JMMServer/AniDB_API/Commands/AniDBCommand_GetCharacterInfo.cs b/JMMServer/AniDB_API/Commands/AniDBCommand_GetCharacterInfo.cs new file mode 100644 index 000000000..12b02bfa6 --- /dev/null +++ b/JMMServer/AniDB_API/Commands/AniDBCommand_GetCharacterInfo.cs @@ -0,0 +1,107 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Net.Sockets; +using System.Net; + +namespace AniDBAPI.Commands +{ + public class AniDBCommand_GetCharacterInfo : AniDBUDPCommand, IAniDBUDPCommand + { + private int charID = 0; + public int CharID + { + get { return charID; } + set { charID = value; } + } + + private Raw_AniDB_Character charInfo = null; + public Raw_AniDB_Character CharInfo + { + get { return charInfo; } + set { charInfo = value; } + } + + private bool forceRefresh = false; + public bool ForceRefresh + { + get { return forceRefresh; } + set { forceRefresh = value; } + } + + public string GetKey() + { + return "AniDBCommand_GetCharacterInfo" + CharID.ToString(); + } + + public virtual enHelperActivityType GetStartEventType() + { + return enHelperActivityType.GettingCharInfo; + } + + public virtual enHelperActivityType Process(ref Socket soUDP, + ref IPEndPoint remoteIpEndPoint, string sessionID, Encoding enc) + { + ProcessCommand(ref soUDP, ref remoteIpEndPoint, sessionID, enc); + + // handle 555 BANNED and 598 - UNKNOWN COMMAND + if (ResponseCode == 598) return enHelperActivityType.UnknownCommand; + if (ResponseCode == 555) return enHelperActivityType.Banned; + + if (errorOccurred) return enHelperActivityType.NoSuchChar; + + //BaseConfig.MyAnimeLog.Write("AniDBCommand_GetCharacterInfo.Process: Response: {0}", socketResponse); + + // Process Response + string sMsgType = socketResponse.Substring(0, 3); + + + switch (sMsgType) + { + case "235": + { + // 235 CHARACTER INFO + // the first 11 characters should be "235 CHARACTER" + // the rest of the information should be the data list + + charInfo = new Raw_AniDB_Character(socketResponse); + return enHelperActivityType.GotCharInfo; + + + // Response: 235 CHARACTER 99297|6267|25|539|5|01|The Girl Returns|Shoujo Kikan|????|1238976000 + } + case "335": + { + return enHelperActivityType.NoSuchChar; + } + case "501": + { + return enHelperActivityType.LoginRequired; + } + } + + return enHelperActivityType.NoSuchChar; + + } + + + + public AniDBCommand_GetCharacterInfo() + { + commandType = enAniDBCommandType.GetCharInfo; + } + + public void Init(int charID, bool force) + { + + this.charID = charID; + this.forceRefresh = force; + commandText = "CHARACTER charid=" + charID.ToString(); + + //BaseConfig.MyAnimeLog.Write("AniDBCommand_GetCharacterInfo.Process: Request: {0}", commandText); + + commandID = charID.ToString(); + } + } +} diff --git a/JMMServer/AniDB_API/Commands/AniDBCommand_GetCreatorInfo.cs b/JMMServer/AniDB_API/Commands/AniDBCommand_GetCreatorInfo.cs new file mode 100644 index 000000000..9e6cd344b --- /dev/null +++ b/JMMServer/AniDB_API/Commands/AniDBCommand_GetCreatorInfo.cs @@ -0,0 +1,108 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Net.Sockets; +using System.Net; + +namespace AniDBAPI.Commands +{ + public class AniDBCommand_GetCreatorInfo : AniDBUDPCommand, IAniDBUDPCommand + { + private int creatorID = 0; + public int CreatorID + { + get { return creatorID; } + set { creatorID = value; } + } + + public string GetKey() + { + return "AniDBCommand_GetCreatorInfo" + CreatorID.ToString(); + } + + private Raw_AniDB_Creator creatorInfo = null; + public Raw_AniDB_Creator CreatorInfo + { + get { return creatorInfo; } + set { creatorInfo = value; } + } + + private bool forceRefresh = false; + public bool ForceRefresh + { + get { return forceRefresh; } + set { forceRefresh = value; } + } + + public virtual enHelperActivityType GetStartEventType() + { + return enHelperActivityType.GettingCreatorInfo; + } + + public virtual enHelperActivityType Process(ref Socket soUDP, + ref IPEndPoint remoteIpEndPoint, string sessionID, Encoding enc) + { + ProcessCommand(ref soUDP, ref remoteIpEndPoint, sessionID, enc); + + // handle 555 BANNED and 598 - UNKNOWN COMMAND + if (ResponseCode == 598) return enHelperActivityType.UnknownCommand; + if (ResponseCode == 555) return enHelperActivityType.Banned; + + if (errorOccurred) return enHelperActivityType.NoSuchCreator; + + //BaseConfig.MyAnimeLog.Write("AniDBCommand_GetCreatorInfo.Process: Response: {0}", socketResponse); + + // Process Response + string sMsgType = socketResponse.Substring(0, 3); + + + switch (sMsgType) + { + case "245": + { + // 245 CREATOR + // the first 11 characters should be "245 CREATOR" + // the rest of the information should be the data list + + creatorInfo = new Raw_AniDB_Creator(socketResponse); + return enHelperActivityType.GotCreatorInfo; + + + // 245 CREATOR 200|?????|Suwabe Jun`ichi|1|17015.jpg||http://www.haikyo.or.jp/PROFILE/man/11470.html|Junichi_Suwabe|%E8%AB%8F%E8%A8%AA%E9%83%A8%E9%A0%86%E4%B8%80|1236300570 + + } + case "345": + { + return enHelperActivityType.NoSuchCreator; + } + case "501": + { + return enHelperActivityType.LoginRequired; + } + } + + return enHelperActivityType.NoSuchCreator; + + } + + + + public AniDBCommand_GetCreatorInfo() + { + commandType = enAniDBCommandType.GetCreatorInfo; + } + + public void Init(int creaID, bool force) + { + + this.creatorID = creaID; + this.forceRefresh = force; + commandText = "CREATOR creatorid=" + creatorID.ToString(); + + //BaseConfig.MyAnimeLog.Write("AniDBCommand_GetCreatorInfo.Process: Request: {0}", commandText); + + commandID = creatorID.ToString(); + } + } +} diff --git a/JMMServer/AniDB_API/Commands/AniDBCommand_GetEpisodeInfo.cs b/JMMServer/AniDB_API/Commands/AniDBCommand_GetEpisodeInfo.cs new file mode 100644 index 000000000..fd1e879d1 --- /dev/null +++ b/JMMServer/AniDB_API/Commands/AniDBCommand_GetEpisodeInfo.cs @@ -0,0 +1,157 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Net.Sockets; +using System.Net; + +namespace AniDBAPI.Commands +{ + public class AniDBCommand_GetEpisodeInfo : AniDBUDPCommand, IAniDBUDPCommand + { + private int episodeID = 0; + public int EpisodeID + { + get { return episodeID; } + set { episodeID = value; } + } + + private int episodeNumber = 0; + public int EpisodeNumber + { + get { return episodeNumber; } + set { episodeNumber = value; } + } + + private int animeID = 0; + public int AnimeID + { + get { return animeID; } + set { animeID = value; } + } + + private enEpisodeType episodeType; + public enEpisodeType EpisodeType + { + get { return episodeType; } + set { episodeType = value; } + } + + private Raw_AniDB_Episode episodeInfo = null; + public Raw_AniDB_Episode EpisodeInfo + { + get { return episodeInfo; } + set { episodeInfo = value; } + } + + private bool forceRefresh = false; + public bool ForceRefresh + { + get { return forceRefresh; } + set { forceRefresh = value; } + } + + string key = ""; + + public string GetKey() + { + return key; + } + + public virtual enHelperActivityType GetStartEventType() + { + return enHelperActivityType.GettingEpisodeInfo; + } + + public virtual enHelperActivityType Process(ref Socket soUDP, + ref IPEndPoint remoteIpEndPoint, string sessionID, Encoding enc) + { + ProcessCommand(ref soUDP, ref remoteIpEndPoint, sessionID, enc); + + // handle 555 BANNED and 598 - UNKNOWN COMMAND + if (ResponseCode == 598) return enHelperActivityType.UnknownCommand; + if (ResponseCode == 555) return enHelperActivityType.Banned; + + if (errorOccurred) return enHelperActivityType.NoSuchEpisode; + + //BaseConfig.MyAnimeLog.Write("AniDBCommand_GetEpisodeInfo.Process: Response: {0}", socketResponse); + + // Process Response + string sMsgType = socketResponse.Substring(0, 3); + + + switch (sMsgType) + { + case "240": + { + // 240 EPISODE INFO + // the first 11 characters should be "240 EPISODE" + // the rest of the information should be the data list + + episodeInfo = new Raw_AniDB_Episode(socketResponse, enEpisodeSourceType.Episode); + return enHelperActivityType.GotEpisodeInfo; + + + // Response: 240 EPISODE 99297|6267|25|539|5|01|The Girl Returns|Shoujo Kikan|????|1238976000 + } + case "340": + { + return enHelperActivityType.NoSuchEpisode; + } + case "501": + { + return enHelperActivityType.LoginRequired; + } + } + + return enHelperActivityType.NoSuchEpisode; + + } + + + + public AniDBCommand_GetEpisodeInfo() + { + commandType = enAniDBCommandType.GetEpisodeInfo; + } + + public void Init(int episodeID, bool force) + { + this.episodeID = episodeID; + this.forceRefresh = force; + + key = "AniDBCommand_GetEpisodeInfo_" + EpisodeID.ToString(); + commandText = "EPISODE eid=" + episodeID.ToString(); + + //BaseConfig.MyAnimeLog.Write("AniDBCommand_GetEpisodeInfo.Process: Request: {0}", commandText); + //BaseConfig.MyAnimeLog.Write("AniDBCommand_GetEpisodeInfo.Init: {0}", key); + + commandID = episodeID.ToString(); + } + + public void Init(int animeID, int episodeNumber, enEpisodeType epType) + { + this.episodeNumber = episodeNumber; + this.animeID = animeID; + this.episodeType = epType; + + string epNumberFormatted = episodeNumber.ToString(); + + switch (epType) + { + case enEpisodeType.Credits: epNumberFormatted = "C" + episodeNumber.ToString(); break; + case enEpisodeType.Special: epNumberFormatted = "S" + episodeNumber.ToString(); break; + case enEpisodeType.Other: epNumberFormatted = "0" + episodeNumber.ToString(); break; + case enEpisodeType.Trailer: epNumberFormatted = "T" + episodeNumber.ToString(); break; + case enEpisodeType.Parody: epNumberFormatted = "P" + episodeNumber.ToString(); break; + } + + key = "AniDBCommand_GetEpisodeInfo_" + animeID.ToString() + "_" + epNumberFormatted; + commandText = string.Format("EPISODE aid={0}&epno={1}", animeID, epNumberFormatted); + + //BaseConfig.MyAnimeLog.Write("AniDBCommand_GetEpisodeInfo.Process: Request: {0}", commandText); + + commandID = animeID.ToString(); + } + } +} diff --git a/JMMServer/AniDB_API/Commands/AniDBCommand_GetFileInfo.cs b/JMMServer/AniDB_API/Commands/AniDBCommand_GetFileInfo.cs new file mode 100644 index 000000000..ba4756c72 --- /dev/null +++ b/JMMServer/AniDB_API/Commands/AniDBCommand_GetFileInfo.cs @@ -0,0 +1,111 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Net.Sockets; +using System.Net; + +namespace AniDBAPI.Commands +{ + public class AniDBCommand_GetFileInfo : AniDBUDPCommand, IAniDBUDPCommand + { + public Raw_AniDB_File fileInfo = null; + //public Raw_AniDB_Episode episodeInfo = null; + public IHash fileData = null; + + private bool forceRefresh = false; + public bool ForceRefresh + { + get { return forceRefresh; } + set { forceRefresh = value; } + } + + public virtual enHelperActivityType GetStartEventType() + { + return enHelperActivityType.GettingFileInfo; + } + + public string GetKey() + { + return "AniDBCommand_GetFileInfo" + fileData.ED2KHash; + } + + public virtual enHelperActivityType Process(ref Socket soUDP, + ref IPEndPoint remoteIpEndPoint, string sessionID, Encoding enc) + { + ProcessCommand(ref soUDP, ref remoteIpEndPoint, sessionID, enc); + + // handle 555 BANNED and 598 - UNKNOWN COMMAND + if (ResponseCode == 598) return enHelperActivityType.UnknownCommand; + if (ResponseCode == 555) return enHelperActivityType.Banned; + + if (errorOccurred) return enHelperActivityType.FileDoesNotExist; + + //BaseConfig.MyAnimeLog.Write("AniDBCommand_GetFileInfo.Process: Response: {0}", socketResponse); + + // Process Response + string sMsgType = socketResponse.Substring(0, 3); + + + switch (sMsgType) + { + case "220": + { + // 220 FILE INFO + // the first 9 characters should be "220 FILE " + // the rest of the information should be the data list + + fileInfo = new Raw_AniDB_File(socketResponse); + //episodeInfo = new Raw_AniDB_Episode(socketResponse, enEpisodeSourceType.File); + return enHelperActivityType.GotFileInfo; + + } + case "320": + { + return enHelperActivityType.FileDoesNotExist; + } + case "501": + { + return enHelperActivityType.LoginRequired; + } + } + + return enHelperActivityType.FileDoesNotExist; + + } + + public AniDBCommand_GetFileInfo() + { + commandType = enAniDBCommandType.GetFileInfo; + } + + public void Init(IHash fileData, bool force) + { + int fByte1 = 124; // fmask - byte1 (old 120 Added other episodes) + int fByte2 = 248; // old 72 fmask - byte2 (Added FileSize, SHA1, MD5) + int fByte3 = 255; // fmask - byte3 + int fByte4 = 249; // fmask - byte4 + + int aByte1 = 0; // amask - byte1 + int aByte2 = 0; // amask - byte2 + int aByte3 = 252; // amask - byte3 old 236 Added Kanji name + int aByte4 = 192; // amask - byte4 + + this.fileData = fileData; + this.forceRefresh = force; + + commandID = fileData.Info; + // 220 FILE572794|6107|99294|2723|c646d82a184a33f4e4f98af39f29a044|8452c4bf|high|HDTV|Vorbis (Ogg Vorbis)|148|H264/AVC|1773|1280x720|mkv|1470||1239494400|2|The Day It Began|Hajimari no Hi|712|14|Eclipse Productions|Eclipse + + + + commandText = "FILE size=" + fileData.FileSize.ToString(); + commandText += "&ed2k=" + fileData.ED2KHash; + commandText += string.Format("&fmask={0}{1}{2}{3}", fByte1.ToString("X").PadLeft(2, '0'), + fByte2.ToString("X").PadLeft(2, '0'), fByte3.ToString("X").PadLeft(2, '0'), fByte4.ToString("X").PadLeft(2, '0')); + commandText += string.Format("&amask={0}{1}{2}{3}", aByte1.ToString("X").PadLeft(2, '0'), + aByte2.ToString("X").PadLeft(2, '0'), aByte3.ToString("X").PadLeft(2, '0'), aByte4.ToString("X").PadLeft(2, '0')); + + } + } +} diff --git a/JMMServer/AniDB_API/Commands/AniDBCommand_GetGroup.cs b/JMMServer/AniDB_API/Commands/AniDBCommand_GetGroup.cs new file mode 100644 index 000000000..1e0caa232 --- /dev/null +++ b/JMMServer/AniDB_API/Commands/AniDBCommand_GetGroup.cs @@ -0,0 +1,83 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using AniDBAPI.Commands; +using AniDBAPI; +using System.Net; +using System.Net.Sockets; + +namespace JMMServer.Commands +{ + public class AniDBCommand_GetGroup : AniDBUDPCommand, IAniDBUDPCommand + { + public int GroupID { get; set; } + public Raw_AniDB_Group Group { get; set; } + + public string GetKey() + { + return "AniDBCommand_GetGroup_" + GroupID.ToString(); + } + + public virtual enHelperActivityType GetStartEventType() + { + return enHelperActivityType.GettingGroup; + } + + public virtual enHelperActivityType Process(ref Socket soUDP, + ref IPEndPoint remoteIpEndPoint, string sessionID, Encoding enc) + { + ProcessCommand(ref soUDP, ref remoteIpEndPoint, sessionID, enc); + + // handle 555 BANNED and 598 - UNKNOWN COMMAND + if (ResponseCode == 598) return enHelperActivityType.UnknownCommand; + if (ResponseCode == 555) return enHelperActivityType.Banned; + + if (errorOccurred) return enHelperActivityType.NoSuchGroup; + + + // Process Response + string sMsgType = socketResponse.Substring(0, 3); + + + switch (sMsgType) + { + case "250": + { + // 250 GROUP + //3938|704|1900|53|1126|Ayako-Fansubs|Ayako|#Ayako|irc.rizon.net|http://ayakofansubs.info/|1669.png + Group = new Raw_AniDB_Group(socketResponse); + return enHelperActivityType.GotGroup; + + } + case "350": + { + return enHelperActivityType.NoSuchGroup; + } + case "501": + { + return enHelperActivityType.LoginRequired; + } + } + + return enHelperActivityType.FileDoesNotExist; + + } + + public AniDBCommand_GetGroup() + { + commandType = enAniDBCommandType.GetGroup; + Group = null; + } + + public void Init(int groupID) + { + this.GroupID = groupID; + commandText = "GROUP gid=" + GroupID.ToString(); + + //BaseConfig.MyAnimeLog.Write("AniDBCommand_GetGroupStatus.Process: Request: {0}", commandText); + + commandID = GroupID.ToString(); + } + } +} diff --git a/JMMServer/AniDB_API/Commands/AniDBCommand_GetGroupStatus.cs b/JMMServer/AniDB_API/Commands/AniDBCommand_GetGroupStatus.cs new file mode 100644 index 000000000..10d359b34 --- /dev/null +++ b/JMMServer/AniDB_API/Commands/AniDBCommand_GetGroupStatus.cs @@ -0,0 +1,96 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Net.Sockets; +using System.Net; + +namespace AniDBAPI.Commands +{ + public class AniDBCommand_GetGroupStatus : AniDBUDPCommand, IAniDBUDPCommand + { + private int animeID; + public int AnimeID + { + get { return animeID; } + set { animeID = value; } + } + + public string GetKey() + { + return "AniDBCommand_GetGroupStatus" + AnimeID.ToString(); + } + + private GroupStatusCollection grpStatus = null; + public GroupStatusCollection GrpStatusCollection + { + get { return grpStatus; } + set { grpStatus = value; } + } + + public virtual enHelperActivityType GetStartEventType() + { + return enHelperActivityType.GettingGroupStatus; + } + + public virtual enHelperActivityType Process(ref Socket soUDP, + ref IPEndPoint remoteIpEndPoint, string sessionID, Encoding enc) + { + ProcessCommand(ref soUDP, ref remoteIpEndPoint, sessionID, enc); + + // handle 555 BANNED and 598 - UNKNOWN COMMAND + if (ResponseCode == 598) return enHelperActivityType.UnknownCommand; + if (ResponseCode == 555) return enHelperActivityType.Banned; + + if (errorOccurred) return enHelperActivityType.NoGroupsFound; + + //BaseConfig.MyAnimeLog.Write("AniDBCommand_GetGroupStatus.Process: Response: {0}", socketResponse); + + // Process Response + string sMsgType = socketResponse.Substring(0, 3); + + + switch (sMsgType) + { + case "225": + { + // 225 GROUPSTATUS + + grpStatus = new GroupStatusCollection(animeID, socketResponse); + return enHelperActivityType.GotGroupStatus; + + } + case "330": + { + return enHelperActivityType.NoSuchAnime; + } + case "325": // no such description + { + return enHelperActivityType.NoGroupsFound; + } + case "501": + { + return enHelperActivityType.LoginRequired; + } + } + + return enHelperActivityType.FileDoesNotExist; + + } + + public AniDBCommand_GetGroupStatus() + { + commandType = enAniDBCommandType.GetGroupStatus; + } + + public void Init(int animeID) + { + this.animeID = animeID; + commandText = "GROUPSTATUS aid=" + animeID.ToString(); + + //BaseConfig.MyAnimeLog.Write("AniDBCommand_GetGroupStatus.Process: Request: {0}", commandText); + + commandID = animeID.ToString(); + } + } +} diff --git a/JMMServer/AniDB_API/Commands/AniDBCommand_GetMyListFileInfo.cs b/JMMServer/AniDB_API/Commands/AniDBCommand_GetMyListFileInfo.cs new file mode 100644 index 000000000..528d66707 --- /dev/null +++ b/JMMServer/AniDB_API/Commands/AniDBCommand_GetMyListFileInfo.cs @@ -0,0 +1,91 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Net.Sockets; +using System.Net; + +namespace AniDBAPI.Commands +{ + public class AniDBCommand_GetMyListFileInfo : AniDBUDPCommand, IAniDBUDPCommand + { + private int fileID = 0; + public int FileID + { + get { return fileID; } + set { fileID = value; } + } + + public string GetKey() + { + return "AniDBCommand_GetMyListFileInfo" + FileID.ToString(); + } + + private Raw_AniDB_MyListFile myListFile = null; + public Raw_AniDB_MyListFile MyListFile + { + get { return myListFile; } + set { myListFile = value; } + } + + public virtual enHelperActivityType GetStartEventType() + { + return enHelperActivityType.GettingMyListFileInfo; + } + + public virtual enHelperActivityType Process(ref Socket soUDP, + ref IPEndPoint remoteIpEndPoint, string sessionID, Encoding enc) + { + ProcessCommand(ref soUDP, ref remoteIpEndPoint, sessionID, enc); + + // handle 555 BANNED and 598 - UNKNOWN COMMAND + if (ResponseCode == 598) return enHelperActivityType.UnknownCommand; + if (ResponseCode == 555) return enHelperActivityType.Banned; + + if (errorOccurred) return enHelperActivityType.NoSuchMyListFile; + + //BaseConfig.MyAnimeLog.Write("AniDBCommand_GetMyListFileInfo.Process: Response: {0}", socketResponse); + + // Process Response + string sMsgType = socketResponse.Substring(0, 3); + + + switch (sMsgType) + { + case "221": + { + myListFile = new Raw_AniDB_MyListFile(socketResponse); + //BaseConfig.MyAnimeLog.Write(myListFile.ToString()); + return enHelperActivityType.GotMyListFileInfo; + + } + case "321": + { + return enHelperActivityType.NoSuchMyListFile; + } + case "501": + { + return enHelperActivityType.LoginRequired; + } + } + + return enHelperActivityType.NoSuchMyListFile; + + } + + public AniDBCommand_GetMyListFileInfo() + { + commandType = enAniDBCommandType.GetMyListFileInfo; + } + + public void Init(int fileId) + { + this.fileID = fileId; + commandText = "MYLIST fid=" + fileID.ToString(); + + //BaseConfig.MyAnimeLog.Write("AniDBCommand_GetMyListFileInfo.Process: Request: {0}", commandText); + + commandID = fileID.ToString(); + } + } +} diff --git a/JMMServer/AniDB_API/Commands/AniDBCommand_GetReview.cs b/JMMServer/AniDB_API/Commands/AniDBCommand_GetReview.cs new file mode 100644 index 000000000..11ef42fbb --- /dev/null +++ b/JMMServer/AniDB_API/Commands/AniDBCommand_GetReview.cs @@ -0,0 +1,95 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Net.Sockets; +using System.Net; + +namespace AniDBAPI.Commands +{ + public class AniDBCommand_GetReview : AniDBUDPCommand, IAniDBUDPCommand + { + private int reviewID; + public int ReviewID + { + get { return reviewID; } + set { reviewID = value; } + } + private string reviewText = ""; + public string ReviewText + { + get { return reviewText; } + set { reviewText = value; } + } + + public Raw_AniDB_Review ReviewInfo = null; + public string GetKey() + { + return "AniDBCommand_GetReview" + ReviewID.ToString(); + } + + public virtual enHelperActivityType GetStartEventType() + { + return enHelperActivityType.GettingReview; + } + + public virtual enHelperActivityType Process(ref Socket soUDP, + ref IPEndPoint remoteIpEndPoint, string sessionID, Encoding enc) + { + ProcessCommand(ref soUDP, ref remoteIpEndPoint, sessionID, enc); + + // handle 555 BANNED and 598 - UNKNOWN COMMAND + if (ResponseCode == 598) return enHelperActivityType.UnknownCommand; + if (ResponseCode == 555) return enHelperActivityType.Banned; + + if (errorOccurred) return enHelperActivityType.NoSuchReview; + + //BaseConfig.MyAnimeLog.Write("AniDBCommand_GetAnimeDescription.Process: Response: {0}", socketResponse); + + // Process Response + string sMsgType = socketResponse.Substring(0, 3); + + + switch (sMsgType) + { + case "234": + { + // 234 REVIEW + // the first 10 characters should be "240 REVIEW" + // the rest of the information should be the data list + + ReviewInfo = new Raw_AniDB_Review(socketResponse); + return enHelperActivityType.GotReview; + + } + case "334": + { + return enHelperActivityType.NoSuchReview; + } + case "501": + { + return enHelperActivityType.LoginRequired; + } + } + + return enHelperActivityType.NoSuchReview; + + } + + public AniDBCommand_GetReview() + { + commandType = enAniDBCommandType.GetReview; + } + + public void Init(int revID) + { + this.reviewID = revID; + commandText = "REVIEW rid=" + revID.ToString(); + commandText += "&part=0"; + + //BaseConfig.MyAnimeLog.Write("AniDBCommand_GetReview.Process: Request: {0}", commandText); + + commandID = revID.ToString(); + } + } +} diff --git a/JMMServer/AniDB_API/Commands/AniDBCommand_GetUpdated.cs b/JMMServer/AniDB_API/Commands/AniDBCommand_GetUpdated.cs new file mode 100644 index 000000000..12d98034e --- /dev/null +++ b/JMMServer/AniDB_API/Commands/AniDBCommand_GetUpdated.cs @@ -0,0 +1,116 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Net.Sockets; +using System.Net; +using NLog; + +namespace AniDBAPI.Commands +{ + public class AniDBCommand_GetUpdated : AniDBUDPCommand, IAniDBUDPCommand + { + private static Logger logger = LogManager.GetCurrentClassLogger(); + + public string StartTime { get; set; } + public int AniDBEntity { get; set; } + public int RecordCount { get; set; } + public List AnimeIDList { get; set; } + public string AnimeIDListRaw { get; set; } + + // 243 UPDATED + // 1|346|1279968638|1185,7703,7682,7307,7432,6399,1349,1149,4193,500,154,5106,1022,357,7683,6327,5725,7653,1429,1653,1656,6716,2418,7690,635,7691,7692,7693,7694,7695,7696,1661,7697,7705,5406,7698,7700,1666,6227,2548,4235,7701,2195,2196,4990,4454,3110,3482,7381,2546,2880,1821,2661,5492,7234,2826,5284,266,6049,6083,7708,4238,5674,4678,1072,2871,2290,1836,2297,891,1061,2183,494,1681,2559,757,6773,594,5044,416,2107,1907,1913,524,505,1025,1825,1692,2045,5248,3677,1563,942,5793,1949,3182,1530,1105,1920,2684,1651,3050,2744,5518,4927,2322,484,947,1936,1383,2019,2740,1356,1864,3304,2048,7412,3667,2786,3388,1829,2007,3396,1496,2816,144,2863,2635,1811,3605,1930,1542,3366,3368,7389,2728,5133,2068,1912,965,2560,2555,3092,2343,2078,3636,7236,950,2582,3305,617,7142,917,591,330,925,2288,2654,4054,210,3658,313,1959,7280,2866,2129,945,2624,7688,7687,7686,7685,7707,7706,6391,3425,7251,7278,6452,4730,7620,7621,7664,6143,7618,4761,7478,7719,7486,7597,7399,7720,7068,4860,2879,7712,943,7713,5016,7715 + + + public string GetKey() + { + return "AniDBCommand_GetUpdated"; + } + + public virtual enHelperActivityType GetStartEventType() + { + return enHelperActivityType.GettingUpdated; + } + + public virtual enHelperActivityType Process(ref Socket soUDP, + ref IPEndPoint remoteIpEndPoint, string sessionID, Encoding enc) + { + + AnimeIDList = new List(); + RecordCount = 0; + + ProcessCommand(ref soUDP, ref remoteIpEndPoint, sessionID, enc); + + // handle 555 BANNED and 598 - UNKNOWN COMMAND + if (ResponseCode == 598) return enHelperActivityType.UnknownCommand; + if (ResponseCode == 555) return enHelperActivityType.Banned; + + if (errorOccurred) return enHelperActivityType.NoUpdates; + + //BaseConfig.MyAnimeLog.Write("AniDBCommand_GetCalendar: Response: {0}", socketResponse); + + // Process Response + string sMsgType = socketResponse.Substring(0, 3); + + + switch (sMsgType) + { + case "243": + { + + // remove the header info + string[] sDetails = socketResponse.Substring(0).Split('\n'); + + if (sDetails.Length > 1) + { + // first item will be the status command so ignore + // only concerned with the second line + + string[] flds = sDetails[1].Substring(0).Split('|'); + AniDBEntity = int.Parse(flds[0]); + RecordCount = int.Parse(flds[1]); + StartTime = flds[2]; + AnimeIDListRaw = flds[3].Trim(); + string[] aids = AnimeIDListRaw.Split(','); + foreach (string sid in aids) + { + AnimeIDList.Add(int.Parse(sid)); + } + } + + return enHelperActivityType.GotUpdated; + + } + case "343": + { + return enHelperActivityType.NoUpdates; + } + case "501": + { + return enHelperActivityType.LoginRequired; + } + } + + return enHelperActivityType.NoUpdates; + + } + + public AniDBCommand_GetUpdated() + { + commandType = enAniDBCommandType.GetUpdated; + RecordCount = 0; + } + + public void Init(string startTime) + { + RecordCount = 0; + this.StartTime = startTime; + + //commandText = string.Format("UPDATED entity=1&time={0}", this.StartTime); + commandText = "UPDATED entity=1&age=1"; + + + commandID = "UPDATED "; + } + } +} diff --git a/JMMServer/AniDB_API/Commands/AniDBCommand_Login.cs b/JMMServer/AniDB_API/Commands/AniDBCommand_Login.cs new file mode 100644 index 000000000..f08084379 --- /dev/null +++ b/JMMServer/AniDB_API/Commands/AniDBCommand_Login.cs @@ -0,0 +1,81 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Net; +using System.Net.Sockets; + +namespace AniDBAPI.Commands +{ + public class AniDBCommand_Login : AniDBUDPCommand, IAniDBUDPCommand + { + public string SessionID = string.Empty; + + public virtual enHelperActivityType GetStartEventType() + { + return enHelperActivityType.LoggingIn; + } + + public string GetKey() + { + return "Login"; + } + + public virtual enHelperActivityType Process(ref Socket soUDP, + ref IPEndPoint remoteIpEndPoint, string sessionID, Encoding enc) + { + ProcessCommand(ref soUDP, ref remoteIpEndPoint, sessionID, enc); + + // handle 555 BANNED and 598 - UNKNOWN COMMAND + if (ResponseCode == 598) return enHelperActivityType.UnknownCommand; + if (ResponseCode == 555) return enHelperActivityType.Banned; + + if (errorOccurred) return enHelperActivityType.LoginFailed; + + // Process Response + string sMsgType = socketResponse.Substring(0, 3); + //BaseConfig.MyAnimeLog.Write("AniDBCommand_Login.Process: Response: {0}", socketResponse); + + // 200 {str session_key} LOGIN ACCEPTED + // 203 LOGGED OUT + // 500 LOGIN FAILED + + if ((sMsgType.Equals("500")) || sMsgType.Equals("598")) + { + return enHelperActivityType.LoginFailed; + + } + + if (!sMsgType.Equals("200") && !sMsgType.Equals("201")) + { + return enHelperActivityType.LoginFailed; + + } + + // Get the session ID + string sMessage = socketResponse.Substring(4); + SessionID = sMessage.Trim(); + int i = sMessage.IndexOf("LOGIN"); + SessionID = sMessage.Substring(0, i - 1).Trim(); + + return enHelperActivityType.LoggedIn; + } + + public AniDBCommand_Login() + { + commandType = enAniDBCommandType.Login; + commandID = ""; + } + + public void Init(string userName, string password) + { + commandText = "AUTH user=" + userName.Trim(); + commandText += "&pass=" + password.Trim(); + commandText += "&protover=3"; + commandText += "&client=ommserver"; + //commandText += "&client=vmcanidb"; + commandText += "&clientver=1&comp=1"; + //BaseConfig.MyAnimeLog.Write("commandText: {0}", commandText); + } + } +} diff --git a/JMMServer/AniDB_API/Commands/AniDBCommand_Logout.cs b/JMMServer/AniDB_API/Commands/AniDBCommand_Logout.cs new file mode 100644 index 000000000..74d227e55 --- /dev/null +++ b/JMMServer/AniDB_API/Commands/AniDBCommand_Logout.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Net; +using System.Net.Sockets; + +namespace AniDBAPI.Commands +{ + public class AniDBCommand_Logout : AniDBUDPCommand, IAniDBUDPCommand + { + public virtual enHelperActivityType GetStartEventType() + { + return enHelperActivityType.LoggingOut; + } + + public string GetKey() + { + return "Logout"; + } + + public virtual enHelperActivityType Process(ref Socket soUDP, + ref IPEndPoint remoteIpEndPoint, string sessionID, Encoding enc) + { + ProcessCommand(ref soUDP, ref remoteIpEndPoint, sessionID, enc); + + return enHelperActivityType.LoggedOut; + } + + public AniDBCommand_Logout() + { + commandType = enAniDBCommandType.Logout; + commandID = ""; + } + + public void Init() + { + commandText = "LOGOUT "; + + } + } +} diff --git a/JMMServer/AniDB_API/Commands/AniDBCommand_NotifyGet.cs b/JMMServer/AniDB_API/Commands/AniDBCommand_NotifyGet.cs new file mode 100644 index 000000000..4289f0b43 --- /dev/null +++ b/JMMServer/AniDB_API/Commands/AniDBCommand_NotifyGet.cs @@ -0,0 +1,89 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Net.Sockets; +using System.Net; + +namespace AniDBAPI.Commands +{ + public class AniDBCommand_NotifyGet : AniDBUDPCommand, IAniDBUDPCommand + { + public string messageType; + public long messageID; + + public Raw_AniDB_NotifyMessage NotifyMessage = null; + public Raw_AniDB_NotifyAlert NotifyAlert = null; + + public string GetKey() + { + return "AniDBCommand_NotifyGet"; + } + + public virtual enHelperActivityType GetStartEventType() + { + return enHelperActivityType.GettingNotifyGet; + } + + public virtual enHelperActivityType Process(ref Socket soUDP, + ref IPEndPoint remoteIpEndPoint, string sessionID, Encoding enc) + { + ProcessCommand(ref soUDP, ref remoteIpEndPoint, sessionID, enc); + + // handle 555 BANNED and 598 - UNKNOWN COMMAND + if (ResponseCode == 598) return enHelperActivityType.UnknownCommand; + if (ResponseCode == 555) return enHelperActivityType.Banned; + + if (errorOccurred) return enHelperActivityType.NoSuchNotify; + + // Process Response + string sMsgType = socketResponse.Substring(0, 3); + + + switch (sMsgType) + { + case "292": + { + + NotifyMessage = new Raw_AniDB_NotifyMessage(socketResponse); + return enHelperActivityType.GotNotifyGet; + } + + case "293": + { + + NotifyAlert = new Raw_AniDB_NotifyAlert(socketResponse); + return enHelperActivityType.GotNotifyGet; + + } + case "392": + case "393": + { + return enHelperActivityType.NoSuchNotify; + } + case "501": + { + return enHelperActivityType.LoginRequired; + } + } + + return enHelperActivityType.GotNotifyList; + + } + + public AniDBCommand_NotifyGet() + { + commandType = enAniDBCommandType.GetNotifyGet; + } + + public void Init(string messageType, long messageID) + { + this.messageType = messageType; + this.messageID = messageID; + + commandText = string.Format("NOTIFYGET type={0}&id={1}", messageType.Trim().ToUpper(), messageID); + + commandID = "NOTIFYGET "; + } + } +} diff --git a/JMMServer/AniDB_API/Commands/AniDBCommand_NotifyList.cs b/JMMServer/AniDB_API/Commands/AniDBCommand_NotifyList.cs new file mode 100644 index 000000000..94c9cf601 --- /dev/null +++ b/JMMServer/AniDB_API/Commands/AniDBCommand_NotifyList.cs @@ -0,0 +1,77 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Net.Sockets; +using System.Net; + +namespace AniDBAPI.Commands +{ + public class AniDBCommand_NotifyList : AniDBUDPCommand, IAniDBUDPCommand + { + public string GetKey() + { + return "AniDBCommand_NotifyList"; + } + + private Raw_AniDB_NotifyList notifyListCollection = null; + public Raw_AniDB_NotifyList NotifyListCollection + { + get { return notifyListCollection; } + set { notifyListCollection = value; } + } + + public virtual enHelperActivityType GetStartEventType() + { + return enHelperActivityType.GettingNotifyList; + } + + public virtual enHelperActivityType Process(ref Socket soUDP, + ref IPEndPoint remoteIpEndPoint, string sessionID, Encoding enc) + { + ProcessCommand(ref soUDP, ref remoteIpEndPoint, sessionID, enc); + + // handle 555 BANNED and 598 - UNKNOWN COMMAND + if (ResponseCode == 598) return enHelperActivityType.UnknownCommand; + if (ResponseCode == 555) return enHelperActivityType.Banned; + + if (errorOccurred) return enHelperActivityType.LoginRequired; + + // Process Response + string sMsgType = socketResponse.Substring(0, 3); + + + switch (sMsgType) + { + case "291": + { + + notifyListCollection = new Raw_AniDB_NotifyList(socketResponse); + return enHelperActivityType.GotNotifyList; + + } + case "501": + { + return enHelperActivityType.LoginRequired; + } + } + + return enHelperActivityType.GotNotifyList; + + } + + public AniDBCommand_NotifyList() + { + commandType = enAniDBCommandType.GetNotifyList; + } + + public void Init() + { + commandText = "NOTIFYLIST "; + + //BaseConfig.MyAnimeLog.Write("AniDBCommand_GetCalendar: Request: {0}", commandText); + + commandID = "NOTIFYLIST "; + } + } +} diff --git a/JMMServer/AniDB_API/Commands/AniDBCommand_Ping.cs b/JMMServer/AniDB_API/Commands/AniDBCommand_Ping.cs new file mode 100644 index 000000000..324d52164 --- /dev/null +++ b/JMMServer/AniDB_API/Commands/AniDBCommand_Ping.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Net; +using System.Net.Sockets; + +namespace AniDBAPI.Commands +{ + public class AniDBCommand_Ping : AniDBUDPCommand, IAniDBUDPCommand + { + public string SessionID = string.Empty; + + public virtual enHelperActivityType GetStartEventType() + { + return enHelperActivityType.Ping; + } + + public string GetKey() + { + return "Ping"; + } + + public virtual enHelperActivityType Process(ref Socket soUDP, + ref IPEndPoint remoteIpEndPoint, string sessionID, Encoding enc) + { + ProcessCommand(ref soUDP, ref remoteIpEndPoint, sessionID, enc); + + // handle 555 BANNED and 598 - UNKNOWN COMMAND + if (ResponseCode == 598) return enHelperActivityType.UnknownCommand; + if (ResponseCode == 555) return enHelperActivityType.Banned; + + if (errorOccurred) return enHelperActivityType.PingFailed; + + // Process Response + string sMsgType = socketResponse.Substring(0, 3); + + // 300 PONG + if (sMsgType.Equals("300")) + return enHelperActivityType.PingFailed; + else + return enHelperActivityType.PingPong; + + } + + public AniDBCommand_Ping() + { + commandType = enAniDBCommandType.Ping; + commandID = ""; + } + + public void Init() + { + commandText = "PING"; + commandID = "PING"; + } + } +} diff --git a/JMMServer/AniDB_API/Commands/AniDBCommand_UpdateFile.cs b/JMMServer/AniDB_API/Commands/AniDBCommand_UpdateFile.cs new file mode 100644 index 000000000..1f9f41816 --- /dev/null +++ b/JMMServer/AniDB_API/Commands/AniDBCommand_UpdateFile.cs @@ -0,0 +1,80 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Net.Sockets; +using System.Net; + +namespace AniDBAPI.Commands +{ + public class AniDBCommand_UpdateFile : AniDBUDPCommand, IAniDBUDPCommand + { + public IHash FileData = null; + public bool IsWatched = false; + + public string GetKey() + { + return "AniDBCommand_UpdateFile" + FileData.ED2KHash; + } + + public virtual enHelperActivityType GetStartEventType() + { + return enHelperActivityType.UpdatingFile; + } + + public virtual enHelperActivityType Process(ref Socket soUDP, + ref IPEndPoint remoteIpEndPoint, string sessionID, Encoding enc) + { + ProcessCommand(ref soUDP, ref remoteIpEndPoint, sessionID, enc); + + // handle 555 BANNED and 598 - UNKNOWN COMMAND + if (ResponseCode == 598) return enHelperActivityType.UnknownCommand; + if (ResponseCode == 555) return enHelperActivityType.Banned; + + if (errorOccurred) return enHelperActivityType.NoSuchFile; + + string sMsgType = socketResponse.Substring(0, 3); + switch (sMsgType) + { + case "210": + return enHelperActivityType.FileAdded; + case "310": + return enHelperActivityType.FileAlreadyExists; + case "311": + return enHelperActivityType.UpdatingFile; + case "320": + return enHelperActivityType.NoSuchFile; + case "411": + return enHelperActivityType.NoSuchFile; + + case "502": + return enHelperActivityType.LoginFailed; + case "501": + { + return enHelperActivityType.LoginRequired; + } + + } + + return enHelperActivityType.FileDoesNotExist; + } + + public AniDBCommand_UpdateFile() + { + commandType = enAniDBCommandType.UpdateFile; + } + + public void Init(IHash fileData, bool watched) + { + FileData = fileData; + IsWatched = watched; + + commandID = fileData.Info; + + commandText = "MYLISTADD size=" + fileData.FileSize.ToString(); + commandText += "&ed2k=" + fileData.ED2KHash; + commandText += "&viewed=" + (IsWatched ? "1" : "0"); //viewed + commandText += "&edit=1"; + } + } +} diff --git a/JMMServer/AniDB_API/Commands/AniDBCommand_Vote.cs b/JMMServer/AniDB_API/Commands/AniDBCommand_Vote.cs new file mode 100644 index 000000000..8ccb0b6b7 --- /dev/null +++ b/JMMServer/AniDB_API/Commands/AniDBCommand_Vote.cs @@ -0,0 +1,205 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Net.Sockets; +using System.Net; + +namespace AniDBAPI.Commands +{ + public class AniDBCommand_Vote : AniDBUDPCommand, IAniDBUDPCommand + { + private int entityID; + public int EntityID + { + get { return entityID; } + set { entityID = value; } + } + + private int episodeNumber = -1; + public int EpisodeNumber + { + get { return episodeNumber; } + set { episodeNumber = value; } + } + + private int voteValue; + public int VoteValue + { + get { return voteValue; } + set { voteValue = value; } + } + + private enAniDBVoteType voteType = enAniDBVoteType.Anime; + public enAniDBVoteType VoteType + { + get { return voteType; } + set { voteType = value; } + } + + private enEpisodeType episodeType = enEpisodeType.Episode; + public enEpisodeType EpisodeType + { + get { return episodeType; } + set { episodeType = value; } + } + + public string GetKey() + { + return "AniDBCommand_Vote" + entityID.ToString() + "_" + episodeNumber.ToString() + "_" + voteType.ToString() + "_" + episodeType.ToString(); + } + + public virtual enHelperActivityType GetStartEventType() + { + return enHelperActivityType.AddingVote; + } + + public virtual enHelperActivityType Process(ref Socket soUDP, + ref IPEndPoint remoteIpEndPoint, string sessionID, Encoding enc) + { + ProcessCommand(ref soUDP, ref remoteIpEndPoint, sessionID, enc); + + // handle 555 BANNED and 598 - UNKNOWN COMMAND + if (ResponseCode == 598) return enHelperActivityType.UnknownCommand; + if (ResponseCode == 555) return enHelperActivityType.Banned; + + if (errorOccurred) return enHelperActivityType.NoSuchVote; + + string sMsgType = socketResponse.Substring(0, 3); + switch (sMsgType) + { + case "260": + return enHelperActivityType.Voted; + case "261": + + // this means we were trying to retrieve the vote + + if (voteType == enAniDBVoteType.Anime || voteType == enAniDBVoteType.AnimeTemp) + { + // 261 VOTE FOUNDCode Geass Hangyaku no Lelouch|900|1|4521 + Raw_AniDB_Vote vote = new Raw_AniDB_Vote(); + vote.ProcessVoteFoundAnime(socketResponse, this.entityID, this.voteType); + this.voteValue = vote.VoteValue; + } + + if (voteType == enAniDBVoteType.Episode) + { + //261 VOTE FOUNDThe Day a New Demon Was Born|700|1|63091 + Raw_AniDB_Vote vote = new Raw_AniDB_Vote(); + vote.ProcessVoteFoundEpisode(socketResponse, this.entityID, this.episodeNumber, this.episodeType); + this.voteValue = vote.VoteValue; + } + + + return enHelperActivityType.VoteFound; + case "262": + return enHelperActivityType.VoteUpdated; + case "263": + return enHelperActivityType.VoteRevoked; + case "360": + return enHelperActivityType.NoSuchVote; + case "361": + return enHelperActivityType.InvalidVoteType; + case "362": + return enHelperActivityType.InvalidVoteValue; + case "363": + return enHelperActivityType.PermVoteNotAllowed; + case "364": + return enHelperActivityType.PermVoteAlready; + + case "501": + { + return enHelperActivityType.LoginRequired; + } + + } + + return enHelperActivityType.NoSuchVote; + } + + public AniDBCommand_Vote() + { + commandType = enAniDBCommandType.AddVote; + } + + public void Init(int entityid, decimal votevalue, enAniDBVoteType votetype) + { + // allow the user to enter a vote value between 1 and 10 + // can be 9.5 etc + // then multiple by 100 to get anidb value + + // type: 1=anime, 2=anime tmpvote, 3=group + // entity: anime, episode, or group + // for episode voting add epno on type=1 + // value: negative number means revoke, 0 means retrieve (default), 100-1000 are valid vote values, rest is illegal + // votes will be updated automatically (no questions asked) + // tmpvoting when there exist a perm vote is not possible + + this.entityID = entityid; + this.episodeNumber = -1; + if (votevalue > 0) + this.voteValue = (int)(votevalue * 100); + else + this.voteValue = (int)votevalue; + this.voteType = votetype; + this.episodeType = enEpisodeType.Episode; + + commandID = entityID.ToString(); + + int iVoteType = 1; + switch (voteType) + { + case enAniDBVoteType.Anime: iVoteType = 1; break; + case enAniDBVoteType.AnimeTemp: iVoteType = 2; break; + case enAniDBVoteType.Group: iVoteType = 3; break; + case enAniDBVoteType.Episode: iVoteType = 1; break; + } + + commandText = "VOTE type=" + iVoteType.ToString(); + commandText += "&id=" + entityID.ToString(); + commandText += "&value=" + voteValue.ToString(); + } + + public void InitEpisode(int entityid, int epno, decimal votevalue, enEpisodeType epType) + { + // allow the user to enter a vote value between 1 and 10 + // can be 9.5 etc + // then multiple by 100 to get anidb value + + // type: 1=anime, 2=anime tmpvote, 3=group + // entity: anime, episode, or group + // for episode voting add epno on type=1 + // value: negative number means revoke, 0 means retrieve (default), 100-1000 are valid vote values, rest is illegal + // votes will be updated automatically (no questions asked) + // tmpvoting when there exist a perm vote is not possible + + this.entityID = entityid; + this.episodeNumber = epno; + if (votevalue > 0) + this.voteValue = (int)(votevalue * 100); + else + this.voteValue = (int)votevalue; + this.voteType = enAniDBVoteType.Episode; + this.episodeType = epType; + + commandID = entityID.ToString(); + + int iVoteType = 1; + + string epNumberFormatted = episodeNumber.ToString(); + switch (epType) + { + case enEpisodeType.Credits: epNumberFormatted = "C" + epno.ToString(); break; + case enEpisodeType.Special: epNumberFormatted = "S" + epno.ToString(); break; + case enEpisodeType.Other: epNumberFormatted = "0" + epno.ToString(); break; + case enEpisodeType.Trailer: epNumberFormatted = "T" + epno.ToString(); break; + case enEpisodeType.Parody: epNumberFormatted = "P" + epno.ToString(); break; + } + + commandText = "VOTE type=" + iVoteType.ToString(); + commandText += "&id=" + entityID.ToString(); + commandText += "&value=" + voteValue.ToString(); + commandText += "&epno=" + epNumberFormatted; + } + } +} diff --git a/JMMServer/AniDB_API/Commands/AniDBHTTPCommand.cs b/JMMServer/AniDB_API/Commands/AniDBHTTPCommand.cs new file mode 100644 index 000000000..d3a63c8c1 --- /dev/null +++ b/JMMServer/AniDB_API/Commands/AniDBHTTPCommand.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer; + +namespace AniDBAPI.Commands +{ + public abstract class AniDBHTTPCommand + { + public string commandID = string.Empty; + public enAniDBCommandType commandType; + + public bool CheckForBan(string xmlresult) + { + if (string.IsNullOrEmpty(xmlresult)) return false; + + int index = xmlresult.IndexOf(@">banned<", 0, StringComparison.InvariantCultureIgnoreCase); + if (index > -1) + { + JMMService.AnidbProcessor.IsBanned = true; + return true; + } + return false; + } + } +} diff --git a/JMMServer/AniDB_API/Commands/AniDBHTTPCommand_GetFullAnime.cs b/JMMServer/AniDB_API/Commands/AniDBHTTPCommand_GetFullAnime.cs new file mode 100644 index 000000000..2eb2b3e54 --- /dev/null +++ b/JMMServer/AniDB_API/Commands/AniDBHTTPCommand_GetFullAnime.cs @@ -0,0 +1,192 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Xml; +using System.IO; +using JMMServer; + +namespace AniDBAPI.Commands +{ + public class AniDBHTTPCommand_GetFullAnime : AniDBHTTPCommand, IAniDBHTTPCommand + { + private int animeID; + public int AnimeID + { + get { return animeID; } + set { animeID = value; } + } + + private Raw_AniDB_Anime anime; + public Raw_AniDB_Anime Anime + { + get { return anime; } + set { anime = value; } + } + + private List episodes = new List(); + public List Episodes + { + get { return episodes; } + set { episodes = value; } + } + + private List titles = new List(); + public List Titles + { + get { return titles; } + set { titles = value; } + } + + private List categories = new List(); + public List Categories + { + get { return categories; } + set { categories = value; } + } + + private List tags = new List(); + public List Tags + { + get { return tags; } + set { tags = value; } + } + + private List characters = new List(); + public List Characters + { + get { return characters; } + set { characters = value; } + } + + private List relations = new List(); + public List Relations + { + get { return relations; } + set { relations = value; } + } + + private List similarAnime = new List(); + public List SimilarAnime + { + get { return similarAnime; } + set { similarAnime = value; } + } + + private bool createAnimeSeriesRecord = true; + public bool CreateAnimeSeriesRecord + { + get { return createAnimeSeriesRecord; } + set { createAnimeSeriesRecord = value; } + } + + private string xmlResult = ""; + public string XmlResult + { + get { return xmlResult; } + set { xmlResult = value; } + } + + public string GetKey() + { + return "AniDBHTTPCommand_GetFullAnime_" + AnimeID.ToString(); + } + + public virtual enHelperActivityType GetStartEventType() + { + return enHelperActivityType.GettingAnimeHTTP; + } + + private XmlDocument LoadAnimeHTTPFromFile(int animeID) + { + string appPath = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location); + string filePath = Path.Combine(appPath, "Anime_HTTP"); + + if (!Directory.Exists(filePath)) + Directory.CreateDirectory(filePath); + + string fileName = string.Format("AnimeDoc_{0}.xml", animeID); + string fileNameWithPath = Path.Combine(filePath, fileName); + + XmlDocument docAnime = null; + if (File.Exists(fileNameWithPath)) + { + StreamReader re = File.OpenText(fileNameWithPath); + string rawXML = re.ReadToEnd(); + re.Close(); + + docAnime = new XmlDocument(); + docAnime.LoadXml(rawXML); + } + + return docAnime; + } + + private void WriteAnimeHTTPToFile(int animeID, string xml) + { + string appPath = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location); + string filePath = Path.Combine(appPath, "Anime_HTTP"); + + if (!Directory.Exists(filePath)) + Directory.CreateDirectory(filePath); + + string fileName = string.Format("AnimeDoc_{0}.xml", animeID); + string fileNameWithPath = Path.Combine(filePath, fileName); + + StreamWriter sw; + sw = File.CreateText(fileNameWithPath); + sw.Write(xml); + sw.Close(); + } + + public virtual enHelperActivityType Process() + { + string appPath = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location); + string filePath = Path.Combine(appPath, "Anime_HTTP"); + + if (!Directory.Exists(filePath)) + Directory.CreateDirectory(filePath); + + string fileName = string.Format("AnimeDoc_{0}.xml", animeID); + string fileNameWithPath = Path.Combine(filePath, fileName); + + JMMService.LastAniDBMessage = DateTime.Now; + JMMService.LastAniDBHTTPMessage = DateTime.Now; + XmlDocument docAnime = AniDBHTTPHelper.GetAnimeXMLFromAPI(animeID, ref xmlResult); + + if (xmlResult.Trim().Length > 0) + WriteAnimeHTTPToFile(animeID, xmlResult); + + if (CheckForBan(xmlResult)) return enHelperActivityType.NoSuchAnime; + + if (docAnime != null) + { + anime = AniDBHTTPHelper.ProcessAnimeDetails(docAnime, animeID); + episodes = AniDBHTTPHelper.ProcessEpisodes(docAnime, animeID); + titles = AniDBHTTPHelper.ProcessTitles(docAnime, animeID); + categories = AniDBHTTPHelper.ProcessCategories(docAnime, animeID); + tags = AniDBHTTPHelper.ProcessTags(docAnime, animeID); + characters = AniDBHTTPHelper.ProcessCharacters(docAnime, animeID); + relations = AniDBHTTPHelper.ProcessRelations(docAnime, animeID); + similarAnime = AniDBHTTPHelper.ProcessSimilarAnime(docAnime, animeID); + return enHelperActivityType.GotAnimeInfoHTTP; + } + else + { + return enHelperActivityType.NoSuchAnime; + } + } + + public AniDBHTTPCommand_GetFullAnime() + { + commandType = enAniDBCommandType.GetAnimeInfoHTTP; + } + + public void Init(int animeID, bool createSeriesRecord) + { + this.animeID = animeID; + commandID = animeID.ToString(); + this.createAnimeSeriesRecord = createSeriesRecord; + } + } +} diff --git a/JMMServer/AniDB_API/Commands/AniDBHTTPCommand_GetMyList.cs b/JMMServer/AniDB_API/Commands/AniDBHTTPCommand_GetMyList.cs new file mode 100644 index 000000000..81e5cd912 --- /dev/null +++ b/JMMServer/AniDB_API/Commands/AniDBHTTPCommand_GetMyList.cs @@ -0,0 +1,132 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Xml; +using JMMServer; +using System.IO; + +namespace AniDBAPI.Commands +{ + public class AniDBHTTPCommand_GetMyList : AniDBHTTPCommand, IAniDBHTTPCommand + { + private List myListItems = new List(); + public List MyListItems + { + get { return myListItems; } + set { myListItems = value; } + } + + private string username = ""; + public string Username + { + get { return username; } + set { username = value; } + } + + private string password = ""; + public string Password + { + get { return password; } + set { password = value; } + } + + private string xmlResult = ""; + public string XmlResult + { + get { return xmlResult; } + set { xmlResult = value; } + } + + public string GetKey() + { + return "AniDBHTTPCommand_GetMyList"; + } + + public virtual enHelperActivityType GetStartEventType() + { + return enHelperActivityType.GettingMyListHTTP; + } + + private void WriteAnimeMyListToFile(string xml) + { + string appPath = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location); + string filePath = Path.Combine(appPath, "MyList"); + + if (!Directory.Exists(filePath)) + Directory.CreateDirectory(filePath); + + //string fileName = string.Format("MyList_{0}_{1}.xml", DateTime.Now.ToString("yyyyMMdd"), DateTime.Now.ToString("HHmmss")); + string fileName = string.Format("MyList.xml"); + string fileNameWithPath = Path.Combine(filePath, fileName); + + StreamWriter sw; + sw = File.CreateText(fileNameWithPath); + sw.Write(xml); + sw.Close(); + } + + private XmlDocument LoadAnimeMyListFromFile() + { + string appPath = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location); + string filePath = Path.Combine(appPath, "MyList"); + + if (!Directory.Exists(filePath)) + Directory.CreateDirectory(filePath); + + string fileName = string.Format("MyList.xml"); + string fileNameWithPath = Path.Combine(filePath, fileName); + + XmlDocument docAnime = null; + if (File.Exists(fileNameWithPath)) + { + StreamReader re = File.OpenText(fileNameWithPath); + string rawXML = re.ReadToEnd(); + re.Close(); + + docAnime = new XmlDocument(); + docAnime.LoadXml(rawXML); + } + + return docAnime; + } + + public virtual enHelperActivityType Process() + { + JMMService.LastAniDBMessage = DateTime.Now; + JMMService.LastAniDBHTTPMessage = DateTime.Now; + + XmlDocument docAnime = AniDBHTTPHelper.GetMyListXMLFromAPI(username, password, ref xmlResult); + //XmlDocument docAnime = LoadAnimeMyListFromFile(); + //APIUtils.WriteToLog("AniDBHTTPCommand_GetFullAnime: " + xmlResult); + + if (xmlResult.Trim().Length > 0) + WriteAnimeMyListToFile(xmlResult); + + if (CheckForBan(xmlResult)) return enHelperActivityType.NoSuchAnime; + + if (docAnime != null) + { + + myListItems = AniDBHTTPHelper.ProcessMyList(docAnime); + return enHelperActivityType.GotMyListHTTP; + } + else + { + return enHelperActivityType.NoSuchAnime; + } + } + + public AniDBHTTPCommand_GetMyList() + { + commandType = enAniDBCommandType.GetMyListHTTP; + } + + public void Init(string uname, string pword) + { + this.username = uname; + this.password = pword; + commandID = "MYLIST"; + } + } +} diff --git a/JMMServer/AniDB_API/Commands/AniDBHTTPCommand_GetVotes.cs b/JMMServer/AniDB_API/Commands/AniDBHTTPCommand_GetVotes.cs new file mode 100644 index 000000000..d20692df8 --- /dev/null +++ b/JMMServer/AniDB_API/Commands/AniDBHTTPCommand_GetVotes.cs @@ -0,0 +1,84 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using AniDBAPI.Commands; +using AniDBAPI; +using JMMServer.AniDB_API.Raws; +using System.Xml; + +namespace JMMServer.AniDB_API.Commands +{ + public class AniDBHTTPCommand_GetVotes : AniDBHTTPCommand, IAniDBHTTPCommand + { + private List myVotes = new List(); + public List MyVotes + { + get { return myVotes; } + set { myVotes = value; } + } + + private string username = ""; + public string Username + { + get { return username; } + set { username = value; } + } + + private string password = ""; + public string Password + { + get { return password; } + set { password = value; } + } + + private string xmlResult = ""; + public string XmlResult + { + get { return xmlResult; } + set { xmlResult = value; } + } + + public string GetKey() + { + return "AniDBHTTPCommand_GetVotes"; + } + + public virtual enHelperActivityType GetStartEventType() + { + return enHelperActivityType.GettingVotesHTTP; + } + + public virtual enHelperActivityType Process() + { + + XmlDocument docAnime = AniDBHTTPHelper.GetVotesXMLFromAPI(username, password, ref xmlResult); + + if (CheckForBan(xmlResult)) return enHelperActivityType.NoSuchAnime; + + //APIUtils.WriteToLog("AniDBHTTPCommand_GetFullAnime: " + xmlResult); + if (docAnime != null) + { + + myVotes = AniDBHTTPHelper.ProcessVotes(docAnime); + return enHelperActivityType.GotVotesHTTP; + } + else + { + return enHelperActivityType.NoSuchAnime; + } + } + + public AniDBHTTPCommand_GetVotes() + { + commandType = enAniDBCommandType.GetVotesHTTP; + } + + public void Init(string uname, string pword) + { + this.username = uname; + this.password = pword; + commandID = "VOTES"; + } + } +} diff --git a/JMMServer/AniDB_API/Commands/AniDBUDPCommand.cs b/JMMServer/AniDB_API/Commands/AniDBUDPCommand.cs new file mode 100644 index 000000000..0beed9da9 --- /dev/null +++ b/JMMServer/AniDB_API/Commands/AniDBUDPCommand.cs @@ -0,0 +1,274 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using ICSharpCode.SharpZipLib.Zip.Compression; +using System.Net.Sockets; +using System.Threading; +using System.Net; +using NLog; +using JMMServer; + +namespace AniDBAPI.Commands +{ + public abstract class AniDBUDPCommand + { + private static Logger logger = LogManager.GetCurrentClassLogger(); + + public string commandText = string.Empty; + public string socketResponse = string.Empty; + public string errorMessage = string.Empty; + public bool errorOccurred = false; + public string mcommandText = string.Empty; + + public string commandID = string.Empty; + protected string sessionID = string.Empty; + public enAniDBCommandType commandType; + private Encoding encoding = Encoding.ASCII; + public int ResponseCode { get; set; } + + public Encoding Encoding { get { return encoding; } } + public void ProcessCommand(ref Socket soUDP, + ref IPEndPoint remoteIpEndPoint, string sessionID, Encoding enc) + { + this.sessionID = sessionID; + Encoding changeencoding = null; + encoding = enc; + EndPoint RemotePoint = (remoteIpEndPoint); + mcommandText = commandText; + errorOccurred = false; + + if (commandType != enAniDBCommandType.Ping) + { + if (commandType != enAniDBCommandType.Login) + { + if (commandType != enAniDBCommandType.Logout) + { + mcommandText += "&"; + } + mcommandText += "s=" + sessionID; + } + else + { + encoding = System.Text.Encoding.ASCII; + changeencoding = enc; + string encod = changeencoding.EncodingName; + if (changeencoding.EncodingName.StartsWith("Unicode")) + encod = "utf-16"; + mcommandText += "&enc=" + encod; + } + } + bool multipart = false; + int part = 0; + int maxpart = 1; + string fulldesc = ""; + string decodedstring = ""; + do + { + + if (part > 0) + { + mcommandText = mcommandText.Replace("part=" + (part - 1).ToString(), "part=" + part.ToString()); + Thread.Sleep(2300); + } + if (commandType != enAniDBCommandType.Login) + { + logger.Trace("ANIDB_UDP_COMMS commandText: {0}", mcommandText); + } + else + { + //string msg = commandText.Replace(MainWindow.settings.Username, "******"); + //msg = msg.Replace(MainWindow.settings.Password, "******"); + //MyAnimeLog.Write("commandText: {0}", msg); + } + bool repeatcmd; + int received; + Byte[] byReceivedAdd = new Byte[2000]; // max length should actually be 1400 + do + { + repeatcmd = false; + // Send Message + Byte[] SendByteAdd = Encoding.GetBytes(mcommandText.ToCharArray()); + + try + { + JMMService.LastAniDBMessage = DateTime.Now; + JMMService.LastAniDBUDPMessage = DateTime.Now; + if (commandType != enAniDBCommandType.Ping) + JMMService.LastAniDBMessageNonPing = DateTime.Now; + else + JMMService.LastAniDBPing = DateTime.Now; + + soUDP.SendTo(SendByteAdd, remoteIpEndPoint); + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + //MyAnimeLog.Write(ex.ToString()); + errorOccurred = true; + errorMessage = ex.ToString(); + } + + + // Receive Response + received = 0; + try + { + //MyAnimeLog.Write("soUDP.ReceiveTimeout = {0}", soUDP.ReceiveTimeout.ToString()); + + + received = soUDP.ReceiveFrom(byReceivedAdd, ref RemotePoint); + JMMService.LastAniDBMessage = DateTime.Now; + JMMService.LastAniDBUDPMessage = DateTime.Now; + if (commandType != enAniDBCommandType.Ping) + JMMService.LastAniDBMessageNonPing = DateTime.Now; + else + JMMService.LastAniDBPing = DateTime.Now; + + //MyAnimeLog.Write("Buffer length = {0}", received.ToString()); + if ((received > 2) && ((byReceivedAdd[0] == 0) && (byReceivedAdd[1] == 0))) + { + //deflate + Byte[] buff = new byte[65536]; + Byte[] input = new byte[received - 2]; + Array.Copy(byReceivedAdd, 2, input, 0, received - 2); + Inflater inf = new Inflater(false); + inf.SetInput(input); + inf.Inflate(buff); + byReceivedAdd = buff; + received = (int)inf.TotalOut; + } + } + catch (SocketException sex) + { + // most likely we have timed out + logger.ErrorException(sex.ToString(), sex); + errorOccurred = true; + errorMessage = sex.ToString(); + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + errorOccurred = true; + errorMessage = ex.ToString(); + } + if ((commandType == enAniDBCommandType.Login) && (byReceivedAdd[0] == 0xFE) && (byReceivedAdd[1] == 0xFF) && (byReceivedAdd[3] == 53) && (byReceivedAdd[5] != 53) && (!Encoding.EncodingName.ToLower().StartsWith("unicode")) && (changeencoding != null) && (changeencoding.EncodingName.ToLower().StartsWith("unicode"))) + { + //Previous Session used utf-16 and was not logged out, AniDB was not yet issued a timeout. + //AUTH command was not understand because it was encoded in ASCII. + encoding = changeencoding; + repeatcmd = true; + } + + } while (repeatcmd); + + if (!errorOccurred) + { + if (changeencoding != null) + encoding = changeencoding; + System.Text.Encoding enco; + if ((byReceivedAdd[0] == 0xFE) && (byReceivedAdd[1] == 0xFF)) + enco = encoding; + else + enco = Encoding.ASCII; + decodedstring = enco.GetString(byReceivedAdd, 0, received); + + if (decodedstring[0] == 0xFEFF) // remove BOM + decodedstring = decodedstring.Substring(1); + if (commandType == enAniDBCommandType.GetAnimeDescription || commandType == enAniDBCommandType.GetReview) + { + //Lets handle multipart + part++; + string[] sp1 = decodedstring.Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries); + + if (sp1[0].StartsWith("233 ANIMEDESC") || sp1[0].StartsWith("233 ANIMEDESC")) + { + string[] sp2 = sp1[1].Split('|'); + fulldesc += sp2[2]; + maxpart = int.Parse(sp2[1]); + } + + if (sp1[0].StartsWith("234 REVIEW") || sp1[0].StartsWith("234 REVIEW")) + { + string[] sp2 = sp1[1].Split('|'); + + if (sp2.Length == 3) + fulldesc += sp2[2]; + else + { + for (int i = 2; i < sp2.Length; i++) + fulldesc += "|" + sp2[i]; + } + + + maxpart = int.Parse(sp2[1]); + } + multipart = true; + if (part == maxpart) + { + decodedstring = sp1[0] + "\n0|1|" + fulldesc + "\n"; + multipart = false; + } + } + } + } while ((multipart) && (!errorOccurred)); + + if (errorOccurred) + { + socketResponse = string.Empty; + } + else + { + // there should be 2 newline characters in each response + // the first is after the command .e.g "220 FILE" + // the second is at the end of the data + int i = 0, ipos = 0, foundpos = 0; + foreach (char c in decodedstring) + { + if (c == '\n') + { + //MyAnimeLog.Write("NEWLINE FOUND AT: {0}", ipos); + i++; + foundpos = ipos; + } + ipos++; + } + + if (i != 2) + { + socketResponse = decodedstring; + logger.Trace("ANIDB_UDP_COMMS socketResponse: {0}", socketResponse); + } + else + { + socketResponse = decodedstring.Substring(0, foundpos + 1); + logger.Trace("ANIDB_UDP_COMMS truncated socketResponse: {0}", socketResponse); + } + } + int val = 0; + if (socketResponse.Length > 2) + int.TryParse(socketResponse.Substring(0, 3), out val); + this.ResponseCode = val; + + // if we get banned pause the command processor for a while + // so we don't make the ban worse + if (ResponseCode == 555) + JMMService.AnidbProcessor.IsBanned = true; + else + JMMService.AnidbProcessor.IsBanned = false; + + // 598 unknown command usually means we had connections issue + // reset login status to start again + if (ResponseCode == 598) + { + JMMService.AnidbProcessor.IsLoggedOn = false; + } + + } + + public AniDBUDPCommand() + { + ResponseCode = 0; + } + } +} diff --git a/JMMServer/AniDB_API/Commands/IAniDBHTTPCommand.cs b/JMMServer/AniDB_API/Commands/IAniDBHTTPCommand.cs new file mode 100644 index 000000000..f614ef263 --- /dev/null +++ b/JMMServer/AniDB_API/Commands/IAniDBHTTPCommand.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace AniDBAPI.Commands +{ + public interface IAniDBHTTPCommand + { + enHelperActivityType GetStartEventType(); + enHelperActivityType Process(); + string GetKey(); + + } +} diff --git a/JMMServer/AniDB_API/Commands/IAniDBUDPCommand.cs b/JMMServer/AniDB_API/Commands/IAniDBUDPCommand.cs new file mode 100644 index 000000000..c3ac22454 --- /dev/null +++ b/JMMServer/AniDB_API/Commands/IAniDBUDPCommand.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Net.Sockets; +using System.Net; + +namespace AniDBAPI.Commands +{ + public interface IAniDBUDPCommand + { + enHelperActivityType GetStartEventType(); + enHelperActivityType Process(ref Socket soUDP, ref IPEndPoint remoteIpEndPoint, string sessionID, Encoding enc); + string GetKey(); + + } +} diff --git a/JMMServer/AniDB_API/Enums.cs b/JMMServer/AniDB_API/Enums.cs new file mode 100644 index 000000000..f67fbfbcc --- /dev/null +++ b/JMMServer/AniDB_API/Enums.cs @@ -0,0 +1,154 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace AniDBAPI +{ + public enum AniDBFileStatus + { + Unknown = 1, + HDD = 2, + DVD = 3 + } + + public enum enAniDBVoteType + { + Anime = 1, + AnimeTemp = 2, + Group = 3, + Episode = 4 + } + + public enum enAniDBCommandType + { + Login = 1, + Logout = 2, + AddFile = 3, + GetFileInfo = 4, + GetAnimeInfo = 5, + GetEpisodeInfo = 6, + GetAnimeDescription = 7, + GetMyListFileInfo = 8, + GetGroupStatus = 9, + UpdateFile = 10, + GetCharInfo = 11, + GetCreatorInfo = 12, + GetCalendar = 13, + GetReview = 14, + AddVote = 15, + GetAnimeInfoHTTP = 16, + GetNotifyList = 17, + GetNotifyGet = 18, + GetUpdated = 19, + GetMyListHTTP = 20, + Ping = 21, + GetGroup = 22, + GetVotesHTTP = 23, + DeleteFile = 24 + + } + + public enum enHelperActivityType + { + //Login + LoggingIn = 1, + LoggedIn = 2, + LoggedInAlready = 3, + LoggedOut = 4, + LoginFailed = 5, + LoggingOut = 6, + LoginRequired = 7, + //File + HashingFile = 10, + HashComplete = 11, + AddingFile = 12, + FileAdded = 13, + GettingFileInfo = 14, + GotFileInfo = 15, + FileDoesNotExist = 16, + FileAlreadyExists = 17, + NoSuchFile = 18, + UpdatingFile = 20, + DeletingFile = 21, + FileDeleted = 22, + //Episode + GotEpisodeInfo = 30, + GettingEpisodeInfo = 32, + NoSuchEpisode = 33, + //Anime + GettingAnimeInfo = 41, + GotAnimeInfo = 42, + NoSuchAnime = 43, + GettingAnimeDesc = 44, + GotAnimeDesc = 45, + GettingGroupStatus = 46, + GotGroupStatus = 47, + NoGroupsFound = 48, + //My List + GettingMyListFileInfo = 50, + NoSuchMyListFile = 51, + GotMyListFileInfo = 52, + //Char + GotCharInfo = 60, + GettingCharInfo = 61, + NoSuchChar = 62, + //Creator + GotCreatorInfo = 70, + GettingCreatorInfo = 71, + NoSuchCreator = 72, + // Calendar + GotCalendar = 81, + CalendarEmpty = 82, + GettingCalendar = 83, + // Review + GotReview = 91, + GettingReview = 92, + NoSuchReview = 93, + // Vote + Voted = 111, + AddingVote = 112, + VoteFound = 113, + VoteUpdated = 114, + VoteRevoked = 115, + NoSuchVote = 116, + InvalidVoteType = 117, + InvalidVoteValue = 118, + PermVoteNotAllowed = 119, + PermVoteAlready = 120, + //Misc + StatusUpdate = 40, + OtherError = 100, + // HTTP, + GettingAnimeHTTP = 121, + GotAnimeInfoHTTP = 122, + GettingMyListHTTP = 123, + GotMyListHTTP = 124, + GettingVotesHTTP = 125, + GotVotesHTTP = 126, + // Notify List + GotNotifyList = 130, + GettingNotifyList = 131, + // Notify Get + GotNotifyGet = 140, + GettingNotifyGet = 141, + NoSuchNotify = 142, + // Updated + GotUpdated = 151, + GettingUpdated = 152, + NoUpdates = 153, + // Group + GettingGroup = 160, + GotGroup = 161, + NoSuchGroup = 162, + + Ping = 900, + PingFailed = 901, + PingPong = 902, + + UnknownCommand = 950, + Banned = 951 + } + + +} diff --git a/JMMServer/AniDB_API/GroupStatusCollection.cs b/JMMServer/AniDB_API/GroupStatusCollection.cs new file mode 100644 index 000000000..a7c9970a7 --- /dev/null +++ b/JMMServer/AniDB_API/GroupStatusCollection.cs @@ -0,0 +1,99 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace AniDBAPI +{ + public class GroupStatusCollection + { + private List groups = new List(); + public List Groups + { + get { return groups; } + } + + public List GetMissingEpisodes(int latestEpNumber) + { + List missingGroups = new List(); + + foreach (Raw_AniDB_GroupStatus grp in groups) + { + if (grp.LastEpisodeNumber > latestEpNumber) + missingGroups.Add(grp); + } + + return missingGroups; + } + + public int LatestEpisodeNumber + { + get + { + int latest = 0; + + foreach (Raw_AniDB_GroupStatus grp in groups) + { + if (grp.LastEpisodeNumber > latest) + latest = grp.LastEpisodeNumber; + } + + return latest; + } + } + + public GroupStatusCollection(int animeID, string sRecMessage) + { + /* + // 225 GROUPSTATUS + 1612|MDAN|1|9|784|2|1-9 + 1412|Dattebayo|1|9|677|55|1-9 + 6371|Hatsuyuki Fansub|1|9|738|4|1-9 + 5900|Shiroi-Fansubs|1|9|645|3|1-9 + 6897|Black Ocean Team|1|8|0|0|1-8 + 7209|Otaku Trad Team|1|8|0|0|1-8 + 5816|ALanime Fansub|1|7|836|2|1-7 + 1472|Saikou-BR|1|6|0|0|1-6 + 6638|Yuurisan-Subs & Shinsen-Subs|1|5|674|12|1-5 + 7624|Desire & Himmel & Inmeliora|1|5|657|15|1-5 + 2777|S?ai`No`Naka|1|5|867|1|1-5 + 5618|Yuurisan-Subs|1|5|594|4|1-5 + 6738|AnimeManganTR|1|5|0|0|1-5 + 7673|PA-Fansub|1|4|0|0|1-4 + 7512|Anime Brat|1|3|0|0|1-3 + 7560|Demon Sub|1|3|0|0|1-3 + 6197|Funny and Fantasy subs|1|2|896|1|1-2 + 7887|Yaoi Daisuki no Fansub & Sleepless Beauty no Fansub|1|7|0|0|5,7 + 7466|Aasasubs Clique|1|1|578|4|1 + 7429|Inter-Anime Fansub|1|1|656|1|1 + 6358|Aino Fansub|1|8|0|0|8 + 6656|Atelier Thryst|1|1|747|13|1 + */ + + // remove the header info + string[] sDetails = sRecMessage.Substring(0).Split('\n'); + + if (sDetails.Length <= 2) return; + + for (int i=1; i< sDetails.Length -1; i++) // first item will be the status command, and last will be empty + { + //BaseConfig.MyAnimeLog.Write("s: {0}", sDetails[i]); + + Raw_AniDB_GroupStatus grp = new Raw_AniDB_GroupStatus(); + grp.AnimeID = animeID; + + // {int group id}|{str group name}|{int completion state}|{int last episode number}|{int rating}|{int votes}|{str episode range}\n + string[] flds = sDetails[i].Substring(0).Split('|'); + grp.GroupID = int.Parse(flds[0]); + grp.GroupName = flds[1]; + grp.CompletionState = int.Parse(flds[2]); + grp.LastEpisodeNumber = int.Parse(flds[3]); + grp.Rating = int.Parse(flds[4]); + grp.Votes = int.Parse(flds[5]); + grp.EpisodeRange = flds[6]; + groups.Add(grp); + + //BaseConfig.MyAnimeLog.Write("grp: {0}", grp); + } + } + } +} diff --git a/JMMServer/AniDB_API/IHash.cs b/JMMServer/AniDB_API/IHash.cs new file mode 100644 index 000000000..1c0a14eeb --- /dev/null +++ b/JMMServer/AniDB_API/IHash.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace AniDBAPI +{ + public interface IHash + { + string ED2KHash { get; set; } + long FileSize { get; set; } + string Info { get; } + } + + public class IHashDummy : IHash + { + public long FileSize { get; set; } + public string ED2KHash { get; set; } + public string Info { get; set; } + } +} diff --git a/JMMServer/AniDB_API/NotifyListHeader.cs b/JMMServer/AniDB_API/NotifyListHeader.cs new file mode 100644 index 000000000..35127627f --- /dev/null +++ b/JMMServer/AniDB_API/NotifyListHeader.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace AniDBAPI +{ + public class NotifyListHeader + { + private string notifyType = ""; + + public string NotifyType + { + get { return notifyType; } + set { notifyType = value; } + } + + private long notifyID = 0; + + public long NotifyID + { + get { return notifyID; } + set { notifyID = value; } + } + } +} diff --git a/JMMServer/AniDB_API/Raws/Raw_AniDB_Anime.cs b/JMMServer/AniDB_API/Raws/Raw_AniDB_Anime.cs new file mode 100644 index 000000000..080e65d23 --- /dev/null +++ b/JMMServer/AniDB_API/Raws/Raw_AniDB_Anime.cs @@ -0,0 +1,297 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Text; +using System.Xml.Serialization; +using System.IO; +using System.Xml; +using JMMServer; + + +namespace AniDBAPI +{ + [Serializable] + public class Raw_AniDB_Anime : XMLBase + { + #region Properties + + public int AnimeID { get; set; } + public int EpisodeCount { get; set; } + public DateTime? AirDate { get; set; } + public DateTime? EndDate { get; set; } + public string URL { get; set; } + public string Picname { get; set; } + public int BeginYear { get; set; } + public int EndYear { get; set; } + public string MainTitle { get; set; } + public string Description { get; set; } + public int EpisodeCountNormal { get; set; } + public int EpisodeCountSpecial { get; set; } + public int Rating { get; set; } + public int VoteCount { get; set; } + public int TempRating { get; set; } + public int TempVoteCount { get; set; } + public int AvgReviewRating { get; set; } + public int ReviewCount { get; set; } + public DateTime DateTimeUpdated { get; set; } + public DateTime? DateTimeDescUpdated { get; set; } + + [XmlIgnore] + public int ImageEnabled { get; set; } + public int VersionNumber { get; set; } + public string AwardList { get; set; } + public int Restricted { get; set; } + public int AnimePlanetID { get; set; } + public int ANNID { get; set; } + public int AllCinemaID { get; set; } + public string AnimeNfoID { get; set; } + public string DateRecordUpdated { get; set; } + + [XmlIgnore] + public int? LatestEpisodeNumber { get; set; } + + [XmlIgnore] + public int AirDateAsSeconds + { + get + { + return Utils.GetAniDBDateAsSeconds(AirDate); + } + } + + [XmlIgnore] + public int EndDateAsSeconds + { + get + { + return Utils.GetAniDBDateAsSeconds(EndDate); + } + } + + + public string AnimeTypeRAW { get; set; } + public string GenreRAW { get; set; } + public string RelatedAnimeIdsRAW { get; set; } + public string RelatedAnimeTypesRAW { get; set; } + public string CharacterIDListRAW { get; set; } + public string ReviewIDListRAW { get; set; } + + [XmlIgnore] + public List ReviewIDList + { + get + { + List reviewIDList = new List(); + + try + { + if (ReviewIDListRAW.Length > 0) + { + string[] reviews = ReviewIDListRAW.Split(','); + foreach (string rid in reviews) + { + reviewIDList.Add(int.Parse(rid)); + } + } + } + catch (Exception ex) + { + //BaseConfig.MyAnimeLog.Write("Error trying to get reviews from anime: {0}", ex); + } + + return reviewIDList; + } + } + + + + + #endregion + + public readonly static int LastVersion = 1; + + private void PopulateDefaults() + { + RelatedAnimeIdsRAW = string.Empty; + RelatedAnimeTypesRAW = string.Empty; + CharacterIDListRAW = string.Empty; + GenreRAW = string.Empty; + AnimeTypeRAW = string.Empty; + ReviewIDListRAW = string.Empty; + AnimeID = 0; + VersionNumber = 0; + EpisodeCount = 0; + AirDate = null; + EndDate = null; + URL = string.Empty; + Picname = string.Empty; + BeginYear = 0; + EndYear = 0; + ImageEnabled = 1; + Description = string.Empty; + EpisodeCountNormal = 0; + EpisodeCountSpecial = 0; + MainTitle = string.Empty; + Rating = 0; + VoteCount = 0; + TempRating = 0; + TempVoteCount = 0; + AvgReviewRating = 0; + ReviewCount = 0; + AwardList = string.Empty; + Restricted = 0; + AnimePlanetID = 0; + ANNID = 0; + AllCinemaID = 0; + AnimeNfoID = string.Empty; + DateRecordUpdated = string.Empty; + DateTimeUpdated = DateTime.Now; + DateTimeDescUpdated = null; + } + + // default constructor + public Raw_AniDB_Anime() + { + PopulateDefaults(); + + } + + // constructor + // sRecMessage is the message received from ANIDB file info command + // example response like '220 FILE .....' + public Raw_AniDB_Anime(string sRecMessage) + { + PopulateDefaults(); + + // remove the header info + string[] sDetails = sRecMessage.Substring(10).Split('|'); + + //230 ANIME 0|0 + // 0. 6107 ** anime id + // 1. 2009 ** year + // 2. TV Series ** type + // 3. 979 ** related anime id's + // 4. 32 ** related anime types + // 5. Magic,Shounen,Manga,Military,Action ** genres + // 6. 6,6,6,6,4 ** genreRAW weight + // 7. Hagane no Renkinjutsushi (2009) ** romaji name + // 8. Kanji Name + // 9. Full Metal Alchemist: Brotherhood ** english name + // 10. * other name + // 11. FMA2'hagaren2 ** short name list (the apostrophe is the list separator) + // 12. Fullmetal Alchemist: Brotherhood'Fullmetal Alchemist 2'Full Metal Alchemist 2'???????? ???????: ????????'St?lalkemisten'????????? ??????? ?????? : ??????'2 ????????? ??????? ??????'??????? ????? 2009'Metalinis Alchemikas 2'?????? 2009 ** synonyms + // 13. 0 ** episodes + // 14. 5 ** normal episode count + // 15. 6 ** special episode count + // 16. 1238889600 ** air date + // 17. 0 ** end date + // 18. http://www.hagaren.jp/ ** url + // 19. 15097.jpg ** pic name + // 20. 175,5,273,171,4 ** category id list + // 21. 0 ** rating + // 22. 0 ** vote count + // 23. 846 ** temp rating (divide by 100) + // 24. 416 ** temp vote count + // 25. 0 ** average review rating + // 26. 0 ** review count + // 27. ** Award List + // 28. 0 ** Restricted 18+ + // 29. 0 Anime Planet ID + // 30. 0 ANN ID + // 31. 0 AllCinema ID + // 32. 0 AnimeNfo ID + // 33. 1238889600 ** last modified + // 34. 705,2409,2410,2411,2412,2413,2414,2415 ** character id list + // 35. 705,2409,2410,2411,2412,2413,2414,2415 ** review id list + + + AnimeID = int.Parse(sDetails[0]); + AnimeTypeRAW = AniDBAPILib.ProcessAniDBString(sDetails[2]); + RelatedAnimeIdsRAW = AniDBAPILib.ProcessAniDBString(sDetails[3]); + + + //BaseConfig.MyAnimeLog.Write("relatedAnimeIDs: {0}", sDetails[3]); + //BaseConfig.MyAnimeLog.Write("relatedAnimeIDs: {0}", AniDBLib.ProcessAniDBString(sDetails[3])); + + RelatedAnimeTypesRAW = AniDBAPILib.ProcessAniDBString(sDetails[4]); + //genreweight = sDetails[6]; + //RomajiName = AniDBAPILib.ProcessAniDBString(sDetails[7]); + //BaseConfig.MyAnimeLog.Write("English name old: **{0}**", sDetails[8]); + //KanjiName = AniDBAPILib.ProcessAniDBString(sDetails[8]); + //EnglishName = AniDBAPILib.ProcessAniDBString(sDetails[9]); + //BaseConfig.MyAnimeLog.Write("English name new: **{0}**", englishName); + //OtherName = AniDBAPILib.ProcessAniDBString(sDetails[10]); + //ShortNames = AniDBAPILib.ProcessAniDBString(sDetails[11].Replace("'", "|")); + //Synonyms = AniDBAPILib.ProcessAniDBString(sDetails[12].Replace("'", "|")); + EpisodeCount = AniDBAPILib.ProcessAniDBInt(sDetails[13]); + EpisodeCountNormal = AniDBAPILib.ProcessAniDBInt(sDetails[14]); + EpisodeCountSpecial = AniDBAPILib.ProcessAniDBInt(sDetails[15]); + + int airDateSeconds = int.Parse(AniDBAPILib.ProcessAniDBString(sDetails[16])); + int endDateSeconds = int.Parse(AniDBAPILib.ProcessAniDBString(sDetails[17])); + + AirDate = Utils.GetAniDBDateAsDate(airDateSeconds); + EndDate = Utils.GetAniDBDateAsDate(endDateSeconds); + + URL = AniDBAPILib.ProcessAniDBString(sDetails[18]); + Picname = AniDBAPILib.ProcessAniDBString(sDetails[19]); + //categoryidlist = sDetails[20]; + Rating = AniDBAPILib.ProcessAniDBInt(sDetails[21]); + VoteCount = AniDBAPILib.ProcessAniDBInt(sDetails[22]); + TempRating = AniDBAPILib.ProcessAniDBInt(sDetails[23]); + TempVoteCount = AniDBAPILib.ProcessAniDBInt(sDetails[24]); + AvgReviewRating = AniDBAPILib.ProcessAniDBInt(sDetails[25]); + ReviewCount = AniDBAPILib.ProcessAniDBInt(sDetails[26]); + AwardList = AniDBAPILib.ProcessAniDBString(sDetails[27]); + Restricted =AniDBAPILib.ProcessAniDBInt(sDetails[28]); + AnimePlanetID=AniDBAPILib.ProcessAniDBInt(sDetails[29]); + ANNID=AniDBAPILib.ProcessAniDBInt(sDetails[30]); + AllCinemaID=AniDBAPILib.ProcessAniDBInt(sDetails[31]); + AnimeNfoID=AniDBAPILib.ProcessAniDBString(sDetails[32]); + DateRecordUpdated=AniDBAPILib.ProcessAniDBString(sDetails[33]); + CharacterIDListRAW = AniDBAPILib.ProcessAniDBString(sDetails[34]); + ReviewIDListRAW = AniDBAPILib.ProcessAniDBString(sDetails[35]); + //New version number + VersionNumber = LastVersion; + //Genres should by right in utf-16 + GenreRAW = sDetails[5]; + BeginYear = AirDate.HasValue ? AirDate.Value.Year : 0; + EndYear = EndDate.HasValue ? EndDate.Value.Year : 0; + + foreach (int rid in this.ReviewIDList) + { + //BaseConfig.MyAnimeLog.Write("ReviewID: {0}", rid.ToString()); + } + + /* + char[] chars = sDetails[5].ToCharArray(); + + foreach (char c in chars) + { + if ((int)c > 31 && (int)c < 127) + genreRAW += c.ToString(); + } + */ + + + } + + + + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + sb.Append("AnimeID: " + AnimeID); + sb.Append(" | Main Title: " + MainTitle); + sb.Append(" | EpisodeCount: " + EpisodeCount); + sb.Append(" | AirDate: " + AirDate); + sb.Append(" | Picname: " + Picname); + sb.Append(" | Type: " + AnimeTypeRAW); + sb.Append(" | relatedAnimeIDs: " + RelatedAnimeIdsRAW); + sb.Append(" | relatedAnimeTypes: " + RelatedAnimeTypesRAW); + return sb.ToString(); + } + + + } +} diff --git a/JMMServer/AniDB_API/Raws/Raw_AniDB_AnimeDesc.cs b/JMMServer/AniDB_API/Raws/Raw_AniDB_AnimeDesc.cs new file mode 100644 index 000000000..aef984ecd --- /dev/null +++ b/JMMServer/AniDB_API/Raws/Raw_AniDB_AnimeDesc.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace AniDBAPI +{ + public class Raw_AniDB_AnimeDesc + { + public string Description { get; set; } + + // constructor + // sRecMessage is the message received from ANIDB file info command + public Raw_AniDB_AnimeDesc(string sRecMessage) + { + // remove the header info + string[] sDetails = sRecMessage.Substring(14).Split('|'); + + // 233 ANIMEDESC + + // {int4 current part}|{int4 max parts}|{str description} + // 0. 0 ** current part + // 1. 1 ** max parts + // 2. Blah blah ** description + + this.Description = AniDBAPILib.ProcessAniDBString(sDetails[2]); + } + public Raw_AniDB_AnimeDesc() + { + Description = string.Empty; + } + public override string ToString() + { + return string.Format("Raw_AniDB_AnimeDesc:: Description: {0}", Description); + } + } +} diff --git a/JMMServer/AniDB_API/Raws/Raw_AniDB_Anime_Title.cs b/JMMServer/AniDB_API/Raws/Raw_AniDB_Anime_Title.cs new file mode 100644 index 000000000..e1d9485eb --- /dev/null +++ b/JMMServer/AniDB_API/Raws/Raw_AniDB_Anime_Title.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Xml; + +namespace AniDBAPI +{ + [Serializable] + public class Raw_AniDB_Anime_Title : XMLBase + { + #region Properties + + public int AnimeID { get; set; } + public string TitleType { get; set; } + public string Language { get; set; } + public string Title { get; set; } + + #endregion + + public Raw_AniDB_Anime_Title() + { + } + + public void ProcessFromHTTPResult(XmlNode node, int anid) + { + this.AnimeID = anid; + this.TitleType = ""; + this.Language = ""; + this.Title = ""; + + this.TitleType = AniDBHTTPHelper.TryGetAttribute(node, "type"); + this.Language = AniDBHTTPHelper.TryGetAttribute(node, "xml:lang"); + this.Title = node.InnerText.Trim(); + + // Title Types + // ------------- + // main + // official + // syn / SYNONYM / SYNONYMs + // short + + // Common Languages + // en = english + // x-jat = romaji + // ja = kanji + } + } +} diff --git a/JMMServer/AniDB_API/Raws/Raw_AniDB_Calendar.cs b/JMMServer/AniDB_API/Raws/Raw_AniDB_Calendar.cs new file mode 100644 index 000000000..5bcc07697 --- /dev/null +++ b/JMMServer/AniDB_API/Raws/Raw_AniDB_Calendar.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace AniDBAPI +{ + [Serializable] + public class Raw_AniDB_Calendar + { + #region Properties + + public int AnimeID { get; set; } + + public DateTime ReleaseDate { get; set; } + + public int DateFlags { get; set; } + + public Raw_AniDB_Calendar() + { + DateFlags = 0; + } + public override string ToString() + { + return string.Format("Calendar - AnimeID: {0}...Release Date: {1}...Flags: {2}", AnimeID, ReleaseDate, DateFlags); + } + + #endregion + } +} diff --git a/JMMServer/AniDB_API/Raws/Raw_AniDB_Category.cs b/JMMServer/AniDB_API/Raws/Raw_AniDB_Category.cs new file mode 100644 index 000000000..7f9113cb8 --- /dev/null +++ b/JMMServer/AniDB_API/Raws/Raw_AniDB_Category.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Xml; + +namespace AniDBAPI +{ + [Serializable] + public class Raw_AniDB_Category : XMLBase + { + #region Properties + + public int AnimeID { get; set; } + public int CategoryID { get; set; } + public int ParentID { get; set; } + public int IsHentai { get; set; } + public string CategoryName { get; set; } + public string CategoryDescription { get; set; } + public int Weighting { get; set; } + + #endregion + + public Raw_AniDB_Category() + { + } + + public void ProcessFromHTTPResult(XmlNode node, int anid) + { + this.AnimeID = anid; + this.CategoryID = 0; + this.ParentID = 0; + this.IsHentai = 0; + this.CategoryName = ""; + this.CategoryDescription = ""; + this.Weighting = 0; + + this.CategoryID = int.Parse(AniDBHTTPHelper.TryGetAttribute(node, "id")); + this.ParentID = int.Parse(AniDBHTTPHelper.TryGetAttribute(node, "parentid")); + + bool hentai = false; + bool.TryParse(AniDBHTTPHelper.TryGetAttribute(node, "hentai"), out hentai); + this.IsHentai = hentai ? 1 : 0; + + + this.CategoryName = AniDBHTTPHelper.TryGetProperty(node, "name"); + this.CategoryDescription = AniDBHTTPHelper.TryGetProperty(node, "description"); + + int weight = 0; + int.TryParse(AniDBHTTPHelper.TryGetAttribute(node, "weight"), out weight); + this.Weighting = weight; + } + } +} diff --git a/JMMServer/AniDB_API/Raws/Raw_AniDB_Character.cs b/JMMServer/AniDB_API/Raws/Raw_AniDB_Character.cs new file mode 100644 index 000000000..6907efa14 --- /dev/null +++ b/JMMServer/AniDB_API/Raws/Raw_AniDB_Character.cs @@ -0,0 +1,116 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Xml.Serialization; +using System.Xml; + + +namespace AniDBAPI +{ + [Serializable] + public class Raw_AniDB_Character : XMLBase + { + public int CharID { get; set; } + public int AnimeID { get; set; } + public string PicName { get; set; } + public string CharName { get; set; } + public string CharKanjiName { get; set; } + public string CharDescription { get; set; } + public string CharType { get; set; } + + public string CreatorListRaw { get; set; } + public string EpisodeListRaw { get; set; } + + public Raw_AniDB_Character() + { + InitFields(); + } + + private void InitFields() + { + CharID = 0; + CharName = string.Empty; + CharKanjiName = string.Empty; + CharDescription = string.Empty; + CharType = string.Empty; + PicName = string.Empty; + + CreatorListRaw = string.Empty; + EpisodeListRaw = string.Empty; + } + + + /// + /// From UDP API + /// + /// + public Raw_AniDB_Character(string sRecMessage) + { + InitFields(); + + this.AnimeID = 0; + + // remove the header info + string[] sDetails = sRecMessage.Substring(14).Split('|'); + + //BaseConfig.MyAnimeLog.Write("PROCESSING EPISODE: {0}", sDetails.Length); + // 235 CHARACTER 7179|?????|Noyamano Shiraume|25513.jpg|4196,3,3875,1||1243176147 + + + // 235 CHARACTER + // 0. 7179 ** char id + // 1. ??? ** char name kanji + // 2. Noyamano Shiraume ** char name + // 3. 25513.jpg ** pic name + // 4 4196,3,3875,1 ** An 'anime block' is {int anime id},{int type},{int creatorid},{boolean is_main_seiyuu} repeated as many times as necessary, separated by a single quote ( ' ). + + CharID = int.Parse(sDetails[0].Trim()); + CharKanjiName = AniDBAPILib.ProcessAniDBString(sDetails[1].Trim()); + CharName = AniDBAPILib.ProcessAniDBString(sDetails[2].Trim()); + PicName = AniDBAPILib.ProcessAniDBString(sDetails[3].Trim()); + CreatorListRaw = AniDBAPILib.ProcessAniDBString(sDetails[4].Trim().Replace("'", "|")); + } + + public void ProcessFromHTTPResult(XmlNode node, int anid) + { + InitFields(); + + this.AnimeID = anid; + this.CharID = int.Parse(AniDBHTTPHelper.TryGetAttribute(node, "id")); + this.CharType = AniDBHTTPHelper.TryGetAttribute(node, "type"); + + this.CharName = AniDBHTTPHelper.TryGetProperty(node, "name"); + this.CharDescription = AniDBHTTPHelper.TryGetProperty(node, "description"); + this.EpisodeListRaw = AniDBHTTPHelper.TryGetProperty(node, "episodes"); + this.PicName = AniDBHTTPHelper.TryGetProperty(node, "picture"); + + CreatorListRaw = ""; + foreach (XmlNode nodeChild in node.ChildNodes) + { + if (nodeChild.Name == "seiyuu") + { + if (nodeChild.Attributes["id"] != null) + { + string creatorid = nodeChild.Attributes["id"].Value; + if (CreatorListRaw.Length > 0) + CreatorListRaw += ","; + CreatorListRaw += creatorid.Trim(); + } + + } + } + + + } + + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + sb.Append("charID: " + CharID.ToString()); + sb.Append(" | characterName: " + CharName); + sb.Append(" | picName: " + PicName); + return sb.ToString(); + } + + } +} diff --git a/JMMServer/AniDB_API/Raws/Raw_AniDB_Creator.cs b/JMMServer/AniDB_API/Raws/Raw_AniDB_Creator.cs new file mode 100644 index 000000000..072978609 --- /dev/null +++ b/JMMServer/AniDB_API/Raws/Raw_AniDB_Creator.cs @@ -0,0 +1,84 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Xml.Serialization; + + +namespace AniDBAPI +{ + [Serializable] + public class Raw_AniDB_Creator : XMLBase + { + public int CreatorID { get; set; } + public string CreatorName { get; set; } + public string PicName { get; set; } + public string CreatorKanjiName { get; set; } + public string CreatorDescription{ get; set; } + public int CreatorType { get; set; } + public string URLEnglish { get; set; } + public string URLJapanese { get; set; } + public string URLWikiEnglish { get; set; } + public string URLWikiJapanese { get; set; } + + + + public Raw_AniDB_Creator() + { + CreatorName = string.Empty; + CreatorKanjiName = string.Empty; + CreatorType = 1; + PicName = string.Empty; + CreatorDescription = ""; + URLEnglish = string.Empty; + URLJapanese = string.Empty; + URLWikiEnglish = string.Empty; + URLWikiJapanese = string.Empty; + } + + + public readonly static int LastVersion = 1; + + public Raw_AniDB_Creator(string sRecMessage) + { + // remove the header info + string[] sDetails = sRecMessage.Substring(12).Split('|'); + + // 245 CREATOR 200|?????|Suwabe Jun`ichi|1|17015.jpg||http://www.haikyo.or.jp/PROFILE/man/11470.html|Junichi_Suwabe|%E8%AB%8F%E8%A8%AA%E9%83%A8%E9%A0%86%E4%B8%80|1236300570 + // 3396|????|Takatsuka Masaya|1|24705.jpg||http://www.aoni.co.jp/actor/ta/takatsuka-masaya.html|Masaya_Takatsuka|????|1271491220 + + // 235 CHARACTER + // 0. 200 ** creator id + // 1. ??? ** creator name kanji + // 2. Suwabe Jun`ichi ** creator name + // 3. 1 ** type values: 1='person', 2='company', 3='collaboration' + // 4. 25513.jpg ** pic name + // 5. ??? ** desc + // 6. ??? ** URLEnglish + // 7. ??? ** URLJapanese + // 8. ??? ** URLWikiEnglish + // 9. ??? ** URLWikiJapanese + + CreatorID = int.Parse(sDetails[0].Trim()); + CreatorKanjiName = AniDBAPILib.ProcessAniDBString(sDetails[1].Trim()); + CreatorName = AniDBAPILib.ProcessAniDBString(sDetails[2].Trim()); + CreatorType = AniDBAPILib.ProcessAniDBInt(AniDBAPILib.ProcessAniDBString(sDetails[3].Trim())); + PicName = AniDBAPILib.ProcessAniDBString(sDetails[4].Trim()); + CreatorDescription = ""; + URLEnglish = AniDBAPILib.ProcessAniDBString(sDetails[5].Trim()); + URLJapanese = AniDBAPILib.ProcessAniDBString(sDetails[6].Trim()); + URLWikiEnglish = AniDBAPILib.ProcessAniDBString(sDetails[7].Trim()); + URLWikiJapanese = AniDBAPILib.ProcessAniDBString(sDetails[8].Trim()); + } + + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + sb.Append("creatorID: " + CreatorID.ToString()); + sb.Append(" | creatorName: " + CreatorName); + sb.Append(" | picName: " + PicName); + + return sb.ToString(); + } + + } +} diff --git a/JMMServer/AniDB_API/Raws/Raw_AniDB_Episode.cs b/JMMServer/AniDB_API/Raws/Raw_AniDB_Episode.cs new file mode 100644 index 000000000..4fb8a957e --- /dev/null +++ b/JMMServer/AniDB_API/Raws/Raw_AniDB_Episode.cs @@ -0,0 +1,354 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Xml.Serialization; +using System.Xml; +using JMMServer; + + +namespace AniDBAPI +{ + [Serializable] + public class Raw_AniDB_Episode : XMLBase + { + /* + + [XmlIgnore] + public string AirDateFormatted + { + get { return APIUtils.GetAniDBDate(AirDate, System.Globalization.CultureInfo.CurrentCulture); } + } + */ + + public int EpisodeID { get; set; } + + public int VersionNumber { get; set; } + + public int AnimeID { get; set; } + + public int LengthSeconds { get; set; } + + public decimal Rating { get; set; } + + public int Votes { get; set; } + + public int EpisodeNumber { get; set; } + + public int EpisodeType { get; set; } + + public string RomajiName { get; set; } + + public string KanjiName { get; set; } + + public string EnglishName { get; set; } + + public int AirDate { get; set; } + + public DateTime DateTimeUpdated { get; set; } + + public int IsDoubleEpisode { get; set; } + + public Raw_AniDB_Episode() + { + VersionNumber = 0; + LengthSeconds = 0; + Rating = 0; + Votes = 0; + EpisodeNumber = 0; + EpisodeType = 1; + RomajiName = string.Empty; + KanjiName = string.Empty; + EnglishName = string.Empty; + AirDate = 0; + DateTimeUpdated = DateTime.Now; + IsDoubleEpisode = 0; + + } + + + private void ProcessEpisodeSource(string sRecMessage) + { + // remove the header info + string[] sDetails = sRecMessage.Substring(12).Split('|'); + + //BaseConfig.MyAnimeLog.Write("PROCESSING EPISODE: {0}", sDetails.Length); + + // 240 EPISODE + // 0. 99294 ** episode id + // 1. 6107 ** anime id + // 2. 25 ** length in minutes + // 3. 712 ** episode rating (7.12) + // 4. 14 ** episode vote count + // 5. 02 ** episode number Returned 'epno' includes special character (only if special) and padding (only if normal). Special characters are S(special), C(credits), T(trailer), P(parody), O(other) + // 6. The Day It Began ** english name + // 7. Hajimari no Hi ** romaji name + // 8. ?????? ** kanji name + // 9. 1239494400 ** air date + + EpisodeID = int.Parse(sDetails[0].Trim()); + AnimeID = int.Parse(sDetails[1].Trim()); + + int lMinutes = 0; + int.TryParse(sDetails[2].Trim(), out lMinutes); + int secs = lMinutes * 60; + LengthSeconds = secs; + + string epno = GetValidatedEpisodeNumber(sDetails[5].Trim()); + + EpisodeType = GetEpisodeType(epno); + EpisodeNumber = GetEpisodeNumber(epno); + IsDoubleEpisode = GetIsDoubleEpisode(epno); + Rating = AniDBAPILib.ProcessAniDBInt(sDetails[3].Trim()); + Votes = AniDBAPILib.ProcessAniDBInt(sDetails[4].Trim()); + EnglishName = AniDBAPILib.ProcessAniDBString(sDetails[6].Trim()); + RomajiName = AniDBAPILib.ProcessAniDBString(sDetails[7].Trim()); + KanjiName = AniDBAPILib.ProcessAniDBString(sDetails[8].Trim()); + AirDate = AniDBAPILib.ProcessAniDBInt(sDetails[9].Trim()); + //BaseConfig.MyAnimeLog.Write("EPISODE: {0}: {1}", sDetails[5].Trim(), this.ToString()); + } + + public void ProcessEpisodeSource(XmlNode node, int anid) + { + // default values + LengthSeconds = 0; + Rating = 0; + Votes = 0; + EpisodeNumber = 0; + EpisodeType = 1; + RomajiName = string.Empty; + KanjiName = string.Empty; + EnglishName = string.Empty; + AirDate = 0; + DateTimeUpdated = DateTime.Now; + + EpisodeID = int.Parse(node.Attributes["id"].Value); + AnimeID = anid; + + string epno = AniDBHTTPHelper.TryGetProperty(node, "epno"); + EpisodeType = GetEpisodeType(epno); + EpisodeNumber = GetEpisodeNumber(epno); + IsDoubleEpisode = GetIsDoubleEpisode(epno); + + string length = AniDBHTTPHelper.TryGetProperty(node, "length"); + int lMinutes = 0; + int.TryParse(length, out lMinutes); + int secs = lMinutes * 60; + LengthSeconds = secs; + + decimal rating = 0; + int votes = 0; + + //string airdate = TryGetProperty(node, "airdate"); + decimal.TryParse(AniDBHTTPHelper.TryGetProperty(node, "rating"), out rating); + int.TryParse(AniDBHTTPHelper.TryGetAttribute(node, "rating", "votes"), out votes); + Rating = rating; + Votes = votes; + EnglishName = AniDBHTTPHelper.TryGetPropertyWithAttribute(node, "title", "xml:lang", "en"); + RomajiName = AniDBHTTPHelper.TryGetPropertyWithAttribute(node, "title", "xml:lang", "x-jat"); + KanjiName = AniDBHTTPHelper.TryGetPropertyWithAttribute(node, "title", "xml:lang", "ja"); + + /* + + The Adventures of Asahina Mikuru Episode 00 + Mikuru Asahinos nuotykiai Epizodas 00 + Asahina Mikuru no Bouken Episode 00*/ + string adate = AniDBHTTPHelper.TryGetProperty(node, "airdate"); + + AirDate = Utils.GetAniDBDateAsSeconds(adate); + + //BaseConfig.MyAnimeLog.Write("EPISODE: {0}: {1}", epno.Trim(), this.ToString()); + } + + private void ProcessFileSource(string sRecMessage) + { + // remove the header info + string[] sDetails = sRecMessage.Substring(9).Split('|'); + + //BaseConfig.MyAnimeLog.Write("PROCESSING EPISODE: {0}", sDetails.Length); + + // 220 FILE + // 0. 572794 ** fileid + // 1. 6107 ** anime id + // 2. 99294 ** episode id + // 3. 12 ** group id + // 4. 2723 ** lid + // 5. c646d82a184a33f4e4f98af39f29a044 ** ed2k hash + // 6. 8452c4bf ** crc32 + // 7. high ** quality + // 8. HDTV ** source + // 9. Vorbis (Ogg Vorbis) ** audio codec + // 10. 148 ** audio bit rate + // 11. H264/AVC ** video codec + // 12. 1773 ** video bit rate + // 13. 1280x720 ** video res + // 14. mkv ** file extension + // 15. 1470 ** length in seconds + // 16. ** description + // 17. 1239494400 ** release date ** date is the time of the event (in seconds since 1.1.1970) + // 18. 2 ** episode # + // 19. The Day It Began ** ep name + // 20. Hajimari no Hi ** ep name romaji20 . + // 21. ** ep Kanji Name + // 22. 712 ** episode rating (7.12) + // 23. 14 ** episode vote count + // 24. Eclipse Productions ** group name + // 25. Eclipse ** group name short + + EpisodeID = int.Parse(sDetails[2].Trim()); + AnimeID = int.Parse(sDetails[1].Trim()); + + int lMinutes = 0; + int.TryParse(sDetails[15].Trim(), out lMinutes); + int secs = lMinutes * 60; + LengthSeconds = secs; + + string epno = GetValidatedEpisodeNumber(sDetails[18].Trim()); + + EpisodeType = GetEpisodeType(epno); + EpisodeNumber = GetEpisodeNumber(epno); + IsDoubleEpisode = GetIsDoubleEpisode(epno); + Rating = AniDBAPILib.ProcessAniDBInt(sDetails[22].Trim()); + Votes = AniDBAPILib.ProcessAniDBInt(sDetails[23].Trim()); + EnglishName = AniDBAPILib.ProcessAniDBString(sDetails[19].Trim()); + RomajiName = AniDBAPILib.ProcessAniDBString(sDetails[20].Trim()); + KanjiName = AniDBAPILib.ProcessAniDBString(sDetails[21].Trim()); + AirDate = AniDBAPILib.ProcessAniDBInt(sDetails[17].Trim()); + + //BaseConfig.MyAnimeLog.Write("EPISODE: {0}: {1}", sDetails[18].Trim(), this.ToString()); + } + + private string GetValidatedEpisodeNumber(string fld) + { + // remove any invalid characters + // string socketResponse = "220 FILE226237|3651|48951|3|63249613|feaf5388f7c0c5a38cd8d5e243c2c6e7|de3f16d8|high|DTV|MP3 CBR|128|XviD|894|640x360|avi|1420||1145836800|04,07|The Boredom of Suzumiya Haruhi|Suzumiya Haruhi no Taikutsu|x|802|48|a.f.k.|a.f.k."; + // "04,07" + + if (fld.Contains(",")) + { + int pos = fld.IndexOf(','); + fld = fld.Substring(0, pos); + } + + return fld; + } + + private int GetEpisodeNumber(string fld) + { + //BaseConfig.MyAnimeLog.Write("GetEpisodeNumber: {0}", fld); + int epno = 0; + + int epType = GetEpisodeType(fld); + + // if it is NOT a normal episode strip the leading character + string fldTemp = fld; + if (epType > 1) + fldTemp = fld.Trim().Substring(1, fld.Trim().Length - 1); + + if (int.TryParse(fldTemp, out epno)) + { + return epno; + } + else + { + // if we couldn't convert to an int, it must mean it is a double episode + // we will just take the first ep as the episode number + string[] sDetails = fldTemp.Split('-'); + epno = int.Parse(sDetails[0]); + return epno; + } + } + + private int GetIsDoubleEpisode(string fld) + { + //BaseConfig.MyAnimeLog.Write("GetIsDoubleEpisode: {0}", fld); + int epno = 0; + + int epType = GetEpisodeType(fld); + + // if it is NOT a normal episode strip the leading character + string fldTemp = fld; + if (epType > 1) + fldTemp = fld.Trim().Substring(1, fld.Trim().Length - 1); + + if (int.TryParse(fldTemp, out epno)) + return 0; + else + return 1; + } + + private int GetEpisodeType(string fld) + { + //BaseConfig.MyAnimeLog.Write("GetEpisodeType: {0}", fld); + + string epType = ""; + int epno = 0; + if (int.TryParse(fld.Trim().Substring(0, 1), out epno)) // if the first char is a numeric than it is a normal episode + { + return (int)enEpisodeType.Episode; + } + else + { + // the first character should contain the type of special episode + // S(special), C(credits), T(trailer), P(parody), O(other) + // we will just take this and store it in the database + // this will allow for the user customizing how it is displayed on screen later + epType = fld.Trim().Substring(0, 1).ToUpper(); + + switch (epType) + { + case "": return (int)enEpisodeType.Episode; + case "C": return (int)enEpisodeType.Credits; + case "S": return (int)enEpisodeType.Special; + case "O": return (int)enEpisodeType.Other; + case "T": return (int)enEpisodeType.Trailer; + case "P": return (int)enEpisodeType.Parody; + default: return (int)enEpisodeType.Episode; + } + } + } + + public Raw_AniDB_Episode(string sRecMessage, enEpisodeSourceType sourceType) + { + if (sourceType == enEpisodeSourceType.Episode) + ProcessEpisodeSource(sRecMessage); + else + ProcessFileSource(sRecMessage); + } + /* + public Raw_AniDB_Episode(XmlNode node, int anid) + { + ProcessEpisodeSource(node, anid); + }*/ + + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + sb.Append("episodeID: " + EpisodeID.ToString()); + sb.Append(" | animeID: " + AnimeID.ToString()); + sb.Append(" | episodeNumber: " + EpisodeNumber.ToString()); + sb.Append(" | episodeType: " + EpisodeType.ToString()); + sb.Append(" | englishName: " + EnglishName); + sb.Append(" | airDate: " + AirDate); + //sb.Append(" | AirDateFormatted: " + AirDateFormatted); + + return sb.ToString(); + } + } + + public enum enEpisodeSourceType + { + File = 1, + Episode = 2, + HTTPAPI = 3 + } + + public enum enEpisodeType + { + Episode = 1, + Credits = 2, + Special = 3, + Trailer = 4, + Parody = 5, + Other = 6 + } +} diff --git a/JMMServer/AniDB_API/Raws/Raw_AniDB_File.cs b/JMMServer/AniDB_API/Raws/Raw_AniDB_File.cs new file mode 100644 index 000000000..7b1428565 --- /dev/null +++ b/JMMServer/AniDB_API/Raws/Raw_AniDB_File.cs @@ -0,0 +1,243 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Xml.Serialization; + +namespace AniDBAPI +{ + [Serializable] + public class Raw_AniDB_File : XMLBase, IHash + { + #region Properties + public int FileID { get; set; } + + public string ED2KHash { get; set; } + + public int AnimeID { get; set; } + + public int GroupID { get; set; } + + public string File_Source { get; set; } + + public string File_AudioCodec { get; set; } + + public string File_VideoCodec { get; set; } + + public string File_VideoResolution { get; set; } + + public string File_FileExtension { get; set; } + + public int File_LengthSeconds { get; set; } + + public string File_Description { get; set; } + + public int File_ReleaseDate { get; set; } + + public string Anime_GroupName { get; set; } + + public string Anime_GroupNameShort { get; set; } + + public int Episode_Rating { get; set; } + + public int Episode_Votes { get; set; } + + public DateTime DateTimeUpdated { get; set; } + + [XmlIgnore] + public int IsWatched { get; set; } + + public string CRC { get; set; } + + public string MD5 { get; set; } + + public string SHA1 { get; set; } + + public long FileSize { get; set; } + + [XmlIgnore] + public int Version { get; set; } + + public string FileName { get; set; } + + public string SubtitlesRAW { get; set; } + + public string LanguagesRAW { get; set; } + + public string EpisodesRAW { get; set; } + + public string EpisodesPercentRAW { get; set; } + + + #endregion + // default constructor + public Raw_AniDB_File() + { + InitDefaultValues(); + } + + private void InitDefaultValues() + { + FileID = 0; + ED2KHash = string.Empty; + MD5 = string.Empty; + SHA1 = string.Empty; + FileSize = 0; + AnimeID = 0; + GroupID = 0; + CRC = string.Empty; + File_LengthSeconds = 0; + File_Source = string.Empty; + File_AudioCodec = string.Empty; + File_VideoCodec = string.Empty; + File_VideoResolution = string.Empty; + File_FileExtension = string.Empty; + File_Description = string.Empty; + File_ReleaseDate = 0; + Anime_GroupName = string.Empty; + Anime_GroupNameShort = string.Empty; + FileName = string.Empty; + Episode_Rating = 0; + Episode_Votes = 0; + DateTimeUpdated = DateTime.Now; + Version = 0; + IsWatched = 0; + } + + public string Info + { + get + { + if (string.IsNullOrEmpty(FileName)) + return FileID.ToString(); + return FileName; + } + } + + public readonly static int LastVersion = 2; + + public Raw_AniDB_File(string sRecMessage) + { + InitDefaultValues(); + + // remove the header info + string[] sDetails = sRecMessage.Substring(9).Split('|'); + + //BaseConfig.MyAnimeLog.Write("PROCESSING FILE: {0}", sDetails.Length); + + // 220 FILE + // 0. 572794 ** fileid + // 1. 6107 ** anime id + // 2. 99294 ** episode id + // 3. 12 ** group id + // 4. 2723 ** lid + + // 5. ** other episodes + + // 6 ** Size + // 7. c646d82a184a33f4e4f98af39f29a044 ** ed2k hash + // 8. ** md5 + // 9. ** sha1 + // 10. 8452c4bf ** crc32 + // 11. high ** quality + // 12. HDTV ** source + // 13. Vorbis (Ogg Vorbis) ** audio codec + // 14. 148 ** audio bit rate + // 15. H264/AVC ** video codec + // 16. 1773 ** video bit rate + // 17. 1280x720 ** video res + // 18. mkv ** file extension + + // 19. Audio Langugages. + // 20. Subtitle languages. + + + // 21. 1470 ** length in seconds + // 22. ** description + // 23. 1239494400 ** release date ** date is the time of the event (in seconds since 1.1.1970) + + // 24. Episode FileName + + // 25. 2 ** episode # + // 26. The Day It Began ** ep name + // 27. Hajimari no Hi ** ep name romaji + // 28. ** ep name kanji + // 29. 712 ** episode rating (7.12) + // 30. 14 ** episode vote count + // 31. Eclipse Productions ** group name + // 32. Eclipse ** group name short + + this.FileSize = long.Parse(sDetails[6].Trim()); + this.ED2KHash = AniDBAPILib.ProcessAniDBString(sDetails[7].Trim()).ToUpper(); + this.MD5 = AniDBAPILib.ProcessAniDBString(sDetails[8].Trim()).ToUpper(); + this.SHA1 = AniDBAPILib.ProcessAniDBString(sDetails[9].Trim()).ToUpper(); + this.CRC = AniDBAPILib.ProcessAniDBString(sDetails[10].Trim()).ToUpper(); + FileID = int.Parse(sDetails[0].Trim()); + AnimeID = int.Parse(sDetails[1].Trim()); + + EpisodesRAW = sDetails[2].Trim(); + EpisodesPercentRAW = "100"; + if (sDetails[5].Trim().Length > 0) + { + string[] Eps = sDetails[5].Trim().Split('\''); + if (Eps.Length > 0) + { + foreach (string ep in Eps) + { + string[] ep2 = ep.Split(','); + if (ep2.Length>0) + EpisodesRAW += "," + ep2[0]; + if (ep2.Length > 1) + EpisodesPercentRAW += "," + ep2[1]; + else + EpisodesPercentRAW += ",100"; + } + } + } + // Other Episodes have this format : FileId, % From The End, Per example 1030, 100 Means the complete 1030 Episode + // 1030, 49 Means content starts at 51% of the episode 1030. + + GroupID = int.Parse(sDetails[3].Trim()); + File_Source = AniDBAPILib.ProcessAniDBString(sDetails[12].Trim()); + File_AudioCodec = AniDBAPILib.ProcessAniDBString(sDetails[13].Trim()); + File_VideoCodec = AniDBAPILib.ProcessAniDBString(sDetails[15].Trim()); + File_VideoResolution = AniDBAPILib.ProcessAniDBString(sDetails[17].Trim()); + File_FileExtension = AniDBAPILib.ProcessAniDBString(sDetails[18].Trim()); + + File_LengthSeconds = AniDBAPILib.ProcessAniDBInt(sDetails[21].Trim()); + File_Description = AniDBAPILib.ProcessAniDBString(sDetails[22].Trim()); + File_ReleaseDate = AniDBAPILib.ProcessAniDBInt(sDetails[23].Trim()); + Anime_GroupName = AniDBAPILib.ProcessAniDBString(sDetails[31].Trim()); + Anime_GroupNameShort = AniDBAPILib.ProcessAniDBString(sDetails[32].Trim()); + + IsWatched = 0; // 0 = false, 1 = true + Episode_Rating = AniDBAPILib.ProcessAniDBInt(sDetails[29].Trim()); + Episode_Votes = AniDBAPILib.ProcessAniDBInt(sDetails[30].Trim()); + + LanguagesRAW = AniDBAPILib.ProcessAniDBString(sDetails[19].Trim()); + SubtitlesRAW = AniDBAPILib.ProcessAniDBString(sDetails[20].Trim()); + + FileName = AniDBAPILib.ProcessAniDBString(sDetails[24].Trim()); + + Version = LastVersion; + } + + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + sb.Append("Raw_AniDB_File:: hash: " + ED2KHash); + sb.Append(" | fileID: " + FileID.ToString()); + sb.Append(" | Source: " + File_Source); + //sb.Append(" | episodeID: " + EpisodeID.ToString()); + sb.Append(" | animeID: " + AnimeID.ToString()); + sb.Append(" | IsWatched: " + IsWatched.ToString()); + sb.Append(" | FileName: " + FileName); + sb.Append(" | FileSize: " + FileSize.ToString()); + sb.Append(" | DateTimeUpdated: " + DateTimeUpdated.ToString()); + sb.Append(" | EpisodesRAW: " + EpisodesRAW.ToString()); + sb.Append(" | EpisodesPercentRAW: " + EpisodesPercentRAW); + sb.Append(" | LanguagesRAW: " + LanguagesRAW); + sb.Append(" | SubtitlesRAW: " + SubtitlesRAW); + return sb.ToString(); + } + } +} diff --git a/JMMServer/AniDB_API/Raws/Raw_AniDB_Group.cs b/JMMServer/AniDB_API/Raws/Raw_AniDB_Group.cs new file mode 100644 index 000000000..5875517ce --- /dev/null +++ b/JMMServer/AniDB_API/Raws/Raw_AniDB_Group.cs @@ -0,0 +1,87 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace AniDBAPI +{ + public class Raw_AniDB_Group : XMLBase + { + public int GroupID { get; set; } + public int Rating { get; set; } + public int Votes { get; set; } + public int AnimeCount { get; set; } + public int FileCount { get; set; } + public string GroupName { get; set; } + public string GroupNameShort { get; set; } + public string IRCChannel { get; set; } + public string IRCServer { get; set; } + public string URL { get; set; } + public string Picname { get; set; } + + private void PopulateDefaults() + { + GroupID = 0; + Rating = 0; + Rating = 0; + Votes = 0; + AnimeCount = 0; + FileCount = 0; + GroupName = string.Empty; + GroupNameShort = string.Empty; + IRCChannel = string.Empty; + IRCServer = string.Empty; + URL = string.Empty; + Picname = string.Empty; + } + + public Raw_AniDB_Group() + { + PopulateDefaults(); + } + + public Raw_AniDB_Group(string sRecMessage) + { + PopulateDefaults(); + + // remove the header info + string[] sDetails = sRecMessage.Substring(10).Split('|'); + + //250 GROUP + // 0. 3938 ** group id + // 1. 704 ** rating + // 2. 1900 ** votes + // 3. 53 ** anime count + // 4. 1126 ** file count + // 5. Ayako-Fansubs ** group name + // 6. Ayako ** short name + // 7. #Ayako ** IRC channel + // 8. irc.rizon.net ** IRC server + // 9. http://ayakofansubs.info/ ** website + // 10. 1669.png + + GroupID = int.Parse(sDetails[0]); + Rating = int.Parse(sDetails[1]); + Votes = int.Parse(sDetails[2]); + AnimeCount = int.Parse(sDetails[3]); + FileCount = int.Parse(sDetails[4]); + + GroupName = AniDBAPILib.ProcessAniDBString(sDetails[5]); + GroupNameShort = AniDBAPILib.ProcessAniDBString(sDetails[6]); + IRCChannel = AniDBAPILib.ProcessAniDBString(sDetails[7]); + IRCServer = AniDBAPILib.ProcessAniDBString(sDetails[8]); + URL = AniDBAPILib.ProcessAniDBString(sDetails[9]); + Picname = AniDBAPILib.ProcessAniDBString(sDetails[10]); + } + + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + sb.Append("AniDB_Group:: AnimeID: " + GroupID.ToString()); + sb.Append(" | GroupName: " + GroupName); + sb.Append(" | URL: " + URL); + + return sb.ToString(); + } + } +} diff --git a/JMMServer/AniDB_API/Raws/Raw_AniDB_GroupStatus.cs b/JMMServer/AniDB_API/Raws/Raw_AniDB_GroupStatus.cs new file mode 100644 index 000000000..e448ebaa9 --- /dev/null +++ b/JMMServer/AniDB_API/Raws/Raw_AniDB_GroupStatus.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using System.Text; + + +namespace AniDBAPI +{ + public class Raw_AniDB_GroupStatus : XMLBase + { + public int AnimeID { get; set; } + public int GroupID { get; set; } + public string GroupName { get; set; } + public int CompletionState { get; set; } + public int LastEpisodeNumber { get; set; } + public int Rating { get; set; } + public int Votes { get; set; } + public string EpisodeRange { get; set; } + + private void PopulateDefaults() + { + AnimeID = 0; + GroupID = 0; + GroupName = string.Empty; + CompletionState = 0; + LastEpisodeNumber = 0; + Rating = 0; + Votes = 0; + EpisodeRange = string.Empty; + } + + public Raw_AniDB_GroupStatus() + { + PopulateDefaults(); + } + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + sb.Append("AniDB_GroupStatus:: AnimeID: " + AnimeID.ToString()); + sb.Append(" | GroupName: " + GroupName); + sb.Append(" | LastEpisode: " + LastEpisodeNumber); + + return sb.ToString(); + } + + } +} diff --git a/JMMServer/AniDB_API/Raws/Raw_AniDB_MyListFile.cs b/JMMServer/AniDB_API/Raws/Raw_AniDB_MyListFile.cs new file mode 100644 index 000000000..9b667529f --- /dev/null +++ b/JMMServer/AniDB_API/Raws/Raw_AniDB_MyListFile.cs @@ -0,0 +1,162 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Xml; +using NLog; + +namespace AniDBAPI +{ + public class Raw_AniDB_MyListFile + { + private static Logger logger = LogManager.GetCurrentClassLogger(); + + public int ListID { get; set; } + public int FileID { get; set; } + public int EpisodeID { get; set; } + public int AnimeID { get; set; } + public int GroupID { get; set; } + public int State { get; set; } + public string FileDate { get; set; } + public DateTime? WatchedDate { get; set; } + public int ViewDateUDP { get; set; } + public string ViewDateHTTP { get; set; } + public string Storage { get; set; } + public string Source { get; set; } + public string Other { get; set; } + public int FileState { get; set; } + + public bool IsWatched + { + get + { + if (this.ViewDateUDP > 0 || this.ViewDateHTTP.Trim().Length > 0) + return true; + else + return false; + } + } + + // default constructor + public Raw_AniDB_MyListFile() + { + } + + private void InitVals() + { + ListID = 0; + FileID = 0; + EpisodeID = 0; + AnimeID = 0; + GroupID = 0; + FileDate = ""; + ViewDateUDP = 0; + ViewDateHTTP = ""; + Storage = ""; + Source = ""; + Other = ""; + FileState = 0; + WatchedDate = null; + } + + // constructor + // sRecMessage is the message received from ANIDB file info command + public Raw_AniDB_MyListFile(string sRecMessage) + { + // remove the header info + string[] sDetails = sRecMessage.Substring(11).Split('|'); + + // 221 MYLIST + + //{int4 lid}|{int4 fid}|{int4 eid}|{int4 aid}|{int4 gid}|{int4 date}|{int2 state}|{int4 viewdate}|{str storage}|{str source}|{str other}|{int2 filestate} + // 0. 66031082 ** list id + // 1. 572794 ** file id + // 2. 99294 ** episode id + // 3. 6107 ** anime id + // 4. 2723 ** group id + // 5. 1239598714 ** fileDate + // 6. 1 ** state + // 7. 0 ** view date (will contain 0 if not watched, otherwise has the date it was watched) + // 8. ** storage + // 9. ** source + // 10. ** other + // 11. 0 ** filestate + + this.ListID = AniDBAPILib.ProcessAniDBInt(sDetails[0]); + this.FileID = AniDBAPILib.ProcessAniDBInt(sDetails[1]); + this.EpisodeID = AniDBAPILib.ProcessAniDBInt(sDetails[2]); + this.AnimeID = AniDBAPILib.ProcessAniDBInt(sDetails[3]); + this.GroupID = AniDBAPILib.ProcessAniDBInt(sDetails[4]); + this.FileDate = AniDBAPILib.ProcessAniDBString(sDetails[5]); + this.State = AniDBAPILib.ProcessAniDBInt(sDetails[6]); + this.ViewDateUDP = AniDBAPILib.ProcessAniDBInt(sDetails[7]); + this.Storage = AniDBAPILib.ProcessAniDBString(sDetails[8]); + this.Source = AniDBAPILib.ProcessAniDBString(sDetails[9]); + this.Other = AniDBAPILib.ProcessAniDBString(sDetails[10]); + this.FileState = AniDBAPILib.ProcessAniDBInt(sDetails[11]); + + // calculate the watched date + if (ViewDateUDP > 0) + { + DateTime utcDate = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); + utcDate = utcDate.AddSeconds(ViewDateUDP); + + WatchedDate = utcDate.ToLocalTime(); + } + } + + public void ProcessHTTPSource(XmlNode node) + { + + this.ListID = int.Parse(node.Attributes["id"].Value); + this.AnimeID = int.Parse(node.Attributes["aid"].Value); + this.EpisodeID = int.Parse(node.Attributes["eid"].Value); + this.FileID = int.Parse(node.Attributes["fid"].Value); + + this.ViewDateHTTP = AniDBHTTPHelper.TryGetAttribute(node, "viewdate"); + + // calculate the watched date + if (!string.IsNullOrEmpty(ViewDateHTTP) && ViewDateHTTP.Length > 17) + { + try + { + // eg "2011-02-23T20:49:18+0000" + int year = int.Parse(ViewDateHTTP.Trim().Substring(0, 4)); + int month = int.Parse(ViewDateHTTP.Trim().Substring(5, 2)); + int day = int.Parse(ViewDateHTTP.Trim().Substring(8, 2)); + + int hour = int.Parse(ViewDateHTTP.Trim().Substring(11, 2)); + int minute = int.Parse(ViewDateHTTP.Trim().Substring(14, 2)); + int second = int.Parse(ViewDateHTTP.Trim().Substring(17, 2)); + + DateTime utcDate = new DateTime(year, month, day, hour, minute, second, DateTimeKind.Utc); + utcDate = utcDate.AddSeconds(ViewDateUDP); + + WatchedDate = utcDate.ToLocalTime(); + } + catch (Exception ex) + { + logger.ErrorException("Error processing View Date HTTP: " + ex.ToString(), ex); + } + } + + string tempstate = AniDBHTTPHelper.TryGetProperty(node, "state"); + int istate = 0; + int.TryParse(tempstate, out istate); + this.State = istate; + + string fstate = AniDBHTTPHelper.TryGetProperty(node, "filestate"); + int ifilestate = 0; + int.TryParse(fstate, out ifilestate); + this.FileState = ifilestate; + + this.Source = AniDBHTTPHelper.TryGetProperty(node, "storage"); + + } + + public override string ToString() + { + return string.Format("Raw_AniDB_MyListFile:: fileID: {0} | IsWatched: {1}", FileID, IsWatched); + } + + } +} diff --git a/JMMServer/AniDB_API/Raws/Raw_AniDB_NotifyAlert.cs b/JMMServer/AniDB_API/Raws/Raw_AniDB_NotifyAlert.cs new file mode 100644 index 000000000..0b9b527b4 --- /dev/null +++ b/JMMServer/AniDB_API/Raws/Raw_AniDB_NotifyAlert.cs @@ -0,0 +1,133 @@ +using System; +using System.Collections.Generic; +using System.Text; +using JMMServer; + +namespace AniDBAPI +{ + public class Raw_AniDB_NotifyAlert + { + protected long iD; + public long ID + { + get { return iD; } + set { iD = value; } + } + + protected long fromUserID; + public long FromUserID + { + get { return fromUserID; } + set { fromUserID = value; } + } + + protected string fromUserName; + public string FromUserName + { + get { return fromUserName; } + set { fromUserName = value; } + } + + protected int alertDate; + public int AlertDate + { + get { return alertDate; } + set { alertDate = value; } + } + + protected long alertType; + public long AlertType + { + get { return alertType; } + set { alertType = value; } + } + + protected int alertCount; + public int AlertCount + { + get { return alertCount; } + set { alertCount = value; } + } + + protected string relName; + public string RelName + { + get { return relName; } + set { relName = value; } + } + + protected string body; + public string Body + { + get { return body; } + set { body = value; } + } + + private List fileIDs = new List(); + public List FileIDs + { + get { return fileIDs; } + set { fileIDs = value; } + } + + public DateTime? AlertDateAsDate + { + get + { + return Utils.GetAniDBDateAsDate(alertDate); + } + } + + public Raw_AniDB_NotifyAlert(string sRecMessage) + { + // remove the header info + string[] sDetails = sRecMessage.Substring(14).Split('|'); + + //{int4 relid}|{int4 type}|{int2 count}|{int4 date}|{str relidname}|{str fids} + //293 NOTIFYGET + //0. 6080 + //1. 0 + //2. 2 + //3. 1262144732 + //4. Queen`s Blade: Rurou no Senshi + //5. 685215,685216,685210,685211,685208,685213,685214,685212,685209 + + + + iD = long.Parse(sDetails[0]); + alertType = long.Parse(sDetails[1]); + alertCount = int.Parse(sDetails[2]); + alertDate = AniDBAPILib.ProcessAniDBInt(sDetails[3]); + relName = AniDBAPILib.ProcessAniDBString(sDetails[4]); + + string[] fids = sDetails[5].Split(','); + + foreach (string fid in fids) + { + long lfid = 0; + long.TryParse(fid, out lfid); + if (lfid > 0) fileIDs.Add(lfid); + } + } + + + + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + sb.Append("Raw_AniDB_NotifyAlert:: ID: " + ID.ToString()); + sb.Append(" | alertDate: " + AlertDateAsDate.ToString()); + sb.Append(" | alertType: " + alertType.ToString()); + sb.Append(" | alertCount: " + alertCount.ToString()); + sb.Append(" | relName: " + relName); + sb.Append(" | file ids: "); + foreach (long fid in fileIDs) + { + sb.Append(fid.ToString() + ","); + } + + + return sb.ToString(); + } + } +} diff --git a/JMMServer/AniDB_API/Raws/Raw_AniDB_NotifyList.cs b/JMMServer/AniDB_API/Raws/Raw_AniDB_NotifyList.cs new file mode 100644 index 000000000..5f20a0bbb --- /dev/null +++ b/JMMServer/AniDB_API/Raws/Raw_AniDB_NotifyList.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace AniDBAPI +{ + public class Raw_AniDB_NotifyList + { + private List headers = new List(); + public List Headers + { + get { return headers; } + set { headers = value; } + } + + public Raw_AniDB_NotifyList(string sRecMessage) + { + /* + // 291 NOTIFYLIST + M|1251116 + M|1251199 + M|1251090 + M|1251036 + M|1250854 + */ + + // remove the header info + string[] sDetails = sRecMessage.Substring(0).Split('\n'); + + if (sDetails.Length <= 2) return; + + for (int i=1; i< sDetails.Length -1; i++) // first item will be the status command, and last will be empty + { + NotifyListHeader head = new NotifyListHeader(); + + // {str type}|{int4 id} + string[] flds = sDetails[i].Substring(0).Split('|'); + head.NotifyType = flds[0].Trim().ToUpper(); + head.NotifyID = long.Parse(flds[1]); + headers.Add(head); + + //BaseConfig.MyAnimeLog.Write("grp: {0}", grp); + } + } + } +} diff --git a/JMMServer/AniDB_API/Raws/Raw_AniDB_NotifyMessage.cs b/JMMServer/AniDB_API/Raws/Raw_AniDB_NotifyMessage.cs new file mode 100644 index 000000000..30eb2ae47 --- /dev/null +++ b/JMMServer/AniDB_API/Raws/Raw_AniDB_NotifyMessage.cs @@ -0,0 +1,109 @@ +using System; +using System.Collections.Generic; +using System.Text; +using JMMServer; + +namespace AniDBAPI +{ + public class Raw_AniDB_NotifyMessage + { + + protected long iD; + public long ID + { + get { return iD; } + set { iD = value; } + } + + protected long fromUserID; + public long FromUserID + { + get { return fromUserID; } + set { fromUserID = value; } + } + + protected string fromUserName; + public string FromUserName + { + get { return fromUserName; } + set { fromUserName = value; } + } + + protected int messageDate; + public int MessageDate + { + get { return messageDate; } + set { messageDate = value; } + } + + protected long messageType; + public long MessageType + { + get { return messageType; } + set { messageType = value; } + } + + protected string title; + public string Title + { + get { return title; } + set { title = value; } + } + + protected string body; + public string Body + { + get { return body; } + set { body = value; } + } + + public DateTime? MessageDateAsDate + { + get + { + return Utils.GetAniDBDateAsDate(MessageDate); + } + } + + public Raw_AniDB_NotifyMessage(string sRecMessage) + { + // remove the header info + string[] sDetails = sRecMessage.Substring(14).Split('|'); + + //{int4 id}|{int4 from_user_id}|{str from_user_name}|{int4 date}|{int4 type}|{str title}|{str body} + //292 NOTIFYGET + //0. 1010180 + //1. 0 + //2. -unknown- + //3. 1243764587 + //4. 2 + //5. Group Drop Notification - [LIME]/Amaenaide yo!! Katsu!! + //6. This is an automated message notifying you that a group has dropped an anime
you were collecting.

Group: LIME Anime [LIME] (2182)
Anime: Amaenaide yo!! Katsu!! (4145)

marked dropped by: keitarou (1294)

comment/reason:
GRANTED CREQ
+ + + + iD = long.Parse(sDetails[0]); + fromUserID = long.Parse(sDetails[1]); + fromUserName = AniDBAPILib.ProcessAniDBString(sDetails[2]); + messageDate = AniDBAPILib.ProcessAniDBInt(sDetails[3]); + messageType = long.Parse(sDetails[4]); + title = AniDBAPILib.ProcessAniDBString(sDetails[5]); + body = AniDBAPILib.ProcessAniDBString(sDetails[6]); + } + + + + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + sb.Append("AniDB_NotifyMessage:: ID: " + ID); + sb.Append(" | messageDate: " + MessageDateAsDate.ToString()); + sb.Append(" | fromUserName: " + fromUserName); + sb.Append(" | title: " + title); + sb.Append(" | body: " + body); + + + return sb.ToString(); + } + } +} diff --git a/JMMServer/AniDB_API/Raws/Raw_AniDB_RelatedAnime.cs b/JMMServer/AniDB_API/Raws/Raw_AniDB_RelatedAnime.cs new file mode 100644 index 000000000..9d18175b5 --- /dev/null +++ b/JMMServer/AniDB_API/Raws/Raw_AniDB_RelatedAnime.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Xml; + +namespace AniDBAPI +{ + [Serializable] + public class Raw_AniDB_RelatedAnime : XMLBase + { + public int AnimeID { get; set; } + public int RelatedAnimeID { get; set; } + public string RelationType { get; set; } + + public Raw_AniDB_RelatedAnime() + { + InitFields(); + } + + private void InitFields() + { + AnimeID = 0; + RelatedAnimeID = 0; + RelationType = string.Empty; + } + + public void ProcessFromHTTPResult(XmlNode node, int anid) + { + InitFields(); + + this.AnimeID = anid; + + int id = 0; + int.TryParse(AniDBHTTPHelper.TryGetAttribute(node, "id"), out id); + this.RelatedAnimeID = id; + + this.RelationType = AniDBHTTPHelper.TryGetAttribute(node, "type"); + } + + } +} diff --git a/JMMServer/AniDB_API/Raws/Raw_AniDB_Review.cs b/JMMServer/AniDB_API/Raws/Raw_AniDB_Review.cs new file mode 100644 index 000000000..a4b48aeab --- /dev/null +++ b/JMMServer/AniDB_API/Raws/Raw_AniDB_Review.cs @@ -0,0 +1,74 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace AniDBAPI +{ + public class Raw_AniDB_Review : XMLBase + { + public int ReviewID { get; set; } + public int AuthorID { get; set; } + public int RatingAnimation { get; set; } + public int RatingSound { get; set; } + public int RatingStory { get; set; } + public int RatingCharacter { get; set; } + public int RatingValue { get; set; } + public int RatingEnjoyment { get; set; } + public string ReviewText { get; set; } + + public Raw_AniDB_Review() + { + ReviewID = 0; + AuthorID = 0; + RatingAnimation = 0; + RatingSound = 0; + RatingStory = 0; + RatingCharacter = 0; + RatingValue = 0; + RatingEnjoyment = 0; + ReviewText = ""; + } + + public Raw_AniDB_Review(string sRecMessage) + { + // remove the header info + string[] sDetails = sRecMessage.Substring(11).Split('|'); + + // 234 REVIEW0|4||1198|18198|700|700|600|900|500|500|*EDIT* just an update, I stopped watching Naruto + + + // 234 REVIEW + // 0. 0 ** current part + // 1. 4 ** max parts + // 2. ** blank + // 3. 1198 ** review id + // 4. 18198 ** author id + // 5. 700 ** rating Animation + // 6. 700 ** rating Sound + // 7. 600 ** rating Story + // 8. 900 ** rating Character + // 9. 500 ** rating Value + // 10. 500 ** rating Enjoyment + // 11. *EDIT* just an update, I stopped watching Naruto ** review text + + ReviewID = int.Parse(sDetails[3].Trim()); + AuthorID = int.Parse(sDetails[4].Trim()); + RatingAnimation = int.Parse(sDetails[5].Trim()); + RatingSound = int.Parse(sDetails[6].Trim()); + RatingStory = int.Parse(sDetails[7].Trim()); + RatingCharacter = int.Parse(sDetails[8].Trim()); + RatingValue = int.Parse(sDetails[9].Trim()); + RatingEnjoyment = int.Parse(sDetails[10].Trim()); + ReviewText = AniDBAPILib.ProcessAniDBString(sDetails[11].Trim()); + } + + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + sb.Append("reviewID: " + ReviewID.ToString()); + sb.Append(" | reviewText: " + ReviewText); + + return sb.ToString(); + } + } +} diff --git a/JMMServer/AniDB_API/Raws/Raw_AniDB_SimilarAnime.cs b/JMMServer/AniDB_API/Raws/Raw_AniDB_SimilarAnime.cs new file mode 100644 index 000000000..5951bc3e3 --- /dev/null +++ b/JMMServer/AniDB_API/Raws/Raw_AniDB_SimilarAnime.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Xml; + +namespace AniDBAPI +{ + [Serializable] + public class Raw_AniDB_SimilarAnime : XMLBase + { + public int AnimeID { get; set; } + public int SimilarAnimeID { get; set; } + public int Approval { get; set; } + public int Total { get; set; } + + public Raw_AniDB_SimilarAnime() + { + InitFields(); + } + + private void InitFields() + { + AnimeID = 0; + SimilarAnimeID = 0; + Approval = 0; + Total = 0; + } + + public void ProcessFromHTTPResult(XmlNode node, int anid) + { + InitFields(); + + this.AnimeID = anid; + + int id = 0; + int.TryParse(AniDBHTTPHelper.TryGetAttribute(node, "id"), out id); + this.SimilarAnimeID = id; + + int appr = 0; + int.TryParse(AniDBHTTPHelper.TryGetAttribute(node, "approval"), out appr); + this.Approval = appr; + + int tot = 0; + int.TryParse(AniDBHTTPHelper.TryGetAttribute(node, "total"), out tot); + this.Total = tot; + } + } +} diff --git a/JMMServer/AniDB_API/Raws/Raw_AniDB_Tag.cs b/JMMServer/AniDB_API/Raws/Raw_AniDB_Tag.cs new file mode 100644 index 000000000..718c72680 --- /dev/null +++ b/JMMServer/AniDB_API/Raws/Raw_AniDB_Tag.cs @@ -0,0 +1,68 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Xml; + +namespace AniDBAPI +{ + [Serializable] + public class Raw_AniDB_Tag : XMLBase + { + #region Properties + + public int AnimeID { get; set; } + public int TagID { get; set; } + public int Spoiler { get; set; } + public int LocalSpoiler { get; set; } + public int GlobalSpoiler { get; set; } + public string TagName { get; set; } + public string TagDescription { get; set; } + public int TagCount { get; set; } + public int Approval { get; set; } + + #endregion + + public Raw_AniDB_Tag() + { + } + + public void ProcessFromHTTPResult(XmlNode node, int anid) + { + this.AnimeID = anid; + this.TagID = 0; + this.Spoiler = 0; + this.LocalSpoiler = 0; + this.GlobalSpoiler = 0; + this.TagName = ""; + this.TagDescription = ""; + this.TagCount = 0; + this.Approval = 0; + + this.TagID = int.Parse(AniDBHTTPHelper.TryGetAttribute(node, "id")); + + int tapp = 0; + int.TryParse(AniDBHTTPHelper.TryGetAttribute(node, "approval"), out tapp); + this.Approval = tapp; + + this.TagName = AniDBHTTPHelper.TryGetProperty(node, "name"); + this.TagDescription = AniDBHTTPHelper.TryGetProperty(node, "description"); + + int tcount = 0; + int.TryParse(AniDBHTTPHelper.TryGetProperty(node, "count"), out tcount); + this.TagCount = tcount; + + bool sp = false; + bool.TryParse(AniDBHTTPHelper.TryGetAttribute(node, "spoiler"), out sp); + this.Spoiler = sp ? 1 : 0; + + bool lsp = false; + bool.TryParse(AniDBHTTPHelper.TryGetAttribute(node, "localspoiler"), out lsp); + this.Spoiler = lsp ? 1 : 0; + + bool gsp = false; + bool.TryParse(AniDBHTTPHelper.TryGetAttribute(node, "globalspoiler"), out gsp); + this.Spoiler = gsp ? 1 : 0; + } + } +} diff --git a/JMMServer/AniDB_API/Raws/Raw_AniDB_Vote.cs b/JMMServer/AniDB_API/Raws/Raw_AniDB_Vote.cs new file mode 100644 index 000000000..f6fa5229a --- /dev/null +++ b/JMMServer/AniDB_API/Raws/Raw_AniDB_Vote.cs @@ -0,0 +1,81 @@ +using System; +using System.Collections.Generic; +using System.Text; + + +namespace AniDBAPI +{ + public class Raw_AniDB_Vote : XMLBase + { + public int EntityID { get; set; } + + public int EpisodeNumber { get; set; } + + public int EpisodeType { get; set; } + + public int VoteValue { get; set; } + + public int VoteType { get; set; } + + public Raw_AniDB_Vote() + { + EpisodeNumber = -1; + EpisodeType = 1; + VoteType = 1; + } + + + // constructor + // sRecMessage is the message received from ANIDB file info command + + + public void ProcessVoteFoundAnime(string sRecMessage, int animeID, enAniDBVoteType vtype) + { + // remove the header info + string[] sDetails = sRecMessage.Substring(15).Split('|'); + + // 261 VOTE FOUNDCode Geass Hangyaku no Lelouch|900|1|4521 + + + // 261 VOTE FOUND + // 0. Code Geass Hangyaku no Lelouch + // 1. 900 ** vote value + // 2. 1 ** vote type + // 3. 4521 ** animeid + + this.EntityID = animeID; + this.EpisodeNumber = -1; + this.VoteValue = int.Parse(sDetails[1].Trim()); + this.VoteType = (int)vtype; + this.EpisodeType = (int)enEpisodeType.Episode; + } + + public void ProcessVoteFoundEpisode(string sRecMessage, int animeID, int epno, enEpisodeType epType) + { + // remove the header info + string[] sDetails = sRecMessage.Substring(15).Split('|'); + + //261 VOTE FOUNDThe Day a New Demon Was Born|700|1|63091 + + // 261 VOTE FOUND + // 0. The Day a New Demon Was Born + // 1. 700 ** vote value + // 2. 1 ** ??? + // 3. 63091 ** episodeid + + this.EntityID = animeID; + this.EpisodeNumber = epno; + this.VoteValue = int.Parse(sDetails[1].Trim()); + this.VoteType = (int)enAniDBVoteType.Episode; + this.EpisodeType = (int)epType; + + } + + public override string ToString() + { + return string.Format("AniDB_Vote:: entityID: {0} | episodeNumber: {1} | episodeType: {2} | voteValue: {3} | voteType: {4}", + EntityID, EpisodeNumber, EpisodeType, VoteValue, VoteType); + } + + } +} diff --git a/JMMServer/AniDB_API/Raws/Raw_AniDB_Vote_HTTP.cs b/JMMServer/AniDB_API/Raws/Raw_AniDB_Vote_HTTP.cs new file mode 100644 index 000000000..dd4fa4192 --- /dev/null +++ b/JMMServer/AniDB_API/Raws/Raw_AniDB_Vote_HTTP.cs @@ -0,0 +1,64 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using AniDBAPI; +using System.Xml; + +namespace JMMServer.AniDB_API.Raws +{ + public class Raw_AniDB_Vote_HTTP : XMLBase + { + public int EntityID { get; set; } + public int VoteValue { get; set; } + public enAniDBVoteType VoteType { get; set; } + + public Raw_AniDB_Vote_HTTP() + { + EntityID = -1; + VoteValue = -1; + VoteType = enAniDBVoteType.Anime; + } + + + public void ProcessAnime(XmlNode node) + { + this.VoteType = enAniDBVoteType.Anime; + this.EntityID = int.Parse(node.Attributes["aid"].Value); + double val = 0; + double.TryParse(node.InnerText, out val); + int ival = 0; + int.TryParse((val * (double)100).ToString(), out ival); + VoteValue = ival; + } + + public void ProcessAnimeTemp(XmlNode node) + { + this.VoteType = enAniDBVoteType.AnimeTemp; + this.EntityID = int.Parse(node.Attributes["aid"].Value); + double val = 0; + double.TryParse(node.InnerText, out val); + int ival = 0; + int.TryParse((val * (double)100).ToString(), out ival); + VoteValue = ival; + } + + public void ProcessEpisode(XmlNode node) + { + this.VoteType = enAniDBVoteType.Episode; + this.EntityID = int.Parse(node.Attributes["eid"].Value); + double val = 0; + double.TryParse(node.InnerText, out val); + int ival = 0; + int.TryParse((val * (double)100).ToString(), out ival); + VoteValue = ival; + } + + + public override string ToString() + { + return string.Format("AniDB_Vote:: entityID: {0} | voteValue: {1} | voteType: {2}", + EntityID, VoteValue, VoteType); + } + } +} diff --git a/JMMServer/AniDB_API/UpdatesCollection.cs b/JMMServer/AniDB_API/UpdatesCollection.cs new file mode 100644 index 000000000..955d28e30 --- /dev/null +++ b/JMMServer/AniDB_API/UpdatesCollection.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace JMMServer.AniDB_API +{ + public class UpdatesCollection + { + protected string rawAnimeIDs = ""; + public string RawAnimeIDs + { + get { return rawAnimeIDs; } + set { rawAnimeIDs = value; } + } + + protected long updateCount = 0; + public long UpdateCount + { + get { return updateCount; } + set { updateCount = value; } + } + + public List AnimeIDs + { + get + { + List ids = new List(); + string[] sids = rawAnimeIDs.Split('|'); + foreach (string sid in sids) + { + int id = 0; + if (int.TryParse(sid, out id)) ids.Add(id); + } + + return ids; + } + } + + + // default constructor + public UpdatesCollection() + { + } + + + } +} diff --git a/JMMServer/AniDB_API/Utils.cs b/JMMServer/AniDB_API/Utils.cs new file mode 100644 index 000000000..f4e0b4267 --- /dev/null +++ b/JMMServer/AniDB_API/Utils.cs @@ -0,0 +1,79 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Net; +using System.IO; +using NLog; + +namespace AniDBAPI +{ + public class APIUtils + { + private static Logger logger = LogManager.GetCurrentClassLogger(); + + public const int LastYear = 2050; + + public static string DownloadWebPage(string url) + { + try + { + HttpWebRequest webReq = (HttpWebRequest)WebRequest.Create(url); + webReq.Timeout = 20000; // 20 seconds + webReq.Headers.Add(HttpRequestHeader.AcceptEncoding, "gzip,deflate"); + webReq.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate; + HttpWebResponse WebResponse = (HttpWebResponse)webReq.GetResponse(); + + Stream responseStream = WebResponse.GetResponseStream(); + String enco = WebResponse.CharacterSet; + Encoding encoding = null; + if (!String.IsNullOrEmpty(enco)) + encoding = Encoding.GetEncoding(WebResponse.CharacterSet); + if (encoding == null) + encoding = Encoding.Default; + StreamReader Reader = new StreamReader(responseStream, encoding); + + string output = Reader.ReadToEnd(); + + WebResponse.Close(); + responseStream.Close(); + + return output; + } + catch (Exception ex) + { + logger.ErrorException("Error in APIUtils.DownloadWebPage: {0}", ex); + return ""; + } + } + + public static Stream DownloadWebBinary(string url) + { + try + { + HttpWebResponse response = null; + HttpWebRequest webReq = (HttpWebRequest)WebRequest.Create(url); + // Note: some network proxies require the useragent string to be set or they will deny the http request + // this is true for instance for EVERY thailand internet connection (also needs to be set for banners/episodethumbs and any other http request we send) + webReq.UserAgent = "Anime2MP"; + webReq.Timeout = 20000; // 20 seconds + response = (HttpWebResponse)webReq.GetResponse(); + + if (response != null) // Get the stream associated with the response. + return response.GetResponseStream(); + else + return null; + } + catch (Exception ex) + { + logger.ErrorException("Error in APIUtils.DownloadWebBinary: {0}", ex); + return null; + } + } + + + + + + + } +} diff --git a/JMMServer/AniDB_API/XMLBase.cs b/JMMServer/AniDB_API/XMLBase.cs new file mode 100644 index 000000000..0163a033e --- /dev/null +++ b/JMMServer/AniDB_API/XMLBase.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Xml.Serialization; +using System.Xml; + +namespace AniDBAPI +{ + public class XMLBase + { + public string ToXML() + { + XmlSerializerNamespaces ns = new XmlSerializerNamespaces(); + ns.Add("", ""); + + XmlSerializer serializer = new XmlSerializer(this.GetType()); + XmlWriterSettings settings = new XmlWriterSettings(); + settings.OmitXmlDeclaration = true; // Remove the + + StringBuilder sb = new StringBuilder(); + XmlWriter writer = XmlWriter.Create(sb, settings); + serializer.Serialize(writer, this, ns); + + return sb.ToString(); + } + } +} diff --git a/JMMServer/App.xaml b/JMMServer/App.xaml new file mode 100644 index 000000000..dac497499 --- /dev/null +++ b/JMMServer/App.xaml @@ -0,0 +1,8 @@ + + + + + diff --git a/JMMServer/App.xaml.cs b/JMMServer/App.xaml.cs new file mode 100644 index 000000000..864ff252e --- /dev/null +++ b/JMMServer/App.xaml.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Configuration; +using System.Data; +using System.Linq; +using System.Windows; + +namespace JMMServer +{ + /// + /// Interaction logic for App.xaml + /// + public partial class App : Application + { + } +} diff --git a/JMMServer/BlockingList.cs b/JMMServer/BlockingList.cs new file mode 100644 index 000000000..e4c88204e --- /dev/null +++ b/JMMServer/BlockingList.cs @@ -0,0 +1,128 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Text; +using System.Threading; + +namespace JMMServer +{ + public class BlockingList : IEnumerable + { + private List _list; + private readonly object _syncRoot; + private int _count = 0; + private int _size = 0; + + public int Count + { + get { return _count; } + } + + public void Add(T data) + { + Add(data, Timeout.Infinite); + } + + public void Add(T data, int millisecondsTimeout) + { + if (data == null) throw new ArgumentNullException("data"); + + lock (_syncRoot) + { + while (_count == _size) + { + try + { + // Monitor exited with exception. + // Could be owner thread of monitor + // object was terminated or timeout + // on wait. Pulse any/all waiting + // threads to ensure we don't get + // any "live locked" producers. + if (!Monitor.Wait(_syncRoot, millisecondsTimeout)) + throw new System.Exception("Timeout on blockinglist add"); + } + catch + { + Monitor.PulseAll(_syncRoot); + throw; + } + } + + _list.Add(data); + _count++; + if (_count == 1) + // could have blocking Dequeue thread(s). + Monitor.PulseAll(_syncRoot); + } + } + + public void Remove(T data) + { + _count--; + lock (_list) _list.Remove(data); + } + + public T GetNextItem() + { + return GetNextItem(Timeout.Infinite); + } + + public T GetNextItem(int millisecondsTimeout) + { + lock (_syncRoot) + { + while (_count == 0) + { + try + { + if (!Monitor.Wait(_syncRoot, millisecondsTimeout)) + throw new System.Exception("Timeout on blockinglist GetNextItem"); + } + catch + { + Monitor.PulseAll(_syncRoot); + throw; + } + } + + if (_count == (_size - 1)) + // could have blocking Enqueue thread(s). + Monitor.PulseAll(_syncRoot); + + return _list[0]; + } + } + + public BlockingList(int size) + { + if (size <= 0) throw new ArgumentOutOfRangeException("size"); + + _size = size; + _syncRoot = new object(); + _list = new List(size); + } + + public BlockingList() + { + _size = int.MaxValue; + _syncRoot = new object(); + _list = new List(); + } + + public bool Contains(T data) + { + lock (_list) return _list.Contains(data); + } + + IEnumerator IEnumerable.GetEnumerator() + { + while (true) yield return GetNextItem(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return ((IEnumerable)this).GetEnumerator(); + } + } +} diff --git a/JMMServer/CachedNLogTarget.cs b/JMMServer/CachedNLogTarget.cs new file mode 100644 index 000000000..0022abf5c --- /dev/null +++ b/JMMServer/CachedNLogTarget.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using NLog; +using NLog.Targets; +using System.Windows; + +namespace JMMServer +{ + [Target("InternalCache")] + public sealed class CachedNLogTarget : TargetWithLayout + { + public CachedNLogTarget() + { + } + + protected override void Write(LogEventInfo logEvent) + { + string logMessage = this.Layout.Render(logEvent); + + + //MainWindow.AddLogEntry(logMessage); + } + + } +} diff --git a/JMMServer/Commands/AniDB/CommandRequest_AddFileToMyList.cs b/JMMServer/Commands/AniDB/CommandRequest_AddFileToMyList.cs new file mode 100644 index 000000000..24c7a3aea --- /dev/null +++ b/JMMServer/Commands/AniDB/CommandRequest_AddFileToMyList.cs @@ -0,0 +1,166 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Repositories; +using JMMServer.Entities; +using System.Xml; + +namespace JMMServer.Commands +{ + [Serializable] + public class CommandRequest_AddFileToMyList : CommandRequestImplementation, ICommandRequest + { + public string Hash { get; set; } + + private VideoLocal vid = null; + + public CommandRequestPriority DefaultPriority + { + get { return CommandRequestPriority.Priority7; } + } + + public string PrettyDescription + { + get + { + if (vid != null) + return string.Format("Adding file to MyList: {0}", vid.FullServerPath); + else + return string.Format("Adding file to MyList: {0}", Hash); + } + } + + public CommandRequest_AddFileToMyList() + { + } + + public CommandRequest_AddFileToMyList(string hash) + { + this.Hash = hash; + this.CommandType = (int)CommandRequestType.AniDB_AddFileUDP; + this.Priority = (int)DefaultPriority; + + GenerateCommandID(); + } + + public override void ProcessCommand() + { + logger.Info("Processing CommandRequest_AddFileToMyList: {0}", Hash); + + + try + { + VideoLocalRepository repVids = new VideoLocalRepository(); + AnimeEpisodeRepository repEpisodes = new AnimeEpisodeRepository(); + + vid = repVids.GetByHash(this.Hash); + if (vid != null) + { + // when adding a file via the API, newWatchedStatus will return with current watched status on AniDB + // if the file is already on the user's list + + // mark the video file as watched + DateTime? watchedDate = null; + bool newWatchedStatus = JMMService.AnidbProcessor.AddFileToMyList(vid, ref watchedDate); + + // do for all AniDB users + JMMUserRepository repUsers = new JMMUserRepository(); + List aniDBUsers = repUsers.GetAniDBUsers(); + + if (aniDBUsers.Count > 0) + { + JMMUser juser = aniDBUsers[0]; + vid.ToggleWatchedStatus(newWatchedStatus, false, watchedDate, false, juser.JMMUserID); + logger.Info("Adding file to list: {0} - {1}", vid.ToString(), watchedDate); + + // if the the episode is watched we may want to set the file to watched as well + if (ServerSettings.Import_UseExistingFileWatchedStatus && !newWatchedStatus) + { + if (vid.AnimeEpisodes.Count > 0) + { + AnimeEpisode ep = vid.AnimeEpisodes[0]; + AnimeEpisode_User epUser = null; + + foreach (JMMUser tempuser in aniDBUsers) + { + // only find the first user who watched this + if (epUser == null) + epUser = ep.GetUserRecord(tempuser.JMMUserID); + } + + if (epUser != null) + { + logger.Info("Setting file as watched, because episode was already watched: {0} - user: {1}", vid.ToString(), juser.Username); + vid.ToggleWatchedStatus(true, true, epUser.WatchedDate, false, epUser.JMMUserID); + + } + + } + } + } + + AnimeSeries ser = vid.AnimeEpisodes[0].AnimeSeries; + // all the eps should belong to the same anime + ser.UpdateStats(true, true, true); + + } + + + } + catch (Exception ex) + { + logger.Error("Error processing CommandRequest_AddFileToMyList: {0} - {1}", Hash, ex.ToString()); + return; + } + } + + /// + /// This should generate a unique key for a command + /// It will be used to check whether the command has already been queued before adding it + /// + public override void GenerateCommandID() + { + this.CommandID = string.Format("CommandRequest_AddFileToMyList_{0}", Hash); + } + + public override bool LoadFromDBCommand(CommandRequest cq) + { + this.CommandID = cq.CommandID; + this.CommandRequestID = cq.CommandRequestID; + this.CommandType = cq.CommandType; + this.Priority = cq.Priority; + this.CommandDetails = cq.CommandDetails; + this.DateTimeUpdated = cq.DateTimeUpdated; + + // read xml to get parameters + if (this.CommandDetails.Trim().Length > 0) + { + XmlDocument docCreator = new XmlDocument(); + docCreator.LoadXml(this.CommandDetails); + + // populate the fields + this.Hash = TryGetProperty(docCreator, "CommandRequest_AddFileToMyList", "Hash"); + } + + if (this.Hash.Trim().Length > 0) + return true; + else + return false; + } + + public override CommandRequest ToDatabaseObject() + { + GenerateCommandID(); + + CommandRequest cq = new CommandRequest(); + cq.CommandID = this.CommandID; + cq.CommandType = this.CommandType; + cq.Priority = this.Priority; + cq.CommandDetails = this.ToXML(); + cq.DateTimeUpdated = DateTime.Now; + + return cq; + } + } +} diff --git a/JMMServer/Commands/AniDB/CommandRequest_DeleteFileFromMyList.cs b/JMMServer/Commands/AniDB/CommandRequest_DeleteFileFromMyList.cs new file mode 100644 index 000000000..7156e28dc --- /dev/null +++ b/JMMServer/Commands/AniDB/CommandRequest_DeleteFileFromMyList.cs @@ -0,0 +1,109 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Repositories; +using JMMServer.Entities; +using System.Xml; + +namespace JMMServer.Commands +{ + [Serializable] + public class CommandRequest_DeleteFileFromMyList : CommandRequestImplementation, ICommandRequest + { + public string Hash { get; set; } + public long FileSize { get; set; } + + public CommandRequestPriority DefaultPriority + { + get { return CommandRequestPriority.Priority7; } + } + + public string PrettyDescription + { + get + { + return string.Format("Deleting file from MyList: {0}", Hash); + } + } + + public CommandRequest_DeleteFileFromMyList() + { + } + + public CommandRequest_DeleteFileFromMyList(string hash, long fileSize) + { + this.Hash = hash; + this.FileSize = fileSize; + this.CommandType = (int)CommandRequestType.AniDB_DeleteFileUDP; + this.Priority = (int)DefaultPriority; + + GenerateCommandID(); + } + + public override void ProcessCommand() + { + logger.Info("Processing CommandRequest_DeleteFileFromMyList: {0}", Hash); + + try + { + JMMService.AnidbProcessor.DeleteFileFromMyList(Hash, FileSize); + logger.Info("Deleting file from list: {0}", Hash); + } + catch (Exception ex) + { + logger.Error("Error processing CommandRequest_AddFileToMyList: {0} - {1}", Hash, ex.ToString()); + return; + } + } + + /// + /// This should generate a unique key for a command + /// It will be used to check whether the command has already been queued before adding it + /// + public override void GenerateCommandID() + { + this.CommandID = string.Format("CommandRequest_DeleteFileFromMyList{0}", Hash); + } + + public override bool LoadFromDBCommand(CommandRequest cq) + { + this.CommandID = cq.CommandID; + this.CommandRequestID = cq.CommandRequestID; + this.CommandType = cq.CommandType; + this.Priority = cq.Priority; + this.CommandDetails = cq.CommandDetails; + this.DateTimeUpdated = cq.DateTimeUpdated; + + // read xml to get parameters + if (this.CommandDetails.Trim().Length > 0) + { + XmlDocument docCreator = new XmlDocument(); + docCreator.LoadXml(this.CommandDetails); + + // populate the fields + this.Hash = TryGetProperty(docCreator, "CommandRequest_DeleteFileFromMyList", "Hash"); + this.FileSize = long.Parse(TryGetProperty(docCreator, "CommandRequest_DeleteFileFromMyList", "FileSize")); + } + + if (this.Hash.Trim().Length > 0) + return true; + else + return false; + } + + public override CommandRequest ToDatabaseObject() + { + GenerateCommandID(); + + CommandRequest cq = new CommandRequest(); + cq.CommandID = this.CommandID; + cq.CommandType = this.CommandType; + cq.Priority = this.Priority; + cq.CommandDetails = this.ToXML(); + cq.DateTimeUpdated = DateTime.Now; + + return cq; + } + } +} diff --git a/JMMServer/Commands/AniDB/CommandRequest_GetAniDBTitles.cs b/JMMServer/Commands/AniDB/CommandRequest_GetAniDBTitles.cs new file mode 100644 index 000000000..9e9813007 --- /dev/null +++ b/JMMServer/Commands/AniDB/CommandRequest_GetAniDBTitles.cs @@ -0,0 +1,206 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Repositories; +using JMMServer.Entities; +using System.Xml; +using System.IO; + +namespace JMMServer.Commands +{ + [Serializable] + public class CommandRequest_GetAniDBTitles : CommandRequestImplementation, ICommandRequest + { + public CommandRequestPriority DefaultPriority + { + get { return CommandRequestPriority.Priority10; } + } + + public string PrettyDescription + { + get + { + return string.Format("Getting AniDB Titles from HTTP API"); + } + } + + public CommandRequest_GetAniDBTitles() + { + } + + public CommandRequest_GetAniDBTitles(string hash, bool watched) + { + this.CommandType = (int)CommandRequestType.AniDB_GetTitles; + this.Priority = (int)DefaultPriority; + + GenerateCommandID(); + } + + public override void ProcessCommand() + { + logger.Info("Processing CommandRequest_GetAniDBTitles"); + + + try + { + string url = Constants.AniDBTitlesURL; + logger.Trace("Get AniDB Titles: {0}", url); + + Stream s = Utils.DownloadWebBinary(url); + int bytes = 2048; + byte[] data = new byte[2048]; + StringBuilder b = new StringBuilder(); + UTF8Encoding enc = new UTF8Encoding(); + + ICSharpCode.SharpZipLib.GZip.GZipInputStream zis = new ICSharpCode.SharpZipLib.GZip.GZipInputStream(s); + + while ((bytes = zis.Read(data, 0, data.Length)) > 0) + b.Append(enc.GetString(data, 0, bytes)); + + zis.Close(); + + AniDB_Anime_TitleRepository repTitles = new AniDB_Anime_TitleRepository(); + + + + + /*string[] lines = b.ToString().Split('\n'); + Dictionary titles = new Dictionary(); + foreach (string line in lines) + { + if (line.Trim().Length == 0 || line.Trim().Substring(0, 1) == "#") continue; + + string[] fields = line.Split('|'); + + int animeID = 0; + int.TryParse(fields[0], out animeID); + if (animeID == 0) continue; + + string titleType = fields[1].Trim().ToLower(); + string language = fields[2].Trim().ToLower(); + string titleValue = fields[3].Trim(); + + List existingtitles = repTitles.GetByAnimeIDLanguageTypeValue(animeID, language, titleType, titleValue); + if (existingtitles.Count == 0) + { + } + + foreach (AniDB_Anime_Title animetitle in existingtitles) + { + if (animetitle.Title != titleValue) + { + animetitle.Title = titleValue; + repTitles.Save(animetitle); + } + } + + + AniDB_Title thisTitle = null; + if (titles.ContainsKey(animeID)) + { + thisTitle = titles[animeID]; + } + else + { + thisTitle = new AniDB_Title(); + thisTitle.AnimeID = animeID; + } + + if (titleType == 1 || titleType == 4) + { + if (language == "EN") thisTitle.EnglishName = titleValue; + if (language == "X-JAT") thisTitle.RomajiName = titleValue; + } + + if (titleType == 2) thisTitle.Synonyms.Add(titleValue); + if (titleType == 3) thisTitle.ShortTitles.Add(titleValue); + + titles[animeID] = thisTitle; + } + + foreach (AniDB_Title aniTitle in titles.Values) + { + AniDB_Anime anime = new AniDB_Anime(); + if (!anime.Load(aniTitle.AnimeID)) + { + anime.AnimeID = aniTitle.AnimeID; + + // populate with blank values instead of nulls + anime.AnimeNfoID = ""; + anime.AnimeType = -1; + anime.AwardList = ""; + anime.CharacterIDListRAW = ""; + anime.DateRecordUpdated = ""; + anime.DateTimeUpdated = DateTime.Now.AddDays(-20); // we do this so it is not excluded from updates + anime.Description = ""; + anime.GenreRAW = ""; + anime.ImageEnabled = 1; + anime.OtherName = ""; + anime.Picname = ""; + anime.RelatedAnimeIdsRAW = ""; + anime.RelatedAnimeTypesRAW = ""; + anime.ReviewIDListRAW = ""; + anime.KanjiName = ""; + anime.URL = ""; + } + anime.RomajiName = aniTitle.RomajiName; + anime.EnglishName = aniTitle.EnglishName; + anime.Synonyms = aniTitle.SynonymDBList; + anime.ShortNames = aniTitle.ShortTitlesDBList; + + anime.Save(true, false, false); + }*/ + + + } + catch (Exception ex) + { + logger.Error("Error processing CommandRequest_GetAniDBTitles: {0}", ex.ToString()); + return; + } + } + + /// + /// This should generate a unique key for a command + /// It will be used to check whether the command has already been queued before adding it + /// + public override void GenerateCommandID() + { + this.CommandID = string.Format("CommandRequest_GetAniDBTitles"); + } + + public override bool LoadFromDBCommand(CommandRequest cq) + { + this.CommandID = cq.CommandID; + this.CommandRequestID = cq.CommandRequestID; + this.CommandType = cq.CommandType; + this.Priority = cq.Priority; + this.CommandDetails = cq.CommandDetails; + this.DateTimeUpdated = cq.DateTimeUpdated; + + // read xml to get parameters + if (this.CommandDetails.Trim().Length > 0) + { + XmlDocument docCreator = new XmlDocument(); + docCreator.LoadXml(this.CommandDetails); + } + + return true; + } + + public override CommandRequest ToDatabaseObject() + { + GenerateCommandID(); + + CommandRequest cq = new CommandRequest(); + cq.CommandID = this.CommandID; + cq.CommandType = this.CommandType; + cq.Priority = this.Priority; + cq.CommandDetails = this.ToXML(); + cq.DateTimeUpdated = DateTime.Now; + + return cq; + } + } +} diff --git a/JMMServer/Commands/AniDB/CommandRequest_GetAnimeHTTP.cs b/JMMServer/Commands/AniDB/CommandRequest_GetAnimeHTTP.cs new file mode 100644 index 000000000..7dc2d89f1 --- /dev/null +++ b/JMMServer/Commands/AniDB/CommandRequest_GetAnimeHTTP.cs @@ -0,0 +1,129 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Xml; +using JMMServer.Entities; +using JMMServer.Repositories; + +namespace JMMServer.Commands +{ + [Serializable] + public class CommandRequest_GetAnimeHTTP : CommandRequestImplementation, ICommandRequest + { + public int AnimeID { get; set; } + public bool ForceRefresh { get; set; } + public bool DownloadRelations { get; set; } + + public CommandRequestPriority DefaultPriority + { + get { return CommandRequestPriority.Priority2; } + } + + public string PrettyDescription + { + get + { + return string.Format("Getting anime info from HTTP API: {0}", AnimeID); + } + } + + public CommandRequest_GetAnimeHTTP() + { + } + + public CommandRequest_GetAnimeHTTP(int animeid, bool forced, bool downloadRelations) + { + this.AnimeID = animeid; + this.DownloadRelations = downloadRelations; + this.ForceRefresh = forced; + this.CommandType = (int)CommandRequestType.AniDB_GetAnimeHTTP; + this.Priority = (int)DefaultPriority; + + GenerateCommandID(); + } + + public override void ProcessCommand() + { + logger.Info("Processing CommandRequest_GetAnimeHTTP: {0}", AnimeID); + + try + { + AniDB_AnimeRepository repAnime = new AniDB_AnimeRepository(); + AniDB_Anime anime = JMMService.AnidbProcessor.GetAnimeInfoHTTP(AnimeID, ForceRefresh, DownloadRelations); + + // download character / creator information + // the HTTP api only contains info about the characters, but not the creators associated with the character + if (ServerSettings.AniDB_DownloadCharactersCreators) + { + CommandRequest_GetCharactersCreators cmdChars = new CommandRequest_GetCharactersCreators(AnimeID, false); + cmdChars.Save(); + } + + // NOTE - related anime are downloaded when the relations are created + + // download group status info for this anime + // the group status will also help us determine missing episodes for a series + + + // download reviews + if (ServerSettings.AniDB_DownloadReviews) + { + CommandRequest_GetReviews cmd = new CommandRequest_GetReviews(AnimeID, ForceRefresh); + cmd.Save(); + } + + // Request an image download + + } + catch (Exception ex) + { + logger.Error("Error processing CommandRequest_GetAnimeHTTP: {0} - {1}", AnimeID, ex.ToString()); + return; + } + } + + public override void GenerateCommandID() + { + this.CommandID = string.Format("CommandRequest_GetAnimeHTTP_{0}", this.AnimeID); + } + + public override bool LoadFromDBCommand(CommandRequest cq) + { + this.CommandID = cq.CommandID; + this.CommandRequestID = cq.CommandRequestID; + this.CommandType = cq.CommandType; + this.Priority = cq.Priority; + this.CommandDetails = cq.CommandDetails; + this.DateTimeUpdated = cq.DateTimeUpdated; + + // read xml to get parameters + if (this.CommandDetails.Trim().Length > 0) + { + XmlDocument docCreator = new XmlDocument(); + docCreator.LoadXml(this.CommandDetails); + + // populate the fields + this.AnimeID = int.Parse(TryGetProperty(docCreator, "CommandRequest_GetAnimeHTTP", "AnimeID")); + this.DownloadRelations = bool.Parse(TryGetProperty(docCreator, "CommandRequest_GetAnimeHTTP", "DownloadRelations")); + this.ForceRefresh = bool.Parse(TryGetProperty(docCreator, "CommandRequest_GetAnimeHTTP", "ForceRefresh")); + } + + return true; + } + + public override CommandRequest ToDatabaseObject() + { + GenerateCommandID(); + + CommandRequest cq = new CommandRequest(); + cq.CommandID = this.CommandID; + cq.CommandType = this.CommandType; + cq.Priority = this.Priority; + cq.CommandDetails = this.ToXML(); + cq.DateTimeUpdated = DateTime.Now; + + return cq; + } + } +} diff --git a/JMMServer/Commands/AniDB/CommandRequest_GetCalendar.cs b/JMMServer/Commands/AniDB/CommandRequest_GetCalendar.cs new file mode 100644 index 000000000..e895d934a --- /dev/null +++ b/JMMServer/Commands/AniDB/CommandRequest_GetCalendar.cs @@ -0,0 +1,152 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Repositories; +using JMMServer.Entities; +using System.Xml; +using AniDBAPI.Commands; +using AniDBAPI; + +namespace JMMServer.Commands +{ + [Serializable] + public class CommandRequest_GetCalendar : CommandRequestImplementation, ICommandRequest + { + public bool ForceRefresh { get; set; } + + public CommandRequestPriority DefaultPriority + { + get { return CommandRequestPriority.Priority7; } + } + + public string PrettyDescription + { + get + { + return string.Format("Getting calendar info from UDP API"); + } + } + + public CommandRequest_GetCalendar() + { + } + + public CommandRequest_GetCalendar(bool forced) + { + this.ForceRefresh = forced; + this.CommandType = (int)CommandRequestType.AniDB_GetCalendar; + this.Priority = (int)DefaultPriority; + + GenerateCommandID(); + } + + public override void ProcessCommand() + { + logger.Info("Processing CommandRequest_GetCalendar"); + + try + { + // we will always assume that an anime was downloaded via http first + ScheduledUpdateRepository repSched = new ScheduledUpdateRepository(); + AniDB_AnimeRepository repAnime = new AniDB_AnimeRepository(); + + ScheduledUpdate sched = repSched.GetByUpdateType((int)ScheduledUpdateType.AniDBCalendar); + if (sched == null) + { + sched = new ScheduledUpdate(); + sched.UpdateType = (int)ScheduledUpdateType.AniDBCalendar; + sched.UpdateDetails = ""; + } + else + { + int freqHours = Utils.GetScheduledHours(ServerSettings.AniDB_Calendar_UpdateFrequency); + + // if we have run this in the last 12 hours and are not forcing it, then exit + TimeSpan tsLastRun = DateTime.Now - sched.LastUpdate; + if (tsLastRun.TotalHours < freqHours) + { + if (!ForceRefresh) return; + } + } + + sched.LastUpdate = DateTime.Now; + repSched.Save(sched); + + CalendarCollection colCalendars = JMMService.AnidbProcessor.GetCalendarUDP(); + foreach (Calendar cal in colCalendars.Calendars) + { + AniDB_Anime anime = repAnime.GetByAnimeID(cal.AnimeID); + if (anime != null) + { + // don't update if the local data is less 2 days old + TimeSpan ts = DateTime.Now - anime.DateTimeUpdated; + if (ts.TotalDays >= 2) + { + CommandRequest_GetAnimeHTTP cmdAnime = new CommandRequest_GetAnimeHTTP(cal.AnimeID, true, false); + cmdAnime.Save(); + } + else + { + // update the release date even if we don't update the anime record + anime.AirDate = cal.ReleaseDate; + repAnime.Save(anime); + + } + } + else + { + CommandRequest_GetAnimeHTTP cmdAnime = new CommandRequest_GetAnimeHTTP(cal.AnimeID, true, false); + cmdAnime.Save(); + } + } + } + catch (Exception ex) + { + logger.Error("Error processing CommandRequest_GetCalendar: {0}", ex.ToString()); + return; + } + } + + public override void GenerateCommandID() + { + this.CommandID = string.Format("CommandRequest_GetCalendar"); + } + + public override bool LoadFromDBCommand(CommandRequest cq) + { + this.CommandID = cq.CommandID; + this.CommandRequestID = cq.CommandRequestID; + this.CommandType = cq.CommandType; + this.Priority = cq.Priority; + this.CommandDetails = cq.CommandDetails; + this.DateTimeUpdated = cq.DateTimeUpdated; + + // read xml to get parameters + if (this.CommandDetails.Trim().Length > 0) + { + XmlDocument docCreator = new XmlDocument(); + docCreator.LoadXml(this.CommandDetails); + + // populate the fields + this.ForceRefresh = bool.Parse(TryGetProperty(docCreator, "CommandRequest_GetCalendar", "ForceRefresh")); + } + + return true; + } + + public override CommandRequest ToDatabaseObject() + { + GenerateCommandID(); + + CommandRequest cq = new CommandRequest(); + cq.CommandID = this.CommandID; + cq.CommandType = this.CommandType; + cq.Priority = this.Priority; + cq.CommandDetails = this.ToXML(); + cq.DateTimeUpdated = DateTime.Now; + + return cq; + } + } +} diff --git a/JMMServer/Commands/AniDB/CommandRequest_GetCharacter.cs b/JMMServer/Commands/AniDB/CommandRequest_GetCharacter.cs new file mode 100644 index 000000000..77918f3ec --- /dev/null +++ b/JMMServer/Commands/AniDB/CommandRequest_GetCharacter.cs @@ -0,0 +1,109 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Repositories; +using JMMServer.Entities; +using System.Xml; + +namespace JMMServer.Commands +{ + [Serializable] + public class CommandRequest_GetCharacter : CommandRequestImplementation, ICommandRequest + { + public int CharID { get; set; } + public bool ForceRefresh { get; set; } + + public CommandRequestPriority DefaultPriority + { + get { return CommandRequestPriority.Priority9; } + } + + public string PrettyDescription + { + get + { + return string.Format("Getting character info from UDP API: {0}", CharID); + } + } + + public CommandRequest_GetCharacter() + { + } + + public CommandRequest_GetCharacter(int charid, bool forced) + { + this.CharID = charid; + this.ForceRefresh = forced; + this.CommandType = (int)CommandRequestType.AniDB_GetCharacter; + this.Priority = (int)DefaultPriority; + + GenerateCommandID(); + } + + public override void ProcessCommand() + { + logger.Info("Processing CommandRequest_GetCharacter: {0}", CharID); + + try + { + AniDB_CharacterRepository repChar = new AniDB_CharacterRepository(); + AniDB_Character chr = repChar.GetByCharID(CharID); + + if (ForceRefresh || chr == null) + { + // redownload anime details from http ap so we can get an update character list + chr = JMMService.AnidbProcessor.GetCharacterInfoUDP(CharID); + } + + } + catch (Exception ex) + { + logger.Error("Error processing CommandRequest_GetCharacter: {0} - {1}", CharID, ex.ToString()); + return; + } + } + + public override void GenerateCommandID() + { + this.CommandID = string.Format("CommandRequest_GetCharacter_{0}", this.CharID); + } + + public override bool LoadFromDBCommand(CommandRequest cq) + { + this.CommandID = cq.CommandID; + this.CommandRequestID = cq.CommandRequestID; + this.CommandType = cq.CommandType; + this.Priority = cq.Priority; + this.CommandDetails = cq.CommandDetails; + this.DateTimeUpdated = cq.DateTimeUpdated; + + // read xml to get parameters + if (this.CommandDetails.Trim().Length > 0) + { + XmlDocument docCreator = new XmlDocument(); + docCreator.LoadXml(this.CommandDetails); + + // populate the fields + this.CharID = int.Parse(TryGetProperty(docCreator, "CommandRequest_GetCharacter", "CharID")); + this.ForceRefresh = bool.Parse(TryGetProperty(docCreator, "CommandRequest_GetCharacter", "ForceRefresh")); + } + + return true; + } + + public override CommandRequest ToDatabaseObject() + { + GenerateCommandID(); + + CommandRequest cq = new CommandRequest(); + cq.CommandID = this.CommandID; + cq.CommandType = this.CommandType; + cq.Priority = this.Priority; + cq.CommandDetails = this.ToXML(); + cq.DateTimeUpdated = DateTime.Now; + + return cq; + } + } +} diff --git a/JMMServer/Commands/AniDB/CommandRequest_GetCharactersCreators.cs b/JMMServer/Commands/AniDB/CommandRequest_GetCharactersCreators.cs new file mode 100644 index 000000000..45a1797d5 --- /dev/null +++ b/JMMServer/Commands/AniDB/CommandRequest_GetCharactersCreators.cs @@ -0,0 +1,129 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Entities; +using System.Xml; +using JMMServer.Repositories; + +namespace JMMServer.Commands +{ + [Serializable] + public class CommandRequest_GetCharactersCreators : CommandRequestImplementation, ICommandRequest + { + public int AnimeID { get; set; } + public bool ForceRefresh { get; set; } + + public CommandRequestPriority DefaultPriority + { + get { return CommandRequestPriority.Priority8; } + } + + public string PrettyDescription + { + get + { + return string.Format("Getting character and creator info from UDP API for Anime: {0}", AnimeID); + } + } + + public CommandRequest_GetCharactersCreators() + { + } + + public CommandRequest_GetCharactersCreators(int animeid, bool forced) + { + this.AnimeID = animeid; + this.ForceRefresh = forced; + this.CommandType = (int)CommandRequestType.AniDB_GetCharsCreators; + this.Priority = (int)DefaultPriority; + + GenerateCommandID(); + } + + public override void ProcessCommand() + { + logger.Info("Processing CommandRequest_GetCharactersCreators: {0}", AnimeID); + + try + { + AniDB_AnimeRepository repAnime = new AniDB_AnimeRepository(); + AniDB_Character_CreatorRepository repCharCreators = new AniDB_Character_CreatorRepository(); + AniDB_Anime anime = null; + + if (ForceRefresh) + { + // redownload anime details from http ap so we can get an update character list + anime = JMMService.AnidbProcessor.GetAnimeInfoHTTP(AnimeID, false, false); + } + else + anime = repAnime.GetByAnimeID(AnimeID); + + if (anime == null) return; + + foreach (AniDB_Anime_Character animeChar in anime.AnimeCharacters) + { + //MainWindow.anidbProcessor.UpdateCharacterInfo(charref.CharID, false); + //logger.Trace("Downloading char info: {0}", animeChar.CharID); + CommandRequest_GetCharacter cmdChar = new CommandRequest_GetCharacter(animeChar.CharID, ForceRefresh); + cmdChar.Save(); + + // for each of the creators for this character + foreach (AniDB_Character_Creator aac in repCharCreators.GetByCharID(animeChar.CharID)) + { + CommandRequest_GetCreator cmdCreators = new CommandRequest_GetCreator(aac.CreatorID, ForceRefresh); + cmdCreators.Save(); + } + } + + } + catch (Exception ex) + { + logger.Error("Error processing CommandRequest_GetCharactersCreators: {0} - {1}", AnimeID, ex.ToString()); + return; + } + } + + public override void GenerateCommandID() + { + this.CommandID = string.Format("CommandRequest_GetCharactersCreators_{0}", this.AnimeID); + } + + public override bool LoadFromDBCommand(CommandRequest cq) + { + this.CommandID = cq.CommandID; + this.CommandRequestID = cq.CommandRequestID; + this.CommandType = cq.CommandType; + this.Priority = cq.Priority; + this.CommandDetails = cq.CommandDetails; + this.DateTimeUpdated = cq.DateTimeUpdated; + + // read xml to get parameters + if (this.CommandDetails.Trim().Length > 0) + { + XmlDocument docCreator = new XmlDocument(); + docCreator.LoadXml(this.CommandDetails); + + // populate the fields + this.AnimeID = int.Parse(TryGetProperty(docCreator, "CommandRequest_GetCharactersCreators", "AnimeID")); + this.ForceRefresh = bool.Parse(TryGetProperty(docCreator, "CommandRequest_GetCharactersCreators", "ForceRefresh")); + } + + return true; + } + + public override CommandRequest ToDatabaseObject() + { + GenerateCommandID(); + + CommandRequest cq = new CommandRequest(); + cq.CommandID = this.CommandID; + cq.CommandType = this.CommandType; + cq.Priority = this.Priority; + cq.CommandDetails = this.ToXML(); + cq.DateTimeUpdated = DateTime.Now; + + return cq; + } + } +} diff --git a/JMMServer/Commands/AniDB/CommandRequest_GetCreator.cs b/JMMServer/Commands/AniDB/CommandRequest_GetCreator.cs new file mode 100644 index 000000000..9596876a0 --- /dev/null +++ b/JMMServer/Commands/AniDB/CommandRequest_GetCreator.cs @@ -0,0 +1,109 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Repositories; +using JMMServer.Entities; +using System.Xml; + +namespace JMMServer.Commands +{ + [Serializable] + public class CommandRequest_GetCreator : CommandRequestImplementation, ICommandRequest + { + public int CreatorID { get; set; } + public bool ForceRefresh { get; set; } + + public CommandRequestPriority DefaultPriority + { + get { return CommandRequestPriority.Priority9; } + } + + public string PrettyDescription + { + get + { + return string.Format("Getting creator info from UDP API: {0}", CreatorID); + } + } + + public CommandRequest_GetCreator() + { + } + + public CommandRequest_GetCreator(int cid, bool forced) + { + this.CreatorID = cid; + this.ForceRefresh = forced; + this.CommandType = (int)CommandRequestType.AniDB_GetCreator; + this.Priority = (int)DefaultPriority; + + GenerateCommandID(); + } + + public override void ProcessCommand() + { + logger.Info("Processing CommandRequest_GetCreator: {0}", CreatorID); + + try + { + AniDB_CreatorRepository repCreator = new AniDB_CreatorRepository(); + AniDB_Creator creator = repCreator.GetByCreatorID(CreatorID); + + if (ForceRefresh || creator == null) + { + // redownload anime details from http ap so we can get an update character list + creator = JMMService.AnidbProcessor.GetCreatorInfoUDP(CreatorID); + } + + } + catch (Exception ex) + { + logger.Error("Error processing CommandRequest_GetCreator: {0} - {1}", CreatorID, ex.ToString()); + return; + } + } + + public override void GenerateCommandID() + { + this.CommandID = string.Format("CommandRequest_GetCreator_{0}", this.CreatorID); + } + + public override bool LoadFromDBCommand(CommandRequest cq) + { + this.CommandID = cq.CommandID; + this.CommandRequestID = cq.CommandRequestID; + this.CommandType = cq.CommandType; + this.Priority = cq.Priority; + this.CommandDetails = cq.CommandDetails; + this.DateTimeUpdated = cq.DateTimeUpdated; + + // read xml to get parameters + if (this.CommandDetails.Trim().Length > 0) + { + XmlDocument docCreator = new XmlDocument(); + docCreator.LoadXml(this.CommandDetails); + + // populate the fields + this.CreatorID = int.Parse(TryGetProperty(docCreator, "CommandRequest_GetCreator", "CreatorID")); + this.ForceRefresh = bool.Parse(TryGetProperty(docCreator, "CommandRequest_GetCreator", "ForceRefresh")); + } + + return true; + } + + public override CommandRequest ToDatabaseObject() + { + GenerateCommandID(); + + CommandRequest cq = new CommandRequest(); + cq.CommandID = this.CommandID; + cq.CommandType = this.CommandType; + cq.Priority = this.Priority; + cq.CommandDetails = this.ToXML(); + cq.DateTimeUpdated = DateTime.Now; + + return cq; + } + } +} diff --git a/JMMServer/Commands/AniDB/CommandRequest_GetFile.cs b/JMMServer/Commands/AniDB/CommandRequest_GetFile.cs new file mode 100644 index 000000000..ee0155c92 --- /dev/null +++ b/JMMServer/Commands/AniDB/CommandRequest_GetFile.cs @@ -0,0 +1,136 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Entities; +using System.IO; +using JMMServer.Repositories; +using JMMContracts; +using JMMFileHelper; +using AniDBAPI; +using System.Xml; +using JMMServer.WebCache; + +namespace JMMServer.Commands +{ + [Serializable] + public class CommandRequest_GetFile : CommandRequestImplementation, ICommandRequest + { + public int VideoLocalID { get; set; } + private VideoLocal vlocal = null; + + public CommandRequestPriority DefaultPriority + { + get { return CommandRequestPriority.Priority3; } + } + + public string PrettyDescription + { + get + { + if (vlocal != null) + return string.Format("Getting file info from UDP API: {0}", vlocal.FullServerPath); + else + return string.Format("Getting file info from UDP API: {0}", VideoLocalID); + } + } + + public CommandRequest_GetFile() + { + } + + public CommandRequest_GetFile(int vidLocalID) + { + this.VideoLocalID = vidLocalID; + this.CommandType = (int)CommandRequestType.AniDB_GetFileUDP; + this.Priority = (int)DefaultPriority; + + GenerateCommandID(); + } + + public override void ProcessCommand() + { + logger.Info("Get AniDB file info: {0}", VideoLocalID); + + + try + { + AniDB_FileRepository repAniFile = new AniDB_FileRepository(); + VideoLocalRepository repVids = new VideoLocalRepository(); + vlocal = repVids.GetByID(VideoLocalID); + if (vlocal == null) return; + + AniDB_File aniFile = repAniFile.GetByHash(vlocal.Hash); + + Raw_AniDB_File fileInfo = JMMService.AnidbProcessor.GetFileInfo(vlocal); + if (fileInfo != null) + { + // save to the database + if (aniFile == null) + aniFile = new AniDB_File(); + + aniFile.Populate(fileInfo); + + //overwrite with local file name + string localFileName = Path.GetFileName(vlocal.FilePath); + aniFile.FileName = localFileName; + + repAniFile.Save(aniFile); + aniFile.CreateLanguages(); + aniFile.CreateCrossEpisodes(localFileName); + } + + } + catch (Exception ex) + { + logger.Error("Error processing CommandRequest_GetFile: {0} - {1}", VideoLocalID, ex.ToString()); + return; + } + } + + /// + /// This should generate a unique key for a command + /// It will be used to check whether the command has already been queued before adding it + /// + public override void GenerateCommandID() + { + this.CommandID = string.Format("CommandRequest_GetFile_{0}", this.VideoLocalID); + } + + public override bool LoadFromDBCommand(CommandRequest cq) + { + this.CommandID = cq.CommandID; + this.CommandRequestID = cq.CommandRequestID; + this.CommandType = cq.CommandType; + this.Priority = cq.Priority; + this.CommandDetails = cq.CommandDetails; + this.DateTimeUpdated = cq.DateTimeUpdated; + + // read xml to get parameters + if (this.CommandDetails.Trim().Length > 0) + { + XmlDocument docCreator = new XmlDocument(); + docCreator.LoadXml(this.CommandDetails); + + // populate the fields + this.VideoLocalID = int.Parse(TryGetProperty(docCreator, "CommandRequest_GetFile", "VideoLocalID")); + } + + return true; + } + + public override CommandRequest ToDatabaseObject() + { + GenerateCommandID(); + + CommandRequest cq = new CommandRequest(); + cq.CommandID = this.CommandID; + cq.CommandType = this.CommandType; + cq.Priority = this.Priority; + cq.CommandDetails = this.ToXML(); + cq.DateTimeUpdated = DateTime.Now; + + return cq; + } + } +} diff --git a/JMMServer/Commands/AniDB/CommandRequest_GetReleaseGroup.cs b/JMMServer/Commands/AniDB/CommandRequest_GetReleaseGroup.cs new file mode 100644 index 000000000..269b61d2a --- /dev/null +++ b/JMMServer/Commands/AniDB/CommandRequest_GetReleaseGroup.cs @@ -0,0 +1,109 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Repositories; +using JMMServer.Entities; +using System.Xml; + +namespace JMMServer.Commands +{ + [Serializable] + public class CommandRequest_GetReleaseGroup : CommandRequestImplementation, ICommandRequest + { + public int GroupID { get; set; } + public bool ForceRefresh { get; set; } + + public CommandRequestPriority DefaultPriority + { + get { return CommandRequestPriority.Priority9; } + } + + public string PrettyDescription + { + get + { + return string.Format("Getting release group info from UDP API: {0}", GroupID); + } + } + + public CommandRequest_GetReleaseGroup() + { + } + + public CommandRequest_GetReleaseGroup(int grpid, bool forced) + { + this.GroupID = grpid; + this.ForceRefresh = forced; + this.CommandType = (int)CommandRequestType.AniDB_GetReleaseGroup; + this.Priority = (int)DefaultPriority; + + GenerateCommandID(); + } + + public override void ProcessCommand() + { + logger.Info("Processing CommandRequest_GetReleaseGroup: {0}", GroupID); + + try + { + AniDB_ReleaseGroupRepository repRelGrp = new AniDB_ReleaseGroupRepository(); + AniDB_ReleaseGroup relGroup = repRelGrp.GetByGroupID(GroupID); + + if (ForceRefresh || relGroup == null) + { + // redownload anime details from http ap so we can get an update character list + JMMService.AnidbProcessor.GetReleaseGroupUDP(GroupID); + } + + } + catch (Exception ex) + { + logger.Error("Error processing CommandRequest_GetReleaseGroup: {0} - {1}", GroupID, ex.ToString()); + return; + } + } + + public override void GenerateCommandID() + { + this.CommandID = string.Format("CommandRequest_GetReleaseGroup_{0}", this.GroupID); + } + + public override bool LoadFromDBCommand(CommandRequest cq) + { + this.CommandID = cq.CommandID; + this.CommandRequestID = cq.CommandRequestID; + this.CommandType = cq.CommandType; + this.Priority = cq.Priority; + this.CommandDetails = cq.CommandDetails; + this.DateTimeUpdated = cq.DateTimeUpdated; + + // read xml to get parameters + if (this.CommandDetails.Trim().Length > 0) + { + XmlDocument docCreator = new XmlDocument(); + docCreator.LoadXml(this.CommandDetails); + + // populate the fields + this.GroupID = int.Parse(TryGetProperty(docCreator, "CommandRequest_GetReleaseGroup", "GroupID")); + this.ForceRefresh = bool.Parse(TryGetProperty(docCreator, "CommandRequest_GetReleaseGroup", "ForceRefresh")); + } + + return true; + } + + public override CommandRequest ToDatabaseObject() + { + GenerateCommandID(); + + CommandRequest cq = new CommandRequest(); + cq.CommandID = this.CommandID; + cq.CommandType = this.CommandType; + cq.Priority = this.Priority; + cq.CommandDetails = this.ToXML(); + cq.DateTimeUpdated = DateTime.Now; + + return cq; + } + } +} diff --git a/JMMServer/Commands/AniDB/CommandRequest_GetReleaseGroupStatus.cs b/JMMServer/Commands/AniDB/CommandRequest_GetReleaseGroupStatus.cs new file mode 100644 index 000000000..885946144 --- /dev/null +++ b/JMMServer/Commands/AniDB/CommandRequest_GetReleaseGroupStatus.cs @@ -0,0 +1,153 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Repositories; +using JMMServer.Entities; +using System.Xml; +using AniDBAPI; + +namespace JMMServer.Commands +{ + [Serializable] + public class CommandRequest_GetReleaseGroupStatus : CommandRequestImplementation, ICommandRequest + { + public int AnimeID { get; set; } + public bool ForceRefresh { get; set; } + + public CommandRequestPriority DefaultPriority + { + get { return CommandRequestPriority.Priority5; } + } + + public string PrettyDescription + { + get + { + return string.Format("Getting group status info from UDP API for Anime: {0}", AnimeID); + } + } + + public CommandRequest_GetReleaseGroupStatus() + { + } + + public CommandRequest_GetReleaseGroupStatus(int aid, bool forced) + { + this.AnimeID = aid; + this.ForceRefresh = forced; + this.CommandType = (int)CommandRequestType.AniDB_GetReleaseGroupStatus; + this.Priority = (int)DefaultPriority; + + GenerateCommandID(); + } + + public override void ProcessCommand() + { + logger.Info("Processing CommandRequest_GetReleaseGroupStatus: {0}", AnimeID); + + try + { + // only get group status if we have an associated series + AnimeSeriesRepository repSeries = new AnimeSeriesRepository(); + AnimeSeries series = repSeries.GetByAnimeID(AnimeID); + if (series == null) return; + + AniDB_AnimeRepository repAnime = new AniDB_AnimeRepository(); + AniDB_Anime anime = repAnime.GetByAnimeID(AnimeID); + if (anime == null) return; + + // don't get group status if the anime has already ended more than 50 days ago + bool skip = false; + if (!ForceRefresh) + { + if (anime.EndDate.HasValue) + { + if (anime.EndDate.Value < DateTime.Now) + { + TimeSpan ts = DateTime.Now - anime.EndDate.Value; + if (ts.TotalDays > 50) + { + // don't skip if we have never downloaded this info before + AniDB_GroupStatusRepository repGrpStatus = new AniDB_GroupStatusRepository(); + List grpStatuses = repGrpStatus.GetByAnimeID(AnimeID); + if (grpStatuses != null && grpStatuses.Count > 0) + { + skip = true; + } + } + } + } + } + + if (skip) + { + logger.Info("Skipping group status command because anime has already ended: {0}", anime.ToString()); + return; + } + + GroupStatusCollection grpCol = JMMService.AnidbProcessor.GetReleaseGroupStatusUDP(AnimeID); + + if (ServerSettings.AniDB_DownloadReleaseGroups) + { + foreach (Raw_AniDB_GroupStatus grpStatus in grpCol.Groups) + { + + CommandRequest_GetReleaseGroup cmdRelgrp = new CommandRequest_GetReleaseGroup(grpStatus.GroupID, false); + cmdRelgrp.Save(); + } + } + + //} + + } + catch (Exception ex) + { + logger.Error("Error processing CommandRequest_GetReleaseGroupStatus: {0} - {1}", AnimeID, ex.ToString()); + return; + } + } + + public override void GenerateCommandID() + { + this.CommandID = string.Format("CommandRequest_GetReleaseGroupStatus_{0}", this.AnimeID); + } + + public override bool LoadFromDBCommand(CommandRequest cq) + { + this.CommandID = cq.CommandID; + this.CommandRequestID = cq.CommandRequestID; + this.CommandType = cq.CommandType; + this.Priority = cq.Priority; + this.CommandDetails = cq.CommandDetails; + this.DateTimeUpdated = cq.DateTimeUpdated; + + // read xml to get parameters + if (this.CommandDetails.Trim().Length > 0) + { + XmlDocument docCreator = new XmlDocument(); + docCreator.LoadXml(this.CommandDetails); + + // populate the fields + this.AnimeID = int.Parse(TryGetProperty(docCreator, "CommandRequest_GetReleaseGroupStatus", "AnimeID")); + this.ForceRefresh = bool.Parse(TryGetProperty(docCreator, "CommandRequest_GetReleaseGroupStatus", "ForceRefresh")); + } + + return true; + } + + public override CommandRequest ToDatabaseObject() + { + GenerateCommandID(); + + CommandRequest cq = new CommandRequest(); + cq.CommandID = this.CommandID; + cq.CommandType = this.CommandType; + cq.Priority = this.Priority; + cq.CommandDetails = this.ToXML(); + cq.DateTimeUpdated = DateTime.Now; + + return cq; + } + } +} diff --git a/JMMServer/Commands/AniDB/CommandRequest_GetReviews.cs b/JMMServer/Commands/AniDB/CommandRequest_GetReviews.cs new file mode 100644 index 000000000..b6a323998 --- /dev/null +++ b/JMMServer/Commands/AniDB/CommandRequest_GetReviews.cs @@ -0,0 +1,117 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Repositories; +using JMMServer.Entities; +using System.Xml; + +namespace JMMServer.Commands +{ + [Serializable] + public class CommandRequest_GetReviews : CommandRequestImplementation, ICommandRequest + { + public int AnimeID { get; set; } + public bool ForceRefresh { get; set; } + + public CommandRequestPriority DefaultPriority + { + get { return CommandRequestPriority.Priority9; } + } + + public string PrettyDescription + { + get + { + return string.Format("Getting review info from UDP API for Anime: {0}", AnimeID); + } + } + + public CommandRequest_GetReviews() + { + } + + public CommandRequest_GetReviews(int animeid, bool forced) + { + this.AnimeID = animeid; + this.ForceRefresh = forced; + this.CommandType = (int)CommandRequestType.AniDB_GetReviews; + this.Priority = (int)DefaultPriority; + + GenerateCommandID(); + } + + public override void ProcessCommand() + { + logger.Info("Processing CommandRequest_GetReviews: {0}", AnimeID); + + try + { + // we will always assume that an anime was downloaded via http first + AniDB_AnimeRepository repAnime = new AniDB_AnimeRepository(); + AniDB_Anime anime = repAnime.GetByAnimeID(AnimeID); + + if (anime != null) + { + // reviews count will be 0 when the anime is only downloaded via HTTP + if (ForceRefresh || anime.AnimeReviews.Count == 0) + anime = JMMService.AnidbProcessor.GetAnimeInfoUDP(AnimeID, true); + + foreach (AniDB_Anime_Review animeRev in anime.AnimeReviews) + { + JMMService.AnidbProcessor.GetReviewUDP(animeRev.ReviewID); + } + + } + + } + catch (Exception ex) + { + logger.Error("Error processing CommandRequest_GetReviews: {0} - {1}", AnimeID, ex.ToString()); + return; + } + } + + public override void GenerateCommandID() + { + this.CommandID = string.Format("CommandRequest_GetReviews_{0}", this.AnimeID); + } + + public override bool LoadFromDBCommand(CommandRequest cq) + { + this.CommandID = cq.CommandID; + this.CommandRequestID = cq.CommandRequestID; + this.CommandType = cq.CommandType; + this.Priority = cq.Priority; + this.CommandDetails = cq.CommandDetails; + this.DateTimeUpdated = cq.DateTimeUpdated; + + // read xml to get parameters + if (this.CommandDetails.Trim().Length > 0) + { + XmlDocument docCreator = new XmlDocument(); + docCreator.LoadXml(this.CommandDetails); + + // populate the fields + this.AnimeID = int.Parse(TryGetProperty(docCreator, "CommandRequest_GetReviews", "AnimeID")); + this.ForceRefresh = bool.Parse(TryGetProperty(docCreator, "CommandRequest_GetReviews", "ForceRefresh")); + } + + return true; + } + + public override CommandRequest ToDatabaseObject() + { + GenerateCommandID(); + + CommandRequest cq = new CommandRequest(); + cq.CommandID = this.CommandID; + cq.CommandType = this.CommandType; + cq.Priority = this.Priority; + cq.CommandDetails = this.ToXML(); + cq.DateTimeUpdated = DateTime.Now; + + return cq; + } + } +} diff --git a/JMMServer/Commands/AniDB/CommandRequest_GetUpdated.cs b/JMMServer/Commands/AniDB/CommandRequest_GetUpdated.cs new file mode 100644 index 000000000..0e5fc46c0 --- /dev/null +++ b/JMMServer/Commands/AniDB/CommandRequest_GetUpdated.cs @@ -0,0 +1,205 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Repositories; +using JMMServer.Entities; +using System.Xml; +using JMMServer.AniDB_API; +using JMMServer.WebCache; + +namespace JMMServer.Commands +{ + [Serializable] + public class CommandRequest_GetUpdated : CommandRequestImplementation, ICommandRequest + { + public bool ForceRefresh { get; set; } + + public CommandRequestPriority DefaultPriority + { + get { return CommandRequestPriority.Priority4; } + } + + public string PrettyDescription + { + get + { + return string.Format("Getting list of updated animes from UDP API"); + } + } + + public CommandRequest_GetUpdated() + { + } + + public CommandRequest_GetUpdated(bool forced) + { + this.ForceRefresh = forced; + this.CommandType = (int)CommandRequestType.AniDB_GetUpdated; + this.Priority = (int)DefaultPriority; + + GenerateCommandID(); + } + + public override void ProcessCommand() + { + logger.Info("Processing CommandRequest_GetUpdated"); + + try + { + List animeIDsToUpdate = new List(); + ScheduledUpdateRepository repSched = new ScheduledUpdateRepository(); + AnimeSeriesRepository repSeries = new AnimeSeriesRepository(); + AniDB_AnimeRepository repAnime = new AniDB_AnimeRepository(); + + //DateTime localTime = DateTime.Now.AddDays(-30); + + long startTime = 0; + + + // check the automated update table to see when the last time we ran this command + ScheduledUpdate sched = repSched.GetByUpdateType((int)ScheduledUpdateType.AniDBUpdates); + if (sched != null) + { + int freqHours = Utils.GetScheduledHours(ServerSettings.AniDB_Anime_UpdateFrequency); + + // if we have run this in the last 12 hours and are not forcing it, then exit + TimeSpan tsLastRun = DateTime.Now - sched.LastUpdate; + if (tsLastRun.TotalHours < freqHours) + { + if (!ForceRefresh) return; + } + } + + // get a list of updates in the last day from AniDB + // startTime will contain the date/time from which the updates apply to + if (!JMMService.AnidbProcessor.GetUpdated(ref animeIDsToUpdate, ref startTime)) return; + + long webUpdateTime = 0; + if (sched == null) + { + // if this is the first time, lets ask web cache for everyting in the last 3 days + DateTime localTime = DateTime.Now.AddDays(-3); + DateTime utcTime = localTime.ToUniversalTime(); + webUpdateTime = long.Parse(Utils.AniDBDate(utcTime)); + + sched = new ScheduledUpdate(); + sched.UpdateType = (int)ScheduledUpdateType.AniDBUpdates; + } + else + { + logger.Trace("Last anidb info update was : {0}", sched.UpdateDetails); + webUpdateTime = long.Parse(sched.UpdateDetails); + } + + // now save the update time from AniDB + // we will use this next time as a starting point when querying the web cache + sched.LastUpdate = DateTime.Now; + sched.UpdateDetails = startTime.ToString(); + repSched.Save(sched); + + // we now have a listof updates in the last 24 hours + // get more from the web cache + UpdatesCollection colUpdates = XMLService.Get_AniDBUpdates(webUpdateTime); + // get a unqiue list of anime id's + if (colUpdates != null) + { + logger.Info("Web cache updates : Time={0} - Count={1} - List={2}", webUpdateTime, colUpdates.UpdateCount, colUpdates.RawAnimeIDs); + foreach (int id in colUpdates.AnimeIDs) + { + if (!animeIDsToUpdate.Contains(id)) animeIDsToUpdate.Add(id); + } + } + else + { + logger.Info("No web Web cache updates"); + } + + int countAnime = 0; + int countSeries = 0; + foreach (int animeID in animeIDsToUpdate) + { + // update the anime from HTTP + AniDB_Anime anime = repAnime.GetByAnimeID(animeID); + if (anime == null) + { + logger.Trace("No local record found for Anime ID: {0}, so skipping...", animeID); + continue; + } + + logger.Info("Updating CommandRequest_GetUpdated: {0} ", animeID); + + // but only if it hasn't been recently updated + TimeSpan ts = DateTime.Now - anime.DateTimeUpdated; + if (ts.TotalHours > 4) + { + CommandRequest_GetAnimeHTTP cmdAnime = new CommandRequest_GetAnimeHTTP(animeID, true, false); + cmdAnime.Save(); + countAnime++; + } + + // update the group status + // this will allow us to determine which anime has missing episodes + // so we wonly get by an amime where we also have an associated series + AnimeSeries ser = repSeries.GetByAnimeID(animeID); + if (ser != null) + { + CommandRequest_GetReleaseGroupStatus cmdStatus = new CommandRequest_GetReleaseGroupStatus(animeID, true); + cmdStatus.Save(); + countSeries++; + } + + } + + logger.Info("Updating {0} anime records, and {1} group status records", countAnime, countSeries); + + } + catch (Exception ex) + { + logger.Error("Error processing CommandRequest_GetUpdated: {0}", ex.ToString()); + return; + } + } + + public override void GenerateCommandID() + { + this.CommandID = string.Format("CommandRequest_GetUpdated"); + } + + public override bool LoadFromDBCommand(CommandRequest cq) + { + this.CommandID = cq.CommandID; + this.CommandRequestID = cq.CommandRequestID; + this.CommandType = cq.CommandType; + this.Priority = cq.Priority; + this.CommandDetails = cq.CommandDetails; + this.DateTimeUpdated = cq.DateTimeUpdated; + + // read xml to get parameters + if (this.CommandDetails.Trim().Length > 0) + { + XmlDocument docCreator = new XmlDocument(); + docCreator.LoadXml(this.CommandDetails); + + // populate the fields + this.ForceRefresh = bool.Parse(TryGetProperty(docCreator, "CommandRequest_GetUpdated", "ForceRefresh")); + } + + return true; + } + + public override CommandRequest ToDatabaseObject() + { + GenerateCommandID(); + + CommandRequest cq = new CommandRequest(); + cq.CommandID = this.CommandID; + cq.CommandType = this.CommandType; + cq.Priority = this.Priority; + cq.CommandDetails = this.ToXML(); + cq.DateTimeUpdated = DateTime.Now; + + return cq; + } + } +} diff --git a/JMMServer/Commands/AniDB/CommandRequest_SyncMyList.cs b/JMMServer/Commands/AniDB/CommandRequest_SyncMyList.cs new file mode 100644 index 000000000..6eeea5881 --- /dev/null +++ b/JMMServer/Commands/AniDB/CommandRequest_SyncMyList.cs @@ -0,0 +1,244 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Repositories; +using JMMServer.Entities; +using System.Xml; +using AniDBAPI.Commands; +using AniDBAPI; + +namespace JMMServer.Commands +{ + [Serializable] + public class CommandRequest_SyncMyList : CommandRequestImplementation, ICommandRequest + { + public bool ForceRefresh { get; set; } + + public CommandRequestPriority DefaultPriority + { + get { return CommandRequestPriority.Priority6; } + } + + public string PrettyDescription + { + get + { + return string.Format("Syncing MyList info from HTTP API"); + } + } + + public CommandRequest_SyncMyList() + { + } + + public CommandRequest_SyncMyList(bool forced) + { + this.ForceRefresh = forced; + this.CommandType = (int)CommandRequestType.AniDB_SyncMyList; + this.Priority = (int)DefaultPriority; + + GenerateCommandID(); + } + + 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) + { + 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 onlineFiles = new Dictionary(); + foreach (Raw_AniDB_MyListFile myitem in cmd.MyListItems) + onlineFiles[myitem.FileID] = myitem; + + Dictionary dictAniFiles = new Dictionary(); + List 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 aniDBUsers = repUsers.GetAniDBUsers(); + + VideoLocal_UserRepository repVidUsers = new VideoLocal_UserRepository(); + + // 1 . sync mylist items + foreach (Raw_AniDB_MyListFile myitem in cmd.MyListItems) + { + totalItems++; + if (myitem.IsWatched) watchedItems++; + + //calculate percentage + pct = (double)totalItems / (double)cmd.MyListItems.Count * (double)100; + string spct = pct.ToString("#0.0"); + + AniDB_File anifile = repAniFile.GetByFileID(myitem.FileID); + if (anifile != null) + { + // find the video associated with this record + VideoLocal vl = repVidLocals.GetByHash(anifile.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, jmmUserID.Value); + 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, jmmUserID.Value); + 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 GenerateCommandID() + { + this.CommandID = string.Format("CommandRequest_SyncMyList"); + } + + public override bool LoadFromDBCommand(CommandRequest cq) + { + this.CommandID = cq.CommandID; + this.CommandRequestID = cq.CommandRequestID; + this.CommandType = cq.CommandType; + this.Priority = cq.Priority; + this.CommandDetails = cq.CommandDetails; + this.DateTimeUpdated = cq.DateTimeUpdated; + + // read xml to get parameters + if (this.CommandDetails.Trim().Length > 0) + { + XmlDocument docCreator = new XmlDocument(); + docCreator.LoadXml(this.CommandDetails); + + // populate the fields + this.ForceRefresh = bool.Parse(TryGetProperty(docCreator, "CommandRequest_SyncMyList", "ForceRefresh")); + } + + return true; + } + + public override CommandRequest ToDatabaseObject() + { + GenerateCommandID(); + + CommandRequest cq = new CommandRequest(); + cq.CommandID = this.CommandID; + cq.CommandType = this.CommandType; + cq.Priority = this.Priority; + cq.CommandDetails = this.ToXML(); + cq.DateTimeUpdated = DateTime.Now; + + return cq; + } + } +} diff --git a/JMMServer/Commands/AniDB/CommandRequest_SyncMyVotes.cs b/JMMServer/Commands/AniDB/CommandRequest_SyncMyVotes.cs new file mode 100644 index 000000000..4628c5b69 --- /dev/null +++ b/JMMServer/Commands/AniDB/CommandRequest_SyncMyVotes.cs @@ -0,0 +1,133 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Repositories; +using JMMServer.Entities; +using System.Xml; +using AniDBAPI.Commands; +using AniDBAPI; +using JMMServer.AniDB_API.Commands; +using JMMServer.AniDB_API.Raws; + +namespace JMMServer.Commands +{ + [Serializable] + public class CommandRequest_SyncMyVotes : CommandRequestImplementation, ICommandRequest + { + public CommandRequestPriority DefaultPriority + { + get { return CommandRequestPriority.Priority9; } + } + + public string PrettyDescription + { + get + { + return string.Format("Syncing Vote info from HTTP API"); + } + } + + + public CommandRequest_SyncMyVotes() + { + this.CommandType = (int)CommandRequestType.AniDB_SyncVotes; + this.Priority = (int)DefaultPriority; + + GenerateCommandID(); + } + + public override void ProcessCommand() + { + logger.Info("Processing CommandRequest_SyncMyVotes"); + + try + { + AniDB_VoteRepository repVotes = new AniDB_VoteRepository(); + + AniDBHTTPCommand_GetVotes cmd = new AniDBHTTPCommand_GetVotes(); + cmd.Init(ServerSettings.AniDB_Username, ServerSettings.AniDB_Password); + enHelperActivityType ev = cmd.Process(); + if (ev == enHelperActivityType.GotVotesHTTP) + { + foreach (Raw_AniDB_Vote_HTTP myVote in cmd.MyVotes) + { + List dbVotes = repVotes.GetByEntity(myVote.EntityID); + AniDB_Vote thisVote = null; + foreach (AniDB_Vote dbVote in dbVotes) + { + // we can only have anime permanent or anime temp but not both + if (myVote.VoteType == enAniDBVoteType.Anime || myVote.VoteType == enAniDBVoteType.AnimeTemp) + { + if (dbVote.VoteType == (int)enAniDBVoteType.Anime || dbVote.VoteType == (int)enAniDBVoteType.AnimeTemp) + { + thisVote = dbVote; + } + } + else + { + thisVote = dbVote; + } + } + + if (thisVote == null) + { + thisVote = new AniDB_Vote(); + thisVote.EntityID = myVote.EntityID; + } + thisVote.VoteType = (int)myVote.VoteType; + thisVote.VoteValue = myVote.VoteValue; + repVotes.Save(thisVote); + + } + + logger.Info("Processed Votes: {0} Items", cmd.MyVotes.Count); + } + } + catch (Exception ex) + { + logger.Error("Error processing CommandRequest_SyncMyVotes: {0} ", ex.ToString()); + return; + } + } + + public override void GenerateCommandID() + { + this.CommandID = string.Format("CommandRequest_SyncMyVotes"); + } + + public override bool LoadFromDBCommand(CommandRequest cq) + { + this.CommandID = cq.CommandID; + this.CommandRequestID = cq.CommandRequestID; + this.CommandType = cq.CommandType; + this.Priority = cq.Priority; + this.CommandDetails = cq.CommandDetails; + this.DateTimeUpdated = cq.DateTimeUpdated; + + // read xml to get parameters + if (this.CommandDetails.Trim().Length > 0) + { + XmlDocument docCreator = new XmlDocument(); + docCreator.LoadXml(this.CommandDetails); + + } + + return true; + } + + public override CommandRequest ToDatabaseObject() + { + GenerateCommandID(); + + CommandRequest cq = new CommandRequest(); + cq.CommandID = this.CommandID; + cq.CommandType = this.CommandType; + cq.Priority = this.Priority; + cq.CommandDetails = this.ToXML(); + cq.DateTimeUpdated = DateTime.Now; + + return cq; + } + } +} diff --git a/JMMServer/Commands/AniDB/CommandRequest_UpdateMyListFileStatus.cs b/JMMServer/Commands/AniDB/CommandRequest_UpdateMyListFileStatus.cs new file mode 100644 index 000000000..05340fb56 --- /dev/null +++ b/JMMServer/Commands/AniDB/CommandRequest_UpdateMyListFileStatus.cs @@ -0,0 +1,131 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Entities; +using System.Xml; +using JMMServer.Repositories; + +namespace JMMServer.Commands +{ + [Serializable] + public class CommandRequest_UpdateMyListFileStatus : CommandRequestImplementation, ICommandRequest + { + public string FullFileName { get; set; } + public string Hash { get; set; } + public bool Watched { get; set; } + + public CommandRequestPriority DefaultPriority + { + get { return CommandRequestPriority.Priority8; } + } + + public string PrettyDescription + { + get + { + return string.Format("Updating MyList info from UDP API for File: {0}", FullFileName); + } + } + + public CommandRequest_UpdateMyListFileStatus() + { + } + + public CommandRequest_UpdateMyListFileStatus(string hash, bool watched) + { + this.Hash = hash; + this.Watched = watched; + this.CommandType = (int)CommandRequestType.AniDB_UpdateWatchedUDP; + this.Priority = (int)DefaultPriority; + + GenerateCommandID(); + } + + public override void ProcessCommand() + { + logger.Info("Processing CommandRequest_UpdateMyListFileStatus: {0}", Hash); + + + try + { + VideoLocalRepository repVids = new VideoLocalRepository(); + AnimeEpisodeRepository repEpisodes = new AnimeEpisodeRepository(); + + // NOTE - we might return more than one VideoLocal record here, if there are duplicates by hash + VideoLocal vid = repVids.GetByHash(this.Hash); + if (vid != null) + { + JMMService.AnidbProcessor.UpdateMyListFileStatus(vid, this.Watched); + + logger.Info("Updating file list status: {0} - {1}", vid.ToString(), this.Watched); + + // update watched stats + List eps = repEpisodes.GetByHash(vid.ED2KHash); + if (eps.Count > 0) + { + // all the eps should belong to the same anime + eps[0].AnimeSeries.UpdateStats(true, false, true); + //eps[0].AnimeSeries.TopLevelAnimeGroup.UpdateStatsFromTopLevel(true, true, false); + } + } + + + } + catch (Exception ex) + { + logger.Error("Error processing CommandRequest_UpdateMyListFileStatus: {0} - {1}", Hash, ex.ToString()); + return; + } + } + + /// + /// This should generate a unique key for a command + /// It will be used to check whether the command has already been queued before adding it + /// + public override void GenerateCommandID() + { + this.CommandID = string.Format("CommandRequest_UpdateMyListFileStatus_{0}_{1}", Hash, Guid.NewGuid().ToString()); + } + + public override bool LoadFromDBCommand(CommandRequest cq) + { + this.CommandID = cq.CommandID; + this.CommandRequestID = cq.CommandRequestID; + this.CommandType = cq.CommandType; + this.Priority = cq.Priority; + this.CommandDetails = cq.CommandDetails; + this.DateTimeUpdated = cq.DateTimeUpdated; + + // read xml to get parameters + if (this.CommandDetails.Trim().Length > 0) + { + XmlDocument docCreator = new XmlDocument(); + docCreator.LoadXml(this.CommandDetails); + + // populate the fields + this.Hash = TryGetProperty(docCreator, "CommandRequest_UpdateMyListFileStatus", "Hash"); + this.Watched = bool.Parse(TryGetProperty(docCreator, "CommandRequest_UpdateMyListFileStatus", "Watched")); + } + + if (this.Hash.Trim().Length > 0) + return true; + else + return false; + } + + public override CommandRequest ToDatabaseObject() + { + GenerateCommandID(); + + CommandRequest cq = new CommandRequest(); + cq.CommandID = this.CommandID; + cq.CommandType = this.CommandType; + cq.Priority = this.Priority; + cq.CommandDetails = this.ToXML(); + cq.DateTimeUpdated = DateTime.Now; + + return cq; + } + } +} diff --git a/JMMServer/Commands/AniDB/CommandRequest_VoteAnime.cs b/JMMServer/Commands/AniDB/CommandRequest_VoteAnime.cs new file mode 100644 index 000000000..23c8f6188 --- /dev/null +++ b/JMMServer/Commands/AniDB/CommandRequest_VoteAnime.cs @@ -0,0 +1,109 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Repositories; +using JMMServer.Entities; +using System.Xml; + +namespace JMMServer.Commands +{ + [Serializable] + public class CommandRequest_VoteAnime : CommandRequestImplementation, ICommandRequest + { + public int AnimeID { get; set; } + public int VoteType { get; set; } + public decimal VoteValue { get; set; } + + public CommandRequestPriority DefaultPriority + { + get { return CommandRequestPriority.Priority8; } + } + + public string PrettyDescription + { + get + { + return string.Format("Voting: {0} - {1}", AnimeID, VoteValue); + } + } + + public CommandRequest_VoteAnime() + { + } + + public CommandRequest_VoteAnime(int animeID, int voteType, decimal voteValue) + { + this.AnimeID = animeID; + this.VoteType = voteType; + this.VoteValue = voteValue; + this.CommandType = (int)CommandRequestType.AniDB_VoteAnime; + this.Priority = (int)DefaultPriority; + + GenerateCommandID(); + } + + public override void ProcessCommand() + { + logger.Info("Processing CommandRequest_Vote: {0}", CommandID); + + + try + { + JMMService.AnidbProcessor.VoteAnime(AnimeID, VoteValue, (AniDBAPI.enAniDBVoteType)VoteType); + } + catch (Exception ex) + { + logger.Error("Error processing CommandRequest_Vote: {0} - {1}", CommandID, ex.ToString()); + return; + } + } + + /// + /// This should generate a unique key for a command + /// It will be used to check whether the command has already been queued before adding it + /// + public override void GenerateCommandID() + { + this.CommandID = string.Format("CommandRequest_Vote_{0}_{1}_{2}", AnimeID, (int)VoteType, VoteValue); + } + + public override bool LoadFromDBCommand(CommandRequest cq) + { + this.CommandID = cq.CommandID; + this.CommandRequestID = cq.CommandRequestID; + this.CommandType = cq.CommandType; + this.Priority = cq.Priority; + this.CommandDetails = cq.CommandDetails; + this.DateTimeUpdated = cq.DateTimeUpdated; + + // read xml to get parameters + if (this.CommandDetails.Trim().Length > 0) + { + XmlDocument docCreator = new XmlDocument(); + docCreator.LoadXml(this.CommandDetails); + + // populate the fields + this.AnimeID = int.Parse(TryGetProperty(docCreator, "CommandRequest_VoteAnime", "AnimeID")); + this.VoteType = int.Parse(TryGetProperty(docCreator, "CommandRequest_VoteAnime", "VoteType")); + this.VoteValue = decimal.Parse(TryGetProperty(docCreator, "CommandRequest_VoteAnime", "VoteValue")); + } + + return true; + } + + public override CommandRequest ToDatabaseObject() + { + GenerateCommandID(); + + CommandRequest cq = new CommandRequest(); + cq.CommandID = this.CommandID; + cq.CommandType = this.CommandType; + cq.Priority = this.Priority; + cq.CommandDetails = this.ToXML(); + cq.DateTimeUpdated = DateTime.Now; + + return cq; + } + } +} diff --git a/JMMServer/Commands/CommandHelper.cs b/JMMServer/Commands/CommandHelper.cs new file mode 100644 index 000000000..b6b8140cf --- /dev/null +++ b/JMMServer/Commands/CommandHelper.cs @@ -0,0 +1,294 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Entities; + +namespace JMMServer.Commands +{ + public class CommandHelper + { + // List of Default priorities for commands + // Pri 1 + //------ + // Reserved for commands user manually initiates from UI + //------ + // Pri 2 + //------ + // CommandRequest_GetAnimeHTTP + //------ + // Pri 3 + //------ + // CommandRequest_ProcessFile + // CommandRequest_GetFile + //------ + // Pri 4 + //------ + // CommandRequest_GetUpdated + //------ + // Pri 5 + //------ + // CommandRequest_GetReleaseGroupStatus + //------ + // Pri 6 + //------ + // CommandRequest_SyncMyList + //------ + // Pri 7 + //------ + // CommandRequest_AddFileToMyList + // CommandRequest_GetCalendar + // CommandRequest_DeleteFileFromMyList + //------ + // Pri 8 + //------ + // CommandRequest_UpdateMyListFileStatus + // CommandRequest_GetCharactersCreators + // CommandRequest_TraktSyncCollection + // CommandRequest_TvDBUpdateSeriesAndEpisodes + // CommandRequest_TvDBDownloadImages + // CommandRequest_TvDBSearchAnime + //------ + // Pri 9 + //------ + // CommandRequest_GetCharacter + // CommandRequest_GetCreator + // CommandRequest_WebCacheSendFileHash + // CommandRequest_GetReviews + // CommandRequest_GetReleaseGroup + // CommandRequest_WebCacheSendXRefFileEpisode + // CommandRequest_WebCacheDeleteXRefFileEpisode + // CommandRequest_SyncMyVotes + // CommandRequest_VoteAnime + // CommandRequest_WebCacheDeleteXRefAniDBTvDB + // CommandRequest_WebCacheDeleteXRefAniDBTvDBAll + // CommandRequest_WebCacheSendXRefAniDBTvDB + // CommandRequest_WebCacheSendXRefAniDBOther + // CommandRequest_WebCacheDeleteXRefAniDBOther + // CommandRequest_MovieDBSearchAnime + // CommandRequest_TraktSearchAnime + // CommandRequest_WebCacheDeleteXRefAniDBTrakt + // CommandRequest_WebCacheSendXRefAniDBTrakt + // CommandRequest_TraktUpdateInfoAndImages + // CommandRequest_TraktShowScrobble + // CommandRequest_TraktSyncCollectionSeries + // CommandRequest_TraktShowEpisodeUnseen + // CommandRequest_DownloadImage + // CommandRequest_TraktUpdateAllSeries + + + public static ICommandRequest GetCommand(CommandRequest crdb) + { + CommandRequestType crt = (CommandRequestType)crdb.CommandType; + switch (crt) + { + case CommandRequestType.AniDB_GetFileUDP: + CommandRequest_GetFile cr_AniDB_GetFileUDP = new CommandRequest_GetFile(); + cr_AniDB_GetFileUDP.LoadFromDBCommand(crdb); + return (ICommandRequest)cr_AniDB_GetFileUDP; + + case CommandRequestType.Trakt_UpdateAllSeries: + CommandRequest_TraktUpdateAllSeries cr_Trakt_UpdateAllSeries = new CommandRequest_TraktUpdateAllSeries(); + cr_Trakt_UpdateAllSeries.LoadFromDBCommand(crdb); + return (ICommandRequest)cr_Trakt_UpdateAllSeries; + + case CommandRequestType.Trakt_ShowEpisodeUnseen: + CommandRequest_TraktShowEpisodeUnseen cr_Trakt_ShowEpisodeUnseen = new CommandRequest_TraktShowEpisodeUnseen(); + cr_Trakt_ShowEpisodeUnseen.LoadFromDBCommand(crdb); + return (ICommandRequest)cr_Trakt_ShowEpisodeUnseen; + + case CommandRequestType.Trakt_SyncCollectionSeries: + CommandRequest_TraktSyncCollectionSeries cr_Trakt_SyncCollectionSeries = new CommandRequest_TraktSyncCollectionSeries(); + cr_Trakt_SyncCollectionSeries.LoadFromDBCommand(crdb); + return (ICommandRequest)cr_Trakt_SyncCollectionSeries; + + case CommandRequestType.Trakt_SyncCollection: + CommandRequest_TraktSyncCollection cr_Trakt_SyncCollection = new CommandRequest_TraktSyncCollection(); + cr_Trakt_SyncCollection.LoadFromDBCommand(crdb); + return (ICommandRequest)cr_Trakt_SyncCollection; + + case CommandRequestType.Trakt_ShowScrobble: + CommandRequest_TraktShowScrobble cr_Trakt_ShowScrobble = new CommandRequest_TraktShowScrobble(); + cr_Trakt_ShowScrobble.LoadFromDBCommand(crdb); + return (ICommandRequest)cr_Trakt_ShowScrobble; + + case CommandRequestType.Trakt_UpdateInfoImages: + CommandRequest_TraktUpdateInfoAndImages cr_Trakt_UpdateInfoImages = new CommandRequest_TraktUpdateInfoAndImages(); + cr_Trakt_UpdateInfoImages.LoadFromDBCommand(crdb); + return (ICommandRequest)cr_Trakt_UpdateInfoImages; + + case CommandRequestType.WebCache_SendXRefAniDBTrakt: + CommandRequest_WebCacheSendXRefAniDBTrakt cr_WebCache_SendXRefAniDBTrakt = new CommandRequest_WebCacheSendXRefAniDBTrakt(); + cr_WebCache_SendXRefAniDBTrakt.LoadFromDBCommand(crdb); + return (ICommandRequest)cr_WebCache_SendXRefAniDBTrakt; + + case CommandRequestType.WebCache_DeleteXRefAniDBTrakt: + CommandRequest_WebCacheDeleteXRefAniDBTrakt cr_WebCache_DeleteXRefAniDBTrakt = new CommandRequest_WebCacheDeleteXRefAniDBTrakt(); + cr_WebCache_DeleteXRefAniDBTrakt.LoadFromDBCommand(crdb); + return (ICommandRequest)cr_WebCache_DeleteXRefAniDBTrakt; + + case CommandRequestType.Trakt_SearchAnime: + CommandRequest_TraktSearchAnime cr_Trakt_SearchAnime = new CommandRequest_TraktSearchAnime(); + cr_Trakt_SearchAnime.LoadFromDBCommand(crdb); + return (ICommandRequest)cr_Trakt_SearchAnime; + + case CommandRequestType.MovieDB_SearchAnime: + CommandRequest_MovieDBSearchAnime cr_MovieDB_SearchAnime = new CommandRequest_MovieDBSearchAnime(); + cr_MovieDB_SearchAnime.LoadFromDBCommand(crdb); + return (ICommandRequest)cr_MovieDB_SearchAnime; + + case CommandRequestType.WebCache_DeleteXRefAniDBOther: + CommandRequest_WebCacheDeleteXRefAniDBOther cr_SendXRefAniDBOther = new CommandRequest_WebCacheDeleteXRefAniDBOther(); + cr_SendXRefAniDBOther.LoadFromDBCommand(crdb); + return (ICommandRequest)cr_SendXRefAniDBOther; + + case CommandRequestType.WebCache_SendXRefAniDBOther: + CommandRequest_WebCacheSendXRefAniDBOther cr_WebCacheSendXRefAniDBOther = new CommandRequest_WebCacheSendXRefAniDBOther(); + cr_WebCacheSendXRefAniDBOther.LoadFromDBCommand(crdb); + return (ICommandRequest)cr_WebCacheSendXRefAniDBOther; + + case CommandRequestType.AniDB_DeleteFileUDP: + CommandRequest_DeleteFileFromMyList cr_AniDB_DeleteFileUDP = new CommandRequest_DeleteFileFromMyList(); + cr_AniDB_DeleteFileUDP.LoadFromDBCommand(crdb); + return (ICommandRequest)cr_AniDB_DeleteFileUDP; + + case CommandRequestType.ImageDownload: + CommandRequest_DownloadImage cr_ImageDownload = new CommandRequest_DownloadImage(); + cr_ImageDownload.LoadFromDBCommand(crdb); + return (ICommandRequest)cr_ImageDownload; + + case CommandRequestType.WebCache_DeleteXRefAniDBTvDB: + CommandRequest_WebCacheDeleteXRefAniDBTvDB cr_DeleteXRefAniDBTvDB = new CommandRequest_WebCacheDeleteXRefAniDBTvDB(); + cr_DeleteXRefAniDBTvDB.LoadFromDBCommand(crdb); + return (ICommandRequest)cr_DeleteXRefAniDBTvDB; + + case CommandRequestType.WebCache_DeleteXRefTvDB: + CommandRequest_WebCacheDeleteXRefAniDBTvDBAll cr_DeleteXRefTvDB = new CommandRequest_WebCacheDeleteXRefAniDBTvDBAll(); + cr_DeleteXRefTvDB.LoadFromDBCommand(crdb); + return (ICommandRequest)cr_DeleteXRefTvDB; + + case CommandRequestType.WebCache_SendXRefAniDBTvDB: + CommandRequest_WebCacheSendXRefAniDBTvDB cr_SendXRefAniDBTvDB = new CommandRequest_WebCacheSendXRefAniDBTvDB(); + cr_SendXRefAniDBTvDB.LoadFromDBCommand(crdb); + return (ICommandRequest)cr_SendXRefAniDBTvDB; + + + case CommandRequestType.TvDB_SearchAnime: + CommandRequest_TvDBSearchAnime cr_TvDB_SearchAnime = new CommandRequest_TvDBSearchAnime(); + cr_TvDB_SearchAnime.LoadFromDBCommand(crdb); + return (ICommandRequest)cr_TvDB_SearchAnime; + + case CommandRequestType.TvDB_DownloadImages: + CommandRequest_TvDBDownloadImages cr_TvDB_DownloadImages = new CommandRequest_TvDBDownloadImages(); + cr_TvDB_DownloadImages.LoadFromDBCommand(crdb); + return (ICommandRequest)cr_TvDB_DownloadImages; + + case CommandRequestType.TvDB_SeriesEpisodes: + CommandRequest_TvDBUpdateSeriesAndEpisodes cr_TvDB_Episodes = new CommandRequest_TvDBUpdateSeriesAndEpisodes(); + cr_TvDB_Episodes.LoadFromDBCommand(crdb); + return (ICommandRequest)cr_TvDB_Episodes; + + case CommandRequestType.AniDB_SyncVotes: + CommandRequest_SyncMyVotes cr_SyncVotes = new CommandRequest_SyncMyVotes(); + cr_SyncVotes.LoadFromDBCommand(crdb); + return (ICommandRequest)cr_SyncVotes; + + case CommandRequestType.AniDB_VoteAnime: + CommandRequest_VoteAnime cr_VoteAnime = new CommandRequest_VoteAnime(); + cr_VoteAnime.LoadFromDBCommand(crdb); + return (ICommandRequest)cr_VoteAnime; + + case CommandRequestType.AniDB_GetCalendar: + CommandRequest_GetCalendar cr_GetCalendar = new CommandRequest_GetCalendar(); + cr_GetCalendar.LoadFromDBCommand(crdb); + return (ICommandRequest)cr_GetCalendar; + + case CommandRequestType.AniDB_GetReleaseGroup: + CommandRequest_GetReleaseGroup cr_GetReleaseGroup = new CommandRequest_GetReleaseGroup(); + cr_GetReleaseGroup.LoadFromDBCommand(crdb); + return (ICommandRequest)cr_GetReleaseGroup; + + case CommandRequestType.AniDB_GetAnimeHTTP: + CommandRequest_GetAnimeHTTP cr_geth = new CommandRequest_GetAnimeHTTP(); + cr_geth.LoadFromDBCommand(crdb); + return (ICommandRequest)cr_geth; + + case CommandRequestType.AniDB_GetReleaseGroupStatus: + CommandRequest_GetReleaseGroupStatus cr_GetReleaseGroupStatus = new CommandRequest_GetReleaseGroupStatus(); + cr_GetReleaseGroupStatus.LoadFromDBCommand(crdb); + return (ICommandRequest)cr_GetReleaseGroupStatus; + + case CommandRequestType.HashFile: + CommandRequest_HashFile cr_HashFile = new CommandRequest_HashFile(); + cr_HashFile.LoadFromDBCommand(crdb); + return (ICommandRequest)cr_HashFile; + + case CommandRequestType.ProcessFile: + CommandRequest_ProcessFile cr_pf = new CommandRequest_ProcessFile(); + cr_pf.LoadFromDBCommand(crdb); + return (ICommandRequest)cr_pf; + + case CommandRequestType.AniDB_AddFileUDP: + CommandRequest_AddFileToMyList cr_af = new CommandRequest_AddFileToMyList(); + cr_af.LoadFromDBCommand(crdb); + return (ICommandRequest)cr_af; + + case CommandRequestType.AniDB_UpdateWatchedUDP: + CommandRequest_UpdateMyListFileStatus cr_umlf = new CommandRequest_UpdateMyListFileStatus(); + cr_umlf.LoadFromDBCommand(crdb); + return (ICommandRequest)cr_umlf; + + case CommandRequestType.AniDB_GetCharsCreators: + CommandRequest_GetCharactersCreators cr_chars = new CommandRequest_GetCharactersCreators(); + cr_chars.LoadFromDBCommand(crdb); + return (ICommandRequest)cr_chars; + + case CommandRequestType.AniDB_GetCharacter: + CommandRequest_GetCharacter cr_char = new CommandRequest_GetCharacter(); + cr_char.LoadFromDBCommand(crdb); + return (ICommandRequest)cr_char; + + case CommandRequestType.AniDB_GetCreator: + CommandRequest_GetCreator cr_creators = new CommandRequest_GetCreator(); + cr_creators.LoadFromDBCommand(crdb); + return (ICommandRequest)cr_creators; + + case CommandRequestType.WebCache_SendFileHash: + CommandRequest_WebCacheSendFileHash cr_SendFileHash = new CommandRequest_WebCacheSendFileHash(); + cr_SendFileHash.LoadFromDBCommand(crdb); + return (ICommandRequest)cr_SendFileHash; + + case CommandRequestType.WebCache_DeleteXRefFileEpisode: + CommandRequest_WebCacheDeleteXRefFileEpisode cr_DeleteXRefFileEpisode = new CommandRequest_WebCacheDeleteXRefFileEpisode(); + cr_DeleteXRefFileEpisode.LoadFromDBCommand(crdb); + return (ICommandRequest)cr_DeleteXRefFileEpisode; + + case CommandRequestType.WebCache_SendXRefFileEpisode: + CommandRequest_WebCacheSendXRefFileEpisode cr_SendXRefFileEpisode = new CommandRequest_WebCacheSendXRefFileEpisode(); + cr_SendXRefFileEpisode.LoadFromDBCommand(crdb); + return (ICommandRequest)cr_SendXRefFileEpisode; + + case CommandRequestType.AniDB_GetReviews: + CommandRequest_GetReviews cr_GetReviews = new CommandRequest_GetReviews(); + cr_GetReviews.LoadFromDBCommand(crdb); + return (ICommandRequest)cr_GetReviews; + + case CommandRequestType.AniDB_GetUpdated: + CommandRequest_GetUpdated cr_GetUpdated = new CommandRequest_GetUpdated(); + cr_GetUpdated.LoadFromDBCommand(crdb); + return (ICommandRequest)cr_GetUpdated; + + case CommandRequestType.AniDB_SyncMyList: + CommandRequest_SyncMyList cr_SyncMyList = new CommandRequest_SyncMyList(); + cr_SyncMyList.LoadFromDBCommand(crdb); + return (ICommandRequest)cr_SyncMyList; + } + + return null; + } + + + } + + +} diff --git a/JMMServer/Commands/CommandProcessorGeneral.cs b/JMMServer/Commands/CommandProcessorGeneral.cs new file mode 100644 index 000000000..a51b0cf82 --- /dev/null +++ b/JMMServer/Commands/CommandProcessorGeneral.cs @@ -0,0 +1,215 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.ComponentModel; +using NLog; +using JMMServer.Repositories; +using JMMServer.Entities; +using System.Threading; + +namespace JMMServer.Commands +{ + public class CommandProcessorGeneral + { + private static Logger logger = LogManager.GetCurrentClassLogger(); + private BackgroundWorker workerCommands = new BackgroundWorker(); + private bool processingCommands = false; + private DateTime? pauseTime = null; + + + private object lockQueueCount = new object(); + private object lockQueueState = new object(); + private object lockPaused = new object(); + + public delegate void QueueCountChangedHandler(QueueCountEventArgs ev); + public event QueueCountChangedHandler OnQueueCountChangedEvent; + protected void OQueueCountChanged(QueueCountEventArgs ev) + { + if (OnQueueCountChangedEvent != null) + { + OnQueueCountChangedEvent(ev); + } + } + + public delegate void QueueStateChangedHandler(QueueStateEventArgs ev); + public event QueueStateChangedHandler OnQueueStateChangedEvent; + protected void OQueueStateChanged(QueueStateEventArgs ev) + { + if (OnQueueStateChangedEvent != null) + { + OnQueueStateChangedEvent(ev); + } + } + + private bool paused = false; + public bool Paused + { + get + { + lock (lockPaused) + { + return paused; + } + } + set + { + lock (lockPaused) + { + paused = value; + if (paused) + { + QueueState = "Paused"; + pauseTime = DateTime.Now; + } + else + { + QueueState = "Idle"; + pauseTime = null; + JMMService.AnidbProcessor.IsBanned = false; + } + ServerInfo.Instance.GeneralQueuePaused = paused; + ServerInfo.Instance.GeneralQueueRunning = !paused; + } + } + } + + private int queueCount = 0; + public int QueueCount + { + get + { + lock (lockQueueCount) + { + return queueCount; + } + } + set + { + lock (lockQueueCount) + { + queueCount = value; + OnQueueCountChangedEvent(new QueueCountEventArgs(queueCount)); + } + } + } + + private string queueState = "Idle"; + public string QueueState + { + get + { + lock (lockQueueState) + { + return queueState; + } + } + set + { + lock (lockQueueCount) + { + queueState = value; + OnQueueStateChangedEvent(new QueueStateEventArgs(queueState)); + } + } + } + + public CommandProcessorGeneral() + { + workerCommands.WorkerReportsProgress = true; + workerCommands.WorkerSupportsCancellation = true; + workerCommands.DoWork += new DoWorkEventHandler(workerCommands_DoWork); + workerCommands.RunWorkerCompleted +=new RunWorkerCompletedEventHandler(workerCommands_RunWorkerCompleted); + } + + void workerCommands_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) + { + processingCommands = false; + logger.Trace("Stopping command worker..."); + QueueState = "Idle"; + } + + public void Init() + { + processingCommands = true; + logger.Trace("Starting command worker..."); + QueueState = "Starting command worker (hasher)..."; + this.workerCommands.RunWorkerAsync(); + } + + /// + /// This is simply used to tell the command processor that a new command has been added to the database + /// + public void NotifyOfNewCommand() + { + // if the worker is busy, it will pick up the next command from the DB + if (processingCommands) + { + //logger.Trace("NotifyOfNewCommand exiting, worker already busy"); + return; + } + + // otherwise need to start the worker again + logger.Trace("Restarting command worker..."); + + processingCommands = true; + this.workerCommands.RunWorkerAsync(); + } + + void workerCommands_DoWork(object sender, DoWorkEventArgs e) + { + while (true) + { + // if paused we will sleep for 5 seconds, and the try again + // we will remove the pause if it was set more than 6 hours ago + // the pause is initiated when banned from AniDB or manually by the user + if (Paused) + { + try + { + logger.Trace("Queue is paused: {0}", pauseTime.Value); + TimeSpan ts = DateTime.Now - pauseTime.Value; + if (ts.TotalHours >= 6) + { + Paused = false; + } + } + catch { } + Thread.Sleep(5000); + continue; + } + + + logger.Trace("Looking for next command request..."); + + CommandRequestRepository repCR = new CommandRequestRepository(); + CommandRequest crdb = repCR.GetNextDBCommandRequestGeneral(); + if (crdb == null) return; + + QueueCount = repCR.GetQueuedCommandCountGeneral(); + logger.Trace("{0} commands remaining in queue", QueueCount); + + logger.Trace("Next command request: {0}", crdb.CommandID); + + ICommandRequest icr = CommandHelper.GetCommand(crdb); + if (icr == null) + { + logger.Trace("No implementation found for command: {0}-{1}", crdb.CommandType, crdb.CommandID); + return; + } + + QueueState = icr.PrettyDescription; + + logger.Trace("Processing command request: {0}", crdb.CommandID); + icr.ProcessCommand(); + + logger.Trace("Deleting command request: {0}", crdb.CommandID); + repCR.Delete(crdb.CommandRequestID); + + QueueCount = repCR.GetQueuedCommandCountGeneral(); + } + } + } + + +} diff --git a/JMMServer/Commands/CommandProcessorHasher.cs b/JMMServer/Commands/CommandProcessorHasher.cs new file mode 100644 index 000000000..1c5975f26 --- /dev/null +++ b/JMMServer/Commands/CommandProcessorHasher.cs @@ -0,0 +1,210 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using NLog; +using System.ComponentModel; +using JMMServer.Repositories; +using JMMServer.Entities; +using System.Threading; + +namespace JMMServer.Commands +{ + public class CommandProcessorHasher + { + private static Logger logger = LogManager.GetCurrentClassLogger(); + private BackgroundWorker workerCommands = new BackgroundWorker(); + private bool processingCommands = false; + private DateTime? pauseTime = null; + + private object lockQueueCount = new object(); + private object lockQueueState = new object(); + private object lockPaused = new object(); + + public delegate void QueueCountChangedHandler(QueueCountEventArgs ev); + public event QueueCountChangedHandler OnQueueCountChangedEvent; + protected void OQueueCountChanged(QueueCountEventArgs ev) + { + if (OnQueueCountChangedEvent != null) + { + OnQueueCountChangedEvent(ev); + } + } + + public delegate void QueueStateChangedHandler(QueueStateEventArgs ev); + public event QueueStateChangedHandler OnQueueStateChangedEvent; + protected void OQueueStateChanged(QueueStateEventArgs ev) + { + if (OnQueueStateChangedEvent != null) + { + OnQueueStateChangedEvent(ev); + } + } + + private bool paused = false; + public bool Paused + { + get + { + lock (lockPaused) + { + return paused; + } + } + set + { + lock (lockPaused) + { + paused = value; + if (paused) + { + QueueState = "Paused"; + pauseTime = DateTime.Now; + } + else + { + QueueState = "Idle"; + pauseTime = null; + } + + ServerInfo.Instance.HasherQueuePaused = paused; + ServerInfo.Instance.HasherQueueRunning = !paused; + } + } + } + + private int queueCount = 0; + public int QueueCount + { + get + { + lock (lockQueueCount) + { + return queueCount; + } + } + set + { + lock (lockQueueCount) + { + queueCount = value; + OnQueueCountChangedEvent(new QueueCountEventArgs(queueCount)); + } + } + } + + private string queueState = "Idle"; + public string QueueState + { + get + { + lock (lockQueueState) + { + return queueState; + } + } + set + { + lock (lockQueueCount) + { + queueState = value; + OnQueueStateChangedEvent(new QueueStateEventArgs(queueState)); + } + } + } + + public CommandProcessorHasher() + { + workerCommands.WorkerReportsProgress = true; + workerCommands.WorkerSupportsCancellation = true; + workerCommands.DoWork += new DoWorkEventHandler(workerCommands_DoWork); + workerCommands.RunWorkerCompleted +=new RunWorkerCompletedEventHandler(workerCommands_RunWorkerCompleted); + } + + void workerCommands_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) + { + processingCommands = false; + logger.Trace("Stopping command worker (hasher)..."); + QueueState = "Idle"; + } + + public void Init() + { + processingCommands = true; + logger.Trace("Starting command worker (hasher)..."); + QueueState = "Starting command worker (hasher)..."; + this.workerCommands.RunWorkerAsync(); + } + + /// + /// This is simply used to tell the command processor that a new command has been added to the database + /// + public void NotifyOfNewCommand() + { + // if the worker is busy, it will pick up the next command from the DB + if (processingCommands) + { + //logger.Trace("NotifyOfNewCommand (hasher) exiting, worker already busy"); + return; + } + + // otherwise need to start the worker again + logger.Trace("Restarting command worker (hasher)..."); + + processingCommands = true; + this.workerCommands.RunWorkerAsync(); + } + + void workerCommands_DoWork(object sender, DoWorkEventArgs e) + { + while (true) + { + // if paused we will sleep for 5 seconds, and the try again + // we will remove the pause if it was set more than 6 hours ago + // the pause is initiated when banned from AniDB or manually by the user + if (Paused) + { + try + { + logger.Trace("Hasher Queue is paused: {0}", pauseTime.Value); + TimeSpan ts = DateTime.Now - pauseTime.Value; + if (ts.TotalHours >= 6) + { + Paused = false; + } + } + catch { } + Thread.Sleep(5000); + continue; + } + + logger.Trace("Looking for next command request (hasher)..."); + + CommandRequestRepository repCR = new CommandRequestRepository(); + CommandRequest crdb = repCR.GetNextDBCommandRequestHasher(); + if (crdb == null) return; + + QueueCount = repCR.GetQueuedCommandCountHasher(); + logger.Trace("{0} commands remaining in queue (hasher)", QueueCount); + + logger.Trace("Next command request (hasher): {0}", crdb.CommandID); + + ICommandRequest icr = CommandHelper.GetCommand(crdb); + if (icr == null) + { + logger.Trace("No implementation found for command: {0}-{1}", crdb.CommandType, crdb.CommandID); + return; + } + + QueueState = icr.PrettyDescription; + + logger.Trace("Processing command request (hasher): {0}", crdb.CommandID); + icr.ProcessCommand(); + + logger.Trace("Deleting command request (hasher): {0}", crdb.CommandID); + repCR.Delete(crdb.CommandRequestID); + QueueCount = repCR.GetQueuedCommandCountHasher(); + } + } + } +} diff --git a/JMMServer/Commands/CommandProcessorImages.cs b/JMMServer/Commands/CommandProcessorImages.cs new file mode 100644 index 000000000..29b83907f --- /dev/null +++ b/JMMServer/Commands/CommandProcessorImages.cs @@ -0,0 +1,210 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using NLog; +using System.ComponentModel; +using JMMServer.Repositories; +using JMMServer.Entities; +using System.Threading; + +namespace JMMServer.Commands +{ + public class CommandProcessorImages + { + private static Logger logger = LogManager.GetCurrentClassLogger(); + private BackgroundWorker workerCommands = new BackgroundWorker(); + private bool processingCommands = false; + private DateTime? pauseTime = null; + + private object lockQueueCount = new object(); + private object lockQueueState = new object(); + private object lockPaused = new object(); + + public delegate void QueueCountChangedHandler(QueueCountEventArgs ev); + public event QueueCountChangedHandler OnQueueCountChangedEvent; + protected void OQueueCountChanged(QueueCountEventArgs ev) + { + if (OnQueueCountChangedEvent != null) + { + OnQueueCountChangedEvent(ev); + } + } + + public delegate void QueueStateChangedHandler(QueueStateEventArgs ev); + public event QueueStateChangedHandler OnQueueStateChangedEvent; + protected void OQueueStateChanged(QueueStateEventArgs ev) + { + if (OnQueueStateChangedEvent != null) + { + OnQueueStateChangedEvent(ev); + } + } + + private bool paused = false; + public bool Paused + { + get + { + lock (lockPaused) + { + return paused; + } + } + set + { + lock (lockPaused) + { + paused = value; + if (paused) + { + QueueState = "Paused"; + pauseTime = DateTime.Now; + } + else + { + QueueState = "Idle"; + pauseTime = null; + } + + ServerInfo.Instance.HasherQueuePaused = paused; + ServerInfo.Instance.HasherQueueRunning = !paused; + } + } + } + + private int queueCount = 0; + public int QueueCount + { + get + { + lock (lockQueueCount) + { + return queueCount; + } + } + set + { + lock (lockQueueCount) + { + queueCount = value; + OnQueueCountChangedEvent(new QueueCountEventArgs(queueCount)); + } + } + } + + private string queueState = "Idle"; + public string QueueState + { + get + { + lock (lockQueueState) + { + return queueState; + } + } + set + { + lock (lockQueueCount) + { + queueState = value; + OnQueueStateChangedEvent(new QueueStateEventArgs(queueState)); + } + } + } + + public CommandProcessorImages() + { + workerCommands.WorkerReportsProgress = true; + workerCommands.WorkerSupportsCancellation = true; + workerCommands.DoWork += new DoWorkEventHandler(workerCommands_DoWork); + workerCommands.RunWorkerCompleted +=new RunWorkerCompletedEventHandler(workerCommands_RunWorkerCompleted); + } + + void workerCommands_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) + { + processingCommands = false; + logger.Trace("Stopping command worker (images)..."); + QueueState = "Idle"; + } + + public void Init() + { + processingCommands = true; + logger.Trace("Starting command worker (images)..."); + QueueState = "Starting command worker (images)..."; + this.workerCommands.RunWorkerAsync(); + } + + /// + /// This is simply used to tell the command processor that a new command has been added to the database + /// + public void NotifyOfNewCommand() + { + // if the worker is busy, it will pick up the next command from the DB + if (processingCommands) + { + //logger.Trace("NotifyOfNewCommand (hasher) exiting, worker already busy"); + return; + } + + // otherwise need to start the worker again + logger.Trace("Restarting command worker (images)..."); + + processingCommands = true; + this.workerCommands.RunWorkerAsync(); + } + + void workerCommands_DoWork(object sender, DoWorkEventArgs e) + { + while (true) + { + // if paused we will sleep for 5 seconds, and the try again + // we will remove the pause if it was set more than 6 hours ago + // the pause is initiated when banned from AniDB or manually by the user + if (Paused) + { + try + { + logger.Trace("Images Queue is paused: {0}", pauseTime.Value); + TimeSpan ts = DateTime.Now - pauseTime.Value; + if (ts.TotalHours >= 6) + { + Paused = false; + } + } + catch { } + Thread.Sleep(5000); + continue; + } + + logger.Trace("Looking for next command request (images)..."); + + CommandRequestRepository repCR = new CommandRequestRepository(); + CommandRequest crdb = repCR.GetNextDBCommandRequestImages(); + if (crdb == null) return; + + QueueCount = repCR.GetQueuedCommandCountImages(); + logger.Trace("{0} commands remaining in queue (images)", QueueCount); + + logger.Trace("Next command request (images): {0}", crdb.CommandID); + + ICommandRequest icr = CommandHelper.GetCommand(crdb); + if (icr == null) + { + logger.Trace("No implementation found for command: {0}-{1}", crdb.CommandType, crdb.CommandID); + return; + } + + QueueState = icr.PrettyDescription; + + logger.Trace("Processing command request (images): {0}", crdb.CommandID); + icr.ProcessCommand(); + + logger.Trace("Deleting command request (images): {0}", crdb.CommandID); + repCR.Delete(crdb.CommandRequestID); + QueueCount = repCR.GetQueuedCommandCountHasher(); + } + } + } +} diff --git a/JMMServer/Commands/CommandRequestImplementation.cs b/JMMServer/Commands/CommandRequestImplementation.cs new file mode 100644 index 000000000..4a975058b --- /dev/null +++ b/JMMServer/Commands/CommandRequestImplementation.cs @@ -0,0 +1,110 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Xml.Serialization; +using NLog; +using System.Xml; +using JMMServer.Entities; +using JMMServer.Repositories; + +namespace JMMServer.Commands +{ + public abstract class CommandRequestImplementation + { + protected static Logger logger = LogManager.GetCurrentClassLogger(); + + // ignoring the base properties so that when we serialize we only get the properties + // defined in the concrete class + + [XmlIgnore] + public int CommandRequestID { get; set; } + + [XmlIgnore] + public int Priority { get; set; } + + [XmlIgnore] + public int CommandType { get; set; } + + [XmlIgnore] + public string CommandID { get; set; } + + [XmlIgnore] + public string CommandDetails { get; set; } + + [XmlIgnore] + public DateTime DateTimeUpdated { get; set; } + + /// + /// Inherited classes to provide the implemenation of how to process this command + /// + public abstract void ProcessCommand(); + + public abstract void GenerateCommandID(); + + public abstract bool LoadFromDBCommand(CommandRequest cq); + + public abstract CommandRequest ToDatabaseObject(); + + public string ToXML() + { + XmlSerializerNamespaces ns = new XmlSerializerNamespaces(); + ns.Add("", ""); + + XmlSerializer serializer = new XmlSerializer(this.GetType()); + XmlWriterSettings settings = new XmlWriterSettings(); + settings.OmitXmlDeclaration = true; // Remove the + + StringBuilder sb = new StringBuilder(); + XmlWriter writer = XmlWriter.Create(sb, settings); + serializer.Serialize(writer, this, ns); + + return sb.ToString(); + } + + public void Save() + { + CommandRequestRepository repCR = new CommandRequestRepository(); + CommandRequest crTemp = repCR.GetByCommandID(this.CommandID); + if (crTemp != null) + { + // we will always mylist watched state changes + // this is because the user may be toggling the status in the client, and we need to process + // them all in the order they were requested + if (CommandType != (int)CommandRequestType.AniDB_UpdateWatchedUDP) + { + logger.Trace("Command already in queue with identifier so skipping: {0}", this.CommandID); + return; + } + } + + CommandRequest cri = this.ToDatabaseObject(); + repCR.Save(cri); + + if (CommandType == (int)CommandRequestType.HashFile) + JMMService.CmdProcessorHasher.NotifyOfNewCommand(); + else if (CommandType == (int)CommandRequestType.ImageDownload) + JMMService.CmdProcessorImages.NotifyOfNewCommand(); + else + JMMService.CmdProcessorGeneral.NotifyOfNewCommand(); + } + + protected string TryGetProperty(XmlDocument doc, string keyName, string propertyName) + { + try + { + string prop = doc[keyName][propertyName].InnerText.Trim(); + return prop; + } + catch (Exception ex) + { + //BaseConfig.MyAnimeLog.Write("---------------------------------------------------------------"); + //BaseConfig.MyAnimeLog.Write("Error in XMLService.TryGetProperty: {0}-{1}", Utils.GetParentMethodName(), ex.ToString()); + //BaseConfig.MyAnimeLog.Write("keyName: {0}, propertyName: {1}", keyName, propertyName); + //BaseConfig.MyAnimeLog.Write("---------------------------------------------------------------"); + } + + return ""; + } + } +} diff --git a/JMMServer/Commands/CommandRequest_DownloadImage.cs b/JMMServer/Commands/CommandRequest_DownloadImage.cs new file mode 100644 index 000000000..eeb2b6232 --- /dev/null +++ b/JMMServer/Commands/CommandRequest_DownloadImage.cs @@ -0,0 +1,425 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Xml; +using JMMServer.Entities; +using JMMServer.Repositories; +using JMMServer.ImageDownload; +using System.IO; +using System.Net; + +namespace JMMServer.Commands +{ + public class CommandRequest_DownloadImage : CommandRequestImplementation, ICommandRequest + { + public int EntityID { get; set; } + public int EntityType { get; set; } + public bool ForceDownload { get; set; } + + public JMMImageType EntityTypeEnum + { + get + { + return (JMMImageType)EntityType; + } + } + + public CommandRequestPriority DefaultPriority + { + get { return CommandRequestPriority.Priority2; } + } + + public string PrettyDescription + { + get + { + return string.Format("Downloading Image: {0}", EntityID); + } + } + + public CommandRequest_DownloadImage() + { + } + + public CommandRequest_DownloadImage(int entityID, JMMImageType entityType, bool forced) + { + this.EntityID = entityID; + this.EntityType = (int)entityType; + this.ForceDownload = forced; + this.CommandType = (int)CommandRequestType.ImageDownload; + this.Priority = (int)DefaultPriority; + + GenerateCommandID(); + } + + public override void ProcessCommand() + { + logger.Info("Processing CommandRequest_DownloadImage: {0}", EntityID); + + try + { + ImageDownloadRequest req = null; + switch (EntityTypeEnum) + { + case JMMImageType.AniDB_Cover: + AniDB_AnimeRepository repAnime = new AniDB_AnimeRepository(); + AniDB_Anime anime = repAnime.GetByID(EntityID); + if (anime == null) return; + + req = new ImageDownloadRequest(EntityTypeEnum, anime, ForceDownload); + break; + + case JMMImageType.TvDB_Episode: + + TvDB_EpisodeRepository repTvEp = new TvDB_EpisodeRepository(); + TvDB_Episode ep = repTvEp.GetByID(EntityID); + if (ep == null) return; + if (string.IsNullOrEmpty(ep.Filename)) return; + + req = new ImageDownloadRequest(EntityTypeEnum, ep, ForceDownload); + break; + + case JMMImageType.TvDB_FanArt: + + TvDB_ImageFanartRepository repFanart = new TvDB_ImageFanartRepository(); + TvDB_ImageFanart fanart = repFanart.GetByID(EntityID); + if (fanart == null) return; + if (string.IsNullOrEmpty(fanart.BannerPath)) return; + + req = new ImageDownloadRequest(EntityTypeEnum, fanart, ForceDownload); + break; + + case JMMImageType.TvDB_Cover: + + TvDB_ImagePosterRepository repPoster = new TvDB_ImagePosterRepository(); + TvDB_ImagePoster poster = repPoster.GetByID(EntityID); + if (poster == null) return; + if (string.IsNullOrEmpty(poster.BannerPath)) return; + + req = new ImageDownloadRequest(EntityTypeEnum, poster, ForceDownload); + break; + + case JMMImageType.TvDB_Banner: + + TvDB_ImageWideBannerRepository repBanners = new TvDB_ImageWideBannerRepository(); + TvDB_ImageWideBanner wideBanner = repBanners.GetByID(EntityID); + if (wideBanner == null) return; + if (string.IsNullOrEmpty(wideBanner.BannerPath)) return; + + req = new ImageDownloadRequest(EntityTypeEnum, wideBanner, ForceDownload); + break; + + case JMMImageType.MovieDB_Poster: + + MovieDB_PosterRepository repMoviePosters = new MovieDB_PosterRepository(); + MovieDB_Poster moviePoster = repMoviePosters.GetByID(EntityID); + if (moviePoster == null) return; + if (string.IsNullOrEmpty(moviePoster.URL)) return; + + req = new ImageDownloadRequest(EntityTypeEnum, moviePoster, ForceDownload); + break; + + case JMMImageType.MovieDB_FanArt: + + MovieDB_FanartRepository repMovieFanart = new MovieDB_FanartRepository(); + MovieDB_Fanart movieFanart = repMovieFanart.GetByID(EntityID); + if (movieFanart == null) return; + if (string.IsNullOrEmpty(movieFanart.URL)) return; + + req = new ImageDownloadRequest(EntityTypeEnum, movieFanart, ForceDownload); + break; + + case JMMImageType.Trakt_Poster: + + Trakt_ImagePosterRepository repTraktPosters = new Trakt_ImagePosterRepository(); + Trakt_ImagePoster traktPoster = repTraktPosters.GetByID(EntityID); + if (traktPoster == null) return; + if (string.IsNullOrEmpty(traktPoster.ImageURL)) return; + + req = new ImageDownloadRequest(EntityTypeEnum, traktPoster, ForceDownload); + break; + + case JMMImageType.Trakt_Fanart: + + Trakt_ImageFanartRepository repTraktFanarts = new Trakt_ImageFanartRepository(); + Trakt_ImageFanart traktFanart = repTraktFanarts.GetByID(EntityID); + if (traktFanart == null) return; + if (string.IsNullOrEmpty(traktFanart.ImageURL)) return; + + req = new ImageDownloadRequest(EntityTypeEnum, traktFanart, ForceDownload); + break; + + case JMMImageType.Trakt_Episode: + + Trakt_EpisodeRepository repTraktEpisodes = new Trakt_EpisodeRepository(); + Trakt_Episode traktEp = repTraktEpisodes.GetByID(EntityID); + if (traktEp == null) return; + if (string.IsNullOrEmpty(traktEp.EpisodeImage)) return; + + req = new ImageDownloadRequest(EntityTypeEnum, traktEp, ForceDownload); + break; + } + + if (req == null) return; + + List fileNames = new List(); + List downloadURLs = new List(); + + string fileNameTemp = GetFileName(req, false); + string downloadURLTemp = GetFileURL(req, false); + + fileNames.Add(fileNameTemp); + downloadURLs.Add(downloadURLTemp); + + if (req.ImageType == JMMImageType.TvDB_FanArt) + { + fileNameTemp = GetFileName(req, true); + downloadURLTemp = GetFileURL(req, true); + + fileNames.Add(fileNameTemp); + downloadURLs.Add(downloadURLTemp); + } + + for (int i = 0; i < fileNames.Count; i++) + { + string fileName = fileNames[i]; + string downloadURL = downloadURLs[i]; + + bool downloadImage = true; + bool fileExists = File.Exists(fileName); + + if (fileExists) + { + if (!req.ForceDownload) + downloadImage = false; + else + downloadImage = true; + } + else + downloadImage = true; + + if (downloadImage) + { + string tempName = Path.Combine(ImageUtils.GetImagesTempFolder(), Path.GetFileName(fileName)); + if (File.Exists(tempName)) File.Delete(tempName); + + + if (fileExists) File.Delete(fileName); + + // download image + using (WebClient client = new WebClient()) + { + client.Headers.Add("user-agent", "JMM"); + //OnImageDownloadEvent(new ImageDownloadEventArgs("", req, ImageDownloadEventType.Started)); + //BaseConfig.MyAnimeLog.Write("ProcessImages: Download: {0} *** to *** {1}", req.URL, fullName); + if (downloadURL.Length > 0) + { + client.DownloadFile(downloadURL, tempName); + + string extension = ""; + string contentType = client.ResponseHeaders["Content-type"].ToLower(); + if (contentType.IndexOf("gif") >= 0) extension = ".gif"; + if (contentType.IndexOf("jpg") >= 0) extension = ".jpg"; + if (contentType.IndexOf("jpeg") >= 0) extension = ".jpg"; + if (contentType.IndexOf("bmp") >= 0) extension = ".bmp"; + if (contentType.IndexOf("png") >= 0) extension = ".png"; + if (extension.Length > 0) + { + string newFile = Path.ChangeExtension(tempName, extension); + if (!newFile.ToLower().Equals(tempName.ToLower())) + { + try + { + System.IO.File.Delete(newFile); + } + catch + { + //BaseConfig.MyAnimeLog.Write("DownloadedImage:Download() Delete failed:{0}", newFile); + } + System.IO.File.Move(tempName, newFile); + tempName = newFile; + } + } + } + } + + // move the file to it's final location + // check that the final folder exists + string fullPath = Path.GetDirectoryName(fileName); + if (!Directory.Exists(fullPath)) + Directory.CreateDirectory(fullPath); + + + System.IO.File.Move(tempName, fileName); + logger.Info("Image downloaded: {0}", fileName); + } + } + + } + catch (Exception ex) + { + logger.Error("Error processing CommandRequest_DownloadImage: {0} - {1}", EntityID, ex.ToString()); + return; + } + } + + public static string GetFileURL(ImageDownloadRequest req, bool thumbNailOnly) + { + switch (req.ImageType) + { + case JMMImageType.AniDB_Cover: + AniDB_Anime anime = req.ImageData as AniDB_Anime; + return string.Format(Constants.URLS.AniDB_Images, anime.Picname); + + case JMMImageType.TvDB_Episode: + TvDB_Episode ep = req.ImageData as TvDB_Episode; + return string.Format(Constants.URLS.TvDB_Images, ep.Filename); + + case JMMImageType.TvDB_FanArt: + TvDB_ImageFanart fanart = req.ImageData as TvDB_ImageFanart; + + if (thumbNailOnly) + return string.Format(Constants.URLS.TvDB_Images, fanart.ThumbnailPath); + else + return string.Format(Constants.URLS.TvDB_Images, fanart.BannerPath); + + case JMMImageType.TvDB_Cover: + TvDB_ImagePoster poster = req.ImageData as TvDB_ImagePoster; + return string.Format(Constants.URLS.TvDB_Images, poster.BannerPath); + + case JMMImageType.TvDB_Banner: + TvDB_ImageWideBanner wideBanner = req.ImageData as TvDB_ImageWideBanner; + return string.Format(Constants.URLS.TvDB_Images, wideBanner.BannerPath); + + case JMMImageType.MovieDB_Poster: + MovieDB_Poster moviePoster = req.ImageData as MovieDB_Poster; + return moviePoster.URL; + + case JMMImageType.MovieDB_FanArt: + + MovieDB_Fanart movieFanart = req.ImageData as MovieDB_Fanart; + return movieFanart.URL; + + case JMMImageType.Trakt_Poster: + Trakt_ImagePoster traktPoster = req.ImageData as Trakt_ImagePoster; + return traktPoster.ImageURL; + + case JMMImageType.Trakt_Fanart: + Trakt_ImageFanart traktFanart = req.ImageData as Trakt_ImageFanart; + return traktFanart.ImageURL; + + case JMMImageType.Trakt_Episode: + Trakt_Episode traktEp = req.ImageData as Trakt_Episode; + return traktEp.EpisodeImage; + + default: + return ""; + + } + } + + private string GetFileName(ImageDownloadRequest req, bool thumbNailOnly) + { + switch (req.ImageType) + { + case JMMImageType.AniDB_Cover: + + AniDB_Anime anime = req.ImageData as AniDB_Anime; + return anime.PosterPath; + + case JMMImageType.TvDB_Episode: + + TvDB_Episode ep = req.ImageData as TvDB_Episode; + return ep.FullImagePath; + + case JMMImageType.TvDB_FanArt: + + TvDB_ImageFanart fanart = req.ImageData as TvDB_ImageFanart; + if (thumbNailOnly) + return fanart.FullThumbnailPath; + else + return fanart.FullImagePath; + + case JMMImageType.TvDB_Cover: + + TvDB_ImagePoster poster = req.ImageData as TvDB_ImagePoster; + return poster.FullImagePath; + + case JMMImageType.TvDB_Banner: + + TvDB_ImageWideBanner wideBanner = req.ImageData as TvDB_ImageWideBanner; + return wideBanner.FullImagePath; + + case JMMImageType.MovieDB_Poster: + + MovieDB_Poster moviePoster = req.ImageData as MovieDB_Poster; + return moviePoster.FullImagePath; + + case JMMImageType.MovieDB_FanArt: + + MovieDB_Fanart movieFanart = req.ImageData as MovieDB_Fanart; + return movieFanart.FullImagePath; + + case JMMImageType.Trakt_Poster: + Trakt_ImagePoster traktPoster = req.ImageData as Trakt_ImagePoster; + return traktPoster.FullImagePath; + + case JMMImageType.Trakt_Fanart: + Trakt_ImageFanart traktFanart = req.ImageData as Trakt_ImageFanart; + return traktFanart.FullImagePath; + + case JMMImageType.Trakt_Episode: + Trakt_Episode traktEp = req.ImageData as Trakt_Episode; + return traktEp.FullImagePath; + + default: + return ""; + } + + } + + public override void GenerateCommandID() + { + this.CommandID = string.Format("CommandRequest_DownloadImage_{0}_{1}", EntityID, (int)EntityType); + } + + public override bool LoadFromDBCommand(CommandRequest cq) + { + this.CommandID = cq.CommandID; + this.CommandRequestID = cq.CommandRequestID; + this.CommandType = cq.CommandType; + this.Priority = cq.Priority; + this.CommandDetails = cq.CommandDetails; + this.DateTimeUpdated = cq.DateTimeUpdated; + + // read xml to get parameters + if (this.CommandDetails.Trim().Length > 0) + { + XmlDocument docCreator = new XmlDocument(); + docCreator.LoadXml(this.CommandDetails); + + // populate the fields + this.EntityID = int.Parse(TryGetProperty(docCreator, "CommandRequest_DownloadImage", "EntityID")); + this.EntityType = int.Parse(TryGetProperty(docCreator, "CommandRequest_DownloadImage", "EntityType")); + this.ForceDownload = bool.Parse(TryGetProperty(docCreator, "CommandRequest_DownloadImage", "ForceDownload")); + } + + return true; + } + + public override CommandRequest ToDatabaseObject() + { + GenerateCommandID(); + + CommandRequest cq = new CommandRequest(); + cq.CommandID = this.CommandID; + cq.CommandType = this.CommandType; + cq.Priority = this.Priority; + cq.CommandDetails = this.ToXML(); + cq.DateTimeUpdated = DateTime.Now; + + return cq; + } + } +} diff --git a/JMMServer/Commands/CommandRequest_HashFile.cs b/JMMServer/Commands/CommandRequest_HashFile.cs new file mode 100644 index 000000000..c40d7c07a --- /dev/null +++ b/JMMServer/Commands/CommandRequest_HashFile.cs @@ -0,0 +1,397 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Entities; +using JMMServer.Repositories; +using System.IO; +using JMMContracts; +using JMMFileHelper; +using System.Xml; +using JMMServer.WebCache; +using System.Threading; + +namespace JMMServer.Commands +{ + [Serializable] + public class CommandRequest_HashFile : CommandRequestImplementation, ICommandRequest + { + public string FileName { get; set; } + public bool ForceHash { get; set; } + + public CommandRequestPriority DefaultPriority + { + get { return CommandRequestPriority.Priority4; } + } + + public string PrettyDescription + { + get + { + return string.Format("Hashing File: {0}", FileName); + } + } + + public CommandRequest_HashFile() + { + } + + public CommandRequest_HashFile(string filename, bool force) + { + this.FileName = filename; + this.ForceHash = force; + this.CommandType = (int)CommandRequestType.HashFile; + this.Priority = (int)DefaultPriority; + + GenerateCommandID(); + } + + public override void ProcessCommand() + { + logger.Info("Hashing File: {0}", FileName); + + VideoLocal vlocal = null; + try + { + vlocal = ProcessFile_LocalInfo(); + } + catch (Exception ex) + { + logger.Error("Error processing CommandRequest_ProcessFile: {0} - {1}", FileName, ex.ToString()); + return; + } + } + + private bool CanAccessFile(string fileName) + { + try + { + using (FileStream fs = File.OpenRead(fileName)) + { + fs.Close(); + return true; + } + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + return false; + } + } + + private VideoLocal ProcessFile_LocalInfo() + { + // hash and read media info for file + int nshareID = -1; + string filePath = ""; + + ImportFolderRepository repNS = new ImportFolderRepository(); + List 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 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); + } + else + { + logger.Trace("VideoLocal, creating new record"); + vlocal = new VideoLocal(); + vlocal.DateTimeUpdated = DateTime.Now; + vlocal.FilePath = filePath; + vlocal.FileSize = fi.Length; + vlocal.ImportFolderID = nshareID; + vlocal.Hash = ""; + vlocal.CRC32 = ""; + vlocal.MD5 = ""; + vlocal.SHA1 = ""; + vlocal.IsIgnored = 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 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 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; + } + } + + // try getting the hash from the WEB cache + if (!ForceHash && string.IsNullOrEmpty(vlocal.Hash)) + { + string hash = XMLService.Get_FileHash(vlocal.FilePath, vlocal.FileSize); + if (!string.IsNullOrEmpty(hash)) + { + logger.Trace("Got hash from web cache: {0} ({1})", FileName, hash); + vlocal.Hash = 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}", ts.TotalSeconds.ToString("#0.0"), FileName); + + 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 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 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); + + // if this was hashed by the user, lets upload to cache + if (vlocal.HashSource == (int)HashSource.DirectHash) + { + CommandRequest_WebCacheSendFileHash cr = new CommandRequest_WebCacheSendFileHash(vlocal.VideoLocalID); + cr.Save(); + } + + } + + + // 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.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.VideoCodec = string.IsNullOrEmpty(mInfo.VideoCodec) ? "" : mInfo.VideoCodec; + vinfo.VideoFrameRate = string.IsNullOrEmpty(mInfo.VideoFrameRate) ? "" : mInfo.VideoFrameRate; + vinfo.VideoResolution = string.IsNullOrEmpty(mInfo.VideoResolution) ? "" : mInfo.VideoResolution; + repVidInfo.Save(vinfo); + } + + // now add a command to process the file + CommandRequest_ProcessFile cr_procfile = new CommandRequest_ProcessFile(vlocal.VideoLocalID); + cr_procfile.Save(); + + return vlocal; + } + + /// + /// This should generate a unique key for a command + /// It will be used to check whether the command has already been queued before adding it + /// + public override void GenerateCommandID() + { + this.CommandID = string.Format("CommandRequest_HashFile_{0}", this.FileName); + } + + public override bool LoadFromDBCommand(CommandRequest cq) + { + this.CommandID = cq.CommandID; + this.CommandRequestID = cq.CommandRequestID; + this.CommandType = cq.CommandType; + this.Priority = cq.Priority; + this.CommandDetails = cq.CommandDetails; + this.DateTimeUpdated = cq.DateTimeUpdated; + + // read xml to get parameters + if (this.CommandDetails.Trim().Length > 0) + { + XmlDocument docCreator = new XmlDocument(); + docCreator.LoadXml(this.CommandDetails); + + // populate the fields + this.FileName = TryGetProperty(docCreator, "CommandRequest_HashFile", "FileName"); + this.ForceHash = bool.Parse(TryGetProperty(docCreator, "CommandRequest_HashFile", "ForceHash")); + } + + if (this.FileName.Trim().Length > 0) + return true; + else + return false; + } + + public override CommandRequest ToDatabaseObject() + { + GenerateCommandID(); + + CommandRequest cq = new CommandRequest(); + cq.CommandID = this.CommandID; + cq.CommandType = this.CommandType; + cq.Priority = this.Priority; + cq.CommandDetails = this.ToXML(); + cq.DateTimeUpdated = DateTime.Now; + + return cq; + } + } +} diff --git a/JMMServer/Commands/CommandRequest_MovieDBSearchAnime.cs b/JMMServer/Commands/CommandRequest_MovieDBSearchAnime.cs new file mode 100644 index 000000000..6076451f0 --- /dev/null +++ b/JMMServer/Commands/CommandRequest_MovieDBSearchAnime.cs @@ -0,0 +1,179 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Entities; +using JMMServer.Repositories; +using JMMServer.Providers.TvDB; +using JMMServer.WebCache; +using System.Xml; +using JMMServer.Providers.MovieDB; + +namespace JMMServer.Commands +{ + [Serializable] + public class CommandRequest_MovieDBSearchAnime : CommandRequestImplementation, ICommandRequest + { + public int AnimeID { get; set; } + public bool ForceRefresh { get; set; } + + public CommandRequestPriority DefaultPriority + { + get { return CommandRequestPriority.Priority9; } + } + + public string PrettyDescription + { + get + { + return string.Format("Searching for anime on The MovieDB: {0}", AnimeID); + } + } + + public CommandRequest_MovieDBSearchAnime() + { + } + + public CommandRequest_MovieDBSearchAnime(int animeID, bool forced) + { + this.AnimeID = animeID; + this.ForceRefresh = forced; + this.CommandType = (int)CommandRequestType.MovieDB_SearchAnime; + this.Priority = (int)DefaultPriority; + + GenerateCommandID(); + } + + public override void ProcessCommand() + { + logger.Info("Processing CommandRequest_MovieDBSearchAnime: {0}", AnimeID); + + try + { + // first check if the user wants to use the web cache + if (ServerSettings.WebCache_TvDB_Get) + { + try + { + MovieDB_MovieRepository repMovies = new MovieDB_MovieRepository(); + + CrossRef_AniDB_OtherResult crossRef = XMLService.Get_CrossRef_AniDB_Other(AnimeID, CrossRefType.MovieDB); + if (crossRef != null) + { + int movieID = int.Parse(crossRef.CrossRefID); + MovieDB_Movie movie = repMovies.GetByOnlineID(movieID); + if (movie == null) + { + // update the info from online + MovieDBHelper.UpdateMovieInfo(movieID, true); + movie = repMovies.GetByOnlineID(movieID); + } + + if (movie != null) + { + // since we are using the web cache result, let's save it + MovieDBHelper.LinkAniDBMovieDB(AnimeID, movieID, true); + return; + } + + } + } + catch (Exception) + { + } + } + + string searchCriteria = ""; + AniDB_AnimeRepository repAnime = new AniDB_AnimeRepository(); + AniDB_Anime anime = repAnime.GetByAnimeID(AnimeID); + if (anime == null) return; + + searchCriteria = anime.MainTitle; + + // if not wanting to use web cache, or no match found on the web cache go to TvDB directly + List results = MovieDBHelper.Search(searchCriteria); + logger.Trace("Found {0} moviedb results for {1} on TheTvDB", results.Count, searchCriteria); + if (ProcessSearchResults(results, searchCriteria)) return; + + + if (results.Count == 0) + { + foreach (AniDB_Anime_Title title in anime.Titles) + { + if (title.TitleType.ToUpper() != Constants.AnimeTitleType.Official.ToUpper()) continue; + + if (searchCriteria.ToUpper() == title.Title.ToUpper()) continue; + + results = MovieDBHelper.Search(title.Title); + logger.Trace("Found {0} moviedb results for search on {1}", results.Count, title.Title); + if (ProcessSearchResults(results, title.Title)) return; + } + } + + } + catch (Exception ex) + { + logger.Error("Error processing CommandRequest_TvDBSearchAnime: {0} - {1}", AnimeID, ex.ToString()); + return; + } + } + + private bool ProcessSearchResults(List results, string searchCriteria) + { + if (results.Count == 1) + { + // since we are using this result, lets download the info + logger.Trace("Found 1 moviedb results for search on {0} --- Linked to {1} ({2})", searchCriteria, results[0].MovieName, results[0].MovieID); + + int movieID = results[0].MovieID; + MovieDBHelper.UpdateMovieInfo(movieID, true); + MovieDBHelper.LinkAniDBMovieDB(AnimeID, movieID, false); + return true; + } + + return false; + } + + public override void GenerateCommandID() + { + this.CommandID = string.Format("CommandRequest_MovieDBSearchAnime{0}", this.AnimeID); + } + + public override bool LoadFromDBCommand(CommandRequest cq) + { + this.CommandID = cq.CommandID; + this.CommandRequestID = cq.CommandRequestID; + this.CommandType = cq.CommandType; + this.Priority = cq.Priority; + this.CommandDetails = cq.CommandDetails; + this.DateTimeUpdated = cq.DateTimeUpdated; + + // read xml to get parameters + if (this.CommandDetails.Trim().Length > 0) + { + XmlDocument docCreator = new XmlDocument(); + docCreator.LoadXml(this.CommandDetails); + + // populate the fields + this.AnimeID = int.Parse(TryGetProperty(docCreator, "CommandRequest_MovieDBSearchAnime", "AnimeID")); + this.ForceRefresh = bool.Parse(TryGetProperty(docCreator, "CommandRequest_MovieDBSearchAnime", "ForceRefresh")); + } + + return true; + } + + public override CommandRequest ToDatabaseObject() + { + GenerateCommandID(); + + CommandRequest cq = new CommandRequest(); + cq.CommandID = this.CommandID; + cq.CommandType = this.CommandType; + cq.Priority = this.Priority; + cq.CommandDetails = this.ToXML(); + cq.DateTimeUpdated = DateTime.Now; + + return cq; + } + } +} diff --git a/JMMServer/Commands/CommandRequest_ProcessFile.cs b/JMMServer/Commands/CommandRequest_ProcessFile.cs new file mode 100644 index 000000000..0531ce2a7 --- /dev/null +++ b/JMMServer/Commands/CommandRequest_ProcessFile.cs @@ -0,0 +1,300 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Entities; +using System.IO; +using JMMServer.Repositories; +using JMMContracts; +using JMMFileHelper; +using AniDBAPI; +using System.Xml; +using JMMServer.WebCache; + +namespace JMMServer.Commands +{ + [Serializable] + public class CommandRequest_ProcessFile : CommandRequestImplementation, ICommandRequest + { + + public int VideoLocalID { get; set; } + + private VideoLocal vlocal = null; + + public CommandRequestPriority DefaultPriority + { + get { return CommandRequestPriority.Priority3; } + } + + public string PrettyDescription + { + get + { + if (vlocal != null) + return string.Format("Getting file info from UDP API: {0}", vlocal.FullServerPath); + else + return string.Format("Getting file info from UDP API: {0}", VideoLocalID); + } + } + + public CommandRequest_ProcessFile() + { + } + + public CommandRequest_ProcessFile(int vidLocalID) + { + this.VideoLocalID = vidLocalID; + this.CommandType = (int)CommandRequestType.ProcessFile; + this.Priority = (int)DefaultPriority; + + GenerateCommandID(); + } + + public override void ProcessCommand() + { + logger.Info("Processing File: {0}", VideoLocalID); + + + try + { + VideoLocalRepository repVids = new VideoLocalRepository(); + vlocal = repVids.GetByID(VideoLocalID); + if (vlocal == null) return; + + //now that we have all the has info, we can get the AniDB Info + ProcessFile_AniDB(vlocal); + } + catch (Exception ex) + { + logger.Error("Error processing CommandRequest_ProcessFile: {0} - {1}", VideoLocalID, ex.ToString()); + return; + } + + // TODO update stats for group and series + + // TODO check for TvDB + } + + 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 = repAniFile.GetByHash(vidLocal.Hash); + + if (aniFile == null) + logger.Trace("AniDB_File record not found"); + + int animeID = 0; + + //if (!vidLocal.FilePath.ToLower().Contains("chobits")) return; + + 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) + { + // save to the database + aniFile = new AniDB_File(); + aniFile.Populate(fileInfo); + + //overwrite with local file name + string localFileName = Path.GetFileName(vidLocal.FilePath); + aniFile.FileName = localFileName; + + repAniFile.Save(aniFile); + aniFile.CreateLanguages(); + aniFile.CreateCrossEpisodes(localFileName); + + 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 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) + foreach (CrossRef_File_Episode xref in aniFile.EpisodeCrossRefs) + { + AniDB_Episode ep = repAniEps.GetByEpisodeID(xref.EpisodeID); + if (ep == null) + missingEpisodes = true; + + animeID = xref.AnimeID; + } + } + + AniDB_Anime anime = null; + if (missingEpisodes) + { + logger.Debug("Getting Anime record from AniDB...."); + anime = JMMService.AnidbProcessor.GetAnimeInfoHTTP(animeID, true, ServerSettings.AniDB_DownloadRelatedAnime); + } + else + { + // get from DB + anime = repAniAnime.GetByAnimeID(animeID); + } + + // 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.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.Anime.MainTitle); + cmdTrakt.Save(); + } + } + + /// + /// This should generate a unique key for a command + /// It will be used to check whether the command has already been queued before adding it + /// + public override void GenerateCommandID() + { + this.CommandID = string.Format("CommandRequest_ProcessFile_{0}", this.VideoLocalID); + } + + public override bool LoadFromDBCommand(CommandRequest cq) + { + this.CommandID = cq.CommandID; + this.CommandRequestID = cq.CommandRequestID; + this.CommandType = cq.CommandType; + this.Priority = cq.Priority; + this.CommandDetails = cq.CommandDetails; + this.DateTimeUpdated = cq.DateTimeUpdated; + + // read xml to get parameters + if (this.CommandDetails.Trim().Length > 0) + { + XmlDocument docCreator = new XmlDocument(); + docCreator.LoadXml(this.CommandDetails); + + // populate the fields + this.VideoLocalID = int.Parse(TryGetProperty(docCreator, "CommandRequest_ProcessFile", "VideoLocalID")); + } + + return true; + } + + public override CommandRequest ToDatabaseObject() + { + GenerateCommandID(); + + CommandRequest cq = new CommandRequest(); + cq.CommandID = this.CommandID; + cq.CommandType = this.CommandType; + cq.Priority = this.Priority; + cq.CommandDetails = this.ToXML(); + cq.DateTimeUpdated = DateTime.Now; + + return cq; + } + } +} diff --git a/JMMServer/Commands/ICommandRequest.cs b/JMMServer/Commands/ICommandRequest.cs new file mode 100644 index 000000000..43a40a91c --- /dev/null +++ b/JMMServer/Commands/ICommandRequest.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Entities; + +namespace JMMServer.Commands +{ + public interface ICommandRequest + { + void ProcessCommand(); + bool LoadFromDBCommand(CommandRequest cq); + CommandRequestPriority DefaultPriority { get; } + string PrettyDescription { get; } + } +} diff --git a/JMMServer/Commands/QueueCountEventArgs.cs b/JMMServer/Commands/QueueCountEventArgs.cs new file mode 100644 index 000000000..c6d31691d --- /dev/null +++ b/JMMServer/Commands/QueueCountEventArgs.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace JMMServer.Commands +{ + public class QueueCountEventArgs : EventArgs + { + public readonly int QueueCount; + + public QueueCountEventArgs(int queueCount) + { + QueueCount = queueCount; + } + } +} diff --git a/JMMServer/Commands/QueueStateEventArgs.cs b/JMMServer/Commands/QueueStateEventArgs.cs new file mode 100644 index 000000000..9ebddb42c --- /dev/null +++ b/JMMServer/Commands/QueueStateEventArgs.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace JMMServer.Commands +{ + public class QueueStateEventArgs : EventArgs + { + public readonly string QueueState; + + public QueueStateEventArgs(string queueState) + { + QueueState = queueState; + } + } +} diff --git a/JMMServer/Commands/Trakt/CommandRequest_TraktSearchAnime.cs b/JMMServer/Commands/Trakt/CommandRequest_TraktSearchAnime.cs new file mode 100644 index 000000000..7df6ecd1e --- /dev/null +++ b/JMMServer/Commands/Trakt/CommandRequest_TraktSearchAnime.cs @@ -0,0 +1,227 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Xml; +using JMMServer.Entities; +using JMMServer.Repositories; +using JMMServer.Providers.TvDB; +using JMMServer.WebCache; +using JMMServer.Providers.TraktTV; + +namespace JMMServer.Commands +{ + [Serializable] + public class CommandRequest_TraktSearchAnime : CommandRequestImplementation, ICommandRequest + { + public int AnimeID { get; set; } + public bool ForceRefresh { get; set; } + + public CommandRequestPriority DefaultPriority + { + get { return CommandRequestPriority.Priority9; } + } + + public string PrettyDescription + { + get + { + return string.Format("Searching for anime on Trakt.TV: {0}", AnimeID); + } + } + + public CommandRequest_TraktSearchAnime() + { + } + + public CommandRequest_TraktSearchAnime(int animeID, bool forced) + { + this.AnimeID = animeID; + this.ForceRefresh = forced; + this.CommandType = (int)CommandRequestType.Trakt_SearchAnime; + this.Priority = (int)DefaultPriority; + + GenerateCommandID(); + } + + + + public override void ProcessCommand() + { + logger.Info("Processing CommandRequest_TraktSearchAnime: {0}", AnimeID); + + try + { + // first check if the user wants to use the web cache + if (ServerSettings.WebCache_TvDB_Get) + { + try + { + CrossRef_AniDB_TraktResult crossRef = XMLService.Get_CrossRef_AniDB_Trakt(AnimeID); + if (crossRef != null) + { + TraktTVShowResponse showInfo = TraktTVHelper.GetShowInfo(crossRef.TraktID); + if (showInfo != null) + { + logger.Trace("Found trakt match on web cache for {0} - id = {1}", AnimeID, showInfo.title); + TraktTVHelper.LinkAniDBTrakt(AnimeID, crossRef.TraktID, crossRef.TraktSeasonNumber, true); + return; + } + } + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + } + } + + + // lets try to see locally if we have a tvDB link for this anime + // Trakt allows the use of TvDB ID's or their own Trakt ID's + CrossRef_AniDB_TvDBRepository repCrossRefTvDB = new CrossRef_AniDB_TvDBRepository(); + CrossRef_AniDB_TvDB xrefTvDB = repCrossRefTvDB.GetByAnimeID(AnimeID); + if (xrefTvDB != null) + { + TraktTVShowResponse showInfo = TraktTVHelper.GetShowInfo(xrefTvDB.TvDBID); + if (showInfo != null) + { + // make sure the season specified by TvDB also exists on Trakt + Trakt_ShowRepository repShow = new Trakt_ShowRepository(); + Trakt_Show traktShow = repShow.GetByTraktID(showInfo.TraktID); + if (traktShow != null) + { + Trakt_SeasonRepository repSeasons = new Trakt_SeasonRepository(); + Trakt_Season traktSeason = repSeasons.GetByShowIDAndSeason(traktShow.Trakt_ShowID, xrefTvDB.TvDBSeasonNumber); + if (traktSeason != null) + { + logger.Trace("Found trakt match using TvDBID locally {0} - id = {1}", AnimeID, showInfo.title); + TraktTVHelper.LinkAniDBTrakt(AnimeID, showInfo.TraktID, traktSeason.Season, true); + return; + } + } + } + } + + // if not lets try the tvdb web cache based on the same reasoning + if (ServerSettings.WebCache_TvDB_Get) + { + CrossRef_AniDB_TvDBResult crossRefTvDB = XMLService.Get_CrossRef_AniDB_TvDB(AnimeID); + if (crossRefTvDB != null) + { + TraktTVShowResponse showInfo = TraktTVHelper.GetShowInfo(crossRefTvDB.TvDBID); + if (showInfo != null) + { + // make sure the season specified by TvDB also exists on Trakt + Trakt_ShowRepository repShow = new Trakt_ShowRepository(); + Trakt_Show traktShow = repShow.GetByTraktID(showInfo.TraktID); + if (traktShow != null) + { + Trakt_SeasonRepository repSeasons = new Trakt_SeasonRepository(); + Trakt_Season traktSeason = repSeasons.GetByShowIDAndSeason(traktShow.Trakt_ShowID, crossRefTvDB.TvDBSeasonNumber); + if (traktSeason != null) + { + logger.Trace("Found trakt match on web cache by using TvDBID {0} - id = {1}", AnimeID, showInfo.title); + TraktTVHelper.LinkAniDBTrakt(AnimeID, showInfo.TraktID, traktSeason.Season, true); + return; + } + } + } + } + } + + // finally lets try searching Trakt directly + string searchCriteria = ""; + AniDB_AnimeRepository repAnime = new AniDB_AnimeRepository(); + AniDB_Anime anime = repAnime.GetByAnimeID(AnimeID); + if (anime == null) return; + + searchCriteria = anime.MainTitle; + + // if not wanting to use web cache, or no match found on the web cache go to TvDB directly + List results = TraktTVHelper.SearchShow(searchCriteria); + logger.Trace("Found {0} trakt results for {1} ", results.Count, searchCriteria); + if (ProcessSearchResults(results, searchCriteria)) return; + + + if (results.Count == 0) + { + foreach (AniDB_Anime_Title title in anime.Titles) + { + if (title.TitleType.ToUpper() != Constants.AnimeTitleType.Official.ToUpper()) continue; + + if (searchCriteria.ToUpper() == title.Title.ToUpper()) continue; + + results = TraktTVHelper.SearchShow(searchCriteria); + logger.Trace("Found {0} trakt results for search on {1}", results.Count, title.Title); + if (ProcessSearchResults(results, title.Title)) return; + } + } + + } + catch (Exception ex) + { + logger.Error("Error processing CommandRequest_TvDBSearchAnime: {0} - {1}", AnimeID, ex.ToString()); + return; + } + } + + private bool ProcessSearchResults(List results, string searchCriteria) + { + if (results.Count == 1) + { + // since we are using this result, lets download the info + logger.Trace("Found 1 trakt results for search on {0} --- Linked to {1} ({2})", searchCriteria, results[0].title, results[0].TraktID); + TraktTVShowResponse showInfo = TraktTVHelper.GetShowInfo(results[0].TraktID); + if (showInfo != null) + { + TraktTVHelper.LinkAniDBTrakt(AnimeID, showInfo.TraktID, 1, false); + return true; + } + } + + return false; + } + + public override void GenerateCommandID() + { + this.CommandID = string.Format("CommandRequest_TraktSearchAnime{0}", this.AnimeID); + } + + public override bool LoadFromDBCommand(CommandRequest cq) + { + this.CommandID = cq.CommandID; + this.CommandRequestID = cq.CommandRequestID; + this.CommandType = cq.CommandType; + this.Priority = cq.Priority; + this.CommandDetails = cq.CommandDetails; + this.DateTimeUpdated = cq.DateTimeUpdated; + + // read xml to get parameters + if (this.CommandDetails.Trim().Length > 0) + { + XmlDocument docCreator = new XmlDocument(); + docCreator.LoadXml(this.CommandDetails); + + // populate the fields + this.AnimeID = int.Parse(TryGetProperty(docCreator, "CommandRequest_TraktSearchAnime", "AnimeID")); + this.ForceRefresh = bool.Parse(TryGetProperty(docCreator, "CommandRequest_TraktSearchAnime", "ForceRefresh")); + } + + return true; + } + + public override CommandRequest ToDatabaseObject() + { + GenerateCommandID(); + + CommandRequest cq = new CommandRequest(); + cq.CommandID = this.CommandID; + cq.CommandType = this.CommandType; + cq.Priority = this.Priority; + cq.CommandDetails = this.ToXML(); + cq.DateTimeUpdated = DateTime.Now; + + return cq; + } + } +} diff --git a/JMMServer/Commands/Trakt/CommandRequest_TraktShowEpisodeUnseen.cs b/JMMServer/Commands/Trakt/CommandRequest_TraktShowEpisodeUnseen.cs new file mode 100644 index 000000000..f5c9ff10e --- /dev/null +++ b/JMMServer/Commands/Trakt/CommandRequest_TraktShowEpisodeUnseen.cs @@ -0,0 +1,111 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Entities; +using System.Xml; +using JMMServer.Repositories; +using JMMServer.Providers.TraktTV; + +namespace JMMServer.Commands +{ + [Serializable] + public class CommandRequest_TraktShowEpisodeUnseen : CommandRequestImplementation, ICommandRequest + { + public int AnimeEpisodeID { get; set; } + + public CommandRequestPriority DefaultPriority + { + get { return CommandRequestPriority.Priority9; } + } + + public string PrettyDescription + { + get + { + return string.Format("Marking episode as unseen on Trakt for episode: {0}", AnimeEpisodeID); + } + } + + public CommandRequest_TraktShowEpisodeUnseen() + { + } + + public CommandRequest_TraktShowEpisodeUnseen(int animeEpisodeID) + { + this.AnimeEpisodeID = animeEpisodeID; + this.CommandType = (int)CommandRequestType.Trakt_ShowEpisodeUnseen; + this.Priority = (int)DefaultPriority; + + GenerateCommandID(); + } + + public override void ProcessCommand() + { + logger.Info("Processing CommandRequest_TraktShowEpisodeUnseen: {0}", AnimeEpisodeID); + + try + { + AnimeEpisodeRepository repEps = new AnimeEpisodeRepository(); + AnimeEpisode ep = repEps.GetByID(AnimeEpisodeID); + if (ep == null) + { + logger.Error("Could not find anime epiosde: {0}", AnimeEpisodeID); + return; + } + + TraktTVHelper.MarkEpisodeUnwatched(ep); + } + catch (Exception ex) + { + logger.Error("Error processing CommandRequest_TraktShowEpisodeUnseen: {0} - {1}", AnimeEpisodeID, ex.ToString()); + return; + } + } + + /// + /// This should generate a unique key for a command + /// It will be used to check whether the command has already been queued before adding it + /// + public override void GenerateCommandID() + { + this.CommandID = string.Format("CommandRequest_TraktShowEpisodeUnseen_{0}", AnimeEpisodeID); + } + + public override bool LoadFromDBCommand(CommandRequest cq) + { + this.CommandID = cq.CommandID; + this.CommandRequestID = cq.CommandRequestID; + this.CommandType = cq.CommandType; + this.Priority = cq.Priority; + this.CommandDetails = cq.CommandDetails; + this.DateTimeUpdated = cq.DateTimeUpdated; + + // read xml to get parameters + if (this.CommandDetails.Trim().Length > 0) + { + XmlDocument docCreator = new XmlDocument(); + docCreator.LoadXml(this.CommandDetails); + + // populate the fields + this.AnimeEpisodeID = int.Parse(TryGetProperty(docCreator, "CommandRequest_TraktShowEpisodeUnseen", "AnimeEpisodeID")); + } + + return true; + } + + public override CommandRequest ToDatabaseObject() + { + GenerateCommandID(); + + CommandRequest cq = new CommandRequest(); + cq.CommandID = this.CommandID; + cq.CommandType = this.CommandType; + cq.Priority = this.Priority; + cq.CommandDetails = this.ToXML(); + cq.DateTimeUpdated = DateTime.Now; + + return cq; + } + } +} diff --git a/JMMServer/Commands/Trakt/CommandRequest_TraktShowScrobble.cs b/JMMServer/Commands/Trakt/CommandRequest_TraktShowScrobble.cs new file mode 100644 index 000000000..c3c59362b --- /dev/null +++ b/JMMServer/Commands/Trakt/CommandRequest_TraktShowScrobble.cs @@ -0,0 +1,111 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Entities; +using System.Xml; +using JMMServer.Repositories; +using JMMServer.Providers.TraktTV; + +namespace JMMServer.Commands +{ + [Serializable] + public class CommandRequest_TraktShowScrobble : CommandRequestImplementation, ICommandRequest + { + public int AnimeEpisodeID { get; set; } + + public CommandRequestPriority DefaultPriority + { + get { return CommandRequestPriority.Priority9; } + } + + public string PrettyDescription + { + get + { + return string.Format("Scrobbling show on Trakt: {0}", AnimeEpisodeID); + } + } + + public CommandRequest_TraktShowScrobble() + { + } + + public CommandRequest_TraktShowScrobble(int animeEpisodeID) + { + this.AnimeEpisodeID = animeEpisodeID; + this.CommandType = (int)CommandRequestType.Trakt_ShowScrobble; + this.Priority = (int)DefaultPriority; + + GenerateCommandID(); + } + + public override void ProcessCommand() + { + logger.Info("Processing CommandRequest_TraktShowScrobble: {0}", AnimeEpisodeID); + + try + { + AnimeEpisodeRepository repEpisodes = new AnimeEpisodeRepository(); + AnimeEpisode ep = repEpisodes.GetByID(AnimeEpisodeID); + if (ep != null) + { + // before scrobbling try to ensure the episode is in the users collection by sync'ing the series + TraktTVHelper.SyncCollectionToTrakt_Series(ep.AnimeSeries); + + TraktTVHelper.MarkEpisodeWatched(ep); + } + } + catch (Exception ex) + { + logger.Error("Error processing CommandRequest_TraktShowScrobble: {0} - {1}", AnimeEpisodeID, ex.ToString()); + return; + } + } + + /// + /// This should generate a unique key for a command + /// It will be used to check whether the command has already been queued before adding it + /// + public override void GenerateCommandID() + { + this.CommandID = string.Format("CommandRequest_TraktShowScrobble{0}", AnimeEpisodeID); + } + + public override bool LoadFromDBCommand(CommandRequest cq) + { + this.CommandID = cq.CommandID; + this.CommandRequestID = cq.CommandRequestID; + this.CommandType = cq.CommandType; + this.Priority = cq.Priority; + this.CommandDetails = cq.CommandDetails; + this.DateTimeUpdated = cq.DateTimeUpdated; + + // read xml to get parameters + if (this.CommandDetails.Trim().Length > 0) + { + XmlDocument docCreator = new XmlDocument(); + docCreator.LoadXml(this.CommandDetails); + + // populate the fields + this.AnimeEpisodeID = int.Parse(TryGetProperty(docCreator, "CommandRequest_TraktShowScrobble", "AnimeEpisodeID")); + } + + return true; + } + + public override CommandRequest ToDatabaseObject() + { + GenerateCommandID(); + + CommandRequest cq = new CommandRequest(); + cq.CommandID = this.CommandID; + cq.CommandType = this.CommandType; + cq.Priority = this.Priority; + cq.CommandDetails = this.ToXML(); + cq.DateTimeUpdated = DateTime.Now; + + return cq; + } + } +} diff --git a/JMMServer/Commands/Trakt/CommandRequest_TraktSyncCollection.cs b/JMMServer/Commands/Trakt/CommandRequest_TraktSyncCollection.cs new file mode 100644 index 000000000..89721cf04 --- /dev/null +++ b/JMMServer/Commands/Trakt/CommandRequest_TraktSyncCollection.cs @@ -0,0 +1,125 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Entities; +using System.Xml; +using JMMServer.Repositories; +using JMMServer.Providers.TraktTV; + +namespace JMMServer.Commands +{ + + [Serializable] + public class CommandRequest_TraktSyncCollection : CommandRequestImplementation, ICommandRequest + { + public bool ForceRefresh { get; set; } + + public CommandRequestPriority DefaultPriority + { + get { return CommandRequestPriority.Priority8; } + } + + public string PrettyDescription + { + get + { + return string.Format("Sync'ing Trakt Collection"); + } + } + + public CommandRequest_TraktSyncCollection() + { + } + + public CommandRequest_TraktSyncCollection(bool forced) + { + this.CommandType = (int)CommandRequestType.Trakt_SyncCollection; + this.Priority = (int)DefaultPriority; + + GenerateCommandID(); + } + + public override void ProcessCommand() + { + logger.Info("Processing CommandRequest_TraktSyncCollection"); + + try + { + ScheduledUpdateRepository repSched = new ScheduledUpdateRepository(); + ScheduledUpdate sched = repSched.GetByUpdateType((int)ScheduledUpdateType.TraktSync); + if (sched == null) + { + sched = new ScheduledUpdate(); + sched.UpdateType = (int)ScheduledUpdateType.TraktSync; + sched.UpdateDetails = ""; + } + else + { + int freqHours = Utils.GetScheduledHours(ServerSettings.Trakt_SyncFrequency); + + // if we have run this in the last xxx hours then exit + TimeSpan tsLastRun = DateTime.Now - sched.LastUpdate; + if (tsLastRun.TotalHours < freqHours) + { + if (!ForceRefresh) return; + } + } + sched.LastUpdate = DateTime.Now; + repSched.Save(sched); + + TraktTVHelper.SyncCollectionToTrakt(); + } + catch (Exception ex) + { + logger.Error("Error processing CommandRequest_TraktSyncCollection: {0}", ex.ToString()); + return; + } + } + + /// + /// This should generate a unique key for a command + /// It will be used to check whether the command has already been queued before adding it + /// + public override void GenerateCommandID() + { + this.CommandID = string.Format("CommandRequest_TraktSyncCollection"); + } + + public override bool LoadFromDBCommand(CommandRequest cq) + { + this.CommandID = cq.CommandID; + this.CommandRequestID = cq.CommandRequestID; + this.CommandType = cq.CommandType; + this.Priority = cq.Priority; + this.CommandDetails = cq.CommandDetails; + this.DateTimeUpdated = cq.DateTimeUpdated; + + // read xml to get parameters + if (this.CommandDetails.Trim().Length > 0) + { + XmlDocument docCreator = new XmlDocument(); + docCreator.LoadXml(this.CommandDetails); + + // populate the fields + this.ForceRefresh = bool.Parse(TryGetProperty(docCreator, "CommandRequest_TraktSyncCollection", "ForceRefresh")); + } + + return true; + } + + public override CommandRequest ToDatabaseObject() + { + GenerateCommandID(); + + CommandRequest cq = new CommandRequest(); + cq.CommandID = this.CommandID; + cq.CommandType = this.CommandType; + cq.Priority = this.Priority; + cq.CommandDetails = this.ToXML(); + cq.DateTimeUpdated = DateTime.Now; + + return cq; + } + } +} diff --git a/JMMServer/Commands/Trakt/CommandRequest_TraktSyncCollectionSeries.cs b/JMMServer/Commands/Trakt/CommandRequest_TraktSyncCollectionSeries.cs new file mode 100644 index 000000000..03e2952d4 --- /dev/null +++ b/JMMServer/Commands/Trakt/CommandRequest_TraktSyncCollectionSeries.cs @@ -0,0 +1,114 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Entities; +using System.Xml; +using JMMServer.Repositories; +using JMMServer.Providers.TraktTV; + +namespace JMMServer.Commands +{ + [Serializable] + public class CommandRequest_TraktSyncCollectionSeries : CommandRequestImplementation, ICommandRequest + { + public int AnimeSeriesID { get; set; } + public string SeriesName { get; set; } + + public CommandRequestPriority DefaultPriority + { + get { return CommandRequestPriority.Priority9; } + } + + public string PrettyDescription + { + get + { + return string.Format("Sync'ing Trakt Collectionfor series: {0}", SeriesName); + } + } + + public CommandRequest_TraktSyncCollectionSeries() + { + } + + public CommandRequest_TraktSyncCollectionSeries(int animeSeriesID, string seriesName) + { + this.AnimeSeriesID = animeSeriesID; + this.SeriesName = seriesName; + this.CommandType = (int)CommandRequestType.Trakt_SyncCollectionSeries; + this.Priority = (int)DefaultPriority; + + GenerateCommandID(); + } + + public override void ProcessCommand() + { + logger.Info("Processing CommandRequest_TraktSyncCollectionSeries"); + + try + { + AnimeSeriesRepository repSeries = new AnimeSeriesRepository(); + AnimeSeries series = repSeries.GetByID(AnimeSeriesID); + if (series == null) + { + logger.Error("Could not find anime series: {0}", AnimeSeriesID); + return; + } + + TraktTVHelper.SyncCollectionToTrakt_Series(series); + } + catch (Exception ex) + { + logger.Error("Error processing CommandRequest_TraktSyncCollectionSeries: {0}", ex.ToString()); + return; + } + } + + /// + /// This should generate a unique key for a command + /// It will be used to check whether the command has already been queued before adding it + /// + public override void GenerateCommandID() + { + this.CommandID = string.Format("CommandRequest_TraktSyncCollectionSeries_{0}", AnimeSeriesID); + } + + public override bool LoadFromDBCommand(CommandRequest cq) + { + this.CommandID = cq.CommandID; + this.CommandRequestID = cq.CommandRequestID; + this.CommandType = cq.CommandType; + this.Priority = cq.Priority; + this.CommandDetails = cq.CommandDetails; + this.DateTimeUpdated = cq.DateTimeUpdated; + + // read xml to get parameters + if (this.CommandDetails.Trim().Length > 0) + { + XmlDocument docCreator = new XmlDocument(); + docCreator.LoadXml(this.CommandDetails); + + // populate the fields + this.AnimeSeriesID = int.Parse(TryGetProperty(docCreator, "CommandRequest_TraktSyncCollectionSeries", "AnimeSeriesID")); + this.SeriesName = TryGetProperty(docCreator, "CommandRequest_TraktSyncCollectionSeries", "SeriesName"); + } + + return true; + } + + public override CommandRequest ToDatabaseObject() + { + GenerateCommandID(); + + CommandRequest cq = new CommandRequest(); + cq.CommandID = this.CommandID; + cq.CommandType = this.CommandType; + cq.Priority = this.Priority; + cq.CommandDetails = this.ToXML(); + cq.DateTimeUpdated = DateTime.Now; + + return cq; + } + } +} diff --git a/JMMServer/Commands/Trakt/CommandRequest_TraktUpdateAllSeries.cs b/JMMServer/Commands/Trakt/CommandRequest_TraktUpdateAllSeries.cs new file mode 100644 index 000000000..ff534cf21 --- /dev/null +++ b/JMMServer/Commands/Trakt/CommandRequest_TraktUpdateAllSeries.cs @@ -0,0 +1,129 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Entities; +using System.Xml; +using JMMServer.Repositories; +using JMMServer.Providers.TraktTV; + +namespace JMMServer.Commands +{ + [Serializable] + public class CommandRequest_TraktUpdateAllSeries : CommandRequestImplementation, ICommandRequest + { + public bool ForceRefresh { get; set; } + + + public CommandRequestPriority DefaultPriority + { + get { return CommandRequestPriority.Priority9; } + } + + public string PrettyDescription + { + get + { + return string.Format("Updating all Trakt Series Info"); + } + } + + public CommandRequest_TraktUpdateAllSeries() + { + } + + public CommandRequest_TraktUpdateAllSeries(bool forced) + { + this.CommandType = (int)CommandRequestType.Trakt_UpdateAllSeries; + this.Priority = (int)DefaultPriority; + + GenerateCommandID(); + } + + public override void ProcessCommand() + { + logger.Info("Processing CommandRequest_TraktUpdateAllSeries"); + + try + { + ScheduledUpdateRepository repSched = new ScheduledUpdateRepository(); + ScheduledUpdate sched = repSched.GetByUpdateType((int)ScheduledUpdateType.TraktUpdate); + if (sched == null) + { + sched = new ScheduledUpdate(); + sched.UpdateType = (int)ScheduledUpdateType.TraktUpdate; + sched.UpdateDetails = ""; + } + else + { + int freqHours = Utils.GetScheduledHours(ServerSettings.Trakt_UpdateFrequency); + + // if we have run this in the last xxx hours then exit + TimeSpan tsLastRun = DateTime.Now - sched.LastUpdate; + if (tsLastRun.TotalHours < freqHours) + { + if (!ForceRefresh) return; + } + } + sched.LastUpdate = DateTime.Now; + repSched.Save(sched); + + // update all info + TraktTVHelper.UpdateAllInfo(); + + // scan for new matches + TraktTVHelper.ScanForMatches(); + } + catch (Exception ex) + { + logger.Error("Error processing CommandRequest_TraktUpdateAllSeries: {0}", ex.ToString()); + return; + } + } + + /// + /// This should generate a unique key for a command + /// It will be used to check whether the command has already been queued before adding it + /// + public override void GenerateCommandID() + { + this.CommandID = string.Format("CommandRequest_TraktUpdateAllSeries"); + } + + public override bool LoadFromDBCommand(CommandRequest cq) + { + this.CommandID = cq.CommandID; + this.CommandRequestID = cq.CommandRequestID; + this.CommandType = cq.CommandType; + this.Priority = cq.Priority; + this.CommandDetails = cq.CommandDetails; + this.DateTimeUpdated = cq.DateTimeUpdated; + + // read xml to get parameters + if (this.CommandDetails.Trim().Length > 0) + { + XmlDocument docCreator = new XmlDocument(); + docCreator.LoadXml(this.CommandDetails); + + // populate the fields + this.ForceRefresh = bool.Parse(TryGetProperty(docCreator, "CommandRequest_TraktUpdateAllSeries", "ForceRefresh")); + } + + return true; + } + + public override CommandRequest ToDatabaseObject() + { + GenerateCommandID(); + + CommandRequest cq = new CommandRequest(); + cq.CommandID = this.CommandID; + cq.CommandType = this.CommandType; + cq.Priority = this.Priority; + cq.CommandDetails = this.ToXML(); + cq.DateTimeUpdated = DateTime.Now; + + return cq; + } + } +} diff --git a/JMMServer/Commands/Trakt/CommandRequest_TraktUpdateInfoAndImages.cs b/JMMServer/Commands/Trakt/CommandRequest_TraktUpdateInfoAndImages.cs new file mode 100644 index 000000000..d007ae685 --- /dev/null +++ b/JMMServer/Commands/Trakt/CommandRequest_TraktUpdateInfoAndImages.cs @@ -0,0 +1,106 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Xml; +using JMMServer.Entities; +using JMMServer.Repositories; +using JMMServer.Providers.TvDB; +using JMMServer.WebCache; +using JMMServer.Providers.TraktTV; + +namespace JMMServer.Commands +{ + [Serializable] + public class CommandRequest_TraktUpdateInfoAndImages : CommandRequestImplementation, ICommandRequest + { + public string TraktID { get; set; } + + public CommandRequestPriority DefaultPriority + { + get { return CommandRequestPriority.Priority9; } + } + + public string PrettyDescription + { + get + { + return string.Format("Updating info/images on Trakt.TV: {0}", TraktID); + } + } + + public CommandRequest_TraktUpdateInfoAndImages() + { + } + + public CommandRequest_TraktUpdateInfoAndImages(string traktID) + { + this.TraktID = traktID; + this.CommandType = (int)CommandRequestType.Trakt_UpdateInfoImages; + this.Priority = (int)DefaultPriority; + + GenerateCommandID(); + } + + + + public override void ProcessCommand() + { + logger.Info("Processing CommandRequest_TraktUpdateInfoAndImages: {0}", TraktID); + + try + { + TraktTVHelper.UpdateAllInfoAndImages(TraktID, false); + + } + catch (Exception ex) + { + logger.Error("Error processing CommandRequest_TraktUpdateInfoAndImages: {0} - {1}", TraktID, ex.ToString()); + return; + } + } + + + + public override void GenerateCommandID() + { + this.CommandID = string.Format("CommandRequest_TraktUpdateInfoAndImages{0}", this.TraktID); + } + + public override bool LoadFromDBCommand(CommandRequest cq) + { + this.CommandID = cq.CommandID; + this.CommandRequestID = cq.CommandRequestID; + this.CommandType = cq.CommandType; + this.Priority = cq.Priority; + this.CommandDetails = cq.CommandDetails; + this.DateTimeUpdated = cq.DateTimeUpdated; + + // read xml to get parameters + if (this.CommandDetails.Trim().Length > 0) + { + XmlDocument docCreator = new XmlDocument(); + docCreator.LoadXml(this.CommandDetails); + + // populate the fields + this.TraktID = TryGetProperty(docCreator, "CommandRequest_TraktUpdateInfoAndImages", "TraktID"); + } + + return true; + } + + public override CommandRequest ToDatabaseObject() + { + GenerateCommandID(); + + CommandRequest cq = new CommandRequest(); + cq.CommandID = this.CommandID; + cq.CommandType = this.CommandType; + cq.Priority = this.Priority; + cq.CommandDetails = this.ToXML(); + cq.DateTimeUpdated = DateTime.Now; + + return cq; + } + } +} diff --git a/JMMServer/Commands/TvDB/CommandRequest_TvDBDownloadImages.cs b/JMMServer/Commands/TvDB/CommandRequest_TvDBDownloadImages.cs new file mode 100644 index 000000000..f59b02b9b --- /dev/null +++ b/JMMServer/Commands/TvDB/CommandRequest_TvDBDownloadImages.cs @@ -0,0 +1,103 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Xml; +using JMMServer.Entities; +using JMMServer.Repositories; +using JMMServer.Providers.TvDB; + +namespace JMMServer.Commands +{ + [Serializable] + public class CommandRequest_TvDBDownloadImages : CommandRequestImplementation, ICommandRequest + { + public int TvDBSeriesID { get; set; } + public bool ForceRefresh { get; set; } + + public CommandRequestPriority DefaultPriority + { + get { return CommandRequestPriority.Priority8; } + } + + public string PrettyDescription + { + get + { + return string.Format("Getting images from The TvDB: {0}", TvDBSeriesID); + } + } + + public CommandRequest_TvDBDownloadImages() + { + } + + public CommandRequest_TvDBDownloadImages(int tvDBSeriesID, bool forced) + { + this.TvDBSeriesID = tvDBSeriesID; + this.ForceRefresh = forced; + this.CommandType = (int)CommandRequestType.TvDB_DownloadImages; + this.Priority = (int)DefaultPriority; + + GenerateCommandID(); + } + + public override void ProcessCommand() + { + logger.Info("Processing CommandRequest_TvDBDownloadImages: {0}", TvDBSeriesID); + + try + { + JMMService.TvdbHelper.DownloadAutomaticImages(TvDBSeriesID, ForceRefresh); + + } + catch (Exception ex) + { + logger.Error("Error processing CommandRequest_TvDBDownloadImages: {0} - {1}", TvDBSeriesID, ex.ToString()); + return; + } + } + + public override void GenerateCommandID() + { + this.CommandID = string.Format("CommandRequest_TvDBDownloadImages_{0}", this.TvDBSeriesID); + } + + public override bool LoadFromDBCommand(CommandRequest cq) + { + this.CommandID = cq.CommandID; + this.CommandRequestID = cq.CommandRequestID; + this.CommandType = cq.CommandType; + this.Priority = cq.Priority; + this.CommandDetails = cq.CommandDetails; + this.DateTimeUpdated = cq.DateTimeUpdated; + + // read xml to get parameters + if (this.CommandDetails.Trim().Length > 0) + { + XmlDocument docCreator = new XmlDocument(); + docCreator.LoadXml(this.CommandDetails); + + // populate the fields + this.TvDBSeriesID = int.Parse(TryGetProperty(docCreator, "CommandRequest_TvDBDownloadImages", "TvDBSeriesID")); + this.ForceRefresh = bool.Parse(TryGetProperty(docCreator, "CommandRequest_TvDBDownloadImages", "ForceRefresh")); + } + + return true; + } + + public override CommandRequest ToDatabaseObject() + { + GenerateCommandID(); + + CommandRequest cq = new CommandRequest(); + cq.CommandID = this.CommandID; + cq.CommandType = this.CommandType; + cq.Priority = this.Priority; + cq.CommandDetails = this.ToXML(); + cq.DateTimeUpdated = DateTime.Now; + + return cq; + } + } +} diff --git a/JMMServer/Commands/TvDB/CommandRequest_TvDBSearchAnime.cs b/JMMServer/Commands/TvDB/CommandRequest_TvDBSearchAnime.cs new file mode 100644 index 000000000..f9e00982a --- /dev/null +++ b/JMMServer/Commands/TvDB/CommandRequest_TvDBSearchAnime.cs @@ -0,0 +1,206 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Xml; +using JMMServer.Entities; +using JMMServer.Repositories; +using JMMServer.Providers.TvDB; +using JMMServer.WebCache; + +namespace JMMServer.Commands +{ + [Serializable] + public class CommandRequest_TvDBSearchAnime : CommandRequestImplementation, ICommandRequest + { + public int AnimeID { get; set; } + public bool ForceRefresh { get; set; } + + public CommandRequestPriority DefaultPriority + { + get { return CommandRequestPriority.Priority8; } + } + + public string PrettyDescription + { + get + { + return string.Format("Searching for anime on The TvDB: {0}", AnimeID); + } + } + + public CommandRequest_TvDBSearchAnime() + { + } + + public CommandRequest_TvDBSearchAnime(int animeID, bool forced) + { + this.AnimeID = animeID; + this.ForceRefresh = forced; + this.CommandType = (int)CommandRequestType.TvDB_SearchAnime; + this.Priority = (int)DefaultPriority; + + GenerateCommandID(); + } + + public override void ProcessCommand() + { + logger.Info("Processing CommandRequest_TvDBSearchAnime: {0}", AnimeID); + + try + { + // first check if the user wants to use the web cache + if (ServerSettings.WebCache_TvDB_Get) + { + try + { + CrossRef_AniDB_TvDBResult crossRef = XMLService.Get_CrossRef_AniDB_TvDB(AnimeID); + if (crossRef != null) + { + TvDB_Series tvser = TvDBHelper.GetSeriesInfoOnline(crossRef.TvDBID); + if (tvser != null) + { + // since we are using the web cache result, let's save it + CrossRef_AniDB_TvDBRepository repCrossRefs = new CrossRef_AniDB_TvDBRepository(); + CrossRef_AniDB_TvDB xref = repCrossRefs.GetByAnimeID(AnimeID); + if (xref == null) + xref = new CrossRef_AniDB_TvDB(); + + xref.AnimeID = crossRef.AnimeID; + xref.CrossRefSource = (int)CrossRefSource.WebCache; + xref.TvDBID = crossRef.TvDBID; + xref.TvDBSeasonNumber = crossRef.TvDBSeasonNumber; + repCrossRefs.Save(xref); + + logger.Trace("Found tvdb match on web cache for {0} - id = {1}", AnimeID, tvser.SeriesID); + TvDBHelper.LinkAniDBTvDB(AnimeID, crossRef.TvDBID, crossRef.TvDBSeasonNumber, true); + return; + } + else + { + //if we got a TvDB ID from the web cache, but couldn't find it on TheTvDB.com, it could mean 2 things + //1. thetvdb.com is offline + //2. the id is no longer valid + // if the id is no longer valid we should remove it from the web cache + if (TvDBHelper.ConfirmTvDBOnline()) + { + // remove from web cache + CommandRequest_WebCacheDeleteXRefAniDBTvDBAll req = new CommandRequest_WebCacheDeleteXRefAniDBTvDBAll(crossRef.TvDBID); + req.Save(); + } + } + } + } + catch (Exception) + { + } + } + + string searchCriteria = ""; + AniDB_AnimeRepository repAnime = new AniDB_AnimeRepository(); + AniDB_Anime anime = repAnime.GetByAnimeID(AnimeID); + if (anime == null) return; + + searchCriteria = anime.MainTitle; + + // if not wanting to use web cache, or no match found on the web cache go to TvDB directly + List results = JMMService.TvdbHelper.SearchSeries(searchCriteria); + logger.Trace("Found {0} tvdb results for {1} on TheTvDB", results.Count, searchCriteria); + if (ProcessSearchResults(results, searchCriteria)) return; + + + if (results.Count == 0) + { + foreach (AniDB_Anime_Title title in anime.Titles) + { + if (title.TitleType.ToUpper() != Constants.AnimeTitleType.Official.ToUpper()) continue; + + if (searchCriteria.ToUpper() == title.Title.ToUpper()) continue; + + results = JMMService.TvdbHelper.SearchSeries(title.Title); + logger.Trace("Found {0} tvdb results for search on {1}", results.Count, title.Title); + if (ProcessSearchResults(results, title.Title)) return; + } + } + + } + catch (Exception ex) + { + logger.Error("Error processing CommandRequest_TvDBSearchAnime: {0} - {1}", AnimeID, ex.ToString()); + return; + } + } + + private bool ProcessSearchResults(List results, string searchCriteria) + { + if (results.Count == 1) + { + // since we are using this result, lets download the info + logger.Trace("Found 1 tvdb results for search on {0} --- Linked to {1} ({2})", searchCriteria, results[0].SeriesName, results[0].SeriesID); + TvDB_Series tvser = TvDBHelper.GetSeriesInfoOnline(results[0].SeriesID); + TvDBHelper.LinkAniDBTvDB(AnimeID, results[0].SeriesID, 1, false); + return true; + } + else if (results.Count > 1) + { + logger.Trace("Found multiple ({0}) tvdb results for search on so checking for english results {1}", results.Count, searchCriteria); + foreach (TVDBSeriesSearchResult sres in results) + { + if (sres.Language.Equals("en", StringComparison.InvariantCultureIgnoreCase)) + { + // since we are using this result, lets download the info + logger.Trace("Found english result for search on {0} --- Linked to {1} ({2})", searchCriteria, sres.SeriesName, sres.SeriesID); + TvDB_Series tvser = TvDBHelper.GetSeriesInfoOnline(results[0].SeriesID); + TvDBHelper.LinkAniDBTvDB(AnimeID, sres.SeriesID, 1, false); + return true; + } + } + logger.Trace("No english results found, so SKIPPING: {0}", searchCriteria); + } + + return false; + } + + public override void GenerateCommandID() + { + this.CommandID = string.Format("CommandRequest_TvDBSearchAnime{0}", this.AnimeID); + } + + public override bool LoadFromDBCommand(CommandRequest cq) + { + this.CommandID = cq.CommandID; + this.CommandRequestID = cq.CommandRequestID; + this.CommandType = cq.CommandType; + this.Priority = cq.Priority; + this.CommandDetails = cq.CommandDetails; + this.DateTimeUpdated = cq.DateTimeUpdated; + + // read xml to get parameters + if (this.CommandDetails.Trim().Length > 0) + { + XmlDocument docCreator = new XmlDocument(); + docCreator.LoadXml(this.CommandDetails); + + // populate the fields + this.AnimeID = int.Parse(TryGetProperty(docCreator, "CommandRequest_TvDBSearchAnime", "AnimeID")); + this.ForceRefresh = bool.Parse(TryGetProperty(docCreator, "CommandRequest_TvDBSearchAnime", "ForceRefresh")); + } + + return true; + } + + public override CommandRequest ToDatabaseObject() + { + GenerateCommandID(); + + CommandRequest cq = new CommandRequest(); + cq.CommandID = this.CommandID; + cq.CommandType = this.CommandType; + cq.Priority = this.Priority; + cq.CommandDetails = this.ToXML(); + cq.DateTimeUpdated = DateTime.Now; + + return cq; + } + } +} diff --git a/JMMServer/Commands/TvDB/CommandRequest_TvDBUpdateSeriesAndEpisodes.cs b/JMMServer/Commands/TvDB/CommandRequest_TvDBUpdateSeriesAndEpisodes.cs new file mode 100644 index 000000000..528bca832 --- /dev/null +++ b/JMMServer/Commands/TvDB/CommandRequest_TvDBUpdateSeriesAndEpisodes.cs @@ -0,0 +1,103 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Xml; +using JMMServer.Entities; +using JMMServer.Repositories; +using JMMServer.Providers.TvDB; + +namespace JMMServer.Commands +{ + [Serializable] + public class CommandRequest_TvDBUpdateSeriesAndEpisodes : CommandRequestImplementation, ICommandRequest + { + public int TvDBSeriesID { get; set; } + public bool ForceRefresh { get; set; } + + public CommandRequestPriority DefaultPriority + { + get { return CommandRequestPriority.Priority8; } + } + + public string PrettyDescription + { + get + { + return string.Format("Getting episodes from The TvDB: {0}", TvDBSeriesID); + } + } + + public CommandRequest_TvDBUpdateSeriesAndEpisodes() + { + } + + public CommandRequest_TvDBUpdateSeriesAndEpisodes(int tvDBSeriesID, bool forced) + { + this.TvDBSeriesID = tvDBSeriesID; + this.ForceRefresh = forced; + this.CommandType = (int)CommandRequestType.TvDB_SeriesEpisodes; + this.Priority = (int)DefaultPriority; + + GenerateCommandID(); + } + + public override void ProcessCommand() + { + logger.Info("Processing CommandRequest_TvDBUpdateSeriesAndEpisodes: {0}", TvDBSeriesID); + + try + { + JMMService.TvdbHelper.UpdateAllInfoAndImages(TvDBSeriesID, ForceRefresh); + + } + catch (Exception ex) + { + logger.Error("Error processing CommandRequest_TvDBUpdateSeriesAndEpisodes: {0} - {1}", TvDBSeriesID, ex.ToString()); + return; + } + } + + public override void GenerateCommandID() + { + this.CommandID = string.Format("CommandRequest_TvDBUpdateSeriesAndEpisodes{0}", this.TvDBSeriesID); + } + + public override bool LoadFromDBCommand(CommandRequest cq) + { + this.CommandID = cq.CommandID; + this.CommandRequestID = cq.CommandRequestID; + this.CommandType = cq.CommandType; + this.Priority = cq.Priority; + this.CommandDetails = cq.CommandDetails; + this.DateTimeUpdated = cq.DateTimeUpdated; + + // read xml to get parameters + if (this.CommandDetails.Trim().Length > 0) + { + XmlDocument docCreator = new XmlDocument(); + docCreator.LoadXml(this.CommandDetails); + + // populate the fields + this.TvDBSeriesID = int.Parse(TryGetProperty(docCreator, "CommandRequest_TvDBUpdateSeriesAndEpisodes", "TvDBSeriesID")); + this.ForceRefresh = bool.Parse(TryGetProperty(docCreator, "CommandRequest_TvDBUpdateSeriesAndEpisodes", "ForceRefresh")); + } + + return true; + } + + public override CommandRequest ToDatabaseObject() + { + GenerateCommandID(); + + CommandRequest cq = new CommandRequest(); + cq.CommandID = this.CommandID; + cq.CommandType = this.CommandType; + cq.Priority = this.Priority; + cq.CommandDetails = this.ToXML(); + cq.DateTimeUpdated = DateTime.Now; + + return cq; + } + } +} diff --git a/JMMServer/Commands/WebCache/CommandRequest_WebCacheDeleteXRefAniDBOther.cs b/JMMServer/Commands/WebCache/CommandRequest_WebCacheDeleteXRefAniDBOther.cs new file mode 100644 index 000000000..7612dda9f --- /dev/null +++ b/JMMServer/Commands/WebCache/CommandRequest_WebCacheDeleteXRefAniDBOther.cs @@ -0,0 +1,100 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Repositories; +using JMMServer.Entities; +using JMMServer.WebCache; +using System.Xml; + +namespace JMMServer.Commands +{ + public class CommandRequest_WebCacheDeleteXRefAniDBOther : CommandRequestImplementation, ICommandRequest + { + public int AnimeID { get; set; } + public int CrossRefType { get; set; } + + public CommandRequestPriority DefaultPriority + { + get { return CommandRequestPriority.Priority9; } + } + + public string PrettyDescription + { + get + { + return string.Format("Deleting cross ref for Anidb to Other from web cache: {0}", AnimeID); + } + } + + public CommandRequest_WebCacheDeleteXRefAniDBOther() + { + } + + public CommandRequest_WebCacheDeleteXRefAniDBOther(int animeID, JMMServer.CrossRefType xrefType) + { + this.AnimeID = animeID; + this.CommandType = (int)CommandRequestType.WebCache_DeleteXRefAniDBOther; + this.CrossRefType = (int)xrefType; + this.Priority = (int)DefaultPriority; + + GenerateCommandID(); + } + + public override void ProcessCommand() + { + + try + { + XMLService.Delete_CrossRef_AniDB_Other(AnimeID, (JMMServer.CrossRefType)CrossRefType); + } + catch (Exception ex) + { + logger.ErrorException("Error processing CommandRequest_WebCacheDeleteXRefAniDBOther: {0}" + ex.ToString(), ex); + return; + } + } + + public override void GenerateCommandID() + { + this.CommandID = string.Format("CommandRequest_WebCacheDeleteXRefAniDBOther_{0}_{1}", AnimeID, CrossRefType); + } + + public override bool LoadFromDBCommand(CommandRequest cq) + { + this.CommandID = cq.CommandID; + this.CommandRequestID = cq.CommandRequestID; + this.CommandType = cq.CommandType; + this.Priority = cq.Priority; + this.CommandDetails = cq.CommandDetails; + this.DateTimeUpdated = cq.DateTimeUpdated; + + // read xml to get parameters + if (this.CommandDetails.Trim().Length > 0) + { + XmlDocument docCreator = new XmlDocument(); + docCreator.LoadXml(this.CommandDetails); + + // populate the fields + this.AnimeID = int.Parse(TryGetProperty(docCreator, "CommandRequest_WebCacheDeleteXRefAniDBOther", "AnimeID")); + this.CrossRefType = int.Parse(TryGetProperty(docCreator, "CommandRequest_WebCacheDeleteXRefAniDBOther", "CrossRefType")); + } + + return true; + } + + public override CommandRequest ToDatabaseObject() + { + GenerateCommandID(); + + CommandRequest cq = new CommandRequest(); + cq.CommandID = this.CommandID; + cq.CommandType = this.CommandType; + cq.Priority = this.Priority; + cq.CommandDetails = this.ToXML(); + cq.DateTimeUpdated = DateTime.Now; + + return cq; + } + } +} diff --git a/JMMServer/Commands/WebCache/CommandRequest_WebCacheDeleteXRefAniDBTrakt.cs b/JMMServer/Commands/WebCache/CommandRequest_WebCacheDeleteXRefAniDBTrakt.cs new file mode 100644 index 000000000..226764991 --- /dev/null +++ b/JMMServer/Commands/WebCache/CommandRequest_WebCacheDeleteXRefAniDBTrakt.cs @@ -0,0 +1,97 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Repositories; +using JMMServer.Entities; +using JMMServer.WebCache; +using System.Xml; + +namespace JMMServer.Commands +{ + public class CommandRequest_WebCacheDeleteXRefAniDBTrakt : CommandRequestImplementation, ICommandRequest + { + public int AnimeID { get; set; } + + public CommandRequestPriority DefaultPriority + { + get { return CommandRequestPriority.Priority9; } + } + + public string PrettyDescription + { + get + { + return string.Format("Deleting cross ref for Anidb to Trakt from web cache: {0}", AnimeID); + } + } + + public CommandRequest_WebCacheDeleteXRefAniDBTrakt() + { + } + + public CommandRequest_WebCacheDeleteXRefAniDBTrakt(int animeID) + { + this.AnimeID = animeID; + this.CommandType = (int)CommandRequestType.WebCache_DeleteXRefAniDBTrakt; + this.Priority = (int)DefaultPriority; + + GenerateCommandID(); + } + + public override void ProcessCommand() + { + + try + { + XMLService.Delete_CrossRef_AniDB_Trakt(AnimeID); + } + catch (Exception ex) + { + logger.ErrorException("Error processing CommandRequest_WebCacheDeleteXRefAniDBTrakt: {0}" + ex.ToString(), ex); + return; + } + } + + public override void GenerateCommandID() + { + this.CommandID = string.Format("CommandRequest_WebCacheDeleteXRefAniDBTrakt{0}", AnimeID); + } + + public override bool LoadFromDBCommand(CommandRequest cq) + { + this.CommandID = cq.CommandID; + this.CommandRequestID = cq.CommandRequestID; + this.CommandType = cq.CommandType; + this.Priority = cq.Priority; + this.CommandDetails = cq.CommandDetails; + this.DateTimeUpdated = cq.DateTimeUpdated; + + // read xml to get parameters + if (this.CommandDetails.Trim().Length > 0) + { + XmlDocument docCreator = new XmlDocument(); + docCreator.LoadXml(this.CommandDetails); + + // populate the fields + this.AnimeID = int.Parse(TryGetProperty(docCreator, "CommandRequest_WebCacheDeleteXRefAniDBTrakt", "AnimeID")); + } + + return true; + } + + public override CommandRequest ToDatabaseObject() + { + GenerateCommandID(); + + CommandRequest cq = new CommandRequest(); + cq.CommandID = this.CommandID; + cq.CommandType = this.CommandType; + cq.Priority = this.Priority; + cq.CommandDetails = this.ToXML(); + cq.DateTimeUpdated = DateTime.Now; + + return cq; + } + } +} diff --git a/JMMServer/Commands/WebCache/CommandRequest_WebCacheDeleteXRefAniDBTvDB.cs b/JMMServer/Commands/WebCache/CommandRequest_WebCacheDeleteXRefAniDBTvDB.cs new file mode 100644 index 000000000..80a885718 --- /dev/null +++ b/JMMServer/Commands/WebCache/CommandRequest_WebCacheDeleteXRefAniDBTvDB.cs @@ -0,0 +1,98 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Repositories; +using JMMServer.Entities; +using JMMServer.WebCache; +using System.Xml; + + +namespace JMMServer.Commands +{ + public class CommandRequest_WebCacheDeleteXRefAniDBTvDB : CommandRequestImplementation, ICommandRequest + { + public int AnimeID { get; set; } + + public CommandRequestPriority DefaultPriority + { + get { return CommandRequestPriority.Priority9; } + } + + public string PrettyDescription + { + get + { + return string.Format("Deleting cross ref for Anidb to TvDB from web cache: {0}", AnimeID); + } + } + + public CommandRequest_WebCacheDeleteXRefAniDBTvDB() + { + } + + public CommandRequest_WebCacheDeleteXRefAniDBTvDB(int animeID) + { + this.AnimeID = animeID; + this.CommandType = (int)CommandRequestType.WebCache_DeleteXRefAniDBTvDB; + this.Priority = (int)DefaultPriority; + + GenerateCommandID(); + } + + public override void ProcessCommand() + { + + try + { + XMLService.Delete_CrossRef_AniDB_TvDB(AnimeID); + } + catch (Exception ex) + { + logger.ErrorException("Error processing CommandRequest_WebCacheDeleteXRefAniDBTvDB: {0}" + ex.ToString(), ex); + return; + } + } + + public override void GenerateCommandID() + { + this.CommandID = string.Format("CommandRequest_WebCacheDeleteXRefAniDBTvDB{0}", AnimeID); + } + + public override bool LoadFromDBCommand(CommandRequest cq) + { + this.CommandID = cq.CommandID; + this.CommandRequestID = cq.CommandRequestID; + this.CommandType = cq.CommandType; + this.Priority = cq.Priority; + this.CommandDetails = cq.CommandDetails; + this.DateTimeUpdated = cq.DateTimeUpdated; + + // read xml to get parameters + if (this.CommandDetails.Trim().Length > 0) + { + XmlDocument docCreator = new XmlDocument(); + docCreator.LoadXml(this.CommandDetails); + + // populate the fields + this.AnimeID = int.Parse(TryGetProperty(docCreator, "CommandRequest_WebCacheDeleteXRefAniDBTvDB", "AnimeID")); + } + + return true; + } + + public override CommandRequest ToDatabaseObject() + { + GenerateCommandID(); + + CommandRequest cq = new CommandRequest(); + cq.CommandID = this.CommandID; + cq.CommandType = this.CommandType; + cq.Priority = this.Priority; + cq.CommandDetails = this.ToXML(); + cq.DateTimeUpdated = DateTime.Now; + + return cq; + } + } +} diff --git a/JMMServer/Commands/WebCache/CommandRequest_WebCacheDeleteXRefAniDBTvDBAll.cs b/JMMServer/Commands/WebCache/CommandRequest_WebCacheDeleteXRefAniDBTvDBAll.cs new file mode 100644 index 000000000..c8c504f0d --- /dev/null +++ b/JMMServer/Commands/WebCache/CommandRequest_WebCacheDeleteXRefAniDBTvDBAll.cs @@ -0,0 +1,101 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Repositories; +using JMMServer.Entities; +using JMMServer.WebCache; +using System.Xml; + +namespace JMMServer.Commands +{ + /// + /// Used to delete all cross refs for a certain TvDB series + /// Only used when the Series ID is no longer valid + /// + public class CommandRequest_WebCacheDeleteXRefAniDBTvDBAll : CommandRequestImplementation, ICommandRequest + { + public int TvDBSeriesID { get; set; } + + public CommandRequestPriority DefaultPriority + { + get { return CommandRequestPriority.Priority9; } + } + + public string PrettyDescription + { + get + { + return string.Format("Deleting cross ref for TvDB from web cache: {0}", TvDBSeriesID); + } + } + + public CommandRequest_WebCacheDeleteXRefAniDBTvDBAll() + { + } + + public CommandRequest_WebCacheDeleteXRefAniDBTvDBAll(int tvDBSeriesID) + { + this.TvDBSeriesID = tvDBSeriesID; + this.CommandType = (int)CommandRequestType.WebCache_DeleteXRefTvDB; + this.Priority = (int)DefaultPriority; + + GenerateCommandID(); + } + + public override void ProcessCommand() + { + + try + { + XMLService.Delete_CrossRef_AniDB_TvDB_All(TvDBSeriesID); + } + catch (Exception ex) + { + logger.ErrorException("Error processing CommandRequest_WebCacheDeleteXRefAniDBTvDBAll: {0}" + ex.ToString(), ex); + return; + } + } + + public override void GenerateCommandID() + { + this.CommandID = string.Format("CommandRequest_WebCacheDeleteXRefAniDBTvDBAll{0}", TvDBSeriesID); + } + + public override bool LoadFromDBCommand(CommandRequest cq) + { + this.CommandID = cq.CommandID; + this.CommandRequestID = cq.CommandRequestID; + this.CommandType = cq.CommandType; + this.Priority = cq.Priority; + this.CommandDetails = cq.CommandDetails; + this.DateTimeUpdated = cq.DateTimeUpdated; + + // read xml to get parameters + if (this.CommandDetails.Trim().Length > 0) + { + XmlDocument docCreator = new XmlDocument(); + docCreator.LoadXml(this.CommandDetails); + + // populate the fields + this.TvDBSeriesID = int.Parse(TryGetProperty(docCreator, "CommandRequest_WebCacheDeleteXRefAniDBTvDBAll", "TvDBSeriesID")); + } + + return true; + } + + public override CommandRequest ToDatabaseObject() + { + GenerateCommandID(); + + CommandRequest cq = new CommandRequest(); + cq.CommandID = this.CommandID; + cq.CommandType = this.CommandType; + cq.Priority = this.Priority; + cq.CommandDetails = this.ToXML(); + cq.DateTimeUpdated = DateTime.Now; + + return cq; + } + } +} diff --git a/JMMServer/Commands/WebCache/CommandRequest_WebCacheDeleteXRefFileEpisode.cs b/JMMServer/Commands/WebCache/CommandRequest_WebCacheDeleteXRefFileEpisode.cs new file mode 100644 index 000000000..25ea14928 --- /dev/null +++ b/JMMServer/Commands/WebCache/CommandRequest_WebCacheDeleteXRefFileEpisode.cs @@ -0,0 +1,100 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Repositories; +using JMMServer.Entities; +using JMMServer.WebCache; +using System.Xml; + +namespace JMMServer.Commands +{ + public class CommandRequest_WebCacheDeleteXRefFileEpisode : CommandRequestImplementation, ICommandRequest + { + public string Hash { get; set; } + public int EpisodeID { get; set; } + + public CommandRequestPriority DefaultPriority + { + get { return CommandRequestPriority.Priority9; } + } + + public string PrettyDescription + { + get + { + return string.Format("Deleting cross ref for file to episode to web cache: {0}-{1}", Hash, EpisodeID); + } + } + + public CommandRequest_WebCacheDeleteXRefFileEpisode() + { + } + + public CommandRequest_WebCacheDeleteXRefFileEpisode(string hash, int aniDBEpisodeID) + { + this.Hash = hash; + this.EpisodeID = aniDBEpisodeID; + this.CommandType = (int)CommandRequestType.WebCache_DeleteXRefFileEpisode; + this.Priority = (int)DefaultPriority; + + GenerateCommandID(); + } + + public override void ProcessCommand() + { + + try + { + XMLService.Delete_CrossRef_File_Episode(Hash, EpisodeID); + } + catch (Exception ex) + { + logger.Error("Error processing CommandRequest_WebCacheDeleteXRefFileEpisode: {0}-{1} - {2}", Hash, EpisodeID, ex.ToString()); + return; + } + } + + public override void GenerateCommandID() + { + this.CommandID = string.Format("CommandRequest_WebCacheDeleteXRefFileEpisode-{0}-{1}", Hash, EpisodeID); + } + + public override bool LoadFromDBCommand(CommandRequest cq) + { + this.CommandID = cq.CommandID; + this.CommandRequestID = cq.CommandRequestID; + this.CommandType = cq.CommandType; + this.Priority = cq.Priority; + this.CommandDetails = cq.CommandDetails; + this.DateTimeUpdated = cq.DateTimeUpdated; + + // read xml to get parameters + if (this.CommandDetails.Trim().Length > 0) + { + XmlDocument docCreator = new XmlDocument(); + docCreator.LoadXml(this.CommandDetails); + + // populate the fields + this.Hash = TryGetProperty(docCreator, "CommandRequest_WebCacheDeleteXRefFileEpisode", "Hash"); + this.EpisodeID = int.Parse(TryGetProperty(docCreator, "CommandRequest_WebCacheDeleteXRefFileEpisode", "EpisodeID")); + } + + return true; + } + + public override CommandRequest ToDatabaseObject() + { + GenerateCommandID(); + + CommandRequest cq = new CommandRequest(); + cq.CommandID = this.CommandID; + cq.CommandType = this.CommandType; + cq.Priority = this.Priority; + cq.CommandDetails = this.ToXML(); + cq.DateTimeUpdated = DateTime.Now; + + return cq; + } + } +} diff --git a/JMMServer/Commands/WebCache/CommandRequest_WebCacheSendFileHash.cs b/JMMServer/Commands/WebCache/CommandRequest_WebCacheSendFileHash.cs new file mode 100644 index 000000000..8d0038343 --- /dev/null +++ b/JMMServer/Commands/WebCache/CommandRequest_WebCacheSendFileHash.cs @@ -0,0 +1,101 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Entities; +using JMMServer.Repositories; +using JMMServer.WebCache; +using System.Xml; + +namespace JMMServer.Commands +{ + public class CommandRequest_WebCacheSendFileHash : CommandRequestImplementation, ICommandRequest + { + public int VideoLocalID { get; set; } + + public CommandRequestPriority DefaultPriority + { + get { return CommandRequestPriority.Priority9; } + } + + public string PrettyDescription + { + get + { + return string.Format("Sending file hash to web cache: {0}", VideoLocalID); + } + } + + public CommandRequest_WebCacheSendFileHash() + { + } + + public CommandRequest_WebCacheSendFileHash(int vidLocalID) + { + this.VideoLocalID = vidLocalID; + this.CommandType = (int)CommandRequestType.WebCache_SendFileHash; + this.Priority = (int)DefaultPriority; + + GenerateCommandID(); + } + + public override void ProcessCommand() + { + + try + { + VideoLocalRepository repVids = new VideoLocalRepository(); + VideoLocal vlocal = repVids.GetByID(VideoLocalID); + if (vlocal == null) return; + + XMLService.Send_FileHash(vlocal); + } + catch (Exception ex) + { + logger.Error("Error processing CommandRequest_WebCacheSendFileHash: {0} - {1}", VideoLocalID, ex.ToString()); + return; + } + } + + public override void GenerateCommandID() + { + this.CommandID = string.Format("CommandRequest_WebCacheSendFileHash_{0}", this.VideoLocalID); + } + + public override bool LoadFromDBCommand(CommandRequest cq) + { + this.CommandID = cq.CommandID; + this.CommandRequestID = cq.CommandRequestID; + this.CommandType = cq.CommandType; + this.Priority = cq.Priority; + this.CommandDetails = cq.CommandDetails; + this.DateTimeUpdated = cq.DateTimeUpdated; + + // read xml to get parameters + if (this.CommandDetails.Trim().Length > 0) + { + XmlDocument docCreator = new XmlDocument(); + docCreator.LoadXml(this.CommandDetails); + + // populate the fields + this.VideoLocalID = int.Parse(TryGetProperty(docCreator, "CommandRequest_WebCacheSendFileHash", "VideoLocalID")); + } + + return true; + } + + public override CommandRequest ToDatabaseObject() + { + GenerateCommandID(); + + CommandRequest cq = new CommandRequest(); + cq.CommandID = this.CommandID; + cq.CommandType = this.CommandType; + cq.Priority = this.Priority; + cq.CommandDetails = this.ToXML(); + cq.DateTimeUpdated = DateTime.Now; + + return cq; + } + } +} diff --git a/JMMServer/Commands/WebCache/CommandRequest_WebCacheSendXRefAniDBOther.cs b/JMMServer/Commands/WebCache/CommandRequest_WebCacheSendXRefAniDBOther.cs new file mode 100644 index 000000000..14f2e15e9 --- /dev/null +++ b/JMMServer/Commands/WebCache/CommandRequest_WebCacheSendXRefAniDBOther.cs @@ -0,0 +1,102 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Repositories; +using JMMServer.Entities; +using JMMServer.WebCache; +using System.Xml; +using JMMServer.Providers.TvDB; + +namespace JMMServer.Commands +{ + public class CommandRequest_WebCacheSendXRefAniDBOther : CommandRequestImplementation, ICommandRequest + { + public int CrossRef_AniDB_OtherID { get; set; } + + public CommandRequestPriority DefaultPriority + { + get { return CommandRequestPriority.Priority9; } + } + + public string PrettyDescription + { + get + { + return string.Format("Sending cross ref for Anidb to Other from web cache: {0}", CrossRef_AniDB_OtherID); + } + } + + public CommandRequest_WebCacheSendXRefAniDBOther() + { + } + + public CommandRequest_WebCacheSendXRefAniDBOther(int xrefID) + { + this.CrossRef_AniDB_OtherID = xrefID; + this.CommandType = (int)CommandRequestType.WebCache_SendXRefAniDBOther; + this.Priority = (int)DefaultPriority; + + GenerateCommandID(); + } + + public override void ProcessCommand() + { + + try + { + CrossRef_AniDB_OtherRepository repCrossRef = new CrossRef_AniDB_OtherRepository(); + CrossRef_AniDB_Other xref = repCrossRef.GetByID(CrossRef_AniDB_OtherID); + if (xref == null) return; + + XMLService.Send_CrossRef_AniDB_Other(xref); + } + catch (Exception ex) + { + logger.ErrorException("Error processing CommandRequest_WebCacheSendXRefAniDBOther: {0}" + ex.ToString(), ex); + return; + } + } + + public override void GenerateCommandID() + { + this.CommandID = string.Format("CommandRequest_WebCacheSendXRefAniDBOther{0}", CrossRef_AniDB_OtherID); + } + + public override bool LoadFromDBCommand(CommandRequest cq) + { + this.CommandID = cq.CommandID; + this.CommandRequestID = cq.CommandRequestID; + this.CommandType = cq.CommandType; + this.Priority = cq.Priority; + this.CommandDetails = cq.CommandDetails; + this.DateTimeUpdated = cq.DateTimeUpdated; + + // read xml to get parameters + if (this.CommandDetails.Trim().Length > 0) + { + XmlDocument docCreator = new XmlDocument(); + docCreator.LoadXml(this.CommandDetails); + + // populate the fields + this.CrossRef_AniDB_OtherID = int.Parse(TryGetProperty(docCreator, "CommandRequest_WebCacheSendXRefAniDBOther", "CrossRef_AniDB_OtherID")); + } + + return true; + } + + public override CommandRequest ToDatabaseObject() + { + GenerateCommandID(); + + CommandRequest cq = new CommandRequest(); + cq.CommandID = this.CommandID; + cq.CommandType = this.CommandType; + cq.Priority = this.Priority; + cq.CommandDetails = this.ToXML(); + cq.DateTimeUpdated = DateTime.Now; + + return cq; + } + } +} diff --git a/JMMServer/Commands/WebCache/CommandRequest_WebCacheSendXRefAniDBTrakt.cs b/JMMServer/Commands/WebCache/CommandRequest_WebCacheSendXRefAniDBTrakt.cs new file mode 100644 index 000000000..3aaa59275 --- /dev/null +++ b/JMMServer/Commands/WebCache/CommandRequest_WebCacheSendXRefAniDBTrakt.cs @@ -0,0 +1,108 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Repositories; +using JMMServer.Entities; +using JMMServer.WebCache; +using System.Xml; + +namespace JMMServer.Commands +{ + public class CommandRequest_WebCacheSendXRefAniDBTrakt : CommandRequestImplementation, ICommandRequest + { + public int CrossRef_AniDB_TraktID { get; set; } + + public CommandRequestPriority DefaultPriority + { + get { return CommandRequestPriority.Priority9; } + } + + public string PrettyDescription + { + get + { + return string.Format("Sending cross ref for Anidb to Trakt from web cache: {0}", CrossRef_AniDB_TraktID); + } + } + + public CommandRequest_WebCacheSendXRefAniDBTrakt() + { + } + + public CommandRequest_WebCacheSendXRefAniDBTrakt(int xrefID) + { + this.CrossRef_AniDB_TraktID = xrefID; + this.CommandType = (int)CommandRequestType.WebCache_SendXRefAniDBTrakt; + this.Priority = (int)DefaultPriority; + + GenerateCommandID(); + } + + public override void ProcessCommand() + { + + try + { + CrossRef_AniDB_TraktRepository repCrossRef = new CrossRef_AniDB_TraktRepository(); + CrossRef_AniDB_Trakt xref = repCrossRef.GetByID(CrossRef_AniDB_TraktID); + if (xref == null) return; + + Trakt_ShowRepository repShow = new Trakt_ShowRepository(); + Trakt_Show tvShow = repShow.GetByTraktID(xref.TraktID); + if (tvShow == null) return; + + string showName = ""; + if (tvShow != null) showName = tvShow.Title; + + XMLService.Send_CrossRef_AniDB_Trakt(xref, showName); + } + catch (Exception ex) + { + logger.ErrorException("Error processing CommandRequest_WebCacheSendXRefAniDBTrakt: {0}" + ex.ToString(), ex); + return; + } + } + + public override void GenerateCommandID() + { + this.CommandID = string.Format("CommandRequest_WebCacheSendXRefAniDBTrakt{0}", CrossRef_AniDB_TraktID); + } + + public override bool LoadFromDBCommand(CommandRequest cq) + { + this.CommandID = cq.CommandID; + this.CommandRequestID = cq.CommandRequestID; + this.CommandType = cq.CommandType; + this.Priority = cq.Priority; + this.CommandDetails = cq.CommandDetails; + this.DateTimeUpdated = cq.DateTimeUpdated; + + // read xml to get parameters + if (this.CommandDetails.Trim().Length > 0) + { + XmlDocument docCreator = new XmlDocument(); + docCreator.LoadXml(this.CommandDetails); + + // populate the fields + this.CrossRef_AniDB_TraktID = int.Parse(TryGetProperty(docCreator, "CommandRequest_WebCacheSendXRefAniDBTrakt", "CrossRef_AniDB_TraktID")); + } + + return true; + } + + public override CommandRequest ToDatabaseObject() + { + GenerateCommandID(); + + CommandRequest cq = new CommandRequest(); + cq.CommandID = this.CommandID; + cq.CommandType = this.CommandType; + cq.Priority = this.Priority; + cq.CommandDetails = this.ToXML(); + cq.DateTimeUpdated = DateTime.Now; + + return cq; + } + } +} diff --git a/JMMServer/Commands/WebCache/CommandRequest_WebCacheSendXRefAniDBTvDB.cs b/JMMServer/Commands/WebCache/CommandRequest_WebCacheSendXRefAniDBTvDB.cs new file mode 100644 index 000000000..005a2be87 --- /dev/null +++ b/JMMServer/Commands/WebCache/CommandRequest_WebCacheSendXRefAniDBTvDB.cs @@ -0,0 +1,110 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Repositories; +using JMMServer.Entities; +using JMMServer.WebCache; +using System.Xml; +using JMMServer.Providers.TvDB; + +namespace JMMServer.Commands +{ + public class CommandRequest_WebCacheSendXRefAniDBTvDB : CommandRequestImplementation, ICommandRequest + { + public int CrossRef_AniDB_TvDBID { get; set; } + + public CommandRequestPriority DefaultPriority + { + get { return CommandRequestPriority.Priority9; } + } + + public string PrettyDescription + { + get + { + return string.Format("Sending cross ref for Anidb to TvDB from web cache: {0}", CrossRef_AniDB_TvDBID); + } + } + + public CommandRequest_WebCacheSendXRefAniDBTvDB() + { + } + + public CommandRequest_WebCacheSendXRefAniDBTvDB(int xrefID) + { + this.CrossRef_AniDB_TvDBID = xrefID; + this.CommandType = (int)CommandRequestType.WebCache_SendXRefAniDBTvDB; + this.Priority = (int)DefaultPriority; + + GenerateCommandID(); + } + + public override void ProcessCommand() + { + + try + { + CrossRef_AniDB_TvDBRepository repCrossRef = new CrossRef_AniDB_TvDBRepository(); + CrossRef_AniDB_TvDB xref = repCrossRef.GetByID(CrossRef_AniDB_TvDBID); + if (xref == null) return; + + TvDB_SeriesRepository repSeries = new TvDB_SeriesRepository(); + TvDB_Series tvSeries = repSeries.GetByTvDBID(xref.TvDBID); + if (tvSeries == null) + tvSeries = TvDBHelper.GetSeriesInfoOnline(xref.TvDBID); + + string seriesName = ""; + if (tvSeries != null) seriesName = tvSeries.SeriesName; + + XMLService.Send_CrossRef_AniDB_TvDB(xref, seriesName); + } + catch (Exception ex) + { + logger.ErrorException("Error processing CommandRequest_WebCacheSendXRefAniDBTvDB: {0}" + ex.ToString(), ex); + return; + } + } + + public override void GenerateCommandID() + { + this.CommandID = string.Format("CommandRequest_WebCacheSendXRefAniDBTvDB{0}", CrossRef_AniDB_TvDBID); + } + + public override bool LoadFromDBCommand(CommandRequest cq) + { + this.CommandID = cq.CommandID; + this.CommandRequestID = cq.CommandRequestID; + this.CommandType = cq.CommandType; + this.Priority = cq.Priority; + this.CommandDetails = cq.CommandDetails; + this.DateTimeUpdated = cq.DateTimeUpdated; + + // read xml to get parameters + if (this.CommandDetails.Trim().Length > 0) + { + XmlDocument docCreator = new XmlDocument(); + docCreator.LoadXml(this.CommandDetails); + + // populate the fields + this.CrossRef_AniDB_TvDBID = int.Parse(TryGetProperty(docCreator, "CommandRequest_WebCacheSendXRefAniDBTvDB", "CrossRef_AniDB_TvDBID")); + } + + return true; + } + + public override CommandRequest ToDatabaseObject() + { + GenerateCommandID(); + + CommandRequest cq = new CommandRequest(); + cq.CommandID = this.CommandID; + cq.CommandType = this.CommandType; + cq.Priority = this.Priority; + cq.CommandDetails = this.ToXML(); + cq.DateTimeUpdated = DateTime.Now; + + return cq; + } + } +} diff --git a/JMMServer/Commands/WebCache/CommandRequest_WebCacheSendXRefFileEpisode.cs b/JMMServer/Commands/WebCache/CommandRequest_WebCacheSendXRefFileEpisode.cs new file mode 100644 index 000000000..c1777d1f2 --- /dev/null +++ b/JMMServer/Commands/WebCache/CommandRequest_WebCacheSendXRefFileEpisode.cs @@ -0,0 +1,101 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Entities; +using System.Xml; +using JMMServer.Repositories; +using JMMServer.WebCache; + +namespace JMMServer.Commands +{ + public class CommandRequest_WebCacheSendXRefFileEpisode : CommandRequestImplementation, ICommandRequest + { + public int CrossRef_File_EpisodeID { get; set; } + + public CommandRequestPriority DefaultPriority + { + get { return CommandRequestPriority.Priority9; } + } + + public string PrettyDescription + { + get + { + return string.Format("Sending cross ref for file to episode to web cache: {0}", CrossRef_File_EpisodeID); + } + } + + public CommandRequest_WebCacheSendXRefFileEpisode() + { + } + + public CommandRequest_WebCacheSendXRefFileEpisode(int crossRef_File_EpisodeID) + { + this.CrossRef_File_EpisodeID = crossRef_File_EpisodeID; + this.CommandType = (int)CommandRequestType.WebCache_SendXRefFileEpisode; + this.Priority = (int)DefaultPriority; + + GenerateCommandID(); + } + + 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; + + XMLService.Send_CrossRef_File_Episode(xref); + } + catch (Exception ex) + { + logger.Error("Error processing CommandRequest_WebCacheSendXRefFileEpisode: {0} - {1}", CrossRef_File_EpisodeID, ex.ToString()); + return; + } + } + + public override void GenerateCommandID() + { + this.CommandID = string.Format("CommandRequest_WebCacheSendXRefFileEpisode{0}", this.CrossRef_File_EpisodeID); + } + + public override bool LoadFromDBCommand(CommandRequest cq) + { + this.CommandID = cq.CommandID; + this.CommandRequestID = cq.CommandRequestID; + this.CommandType = cq.CommandType; + this.Priority = cq.Priority; + this.CommandDetails = cq.CommandDetails; + this.DateTimeUpdated = cq.DateTimeUpdated; + + // read xml to get parameters + if (this.CommandDetails.Trim().Length > 0) + { + XmlDocument docCreator = new XmlDocument(); + docCreator.LoadXml(this.CommandDetails); + + // populate the fields + this.CrossRef_File_EpisodeID = int.Parse(TryGetProperty(docCreator, "CommandRequest_WebCacheSendXRefFileEpisode", "CrossRef_File_EpisodeID")); + } + + return true; + } + + public override CommandRequest ToDatabaseObject() + { + GenerateCommandID(); + + CommandRequest cq = new CommandRequest(); + cq.CommandID = this.CommandID; + cq.CommandType = this.CommandType; + cq.Priority = this.Priority; + cq.CommandDetails = this.ToXML(); + cq.DateTimeUpdated = DateTime.Now; + + return cq; + } + } +} diff --git a/JMMServer/Constants.cs b/JMMServer/Constants.cs new file mode 100644 index 000000000..5453ff49e --- /dev/null +++ b/JMMServer/Constants.cs @@ -0,0 +1,176 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace JMMServer +{ + public static class Constants + { + public static readonly string WebCacheError = @"No Results"; + public static readonly string AniDBTitlesURL = @"http://anidb.net/api/animetitles.dat.gz"; + public static readonly string AnonWebCacheUsername = @"AnonymousWebCacheUser"; + + public const string DatabaseTypeKey = "Database"; + + + #region Labels + public struct Labels + { + public static readonly string LASTWATCHED = "Last Watched"; + public static readonly string NEWEPISODES = "New Episodes"; + public static readonly string FAVES = "Favorites"; + public static readonly string FAVESNEW = "New in Favorites"; + public static readonly string MISSING = "Missing Episodes"; + public static readonly string MAINVIEW = "[ Main View ]"; + public static readonly string PREVIOUSFOLDER = ".."; + + } + + public struct SeriesDisplayString + { + public static readonly string SeriesName = ""; + public static readonly string AniDBNameRomaji = ""; + public static readonly string AniDBNameEnglish = ""; + public static readonly string TvDBSeason = ""; + public static readonly string AnimeYear = ""; + } + + public struct GroupDisplayString + { + public static readonly string GroupName = ""; + public static readonly string AniDBNameRomaji = ""; + public static readonly string AniDBNameEnglish = ""; + public static readonly string AnimeYear = ""; + } + + public struct FileSelectionDisplayString + { + public static readonly string Group = ""; + public static readonly string GroupShort = ""; + public static readonly string FileSource = ""; + public static readonly string FileRes = ""; + public static readonly string FileCodec = ""; + public static readonly string AudioCodec = ""; + } + + public struct EpisodeDisplayString + { + public static readonly string EpisodeNumber = ""; + public static readonly string EpisodeName = ""; + } + + public struct URLS + { + public static readonly string MAL_Series_Prefix = @"http://myanimelist.net/anime/"; + + public static readonly string AniDB_File = @"http://anidb.net/perl-bin/animedb.pl?show=file&fid={0}"; + public static readonly string AniDB_Episode = @"http://anidb.net/perl-bin/animedb.pl?show=ep&eid={0}"; + public static readonly string AniDB_Series = @"http://anidb.net/perl-bin/animedb.pl?show=anime&aid={0}"; + public static readonly string AniDB_ReleaseGroup = @"http://anidb.net/perl-bin/animedb.pl?show=group&gid={0}"; + public static readonly string AniDB_Images = @"http://img7.anidb.net/pics/anime/{0}"; + + public static readonly string TvDB_Series = @"http://thetvdb.com/?tab=series&id={0}"; + //public static readonly string tvDBEpisodeURLPrefix = @"http://anidb.net/perl-bin/animedb.pl?show=ep&eid={0}"; + public static readonly string TvDB_Images = @"http://thetvdb.com/banners/{0}"; + + public static readonly string MovieDB_Series = @"http://www.themoviedb.org/movie/{0}"; + } + + public struct GroupLabelStyle + { + public static readonly string EpCount = "Total Episode Count"; + public static readonly string Unwatched = "Only Unwatched Episode Count"; + public static readonly string WatchedUnwatched = "Watched and Unwatched Episode Counts"; + } + + public struct EpisodeLabelStyle + { + public static readonly string IconsDate = "Icons and Date"; + public static readonly string IconsOnly = "Icons Only"; + } + + #endregion + + public struct WebURLStrings + { + + } + + public struct TorrentSourceNames + { + public static readonly string TT = "Tokyo Toshokan"; + public static readonly string AnimeSuki = "Anime Suki"; + public static readonly string BakaBT = "Baka BT"; + public static readonly string BakaUpdates = "BakaUpdates"; + public static readonly string Nyaa = "Nyaa Torrents"; + } + + public struct EpisodeTypeStrings + { + public static readonly string Normal = "Episodes"; + public static readonly string Credits = "Credits"; + public static readonly string Specials = "Specials"; + public static readonly string Trailer = "Trailer"; + public static readonly string Parody = "Parody"; + public static readonly string Other = "Other"; + } + + public struct TvDBURLs + { + public static readonly string apiKey = "B178B8940CAF4A2C"; + public static readonly string urlSeriesSearch = @"http://www.thetvdb.com/api/GetSeries.php?seriesname={0}&language=all"; + public static readonly string urlFullSeriesData = @"{0}/api/{1}/series/{2}/all/en.zip"; // mirrirURL, apiKey, seriesID + public static readonly string urlBannersXML = @"{0}/api/{1}/series/{2}/banners.xml"; // mirrirURL, apiKey, seriesID + public static readonly string urlSeriesBaseXML = @"{0}/api/{1}/series/{2}/en.xml"; // mirrirURL, apiKey, seriesID + public static readonly string urlEpisodeXML = @"{0}/api/{1}/episodes/{2}/en.xml"; // mirrirURL, apiKey, episodeID + public static readonly string urlUpdatesList = @"{0}/api/Updates.php?type=all&time={1}"; // mirrirURL, server time + } + + public struct TraktTvURLs + { + public static readonly string APIKey = "f9db01de75fcc4c26f26245262c7715803e376d1"; + public static readonly string URLGetShowExtended = @"http://api.trakt.tv/show/summary.json/{0}/{1}/extended"; // apiKey/ tvdb id or trakt id + public static readonly string URLSearchShow = @"http://api.trakt.tv/search/shows.json/{0}/{1}"; // apiKey/ search criteria + + public static readonly string URLPostShowScrobble = @"http://api.trakt.tv/show/scrobble/{0}"; // apiKey + public static readonly string URLPostAccountTest = @"http://api.trakt.tv/account/test/{0}"; // apiKey + public static readonly string URLPostShowEpisodeLibrary = @"http://api.trakt.tv/show/episode/library/{0}"; // apiKey + public static readonly string URLPostShowEpisodeSeen = @"http://api.trakt.tv/show/episode/seen/{0}"; // apiKey + public static readonly string URLPostShowEpisodeUnseen = @"http://api.trakt.tv/show/episode/unseen/{0}"; // apiKey + } + + public struct Folders + { + public static readonly string thumbsSubFolder = "AnimeThumbs"; + public static readonly string thumbsTvDB = @"TvDB"; + public static readonly string thumbsAniDB = @"AniDB"; + public static readonly string thumbsAniDB_Chars = @"AniDB\Characters"; + public static readonly string thumbsAniDB_Creators = @"AniDB\Creators"; + public static readonly string thumbsMAL = @"MAL"; + public static readonly string thumbsMovieDB = @"MovieDB"; + } + + public struct AnimeTitleType + { + public static readonly string Main = "main"; + public static readonly string Official = "official"; + public static readonly string ShortName = "short"; + public static readonly string Synonym = "synonym"; + } + + public struct MovieDBImageSize + { + public static readonly string Original = "original"; + public static readonly string Thumb = "thumb"; + public static readonly string Cover = "cover"; + } + + } + + public static class Globals + { + public static System.Globalization.CultureInfo Culture = System.Globalization.CultureInfo.CurrentCulture; + + } +} diff --git a/JMMServer/DataAccessHelper.cs b/JMMServer/DataAccessHelper.cs new file mode 100644 index 000000000..b1b500a45 --- /dev/null +++ b/JMMServer/DataAccessHelper.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Entities; + +namespace JMMServer +{ + public class DataAccessHelper + { + public static void GetShareAndPath(string fileName, List shares, ref int importFolderID, ref string filePath) + { + // TODO make sure that import folders are not sub folders of each other + // TODO make sure import folders do not contain a trailing "\" + importFolderID = -1; + foreach (ImportFolder ifolder in shares) + { + string importLocation = ifolder.ImportFolderLocation; + importLocation = importLocation.TrimEnd('\\'); + if (fileName.StartsWith(ifolder.ImportFolderLocation)) + { + importFolderID = ifolder.ImportFolderID; + filePath = fileName.Replace(importLocation, ""); + filePath = filePath.TrimStart('\\'); + break; + } + } + } + } +} diff --git a/JMMServer/Databases/DatabaseHelper.cs b/JMMServer/Databases/DatabaseHelper.cs new file mode 100644 index 000000000..abd4bdf1c --- /dev/null +++ b/JMMServer/Databases/DatabaseHelper.cs @@ -0,0 +1,77 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Data.SQLite; +using NLog; +using NHibernate; +using FluentNHibernate.Cfg; +using FluentNHibernate.Cfg.Db; + +namespace JMMServer.Databases +{ + public class DatabaseHelper + { + private static Logger logger = LogManager.GetCurrentClassLogger(); + + public static ISessionFactory CreateSessionFactory() + { + + if (ServerSettings.DatabaseType.Trim().ToUpper() == "SQLSERVER") + { + string connectionstring = string.Format(@"data source={0};initial catalog={1};persist security info=True;user id={2};password={3}", + ServerSettings.DatabaseServer, ServerSettings.DatabaseName, ServerSettings.DatabaseUsername, ServerSettings.DatabasePassword); + + return Fluently.Configure() + .Database(MsSqlConfiguration.MsSql2008.ConnectionString(connectionstring)) + .Mappings(m => + m.FluentMappings.AddFromAssemblyOf()) + .BuildSessionFactory(); + } + else if (ServerSettings.DatabaseType.Trim().ToUpper() == "SQLITE") + { + return Fluently.Configure() + .Database(SQLiteConfiguration.Standard + .UsingFile(SQLite.GetDatabaseFilePath())) + .Mappings(m => + m.FluentMappings.AddFromAssemblyOf()) + .BuildSessionFactory(); + } + else + return null; + } + + public static bool InitDB() + { + try + { + if (ServerSettings.DatabaseType.Trim().ToUpper() == "SQLSERVER") + { + if (!SQLServer.DatabaseAlreadyExists()) + { + logger.Error("Database: {0} does not exist", ServerSettings.DatabaseName); + return false; + } + + SQLServer.CreateInitialSchema(); + SQLServer.UpdateSchema(); + + return true; + } + else + { + SQLite.CreateDatabase(); + SQLite.CreateInitialSchema(); + SQLite.UpdateSchema(); + + return true; + } + } + catch (Exception ex) + { + logger.ErrorException("Could not init database: " + ex.ToString(), ex); + return false; + } + } + } +} diff --git a/JMMServer/Databases/SQLServer.cs b/JMMServer/Databases/SQLServer.cs new file mode 100644 index 000000000..efc90853d --- /dev/null +++ b/JMMServer/Databases/SQLServer.cs @@ -0,0 +1,1662 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Data.SqlClient; +using System.IO; +using Microsoft.Win32; +using JMMServer.Entities; +using JMMServer.Repositories; +using NLog; + +namespace JMMServer.Databases +{ + public class SQLServer + { + private static Logger logger = LogManager.GetCurrentClassLogger(); + + public static string GetConnectionString() + { + return string.Format("Server={0};Database={1};UID={2};PWD={3};", + ServerSettings.DatabaseServer, ServerSettings.DatabaseName, ServerSettings.DatabaseUsername, ServerSettings.DatabasePassword); + } + + public static bool DatabaseAlreadyExists() + { + int count = 0; + string cmd = string.Format("Select count(*) from sysdatabases where name = '{0}'", ServerSettings.DatabaseName); + using (SqlConnection tmpConn = new SqlConnection(string.Format("Server={0};User ID={1};Password={2};database={3}", ServerSettings.DatabaseServer, + ServerSettings.DatabaseUsername, ServerSettings.DatabasePassword, "master"))) + { + using (SqlCommand command = new SqlCommand(cmd, tmpConn)) + { + tmpConn.Open(); + object result = command.ExecuteScalar(); + count = int.Parse(result.ToString()); + } + } + + // if the Versions already exists, it means we have done this already + if (count > 0) return true; + + return false; + } + + public static bool TestLogin() + { + return true; + } + + public static void CreateDatabase() + { + if (DatabaseAlreadyExists()) return; + + SQLServerDatabase db = new SQLServerDatabase(); + + string dataPath = GetDatabasePath(ServerSettings.DatabaseServer); + + db.DatabaseName = ServerSettings.DatabaseName; + db.MdfFileName = ServerSettings.DatabaseName; + db.MdfFilePath = Path.Combine(dataPath, ServerSettings.DatabaseName + ".mdf"); + db.MdfFileSize = "3072KB"; + db.MdfMaxFileSize = "UNLIMITED"; + db.MdfFileGrowth = "1024KB"; + db.LdfFileName = ServerSettings.DatabaseName + "_log"; + db.LdfFilePath = Path.Combine(dataPath, ServerSettings.DatabaseName + ".ldf"); + db.LdfFileSize = "3072KB"; + db.LdfMaxFileSize = "2048GB"; + db.LdfFileGrowth = "1024KB"; + + + StringBuilder sb = new StringBuilder(); + sb.AppendFormat("CREATE DATABASE [{0}] ON PRIMARY ", db.DatabaseName); + sb.AppendFormat("( NAME = N'{0}', FILENAME = N'{1}' , SIZE = ", db.MdfFileName, db.MdfFilePath); + sb.AppendFormat("{0} , MAXSIZE = {1}, FILEGROWTH = {2}", db.MdfFileSize, db.MdfMaxFileSize, db.MdfFileGrowth); + sb.Append(" )"); + sb.Append(" LOG ON "); + sb.AppendFormat("( NAME = N'{0}', FILENAME = N'{1}' , SIZE = ", db.LdfFileName, db.LdfFilePath); + sb.AppendFormat("{0} , MAXSIZE = {1}, FILEGROWTH = {2}", db.LdfFileSize, db.LdfMaxFileSize, db.LdfFileGrowth); + sb.Append(" ) "); + + using (SqlConnection tmpConn = new SqlConnection(string.Format("Server={0};User ID={1};Password={2};database=master", ServerSettings.DatabaseServer, + ServerSettings.DatabaseUsername, ServerSettings.DatabasePassword))) + { + using (SqlCommand command = new SqlCommand(sb.ToString(), tmpConn)) + { + tmpConn.Open(); + command.ExecuteNonQuery(); + + Console.WriteLine("Database created successfully!"); + } + + } + } + + #region Schema Updates + + public static void UpdateSchema() + { + + VersionsRepository repVersions = new VersionsRepository(); + Versions ver = repVersions.GetByVersionType(Constants.DatabaseTypeKey); + if (ver == null) return; + + int versionNumber = 0; + int.TryParse(ver.VersionValue, out versionNumber); + + try + { + UpdateSchema_002(versionNumber); + } + catch (Exception ex) + { + logger.ErrorException("Error updating schema: " + ex.ToString(), ex); + } + + } + + private static void UpdateSchema_002(int currentVersionNumber) + { + /*int thisVersion = 2; + if (currentVersionNumber >= thisVersion) return; + + logger.Info("Updating schema to VERSION: {0}", thisVersion); + + string sql = "ALTER TABLE GroupFilter ADD SortingCriteria [nvarchar](max)"; + + using (SqlConnection tmpConn = new SqlConnection(string.Format("Server={0};User ID={1};Password={2};database={3}", ServerSettings.DatabaseServer, + ServerSettings.DatabaseUsername, ServerSettings.DatabasePassword, ServerSettings.DatabaseName))) + { + tmpConn.Open(); + using (SqlCommand command = new SqlCommand(sql, tmpConn)) + { + command.ExecuteNonQuery(); + } + } + + UpdateDatabaseVersion(thisVersion);*/ + + } + + + + + + + private static void UpdateDatabaseVersion(int versionNumber) + { + VersionsRepository repVersions = new VersionsRepository(); + Versions ver = repVersions.GetByVersionType(Constants.DatabaseTypeKey); + if (ver == null) return; + + ver.VersionValue = versionNumber.ToString(); + repVersions.Save(ver); + } + + #endregion + + #region Create Initial Schema + + + + public static void CreateInitialSchema() + { + + + int count = 0; + string cmd = string.Format("Select count(*) from sysobjects where name = 'Versions'"); + using (SqlConnection tmpConn = new SqlConnection(string.Format("Server={0};User ID={1};Password={2};database={3}", ServerSettings.DatabaseServer, + ServerSettings.DatabaseUsername, ServerSettings.DatabasePassword, ServerSettings.DatabaseName))) + { + using (SqlCommand command = new SqlCommand(cmd, tmpConn)) + { + tmpConn.Open(); + object result = command.ExecuteScalar(); + count = int.Parse(result.ToString()); + } + } + + // if the Versions already exists, it means we have done this already + if (count > 0) return; + + //Create all the commands to be executed + List commands = new List(); + commands.AddRange(CreateTableString_Versions()); + commands.AddRange(CreateTableString_AniDB_Anime()); + commands.AddRange(CreateTableString_AniDB_Anime_Category()); + commands.AddRange(CreateTableString_AniDB_Anime_Character()); + commands.AddRange(CreateTableString_AniDB_Anime_Relation()); + commands.AddRange(CreateTableString_AniDB_Anime_Review()); + commands.AddRange(CreateTableString_AniDB_Anime_Similar()); + commands.AddRange(CreateTableString_AniDB_Anime_Tag()); + commands.AddRange(CreateTableString_AniDB_Anime_Title()); + commands.AddRange(CreateTableString_AniDB_Category()); + commands.AddRange(CreateTableString_AniDB_Character()); + commands.AddRange(CreateTableString_AniDB_Character_Creator()); + commands.AddRange(CreateTableString_AniDB_Creator()); + commands.AddRange(CreateTableString_AniDB_Episode()); + commands.AddRange(CreateTableString_AniDB_File()); + commands.AddRange(CreateTableString_AniDB_GroupStatus()); + commands.AddRange(CreateTableString_AniDB_ReleaseGroup()); + commands.AddRange(CreateTableString_AniDB_Review()); + commands.AddRange(CreateTableString_AniDB_Tag()); + commands.AddRange(CreateTableString_AnimeEpisode()); + commands.AddRange(CreateTableString_AnimeGroup()); + commands.AddRange(CreateTableString_AnimeSeries()); + commands.AddRange(CreateTableString_CommandRequest()); + commands.AddRange(CreateTableString_CrossRef_AniDB_Other()); + commands.AddRange(CreateTableString_CrossRef_AniDB_TvDB()); + commands.AddRange(CreateTableString_CrossRef_File_Episode()); + commands.AddRange(CreateTableString_CrossRef_Languages_AniDB_File()); + commands.AddRange(CreateTableString_CrossRef_Subtitles_AniDB_File()); + commands.AddRange(CreateTableString_FileNameHash()); + commands.AddRange(CreateTableString_Language()); + commands.AddRange(CreateTableString_ImportFolder()); + commands.AddRange(CreateTableString_ScheduledUpdate()); + commands.AddRange(CreateTableString_VideoInfo()); + commands.AddRange(CreateTableString_VideoLocal()); + commands.AddRange(CreateTableString_DuplicateFile()); + commands.AddRange(CreateTableString_GroupFilter()); + commands.AddRange(CreateTableString_GroupFilterCondition()); + commands.AddRange(CreateTableString_AniDB_Vote()); + commands.AddRange(CreateTableString_TvDB_ImageFanart()); + commands.AddRange(CreateTableString_TvDB_ImageWideBanner()); + commands.AddRange(CreateTableString_TvDB_ImagePoster()); + commands.AddRange(CreateTableString_TvDB_Episode()); + commands.AddRange(CreateTableString_TvDB_Series()); + commands.AddRange(CreateTableString_AniDB_Anime_DefaultImage()); + commands.AddRange(CreateTableString_MovieDB_Movie()); + commands.AddRange(CreateTableString_MovieDB_Poster()); + commands.AddRange(CreateTableString_MovieDB_Fanart()); + commands.AddRange(CreateTableString_JMMUser()); + commands.AddRange(CreateTableString_Trakt_Episode()); + commands.AddRange(CreateTableString_Trakt_ImagePoster()); + commands.AddRange(CreateTableString_Trakt_ImageFanart()); + commands.AddRange(CreateTableString_Trakt_Show()); + commands.AddRange(CreateTableString_Trakt_Season()); + commands.AddRange(CreateTableString_CrossRef_AniDB_Trakt()); + + commands.AddRange(CreateTableString_AnimeEpisode_User()); + commands.AddRange(CreateTableString_AnimeSeries_User()); + commands.AddRange(CreateTableString_AnimeGroup_User()); + commands.AddRange(CreateTableString_VideoLocal_User()); + + + //commands.AddRange(CreateTableString_CrossRef_AnimeEpisode_Hash()); + + using (SqlConnection tmpConn = new SqlConnection(string.Format("Server={0};User ID={1};Password={2};database={3}", ServerSettings.DatabaseServer, + ServerSettings.DatabaseUsername, ServerSettings.DatabasePassword, ServerSettings.DatabaseName))) + { + tmpConn.Open(); + foreach (string cmdTable in commands) + { + using (SqlCommand command = new SqlCommand(cmdTable, tmpConn)) + { + command.ExecuteNonQuery(); + } + } + } + + Console.WriteLine("Creating version..."); + Versions ver1 = new Versions(); + ver1.VersionType = Constants.DatabaseTypeKey; + ver1.VersionValue = "1"; + + VersionsRepository repVer = new VersionsRepository(); + repVer.Save(ver1); + } + + + public static List CreateTableString_Versions() + { + List cmds = new List(); + cmds.Add("CREATE TABLE [Versions]( " + + " [VersionsID] [int] IDENTITY(1,1) NOT NULL, " + + " [VersionType] [varchar](100) NOT NULL, " + + " [VersionValue] [varchar](100) NOT NULL, " + + " CONSTRAINT [PK_Versions] PRIMARY KEY CLUSTERED " + + " ( " + + " [VersionsID] ASC " + + " )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] " + + " ) ON [PRIMARY] "); + + cmds.Add("CREATE UNIQUE INDEX UIX_Versions_VersionType ON Versions(VersionType)"); + + return cmds; + } + + public static List CreateTableString_AniDB_Anime() + { + List cmds = new List(); + cmds.Add("CREATE TABLE AniDB_Anime( " + + " AniDB_AnimeID int IDENTITY(1,1) NOT NULL, " + + " AnimeID int NOT NULL, " + + " EpisodeCount int NOT NULL, " + + " AirDate datetime NULL, " + + " EndDate datetime NULL, " + + " URL varchar(max) NULL, " + + " Picname varchar(max) NULL, " + + " BeginYear int NOT NULL, " + + " EndYear int NOT NULL, " + + " AnimeType int NOT NULL, " + + " MainTitle nvarchar(500) NOT NULL, " + + " AllTitles nvarchar(1500) NOT NULL, " + + " AllCategories nvarchar(MAX) NOT NULL, " + + " AllTags nvarchar(MAX) NOT NULL, " + + " Description varchar(max) NOT NULL, " + + " EpisodeCountNormal int NOT NULL, " + + " EpisodeCountSpecial int NOT NULL, " + + " Rating int NOT NULL, " + + " VoteCount int NOT NULL, " + + " TempRating int NOT NULL, " + + " TempVoteCount int NOT NULL, " + + " AvgReviewRating int NOT NULL, " + + " ReviewCount int NOT NULL, " + + " DateTimeUpdated datetime NOT NULL, " + + " DateTimeDescUpdated datetime NOT NULL, " + + " ImageEnabled int NOT NULL, " + + " AwardList varchar(max) NOT NULL, " + + " Restricted int NOT NULL, " + + " AnimePlanetID int NULL, " + + " ANNID int NULL, " + + " AllCinemaID int NULL, " + + " AnimeNfo int NULL, " + + " [LatestEpisodeNumber] [int] NULL, " + + " CONSTRAINT [PK_AniDB_Anime] PRIMARY KEY CLUSTERED " + + " ( " + + " [AniDB_AnimeID] ASC " + + " )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] " + + " ) ON [PRIMARY] "); + + cmds.Add("CREATE UNIQUE INDEX UIX_AniDB_Anime_AnimeID ON AniDB_Anime(AnimeID)"); + + return cmds; + } + + public static List CreateTableString_AniDB_Anime_Category() + { + List cmds = new List(); + cmds.Add("CREATE TABLE AniDB_Anime_Category ( " + + " AniDB_Anime_CategoryID int IDENTITY(1,1) NOT NULL, " + + " AnimeID int NOT NULL, " + + " CategoryID int NOT NULL, " + + " Weighting int NOT NULL, " + + " CONSTRAINT [PK_AniDB_Anime_Category] PRIMARY KEY CLUSTERED " + + " ( " + + " AniDB_Anime_CategoryID ASC " + + " )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] " + + " ) ON [PRIMARY] "); + + cmds.Add("CREATE INDEX IX_AniDB_Anime_Category_AnimeID on AniDB_Anime_Category(AnimeID)"); + cmds.Add("CREATE UNIQUE INDEX UIX_AniDB_Anime_Category_AnimeID_CategoryID ON AniDB_Anime_Category(AnimeID, CategoryID)"); + + return cmds; + } + + public static List CreateTableString_AniDB_Anime_Character() + { + List cmds = new List(); + cmds.Add("CREATE TABLE AniDB_Anime_Character ( " + + " AniDB_Anime_CharacterID int IDENTITY(1,1) NOT NULL, " + + " AnimeID int NOT NULL, " + + " CharID int NOT NULL, " + + " CharType varchar(100) NOT NULL, " + + " EpisodeListRaw varchar(max) NULL, " + + " CONSTRAINT [PK_AniDB_Anime_Character] PRIMARY KEY CLUSTERED " + + " ( " + + " AniDB_Anime_CharacterID ASC " + + " )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] " + + " ) ON [PRIMARY] "); + + cmds.Add("CREATE INDEX IX_AniDB_Anime_Character_AnimeID on AniDB_Anime_Character(AnimeID)"); + cmds.Add("CREATE UNIQUE INDEX UIX_AniDB_Anime_Character_AnimeID_CharID ON AniDB_Anime_Character(AnimeID, CharID)"); + + return cmds; + } + + public static List CreateTableString_AniDB_Anime_Relation() + { + List cmds = new List(); + cmds.Add("CREATE TABLE AniDB_Anime_Relation ( " + + " AniDB_Anime_RelationID int IDENTITY(1,1) NOT NULL, " + + " AnimeID int NOT NULL, " + + " RelatedAnimeID int NOT NULL, " + + " RelationType varchar(100) NOT NULL, " + + " CONSTRAINT [PK_AniDB_Anime_Relation] PRIMARY KEY CLUSTERED " + + " ( " + + " AniDB_Anime_RelationID ASC " + + " )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] " + + " ) ON [PRIMARY] "); + + cmds.Add("CREATE INDEX IX_AniDB_Anime_Relation_AnimeID on AniDB_Anime_Relation(AnimeID)"); + cmds.Add("CREATE UNIQUE INDEX UIX_AniDB_Anime_Relation_AnimeID_RelatedAnimeID ON AniDB_Anime_Relation(AnimeID, RelatedAnimeID)"); + + return cmds; + } + + public static List CreateTableString_AniDB_Anime_Review() + { + List cmds = new List(); + cmds.Add("CREATE TABLE AniDB_Anime_Review ( " + + " AniDB_Anime_ReviewID int IDENTITY(1,1) NOT NULL, " + + " AnimeID int NOT NULL, " + + " ReviewID int NOT NULL, " + + " CONSTRAINT [PK_AniDB_Anime_Review] PRIMARY KEY CLUSTERED " + + " ( " + + " AniDB_Anime_ReviewID ASC " + + " )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] " + + " ) ON [PRIMARY] "); + + cmds.Add("CREATE INDEX IX_AniDB_Anime_Review_AnimeID on AniDB_Anime_Review(AnimeID)"); + cmds.Add("CREATE UNIQUE INDEX UIX_AniDB_Anime_Review_AnimeID_ReviewID ON AniDB_Anime_Review(AnimeID, ReviewID)"); + + return cmds; + } + + public static List CreateTableString_AniDB_Anime_Similar() + { + List cmds = new List(); + cmds.Add("CREATE TABLE AniDB_Anime_Similar ( " + + " AniDB_Anime_SimilarID int IDENTITY(1,1) NOT NULL, " + + " AnimeID int NOT NULL, " + + " SimilarAnimeID int NOT NULL, " + + " Approval int NOT NULL, " + + " Total int NOT NULL, " + + " CONSTRAINT [PK_AniDB_Anime_Similar] PRIMARY KEY CLUSTERED " + + " ( " + + " AniDB_Anime_SimilarID ASC " + + " )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] " + + " ) ON [PRIMARY] "); + + cmds.Add("CREATE INDEX IX_AniDB_Anime_Similar_AnimeID on AniDB_Anime_Similar(AnimeID)"); + cmds.Add("CREATE UNIQUE INDEX UIX_AniDB_Anime_Similar_AnimeID_SimilarAnimeID ON AniDB_Anime_Similar(AnimeID, SimilarAnimeID)"); + + return cmds; + } + + public static List CreateTableString_AniDB_Anime_Tag() + { + List cmds = new List(); + cmds.Add("CREATE TABLE AniDB_Anime_Tag ( " + + " AniDB_Anime_TagID int IDENTITY(1,1) NOT NULL, " + + " AnimeID int NOT NULL, " + + " TagID int NOT NULL, " + + " Approval int NOT NULL, " + + " CONSTRAINT [PK_AniDB_Anime_Tag] PRIMARY KEY CLUSTERED " + + " ( " + + " AniDB_Anime_TagID ASC " + + " )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] " + + " ) ON [PRIMARY] "); + + cmds.Add("CREATE INDEX IX_AniDB_Anime_Tag_AnimeID on AniDB_Anime_Tag(AnimeID)"); + cmds.Add("CREATE UNIQUE INDEX UIX_AniDB_Anime_Tag_AnimeID_TagID ON AniDB_Anime_Tag(AnimeID, TagID)"); + + return cmds; + } + + public static List CreateTableString_AniDB_Anime_Title() + { + List cmds = new List(); + cmds.Add("CREATE TABLE [AniDB_Anime_Title]( " + + " AniDB_Anime_TitleID int IDENTITY(1,1) NOT NULL, " + + " AnimeID int NOT NULL, " + + " TitleType varchar(50) NOT NULL, " + + " Language nvarchar(50) NOT NULL, " + + " Title nvarchar(500) NOT NULL, " + + " CONSTRAINT [PK_AniDB_Anime_Title] PRIMARY KEY CLUSTERED " + + " ( " + + " AniDB_Anime_TitleID ASC " + + " )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] " + + " ) ON [PRIMARY] "); + + cmds.Add("CREATE INDEX IX_AniDB_Anime_Title_AnimeID on AniDB_Anime_Title(AnimeID)"); + + return cmds; + } + + public static List CreateTableString_AniDB_Category() + { + List cmds = new List(); + cmds.Add("CREATE TABLE AniDB_Category ( " + + " AniDB_CategoryID int IDENTITY(1,1) NOT NULL, " + + " CategoryID int NOT NULL, " + + " ParentID int NOT NULL, " + + " IsHentai int NOT NULL, " + + " CategoryName varchar(50) NOT NULL, " + + " CategoryDescription varchar(max) NOT NULL, " + + " CONSTRAINT [PK_AniDB_Category] PRIMARY KEY CLUSTERED " + + " ( " + + " AniDB_CategoryID ASC " + + " )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] " + + " ) ON [PRIMARY] "); + + cmds.Add("CREATE UNIQUE INDEX UIX_AniDB_Category_CategoryID ON AniDB_Category(CategoryID)"); + + return cmds; + } + + public static List CreateTableString_AniDB_Character() + { + List cmds = new List(); + cmds.Add("CREATE TABLE AniDB_Character ( " + + " AniDB_CharacterID int IDENTITY(1,1) NOT NULL, " + + " CharID int NOT NULL, " + + " CharName nvarchar(200) NOT NULL, " + + " PicName varchar(100) NOT NULL, " + + " CharKanjiName nvarchar(max) NOT NULL, " + + " CharDescription nvarchar(max) NOT NULL, " + + " CreatorListRaw varchar(max) NOT NULL, " + + " CONSTRAINT [PK_AniDB_Character] PRIMARY KEY CLUSTERED " + + " ( " + + " AniDB_CharacterID ASC " + + " )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] " + + " ) ON [PRIMARY] "); + + cmds.Add("CREATE UNIQUE INDEX UIX_AniDB_Character_CharID ON AniDB_Character(CharID)"); + + return cmds; + } + + public static List CreateTableString_AniDB_Character_Creator() + { + List cmds = new List(); + cmds.Add("CREATE TABLE AniDB_Character_Creator ( " + + " AniDB_Character_CreatorID int IDENTITY(1,1) NOT NULL, " + + " CharID int NOT NULL, " + + " CreatorID int NOT NULL " + + " CONSTRAINT [PK_AniDB_Character_Creator] PRIMARY KEY CLUSTERED " + + " ( " + + " AniDB_Character_CreatorID ASC " + + " )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] " + + " ) ON [PRIMARY] "); + + cmds.Add("CREATE INDEX IX_AniDB_Character_Creator_CharID on AniDB_Character_Creator(CharID)"); + cmds.Add("CREATE INDEX IX_AniDB_Character_Creator_CreatorID on AniDB_Character_Creator(CreatorID)"); + cmds.Add("CREATE UNIQUE INDEX UIX_AniDB_Character_Creator_CharID_CreatorID ON AniDB_Character_Creator(CharID, CreatorID)"); + + return cmds; + } + + public static List CreateTableString_AniDB_Creator() + { + List cmds = new List(); + cmds.Add("CREATE TABLE AniDB_Creator ( " + + " AniDB_CreatorID int IDENTITY(1,1) NOT NULL, " + + " CreatorID int NOT NULL, " + + " CreatorName nvarchar(200) NOT NULL, " + + " PicName varchar(100) NOT NULL, " + + " CreatorKanjiName nvarchar(max) NOT NULL, " + + " CreatorDescription nvarchar(max) NOT NULL, " + + " CreatorType int NOT NULL, " + + " URLEnglish nvarchar(max) NOT NULL, " + + " URLJapanese nvarchar(max) NOT NULL, " + + " URLWikiEnglish nvarchar(max) NOT NULL, " + + " URLWikiJapanese nvarchar(max) NOT NULL, " + + " CONSTRAINT [PK_AniDB_Creator] PRIMARY KEY CLUSTERED " + + " ( " + + " AniDB_CreatorID ASC " + + " )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] " + + " ) ON [PRIMARY] "); + + cmds.Add("CREATE UNIQUE INDEX UIX_AniDB_Creator_CreatorID ON AniDB_Creator(CreatorID)"); + + + return cmds; + } + + public static List CreateTableString_AniDB_Episode() + { + List cmds = new List(); + cmds.Add("CREATE TABLE AniDB_Episode( " + + " AniDB_EpisodeID int IDENTITY(1,1) NOT NULL, " + + " EpisodeID int NOT NULL, " + + " AnimeID int NOT NULL, " + + " LengthSeconds int NOT NULL, " + + " Rating varchar(max) NOT NULL, " + + " Votes varchar(max) NOT NULL, " + + " EpisodeNumber int NOT NULL, " + + " EpisodeType int NOT NULL, " + + " RomajiName varchar(max) NOT NULL, " + + " EnglishName varchar(max) NOT NULL, " + + " AirDate int NOT NULL, " + + " DateTimeUpdated datetime NOT NULL, " + + " CONSTRAINT [PK_AniDB_Episode] PRIMARY KEY CLUSTERED " + + " ( " + + " AniDB_EpisodeID ASC " + + " )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] " + + " ) ON [PRIMARY] "); + + cmds.Add("CREATE INDEX IX_AniDB_Episode_AnimeID on AniDB_Episode(AnimeID)"); + cmds.Add("CREATE UNIQUE INDEX UIX_AniDB_Episode_EpisodeID ON AniDB_Episode(EpisodeID)"); + + return cmds; + } + + public static List CreateTableString_AniDB_File() + { + List cmds = new List(); + cmds.Add("CREATE TABLE AniDB_File( " + + " AniDB_FileID int IDENTITY(1,1) NOT NULL, " + + " FileID int NOT NULL, " + + " Hash varchar(50) NOT NULL, " + + " AnimeID int NOT NULL, " + + " GroupID int NOT NULL, " + + " File_Source varchar(max) NOT NULL, " + + " File_AudioCodec varchar(max) NOT NULL, " + + " File_VideoCodec varchar(max) NOT NULL, " + + " File_VideoResolution varchar(max) NOT NULL, " + + " File_FileExtension varchar(max) NOT NULL, " + + " File_LengthSeconds int NOT NULL, " + + " File_Description varchar(max) NOT NULL, " + + " File_ReleaseDate int NOT NULL, " + + " Anime_GroupName nvarchar(max) NOT NULL, " + + " Anime_GroupNameShort nvarchar(max) NOT NULL, " + + " Episode_Rating int NOT NULL, " + + " Episode_Votes int NOT NULL, " + + " DateTimeUpdated datetime NOT NULL, " + + " IsWatched int NOT NULL, " + + " WatchedDate datetime NULL, " + + " CRC varchar(max) NOT NULL, " + + " MD5 varchar(max) NOT NULL, " + + " SHA1 varchar(max) NOT NULL, " + + " FileName nvarchar(max) NOT NULL, " + + " FileSize bigint NOT NULL, " + + " CONSTRAINT [PK_AniDB_File] PRIMARY KEY CLUSTERED " + + " ( " + + " AniDB_FileID ASC " + + " )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] " + + " ) ON [PRIMARY] "); + + cmds.Add("CREATE UNIQUE INDEX UIX_AniDB_File_Hash on AniDB_File(Hash)"); + cmds.Add("CREATE UNIQUE INDEX UIX_AniDB_File_FileID ON AniDB_File(FileID)"); + + return cmds; + } + + public static List CreateTableString_AniDB_GroupStatus() + { + List cmds = new List(); + cmds.Add("CREATE TABLE AniDB_GroupStatus ( " + + " AniDB_GroupStatusID int IDENTITY(1,1) NOT NULL, " + + " AnimeID int NOT NULL, " + + " GroupID int NOT NULL, " + + " GroupName nvarchar(200) NOT NULL, " + + " CompletionState int NOT NULL, " + + " LastEpisodeNumber int NOT NULL, " + + " Rating int NOT NULL, " + + " Votes int NOT NULL, " + + " EpisodeRange nvarchar(200) NOT NULL, " + + " CONSTRAINT [PK_AniDB_GroupStatus] PRIMARY KEY CLUSTERED " + + " ( " + + " AniDB_GroupStatusID ASC " + + " )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] " + + " ) ON [PRIMARY] "); + + cmds.Add("CREATE INDEX IX_AniDB_GroupStatus_AnimeID on AniDB_GroupStatus(AnimeID)"); + cmds.Add("CREATE UNIQUE INDEX UIX_AniDB_GroupStatus_AnimeID_GroupID ON AniDB_GroupStatus(AnimeID, GroupID)"); + + + return cmds; + } + + public static List CreateTableString_AniDB_ReleaseGroup() + { + List cmds = new List(); + cmds.Add("CREATE TABLE AniDB_ReleaseGroup ( " + + " AniDB_ReleaseGroupID int IDENTITY(1,1) NOT NULL, " + + " GroupID int NOT NULL, " + + " Rating int NOT NULL, " + + " Votes int NOT NULL, " + + " AnimeCount int NOT NULL, " + + " FileCount int NOT NULL, " + + " GroupName nvarchar(MAX) NOT NULL, " + + " GroupNameShort nvarchar(200) NOT NULL, " + + " IRCChannel nvarchar(200) NOT NULL, " + + " IRCServer nvarchar(200) NOT NULL, " + + " URL nvarchar(200) NOT NULL, " + + " Picname nvarchar(200) NOT NULL, " + + " CONSTRAINT [PK_AniDB_ReleaseGroup] PRIMARY KEY CLUSTERED " + + " ( " + + " AniDB_ReleaseGroupID ASC " + + " )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] " + + " ) ON [PRIMARY] "); + + cmds.Add("CREATE UNIQUE INDEX UIX_AniDB_ReleaseGroup_GroupID ON AniDB_ReleaseGroup(GroupID)"); + + + return cmds; + } + + public static List CreateTableString_AniDB_Review() + { + List cmds = new List(); + cmds.Add("CREATE TABLE AniDB_Review ( " + + " AniDB_ReviewID int IDENTITY(1,1) NOT NULL, " + + " ReviewID int NOT NULL, " + + " AuthorID int NOT NULL, " + + " RatingAnimation int NOT NULL, " + + " RatingSound int NOT NULL, " + + " RatingStory int NOT NULL, " + + " RatingCharacter int NOT NULL, " + + " RatingValue int NOT NULL, " + + " RatingEnjoyment int NOT NULL, " + + " ReviewText nvarchar(MAX) NOT NULL, " + + " CONSTRAINT [PK_AniDB_Review] PRIMARY KEY CLUSTERED " + + " ( " + + " AniDB_ReviewID ASC " + + " )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] " + + " ) ON [PRIMARY] "); + + cmds.Add("CREATE UNIQUE INDEX UIX_AniDB_Review_ReviewID ON AniDB_Review(ReviewID)"); + + + return cmds; + } + + public static List CreateTableString_AniDB_Tag() + { + List cmds = new List(); + cmds.Add("CREATE TABLE AniDB_Tag ( " + + " AniDB_TagID int IDENTITY(1,1) NOT NULL, " + + " TagID int NOT NULL, " + + " Spoiler int NOT NULL, " + + " LocalSpoiler int NOT NULL, " + + " GlobalSpoiler int NOT NULL, " + + " TagName nvarchar(150) NOT NULL, " + + " TagCount int NOT NULL, " + + " TagDescription nvarchar(max) NOT NULL, " + + " CONSTRAINT [PK_AniDB_Tag] PRIMARY KEY CLUSTERED " + + " ( " + + " AniDB_TagID ASC " + + " )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] " + + " ) ON [PRIMARY] "); + + cmds.Add("CREATE UNIQUE INDEX UIX_AniDB_Tag_TagID ON AniDB_Tag(TagID)"); + + return cmds; + } + + public static List CreateTableString_AnimeEpisode() + { + List cmds = new List(); + cmds.Add("CREATE TABLE AnimeEpisode( " + + " AnimeEpisodeID int IDENTITY(1,1) NOT NULL, " + + " AnimeSeriesID int NOT NULL, " + + " AniDB_EpisodeID int NOT NULL, " + + " DateTimeUpdated datetime NOT NULL, " + + " DateTimeCreated datetime NOT NULL, " + + " CONSTRAINT [PK_AnimeEpisode] PRIMARY KEY CLUSTERED " + + " ( " + + " AnimeEpisodeID ASC " + + " )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] " + + " ) ON [PRIMARY]"); + + cmds.Add("CREATE UNIQUE INDEX UIX_AnimeEpisode_AniDB_EpisodeID ON AnimeEpisode(AniDB_EpisodeID)"); + cmds.Add("CREATE INDEX IX_AnimeEpisode_AnimeSeriesID on AnimeEpisode(AnimeSeriesID)"); + + return cmds; + } + + public static List CreateTableString_AnimeEpisode_User() + { + List cmds = new List(); + cmds.Add("CREATE TABLE AnimeEpisode_User( " + + " AnimeEpisode_UserID int IDENTITY(1,1) NOT NULL, " + + " JMMUserID int NOT NULL, " + + " AnimeEpisodeID int NOT NULL, " + + " AnimeSeriesID int NOT NULL, " + // we only have this column to improve performance + " WatchedDate datetime NOT NULL, " + + " PlayedCount int NOT NULL, " + + " WatchedCount int NOT NULL, " + + " StoppedCount int NOT NULL, " + + " CONSTRAINT [PK_AnimeEpisode_User] PRIMARY KEY CLUSTERED " + + " ( " + + " AnimeEpisode_UserID ASC " + + " )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] " + + " ) ON [PRIMARY]"); + + cmds.Add("CREATE UNIQUE INDEX UIX_AnimeEpisode_User_User_EpisodeID ON AnimeEpisode_User(JMMUserID, AnimeEpisodeID)"); + cmds.Add("CREATE INDEX IX_AnimeEpisode_User_User_AnimeSeriesID on AnimeEpisode_User(JMMUserID, AnimeSeriesID)"); + + return cmds; + } + + public static List CreateTableString_VideoLocal() + { + List cmds = new List(); + cmds.Add("CREATE TABLE VideoLocal( " + + " VideoLocalID int IDENTITY(1,1) NOT NULL, " + + " FilePath nvarchar(max) NOT NULL, " + + " ImportFolderID int NOT NULL, " + + " Hash varchar(50) NOT NULL, " + + " CRC32 varchar(50) NULL, " + + " MD5 varchar(50) NULL, " + + " SHA1 varchar(50) NULL, " + + " HashSource int NOT NULL, " + + " FileSize bigint NOT NULL, " + + " IsIgnored int NOT NULL, " + + " DateTimeUpdated datetime NOT NULL, " + + " CONSTRAINT [PK_VideoLocal] PRIMARY KEY CLUSTERED " + + " ( " + + " VideoLocalID ASC " + + " )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] " + + " ) ON [PRIMARY] "); + + cmds.Add("CREATE UNIQUE INDEX UIX_VideoLocal_Hash on VideoLocal(Hash)"); + + return cmds; + } + + public static List CreateTableString_VideoLocal_User() + { + List cmds = new List(); + cmds.Add("CREATE TABLE VideoLocal_User( " + + " VideoLocal_UserID int IDENTITY(1,1) NOT NULL, " + + " JMMUserID int NOT NULL, " + + " VideoLocalID int NOT NULL, " + + " WatchedDate datetime NOT NULL, " + + " CONSTRAINT [PK_VideoLocal_User] PRIMARY KEY CLUSTERED " + + " ( " + + " VideoLocal_UserID ASC " + + " )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] " + + " ) ON [PRIMARY] "); + + cmds.Add("CREATE UNIQUE INDEX UIX_VideoLocal_User_User_VideoLocalID ON VideoLocal_User(JMMUserID, VideoLocalID)"); + + return cmds; + } + + public static List CreateTableString_AnimeGroup() + { + List cmds = new List(); + cmds.Add("CREATE TABLE AnimeGroup( " + + " AnimeGroupID int IDENTITY(1,1) NOT NULL, " + + " AnimeGroupParentID int NULL, " + + " GroupName nvarchar(max) NOT NULL, " + + " Description nvarchar(max) NULL, " + + " IsManuallyNamed int NOT NULL, " + + " DateTimeUpdated datetime NOT NULL, " + + " DateTimeCreated datetime NOT NULL, " + + + " SortName varchar(max) NOT NULL, " + + " MissingEpisodeCount int NOT NULL, " + + " MissingEpisodeCountGroups int NOT NULL, " + + " OverrideDescription int NOT NULL, " + + " EpisodeAddedDate datetime NULL, " + + " CONSTRAINT [PK_AnimeGroup] PRIMARY KEY CLUSTERED " + + " ( " + + " [AnimeGroupID] ASC " + + " )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] " + + " ) ON [PRIMARY] "); + + return cmds; + } + + public static List CreateTableString_AnimeGroup_User() + { + List cmds = new List(); + cmds.Add("CREATE TABLE AnimeGroup_User( " + + " AnimeGroup_UserID int IDENTITY(1,1) NOT NULL, " + + " JMMUserID int NOT NULL, " + + " AnimeGroupID int NOT NULL, " + + " IsFave int NOT NULL, " + + " UnwatchedEpisodeCount int NOT NULL, " + + " WatchedEpisodeCount int NOT NULL, " + + " WatchedDate datetime NULL, " + + " PlayedCount int NOT NULL, " + + " WatchedCount int NOT NULL, " + + " StoppedCount int NOT NULL, " + + " CONSTRAINT [PK_AnimeGroup_User] PRIMARY KEY CLUSTERED " + + " ( " + + " AnimeGroup_UserID ASC " + + " )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] " + + " ) ON [PRIMARY]"); + + cmds.Add("CREATE UNIQUE INDEX UIX_AnimeGroup_User_User_GroupID ON AnimeGroup_User(JMMUserID, AnimeGroupID)"); + + return cmds; + } + + public static List CreateTableString_AnimeSeries() + { + List cmds = new List(); + cmds.Add("CREATE TABLE AnimeSeries ( " + + " AnimeSeriesID int IDENTITY(1,1) NOT NULL, " + + " AnimeGroupID int NOT NULL, " + + " AniDB_ID int NOT NULL, " + + " DateTimeUpdated datetime NOT NULL, " + + " DateTimeCreated datetime NOT NULL, " + + " DefaultAudioLanguage varchar(max) NULL, " + + " DefaultSubtitleLanguage varchar(max) NULL, " + + " MissingEpisodeCount int NOT NULL, " + + " MissingEpisodeCountGroups int NOT NULL, " + + " LatestLocalEpisodeNumber int NOT NULL, " + + " EpisodeAddedDate datetime NULL, " + + " CONSTRAINT [PK_AnimeSeries] PRIMARY KEY CLUSTERED " + + " ( " + + " AnimeSeriesID ASC " + + " )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] " + + " ) ON [PRIMARY] "); + + cmds.Add("CREATE UNIQUE INDEX UIX_AnimeSeries_AniDB_ID ON AnimeSeries(AniDB_ID)"); + + return cmds; + } + + public static List CreateTableString_AnimeSeries_User() + { + List cmds = new List(); + cmds.Add("CREATE TABLE AnimeSeries_User( " + + " AnimeSeries_UserID int IDENTITY(1,1) NOT NULL, " + + " JMMUserID int NOT NULL, " + + " AnimeSeriesID int NOT NULL, " + + " UnwatchedEpisodeCount int NOT NULL, " + + " WatchedEpisodeCount int NOT NULL, " + + " WatchedDate datetime NULL, " + + " PlayedCount int NOT NULL, " + + " WatchedCount int NOT NULL, " + + " StoppedCount int NOT NULL, " + + " CONSTRAINT [PK_AnimeSeries_User] PRIMARY KEY CLUSTERED " + + " ( " + + " AnimeSeries_UserID ASC " + + " )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] " + + " ) ON [PRIMARY]"); + + cmds.Add("CREATE UNIQUE INDEX UIX_AnimeSeries_User_User_SeriesID ON AnimeSeries_User(JMMUserID, AnimeSeriesID)"); + + return cmds; + } + + public static List CreateTableString_CommandRequest() + { + List cmds = new List(); + cmds.Add("CREATE TABLE CommandRequest( " + + " CommandRequestID int IDENTITY(1,1) NOT NULL, " + + " Priority int NOT NULL, " + + " CommandType int NOT NULL, " + + " CommandID nvarchar(max) NOT NULL, " + + " CommandDetails nvarchar(max) NOT NULL, " + + " DateTimeUpdated datetime NOT NULL, " + + " CONSTRAINT [PK_CommandRequest] PRIMARY KEY CLUSTERED " + + " ( " + + " CommandRequestID ASC " + + " )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] " + + " ) ON [PRIMARY] "); + + return cmds; + } + + + + public static List CreateTableString_CrossRef_AniDB_TvDB() + { + List cmds = new List(); + cmds.Add("CREATE TABLE CrossRef_AniDB_TvDB( " + + " CrossRef_AniDB_TvDBID int IDENTITY(1,1) NOT NULL, " + + " AnimeID int NOT NULL, " + + " TvDBID int NOT NULL, " + + " TvDBSeasonNumber int NOT NULL, " + + " CrossRefSource int NOT NULL, " + + " CONSTRAINT [PK_CrossRef_AniDB_TvDB] PRIMARY KEY CLUSTERED " + + " ( " + + " CrossRef_AniDB_TvDBID ASC " + + " )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] " + + " ) ON [PRIMARY] "); + + cmds.Add("CREATE UNIQUE INDEX UIX_CrossRef_AniDB_TvDB ON CrossRef_AniDB_TvDB(AnimeID, TvDBID, TvDBSeasonNumber, CrossRefSource)"); + cmds.Add("CREATE UNIQUE INDEX UIX_CrossRef_AniDB_TvDB_AnimeID ON CrossRef_AniDB_TvDB(AnimeID)"); + + return cmds; + } + + public static List CreateTableString_CrossRef_AniDB_Other() + { + List cmds = new List(); + cmds.Add("CREATE TABLE CrossRef_AniDB_Other( " + + " CrossRef_AniDB_OtherID int IDENTITY(1,1) NOT NULL, " + + " AnimeID int NOT NULL, " + + " CrossRefID nvarchar(500) NOT NULL, " + + " CrossRefSource int NOT NULL, " + + " CrossRefType int NOT NULL, " + + " CONSTRAINT [PK_CrossRef_AniDB_Other] PRIMARY KEY CLUSTERED " + + " ( " + + " CrossRef_AniDB_OtherID ASC " + + " )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] " + + " ) ON [PRIMARY] "); + + cmds.Add("CREATE UNIQUE INDEX UIX_CrossRef_AniDB_Other ON CrossRef_AniDB_Other(AnimeID, CrossRefID, CrossRefSource, CrossRefType)"); + + return cmds; + } + + public static List CreateTableString_CrossRef_File_Episode() + { + List cmds = new List(); + cmds.Add("CREATE TABLE CrossRef_File_Episode( " + + " CrossRef_File_EpisodeID int IDENTITY(1,1) NOT NULL, " + + " Hash varchar(50) NULL, " + + " FileName nvarchar(500) NOT NULL, " + + " FileSize bigint NOT NULL, " + + " CrossRefSource int NOT NULL, " + + " AnimeID int NOT NULL, " + + " EpisodeID int NOT NULL, " + + " Percentage int NOT NULL, " + + " EpisodeOrder int NOT NULL, " + + " CONSTRAINT [PK_CrossRef_File_Episode] PRIMARY KEY CLUSTERED " + + " ( " + + " CrossRef_File_EpisodeID ASC " + + " )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] " + + " ) ON [PRIMARY] "); + + cmds.Add("CREATE UNIQUE INDEX UIX_CrossRef_File_Episode_Hash_EpisodeID ON CrossRef_File_Episode(Hash, EpisodeID)"); + + return cmds; + } + + public static List CreateTableString_CrossRef_Languages_AniDB_File() + { + List cmds = new List(); + cmds.Add("CREATE TABLE CrossRef_Languages_AniDB_File( " + + " CrossRef_Languages_AniDB_FileID int IDENTITY(1,1) NOT NULL, " + + " FileID int NOT NULL, " + + " LanguageID int NOT NULL, " + + " CONSTRAINT [PK_CrossRef_Languages_AniDB_File] PRIMARY KEY CLUSTERED " + + " ( " + + " CrossRef_Languages_AniDB_FileID ASC " + + " )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] " + + " ) ON [PRIMARY] ");; + + return cmds; + } + + public static List CreateTableString_CrossRef_Subtitles_AniDB_File() + { + List cmds = new List(); + cmds.Add("CREATE TABLE CrossRef_Subtitles_AniDB_File( " + + " CrossRef_Subtitles_AniDB_FileID int IDENTITY(1,1) NOT NULL, " + + " FileID int NOT NULL, " + + " LanguageID int NOT NULL, " + + " CONSTRAINT [PK_CrossRef_Subtitles_AniDB_File] PRIMARY KEY CLUSTERED " + + " ( " + + " CrossRef_Subtitles_AniDB_FileID ASC " + + " )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] " + + " ) ON [PRIMARY] "); + + return cmds; + } + + public static List CreateTableString_FileNameHash() + { + List cmds = new List(); + cmds.Add("CREATE TABLE FileNameHash ( " + + " FileNameHashID int IDENTITY(1,1) NOT NULL, " + + " FileName nvarchar(500) NOT NULL, " + + " FileSize bigint NOT NULL, " + + " Hash varchar(50) NOT NULL, " + + " DateTimeUpdated datetime NOT NULL, " + + " CONSTRAINT [PK_FileNameHash] PRIMARY KEY CLUSTERED " + + " ( " + + " FileNameHashID ASC " + + " )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] " + + " ) ON [PRIMARY] "); + + cmds.Add("CREATE UNIQUE INDEX UIX_FileNameHash ON FileNameHash(FileName, FileSize, Hash)"); + + return cmds; + } + + public static List CreateTableString_Language() + { + List cmds = new List(); + cmds.Add("CREATE TABLE Language( " + + " LanguageID int IDENTITY(1,1) NOT NULL, " + + " LanguageName varchar(100) NOT NULL, " + + " CONSTRAINT [PK_Language] PRIMARY KEY CLUSTERED " + + " ( " + + " LanguageID ASC " + + " )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] " + + " ) ON [PRIMARY] "); + + cmds.Add("CREATE UNIQUE INDEX UIX_Language_LanguageName ON Language(LanguageName)"); + + return cmds; + } + + public static List CreateTableString_ImportFolder() + { + List cmds = new List(); + cmds.Add("CREATE TABLE ImportFolder( " + + " ImportFolderID int IDENTITY(1,1) NOT NULL, " + + " ImportFolderType int NOT NULL, " + + " ImportFolderName nvarchar(max) NOT NULL, " + + " ImportFolderLocation nvarchar(max) NOT NULL, " + + " IsDropSource int NOT NULL, " + + " IsDropDestination int NOT NULL, " + + " CONSTRAINT [PK_ImportFolder] PRIMARY KEY CLUSTERED " + + " ( " + + " ImportFolderID ASC " + + " )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] " + + " ) ON [PRIMARY] "); + + return cmds; + } + + public static List CreateTableString_ScheduledUpdate() + { + List cmds = new List(); + cmds.Add("CREATE TABLE ScheduledUpdate( " + + " ScheduledUpdateID int IDENTITY(1,1) NOT NULL, " + + " UpdateType int NOT NULL, " + + " LastUpdate datetime NOT NULL, " + + " UpdateDetails nvarchar(max) NOT NULL, " + + " CONSTRAINT [PK_ScheduledUpdate] PRIMARY KEY CLUSTERED " + + " ( " + + " ScheduledUpdateID ASC " + + " )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] " + + " ) ON [PRIMARY] "); + + cmds.Add("CREATE UNIQUE INDEX UIX_ScheduledUpdate_UpdateType ON ScheduledUpdate(UpdateType)"); + + return cmds; + } + + public static List CreateTableString_VideoInfo() + { + List cmds = new List(); + cmds.Add("CREATE TABLE VideoInfo ( " + + " VideoInfoID int IDENTITY(1,1) NOT NULL, " + + " Hash varchar(50) NOT NULL, " + + " FileSize bigint NOT NULL, " + + " FileName nvarchar(max) NOT NULL, " + + " DateTimeUpdated datetime NOT NULL, " + + " VideoCodec varchar(max) NOT NULL, " + + " VideoBitrate varchar(max) NOT NULL, " + + " VideoFrameRate varchar(max) NOT NULL, " + + " VideoResolution varchar(max) NOT NULL, " + + " AudioCodec varchar(max) NOT NULL, " + + " AudioBitrate varchar(max) NOT NULL, " + + " Duration bigint NOT NULL, " + + " CONSTRAINT [PK_VideoInfo] PRIMARY KEY CLUSTERED " + + " ( " + + " VideoInfoID ASC " + + " )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] " + + " ) ON [PRIMARY] "); + + cmds.Add("CREATE UNIQUE INDEX UIX_VideoInfo_Hash on VideoInfo(Hash)"); + + return cmds; + } + + + + public static List CreateTableString_DuplicateFile() + { + List cmds = new List(); + cmds.Add("CREATE TABLE DuplicateFile( " + + " DuplicateFileID int IDENTITY(1,1) NOT NULL, " + + " FilePathFile1 nvarchar(max) NOT NULL, " + + " FilePathFile2 nvarchar(max) NOT NULL, " + + " ImportFolderIDFile1 int NOT NULL, " + + " ImportFolderIDFile2 int NOT NULL, " + + " Hash varchar(50) NOT NULL, " + + " DateTimeUpdated datetime NOT NULL, " + + " CONSTRAINT [PK_DuplicateFile] PRIMARY KEY CLUSTERED " + + " ( " + + " DuplicateFileID ASC " + + " )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] " + + " ) ON [PRIMARY] "); + + return cmds; + } + + public static List CreateTableString_GroupFilter() + { + List cmds = new List(); + cmds.Add("CREATE TABLE GroupFilter( " + + " GroupFilterID int IDENTITY(1,1) NOT NULL, " + + " GroupFilterName nvarchar(max) NOT NULL, " + + " ApplyToSeries int NOT NULL, " + + " BaseCondition int NOT NULL, " + + " SortingCriteria nvarchar(max), " + + " CONSTRAINT [PK_GroupFilter] PRIMARY KEY CLUSTERED " + + " ( " + + " GroupFilterID ASC " + + " )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] " + + " ) ON [PRIMARY] "); + + return cmds; + } + + public static List CreateTableString_GroupFilterCondition() + { + List cmds = new List(); + cmds.Add("CREATE TABLE GroupFilterCondition( " + + " GroupFilterConditionID int IDENTITY(1,1) NOT NULL, " + + " GroupFilterID int NOT NULL, " + + " ConditionType int NOT NULL, " + + " ConditionOperator int NOT NULL, " + + " ConditionParameter nvarchar(max) NOT NULL, " + + " CONSTRAINT [PK_GroupFilterCondition] PRIMARY KEY CLUSTERED " + + " ( " + + " GroupFilterConditionID ASC " + + " )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] " + + " ) ON [PRIMARY] "); + + return cmds; + } + + public static List CreateTableString_AniDB_Vote() + { + List cmds = new List(); + cmds.Add("CREATE TABLE AniDB_Vote ( " + + " AniDB_VoteID int IDENTITY(1,1) NOT NULL, " + + " EntityID int NOT NULL, " + + " VoteValue int NOT NULL, " + + " VoteType int NOT NULL, " + + " CONSTRAINT [PK_AniDB_Vote] PRIMARY KEY CLUSTERED " + + " ( " + + " AniDB_VoteID ASC " + + " )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] " + + " ) ON [PRIMARY] "); + + return cmds; + } + + public static List CreateTableString_TvDB_ImageFanart() + { + List cmds = new List(); + cmds.Add("CREATE TABLE TvDB_ImageFanart( " + + " TvDB_ImageFanartID int IDENTITY(1,1) NOT NULL, " + + " Id int NOT NULL, " + + " SeriesID int NOT NULL, " + + " BannerPath nvarchar(MAX), " + + " BannerType nvarchar(MAX), " + + " BannerType2 nvarchar(MAX), " + + " Colors nvarchar(MAX), " + + " Language nvarchar(MAX), " + + " ThumbnailPath nvarchar(MAX), " + + " VignettePath nvarchar(MAX), " + + " Enabled int NOT NULL, " + + " Chosen int NOT NULL, " + + " CONSTRAINT PK_TvDB_ImageFanart PRIMARY KEY CLUSTERED " + + " ( " + + " TvDB_ImageFanartID ASC " + + " )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] " + + " ) ON [PRIMARY] "); + + cmds.Add("CREATE UNIQUE INDEX UIX_TvDB_ImageFanart_Id ON TvDB_ImageFanart(Id)"); + + return cmds; + } + + public static List CreateTableString_TvDB_ImageWideBanner() + { + List cmds = new List(); + cmds.Add("CREATE TABLE TvDB_ImageWideBanner( " + + " TvDB_ImageWideBannerID int IDENTITY(1,1) NOT NULL, " + + " Id int NOT NULL, " + + " SeriesID int NOT NULL, " + + " BannerPath nvarchar(MAX), " + + " BannerType nvarchar(MAX), " + + " BannerType2 nvarchar(MAX), " + + " Language nvarchar(MAX), " + + " Enabled int NOT NULL, " + + " SeasonNumber int, " + + " CONSTRAINT PK_TvDB_ImageWideBanner PRIMARY KEY CLUSTERED " + + " ( " + + " TvDB_ImageWideBannerID ASC " + + " )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] " + + " ) ON [PRIMARY] "); + + cmds.Add("CREATE UNIQUE INDEX UIX_TvDB_ImageWideBanner_Id ON TvDB_ImageWideBanner(Id)"); + + return cmds; + } + + public static List CreateTableString_TvDB_ImagePoster() + { + List cmds = new List(); + cmds.Add("CREATE TABLE TvDB_ImagePoster( " + + " TvDB_ImagePosterID int IDENTITY(1,1) NOT NULL, " + + " Id int NOT NULL, " + + " SeriesID int NOT NULL, " + + " BannerPath nvarchar(MAX), " + + " BannerType nvarchar(MAX), " + + " BannerType2 nvarchar(MAX), " + + " Language nvarchar(MAX), " + + " Enabled int NOT NULL, " + + " SeasonNumber int, " + + " CONSTRAINT PK_TvDB_ImagePoster PRIMARY KEY CLUSTERED " + + " ( " + + " TvDB_ImagePosterID ASC " + + " )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] " + + " ) ON [PRIMARY] "); + + cmds.Add("CREATE UNIQUE INDEX UIX_TvDB_ImagePoster_Id ON TvDB_ImagePoster(Id)"); + + return cmds; + } + + public static List CreateTableString_TvDB_Episode() + { + List cmds = new List(); + cmds.Add("CREATE TABLE TvDB_Episode( " + + " TvDB_EpisodeID int IDENTITY(1,1) NOT NULL, " + + " Id int NOT NULL, " + + " SeriesID int NOT NULL, " + + " SeasonID int NOT NULL, " + + " SeasonNumber int NOT NULL, " + + " EpisodeNumber int NOT NULL, " + + " EpisodeName nvarchar(MAX), " + + " Overview nvarchar(MAX), " + + " Filename nvarchar(MAX), " + + " EpImgFlag int NOT NULL, " + + " FirstAired nvarchar(MAX), " + + " AbsoluteNumber int, " + + " AirsAfterSeason int, " + + " AirsBeforeEpisode int, " + + " AirsBeforeSeason int, " + + " CONSTRAINT PK_TvDB_Episode PRIMARY KEY CLUSTERED " + + " ( " + + " TvDB_EpisodeID ASC " + + " )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] " + + " ) ON [PRIMARY] "); + + cmds.Add("CREATE UNIQUE INDEX UIX_TvDB_Episode_Id ON TvDB_Episode(Id)"); + + return cmds; + } + + public static List CreateTableString_TvDB_Series() + { + List cmds = new List(); + cmds.Add("CREATE TABLE TvDB_Series( " + + " TvDB_SeriesID int IDENTITY(1,1) NOT NULL, " + + " SeriesID int NOT NULL, " + + " Overview nvarchar(MAX), " + + " SeriesName nvarchar(MAX), " + + " Status varchar(100), " + + " Banner varchar(100), " + + " Fanart varchar(100), " + + " Poster varchar(100), " + + " Lastupdated varchar(100), " + + " CONSTRAINT PK_TvDB_Series PRIMARY KEY CLUSTERED " + + " ( " + + " TvDB_SeriesID ASC " + + " )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] " + + " ) ON [PRIMARY] "); + + cmds.Add("CREATE UNIQUE INDEX UIX_TvDB_Series_Id ON TvDB_Series(SeriesID)"); + + return cmds; + } + + public static List CreateTableString_AniDB_Anime_DefaultImage() + { + List cmds = new List(); + cmds.Add("CREATE TABLE AniDB_Anime_DefaultImage ( " + + " AniDB_Anime_DefaultImageID int IDENTITY(1,1) NOT NULL, " + + " AnimeID int NOT NULL, " + + " ImageParentID int NOT NULL, " + + " ImageParentType int NOT NULL, " + + " ImageType int NOT NULL, " + + " CONSTRAINT [PK_AniDB_Anime_DefaultImage] PRIMARY KEY CLUSTERED " + + " ( " + + " [AniDB_Anime_DefaultImageID] ASC " + + " )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] " + + " ) ON [PRIMARY] "); + + cmds.Add("CREATE UNIQUE INDEX UIX_AniDB_Anime_DefaultImage_ImageType ON AniDB_Anime_DefaultImage(AnimeID, ImageType)"); + + return cmds; + } + + public static List CreateTableString_MovieDB_Movie() + { + List cmds = new List(); + + cmds.Add("CREATE TABLE MovieDB_Movie( " + + " MovieDB_MovieID int IDENTITY(1,1) NOT NULL, " + + " MovieId int NOT NULL, " + + " MovieName nvarchar(MAX), " + + " OriginalName nvarchar(MAX), " + + " Overview nvarchar(MAX), " + + " CONSTRAINT PK_MovieDB_Movie PRIMARY KEY CLUSTERED " + + " ( " + + " MovieDB_MovieID ASC " + + " )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] " + + " ) ON [PRIMARY] "); + + cmds.Add("CREATE UNIQUE INDEX UIX_MovieDB_Movie_Id ON MovieDB_Movie(MovieId)"); + + return cmds; + } + + public static List CreateTableString_MovieDB_Poster() + { + List cmds = new List(); + + cmds.Add("CREATE TABLE MovieDB_Poster( " + + " MovieDB_PosterID int IDENTITY(1,1) NOT NULL, " + + " ImageID varchar(100), " + + " MovieId int NOT NULL, " + + " ImageType varchar(100), " + + " ImageSize varchar(100), " + + " URL nvarchar(MAX), " + + " ImageWidth int NOT NULL, " + + " ImageHeight int NOT NULL, " + + " Enabled int NOT NULL, " + + " CONSTRAINT PK_MovieDB_Poster PRIMARY KEY CLUSTERED " + + " ( " + + " MovieDB_PosterID ASC " + + " )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] " + + " ) ON [PRIMARY] "); + + return cmds; + } + + public static List CreateTableString_MovieDB_Fanart() + { + List cmds = new List(); + + cmds.Add("CREATE TABLE MovieDB_Fanart( " + + " MovieDB_FanartID int IDENTITY(1,1) NOT NULL, " + + " ImageID varchar(100), " + + " MovieId int NOT NULL, " + + " ImageType varchar(100), " + + " ImageSize varchar(100), " + + " URL nvarchar(MAX), " + + " ImageWidth int NOT NULL, " + + " ImageHeight int NOT NULL, " + + " Enabled int NOT NULL, " + + " CONSTRAINT PK_MovieDB_Fanart PRIMARY KEY CLUSTERED " + + " ( " + + " MovieDB_FanartID ASC " + + " )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] " + + " ) ON [PRIMARY] "); + + return cmds; + } + + public static List CreateTableString_JMMUser() + { + List cmds = new List(); + + cmds.Add("CREATE TABLE JMMUser( " + + " JMMUserID int IDENTITY(1,1) NOT NULL, " + + " Username nvarchar(100), " + + " Password nvarchar(100), " + + " IsAdmin int NOT NULL, " + + " IsAniDBUser int NOT NULL, " + + " IsTraktUser int NOT NULL, " + + " HideCategories nvarchar(MAX), " + + " CONSTRAINT PK_JMMUser PRIMARY KEY CLUSTERED " + + " ( " + + " JMMUserID ASC " + + " )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] " + + " ) ON [PRIMARY] "); + + cmds.Add("INSERT Into JMMUser (Username, Password, IsAdmin, IsAniDBUser, IsTraktUser, HideCategories) VALUES ('Default', '', 1, 1, 1, '')"); + + cmds.Add("INSERT Into JMMUser (Username, Password, IsAdmin, IsAniDBUser, IsTraktUser, HideCategories) VALUES ('Family Friendly', '', 0, 1, 1, 'Ecchi,Nudity,Sex,Sexual Abuse,Horror,Erotic Game,Incest,18 Restricted')"); + + + return cmds; + } + + public static List CreateTableString_Trakt_Episode() + { + List cmds = new List(); + + cmds.Add("CREATE TABLE Trakt_Episode( " + + " Trakt_EpisodeID int IDENTITY(1,1) NOT NULL, " + + " Trakt_ShowID int NOT NULL, " + + " Season int NOT NULL, " + + " EpisodeNumber int NOT NULL, " + + " Title nvarchar(MAX), " + + " URL nvarchar(500), " + + " Overview nvarchar(MAX), " + + " EpisodeImage nvarchar(500), " + + " CONSTRAINT PK_Trakt_Episode PRIMARY KEY CLUSTERED " + + " ( " + + " Trakt_EpisodeID ASC " + + " )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] " + + " ) ON [PRIMARY] "); + + return cmds; + } + + public static List CreateTableString_Trakt_ImagePoster() + { + List cmds = new List(); + + cmds.Add("CREATE TABLE Trakt_ImagePoster( " + + " Trakt_ImagePosterID int IDENTITY(1,1) NOT NULL, " + + " Trakt_ShowID int NOT NULL, " + + " Season int NOT NULL, " + + " ImageURL nvarchar(500), " + + " Enabled int NOT NULL, " + + " CONSTRAINT PK_Trakt_ImagePoster PRIMARY KEY CLUSTERED " + + " ( " + + " Trakt_ImagePosterID ASC " + + " )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] " + + " ) ON [PRIMARY] "); + + return cmds; + } + + public static List CreateTableString_Trakt_ImageFanart() + { + List cmds = new List(); + + cmds.Add("CREATE TABLE Trakt_ImageFanart( " + + " Trakt_ImageFanartID int IDENTITY(1,1) NOT NULL, " + + " Trakt_ShowID int NOT NULL, " + + " Season int NOT NULL, " + + " ImageURL nvarchar(500), " + + " Enabled int NOT NULL, " + + " CONSTRAINT PK_Trakt_ImageFanart PRIMARY KEY CLUSTERED " + + " ( " + + " Trakt_ImageFanartID ASC " + + " )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] " + + " ) ON [PRIMARY] "); + + return cmds; + } + + public static List CreateTableString_Trakt_Show() + { + List cmds = new List(); + + cmds.Add("CREATE TABLE Trakt_Show( " + + " Trakt_ShowID int IDENTITY(1,1) NOT NULL, " + + " TraktID nvarchar(500), " + + " Title nvarchar(MAX), " + + " Year nvarchar(500), " + + " URL nvarchar(500), " + + " Overview nvarchar(MAX), " + + " TvDB_ID int NULL, " + + " CONSTRAINT PK_Trakt_Show PRIMARY KEY CLUSTERED " + + " ( " + + " Trakt_ShowID ASC " + + " )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] " + + " ) ON [PRIMARY] "); + + return cmds; + } + + public static List CreateTableString_Trakt_Season() + { + List cmds = new List(); + + cmds.Add("CREATE TABLE Trakt_Season( " + + " Trakt_SeasonID int IDENTITY(1,1) NOT NULL, " + + " Trakt_ShowID int NOT NULL, " + + " Season int NOT NULL, " + + " URL nvarchar(500), " + + " CONSTRAINT PK_Trakt_Season PRIMARY KEY CLUSTERED " + + " ( " + + " Trakt_SeasonID ASC " + + " )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] " + + " ) ON [PRIMARY] "); + + return cmds; + } + + public static List CreateTableString_CrossRef_AniDB_Trakt() + { + List cmds = new List(); + + cmds.Add("CREATE TABLE CrossRef_AniDB_Trakt( " + + " CrossRef_AniDB_TraktID int IDENTITY(1,1) NOT NULL, " + + " AnimeID int NOT NULL, " + + " TraktID nvarchar(500), " + + " TraktSeasonNumber int NOT NULL, " + + " CrossRefSource int NOT NULL, " + + " CONSTRAINT [PK_CrossRef_AniDB_Trakt] PRIMARY KEY CLUSTERED " + + " ( " + + " CrossRef_AniDB_TraktID ASC " + + " )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] " + + " ) ON [PRIMARY] "); + + return cmds; + } + + #endregion + + public static string GetDatabasePath(string serverName) + { + string dbPath = ""; + + // normally installed versions of sql server + dbPath = GetDatabasePath(serverName, @"SOFTWARE\Microsoft\Microsoft SQL Server"); + if (dbPath.Length > 0) return dbPath; + + // sql server 32bit version installed on 64bit OS + dbPath = GetDatabasePath(serverName, @"SOFTWARE\Wow6432Node\Microsoft\Microsoft SQL Server"); + return dbPath; + } + + public static string GetDatabasePath(string serverName, string registryPoint) + { + string instName = GetInstanceNameFromServerName(serverName).Trim().ToUpper(); + + + + // + using (RegistryKey sqlServerKey = Registry.LocalMachine.OpenSubKey(registryPoint)) + { + foreach (string subKeyName in sqlServerKey.GetSubKeyNames()) + { + if (subKeyName.StartsWith("MSSQL")) + { + using (RegistryKey instanceKey = sqlServerKey.OpenSubKey(subKeyName)) + { + object val = instanceKey.GetValue(""); + if (val != null) + { + string instanceName = val.ToString().Trim().ToUpper(); + + if (instanceName == instName)//say + { + string path = instanceKey.OpenSubKey(@"Setup").GetValue("SQLDataRoot").ToString(); + path = Path.Combine(path, "Data"); + return path; + } + } + } + } + } + } + + return ""; + } + + public static string GetInstanceNameFromServerName(string servername) + { + if (!servername.Contains('\\')) return "MSSQLSERVER"; //default instance + + int pos = servername.IndexOf('\\'); + string instancename = servername.Substring(pos + 1, servername.Length - pos - 1); + + return instancename; + + } + + } + + public class SQLServerDatabase + { + public string MdfFileName { get; set; } + public string MdfFilePath { get; set; } + public string MdfFileSize { get; set; } + public string MdfMaxFileSize { get; set; } + public string MdfFileGrowth { get; set; } + public string LdfFileName { get; set; } + public string LdfFilePath { get; set; } + public string LdfFileSize { get; set; } + public string LdfMaxFileSize { get; set; } + public string LdfFileGrowth { get; set; } + public string DatabaseName { get; set; } + } +} diff --git a/JMMServer/Databases/SQLite.cs b/JMMServer/Databases/SQLite.cs new file mode 100644 index 000000000..0cff1bf37 --- /dev/null +++ b/JMMServer/Databases/SQLite.cs @@ -0,0 +1,1297 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.IO; +using System.Data.SqlClient; +using System.Data.SQLite; +using JMMServer.Entities; +using JMMServer.Repositories; +using NLog; + +namespace JMMServer.Databases +{ + public class SQLite + { + private static Logger logger = LogManager.GetCurrentClassLogger(); + public const string DefaultDBName = @"JMMServer.db3"; + + public static string GetDatabasePath() + { + string appPath = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location); + string dbPath = Path.Combine(appPath, "SQLite"); + return dbPath; + } + + public static string GetDatabaseFilePath() + { + string dbName = Path.Combine(GetDatabasePath(), DefaultDBName); + return dbName; + } + + public static string GetConnectionString() + { + return string.Format(@"data source={0};useutf16encoding=True", GetDatabaseFilePath()); + } + + public static bool DatabaseAlreadyExists() + { + if (SQLite.GetDatabaseFilePath().Length == 0) return false; + + if (File.Exists(SQLite.GetDatabaseFilePath())) + return true; + else + return false; + + } + + public static bool TestLogin(string serverName, string user, string password) + { + return true; + } + + public static void CreateDatabase() + { + if (DatabaseAlreadyExists()) return; + + if (!Directory.Exists(GetDatabasePath())) + Directory.CreateDirectory(GetDatabasePath()); + + if (!File.Exists(GetDatabaseFilePath())) + SQLiteConnection.CreateFile(GetDatabaseFilePath()); + + ServerSettings.DatabaseFile = GetDatabaseFilePath(); + } + + #region Schema Updates + + public static void UpdateSchema() + { + + VersionsRepository repVersions = new VersionsRepository(); + Versions ver = repVersions.GetByVersionType(Constants.DatabaseTypeKey); + if (ver == null) return; + + int versionNumber = 0; + int.TryParse(ver.VersionValue, out versionNumber); + + try + { + UpdateSchema_002(versionNumber); + } + catch (Exception ex) + { + logger.ErrorException("Error updating schema: " + ex.ToString(), ex); + } + + } + + private static void UpdateSchema_002(int currentVersionNumber) + { + /*int thisVersion = 2; + if (currentVersionNumber >= thisVersion) return; + + logger.Info("Updating schema to VERSION: {0}", thisVersion); + + string sql = "ALTER TABLE GroupFilter ADD SortingCriteria text"; + + SQLiteConnection myConn = new SQLiteConnection(GetConnectionString()); + myConn.Open(); + SQLiteCommand sqCommand = new SQLiteCommand(sql); + sqCommand.Connection = myConn; + sqCommand.ExecuteNonQuery(); + myConn.Close(); + + UpdateDatabaseVersion(thisVersion);*/ + + } + + + + + private static void UpdateDatabaseVersion(int versionNumber) + { + VersionsRepository repVersions = new VersionsRepository(); + Versions ver = repVersions.GetByVersionType(Constants.DatabaseTypeKey); + if (ver == null) return; + + ver.VersionValue = versionNumber.ToString(); + repVersions.Save(ver); + } + + #endregion + + #region Create Initial Schema + + public static void CreateInitialSchema() + { + SQLiteConnection myConn = new SQLiteConnection(GetConnectionString()); + myConn.Open(); + + string cmd = string.Format("SELECT count(*) as NumTables FROM sqlite_master WHERE name='Versions'"); + SQLiteCommand sqCommandCheck = new SQLiteCommand(cmd); + sqCommandCheck.Connection = myConn; + long count = long.Parse(sqCommandCheck.ExecuteScalar().ToString()); + + // if the Versions already exists, it means we have done this already + if (count > 0) return; + + //Create all the commands to be executed + List commands = new List(); + commands.AddRange(CreateTableString_Versions()); + commands.AddRange(CreateTableString_AniDB_Anime()); + commands.AddRange(CreateTableString_AniDB_Anime_Category()); + commands.AddRange(CreateTableString_AniDB_Anime_Character()); + commands.AddRange(CreateTableString_AniDB_Anime_Relation()); + commands.AddRange(CreateTableString_AniDB_Anime_Review()); + commands.AddRange(CreateTableString_AniDB_Anime_Similar()); + commands.AddRange(CreateTableString_AniDB_Anime_Tag()); + commands.AddRange(CreateTableString_AniDB_Anime_Title()); + commands.AddRange(CreateTableString_AniDB_Category()); + commands.AddRange(CreateTableString_AniDB_Character()); + commands.AddRange(CreateTableString_AniDB_Character_Creator()); + commands.AddRange(CreateTableString_AniDB_Creator()); + commands.AddRange(CreateTableString_AniDB_Episode()); + commands.AddRange(CreateTableString_AniDB_File()); + commands.AddRange(CreateTableString_AniDB_GroupStatus()); + commands.AddRange(CreateTableString_AniDB_ReleaseGroup()); + commands.AddRange(CreateTableString_AniDB_Review()); + commands.AddRange(CreateTableString_AniDB_Tag()); + commands.AddRange(CreateTableString_AnimeEpisode()); + commands.AddRange(CreateTableString_AnimeGroup()); + commands.AddRange(CreateTableString_AnimeSeries()); + commands.AddRange(CreateTableString_CommandRequest()); + commands.AddRange(CreateTableString_CrossRef_AniDB_Other()); + commands.AddRange(CreateTableString_CrossRef_AniDB_TvDB()); + commands.AddRange(CreateTableString_CrossRef_File_Episode()); + commands.AddRange(CreateTableString_CrossRef_Languages_AniDB_File()); + commands.AddRange(CreateTableString_CrossRef_Subtitles_AniDB_File()); + commands.AddRange(CreateTableString_FileNameHash()); + commands.AddRange(CreateTableString_Language()); + commands.AddRange(CreateTableString_ImportFolder()); + commands.AddRange(CreateTableString_ScheduledUpdate()); + commands.AddRange(CreateTableString_VideoInfo()); + commands.AddRange(CreateTableString_VideoLocal()); + commands.AddRange(CreateTableString_DuplicateFile()); + commands.AddRange(CreateTableString_GroupFilter()); + commands.AddRange(CreateTableString_GroupFilterCondition()); + commands.AddRange(CreateTableString_AniDB_Vote()); + commands.AddRange(CreateTableString_TvDB_ImageFanart()); + commands.AddRange(CreateTableString_TvDB_ImageWideBanner()); + commands.AddRange(CreateTableString_TvDB_ImagePoster()); + commands.AddRange(CreateTableString_TvDB_Episode()); + commands.AddRange(CreateTableString_TvDB_Series()); + commands.AddRange(CreateTableString_AniDB_Anime_DefaultImage()); + commands.AddRange(CreateTableString_MovieDB_Movie()); + commands.AddRange(CreateTableString_MovieDB_Poster()); + commands.AddRange(CreateTableString_MovieDB_Fanart()); + commands.AddRange(CreateTableString_JMMUser()); + commands.AddRange(CreateTableString_Trakt_Episode()); + commands.AddRange(CreateTableString_Trakt_ImagePoster()); + commands.AddRange(CreateTableString_Trakt_ImageFanart()); + commands.AddRange(CreateTableString_Trakt_Show()); + commands.AddRange(CreateTableString_Trakt_Season()); + commands.AddRange(CreateTableString_CrossRef_AniDB_Trakt()); + + commands.AddRange(CreateTableString_AnimeEpisode_User()); + commands.AddRange(CreateTableString_AnimeSeries_User()); + commands.AddRange(CreateTableString_AnimeGroup_User()); + commands.AddRange(CreateTableString_VideoLocal_User()); + + foreach (string cmdTable in commands) + { + SQLiteCommand sqCommand = new SQLiteCommand(cmdTable); + sqCommand.Connection = myConn; + sqCommand.ExecuteNonQuery(); + } + + myConn.Close(); + + logger.Trace("Creating version..."); + Versions ver1 = new Versions(); + ver1.VersionType = Constants.DatabaseTypeKey; + ver1.VersionValue = "1"; + + VersionsRepository repVer = new VersionsRepository(); + repVer.Save(ver1); + + } + + public static List CreateTableString_Versions() + { + List cmds = new List(); + cmds.Add("CREATE TABLE Versions ( " + + " VersionsID INTEGER PRIMARY KEY AUTOINCREMENT, " + + " VersionType Text NOT NULL, " + + " VersionValue Text NOT NULL)"); + + return cmds; + } + + public static List CreateTableString_AniDB_Anime() + { + List cmds = new List(); + cmds.Add("CREATE TABLE AniDB_Anime ( " + + " AniDB_AnimeID INTEGER PRIMARY KEY AUTOINCREMENT, " + + " AnimeID int NOT NULL, " + + " EpisodeCount int NOT NULL, " + + " AirDate timestamp NULL, " + + " EndDate timestamp NULL, " + + " URL text NULL, " + + " Picname text NULL, " + + " BeginYear int NOT NULL, " + + " EndYear int NOT NULL, " + + " AnimeType int NOT NULL, " + + " MainTitle text NOT NULL, " + + " AllTitles text NOT NULL, " + + " AllCategories text NOT NULL, " + + " AllTags text NOT NULL, " + + " Description text NOT NULL, " + + " EpisodeCountNormal int NOT NULL, " + + " EpisodeCountSpecial int NOT NULL, " + + " Rating int NOT NULL, " + + " VoteCount int NOT NULL, " + + " TempRating int NOT NULL, " + + " TempVoteCount int NOT NULL, " + + " AvgReviewRating int NOT NULL, " + + " ReviewCount int NOT NULL, " + + " DateTimeUpdated timestamp NOT NULL, " + + " DateTimeDescUpdated timestamp NOT NULL, " + + " ImageEnabled int NOT NULL, " + + " AwardList text NOT NULL, " + + " Restricted int NOT NULL, " + + " AnimePlanetID int NULL, " + + " ANNID int NULL, " + + " AllCinemaID int NULL, " + + " AnimeNfo int NULL, " + + " LatestEpisodeNumber int NULL " + + " );"); + + cmds.Add("CREATE UNIQUE INDEX [UIX_AniDB_Anime_AnimeID] ON [AniDB_Anime] ([AnimeID]);"); + + return cmds; + } + + public static List CreateTableString_AniDB_Anime_Category() + { + List cmds = new List(); + cmds.Add("CREATE TABLE AniDB_Anime_Category ( " + + " AniDB_Anime_CategoryID INTEGER PRIMARY KEY AUTOINCREMENT, " + + " AnimeID int NOT NULL, " + + " CategoryID int NOT NULL, " + + " Weighting int NOT NULL " + + " ); "); + + cmds.Add("CREATE INDEX IX_AniDB_Anime_Category_AnimeID on AniDB_Anime_Category(AnimeID);"); + cmds.Add("CREATE UNIQUE INDEX UIX_AniDB_Anime_Category_AnimeID_CategoryID ON AniDB_Anime_Category (AnimeID, CategoryID);"); + + return cmds; + } + + public static List CreateTableString_AniDB_Anime_Character() + { + List cmds = new List(); + cmds.Add("CREATE TABLE AniDB_Anime_Character ( " + + " AniDB_Anime_CharacterID INTEGER PRIMARY KEY AUTOINCREMENT, " + + " AnimeID int NOT NULL, " + + " CharID int NOT NULL, " + + " CharType text NOT NULL, " + + " EpisodeListRaw text NOT NULL " + + " ); "); + + cmds.Add("CREATE INDEX IX_AniDB_Anime_Character_AnimeID on AniDB_Anime_Character(AnimeID);"); + cmds.Add("CREATE UNIQUE INDEX UIX_AniDB_Anime_Character_AnimeID_CharID ON AniDB_Anime_Character(AnimeID, CharID);"); + + return cmds; + } + + public static List CreateTableString_AniDB_Anime_Relation() + { + List cmds = new List(); + cmds.Add("CREATE TABLE AniDB_Anime_Relation ( " + + " AniDB_Anime_RelationID INTEGER PRIMARY KEY AUTOINCREMENT, " + + " AnimeID int NOT NULL, " + + " RelatedAnimeID int NOT NULL, " + + " RelationType text NOT NULL " + + " ); "); + + cmds.Add("CREATE INDEX IX_AniDB_Anime_Relation_AnimeID on AniDB_Anime_Relation(AnimeID);"); + cmds.Add("CREATE UNIQUE INDEX UIX_AniDB_Anime_Relation_AnimeID_RelatedAnimeID ON AniDB_Anime_Relation(AnimeID, RelatedAnimeID);"); + + return cmds; + } + + public static List CreateTableString_AniDB_Anime_Review() + { + List cmds = new List(); + cmds.Add("CREATE TABLE AniDB_Anime_Review ( " + + " AniDB_Anime_ReviewID INTEGER PRIMARY KEY AUTOINCREMENT, " + + " AnimeID int NOT NULL, " + + " ReviewID int NOT NULL " + + " ); "); + + cmds.Add("CREATE INDEX IX_AniDB_Anime_Review_AnimeID on AniDB_Anime_Review(AnimeID);"); + cmds.Add("CREATE UNIQUE INDEX UIX_AniDB_Anime_Review_AnimeID_ReviewID ON AniDB_Anime_Review(AnimeID, ReviewID);"); + + return cmds; + } + + public static List CreateTableString_AniDB_Anime_Similar() + { + List cmds = new List(); + cmds.Add("CREATE TABLE AniDB_Anime_Similar ( " + + " AniDB_Anime_SimilarID INTEGER PRIMARY KEY AUTOINCREMENT, " + + " AnimeID int NOT NULL, " + + " SimilarAnimeID int NOT NULL, " + + " Approval int NOT NULL, " + + " Total int NOT NULL " + + " ); "); + + cmds.Add("CREATE INDEX IX_AniDB_Anime_Similar_AnimeID on AniDB_Anime_Similar(AnimeID);"); + cmds.Add("CREATE UNIQUE INDEX UIX_AniDB_Anime_Similar_AnimeID_SimilarAnimeID ON AniDB_Anime_Similar(AnimeID, SimilarAnimeID);"); + + return cmds; + } + + public static List CreateTableString_AniDB_Anime_Tag() + { + List cmds = new List(); + cmds.Add("CREATE TABLE AniDB_Anime_Tag ( " + + " AniDB_Anime_TagID INTEGER PRIMARY KEY AUTOINCREMENT, " + + " AnimeID int NOT NULL, " + + " TagID int NOT NULL, " + + " Approval int NOT NULL " + + " ); "); + + cmds.Add("CREATE INDEX IX_AniDB_Anime_Tag_AnimeID on AniDB_Anime_Tag(AnimeID);"); + cmds.Add("CREATE UNIQUE INDEX UIX_AniDB_Anime_Tag_AnimeID_TagID ON AniDB_Anime_Tag(AnimeID, TagID);"); + + return cmds; + } + + public static List CreateTableString_AniDB_Anime_Title() + { + List cmds = new List(); + cmds.Add("CREATE TABLE AniDB_Anime_Title ( " + + " AniDB_Anime_TitleID INTEGER PRIMARY KEY AUTOINCREMENT, " + + " AnimeID int NOT NULL, " + + " TitleType text NOT NULL, " + + " Language text NOT NULL, " + + " Title text NULL " + + " ); "); + + cmds.Add("CREATE INDEX IX_AniDB_Anime_Title_AnimeID on AniDB_Anime_Title(AnimeID);"); + + return cmds; + } + + public static List CreateTableString_AniDB_Category() + { + List cmds = new List(); + cmds.Add("CREATE TABLE AniDB_Category ( " + + " AniDB_CategoryID INTEGER PRIMARY KEY AUTOINCREMENT, " + + " CategoryID int NOT NULL, " + + " ParentID int NOT NULL, " + + " IsHentai int NOT NULL, " + + " CategoryName text NOT NULL, " + + " CategoryDescription text NOT NULL " + + " ); "); + + cmds.Add("CREATE UNIQUE INDEX UIX_AniDB_Category_CategoryID ON AniDB_Category(CategoryID);"); + + return cmds; + } + + public static List CreateTableString_AniDB_Character() + { + List cmds = new List(); + cmds.Add("CREATE TABLE AniDB_Character ( " + + " AniDB_CharacterID INTEGER PRIMARY KEY AUTOINCREMENT, " + + " CharID int NOT NULL, " + + " CharName text NOT NULL, " + + " PicName text NOT NULL, " + + " CharKanjiName text NOT NULL, " + + " CharDescription text NOT NULL, " + + " CreatorListRaw text NOT NULL " + + " ); "); + + cmds.Add("CREATE UNIQUE INDEX UIX_AniDB_Character_CharID ON AniDB_Character(CharID);"); + + return cmds; + } + + public static List CreateTableString_AniDB_Character_Creator() + { + List cmds = new List(); + + cmds.Add("CREATE TABLE AniDB_Character_Creator ( " + + " AniDB_Character_CreatorID INTEGER PRIMARY KEY AUTOINCREMENT, " + + " CharID int NOT NULL, " + + " CreatorID int NOT NULL " + + " ); "); + + cmds.Add("CREATE INDEX IX_AniDB_Character_Creator_CharID on AniDB_Character_Creator(CharID);"); + cmds.Add("CREATE INDEX IX_AniDB_Character_Creator_CreatorID on AniDB_Character_Creator(CreatorID);"); + cmds.Add("CREATE UNIQUE INDEX UIX_AniDB_Character_Creator_CharID_CreatorID ON AniDB_Character_Creator(CharID, CreatorID);"); + + return cmds; + } + + public static List CreateTableString_AniDB_Creator() + { + List cmds = new List(); + + cmds.Add("CREATE TABLE AniDB_Creator ( " + + " AniDB_CreatorID INTEGER PRIMARY KEY AUTOINCREMENT, " + + " CreatorID int NOT NULL, " + + " CreatorName text NOT NULL, " + + " PicName text NOT NULL, " + + " CreatorKanjiName text NOT NULL, " + + " CreatorDescription text NOT NULL, " + + " CreatorType int NOT NULL, " + + " URLEnglish text NOT NULL, " + + " URLJapanese text NOT NULL, " + + " URLWikiEnglish text NOT NULL, " + + " URLWikiJapanese text NOT NULL " + + " ); "); + + cmds.Add("CREATE UNIQUE INDEX UIX_AniDB_Creator_CreatorID ON AniDB_Creator(CreatorID);"); + + + return cmds; + } + + public static List CreateTableString_AniDB_Episode() + { + List cmds = new List(); + cmds.Add("CREATE TABLE AniDB_Episode ( " + + " AniDB_EpisodeID INTEGER PRIMARY KEY AUTOINCREMENT, " + + " EpisodeID int NOT NULL, " + + " AnimeID int NOT NULL, " + + " LengthSeconds int NOT NULL, " + + " Rating text NOT NULL, " + + " Votes text NOT NULL, " + + " EpisodeNumber int NOT NULL, " + + " EpisodeType int NOT NULL, " + + " RomajiName text NOT NULL, " + + " EnglishName text NOT NULL, " + + " AirDate int NOT NULL, " + + " DateTimeUpdated timestamp NOT NULL " + + " ); "); + + cmds.Add("CREATE INDEX IX_AniDB_Episode_AnimeID on AniDB_Episode(AnimeID);"); + cmds.Add("CREATE UNIQUE INDEX UIX_AniDB_Episode_EpisodeID ON AniDB_Episode(EpisodeID);"); + + return cmds; + } + + public static List CreateTableString_AniDB_File() + { + List cmds = new List(); + cmds.Add("CREATE TABLE AniDB_File ( " + + " AniDB_FileID INTEGER PRIMARY KEY AUTOINCREMENT, " + + " FileID int NOT NULL, " + + " Hash text NOT NULL, " + + " AnimeID int NOT NULL, " + + " GroupID int NOT NULL, " + + " File_Source text NOT NULL, " + + " File_AudioCodec text NOT NULL, " + + " File_VideoCodec text NOT NULL, " + + " File_VideoResolution text NOT NULL, " + + " File_FileExtension text NOT NULL, " + + " File_LengthSeconds int NOT NULL, " + + " File_Description text NOT NULL, " + + " File_ReleaseDate int NOT NULL, " + + " Anime_GroupName text NOT NULL, " + + " Anime_GroupNameShort text NOT NULL, " + + " Episode_Rating int NOT NULL, " + + " Episode_Votes int NOT NULL, " + + " DateTimeUpdated timestamp NOT NULL, " + + " IsWatched int NOT NULL, " + + " WatchedDate timestamp NULL, " + + " CRC text NOT NULL, " + + " MD5 text NOT NULL, " + + " SHA1 text NOT NULL, " + + " FileName text NOT NULL, " + + " FileSize INTEGER NOT NULL " + + " ); "); + + cmds.Add("CREATE UNIQUE INDEX UIX_AniDB_File_Hash on AniDB_File(Hash);"); + cmds.Add("CREATE UNIQUE INDEX UIX_AniDB_File_FileID ON AniDB_File(FileID);"); + cmds.Add("CREATE INDEX IX_AniDB_File_File_Source on AniDB_File(File_Source);"); + + return cmds; + } + + public static List CreateTableString_AniDB_GroupStatus() + { + List cmds = new List(); + cmds.Add("CREATE TABLE AniDB_GroupStatus ( " + + " AniDB_GroupStatusID INTEGER PRIMARY KEY AUTOINCREMENT, " + + " AnimeID int NOT NULL, " + + " GroupID int NOT NULL, " + + " GroupName text NOT NULL, " + + " CompletionState int NOT NULL, " + + " LastEpisodeNumber int NOT NULL, " + + " Rating int NOT NULL, " + + " Votes int NOT NULL, " + + " EpisodeRange text NOT NULL " + + " ); "); + + cmds.Add("CREATE INDEX IX_AniDB_GroupStatus_AnimeID on AniDB_GroupStatus(AnimeID);"); + cmds.Add("CREATE UNIQUE INDEX UIX_AniDB_GroupStatus_AnimeID_GroupID ON AniDB_GroupStatus(AnimeID, GroupID);"); + + + return cmds; + } + + public static List CreateTableString_AniDB_ReleaseGroup() + { + List cmds = new List(); + cmds.Add("CREATE TABLE AniDB_ReleaseGroup ( " + + " AniDB_ReleaseGroupID INTEGER PRIMARY KEY AUTOINCREMENT, " + + " GroupID int NOT NULL, " + + " Rating int NOT NULL, " + + " Votes int NOT NULL, " + + " AnimeCount int NOT NULL, " + + " FileCount int NOT NULL, " + + " GroupName text NOT NULL, " + + " GroupNameShort text NOT NULL, " + + " IRCChannel text NOT NULL, " + + " IRCServer text NOT NULL, " + + " URL text NOT NULL, " + + " Picname text NOT NULL " + + " ); "); + + cmds.Add("CREATE UNIQUE INDEX UIX_AniDB_ReleaseGroup_GroupID ON AniDB_ReleaseGroup(GroupID);"); + + + return cmds; + } + + public static List CreateTableString_AniDB_Review() + { + List cmds = new List(); + cmds.Add("CREATE TABLE AniDB_Review ( " + + " AniDB_ReviewID INTEGER PRIMARY KEY AUTOINCREMENT, " + + " ReviewID int NOT NULL, " + + " AuthorID int NOT NULL, " + + " RatingAnimation int NOT NULL, " + + " RatingSound int NOT NULL, " + + " RatingStory int NOT NULL, " + + " RatingCharacter int NOT NULL, " + + " RatingValue int NOT NULL, " + + " RatingEnjoyment int NOT NULL, " + + " ReviewText text NOT NULL " + + " ); "); + + + cmds.Add("CREATE UNIQUE INDEX UIX_AniDB_Review_ReviewID ON AniDB_Review(ReviewID);"); + + + return cmds; + } + + public static List CreateTableString_AniDB_Tag() + { + List cmds = new List(); + cmds.Add("CREATE TABLE AniDB_Tag ( " + + " AniDB_TagID INTEGER PRIMARY KEY AUTOINCREMENT, " + + " TagID int NOT NULL, " + + " Spoiler int NOT NULL, " + + " LocalSpoiler int NOT NULL, " + + " GlobalSpoiler int NOT NULL, " + + " TagName text NOT NULL, " + + " TagCount int NOT NULL, " + + " TagDescription text NOT NULL " + + " ); "); + + cmds.Add("CREATE UNIQUE INDEX UIX_AniDB_Tag_TagID ON AniDB_Tag(TagID);"); + + return cmds; + } + + public static List CreateTableString_AnimeEpisode() + { + List cmds = new List(); + cmds.Add("CREATE TABLE [AnimeEpisode]( " + + " AnimeEpisodeID INTEGER PRIMARY KEY AUTOINCREMENT, " + + " AnimeSeriesID int NOT NULL, " + + " AniDB_EpisodeID int NOT NULL, " + + " DateTimeUpdated timestamp NOT NULL, " + + " DateTimeCreated timestamp NOT NULL " + + " );"); + + cmds.Add("CREATE UNIQUE INDEX UIX_AnimeEpisode_AniDB_EpisodeID ON AnimeEpisode(AniDB_EpisodeID);"); + cmds.Add("CREATE INDEX IX_AnimeEpisode_AnimeSeriesID on AnimeEpisode(AnimeSeriesID);"); + + return cmds; + } + + public static List CreateTableString_AnimeEpisode_User() + { + List cmds = new List(); + cmds.Add("CREATE TABLE AnimeEpisode_User( " + + " AnimeEpisode_UserID INTEGER PRIMARY KEY AUTOINCREMENT, " + + " JMMUserID int NOT NULL, " + + " AnimeEpisodeID int NOT NULL, " + + " AnimeSeriesID int NOT NULL, " + // we only have this column to improve performance + " WatchedDate timestamp NOT NULL, " + + " PlayedCount int NOT NULL, " + + " WatchedCount int NOT NULL, " + + " StoppedCount int NOT NULL " + + " );"); + + cmds.Add("CREATE UNIQUE INDEX UIX_AnimeEpisode_User_User_EpisodeID ON AnimeEpisode_User(JMMUserID, AnimeEpisodeID);"); + cmds.Add("CREATE INDEX IX_AnimeEpisode_User_User_AnimeSeriesID on AnimeEpisode_User(JMMUserID, AnimeSeriesID);"); + + return cmds; + } + + public static List CreateTableString_AnimeGroup() + { + List cmds = new List(); + cmds.Add("CREATE TABLE AnimeGroup ( " + + " AnimeGroupID INTEGER PRIMARY KEY AUTOINCREMENT, " + + " AnimeGroupParentID int NULL, " + + " GroupName text NOT NULL, " + + " Description text NULL, " + + " IsManuallyNamed int NOT NULL, " + + " DateTimeUpdated timestamp NOT NULL, " + + " DateTimeCreated timestamp NOT NULL, " + + " SortName text NOT NULL, " + + " MissingEpisodeCount int NOT NULL, " + + " MissingEpisodeCountGroups int NOT NULL, " + + " OverrideDescription int NOT NULL, " + + " EpisodeAddedDate timestamp NULL " + + " ); "); + + return cmds; + } + + public static List CreateTableString_AnimeGroup_User() + { + List cmds = new List(); + cmds.Add("CREATE TABLE AnimeGroup_User( " + + " AnimeGroup_UserID INTEGER PRIMARY KEY AUTOINCREMENT, " + + " JMMUserID int NOT NULL, " + + " AnimeGroupID int NOT NULL, " + + " IsFave int NOT NULL, " + + " UnwatchedEpisodeCount int NOT NULL, " + + " WatchedEpisodeCount int NOT NULL, " + + " WatchedDate timestamp NULL, " + + " PlayedCount int NOT NULL, " + + " WatchedCount int NOT NULL, " + + " StoppedCount int NOT NULL " + + " ); "); + + cmds.Add("CREATE UNIQUE INDEX UIX_AnimeGroup_User_User_GroupID ON AnimeGroup_User(JMMUserID, AnimeGroupID);"); + + return cmds; + } + + public static List CreateTableString_AnimeSeries() + { + List cmds = new List(); + cmds.Add("CREATE TABLE AnimeSeries ( " + + " AnimeSeriesID INTEGER PRIMARY KEY AUTOINCREMENT, " + + " AnimeGroupID int NOT NULL, " + + " AniDB_ID int NOT NULL, " + + " DateTimeUpdated timestamp NOT NULL, " + + " DateTimeCreated timestamp NOT NULL, " + + " DefaultAudioLanguage text NULL, " + + " DefaultSubtitleLanguage text NULL, " + + " MissingEpisodeCount int NOT NULL, " + + " MissingEpisodeCountGroups int NOT NULL, " + + " LatestLocalEpisodeNumber int NOT NULL, " + + " EpisodeAddedDate timestamp NULL " + + " ); "); + + cmds.Add("CREATE UNIQUE INDEX UIX_AnimeSeries_AniDB_ID ON AnimeSeries(AniDB_ID);"); + + return cmds; + } + + public static List CreateTableString_AnimeSeries_User() + { + List cmds = new List(); + cmds.Add("CREATE TABLE AnimeSeries_User( " + + " AnimeSeries_UserID INTEGER PRIMARY KEY AUTOINCREMENT, " + + " JMMUserID int NOT NULL, " + + " AnimeSeriesID int NOT NULL, " + + " UnwatchedEpisodeCount int NOT NULL, " + + " WatchedEpisodeCount int NOT NULL, " + + " WatchedDate timestamp NULL, " + + " PlayedCount int NOT NULL, " + + " WatchedCount int NOT NULL, " + + " StoppedCount int NOT NULL " + + " ); "); + + cmds.Add("CREATE UNIQUE INDEX UIX_AnimeSeries_User_User_SeriesID ON AnimeSeries_User(JMMUserID, AnimeSeriesID);"); + + return cmds; + } + + public static List CreateTableString_CommandRequest() + { + List cmds = new List(); + cmds.Add("CREATE TABLE CommandRequest ( " + + " CommandRequestID INTEGER PRIMARY KEY AUTOINCREMENT, " + + " Priority int NOT NULL, " + + " CommandType int NOT NULL, " + + " CommandID text NOT NULL, " + + " CommandDetails text NOT NULL, " + + " DateTimeUpdated timestamp NOT NULL " + + " ); "); + + return cmds; + } + + public static List CreateTableString_CrossRef_AniDB_TvDB() + { + List cmds = new List(); + cmds.Add("CREATE TABLE CrossRef_AniDB_TvDB( " + + " CrossRef_AniDB_TvDBID INTEGER PRIMARY KEY AUTOINCREMENT, " + + " AnimeID int NOT NULL, " + + " TvDBID int NOT NULL, " + + " TvDBSeasonNumber int NOT NULL, " + + " CrossRefSource int NOT NULL " + + " ); "); + + cmds.Add("CREATE UNIQUE INDEX UIX_CrossRef_AniDB_TvDB ON CrossRef_AniDB_TvDB(AnimeID, TvDBID, TvDBSeasonNumber, CrossRefSource);"); + + return cmds; + } + + public static List CreateTableString_CrossRef_AniDB_Other() + { + List cmds = new List(); + cmds.Add("CREATE TABLE CrossRef_AniDB_Other( " + + " CrossRef_AniDB_OtherID INTEGER PRIMARY KEY AUTOINCREMENT, " + + " AnimeID int NOT NULL, " + + " CrossRefID text NOT NULL, " + + " CrossRefSource int NOT NULL, " + + " CrossRefType int NOT NULL " + + " ); "); + + cmds.Add("CREATE UNIQUE INDEX UIX_CrossRef_AniDB_Other ON CrossRef_AniDB_Other(AnimeID, CrossRefID, CrossRefSource, CrossRefType);"); + + return cmds; + } + + public static List CreateTableString_CrossRef_File_Episode() + { + List cmds = new List(); + cmds.Add("CREATE TABLE CrossRef_File_Episode ( " + + " CrossRef_File_EpisodeID INTEGER PRIMARY KEY AUTOINCREMENT, " + + " Hash text NULL, " + + " FileName text NOT NULL, " + + " FileSize INTEGER NOT NULL, " + + " CrossRefSource int NOT NULL, " + + " AnimeID int NOT NULL, " + + " EpisodeID int NOT NULL, " + + " Percentage int NOT NULL, " + + " EpisodeOrder int NOT NULL " + + " ); "); + + cmds.Add("CREATE UNIQUE INDEX UIX_CrossRef_File_Episode_Hash_EpisodeID ON CrossRef_File_Episode(Hash, EpisodeID);"); + + return cmds; + } + + public static List CreateTableString_CrossRef_Languages_AniDB_File() + { + List cmds = new List(); + cmds.Add("CREATE TABLE CrossRef_Languages_AniDB_File ( " + + " CrossRef_Languages_AniDB_FileID INTEGER PRIMARY KEY AUTOINCREMENT, " + + " FileID int NOT NULL, " + + " LanguageID int NOT NULL " + + " ); "); + + return cmds; + } + + public static List CreateTableString_CrossRef_Subtitles_AniDB_File() + { + List cmds = new List(); + cmds.Add("CREATE TABLE CrossRef_Subtitles_AniDB_File ( " + + " CrossRef_Subtitles_AniDB_FileID INTEGER PRIMARY KEY AUTOINCREMENT, " + + " FileID int NOT NULL, " + + " LanguageID int NOT NULL " + + " ); "); + + return cmds; + } + + public static List CreateTableString_FileNameHash() + { + List cmds = new List(); + cmds.Add("CREATE TABLE FileNameHash ( " + + " FileNameHashID INTEGER PRIMARY KEY AUTOINCREMENT, " + + " FileName text NOT NULL, " + + " FileSize INTEGER NOT NULL, " + + " Hash text NOT NULL, " + + " DateTimeUpdated timestamp NOT NULL " + + " ); "); + + cmds.Add("CREATE UNIQUE INDEX UIX_FileNameHash ON FileNameHash(FileName, FileSize, Hash);"); + + return cmds; + } + + public static List CreateTableString_Language() + { + List cmds = new List(); + cmds.Add("CREATE TABLE Language ( " + + " LanguageID INTEGER PRIMARY KEY AUTOINCREMENT, " + + " LanguageName text NOT NULL " + + " ); "); + + cmds.Add("CREATE UNIQUE INDEX UIX_Language_LanguageName ON Language(LanguageName);"); + + return cmds; + } + + public static List CreateTableString_ImportFolder() + { + List cmds = new List(); + cmds.Add("CREATE TABLE ImportFolder ( " + + " ImportFolderID INTEGER PRIMARY KEY AUTOINCREMENT, " + + " ImportFolderType int NOT NULL, " + + " ImportFolderName text NOT NULL, " + + " ImportFolderLocation text NOT NULL, " + + " IsDropSource int NOT NULL, " + + " IsDropDestination int NOT NULL " + + " ); "); + + return cmds; + } + + public static List CreateTableString_ScheduledUpdate() + { + List cmds = new List(); + cmds.Add("CREATE TABLE ScheduledUpdate( " + + " ScheduledUpdateID INTEGER PRIMARY KEY AUTOINCREMENT, " + + " UpdateType int NOT NULL, " + + " LastUpdate timestamp NOT NULL, " + + " UpdateDetails text NOT NULL " + + " ); "); + + cmds.Add("CREATE UNIQUE INDEX UIX_ScheduledUpdate_UpdateType ON ScheduledUpdate(UpdateType);"); + + return cmds; + } + + public static List CreateTableString_VideoInfo() + { + List cmds = new List(); + cmds.Add("CREATE TABLE VideoInfo ( " + + " VideoInfoID INTEGER PRIMARY KEY AUTOINCREMENT, " + + " Hash text NOT NULL, " + + " FileSize INTEGER NOT NULL, " + + " FileName text NOT NULL, " + + " DateTimeUpdated timestamp NOT NULL, " + + " VideoCodec text NOT NULL, " + + " VideoBitrate text NOT NULL, " + + " VideoFrameRate text NOT NULL, " + + " VideoResolution text NOT NULL, " + + " AudioCodec text NOT NULL, " + + " AudioBitrate text NOT NULL, " + + " Duration INTEGER NOT NULL " + + " ); "); + + cmds.Add("CREATE UNIQUE INDEX UIX_VideoInfo_Hash on VideoInfo(Hash);"); + + return cmds; + } + + public static List CreateTableString_VideoLocal() + { + List cmds = new List(); + cmds.Add("CREATE TABLE VideoLocal ( " + + " VideoLocalID INTEGER PRIMARY KEY AUTOINCREMENT, " + + " FilePath text NOT NULL, " + + " ImportFolderID int NOT NULL, " + + " Hash text NOT NULL, " + + " CRC32 text NULL, " + + " MD5 text NULL, " + + " SHA1 text NULL, " + + " HashSource int NOT NULL, " + + " FileSize INTEGER NOT NULL, " + + " IsIgnored int NOT NULL, " + + " DateTimeUpdated timestamp NOT NULL " + + " ); "); + + cmds.Add("CREATE UNIQUE INDEX UIX_VideoLocal_Hash on VideoLocal(Hash)"); + + return cmds; + } + + public static List CreateTableString_VideoLocal_User() + { + List cmds = new List(); + cmds.Add("CREATE TABLE VideoLocal_User( " + + " VideoLocal_UserID INTEGER PRIMARY KEY AUTOINCREMENT, " + + " JMMUserID int NOT NULL, " + + " VideoLocalID int NOT NULL, " + + " WatchedDate timestamp NOT NULL " + + " ); "); + + cmds.Add("CREATE UNIQUE INDEX UIX_VideoLocal_User_User_VideoLocalID ON VideoLocal_User(JMMUserID, VideoLocalID);"); + + return cmds; + } + + public static List CreateTableString_DuplicateFile() + { + List cmds = new List(); + cmds.Add("CREATE TABLE DuplicateFile ( " + + " DuplicateFileID INTEGER PRIMARY KEY AUTOINCREMENT, " + + " FilePathFile1 text NOT NULL, " + + " FilePathFile2 text NOT NULL, " + + " ImportFolderIDFile1 int NOT NULL, " + + " ImportFolderIDFile2 int NOT NULL, " + + " Hash text NOT NULL, " + + " DateTimeUpdated timestamp NOT NULL " + + " ); "); + + return cmds; + } + + public static List CreateTableString_GroupFilter() + { + List cmds = new List(); + cmds.Add("CREATE TABLE GroupFilter( " + + " GroupFilterID INTEGER PRIMARY KEY AUTOINCREMENT, " + + " GroupFilterName text NOT NULL, " + + " ApplyToSeries int NOT NULL, " + + " BaseCondition int NOT NULL " + + " SortingCriteria text " + + " ); "); + + return cmds; + } + + public static List CreateTableString_GroupFilterCondition() + { + List cmds = new List(); + cmds.Add("CREATE TABLE GroupFilterCondition( " + + " GroupFilterConditionID INTEGER PRIMARY KEY AUTOINCREMENT, " + + " GroupFilterID int NOT NULL, " + + " ConditionType int NOT NULL, " + + " ConditionOperator int NOT NULL, " + + " ConditionParameter text NOT NULL " + + " ); "); + + return cmds; + } + + public static List CreateTableString_AniDB_Vote() + { + List cmds = new List(); + cmds.Add("CREATE TABLE AniDB_Vote ( " + + " AniDB_VoteID INTEGER PRIMARY KEY AUTOINCREMENT, " + + " EntityID int NOT NULL, " + + " VoteValue int NOT NULL, " + + " VoteType int NOT NULL " + + " ); "); + + return cmds; + } + + public static List CreateTableString_TvDB_ImageFanart() + { + List cmds = new List(); + + cmds.Add("CREATE TABLE TvDB_ImageFanart ( " + + " TvDB_ImageFanartID INTEGER PRIMARY KEY AUTOINCREMENT, " + + " Id integer NOT NULL, " + + " SeriesID integer NOT NULL, " + + " BannerPath text, " + + " BannerType text, " + + " BannerType2 text, " + + " Colors text, " + + " Language text, " + + " ThumbnailPath text, " + + " VignettePath text, " + + " Enabled integer NOT NULL, " + + " Chosen INTEGER NULL)"); + + cmds.Add("CREATE UNIQUE INDEX UIX_TvDB_ImageFanart_Id ON TvDB_ImageFanart(Id)"); + + return cmds; + } + + public static List CreateTableString_TvDB_ImageWideBanner() + { + List cmds = new List(); + + cmds.Add("CREATE TABLE TvDB_ImageWideBanner ( " + + " TvDB_ImageWideBannerID INTEGER PRIMARY KEY AUTOINCREMENT, " + + " Id integer NOT NULL, " + + " SeriesID integer NOT NULL, " + + " BannerPath text, " + + " BannerType text, " + + " BannerType2 text, " + + " Language text, " + + " Enabled integer NOT NULL, " + + " SeasonNumber integer)"); + + cmds.Add("CREATE UNIQUE INDEX UIX_TvDB_ImageWideBanner_Id ON TvDB_ImageWideBanner(Id);"); + + return cmds; + } + + public static List CreateTableString_TvDB_ImagePoster() + { + List cmds = new List(); + + cmds.Add("CREATE TABLE TvDB_ImagePoster ( " + + " TvDB_ImagePosterID INTEGER PRIMARY KEY AUTOINCREMENT, " + + " Id integer NOT NULL, " + + " SeriesID integer NOT NULL, " + + " BannerPath text, " + + " BannerType text, " + + " BannerType2 text, " + + " Language text, " + + " Enabled integer NOT NULL, " + + " SeasonNumber integer)"); + + cmds.Add("CREATE UNIQUE INDEX UIX_TvDB_ImagePoster_Id ON TvDB_ImagePoster(Id)"); + + return cmds; + } + + public static List CreateTableString_TvDB_Episode() + { + List cmds = new List(); + + cmds.Add("CREATE TABLE TvDB_Episode ( " + + " TvDB_EpisodeID INTEGER PRIMARY KEY AUTOINCREMENT, " + + " Id integer NOT NULL, " + + " SeriesID integer NOT NULL, " + + " SeasonID integer NOT NULL, " + + " SeasonNumber integer NOT NULL, " + + " EpisodeNumber integer NOT NULL, " + + " EpisodeName text, " + + " Overview text, " + + " Filename text, " + + " EpImgFlag integer NOT NULL, " + + " FirstAired text, " + + " AbsoluteNumber integer, " + + " AirsAfterSeason integer, " + + " AirsBeforeEpisode integer, " + + " AirsBeforeSeason integer)"); + + cmds.Add("CREATE UNIQUE INDEX UIX_TvDB_Episode_Id ON TvDB_Episode(Id);"); + + return cmds; + } + + public static List CreateTableString_TvDB_Series() + { + List cmds = new List(); + + cmds.Add("CREATE TABLE TvDB_Series( " + + " TvDB_SeriesID INTEGER PRIMARY KEY AUTOINCREMENT, " + + " SeriesID integer NOT NULL, " + + " Overview text, " + + " SeriesName text, " + + " Status text, " + + " Banner text, " + + " Fanart text, " + + " Poster text, " + + " Lastupdated text)"); + + cmds.Add("CREATE UNIQUE INDEX UIX_TvDB_Series_Id ON TvDB_Series(SeriesID);"); + + return cmds; + } + + public static List CreateTableString_AniDB_Anime_DefaultImage() + { + List cmds = new List(); + + cmds.Add("CREATE TABLE AniDB_Anime_DefaultImage ( " + + " AniDB_Anime_DefaultImageID INTEGER PRIMARY KEY AUTOINCREMENT, " + + " AnimeID int NOT NULL, " + + " ImageParentID int NOT NULL, " + + " ImageParentType int NOT NULL, " + + " ImageType int NOT NULL " + + " );"); + + cmds.Add("CREATE UNIQUE INDEX UIX_AniDB_Anime_DefaultImage_ImageType ON AniDB_Anime_DefaultImage(AnimeID, ImageType)"); + + return cmds; + } + + public static List CreateTableString_MovieDB_Movie() + { + List cmds = new List(); + cmds.Add("CREATE TABLE MovieDB_Movie( " + + " MovieDB_MovieID INTEGER PRIMARY KEY AUTOINCREMENT, " + + " MovieId int NOT NULL, " + + " MovieName text, " + + " OriginalName text, " + + " Overview text " + + " );"); + + cmds.Add("CREATE UNIQUE INDEX UIX_MovieDB_Movie_Id ON MovieDB_Movie(MovieId)"); + + return cmds; + } + + public static List CreateTableString_MovieDB_Poster() + { + List cmds = new List(); + cmds.Add("CREATE TABLE MovieDB_Poster( " + + " MovieDB_PosterID INTEGER PRIMARY KEY AUTOINCREMENT, " + + " ImageID text, " + + " MovieId int NOT NULL, " + + " ImageType text, " + + " ImageSize text, " + + " URL text, " + + " ImageWidth int NOT NULL, " + + " ImageHeight int NOT NULL, " + + " Enabled int NOT NULL " + + " );"); + + return cmds; + } + + public static List CreateTableString_MovieDB_Fanart() + { + List cmds = new List(); + cmds.Add("CREATE TABLE MovieDB_Fanart( " + + " MovieDB_FanartID INTEGER PRIMARY KEY AUTOINCREMENT, " + + " ImageID text, " + + " MovieId int NOT NULL, " + + " ImageType text, " + + " ImageSize text, " + + " URL text, " + + " ImageWidth int NOT NULL, " + + " ImageHeight int NOT NULL, " + + " Enabled int NOT NULL " + + " );"); + + return cmds; + } + + public static List CreateTableString_JMMUser() + { + List cmds = new List(); + cmds.Add("CREATE TABLE JMMUser( " + + " JMMUserID INTEGER PRIMARY KEY AUTOINCREMENT, " + + " Username text, " + + " Password text, " + + " IsAdmin int NOT NULL, " + + " IsAniDBUser int NOT NULL, " + + " IsTraktUser int NOT NULL, " + + " HideCategories text " + + " );"); + + cmds.Add("INSERT Into JMMUser (Username, Password, IsAdmin, IsAniDBUser, IsTraktUser, HideCategories) VALUES ('Default', '', 1, 1, 1, '')"); + + cmds.Add("INSERT Into JMMUser (Username, Password, IsAdmin, IsAniDBUser, IsTraktUser, HideCategories) VALUES ('Family Friendly', '', 0, 1, 1, 'Ecchi,Nudity,Sex,Sexual Abuse,Horror,Erotic Game,Incest,18 Restricted')"); + + + return cmds; + } + + public static List CreateTableString_Trakt_Episode() + { + List cmds = new List(); + + cmds.Add("CREATE TABLE Trakt_Episode( " + + " Trakt_EpisodeID INTEGER PRIMARY KEY AUTOINCREMENT, " + + " Trakt_ShowID int NOT NULL, " + + " Season int NOT NULL, " + + " EpisodeNumber int NOT NULL, " + + " Title text, " + + " URL text, " + + " Overview text, " + + " EpisodeImage text " + + " );"); + + return cmds; + } + + public static List CreateTableString_Trakt_ImagePoster() + { + List cmds = new List(); + + cmds.Add("CREATE TABLE Trakt_ImagePoster( " + + " Trakt_ImagePosterID INTEGER PRIMARY KEY AUTOINCREMENT, " + + " Trakt_ShowID int NOT NULL, " + + " Season int NOT NULL, " + + " ImageURL text, " + + " Enabled int NOT NULL " + + " );"); + + return cmds; + } + + public static List CreateTableString_Trakt_ImageFanart() + { + List cmds = new List(); + + cmds.Add("CREATE TABLE Trakt_ImageFanart( " + + " Trakt_ImageFanartID INTEGER PRIMARY KEY AUTOINCREMENT, " + + " Trakt_ShowID int NOT NULL, " + + " Season int NOT NULL, " + + " ImageURL text, " + + " Enabled int NOT NULL " + + " );"); + + return cmds; + } + + public static List CreateTableString_Trakt_Show() + { + List cmds = new List(); + + cmds.Add("CREATE TABLE Trakt_Show( " + + " Trakt_ShowID INTEGER PRIMARY KEY AUTOINCREMENT, " + + " TraktID text, " + + " Title text, " + + " Year text, " + + " URL text, " + + " Overview text, " + + " TvDB_ID int NULL " + + " );"); + + return cmds; + } + + public static List CreateTableString_Trakt_Season() + { + List cmds = new List(); + + cmds.Add("CREATE TABLE Trakt_Season( " + + " Trakt_SeasonID INTEGER PRIMARY KEY AUTOINCREMENT, " + + " Trakt_ShowID int NOT NULL, " + + " Season int NOT NULL, " + + " URL text " + + " );"); + + return cmds; + } + + public static List CreateTableString_CrossRef_AniDB_Trakt() + { + List cmds = new List(); + + cmds.Add("CREATE TABLE CrossRef_AniDB_Trakt( " + + " CrossRef_AniDB_TraktID INTEGER PRIMARY KEY AUTOINCREMENT, " + + " AnimeID int NOT NULL, " + + " TraktID text, " + + " TraktSeasonNumber int NOT NULL, " + + " CrossRefSource int NOT NULL " + + " );"); + + return cmds; + } + + #endregion + } +} diff --git a/JMMServer/Entities/AniDB_Anime.cs b/JMMServer/Entities/AniDB_Anime.cs new file mode 100644 index 000000000..2989a804d --- /dev/null +++ b/JMMServer/Entities/AniDB_Anime.cs @@ -0,0 +1,1278 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using NLog; +using System.Xml.Serialization; +using AniDBAPI; +using JMMServer.Repositories; +using JMMServer.Commands; +using JMMContracts; +using System.IO; +using JMMServer.ImageDownload; + +namespace JMMServer.Entities +{ + public class AniDB_Anime + { + #region DB columns + public int AniDB_AnimeID { get; private set; } + public int AnimeID { get; set; } + public int EpisodeCount { get; set; } + public DateTime? AirDate { get; set; } + public DateTime? EndDate { get; set; } + public string URL { get; set; } + public string Picname { get; set; } + public int BeginYear { get; set; } + public int EndYear { get; set; } + public int AnimeType { get; set; } + public string MainTitle { get; set; } + public string AllTitles { get; set; } + public string AllCategories { get; set; } + public string AllTags { get; set; } + public string Description { get; set; } + public int EpisodeCountNormal { get; set; } + public int EpisodeCountSpecial { get; set; } + public int Rating { get; set; } + public int VoteCount { get; set; } + public int TempRating { get; set; } + public int TempVoteCount { get; set; } + public int AvgReviewRating { get; set; } + public int ReviewCount { get; set; } + public DateTime DateTimeUpdated { get; set; } + public DateTime DateTimeDescUpdated { get; set; } + public int ImageEnabled { get; set; } + public string AwardList { get; set; } + public int Restricted { get; set; } + public int? AnimePlanetID { get; set; } + public int? ANNID { get; set; } + public int? AllCinemaID { get; set; } + public int? AnimeNfo { get; set; } + public int? LatestEpisodeNumber { get; set; } + #endregion + + private static Logger logger = LogManager.GetCurrentClassLogger(); + + // these files come from AniDB but we don't directly save them + private string reviewIDListRAW; + + public enAnimeType AnimeTypeEnum + { + get + { + if (AnimeType > 5) return enAnimeType.Other; + return (enAnimeType)AnimeType; + } + } + + public string AnimeTypeDescription + { + get + { + switch (AnimeTypeEnum) + { + case enAnimeType.Movie: return "Movie"; + case enAnimeType.Other: return "Other"; + case enAnimeType.OVA: return "OVA"; + case enAnimeType.TVSeries: return "TV Series"; + case enAnimeType.TVSpecial: return "TV Special"; + case enAnimeType.Web: return "Web"; + default: return "Other"; + + } + } + } + + [XmlIgnore] + public int AirDateAsSeconds + { + get { return Utils.GetAniDBDateAsSeconds(AirDate); } + } + + [XmlIgnore] + public string AirDateFormatted + { + get { return Utils.GetAniDBDate(AirDateAsSeconds); } + } + + public const int LastYear = 2050; + + [XmlIgnore] + public string PosterPath + { + get + { + if (string.IsNullOrEmpty(Picname)) return ""; + + return Path.Combine(ImageUtils.GetAniDBImagePath(AnimeID), Picname); + } + } + + [XmlIgnore] + public string Year + { + get + { + string y = BeginYear.ToString(); + if (BeginYear != EndYear) + { + if (EndYear == LastYear) + y += "-Ongoing"; + else + y += "-" + EndYear.ToString(); + } + return y; + } + } + + public CrossRef_AniDB_TvDB CrossRefTvDB + { + get + { + CrossRef_AniDB_TvDBRepository repCrossRef = new CrossRef_AniDB_TvDBRepository(); + return repCrossRef.GetByAnimeID(this.AnimeID); + } + } + + public CrossRef_AniDB_Trakt CrossRefTrakt + { + get + { + CrossRef_AniDB_TraktRepository repCrossRef = new CrossRef_AniDB_TraktRepository(); + return repCrossRef.GetByAnimeID(this.AnimeID); + } + } + + public Trakt_Show TraktShow + { + get + { + CrossRef_AniDB_Trakt xref = CrossRefTrakt; + if (xref == null) return null; + + Trakt_ShowRepository repShows = new Trakt_ShowRepository(); + return repShows.GetByTraktID(xref.TraktID); + } + } + + public Trakt_ImagePoster TraktImagePoster + { + get + { + Trakt_Show show = TraktShow; + if (show == null) return null; + + CrossRef_AniDB_Trakt xref = CrossRefTrakt; + if (xref == null) return null; + + Trakt_ImagePosterRepository repPosters = new Trakt_ImagePosterRepository(); + return repPosters.GetByShowIDAndSeason(show.Trakt_ShowID, xref.TraktSeasonNumber); + } + } + + public Trakt_ImageFanart TraktImageFanart + { + get + { + Trakt_Show show = TraktShow; + if (show == null) return null; + + Trakt_ImageFanartRepository repFanart = new Trakt_ImageFanartRepository(); + return repFanart.GetByShowIDAndSeason(show.Trakt_ShowID, 1); + } + } + + public TvDB_Series TvDBSeries + { + get + { + CrossRef_AniDB_TvDB xref = CrossRefTvDB; + if (xref == null) return null; + + TvDB_SeriesRepository repSeries = new TvDB_SeriesRepository(); + return repSeries.GetByTvDBID(xref.TvDBID); + } + } + + public List TvDBEpisodes + { + get + { + CrossRef_AniDB_TvDB xref = CrossRefTvDB; + if (xref == null) return new List(); + + TvDB_EpisodeRepository repEps = new TvDB_EpisodeRepository(); + return repEps.GetBySeriesID(xref.TvDBID); + } + } + + public List TvDBImageFanarts + { + get + { + CrossRef_AniDB_TvDB xref = CrossRefTvDB; + if (xref == null) return new List(); + + TvDB_ImageFanartRepository repFanart = new TvDB_ImageFanartRepository(); + return repFanart.GetBySeriesID(xref.TvDBID); + } + } + + public List TvDBImagePosters + { + get + { + CrossRef_AniDB_TvDB xref = CrossRefTvDB; + if (xref == null) return new List(); + + TvDB_ImagePosterRepository repPosters = new TvDB_ImagePosterRepository(); + return repPosters.GetBySeriesID(xref.TvDBID); + } + } + + public List TvDBImageWideBanners + { + get + { + CrossRef_AniDB_TvDB xref = CrossRefTvDB; + if (xref == null) return new List(); + + TvDB_ImageWideBannerRepository repBanners = new TvDB_ImageWideBannerRepository(); + return repBanners.GetBySeriesID(xref.TvDBID); + } + } + + public CrossRef_AniDB_Other CrossRefMovieDB + { + get + { + CrossRef_AniDB_OtherRepository repCrossRef = new CrossRef_AniDB_OtherRepository(); + return repCrossRef.GetByAnimeIDAndType(this.AnimeID, CrossRefType.MovieDB); + } + } + + public MovieDB_Movie MovieDBMovie + { + get + { + CrossRef_AniDB_Other xref = CrossRefMovieDB; + if (xref == null) return null; + + MovieDB_MovieRepository repMovies = new MovieDB_MovieRepository(); + return repMovies.GetByOnlineID(int.Parse(xref.CrossRefID)); + } + } + + public List MovieDBFanarts + { + get + { + CrossRef_AniDB_Other xref = CrossRefMovieDB; + if (xref == null) return new List(); + + MovieDB_FanartRepository repFanart = new MovieDB_FanartRepository(); + return repFanart.GetByMovieID(int.Parse(xref.CrossRefID)); + } + } + + public List MovieDBPosters + { + get + { + CrossRef_AniDB_Other xref = CrossRefMovieDB; + if (xref == null) return new List(); + + MovieDB_PosterRepository repPosters = new MovieDB_PosterRepository(); + return repPosters.GetByMovieID(int.Parse(xref.CrossRefID)); + } + } + + public AniDB_Anime_DefaultImage DefaultPoster + { + get + { + AniDB_Anime_DefaultImageRepository repDefaults = new AniDB_Anime_DefaultImageRepository(); + return repDefaults.GetByAnimeIDAndImagezSizeType(this.AnimeID, (int)ImageSizeType.Poster); + } + } + + public AniDB_Anime_DefaultImage DefaultFanart + { + get + { + AniDB_Anime_DefaultImageRepository repDefaults = new AniDB_Anime_DefaultImageRepository(); + return repDefaults.GetByAnimeIDAndImagezSizeType(this.AnimeID, (int)ImageSizeType.Fanart); + } + } + + public AniDB_Anime_DefaultImage DefaultWideBanner + { + get + { + AniDB_Anime_DefaultImageRepository repDefaults = new AniDB_Anime_DefaultImageRepository(); + return repDefaults.GetByAnimeIDAndImagezSizeType(this.AnimeID, (int)ImageSizeType.WideBanner); + } + } + + public string AnimeTypeRAW + { + get + { + switch (AnimeType) + { + case (int)AnimeTypes.Movie: + return "movie"; + case (int)AnimeTypes.OVA: + return "ova"; + case (int)AnimeTypes.TV_Series: + return "tv series"; + case (int)AnimeTypes.TV_Special: + return "tv special"; + case (int)AnimeTypes.Web: + return "web"; + default: + return "other"; + + } + } + set + { + switch (value.ToLower()) + { + case "movie": + AnimeType = (int)AnimeTypes.Movie; + break; + case "ova": + AnimeType = (int)AnimeTypes.OVA; + break; + case "tv series": + AnimeType = (int)AnimeTypes.TV_Series; + break; + case "tv special": + AnimeType = (int)AnimeTypes.TV_Special; + break; + case "web": + AnimeType = (int)AnimeTypes.Web; + break; + default: + AnimeType = (int)AnimeTypes.Other; + break; + } + } + } + + [XmlIgnore] + public string AnimeTypeName + { + get { return Enum.GetName(typeof(AnimeTypes), (AnimeTypes)AnimeType).Replace('_', ' '); } + } + + [XmlIgnore] + public string CategoriesString + { + get + { + List cats = Categories; + string temp = ""; + foreach (AniDB_Category cr in cats) + temp += cr.CategoryName + "|"; + if (temp.Length > 2) + temp = temp.Substring(0, temp.Length - 2); + return temp; + } + } + + + [XmlIgnore] + public bool SearchOnTvDB + { + get + { + return (AnimeType != (int)AnimeTypes.Movie); + } + } + + [XmlIgnore] + public bool SearchOnMovieDB + { + get + { + return (AnimeType == (int)AnimeTypes.Movie); + } + } + + [XmlIgnore] + public List Categories + { + get + { + AniDB_CategoryRepository repCat = new AniDB_CategoryRepository(); + + List categories = new List(); + foreach (AniDB_Anime_Category cat in AnimeCategories) + { + AniDB_Category newcat = repCat.GetByID(cat.CategoryID); + if (newcat != null) categories.Add(newcat); + } + categories.Sort(); + return categories; + } + } + + [XmlIgnore] + public List AnimeCategories + { + get + { + AniDB_Anime_CategoryRepository repCatXRef = new AniDB_Anime_CategoryRepository(); + return repCatXRef.GetByAnimeID(AnimeID); + } + } + + [XmlIgnore] + public List Tags + { + get + { + AniDB_TagRepository repCat = new AniDB_TagRepository(); + + List tags = new List(); + foreach (AniDB_Anime_Tag tag in AnimeTags) + { + AniDB_Tag newtag = repCat.GetByID(tag.TagID); + if (newtag != null) tags.Add(newtag); + } + //tags.Sort(); + return tags; + } + } + + [XmlIgnore] + public List AnimeTags + { + get + { + AniDB_Anime_TagRepository repAnimeTags = new AniDB_Anime_TagRepository(); + return repAnimeTags.GetByAnimeID(AnimeID); + } + } + + [XmlIgnore] + public List RelatedAnime + { + get + { + AniDB_Anime_RelationRepository repRels = new AniDB_Anime_RelationRepository(); + return repRels.GetByAnimeID(AnimeID); + } + } + + [XmlIgnore] + public List SimilarAnime + { + get + { + AniDB_Anime_SimilarRepository rep = new AniDB_Anime_SimilarRepository(); + return rep.GetByAnimeID(AnimeID); + } + } + + [XmlIgnore] + public List AnimeReviews + { + get + { + AniDB_Anime_ReviewRepository RepRevs = new AniDB_Anime_ReviewRepository(); + return RepRevs.GetByAnimeID(AnimeID); + } + } + + [XmlIgnore] + public List AllRelatedAnime + { + get + { + List relList = new List(); + List relListIDs = new List(); + List searchedIDs = new List(); + + GetRelatedAnimeRecursive(this.AnimeID, ref relList, ref relListIDs, ref searchedIDs); + return relList; + } + } + + [XmlIgnore] + public List AnimeCharacters + { + get + { + AniDB_Anime_CharacterRepository repRels = new AniDB_Anime_CharacterRepository(); + return repRels.GetByAnimeID(AnimeID); + } + } + + [XmlIgnore] + public decimal AniDBTotalRating + { + get + { + try + { + decimal totalRating = 0; + totalRating += ((decimal)Rating * VoteCount); + totalRating += ((decimal)TempRating * TempVoteCount); + + return totalRating; + } + catch (Exception ex) + { + logger.Error("Error in AniDBRating: {0}", ex.ToString()); + return 0; + } + } + } + + [XmlIgnore] + public int AniDBTotalVotes + { + get + { + try + { + return TempVoteCount + VoteCount; + } + catch (Exception ex) + { + logger.Error("Error in AniDBRating: {0}", ex.ToString()); + return 0; + } + } + } + + public List Titles + { + get + { + AniDB_Anime_TitleRepository repTitles = new AniDB_Anime_TitleRepository(); + return repTitles.GetByAnimeID(AnimeID); + } + } + + + public string FormattedTitle + { + get + { + List thisTitles = this.Titles; + foreach (NamingLanguage nlan in Languages.PreferredNamingLanguages) + { + string thisLanguage = nlan.Language.Trim().ToUpper(); + + // Romaji and English titles will be contained in MAIN and/or OFFICIAL + // we won't use synonyms for these two languages + if (thisLanguage == "X-JAT" || thisLanguage == "EN") + { + foreach (AniDB_Anime_Title title in thisTitles) + { + string titleType = title.TitleType.Trim().ToUpper(); + // first try the Main title + if (titleType == Constants.AnimeTitleType.Main.ToUpper() && title.Language.Trim().ToUpper() == thisLanguage) return title.Title; + } + } + + // now try the official title + foreach (AniDB_Anime_Title title in thisTitles) + { + string titleType = title.TitleType.Trim().ToUpper(); + if (titleType == Constants.AnimeTitleType.Official.ToUpper() && title.Language.Trim().ToUpper() == thisLanguage) return title.Title; + } + + // try synonyms + if (ServerSettings.LanguageUseSynonyms) + { + foreach (AniDB_Anime_Title title in thisTitles) + { + string titleType = title.TitleType.Trim().ToUpper(); + if (titleType == Constants.AnimeTitleType.Synonym.ToUpper() && title.Language.Trim().ToUpper() == thisLanguage) return title.Title; + } + } + + } + + // otherwise just use the main title + return this.MainTitle; + } + } + + [XmlIgnore] + public AniDB_Vote UserVote + { + get + { + try + { + AniDB_VoteRepository repVotes = new AniDB_VoteRepository(); + AniDB_Vote dbVote = repVotes.GetByAnimeID(this.AnimeID); + return dbVote; + } + catch (Exception ex) + { + logger.Error("Error in UserVote: {0}", ex.ToString()); + return null; + } + } + } + + + public string PreferredTitle + { + get + { + List titles = this.Titles; + + foreach (NamingLanguage nlan in Languages.PreferredNamingLanguages) + { + string thisLanguage = nlan.Language.Trim().ToUpper(); + // Romaji and English titles will be contained in MAIN and/or OFFICIAL + // we won't use synonyms for these two languages + if (thisLanguage == "X-JAT" || thisLanguage == "EN") + { + // first try the Main title + for (int i = 0; i < titles.Count; i++) + { + if (titles[i].Language.Trim().ToUpper() == thisLanguage && + titles[i].TitleType.Trim().ToUpper() == Constants.AnimeTitleType.Main.ToUpper()) return titles[i].Title; + } + } + + // now try the official title + for (int i = 0; i < titles.Count; i++) + { + if (titles[i].Language.Trim().ToUpper() == thisLanguage && + titles[i].TitleType.Trim().ToUpper() == Constants.AnimeTitleType.Official.ToUpper()) return titles[i].Title; + } + + // try synonyms + if (ServerSettings.LanguageUseSynonyms) + { + for (int i = 0; i < titles.Count; i++) + { + if (titles[i].Language.Trim().ToUpper() == thisLanguage && + titles[i].TitleType.Trim().ToUpper() == Constants.AnimeTitleType.Synonym.ToUpper()) return titles[i].Title; + } + } + + } + + // otherwise just use the main title + for (int i = 0; i < titles.Count; i++) + { + if (titles[i].TitleType.Trim().ToUpper() == Constants.AnimeTitleType.Main.ToUpper()) return titles[i].Title; + } + + return "ERROR"; + } + } + + + [XmlIgnore] + public List AniDBEpisodes + { + get + { + AniDB_EpisodeRepository repEps = new AniDB_EpisodeRepository(); + return repEps.GetByAnimeID(AnimeID); + } + } + + private void Populate(Raw_AniDB_Anime animeInfo) + { + this.AirDate = animeInfo.AirDate; + this.AllCinemaID = animeInfo.AllCinemaID; + this.AnimeID = animeInfo.AnimeID; + //this.AnimeNfo = animeInfo.AnimeNfoID; + this.AnimePlanetID = animeInfo.AnimePlanetID; + this.AnimeTypeRAW = animeInfo.AnimeTypeRAW; + this.ANNID = animeInfo.ANNID; + this.AvgReviewRating = animeInfo.AvgReviewRating; + this.AwardList = animeInfo.AwardList; + this.BeginYear = animeInfo.BeginYear; + this.DateTimeDescUpdated = DateTime.Now; + this.DateTimeUpdated = DateTime.Now; + this.Description = animeInfo.Description; + this.EndDate = animeInfo.EndDate; + this.EndYear = animeInfo.EndYear; + this.MainTitle = animeInfo.MainTitle; + this.AllTitles = ""; + this.AllCategories = ""; + this.AllTags = ""; + //this.EnglishName = animeInfo.EnglishName; + this.EpisodeCount = animeInfo.EpisodeCount; + this.EpisodeCountNormal = animeInfo.EpisodeCountNormal; + this.EpisodeCountSpecial = animeInfo.EpisodeCountSpecial; + //this.genre + this.ImageEnabled = 1; + //this.KanjiName = animeInfo.KanjiName; + this.LatestEpisodeNumber = animeInfo.LatestEpisodeNumber; + //this.OtherName = animeInfo.OtherName; + this.Picname = animeInfo.Picname; + this.Rating = animeInfo.Rating; + //this.relations + this.Restricted = animeInfo.Restricted; + this.ReviewCount = animeInfo.ReviewCount; + //this.RomajiName = animeInfo.RomajiName; + //this.ShortNames = animeInfo.ShortNames.Replace("'", "|"); + //this.Synonyms = animeInfo.Synonyms.Replace("'", "|"); + this.TempRating = animeInfo.TempRating; + this.TempVoteCount = animeInfo.TempVoteCount; + this.URL = animeInfo.URL; + this.VoteCount = animeInfo.VoteCount; + } + + public void PopulateAndSaveFromHTTP(Raw_AniDB_Anime animeInfo, List eps, List titles, + List cats, List tags, List chars, List rels, List sims, + bool downloadRelations) + { + Populate(animeInfo); + + // save now for FK purposes + AniDB_AnimeRepository repAnime = new AniDB_AnimeRepository(); + repAnime.Save(this); + + CreateEpisodes(eps); + CreateTitles(titles); + CreateCategories(cats); + CreateTags(tags); + CreateCharacters(chars); + CreateRelations(rels, downloadRelations); + CreateSimilarAnime(sims); + + repAnime.Save(this); + } + + /// + /// we are depending on the HTTP api call to get most of the info + /// we only use UDP to get mssing information + /// + /// + public void PopulateAndSaveFromUDP(Raw_AniDB_Anime animeInfo) + { + // raw fields + this.reviewIDListRAW = animeInfo.ReviewIDListRAW; + + // save now for FK purposes + AniDB_AnimeRepository repAnime = new AniDB_AnimeRepository(); + repAnime.Save(this); + + CreateAnimeReviews(); + } + + private void CreateEpisodes(List eps) + { + if (eps == null) return; + + AniDB_EpisodeRepository repEps = new AniDB_EpisodeRepository(); + + this.EpisodeCountSpecial = 0; + this.EpisodeCountNormal = 0; + + foreach (Raw_AniDB_Episode epraw in eps) + { + List existingEps = repEps.GetByAnimeIDAndEpisodeTypeNumber(epraw.AnimeID, (enEpisodeType)epraw.EpisodeType, epraw.EpisodeNumber); + // we need to do this check because some times AniDB will replace an existing episode with a new episode + + // delete any old records + foreach (AniDB_Episode epOld in existingEps) + { + if (epOld.EpisodeID != epraw.EpisodeID) + { + // first delete any AnimeEpisode records that point to the new anidb episode + AnimeEpisodeRepository repAnimeEps = new AnimeEpisodeRepository(); + AnimeEpisode aniep = repAnimeEps.GetByAniDBEpisodeID(epOld.EpisodeID); + if (aniep != null) + repAnimeEps.Delete(aniep.AnimeEpisodeID); + + repEps.Delete(epOld.AniDB_EpisodeID); + } + } + + + AniDB_Episode ep = repEps.GetByEpisodeID(epraw.EpisodeID); + if (ep == null) ep = new AniDB_Episode(); + + ep.Populate(epraw); + repEps.Save(ep); + + // since the HTTP api doesn't return a count of the number of specials, we will calculate it here + if (ep.EpisodeTypeEnum == AniDBAPI.enEpisodeType.Episode) + this.EpisodeCountNormal++; + + if (ep.EpisodeTypeEnum == AniDBAPI.enEpisodeType.Special) + this.EpisodeCountSpecial++; + } + + this.EpisodeCount = EpisodeCountSpecial + EpisodeCountNormal; + } + + private void CreateTitles(List titles) + { + if (titles == null) return; + + this.AllTitles = ""; + + // first delete all existing titles for this anime + AniDB_Anime_TitleRepository repTitles = new AniDB_Anime_TitleRepository(); + List existingtitles = repTitles.GetByAnimeID(this.AnimeID); + foreach (AniDB_Anime_Title animetitle in existingtitles) + { + repTitles.Delete(animetitle.AniDB_Anime_TitleID); + } + + foreach (Raw_AniDB_Anime_Title rawtitle in titles) + { + AniDB_Anime_Title title = new AniDB_Anime_Title(); + title.Populate(rawtitle); + repTitles.Save(title); + + if (this.AllTitles.Length > 0) this.AllTitles += "|"; + this.AllTitles += rawtitle.Title; + } + } + + private void CreateCategories(List cats) + { + if (cats == null) return; + + this.AllCategories = ""; + + AniDB_CategoryRepository repCats = new AniDB_CategoryRepository(); + AniDB_Anime_CategoryRepository repXRefs = new AniDB_Anime_CategoryRepository(); + + foreach (Raw_AniDB_Category rawcat in cats) + { + AniDB_Category cat = repCats.GetByCategoryID(rawcat.CategoryID); + if (cat == null) cat = new AniDB_Category(); + + cat.Populate(rawcat); + repCats.Save(cat); + + AniDB_Anime_Category anime_cat = repXRefs.GetByAnimeIDAndCategoryID(rawcat.AnimeID, rawcat.CategoryID); + if (anime_cat == null) anime_cat = new AniDB_Anime_Category(); + + anime_cat.Populate(rawcat); + repXRefs.Save(anime_cat); + + if (this.AllCategories.Length > 0) this.AllCategories += "|"; + this.AllCategories += cat.CategoryName; + } + } + + private void CreateTags(List tags) + { + if (tags == null) return; + + this.AllTags = ""; + + AniDB_TagRepository repTags = new AniDB_TagRepository(); + AniDB_Anime_TagRepository repTagsXRefs = new AniDB_Anime_TagRepository(); + + foreach (Raw_AniDB_Tag rawtag in tags) + { + AniDB_Tag tag = repTags.GetByTagID(rawtag.TagID); + if (tag == null) tag = new AniDB_Tag(); + + tag.Populate(rawtag); + repTags.Save(tag); + + AniDB_Anime_Tag anime_tag = repTagsXRefs.GetByAnimeIDAndTagID(rawtag.AnimeID, rawtag.TagID); + if (anime_tag == null) anime_tag = new AniDB_Anime_Tag(); + + anime_tag.Populate(rawtag); + repTagsXRefs.Save(anime_tag); + + if (this.AllTags.Length > 0) this.AllTags += "|"; + this.AllTags += tag.TagName; + } + } + + private void CreateCharacters(List chars) + { + if (chars == null) return; + + AniDB_CharacterRepository repChars = new AniDB_CharacterRepository(); + AniDB_Anime_CharacterRepository repAnimeChars = new AniDB_Anime_CharacterRepository(); + AniDB_Character_CreatorRepository repCharCreators = new AniDB_Character_CreatorRepository(); + + // delete all the existing cross references just in case one has been removed + List animeChars = repAnimeChars.GetByAnimeID(AnimeID); + foreach (AniDB_Anime_Character xref in animeChars) + { + repAnimeChars.Delete(xref.AniDB_Anime_CharacterID); + } + + foreach (Raw_AniDB_Character rawchar in chars) + { + AniDB_Character chr = repChars.GetByCharID(rawchar.CharID); + if (chr == null) chr = new AniDB_Character(); + + chr.PopulateFromHTTP(rawchar); + repChars.Save(chr); + + // create cross ref's between anime and character, but don't actually download anything + AniDB_Anime_Character anime_char = new AniDB_Anime_Character(); + + anime_char.Populate(rawchar); + repAnimeChars.Save(anime_char); + + // create cross ref's between character and creator, but don't actually download anything + if (chr.CreatorListRaw.Trim().Length > 0) + { + string[] creatorids = chr.CreatorListRaw.Split(','); + foreach (string crid in creatorids) + { + int cid = 0; + int.TryParse(crid, out cid); + if (cid > 0) + { + AniDB_Character_Creator acc = repCharCreators.GetByCharIDAndCreatorID(rawchar.CharID, cid); + if (acc == null) + { + acc = new AniDB_Character_Creator(); + acc.CharID = chr.CharID; + acc.CreatorID = cid; + repCharCreators.Save(acc); + } + } + } + } + } + } + + private void CreateRelations(List rels, bool downloadRelations) + { + if (rels == null) return; + + AniDB_Anime_RelationRepository repRels = new AniDB_Anime_RelationRepository(); + + foreach (Raw_AniDB_RelatedAnime rawrel in rels) + { + AniDB_Anime_Relation anime_rel = repRels.GetByAnimeIDAndRelationID(rawrel.AnimeID, rawrel.RelatedAnimeID); + if (anime_rel == null) anime_rel = new AniDB_Anime_Relation(); + + anime_rel.Populate(rawrel); + repRels.Save(anime_rel); + + if (ServerSettings.AniDB_DownloadRelatedAnime && downloadRelations) + { + logger.Info("Adding command to download related anime for {0} ({1}), related anime ID = {2}", + this.MainTitle, this.AnimeID, rawrel.RelatedAnimeID); + + // I have disable the downloading of relations here because of banning issues + // basically we will download immediate relations, but not relations of relations + + //CommandRequest_GetAnimeHTTP cr_anime = new CommandRequest_GetAnimeHTTP(rawrel.RelatedAnimeID, false, downloadRelations); + CommandRequest_GetAnimeHTTP cr_anime = new CommandRequest_GetAnimeHTTP(rawrel.RelatedAnimeID, false, false); + cr_anime.Save(); + } + } + } + + private void CreateSimilarAnime(List sims) + { + if (sims == null) return; + + AniDB_Anime_SimilarRepository repSim = new AniDB_Anime_SimilarRepository(); + + foreach (Raw_AniDB_SimilarAnime rawsim in sims) + { + AniDB_Anime_Similar anime_sim = repSim.GetByAnimeIDAndSimilarID(rawsim.AnimeID, rawsim.SimilarAnimeID); + if (anime_sim == null) anime_sim = new AniDB_Anime_Similar(); + + anime_sim.Populate(rawsim); + repSim.Save(anime_sim); + + // Have commented this out for now, because it ends up downloading most of the database + /* + if (ServerSettings.AniDB_DownloadRelatedAnime) + { + logger.Info("Adding command to download similar anime for {0} ({1}), similar anime ID = {2}", + this.MainTitle, this.AnimeID, rawsim.SimilarAnimeID); + CommandRequest_GetAnimeHTTP cr_anime = new CommandRequest_GetAnimeHTTP(rawsim.SimilarAnimeID, false); + cr_anime.Priority = (int)CommandRequestPriority.Priority10; // set as low priority, so that we get info about animes we actually have first + cr_anime.Save(); + }*/ + } + } + + private void CreateAnimeReviews() + { + if (reviewIDListRAW != null) + //Only create relations if the origin of the data if from Raw (WebService/AniDB) + { + if (reviewIDListRAW.Trim().Length == 0) + return; + + //Delete old if changed + AniDB_Anime_ReviewRepository repReviews = new AniDB_Anime_ReviewRepository(); + List animeReviews = repReviews.GetByAnimeID(AnimeID); + foreach (AniDB_Anime_Review xref in animeReviews) + { + repReviews.Delete(xref.AniDB_Anime_ReviewID); + } + + + string[] revs = reviewIDListRAW.Split(','); + foreach (string review in revs) + { + if (review.Trim().Length > 0) + { + int rev = 0; + Int32.TryParse(review.Trim(), out rev); + if (rev != 0) + { + AniDB_Anime_Review csr = new AniDB_Anime_Review(); + csr.AnimeID = this.AnimeID; + csr.ReviewID = rev; + repReviews.Save(csr); + } + } + } + } + } + + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + sb.Append("AnimeID: " + AnimeID); + sb.Append(" | Main Title: " + MainTitle); + sb.Append(" | EpisodeCount: " + EpisodeCount); + sb.Append(" | AirDate: " + AirDate); + sb.Append(" | Picname: " + Picname); + sb.Append(" | Type: " + AnimeTypeRAW); + return sb.ToString(); + } + + public Contract_AniDBAnime ToContract() + { + Contract_AniDBAnime contract = new Contract_AniDBAnime(); + + contract.AirDate = this.AirDate; + contract.AllCategories = this.AllCategories; + contract.AllCinemaID = this.AllCinemaID; + contract.AllTags = this.AllTags; + contract.AllTitles = this.AllTitles; + contract.AnimeID = this.AnimeID; + contract.AnimeNfo = this.AnimeNfo; + contract.AnimePlanetID = this.AnimePlanetID; + contract.AnimeType = this.AnimeType; + contract.ANNID = this.ANNID; + contract.AvgReviewRating = this.AvgReviewRating; + contract.AwardList = this.AwardList; + contract.BeginYear = this.BeginYear; + contract.Description = this.Description; + contract.DateTimeDescUpdated = this.DateTimeDescUpdated; + contract.DateTimeUpdated = this.DateTimeUpdated; + contract.EndDate = this.EndDate; + contract.EndYear = this.EndYear; + contract.EpisodeCount = this.EpisodeCount; + contract.EpisodeCountNormal = this.EpisodeCountNormal; + contract.EpisodeCountSpecial = this.EpisodeCountSpecial; + contract.ImageEnabled = this.ImageEnabled; + contract.LatestEpisodeNumber = this.LatestEpisodeNumber; + contract.MainTitle = this.MainTitle; + contract.Picname = this.Picname; + contract.Rating = this.Rating; + contract.Restricted = this.Restricted; + contract.ReviewCount = this.ReviewCount; + contract.TempRating = this.TempRating; + contract.TempVoteCount = this.TempVoteCount; + contract.URL = this.URL; + contract.VoteCount = this.VoteCount; + contract.FormattedTitle = this.FormattedTitle; + + return contract; + } + + public Contract_AniDB_AnimeDetailed ToContractDetailed() + { + AniDB_Anime_TitleRepository repTitles = new AniDB_Anime_TitleRepository(); + AniDB_CategoryRepository repCats = new AniDB_CategoryRepository(); + AniDB_TagRepository repTags = new AniDB_TagRepository(); + + Contract_AniDB_AnimeDetailed contract = new Contract_AniDB_AnimeDetailed(); + + contract.AnimeTitles = new List(); + contract.Categories = new List(); + contract.Tags = new List(); + + contract.AniDBAnime = this.ToContract(); + + // get all the anime titles + List animeTitles = repTitles.GetByAnimeID(AnimeID); + if (animeTitles != null) + { + foreach (AniDB_Anime_Title title in animeTitles) + { + Contract_AnimeTitle ctitle = new Contract_AnimeTitle(); + ctitle.AnimeID = title.AnimeID; + ctitle.Language = title.Language; + ctitle.Title = title.Title; + ctitle.TitleType = title.TitleType; + contract.AnimeTitles.Add(ctitle); + } + } + + + foreach (AniDB_Anime_Category animeCat in AnimeCategories) + { + AniDB_Category cat = repCats.GetByCategoryID(animeCat.CategoryID); + if (cat != null) + { + Contract_AnimeCategory ccat = new Contract_AnimeCategory(); + ccat.CategoryDescription = cat.CategoryDescription; + ccat.CategoryID = cat.CategoryID; + ccat.CategoryName = cat.CategoryName; + ccat.IsHentai = cat.IsHentai; + ccat.ParentID = cat.ParentID; + ccat.Weighting = animeCat.Weighting; + contract.Categories.Add(ccat); + } + } + + foreach (AniDB_Anime_Tag animeTag in AnimeTags) + { + AniDB_Tag tag = repTags.GetByTagID(animeTag.TagID); + if (tag != null) + { + Contract_AnimeTag ctag = new Contract_AnimeTag(); + ctag.Approval = animeTag.Approval; + ctag.GlobalSpoiler = tag.GlobalSpoiler; + ctag.LocalSpoiler = tag.LocalSpoiler; + ctag.Spoiler = tag.Spoiler; + ctag.TagCount = tag.TagCount; + ctag.TagDescription = tag.TagDescription; + ctag.TagID = tag.TagID; + ctag.TagName = tag.TagName; + contract.Tags.Add(ctag); + } + } + + if (this.UserVote != null) + contract.UserVote = this.UserVote.ToContract(); + + AdhocRepository repAdHoc = new AdhocRepository(); + List audioLanguages = new List(); + List subtitleLanguages = new List(); + + // audio languages + Dictionary dicAudio = repAdHoc.GetAudioLanguageStatsByAnime(this.AnimeID); + foreach (KeyValuePair kvp in dicAudio) + { + foreach (string lanName in kvp.Value.LanguageNames) + { + if (!audioLanguages.Contains(lanName)) + audioLanguages.Add(lanName); + } + } + + // subtitle languages + Dictionary dicSubtitle = repAdHoc.GetSubtitleLanguageStatsByAnime(this.AnimeID); + foreach (KeyValuePair kvp in dicSubtitle) + { + foreach (string lanName in kvp.Value.LanguageNames) + { + if (!subtitleLanguages.Contains(lanName)) + subtitleLanguages.Add(lanName); + } + } + + contract.Stat_AudioLanguages = ""; + foreach (string audioLan in audioLanguages) + { + if (contract.Stat_AudioLanguages.Length > 0) contract.Stat_AudioLanguages += ","; + contract.Stat_AudioLanguages += audioLan; + } + + contract.Stat_SubtitleLanguages = ""; + foreach (string subLan in subtitleLanguages) + { + if (contract.Stat_SubtitleLanguages.Length > 0) contract.Stat_SubtitleLanguages += ","; + contract.Stat_SubtitleLanguages += subLan; + } + + contract.Stat_AllVideoQuality = repAdHoc.GetAllVideoQualityForAnime(this.AnimeID); + + AnimeVideoQualityStat stat = repAdHoc.GetEpisodeVideoQualityStatsForAnime(this.AnimeID); + + return contract; + } + + public AnimeSeries CreateAnimeSeriesAndGroup() + { + // create a new AnimeSeries record + AnimeSeriesRepository repSeries = new AnimeSeriesRepository(); + AnimeGroupRepository repGroups = new AnimeGroupRepository(); + + AnimeSeries ser = new AnimeSeries(); + ser.Populate(this); + + JMMUserRepository repUsers = new JMMUserRepository(); + List allUsers = repUsers.GetAll(); + + // create the AnimeGroup record + // check if there are any existing groups we could add this series to + bool createNewGroup = true; + + List grps = AnimeGroup.GetRelatedGroupsFromAnimeID(ser.AniDB_ID); + + // only use if there is just one result + if (grps != null && grps.Count > 0) + { + ser.AnimeGroupID = grps[0].AnimeGroupID; + createNewGroup = false; + } + + if (createNewGroup) + { + AnimeGroup anGroup = new AnimeGroup(); + anGroup.Populate(ser); + repGroups.Save(anGroup); + + ser.AnimeGroupID = anGroup.AnimeGroupID; + } + + repSeries.Save(ser); + + // check for TvDB associations + CommandRequest_TvDBSearchAnime cmd = new CommandRequest_TvDBSearchAnime(this.AnimeID, false); + cmd.Save(); + + // check for Trakt associations + CommandRequest_TraktSearchAnime cmd2 = new CommandRequest_TraktSearchAnime(this.AnimeID, false); + cmd2.Save(); + + return ser; + } + + public static void GetRelatedAnimeRecursive(int animeID, ref List relList, ref List relListIDs, ref List searchedIDs) + { + AniDB_AnimeRepository repAnime = new AniDB_AnimeRepository(); + AniDB_Anime anime = repAnime.GetByAnimeID(animeID); + searchedIDs.Add(animeID); + + foreach (AniDB_Anime_Relation rel in anime.RelatedAnime) + { + AniDB_Anime relAnime = repAnime.GetByAnimeID(rel.RelatedAnimeID); + if (relAnime!= null && !relListIDs.Contains(relAnime.AnimeID)) + { + relList.Add(relAnime); + relListIDs.Add(relAnime.AnimeID); + if (!searchedIDs.Contains(rel.RelatedAnimeID)) + { + GetRelatedAnimeRecursive(rel.RelatedAnimeID, ref relList, ref relListIDs, ref searchedIDs); + } + } + } + } + } +} diff --git a/JMMServer/Entities/AniDB_Anime_Category.cs b/JMMServer/Entities/AniDB_Anime_Category.cs new file mode 100644 index 000000000..eb03e1232 --- /dev/null +++ b/JMMServer/Entities/AniDB_Anime_Category.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using AniDBAPI; + +namespace JMMServer.Entities +{ + public class AniDB_Anime_Category + { + public int AniDB_Anime_CategoryID { get; private set; } + public int AnimeID { get; set; } + public int CategoryID { get; set; } + public int Weighting { get; set; } + + public void Populate(Raw_AniDB_Category rawCat) + { + this.AnimeID = rawCat.AnimeID; + this.CategoryID = rawCat.CategoryID; + this.Weighting = rawCat.Weighting; + } + + public override string ToString() + { + return string.Format("AniDB_Anime_Category: {0}/{1} = {2}", AnimeID, CategoryID, Weighting); + } + } +} diff --git a/JMMServer/Entities/AniDB_Anime_Character.cs b/JMMServer/Entities/AniDB_Anime_Character.cs new file mode 100644 index 000000000..279a4a7a9 --- /dev/null +++ b/JMMServer/Entities/AniDB_Anime_Character.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using AniDBAPI; + +namespace JMMServer.Entities +{ + public class AniDB_Anime_Character + { + public int AniDB_Anime_CharacterID { get; private set; } + public int AnimeID { get; set; } + public int CharID { get; set; } + public string CharType { get; set; } + public string EpisodeListRaw { get; set; } + + public void Populate(Raw_AniDB_Character rawChar) + { + this.CharID = rawChar.CharID; + this.AnimeID = rawChar.AnimeID; + this.CharType = rawChar.CharType; + this.EpisodeListRaw = rawChar.EpisodeListRaw; + } + } +} diff --git a/JMMServer/Entities/AniDB_Anime_DefaultImage.cs b/JMMServer/Entities/AniDB_Anime_DefaultImage.cs new file mode 100644 index 000000000..5b8a67b3b --- /dev/null +++ b/JMMServer/Entities/AniDB_Anime_DefaultImage.cs @@ -0,0 +1,100 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMContracts; +using JMMServer.Repositories; + +namespace JMMServer.Entities +{ + public class AniDB_Anime_DefaultImage + { + public int AniDB_Anime_DefaultImageID { get; private set; } + public int AnimeID { get; set; } + public int ImageParentID { get; set; } + public int ImageParentType { get; set; } + public int ImageType { get; set; } + + public Contract_AniDB_Anime_DefaultImage ToContract() + { + Contract_AniDB_Anime_DefaultImage contract = new Contract_AniDB_Anime_DefaultImage(); + + contract.AniDB_Anime_DefaultImageID = this.AniDB_Anime_DefaultImageID; + contract.AnimeID = this.AnimeID; + contract.ImageParentID = this.ImageParentID; + contract.ImageParentType = this.ImageParentType; + contract.ImageType = this.ImageType; + + contract.MovieFanart = null; + contract.MoviePoster = null; + contract.TVPoster = null; + contract.TVFanart = null; + contract.TVWideBanner = null; + contract.TraktFanart = null; + contract.TraktPoster = null; + + JMMImageType imgType = (JMMImageType)ImageParentType; + + switch (imgType) + { + case JMMImageType.TvDB_Banner: + + TvDB_ImageWideBannerRepository repBanners = new TvDB_ImageWideBannerRepository(); + TvDB_ImageWideBanner banner = repBanners.GetByID(ImageParentID); + if (banner != null) contract.TVWideBanner = banner.ToContract(); + + break; + + case JMMImageType.TvDB_Cover: + + TvDB_ImagePosterRepository repPosters = new TvDB_ImagePosterRepository(); + TvDB_ImagePoster poster = repPosters.GetByID(ImageParentID); + if (poster != null) contract.TVPoster = poster.ToContract(); + + break; + + case JMMImageType.TvDB_FanArt: + + TvDB_ImageFanartRepository repFanart = new TvDB_ImageFanartRepository(); + TvDB_ImageFanart fanart = repFanart.GetByID(ImageParentID); + if (fanart != null) contract.TVFanart = fanart.ToContract(); + + break; + + case JMMImageType.MovieDB_Poster: + + MovieDB_PosterRepository repMoviePosters = new MovieDB_PosterRepository(); + MovieDB_Poster moviePoster = repMoviePosters.GetByID(ImageParentID); + if (moviePoster != null) contract.MoviePoster = moviePoster.ToContract(); + + break; + + case JMMImageType.MovieDB_FanArt: + + MovieDB_FanartRepository repMovieFanart = new MovieDB_FanartRepository(); + MovieDB_Fanart movieFanart = repMovieFanart.GetByID(ImageParentID); + if (movieFanart != null) contract.MovieFanart = movieFanart.ToContract(); + + break; + + case JMMImageType.Trakt_Fanart: + + Trakt_ImageFanartRepository repTraktFanart = new Trakt_ImageFanartRepository(); + Trakt_ImageFanart traktFanart = repTraktFanart.GetByID(ImageParentID); + if (traktFanart != null) contract.TraktFanart = traktFanart.ToContract(); + + break; + + case JMMImageType.Trakt_Poster: + + Trakt_ImagePosterRepository repTraktPoster = new Trakt_ImagePosterRepository(); + Trakt_ImagePoster traktPoster = repTraktPoster.GetByID(ImageParentID); + if (traktPoster != null) contract.TraktPoster = traktPoster.ToContract(); + + break; + } + + return contract; + } + } +} diff --git a/JMMServer/Entities/AniDB_Anime_Relation.cs b/JMMServer/Entities/AniDB_Anime_Relation.cs new file mode 100644 index 000000000..c439d3846 --- /dev/null +++ b/JMMServer/Entities/AniDB_Anime_Relation.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using AniDBAPI; + +namespace JMMServer.Entities +{ + public class AniDB_Anime_Relation + { + public int AniDB_Anime_RelationID { get; set; } + public int AnimeID { get; set; } + public string RelationType { get; set; } + public int RelatedAnimeID { get; set; } + + public void Populate(Raw_AniDB_RelatedAnime rawRel) + { + this.AnimeID = rawRel.AnimeID; + this.RelatedAnimeID = rawRel.RelatedAnimeID; + this.RelationType = rawRel.RelationType; + } + } +} diff --git a/JMMServer/Entities/AniDB_Anime_Review.cs b/JMMServer/Entities/AniDB_Anime_Review.cs new file mode 100644 index 000000000..1540b66ee --- /dev/null +++ b/JMMServer/Entities/AniDB_Anime_Review.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace JMMServer.Entities +{ + public class AniDB_Anime_Review + { + public int AniDB_Anime_ReviewID { get; private set; } + public int AnimeID { get; set; } + public int ReviewID { get; set; } + } +} diff --git a/JMMServer/Entities/AniDB_Anime_Similar.cs b/JMMServer/Entities/AniDB_Anime_Similar.cs new file mode 100644 index 000000000..779c153fe --- /dev/null +++ b/JMMServer/Entities/AniDB_Anime_Similar.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using AniDBAPI; + +namespace JMMServer.Entities +{ + public class AniDB_Anime_Similar + { + public int AniDB_Anime_SimilarID { get; private set; } + public int AnimeID { get; set; } + public int SimilarAnimeID { get; set; } + public int Approval { get; set; } + public int Total { get; set; } + + + public void Populate(Raw_AniDB_SimilarAnime rawSim) + { + this.AnimeID = rawSim.AnimeID; + this.Approval = rawSim.Approval; + this.Total = rawSim.Total; + this.SimilarAnimeID = rawSim.SimilarAnimeID; + + } + } +} diff --git a/JMMServer/Entities/AniDB_Anime_Tag.cs b/JMMServer/Entities/AniDB_Anime_Tag.cs new file mode 100644 index 000000000..454a559ed --- /dev/null +++ b/JMMServer/Entities/AniDB_Anime_Tag.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using AniDBAPI; + +namespace JMMServer.Entities +{ + public class AniDB_Anime_Tag + { + public int AniDB_Anime_TagID { get; private set; } + public int AnimeID { get; set; } + public int TagID { get; set; } + public int Approval { get; set; } + + public void Populate(Raw_AniDB_Tag rawTag) + { + this.AnimeID = rawTag.AnimeID; + this.TagID = rawTag.TagID; + this.Approval = rawTag.Approval; + } + } +} diff --git a/JMMServer/Entities/AniDB_Anime_Title.cs b/JMMServer/Entities/AniDB_Anime_Title.cs new file mode 100644 index 000000000..8dc98a775 --- /dev/null +++ b/JMMServer/Entities/AniDB_Anime_Title.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using AniDBAPI; + +namespace JMMServer.Entities +{ + public class AniDB_Anime_Title + { + public int AniDB_Anime_TitleID { get; private set; } + public int AnimeID { get; set; } + public string TitleType { get; set; } + public string Language { get; set; } + public string Title { get; set; } + + public void Populate(Raw_AniDB_Anime_Title rawTitle) + { + this.AnimeID = rawTitle.AnimeID; + this.Language = rawTitle.Language; + this.Title = rawTitle.Title; + this.TitleType = rawTitle.TitleType; + } + + public override string ToString() + { + return string.Format("{0} - {1} ({2}) - {3}", AnimeID, TitleType, Language, Title); + } + } +} diff --git a/JMMServer/Entities/AniDB_Category.cs b/JMMServer/Entities/AniDB_Category.cs new file mode 100644 index 000000000..28370c24d --- /dev/null +++ b/JMMServer/Entities/AniDB_Category.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using AniDBAPI; + +namespace JMMServer.Entities +{ + public class AniDB_Category : IComparable + { + public int AniDB_CategoryID { get; private set; } + public int CategoryID { get; set; } + public int ParentID { get; set; } + public int IsHentai { get; set; } + public string CategoryName { get; set; } + public string CategoryDescription { get; set; } + + public void Populate(Raw_AniDB_Category rawCat) + { + this.CategoryID = rawCat.CategoryID; + this.CategoryDescription = rawCat.CategoryDescription; + this.CategoryName = rawCat.CategoryName; + this.IsHentai = rawCat.IsHentai; + this.ParentID = rawCat.ParentID; + } + + public int CompareTo(AniDB_Category obj) + { + return CategoryName.CompareTo(obj.CategoryName); + } + + public override string ToString() + { + return string.Format("AniDB_Category: {0}({1}) - {2}", CategoryName, CategoryID, CategoryDescription); + } + } +} diff --git a/JMMServer/Entities/AniDB_Character.cs b/JMMServer/Entities/AniDB_Character.cs new file mode 100644 index 000000000..5c9d9863d --- /dev/null +++ b/JMMServer/Entities/AniDB_Character.cs @@ -0,0 +1,61 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using AniDBAPI; + +namespace JMMServer.Entities +{ + public class AniDB_Character + { + public int AniDB_CharacterID { get; private set; } + public int CharID { get; set; } + public string PicName { get; set; } + public string CreatorListRaw { get; set; } + public string CharName { get; set; } + public string CharKanjiName { get; set; } + public string CharDescription { get; set; } + + + private void Populate(Raw_AniDB_Character rawChar) + { + this.CharID = rawChar.CharID; + this.CharDescription = rawChar.CharDescription; + this.CharKanjiName = rawChar.CharKanjiName; + this.CharName = rawChar.CharName; + this.PicName = rawChar.PicName; + this.CreatorListRaw = rawChar.CreatorListRaw; + + } + + public void PopulateFromHTTP(Raw_AniDB_Character rawChar) + { + if (this.CharID == 0) // a new object + { + Populate(rawChar); + } + else + { + // only update the fields that come from HTTP API + this.CharDescription = rawChar.CharDescription; + this.CharName = rawChar.CharName; + this.CreatorListRaw = rawChar.CreatorListRaw; + } + } + + public void PopulateFromUDP(Raw_AniDB_Character rawChar) + { + if (this.CharID == 0) // a new object + { + Populate(rawChar); + } + else + { + // only update the fields that com from UDP API + this.CharKanjiName = rawChar.CharKanjiName; + this.CharName = rawChar.CharName; + //this.CreatorListRaw = rawChar.CreatorListRaw; + } + } + } +} diff --git a/JMMServer/Entities/AniDB_Character_Creator.cs b/JMMServer/Entities/AniDB_Character_Creator.cs new file mode 100644 index 000000000..989a1f3d6 --- /dev/null +++ b/JMMServer/Entities/AniDB_Character_Creator.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace JMMServer.Entities +{ + public class AniDB_Character_Creator + { + public int AniDB_Character_CreatorID { get; private set; } + public int CharID { get; set; } + public int CreatorID { get; set; } + + public AniDB_Character_Creator() + { + } + } +} diff --git a/JMMServer/Entities/AniDB_Creator.cs b/JMMServer/Entities/AniDB_Creator.cs new file mode 100644 index 000000000..9bf84cf76 --- /dev/null +++ b/JMMServer/Entities/AniDB_Creator.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using AniDBAPI; + +namespace JMMServer.Entities +{ + public class AniDB_Creator + { + public int AniDB_CreatorID { get; private set; } + public int CreatorID { get; set; } + public string CreatorName { get; set; } + public string PicName { get; set; } + public string CreatorKanjiName { get; set; } + public string CreatorDescription { get; set; } + public int CreatorType { get; set; } + public string URLEnglish { get; set; } + public string URLJapanese { get; set; } + public string URLWikiEnglish { get; set; } + public string URLWikiJapanese { get; set; } + + public void Populate(Raw_AniDB_Creator rawChar) + { + this.CreatorDescription = rawChar.CreatorDescription; + this.CreatorID = rawChar.CreatorID; + this.CreatorKanjiName = rawChar.CreatorKanjiName; + this.CreatorName = rawChar.CreatorName; + this.CreatorType = rawChar.CreatorType; + this.PicName = rawChar.PicName; + this.URLEnglish = rawChar.URLEnglish; + this.URLJapanese = rawChar.URLJapanese; + this.URLWikiEnglish = rawChar.URLWikiEnglish; + this.URLWikiJapanese = rawChar.URLWikiJapanese; + + } + } +} diff --git a/JMMServer/Entities/AniDB_Episode.cs b/JMMServer/Entities/AniDB_Episode.cs new file mode 100644 index 000000000..9dcbaeccb --- /dev/null +++ b/JMMServer/Entities/AniDB_Episode.cs @@ -0,0 +1,108 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Xml.Serialization; +using AniDBAPI; +using JMMServer.Repositories; + +namespace JMMServer.Entities +{ + public class AniDB_Episode + { + #region DB columns + public int AniDB_EpisodeID { get; private set; } + public int EpisodeID { get; set; } + public int AnimeID { get; set; } + public int LengthSeconds { get; set; } + public string Rating { get; set; } + public string Votes { get; set; } + public int EpisodeNumber { get; set; } + public int EpisodeType { get; set; } + public string RomajiName { get; set; } + public string EnglishName { get; set; } + public int AirDate { get; set; } + public DateTime DateTimeUpdated { get; set; } + #endregion + + [XmlIgnore] + public string AirDateFormatted + { + get + { + try + { + return Utils.GetAniDBDate(AirDate); + } + catch (Exception) + { + + return ""; + } + + } + } + + [XmlIgnore] + public DateTime? AirDateAsDate + { + get + { + return Utils.GetAniDBDateAsDate(AirDate); + } + } + + public enEpisodeType EpisodeTypeEnum + { + get + { + return (enEpisodeType)EpisodeType; + } + } + + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + sb.Append("episodeID: " + EpisodeID.ToString()); + sb.Append(" | animeID: " + AnimeID.ToString()); + sb.Append(" | episodeNumber: " + EpisodeNumber.ToString()); + sb.Append(" | episodeType: " + EpisodeType); + sb.Append(" | englishName: " + EnglishName); + sb.Append(" | airDate: " + AirDate); + //sb.Append(" | AirDateFormatted: " + AirDateFormatted); + + return sb.ToString(); + } + + public void Populate(Raw_AniDB_Episode epInfo) + { + this.AirDate = epInfo.AirDate; + this.AnimeID = epInfo.AnimeID; + this.DateTimeUpdated = DateTime.Now; + this.EnglishName = epInfo.EnglishName; + this.EpisodeID = epInfo.EpisodeID; + this.EpisodeNumber = epInfo.EpisodeNumber; + this.EpisodeType = epInfo.EpisodeType; + this.LengthSeconds = epInfo.LengthSeconds; + this.Rating = epInfo.Rating.ToString(); + this.RomajiName = epInfo.RomajiName; + this.Votes = epInfo.Votes.ToString(); + } + + + public void CreateAnimeEpisode(int animeSeriesID) + { + // check if there is an existing episode for this EpisodeID + AnimeEpisodeRepository repEps = new AnimeEpisodeRepository(); + List existingEps = repEps.GetByAniEpisodeIDAndSeriesID(EpisodeID, animeSeriesID); + + if (existingEps.Count == 0) + { + AnimeEpisode animeEp = new AnimeEpisode(); + animeEp.Populate(this); + animeEp.AnimeSeriesID = animeSeriesID; + repEps.Save(animeEp); + } + } + } +} diff --git a/JMMServer/Entities/AniDB_File.cs b/JMMServer/Entities/AniDB_File.cs new file mode 100644 index 000000000..d01d7be7a --- /dev/null +++ b/JMMServer/Entities/AniDB_File.cs @@ -0,0 +1,421 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Xml.Serialization; +using NLog; +using JMMServer.Repositories; +using AniDBAPI; + +namespace JMMServer.Entities +{ + public class AniDB_File + { + private static Logger logger = LogManager.GetCurrentClassLogger(); + + #region DB columns + public int AniDB_FileID { get; private set; } + public int FileID { get; set; } + public string Hash { get; set; } + public int AnimeID { get; set; } + public int GroupID { get; set; } + public string File_Source { get; set; } + public string File_AudioCodec { get; set; } + public string File_VideoCodec { get; set; } + public string File_VideoResolution { get; set; } + public string File_FileExtension { get; set; } + public int File_LengthSeconds { get; set; } + public string File_Description { get; set; } + public int File_ReleaseDate { get; set; } + public string Anime_GroupName { get; set; } + public string Anime_GroupNameShort { get; set; } + public int Episode_Rating { get; set; } + public int Episode_Votes { get; set; } + public DateTime DateTimeUpdated { get; set; } + public int IsWatched { get; set; } + public DateTime? WatchedDate { get; set; } + public string CRC { get; set; } + public string MD5 { get; set; } + public string SHA1 { get; set; } + public string FileName { get; set; } + public long FileSize { get; set; } + #endregion + + + private string subtitlesRAW; + private string languagesRAW; + private string episodesRAW; + private string episodesPercentRAW; + + + [XmlIgnore] + public List Languages + { + get + { + List lans = new List(); + + CrossRef_Languages_AniDB_FileRepository repFileLanguages = new CrossRef_Languages_AniDB_FileRepository(); + LanguageRepository repLanguages = new LanguageRepository(); + + List fileLanguages = repFileLanguages.GetByFileID(this.FileID); + + foreach (CrossRef_Languages_AniDB_File crossref in fileLanguages) + { + Language lan = repLanguages.GetByID(crossref.LanguageID); + if (lan != null) lans.Add(lan); + } + return lans; + } + } + + + [XmlIgnore] + public List Subtitles + { + get + { + List subs = new List(); + + CrossRef_Subtitles_AniDB_FileRepository repFileSubtitles = new CrossRef_Subtitles_AniDB_FileRepository(); + LanguageRepository repLanguages = new LanguageRepository(); + + List fileSubtitles = repFileSubtitles.GetByFileID(this.FileID); + + + foreach (CrossRef_Subtitles_AniDB_File crossref in fileSubtitles) + { + Language sub = repLanguages.GetByID(crossref.LanguageID); + if (sub != null) subs.Add(sub); + } + return subs; + + } + } + + [XmlIgnore] + public List EpisodeIDs + { + get + { + List ids = new List(); + + CrossRef_File_EpisodeRepository repFileEps = new CrossRef_File_EpisodeRepository(); + List fileEps = repFileEps.GetByHash(this.Hash); + + foreach (CrossRef_File_Episode crossref in fileEps) + { + ids.Add(crossref.EpisodeID); + } + return ids; + } + } + + [XmlIgnore] + public List Episodes + { + get + { + List eps = new List(); + + CrossRef_File_EpisodeRepository repFileEps = new CrossRef_File_EpisodeRepository(); + List fileEps = repFileEps.GetByHash(this.Hash); + + foreach (CrossRef_File_Episode crossref in fileEps) + { + if (crossref.Episode != null) eps.Add(crossref.Episode); + } + return eps; + } + } + + [XmlIgnore] + public List EpisodeCrossRefs + { + get + { + CrossRef_File_EpisodeRepository repFileEps = new CrossRef_File_EpisodeRepository(); + return repFileEps.GetByHash(this.Hash); + } + } + + + + public string SubtitlesRAW + { + get + { + if (!string.IsNullOrEmpty(subtitlesRAW)) + return subtitlesRAW; + string ret = ""; + foreach (Language lang in this.Subtitles) + { + if (ret.Length > 0) + ret += ","; + ret += lang.LanguageName; + } + return ret; + } + set + { + subtitlesRAW = value; + } + } + + + public string LanguagesRAW + { + get + { + if (!string.IsNullOrEmpty(languagesRAW)) + return languagesRAW; + string ret = ""; + foreach (Language lang in this.Languages) + { + if (ret.Length > 0) + ret += ","; + ret += lang.LanguageName; + } + return ret; + } + set + { + languagesRAW = value; + } + } + + + public string EpisodesRAW + { + get + { + if (!string.IsNullOrEmpty(episodesRAW)) + return episodesRAW; + string ret = ""; + foreach (CrossRef_File_Episode cross in EpisodeCrossRefs) + { + if (ret.Length > 0) + ret += ", "; + ret += cross.EpisodeID.ToString(); + } + return ret; + } + set + { + episodesRAW = value; + } + } + + + public string EpisodesPercentRAW + { + get + { + if (!string.IsNullOrEmpty(episodesPercentRAW)) + return episodesPercentRAW; + string ret = ""; + foreach (CrossRef_File_Episode cross in EpisodeCrossRefs) + { + if (ret.Length > 0) + ret += ", "; + ret += cross.Percentage.ToString(); + } + return ret; + } + set + { + episodesPercentRAW = value; + } + } + + + public void Populate(Raw_AniDB_File fileInfo) + { + this.Anime_GroupName = fileInfo.Anime_GroupName; + this.Anime_GroupNameShort = fileInfo.Anime_GroupNameShort; + this.AnimeID = fileInfo.AnimeID; + this.CRC = fileInfo.CRC; + this.DateTimeUpdated = DateTime.Now; + this.Episode_Rating = fileInfo.Episode_Rating; + this.Episode_Votes = fileInfo.Episode_Votes; + this.File_AudioCodec = fileInfo.File_AudioCodec; + this.File_Description = fileInfo.File_Description; + this.File_FileExtension = fileInfo.File_FileExtension; + this.File_LengthSeconds = fileInfo.File_LengthSeconds; + this.File_ReleaseDate = fileInfo.File_ReleaseDate; + this.File_Source = fileInfo.File_Source; + this.File_VideoCodec = fileInfo.File_VideoCodec; + this.File_VideoResolution = fileInfo.File_VideoResolution; + this.FileID = fileInfo.FileID; + this.FileName = fileInfo.FileName; + this.FileSize = fileInfo.FileSize; + this.GroupID = fileInfo.GroupID; + this.Hash = fileInfo.ED2KHash; + this.IsWatched = fileInfo.IsWatched; + this.MD5 = fileInfo.MD5; + this.SHA1 = fileInfo.SHA1; + + this.languagesRAW = fileInfo.LanguagesRAW; + this.subtitlesRAW = fileInfo.SubtitlesRAW; + this.episodesPercentRAW = fileInfo.EpisodesPercentRAW; + this.episodesRAW = fileInfo.EpisodesRAW; + } + + public void CreateLanguages() + { + char apostrophe = ("'").ToCharArray()[0]; + + LanguageRepository repLanguages = new LanguageRepository(); + + if (languagesRAW != null) //Only create relations if the origin of the data if from Raw (WebService/AniDB) + { + if (languagesRAW.Trim().Length == 0) return; + // Delete old if changed + + CrossRef_Languages_AniDB_FileRepository repFileLanguages = new CrossRef_Languages_AniDB_FileRepository(); + + + List fileLanguages = repFileLanguages.GetByFileID(this.FileID); + foreach (CrossRef_Languages_AniDB_File fLan in fileLanguages) + { + repFileLanguages.Delete(fLan.CrossRef_Languages_AniDB_FileID); + } + + + string[] langs = languagesRAW.Split(apostrophe); + foreach (string language in langs) + { + string rlan = language.Trim().ToLower(); + if (rlan.Length > 0) + { + Language lan = repLanguages.GetByLanguageName(rlan); + if (lan == null) + { + lan = new Language(); + lan.LanguageName = rlan; + repLanguages.Save(lan); + } + CrossRef_Languages_AniDB_File cross = new CrossRef_Languages_AniDB_File(); + cross.LanguageID = lan.LanguageID; + cross.FileID = FileID; + repFileLanguages.Save(cross); + } + } + } + + if (subtitlesRAW != null) + { + if (subtitlesRAW.Trim().Length == 0) return; + + // Delete old if changed + CrossRef_Subtitles_AniDB_FileRepository repFileSubtitles = new CrossRef_Subtitles_AniDB_FileRepository(); + List fileSubtitles = repFileSubtitles.GetByFileID(this.FileID); + + foreach (CrossRef_Subtitles_AniDB_File fSub in fileSubtitles) + { + repFileSubtitles.Delete(fSub.CrossRef_Subtitles_AniDB_FileID); + } + + string[] subs = subtitlesRAW.Split(apostrophe); + foreach (string language in subs) + { + string rlan = language.Trim().ToLower(); + if (rlan.Length > 0) + { + Language lan = repLanguages.GetByLanguageName(rlan); + if (lan == null) + { + lan = new Language(); + lan.LanguageName = rlan; + repLanguages.Save(lan); + } + CrossRef_Subtitles_AniDB_File cross = new CrossRef_Subtitles_AniDB_File(); + cross.LanguageID = lan.LanguageID; + cross.FileID = FileID; + repFileSubtitles.Save(cross); + } + } + } + } + + 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 fileEps = repFileEpisodes.GetByHash(this.Hash); + + foreach (CrossRef_File_Episode fileEp in fileEps) + { + // only delete cross refs from AniDB, not manual associations by the user + if (fileEp.CrossRefSource == (int)CrossRefSource.AniDB) + repFileEpisodes.Delete(fileEp.CrossRef_File_EpisodeID); + } + + string[] epi = episodesRAW.Split(','); + string[] epp = episodesPercentRAW.Split(','); + 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 string ToXML() + { + StringBuilder sb = new StringBuilder(); + sb.Append(@""); + sb.Append(string.Format("{0}", Hash)); + sb.Append(string.Format("{0}", Hash)); + sb.Append(string.Format("{0}", CRC)); + sb.Append(string.Format("{0}", MD5)); + sb.Append(string.Format("{0}", SHA1)); + sb.Append(string.Format("{0}", FileID)); + sb.Append(string.Format("{0}", AnimeID)); + sb.Append(string.Format("{0}", GroupID)); + sb.Append(string.Format("{0}", File_LengthSeconds)); + sb.Append(string.Format("{0}", File_Source)); + sb.Append(string.Format("{0}", File_AudioCodec)); + sb.Append(string.Format("{0}", File_VideoCodec)); + sb.Append(string.Format("{0}", File_VideoResolution)); + sb.Append(string.Format("{0}", File_FileExtension)); + sb.Append(string.Format("{0}", File_Description)); + sb.Append(string.Format("{0}", FileName)); + sb.Append(string.Format("{0}", File_ReleaseDate)); + sb.Append(string.Format("{0}", Anime_GroupName)); + sb.Append(string.Format("{0}", Anime_GroupNameShort)); + sb.Append(string.Format("{0}", Episode_Rating)); + sb.Append(string.Format("{0}", Episode_Votes)); + sb.Append(string.Format("{0}", DateTimeUpdated)); + sb.Append(string.Format("{0}", EpisodesRAW)); + sb.Append(string.Format("{0}", SubtitlesRAW)); + sb.Append(string.Format("{0}", LanguagesRAW)); + sb.Append(string.Format("{0}", EpisodesPercentRAW)); + sb.Append(@""); + + return sb.ToString(); + } + } +} diff --git a/JMMServer/Entities/AniDB_GroupStatus.cs b/JMMServer/Entities/AniDB_GroupStatus.cs new file mode 100644 index 000000000..b5401f3f7 --- /dev/null +++ b/JMMServer/Entities/AniDB_GroupStatus.cs @@ -0,0 +1,74 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using AniDBAPI; + +namespace JMMServer.Entities +{ + public class AniDB_GroupStatus + { + public int AniDB_GroupStatusID { get; private set; } + public int AnimeID { get; set; } + public int GroupID { get; set; } + public string GroupName { get; set; } + public int CompletionState { get; set; } + public int LastEpisodeNumber { get; set; } + public int Rating { get; set; } + public int Votes { get; set; } + public string EpisodeRange { get; set; } + + public AniDB_GroupStatus() + { + } + + public AniDB_GroupStatus(Raw_AniDB_GroupStatus raw) + { + this.AnimeID = raw.AnimeID; + this.GroupID = raw.GroupID; + this.GroupName = raw.GroupName; + this.CompletionState = raw.CompletionState; + this.LastEpisodeNumber = raw.LastEpisodeNumber; + this.Rating = raw.Rating; + this.Votes = raw.Votes; + this.EpisodeRange = raw.EpisodeRange; + } + + /// + /// looking at the episode range determine if the group has released a file + /// for the specified episode number + /// + /// + /// + public bool HasGroupReleasedEpisode(int episodeNumber) + { + // examples + // 1-12 + // 1 + // 5-10 + // 1-10, 12 + + string[] ranges = EpisodeRange.Split(','); + + foreach (string range in ranges) + { + string[] subRanges = range.Split('-'); + if (subRanges.Length == 1) // 1 episode + { + if (int.Parse(subRanges[0]) == episodeNumber) return true; + } + if (subRanges.Length == 2) // range + { + if (episodeNumber >= int.Parse(subRanges[0]) && episodeNumber <= int.Parse(subRanges[1])) return true; + } + } + + return false; + } + + public override string ToString() + { + return string.Format("Group Status for anime: {0} - {1} : {2}", AnimeID, GroupName, EpisodeRange); + } + } +} diff --git a/JMMServer/Entities/AniDB_ReleaseGroup.cs b/JMMServer/Entities/AniDB_ReleaseGroup.cs new file mode 100644 index 000000000..f3ac9298a --- /dev/null +++ b/JMMServer/Entities/AniDB_ReleaseGroup.cs @@ -0,0 +1,73 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using AniDBAPI; +using JMMContracts; + +namespace JMMServer.Entities +{ + public class AniDB_ReleaseGroup + { + public int AniDB_ReleaseGroupID { get; private set; } + public int GroupID { get; set; } + public int Rating { get; set; } + public int Votes { get; set; } + public int AnimeCount { get; set; } + public int FileCount { get; set; } + public string GroupName { get; set; } + public string GroupNameShort { get; set; } + public string IRCChannel { get; set; } + public string IRCServer { get; set; } + public string URL { get; set; } + public string Picname { get; set; } + + public AniDB_ReleaseGroup() + { + } + + public AniDB_ReleaseGroup(Raw_AniDB_Group raw) + { + Populate(raw); + } + + public void Populate(Raw_AniDB_Group raw) + { + this.GroupID = raw.GroupID; + this.Rating = raw.Rating; + this.Votes = raw.Votes; + this.AnimeCount = raw.AnimeCount; + this.FileCount = raw.FileCount; + this.GroupName = raw.GroupName; + this.GroupNameShort = raw.GroupNameShort; + this.IRCChannel = raw.IRCChannel; + this.IRCServer = raw.IRCServer; + this.URL = raw.URL; + this.Picname = raw.Picname; + } + + public Contract_ReleaseGroup ToContract() + { + Contract_ReleaseGroup contract = new Contract_ReleaseGroup(); + + contract.GroupID = this.GroupID; + contract.Rating = this.Rating; + contract.Votes = this.Votes; + contract.AnimeCount = this.AnimeCount; + contract.FileCount = this.FileCount; + contract.GroupName = this.GroupName; + contract.GroupNameShort = this.GroupNameShort; + contract.IRCChannel = this.IRCChannel; + contract.IRCServer = this.IRCServer; + contract.URL = this.URL; + contract.Picname = this.Picname; + + return contract; + } + + public override string ToString() + { + return string.Format("Release Group: {0} - {1} : {2}", GroupID, GroupName, URL); + } + } +} diff --git a/JMMServer/Entities/AniDB_Review.cs b/JMMServer/Entities/AniDB_Review.cs new file mode 100644 index 000000000..cac797e18 --- /dev/null +++ b/JMMServer/Entities/AniDB_Review.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using AniDBAPI; + +namespace JMMServer.Entities +{ + public class AniDB_Review + { + public int AniDB_ReviewID { get; private set; } + public int ReviewID { get; set; } + public int AuthorID { get; set; } + public int RatingAnimation { get; set; } + public int RatingSound { get; set; } + public int RatingStory { get; set; } + public int RatingCharacter { get; set; } + public int RatingValue { get; set; } + public int RatingEnjoyment { get; set; } + public string ReviewText { get; set; } + + public void Populate(Raw_AniDB_Review rawReview) + { + this.ReviewID = rawReview.ReviewID; + this.AuthorID = rawReview.AuthorID; + this.RatingAnimation = rawReview.RatingAnimation; + this.RatingSound = rawReview.RatingSound; + this.RatingStory = rawReview.RatingStory; + this.RatingCharacter = rawReview.RatingCharacter; + this.RatingValue = rawReview.RatingValue; + this.RatingEnjoyment = rawReview.RatingEnjoyment; + this.ReviewText = rawReview.ReviewText; + + } + + public override string ToString() + { + return string.Format("Review: {0} - {1}", ReviewID, RatingEnjoyment); + } + } +} diff --git a/JMMServer/Entities/AniDB_Tag.cs b/JMMServer/Entities/AniDB_Tag.cs new file mode 100644 index 000000000..fc6a228d4 --- /dev/null +++ b/JMMServer/Entities/AniDB_Tag.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using AniDBAPI; + +namespace JMMServer.Entities +{ + public class AniDB_Tag + { + public int AniDB_TagID { get; private set; } + public int TagID { get; set; } + public int Spoiler { get; set; } + public int LocalSpoiler { get; set; } + public int GlobalSpoiler { get; set; } + public string TagName { get; set; } + public int TagCount { get; set; } + public string TagDescription { get; set; } + + public void Populate(Raw_AniDB_Tag rawTag) + { + this.TagID = rawTag.TagID; + this.GlobalSpoiler = rawTag.GlobalSpoiler; + this.LocalSpoiler = rawTag.LocalSpoiler; + this.Spoiler = rawTag.Spoiler; + this.TagCount = rawTag.TagCount; + this.TagDescription = rawTag.TagDescription; + this.TagName = rawTag.TagName; + } + } +} diff --git a/JMMServer/Entities/AniDB_Vote.cs b/JMMServer/Entities/AniDB_Vote.cs new file mode 100644 index 000000000..d8f2824c1 --- /dev/null +++ b/JMMServer/Entities/AniDB_Vote.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMContracts; + +namespace JMMServer.Entities +{ + public class AniDB_Vote + { + public int AniDB_VoteID { get; private set; } + public int EntityID { get; set; } + public int VoteValue { get; set; } + public int VoteType { get; set; } + + public Contract_AniDBVote ToContract() + { + Contract_AniDBVote contract = new Contract_AniDBVote(); + + contract.EntityID = this.EntityID; + contract.VoteValue = (decimal)this.VoteValue / (decimal)100; + contract.VoteType = this.VoteType; + + return contract; + } + } +} diff --git a/JMMServer/Entities/AnimeEpisode.cs b/JMMServer/Entities/AnimeEpisode.cs new file mode 100644 index 000000000..26e7b352b --- /dev/null +++ b/JMMServer/Entities/AnimeEpisode.cs @@ -0,0 +1,385 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMContracts; +using JMMServer.Repositories; +using JMMServer.Commands; +using AniDBAPI; + +namespace JMMServer.Entities +{ + public class AnimeEpisode + { + public int AnimeEpisodeID { get; private set; } + public int AnimeSeriesID { get; set; } + public int AniDB_EpisodeID { get; set; } + public DateTime DateTimeUpdated { get; set; } + public DateTime DateTimeCreated { get; set; } + + + public enEpisodeType EpisodeTypeEnum + { + get + { + return (enEpisodeType)AniDB_Episode.EpisodeType; + } + } + + public AniDB_Episode AniDB_Episode + { + get + { + AniDB_EpisodeRepository repEps = new AniDB_EpisodeRepository(); + return repEps.GetByEpisodeID(this.AniDB_EpisodeID); + } + } + + public void Populate(AniDB_Episode anidbEp) + { + this.AniDB_EpisodeID = anidbEp.EpisodeID; + this.DateTimeUpdated = DateTime.Now; + this.DateTimeCreated = DateTime.Now; + } + + public AnimeEpisode_User GetUserRecord(int userID) + { + AnimeEpisode_UserRepository repEpUser = new AnimeEpisode_UserRepository(); + return repEpUser.GetByUserIDAndEpisodeID(userID, this.AnimeEpisodeID); + } + + public Contract_AnimeEpisode ToContract(bool getFileCount, int userID) + { + Contract_AnimeEpisode contract = new Contract_AnimeEpisode(); + contract.AniDB_EpisodeID = this.AniDB_EpisodeID; + contract.AnimeEpisodeID = this.AnimeEpisodeID; + contract.AnimeSeriesID = this.AnimeSeriesID; + contract.DateTimeUpdated = this.DateTimeUpdated; + + AnimeEpisode_User epuser = this.GetUserRecord(userID); + + if (epuser == null) + { + contract.IsWatched = 0; + contract.PlayedCount = 0; + contract.StoppedCount = 0; + contract.WatchedCount = 0; + contract.WatchedDate = null; + } + else + { + contract.IsWatched = 1; + contract.PlayedCount = epuser.PlayedCount; + contract.StoppedCount = epuser.StoppedCount; + contract.WatchedCount = epuser.WatchedCount; + contract.WatchedDate = epuser.WatchedDate; + } + + + AniDB_Episode aniEp = this.AniDB_Episode; + contract.AniDB_AirDate = aniEp.AirDateAsDate; + contract.AniDB_EnglishName = aniEp.EnglishName; + contract.AniDB_LengthSeconds = aniEp.LengthSeconds; + contract.AniDB_Rating = aniEp.Rating; + contract.AniDB_RomajiName = aniEp.RomajiName; + contract.AniDB_Votes = aniEp.Votes; + + contract.EpisodeNumber = aniEp.EpisodeNumber; + contract.EpisodeNameRomaji = aniEp.RomajiName; + contract.EpisodeNameEnglish = aniEp.EnglishName; + contract.EpisodeType = aniEp.EpisodeType; + + + // find the number of files we actually have for this episode + if (getFileCount) + contract.LocalFileCount = this.VideoLocals.Count; + + contract.ReleaseGroups = new List(); + + + + return contract; + } + + public Contract_AnimeEpisode ToContract(int userID) + { + return ToContract(true, userID); + } + + public Contract_AnimeEpisode ToContract(AniDB_Episode aniEp, List epVids, AnimeEpisode_User epuser) + { + Contract_AnimeEpisode contract = new Contract_AnimeEpisode(); + contract.AniDB_EpisodeID = this.AniDB_EpisodeID; + contract.AnimeEpisodeID = this.AnimeEpisodeID; + contract.AnimeSeriesID = this.AnimeSeriesID; + contract.DateTimeUpdated = this.DateTimeUpdated; + + if (epuser == null) + { + contract.IsWatched = 0; + contract.PlayedCount = 0; + contract.StoppedCount = 0; + contract.WatchedCount = 0; + contract.WatchedDate = null; + } + else + { + contract.IsWatched = 1; + contract.PlayedCount = epuser.PlayedCount; + contract.StoppedCount = epuser.StoppedCount; + contract.WatchedCount = epuser.WatchedCount; + contract.WatchedDate = epuser.WatchedDate; + } + + + contract.AniDB_AirDate = aniEp.AirDateAsDate; + contract.AniDB_EnglishName = aniEp.EnglishName; + contract.AniDB_LengthSeconds = aniEp.LengthSeconds; + contract.AniDB_Rating = aniEp.Rating; + contract.AniDB_RomajiName = aniEp.RomajiName; + contract.AniDB_Votes = aniEp.Votes; + + contract.EpisodeNumber = aniEp.EpisodeNumber; + contract.EpisodeNameRomaji = aniEp.RomajiName; + contract.EpisodeNameEnglish = aniEp.EnglishName; + contract.EpisodeType = aniEp.EpisodeType; + + + // find the number of files we actually have for this episode + //contract.LocalFileCount = VideoLocals.Count; + contract.LocalFileCount = epVids.Count; + + contract.ReleaseGroups = new List(); + + + + return contract; + } + + public Contract_AnimeEpisode ToContractOld(AniDB_Episode aniEp) + { + Contract_AnimeEpisode contract = new Contract_AnimeEpisode(); + contract.AniDB_EpisodeID = this.AniDB_EpisodeID; + contract.AnimeEpisodeID = this.AnimeEpisodeID; + contract.AnimeSeriesID = this.AnimeSeriesID; + contract.DateTimeUpdated = this.DateTimeUpdated; + //contract.IsWatched = this.IsWatched; + //contract.PlayedCount = this.PlayedCount; + //contract.StoppedCount = this.StoppedCount; + //contract.WatchedCount = this.WatchedCount; + //contract.WatchedDate = this.WatchedDate; + + + + contract.AniDB_AirDate = aniEp.AirDateAsDate; + contract.AniDB_EnglishName = aniEp.EnglishName; + contract.AniDB_LengthSeconds = aniEp.LengthSeconds; + contract.AniDB_Rating = aniEp.Rating; + contract.AniDB_RomajiName = aniEp.RomajiName; + contract.AniDB_Votes = aniEp.Votes; + + contract.EpisodeNumber = aniEp.EpisodeNumber; + contract.EpisodeNameRomaji = aniEp.RomajiName; + contract.EpisodeNameEnglish = aniEp.EnglishName; + contract.EpisodeType = aniEp.EpisodeType; + + + // find the number of files we actually have for this episode + contract.LocalFileCount = VideoLocals.Count; + + contract.ReleaseGroups = new List(); + + + + return contract; + } + + /// + /// Gets the AnimeSeries this episode belongs to + /// + public AnimeSeries AnimeSeries + { + get + { + AnimeSeriesRepository repSeries = new AnimeSeriesRepository(); + return repSeries.GetByID(this.AnimeSeriesID); + } + } + + public List VideoLocals + { + get + { + VideoLocalRepository repVidLocals = new VideoLocalRepository(); + return repVidLocals.GetByAniDBEpisodeID(AniDB_EpisodeID); + } + } + + public List FileCrossRefs + { + get + { + CrossRef_File_EpisodeRepository repCrossRefs = new CrossRef_File_EpisodeRepository(); + return repCrossRefs.GetByEpisodeID(AniDB_EpisodeID); + } + } + + public void SaveWatchedStatus(bool watched, int userID, DateTime? watchedDate) + { + AnimeEpisode_UserRepository repEpisodeUsers = new AnimeEpisode_UserRepository(); + AnimeEpisode_User epUserRecord = this.GetUserRecord(userID); + + if (watched) + { + if (epUserRecord == null) + { + epUserRecord = new AnimeEpisode_User(); + epUserRecord.PlayedCount = 0; + epUserRecord.StoppedCount = 0; + epUserRecord.WatchedCount = 0; + } + epUserRecord.AnimeEpisodeID = this.AnimeEpisodeID; + epUserRecord.AnimeSeriesID = this.AnimeSeriesID; + epUserRecord.JMMUserID = userID; + + if (watchedDate.HasValue) + epUserRecord.WatchedDate = watchedDate.Value; + else + epUserRecord.WatchedDate = DateTime.Now; + + repEpisodeUsers.Save(epUserRecord); + } + else + { + if (epUserRecord != null) + repEpisodeUsers.Delete(epUserRecord.AnimeEpisode_UserID); + } + } + + + + public List GetVideoDetailedContracts(int userID) + { + VideoLocalRepository repVids = new VideoLocalRepository(); + List contracts = new List(); + + // get all the cross refs + foreach (CrossRef_File_Episode xref in FileCrossRefs) + { + Contract_VideoDetailed contract = new Contract_VideoDetailed(); + contract.Percentage = xref.Percentage; + contract.EpisodeOrder = xref.EpisodeOrder; + contract.CrossRefSource = xref.CrossRefSource; + contract.AnimeEpisodeID = this.AnimeEpisodeID; + + // get the video file + // we will assume that it is unique by hash/episodeid + VideoLocal vid = repVids.GetByHash(xref.Hash); + if (vid != null) + { + contract.VideoLocal_FilePath = vid.FilePath; + contract.VideoLocal_Hash = vid.Hash; + contract.VideoLocal_FileSize = vid.FileSize; + contract.VideoLocalID = vid.VideoLocalID; + + AnimeEpisode_User userRecord = this.GetUserRecord(userID); + if (userRecord == null) + contract.VideoLocal_IsWatched = 0; + else + contract.VideoLocal_IsWatched = 1; + contract.VideoLocal_IsIgnored = vid.IsIgnored; + + // Import Folder + ImportFolder ns = vid.ImportFolder; // to prevent multiple db calls + contract.ImportFolderID = ns.ImportFolderID; + contract.ImportFolderLocation = ns.ImportFolderLocation; + contract.ImportFolderName = ns.ImportFolderName; + + // video info + VideoInfo vi = vid.VideoInfo; // to prevent multiple db calls + contract.VideoInfo_AudioBitrate = vi.AudioBitrate; + contract.VideoInfo_AudioCodec = vi.AudioCodec; + contract.VideoInfo_Duration = vi.Duration; + contract.VideoInfo_VideoBitrate = vi.VideoBitrate; + contract.VideoInfo_VideoCodec = vi.VideoCodec; + contract.VideoInfo_VideoFrameRate = vi.VideoFrameRate; + contract.VideoInfo_VideoResolution = vi.VideoResolution; + contract.VideoInfo_VideoInfoID = vi.VideoInfoID; + + // AniDB File + AniDB_File anifile = vid.AniDBFile; // to prevent multiple db calls + if (anifile != null) + { + contract.AniDB_Anime_GroupName = anifile.Anime_GroupName; + contract.AniDB_Anime_GroupNameShort = anifile.Anime_GroupNameShort; + contract.AniDB_AnimeID = anifile.AnimeID; + contract.AniDB_CRC = anifile.CRC; + contract.AniDB_Episode_Rating = anifile.Episode_Rating; + contract.AniDB_Episode_Votes = anifile.Episode_Votes; + contract.AniDB_File_AudioCodec = anifile.File_AudioCodec; + contract.AniDB_File_Description = anifile.File_Description; + contract.AniDB_File_FileExtension = anifile.File_FileExtension; + contract.AniDB_File_LengthSeconds = anifile.File_LengthSeconds; + contract.AniDB_File_ReleaseDate = anifile.File_ReleaseDate; + contract.AniDB_File_Source = anifile.File_Source; + contract.AniDB_File_VideoCodec = anifile.File_VideoCodec; + contract.AniDB_File_VideoResolution = anifile.File_VideoResolution; + contract.AniDB_FileID = anifile.FileID; + contract.AniDB_GroupID = anifile.GroupID; + contract.AniDB_MD5 = anifile.MD5; + contract.AniDB_SHA1 = anifile.SHA1; + + // languages + contract.LanguagesAudio = anifile.LanguagesRAW; + contract.LanguagesSubtitle = anifile.SubtitlesRAW; + } + else + { + contract.AniDB_Anime_GroupName = ""; + contract.AniDB_Anime_GroupNameShort = ""; + contract.AniDB_CRC = ""; + contract.AniDB_File_AudioCodec = ""; + contract.AniDB_File_Description = ""; + contract.AniDB_File_FileExtension = ""; + contract.AniDB_File_Source = ""; + contract.AniDB_File_VideoCodec = ""; + contract.AniDB_File_VideoResolution = ""; + contract.AniDB_MD5 = ""; + contract.AniDB_SHA1 = ""; + + // languages + contract.LanguagesAudio = ""; + contract.LanguagesSubtitle = ""; + } + + + + + AniDB_ReleaseGroup relGroup = vid.ReleaseGroup; // to prevent multiple db calls + if (relGroup != null) + contract.ReleaseGroup = relGroup.ToContract(); + else + contract.ReleaseGroup = null; + + contracts.Add(contract); + } + } + + + return contracts; + } + + public void ToggleWatchedStatus(bool watched, bool updateOnline, DateTime? watchedDate, int userID) + { + ToggleWatchedStatus(watched, updateOnline, watchedDate, true, userID); + } + + public void ToggleWatchedStatus(bool watched, bool updateOnline, DateTime? watchedDate, bool updateStats, int userID) + { + foreach (VideoLocal vid in VideoLocals) + { + vid.ToggleWatchedStatus(watched, updateOnline, watchedDate, updateStats, userID); + } + } + } +} diff --git a/JMMServer/Entities/AnimeEpisode_User.cs b/JMMServer/Entities/AnimeEpisode_User.cs new file mode 100644 index 000000000..14b499c0b --- /dev/null +++ b/JMMServer/Entities/AnimeEpisode_User.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMContracts; +using JMMServer.Repositories; +using JMMServer.Commands; +using AniDBAPI; + +namespace JMMServer.Entities +{ + public class AnimeEpisode_User + { + public int AnimeEpisode_UserID { get; private set; } + public int JMMUserID { get; set; } + public int AnimeEpisodeID { get; set; } + public int AnimeSeriesID { get; set; } + public DateTime WatchedDate { get; set; } + public int PlayedCount { get; set; } + public int WatchedCount { get; set; } + public int StoppedCount { get; set; } + } +} diff --git a/JMMServer/Entities/AnimeGroup.cs b/JMMServer/Entities/AnimeGroup.cs new file mode 100644 index 000000000..1bc6fa0c8 --- /dev/null +++ b/JMMServer/Entities/AnimeGroup.cs @@ -0,0 +1,700 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using NLog; +using JMMServer.Repositories; +using JMMContracts; +using System.Xml.Serialization; +using BinaryNorthwest; + +namespace JMMServer.Entities +{ + public class AnimeGroup + { + #region DB Columns + public int AnimeGroupID { get; private set; } + public int? AnimeGroupParentID { get; set; } + public string GroupName { get; set; } + public string Description { get; set; } + public int IsManuallyNamed { get; set; } + public DateTime DateTimeUpdated { get; set; } + public DateTime DateTimeCreated { get; set; } + public string SortName { get; set; } + public DateTime? EpisodeAddedDate { get; set; } + public int MissingEpisodeCount { get; set; } + public int MissingEpisodeCountGroups { get; set; } + public int OverrideDescription { get; set; } + #endregion + + private static Logger logger = LogManager.GetCurrentClassLogger(); + + public static List GetRelatedGroupsFromAnimeID(int animeid) + { + // TODO we need to recusrive list at all relations and not just the first one + AniDB_AnimeRepository repAniAnime = new AniDB_AnimeRepository(); + AnimeSeriesRepository repSeries = new AnimeSeriesRepository(); + AnimeGroupRepository repGroups = new AnimeGroupRepository(); + + List grps = new List(); + + AniDB_Anime anime = repAniAnime.GetByAnimeID(animeid); + if (anime == null) return grps; + + // first check for groups which are directly related + List relations = anime.RelatedAnime; + foreach (AniDB_Anime_Relation rel in relations) + { + // we actually need to get the series, because it might have been added to another group already + AnimeSeries ser = repSeries.GetByAnimeID(rel.RelatedAnimeID); + if (ser != null) + { + AnimeGroup grp = repGroups.GetByID(ser.AnimeGroupID); + if (grp != null) grps.Add(grp); + } + } + if (grps.Count > 0) return grps; + + // if nothing found check by all related anime + List relatedAnime = anime.AllRelatedAnime; + foreach (AniDB_Anime rel in relatedAnime) + { + // we actually need to get the series, because it might have been added to another group already + AnimeSeries ser = repSeries.GetByAnimeID(rel.AnimeID); + if (ser != null) + { + AnimeGroup grp = repGroups.GetByID(ser.AnimeGroupID); + if (grp != null) grps.Add(grp); + } + } + + return grps; + } + + public AnimeGroup_User GetUserRecord(int userID) + { + AnimeGroup_UserRepository repUser = new AnimeGroup_UserRepository(); + return repUser.GetByUserAndGroupID(userID, this.AnimeGroupID); + } + + public void Populate(AnimeSeries series) + { + this.Description = series.Anime.Description; + this.GroupName = series.Anime.PreferredTitle; + this.SortName = series.Anime.PreferredTitle; + this.DateTimeUpdated = DateTime.Now; + this.DateTimeCreated = DateTime.Now; + } + + public bool HasMissingEpisodesAny + { + get + { + return (MissingEpisodeCount > 0 || MissingEpisodeCountGroups > 0); + } + } + + public bool HasMissingEpisodesGroups + { + get + { + return MissingEpisodeCountGroups > 0; + } + } + + public bool HasMissingEpisodes + { + get + { + return MissingEpisodeCountGroups > 0; + } + } + + public List AnimeTypesList + { + get + { + List atypeList = new List(); + foreach (AnimeSeries series in AllSeries) + { + string atype = series.Anime.AnimeTypeDescription; + if (!atypeList.Contains(atype)) atypeList.Add(atype); + } + return atypeList; + } + } + + /// + /// Renames all Anime groups based on the user's language preferences + /// + public static void RenameAllGroups() + { + AnimeGroupRepository repGroups = new AnimeGroupRepository(); + List groupsToSave = new List(); + foreach (AnimeGroup grp in repGroups.GetAll()) + { + // only rename the group if it has one direct child Anime Series + if (grp.Series.Count == 1) + { + string newTitle = grp.Series[0].Anime.PreferredTitle; + grp.GroupName = newTitle; + grp.SortName = newTitle; + groupsToSave.Add(grp); + repGroups.Save(grp); + } + } + + foreach (AnimeGroup grp in groupsToSave) + repGroups.Save(grp); + } + + public List Anime + { + get + { + List relAnime = new List(); + foreach (AnimeSeries serie in Series) + { + AniDB_Anime anime = serie.Anime; + if (anime != null) relAnime.Add(anime); + + } + return relAnime; + } + } + + public Contract_AnimeGroup ToContract(AnimeGroup_User userRecord) + { + Contract_AnimeGroup contract = new Contract_AnimeGroup(); + contract.AnimeGroupID = this.AnimeGroupID; + contract.AnimeGroupParentID = this.AnimeGroupParentID; + contract.GroupName = this.GroupName; + contract.Description = this.Description; + contract.SortName = this.SortName; + contract.EpisodeAddedDate = this.EpisodeAddedDate; + contract.OverrideDescription = this.OverrideDescription; + contract.DateTimeUpdated = this.DateTimeUpdated; + + if (userRecord == null) + { + contract.IsFave = 0; + contract.UnwatchedEpisodeCount = 0; + contract.WatchedEpisodeCount = 0; + contract.WatchedDate = null; + contract.PlayedCount = 0; + contract.WatchedCount = 0; + contract.StoppedCount = 0; + } + else + { + contract.IsFave = userRecord.IsFave; + contract.UnwatchedEpisodeCount = userRecord.UnwatchedEpisodeCount; + contract.WatchedEpisodeCount = userRecord.WatchedEpisodeCount; + contract.WatchedDate = userRecord.WatchedDate; + contract.PlayedCount = userRecord.PlayedCount; + contract.WatchedCount = userRecord.WatchedCount; + contract.StoppedCount = userRecord.StoppedCount; + } + + contract.MissingEpisodeCount = this.MissingEpisodeCount; + contract.MissingEpisodeCountGroups = this.MissingEpisodeCountGroups; + + if (StatsCache.Instance.StatGroupAudioLanguages.ContainsKey(this.AnimeGroupID)) + contract.Stat_AudioLanguages = StatsCache.Instance.StatGroupAudioLanguages[this.AnimeGroupID]; + else contract.Stat_AudioLanguages = ""; + + if (StatsCache.Instance.StatGroupSubtitleLanguages.ContainsKey(this.AnimeGroupID)) + contract.Stat_SubtitleLanguages = StatsCache.Instance.StatGroupSubtitleLanguages[this.AnimeGroupID]; + else contract.Stat_SubtitleLanguages = ""; + + if (StatsCache.Instance.StatGroupVideoQuality.ContainsKey(this.AnimeGroupID)) + contract.Stat_AllVideoQuality = StatsCache.Instance.StatGroupVideoQuality[this.AnimeGroupID]; + else contract.Stat_AllVideoQuality = ""; + + if (StatsCache.Instance.StatGroupVideoQualityEpisodes.ContainsKey(this.AnimeGroupID)) + contract.Stat_AllVideoQuality_Episodes = StatsCache.Instance.StatGroupVideoQualityEpisodes[this.AnimeGroupID]; + else contract.Stat_AllVideoQuality_Episodes = ""; + + if (StatsCache.Instance.StatGroupIsComplete.ContainsKey(this.AnimeGroupID)) + contract.Stat_IsComplete = StatsCache.Instance.StatGroupIsComplete[this.AnimeGroupID]; + else contract.Stat_IsComplete = false; + + if (StatsCache.Instance.StatGroupHasTvDB.ContainsKey(this.AnimeGroupID)) + contract.Stat_HasTvDBLink = StatsCache.Instance.StatGroupHasTvDB[this.AnimeGroupID]; + else contract.Stat_HasTvDBLink = false; + + if (StatsCache.Instance.StatGroupHasMovieDB.ContainsKey(this.AnimeGroupID)) + contract.Stat_HasMovieDBLink = StatsCache.Instance.StatGroupHasMovieDB[this.AnimeGroupID]; + else contract.Stat_HasMovieDBLink = false; + + if (StatsCache.Instance.StatGroupHasMovieDBOrTvDB.ContainsKey(this.AnimeGroupID)) + contract.Stat_HasMovieDBOrTvDBLink = StatsCache.Instance.StatGroupHasMovieDBOrTvDB[this.AnimeGroupID]; + else contract.Stat_HasMovieDBOrTvDBLink = false; + + if (StatsCache.Instance.StatGroupIsFinishedAiring.ContainsKey(this.AnimeGroupID)) + contract.Stat_HasFinishedAiring = StatsCache.Instance.StatGroupIsFinishedAiring[this.AnimeGroupID]; + else contract.Stat_HasFinishedAiring = false; + + if (StatsCache.Instance.StatGroupAirDate_Max.ContainsKey(this.AnimeGroupID)) + contract.Stat_AirDate_Max = StatsCache.Instance.StatGroupAirDate_Max[this.AnimeGroupID]; + else contract.Stat_AirDate_Max = null; + + if (StatsCache.Instance.StatGroupAirDate_Min.ContainsKey(this.AnimeGroupID)) + contract.Stat_AirDate_Min = StatsCache.Instance.StatGroupAirDate_Min[this.AnimeGroupID]; + else contract.Stat_AirDate_Min = null; + + if (StatsCache.Instance.StatGroupCategories.ContainsKey(this.AnimeGroupID)) + contract.Stat_AllCategories = StatsCache.Instance.StatGroupCategories[this.AnimeGroupID]; + else contract.Stat_AllCategories = ""; + + if (StatsCache.Instance.StatGroupEndDate.ContainsKey(this.AnimeGroupID)) + contract.Stat_EndDate = StatsCache.Instance.StatGroupEndDate[this.AnimeGroupID]; + else contract.Stat_EndDate = null; + + if (StatsCache.Instance.StatGroupSeriesCreatedDate.ContainsKey(this.AnimeGroupID)) + contract.Stat_SeriesCreatedDate = StatsCache.Instance.StatGroupSeriesCreatedDate[this.AnimeGroupID]; + else contract.Stat_SeriesCreatedDate = null; + + if (StatsCache.Instance.StatGroupTitles.ContainsKey(this.AnimeGroupID)) + contract.Stat_AllTitles = StatsCache.Instance.StatGroupTitles[this.AnimeGroupID]; + else contract.Stat_AllTitles = ""; + + if (StatsCache.Instance.StatGroupUserVoteOverall.ContainsKey(this.AnimeGroupID)) + contract.Stat_UserVoteOverall = StatsCache.Instance.StatGroupUserVoteOverall[this.AnimeGroupID]; + else contract.Stat_UserVoteOverall = null; + + if (StatsCache.Instance.StatGroupUserVotePermanent.ContainsKey(this.AnimeGroupID)) + contract.Stat_UserVotePermanent = StatsCache.Instance.StatGroupUserVotePermanent[this.AnimeGroupID]; + else contract.Stat_UserVotePermanent = null; + + if (StatsCache.Instance.StatGroupUserVoteTemporary.ContainsKey(this.AnimeGroupID)) + contract.Stat_UserVoteTemporary = StatsCache.Instance.StatGroupUserVoteTemporary[this.AnimeGroupID]; + else contract.Stat_UserVoteTemporary = null; + + if (StatsCache.Instance.StatGroupSeriesCount.ContainsKey(this.AnimeGroupID)) + contract.Stat_SeriesCount = StatsCache.Instance.StatGroupSeriesCount[this.AnimeGroupID]; + else contract.Stat_SeriesCount = 0; + + //contract.AniDB_AirDate = this.AirDate; + //contract.AniDB_Year = animeRec.Year; + + return contract; + } + + public decimal AniDBRating + { + get + { + try + { + decimal totalRating = 0; + int totalVotes = 0; + + foreach (AniDB_Anime anime in Anime) + { + totalRating += (decimal)anime.AniDBTotalRating; + totalVotes += anime.AniDBTotalVotes; + } + + if (totalVotes == 0) + return 0; + else + return totalRating / (decimal)totalVotes; + + } + catch (Exception ex) + { + logger.Error("Error in AniDBRating: {0}", ex.ToString()); + return 0; + } + } + } + + [XmlIgnore] + public List ChildGroups + { + get + { + AnimeGroupRepository repGroups = new AnimeGroupRepository(); + return repGroups.GetByParentID(this.AnimeGroupID); + } + } + + [XmlIgnore] + public List AllChildGroups + { + get + { + List grpList = new List(); + AnimeGroup.GetAnimeGroupsRecursive(this.AnimeGroupID, ref grpList); + return grpList; + } + } + + [XmlIgnore] + public List Series + { + get + { + AnimeSeriesRepository repSeries = new AnimeSeriesRepository(); + List seriesList = repSeries.GetByGroupID(this.AnimeGroupID); + + /*List sortCriteria = new List(); + sortCriteria.Add(new SortPropOrFieldAndDirection("Year", false, SortType.eString)); + seriesList = Sorting.MultiSort(seriesList, sortCriteria);*/ + + return seriesList; + } + } + + [XmlIgnore] + public List AllSeries + { + get + { + List seriesList = new List(); + AnimeGroup.GetAnimeSeriesRecursive(this.AnimeGroupID, ref seriesList); + + /*List sortCriteria = new List(); + sortCriteria.Add(new SortPropOrFieldAndDirection("Year", false, SortType.eString)); + seriesList = Sorting.MultiSort(seriesList, sortCriteria);*/ + + return seriesList; + } + } + + public string CategoriesString + { + get + { + string temp = ""; + foreach (AniDB_Category cat in Categories) + temp += cat.CategoryName + "|"; + if (temp.Length > 2) + temp = temp.Substring(0, temp.Length - 2); + + return temp; + } + } + + public List Categories + { + get + { + List cats = new List(); + List animeCatIDs = new List(); + List animeCats = new List(); + + // get a list of all the unique categories for this all the series in this group + foreach (AnimeSeries ser in AllSeries) + { + foreach (AniDB_Anime_Category aac in ser.Anime.AnimeCategories) + { + if (!animeCatIDs.Contains(aac.AniDB_Anime_CategoryID)) + { + animeCatIDs.Add(aac.AniDB_Anime_CategoryID); + animeCats.Add(aac); + } + } + } + + // now sort it by the weighting + List sortCriteria = new List(); + sortCriteria.Add(new SortPropOrFieldAndDirection("Weighting", true, SortType.eInteger)); + animeCats = Sorting.MultiSort(animeCats, sortCriteria); + + AniDB_CategoryRepository repCat = new AniDB_CategoryRepository(); + foreach (AniDB_Anime_Category animeCat in animeCats) + { + AniDB_Category cat = repCat.GetByCategoryID(animeCat.CategoryID); + if (cat != null) cats.Add(cat); + } + + return cats; + } + } + + public List Titles + { + get + { + List animeTitleIDs = new List(); + List animeTitles = new List(); + + + // get a list of all the unique titles for this all the series in this group + foreach (AnimeSeries ser in AllSeries) + { + foreach (AniDB_Anime_Title aat in ser.Anime.Titles) + { + if (!animeTitleIDs.Contains(aat.AniDB_Anime_TitleID)) + { + animeTitleIDs.Add(aat.AniDB_Anime_TitleID); + animeTitles.Add(aat); + } + } + } + + return animeTitles; + } + } + + public string TitlesString + { + get + { + string temp = ""; + foreach (AniDB_Anime_Title title in Titles) + temp += title.Title + ", "; + if (temp.Length > 2) + temp = temp.Substring(0, temp.Length - 2); + + return temp; + } + } + + public string VideoQualityString + { + get + { + AdhocRepository rep = new AdhocRepository(); + return rep.GetAllVideoQualityForGroup(this.AnimeGroupID); + } + } + + public decimal? UserVote + { + get + { + decimal totalVotes = 0; + int countVotes = 0; + foreach (AnimeSeries ser in AllSeries) + { + AniDB_Vote vote = ser.Anime.UserVote; + if (vote != null) + { + countVotes++; + totalVotes += (decimal)vote.VoteValue; + } + } + + if (countVotes == 0) + return null; + else + return totalVotes / (decimal)countVotes / (decimal)100; + + + } + } + + public decimal? UserVotePermanent + { + get + { + decimal totalVotes = 0; + int countVotes = 0; + foreach (AnimeSeries ser in AllSeries) + { + AniDB_Vote vote = ser.Anime.UserVote; + if (vote != null && vote.VoteType == (int)AniDBVoteType.Anime) + { + countVotes++; + totalVotes += (decimal)vote.VoteValue; + } + } + + if (countVotes == 0) + return null; + else + return totalVotes / (decimal)countVotes / (decimal)100; + + } + } + + public decimal? UserVoteTemporary + { + get + { + decimal totalVotes = 0; + int countVotes = 0; + foreach (AnimeSeries ser in AllSeries) + { + AniDB_Vote vote = ser.Anime.UserVote; + if (vote != null && vote.VoteType == (int)AniDBVoteType.AnimeTemp) + { + countVotes++; + totalVotes += (decimal)vote.VoteValue; + } + } + + if (countVotes == 0) + return null; + else + return totalVotes / (decimal)countVotes / (decimal)100; + + } + } + + public override string ToString() + { + return string.Format("Group: {0} ({1})", GroupName, AnimeGroupID); + //return ""; + } + + public void UpdateStatsFromTopLevel(bool watchedStats, bool missingEpsStats) + { + UpdateStatsFromTopLevel(false, watchedStats, missingEpsStats); + } + + /// + /// Update stats for all child groups and series + /// This should only be called from the very top level group. + /// + public void UpdateStatsFromTopLevel(bool updateGroupStatsOnly, bool watchedStats, bool missingEpsStats) + { + if (this.AnimeGroupParentID.HasValue) return; + + // update the stats for all the sries first + if (!updateGroupStatsOnly) + { + foreach (AnimeSeries ser in AllSeries) + { + ser.UpdateStats(watchedStats, missingEpsStats, false); + } + } + + // now recursively update stats for all the child groups + // and update the stats for the groups + foreach (AnimeGroup grp in AllChildGroups) + { + grp.UpdateStats(watchedStats, missingEpsStats); + } + + UpdateStats(watchedStats, missingEpsStats); + } + + /// + /// Update the stats for this group based on the child series + /// Assumes that all the AnimeSeries have had their stats updated already + /// + public void UpdateStats(bool watchedStats, bool missingEpsStats) + { + List seriesList = AllSeries; + + JMMUserRepository repUsers = new JMMUserRepository(); + List allUsers = repUsers.GetAll(); + + if (watchedStats) + { + foreach (JMMUser juser in allUsers) + { + AnimeGroup_User userRecord = GetUserRecord(juser.JMMUserID); + if (userRecord == null) userRecord = new AnimeGroup_User(juser.JMMUserID, this.AnimeGroupID); + + // reset stats + userRecord.WatchedCount = 0; + userRecord.UnwatchedEpisodeCount = 0; + userRecord.PlayedCount = 0; + userRecord.StoppedCount = 0; + userRecord.WatchedEpisodeCount = 0; + userRecord.WatchedDate = null; + + foreach (AnimeSeries ser in seriesList) + { + AnimeSeries_User serUserRecord = ser.GetUserRecord(juser.JMMUserID); + if (serUserRecord != null) + { + userRecord.WatchedCount += serUserRecord.WatchedCount; + userRecord.UnwatchedEpisodeCount += serUserRecord.UnwatchedEpisodeCount; + userRecord.PlayedCount += serUserRecord.PlayedCount; + userRecord.StoppedCount += serUserRecord.StoppedCount; + userRecord.WatchedEpisodeCount += serUserRecord.WatchedEpisodeCount; + + if (serUserRecord.WatchedDate.HasValue) + { + if (userRecord.WatchedDate.HasValue) + { + if (serUserRecord.WatchedDate > userRecord.WatchedDate) + userRecord.WatchedDate = serUserRecord.WatchedDate; + } + else + userRecord.WatchedDate = serUserRecord.WatchedDate; + } + } + } + + // now update the stats for the groups + logger.Trace("Updating stats for {0}", this.ToString()); + AnimeGroup_UserRepository rep = new AnimeGroup_UserRepository(); + rep.Save(userRecord); + } + } + + if (missingEpsStats) + { + this.MissingEpisodeCount = 0; + this.MissingEpisodeCountGroups = 0; + + foreach (AnimeSeries ser in seriesList) + { + this.MissingEpisodeCount += ser.MissingEpisodeCount; + this.MissingEpisodeCountGroups += ser.MissingEpisodeCountGroups; + } + + AnimeGroupRepository repGrp = new AnimeGroupRepository(); + repGrp.Save(this); + } + + + } + + public static void GetAnimeGroupsRecursive(int animeGroupID, ref List groupList) + { + AnimeGroupRepository rep = new AnimeGroupRepository(); + AnimeGroup grp = rep.GetByID(animeGroupID); + if (grp == null) return; + + // get the child groups for this group + groupList.AddRange(grp.ChildGroups); + + foreach (AnimeGroup childGroup in grp.ChildGroups) + { + GetAnimeGroupsRecursive(childGroup.AnimeGroupID, ref groupList); + } + } + + + public static void GetAnimeSeriesRecursive(int animeGroupID, ref List seriesList) + { + AnimeGroupRepository rep = new AnimeGroupRepository(); + AnimeGroup grp = rep.GetByID(animeGroupID); + if (grp == null) return; + + // get the series for this group + List thisSeries = grp.Series; + seriesList.AddRange(thisSeries); + + foreach (AnimeGroup childGroup in grp.ChildGroups) + { + GetAnimeSeriesRecursive(childGroup.AnimeGroupID, ref seriesList); + } + } + + public AnimeGroup TopLevelAnimeGroup + { + get + { + if (!AnimeGroupParentID.HasValue) return this; + AnimeGroupRepository repGroups = new AnimeGroupRepository(); + AnimeGroup parentGroup = repGroups.GetByID(this.AnimeGroupParentID.Value); + + while (parentGroup.AnimeGroupParentID.HasValue) + { + parentGroup = repGroups.GetByID(parentGroup.AnimeGroupParentID.Value); + } + return parentGroup; + } + } + + } +} diff --git a/JMMServer/Entities/AnimeGroup_User.cs b/JMMServer/Entities/AnimeGroup_User.cs new file mode 100644 index 000000000..851145c4f --- /dev/null +++ b/JMMServer/Entities/AnimeGroup_User.cs @@ -0,0 +1,70 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using NLog; + +namespace JMMServer.Entities +{ + public class AnimeGroup_User + { + private static Logger logger = LogManager.GetCurrentClassLogger(); + + #region DB Columns + public int AnimeGroup_UserID { get; private set; } + public int JMMUserID { get; set; } + public int AnimeGroupID { get; set; } + public int IsFave { get; set; } + public int UnwatchedEpisodeCount { get; set; } + public int WatchedEpisodeCount { get; set; } + public DateTime? WatchedDate { get; set; } + public int PlayedCount { get; set; } + public int WatchedCount { get; set; } + public int StoppedCount { get; set; } + #endregion + + public AnimeGroup_User() + { + } + + public AnimeGroup_User(int userID, int groupID) + { + JMMUserID = userID; + AnimeGroupID = groupID; + + IsFave = 0; + UnwatchedEpisodeCount = 0; + WatchedEpisodeCount = 0; + WatchedDate = null; + PlayedCount = 0; + WatchedCount = 0; + StoppedCount = 0; + } + + + + public bool HasUnwatchedFiles + { + get + { + return UnwatchedEpisodeCount > 0; + } + } + + public bool AllFilesWatched + { + get + { + return UnwatchedEpisodeCount == 0; + } + } + + public bool AnyFilesWatched + { + get + { + return WatchedEpisodeCount > 0; + } + } + } +} diff --git a/JMMServer/Entities/AnimeSeries.cs b/JMMServer/Entities/AnimeSeries.cs new file mode 100644 index 000000000..dfa17bf0f --- /dev/null +++ b/JMMServer/Entities/AnimeSeries.cs @@ -0,0 +1,446 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using NLog; +using JMMServer.Repositories; +using JMMContracts; + +namespace JMMServer.Entities +{ + public class AnimeSeries + { + #region DB Columns + public int AnimeSeriesID { get; private set; } + public int AnimeGroupID { get; set; } + public int AniDB_ID { get; set; } + public DateTime DateTimeUpdated { get; set; } + public DateTime DateTimeCreated { get; set; } + public string DefaultAudioLanguage { get; set; } + public string DefaultSubtitleLanguage { get; set; } + public DateTime? EpisodeAddedDate { get; set; } + public int MissingEpisodeCount { get; set; } + public int MissingEpisodeCountGroups { get; set; } + public int LatestLocalEpisodeNumber { get; set; } + #endregion + + public string Year + { + get + { + return Anime.Year; + } + } + + private static Logger logger = LogManager.GetCurrentClassLogger(); + + + public string GenresRaw + { + get + { + if (Anime == null) + return ""; + else + return Anime.CategoriesString; + } + } + + public List AnimeEpisodes + { + get + { + AnimeEpisodeRepository repEpisodes = new AnimeEpisodeRepository(); + return repEpisodes.GetBySeriesID(AnimeSeriesID); + } + } + + public CrossRef_AniDB_TvDB CrossRefTvDB + { + get + { + CrossRef_AniDB_TvDBRepository repCrossRef = new CrossRef_AniDB_TvDBRepository(); + return repCrossRef.GetByAnimeID(this.AniDB_ID); + } + } + + public CrossRef_AniDB_Trakt CrossRefTrakt + { + get + { + CrossRef_AniDB_TraktRepository repCrossRef = new CrossRef_AniDB_TraktRepository(); + return repCrossRef.GetByAnimeID(this.AniDB_ID); + } + } + + public CrossRef_AniDB_Other CrossRefMovieDB + { + get + { + CrossRef_AniDB_OtherRepository repCrossRef = new CrossRef_AniDB_OtherRepository(); + return repCrossRef.GetByAnimeIDAndType(this.AniDB_ID, CrossRefType.MovieDB); + } + } + + public AnimeEpisode GetLastEpisodeWatched(int userID) + { + AnimeEpisode watchedep = null; + AnimeEpisode_User userRecordWatched = null; + + foreach (AnimeEpisode ep in AnimeEpisodes) + { + AnimeEpisode_User userRecord = ep.GetUserRecord(userID); + if (userRecord != null && ep.EpisodeTypeEnum == AniDBAPI.enEpisodeType.Episode) + { + if (watchedep == null) + { + watchedep = ep; + userRecordWatched = userRecord; + } + + if (userRecord.WatchedDate > userRecordWatched.WatchedDate) + { + watchedep = ep; + userRecordWatched = userRecord; + } + } + } + return watchedep; + } + + public AnimeSeries_User GetUserRecord(int userID) + { + AnimeSeries_UserRepository repUser = new AnimeSeries_UserRepository(); + return repUser.GetByUserAndSeriesID(userID, this.AnimeSeriesID); + } + + public AniDB_Anime Anime + { + get + { + AniDB_AnimeRepository repAnime = new AniDB_AnimeRepository(); + AniDB_Anime anidb_anime = repAnime.GetByAnimeID(this.AniDB_ID); + return anidb_anime; + } + } + + public DateTime? AirDate + { + get + { + if (Anime != null) + return Anime.AirDate; + return DateTime.Now; + + } + } + + public DateTime? EndDate + { + get + { + if (Anime != null) + return Anime.EndDate; + return null; + + } + } + + public void Populate(AniDB_Anime anime) + { + this.AniDB_ID = anime.AnimeID; + this.LatestLocalEpisodeNumber = 0; + this.DateTimeUpdated = DateTime.Now; + this.DateTimeCreated = DateTime.Now; + } + + public void CreateAnimeEpisodes() + { + AniDB_Anime anime = Anime; + if (anime == null) return; + + foreach (AniDB_Episode ep in anime.AniDBEpisodes) + { + ep.CreateAnimeEpisode(this.AnimeSeriesID); + } + } + + /// + /// Gets the direct parent AnimeGroup this series belongs to + /// + public AnimeGroup AnimeGroup + { + get + { + AnimeGroupRepository repGroups = new AnimeGroupRepository(); + return repGroups.GetByID(this.AnimeGroupID); + } + } + + /// + /// Gets the very top level AnimeGroup which this series belongs to + /// + public AnimeGroup TopLevelAnimeGroup + { + get + { + AnimeGroupRepository repGroups = new AnimeGroupRepository(); + AnimeGroup parentGroup = repGroups.GetByID(this.AnimeGroupID); + + while (parentGroup.AnimeGroupParentID.HasValue) + { + parentGroup = repGroups.GetByID(parentGroup.AnimeGroupParentID.Value); + } + return parentGroup; + } + } + + public List AllGroupsAbove + { + get + { + List grps = new List(); + try + { + AnimeGroupRepository repGroups = new AnimeGroupRepository(); + AnimeSeriesRepository repSeries = new AnimeSeriesRepository(); + + int? groupID = AnimeGroupID; + while (groupID.HasValue) + { + AnimeGroup grp = repGroups.GetByID(groupID.Value); + if (grp != null) + { + grps.Add(grp); + groupID = grp.AnimeGroupParentID; + } + else + { + groupID = null; + } + } + + return grps; + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + } + return grps; + } + } + + public Contract_AnimeSeries ToContract(AnimeSeries_User userRecord) + { + AniDB_Anime anime = this.Anime; + CrossRef_AniDB_TvDB tvDBCrossRef = this.CrossRefTvDB; + CrossRef_AniDB_Other movieDBCrossRef = this.CrossRefMovieDB; + + return this.ToContract(anime, tvDBCrossRef, movieDBCrossRef, userRecord); + } + + public Contract_AnimeSeries ToContract(AniDB_Anime animeRec, CrossRef_AniDB_TvDB tvDBCrossRef, CrossRef_AniDB_Other movieDBCrossRef, AnimeSeries_User userRecord) + { + Contract_AnimeSeries contract = new Contract_AnimeSeries(); + + contract.AniDB_ID = this.AniDB_ID; + contract.AnimeGroupID = this.AnimeGroupID; + contract.AnimeSeriesID = this.AnimeSeriesID; + contract.DateTimeUpdated = this.DateTimeUpdated; + contract.DateTimeCreated = this.DateTimeCreated; + contract.DefaultAudioLanguage = this.DefaultAudioLanguage; + contract.DefaultSubtitleLanguage = this.DefaultSubtitleLanguage; + contract.LatestLocalEpisodeNumber = this.LatestLocalEpisodeNumber; + contract.EpisodeAddedDate = this.EpisodeAddedDate; + contract.MissingEpisodeCount = this.MissingEpisodeCount; + contract.MissingEpisodeCountGroups = this.MissingEpisodeCountGroups; + + if (userRecord == null) + { + contract.PlayedCount = 0; + contract.StoppedCount = 0; + contract.UnwatchedEpisodeCount = 0; + contract.WatchedCount = 0; + contract.WatchedDate = null; + contract.WatchedEpisodeCount = 0; + } + else + { + contract.PlayedCount = userRecord.PlayedCount; + contract.StoppedCount = userRecord.StoppedCount; + contract.UnwatchedEpisodeCount = userRecord.UnwatchedEpisodeCount; + contract.WatchedCount = userRecord.WatchedCount; + contract.WatchedDate = userRecord.WatchedDate; + contract.WatchedEpisodeCount = userRecord.WatchedEpisodeCount; + } + + // get AniDB data + contract.AniDBAnime = null; + if (animeRec != null) + { + Contract_AniDBAnime animecontract = animeRec.ToContract(); + + AniDB_Anime_DefaultImage defaultPoster = animeRec.DefaultPoster; + if (defaultPoster == null) + animecontract.DefaultImagePoster = null; + else + animecontract.DefaultImagePoster = defaultPoster.ToContract(); + + AniDB_Anime_DefaultImage defaultFanart = animeRec.DefaultFanart; + if (defaultFanart == null) + animecontract.DefaultImageFanart = null; + else + animecontract.DefaultImageFanart = defaultFanart.ToContract(); + + AniDB_Anime_DefaultImage defaultWideBanner = animeRec.DefaultWideBanner; + if (defaultWideBanner == null) + animecontract.DefaultImageWideBanner = null; + else + animecontract.DefaultImageWideBanner = defaultWideBanner.ToContract(); + + contract.AniDBAnime = animecontract; + } + + contract.CrossRefAniDBTvDB = null; + if (tvDBCrossRef != null) + contract.CrossRefAniDBTvDB = tvDBCrossRef.ToContract(); + + contract.CrossRefAniDBMovieDB = null; + if (movieDBCrossRef != null) + contract.CrossRefAniDBMovieDB = movieDBCrossRef.ToContract(); + + return contract; + } + + public override string ToString() + { + return string.Format("Series: {0} ({1})", Anime.MainTitle, AnimeSeriesID); + //return ""; + } + + public void UpdateStats(bool watchedStats, bool missingEpsStats, bool updateAllGroupsAbove) + { + + DateTime start = DateTime.Now; + + AnimeSeries_UserRepository repSeriesUser = new AnimeSeries_UserRepository(); + + JMMUserRepository repUsers = new JMMUserRepository(); + List allUsers = repUsers.GetAll(); + + if (watchedStats) + { + foreach (JMMUser juser in allUsers) + { + //this.WatchedCount = 0; + AnimeSeries_User userRecord = GetUserRecord(juser.JMMUserID); + if (userRecord == null) userRecord = new AnimeSeries_User(juser.JMMUserID, this.AnimeSeriesID); + + // reset stats + userRecord.UnwatchedEpisodeCount = 0; + userRecord.WatchedEpisodeCount = 0; + userRecord.WatchedDate = null; + + foreach (AnimeEpisode ep in AnimeEpisodes) + { + // if the episode doesn't have any files then it won't count towards watched/unwatched counts + if (ep.VideoLocals.Count == 0) continue; + + if (ep.EpisodeTypeEnum == AniDBAPI.enEpisodeType.Episode || ep.EpisodeTypeEnum == AniDBAPI.enEpisodeType.Special) + { + AnimeEpisode_User epUserRecord = ep.GetUserRecord(juser.JMMUserID); + + if (epUserRecord != null) userRecord.WatchedEpisodeCount++; + else userRecord.UnwatchedEpisodeCount++; + + if (epUserRecord != null) + { + if (userRecord.WatchedDate.HasValue) + { + if (epUserRecord.WatchedDate > userRecord.WatchedDate) + userRecord.WatchedDate = epUserRecord.WatchedDate; + } + else + userRecord.WatchedDate = epUserRecord.WatchedDate; + } + } + } + repSeriesUser.Save(userRecord); + + } + } + + if (missingEpsStats) + { + MissingEpisodeCount = 0; + MissingEpisodeCountGroups = 0; + + // get all the group status records + AniDB_GroupStatusRepository repGrpStat = new AniDB_GroupStatusRepository(); + List grpStatuses = repGrpStat.GetByAnimeID(this.AniDB_ID); + List eps = AnimeEpisodes; + + // find all the episodes for which the user has a file + // from this we can determine what their latest episode number is + // find out which groups the user is collecting + + List userReleaseGroups = new List(); + foreach (AnimeEpisode ep in eps) + { + List vids = ep.VideoLocals; + foreach (VideoLocal vid in vids) + { + AniDB_File anifile = vid.AniDBFile; + if (anifile != null) + { + if (!userReleaseGroups.Contains(anifile.GroupID)) userReleaseGroups.Add(anifile.GroupID); + } + } + } + + int latestLocalEpNumber = 0; + foreach (AnimeEpisode ep in eps) + { + List vids = ep.VideoLocals; + if (ep.EpisodeTypeEnum != AniDBAPI.enEpisodeType.Episode) continue; + + AniDB_Episode aniEp = ep.AniDB_Episode; + int thisEpNum = aniEp.EpisodeNumber; + + if (thisEpNum > latestLocalEpNumber && vids.Count > 0) + latestLocalEpNumber = thisEpNum; + + // does this episode have a file released + // does this episode have a file released by the group the user is collecting + bool epReleased = false; + bool epReleasedGroup = false; + foreach (AniDB_GroupStatus gs in grpStatuses) + { + if (gs.LastEpisodeNumber >= thisEpNum) epReleased = true; + if (userReleaseGroups.Contains(gs.GroupID) && gs.HasGroupReleasedEpisode(thisEpNum)) epReleasedGroup = true; + } + + if (epReleased && vids.Count == 0) + MissingEpisodeCount++; + if (epReleasedGroup && vids.Count == 0) + MissingEpisodeCountGroups++; + } + this.LatestLocalEpisodeNumber = latestLocalEpNumber; + } + + AnimeSeriesRepository rep = new AnimeSeriesRepository(); + rep.Save(this); + + if (updateAllGroupsAbove) + { + foreach (AnimeGroup grp in AllGroupsAbove) + { + grp.UpdateStats(watchedStats, missingEpsStats); + } + } + TimeSpan ts = DateTime.Now - start; + logger.Trace("Updated stats for SERIES {0} in {1}ms", this.ToString(), ts.TotalMilliseconds); + } + + } +} diff --git a/JMMServer/Entities/AnimeSeries_User.cs b/JMMServer/Entities/AnimeSeries_User.cs new file mode 100644 index 000000000..49d4ce8c4 --- /dev/null +++ b/JMMServer/Entities/AnimeSeries_User.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace JMMServer.Entities +{ + public class AnimeSeries_User + { + public int AnimeSeries_UserID { get; private set; } + public int JMMUserID { get; set; } + public int AnimeSeriesID { get; set; } + + public int UnwatchedEpisodeCount { get; set; } + public int WatchedEpisodeCount { get; set; } + public DateTime? WatchedDate { get; set; } + public int PlayedCount { get; set; } + public int WatchedCount { get; set; } + public int StoppedCount { get; set; } + + public AnimeSeries_User() + { + } + + public AnimeSeries_User(int userID, int seriesID) + { + JMMUserID = userID; + AnimeSeriesID = seriesID; + + UnwatchedEpisodeCount = 0; + WatchedEpisodeCount = 0; + WatchedDate = null; + PlayedCount = 0; + WatchedCount = 0; + StoppedCount = 0; + } + } +} diff --git a/JMMServer/Entities/CommandRequest.cs b/JMMServer/Entities/CommandRequest.cs new file mode 100644 index 000000000..3c155c453 --- /dev/null +++ b/JMMServer/Entities/CommandRequest.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace JMMServer.Entities +{ + public class CommandRequest + { + public int CommandRequestID { get; private set; } + public int Priority { get; set; } + public int CommandType { get; set; } + public string CommandID { get; set; } + public string CommandDetails { get; set; } + public DateTime DateTimeUpdated { get; set; } + + + } +} diff --git a/JMMServer/Entities/CrossRef_AniDB_Other.cs b/JMMServer/Entities/CrossRef_AniDB_Other.cs new file mode 100644 index 000000000..6a792340e --- /dev/null +++ b/JMMServer/Entities/CrossRef_AniDB_Other.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMContracts; + +namespace JMMServer.Entities +{ + public class CrossRef_AniDB_Other + { + public int CrossRef_AniDB_OtherID { get; private set; } + public int AnimeID { get; set; } + public string CrossRefID { get; set; } + public int CrossRefSource { get; set; } + public int CrossRefType { get; set; } + + public Contract_CrossRef_AniDB_Other ToContract() + { + Contract_CrossRef_AniDB_Other contract = new Contract_CrossRef_AniDB_Other(); + contract.AnimeID = this.AnimeID; + contract.CrossRefID = this.CrossRefID; + contract.CrossRefSource = this.CrossRefSource; + contract.CrossRefType = this.CrossRefType; + return contract; + } + } +} diff --git a/JMMServer/Entities/CrossRef_AniDB_Trakt.cs b/JMMServer/Entities/CrossRef_AniDB_Trakt.cs new file mode 100644 index 000000000..c18f56d55 --- /dev/null +++ b/JMMServer/Entities/CrossRef_AniDB_Trakt.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Xml; +using NLog; +using System.IO; +using JMMServer.ImageDownload; +using JMMContracts; + +namespace JMMServer.Entities +{ + public class CrossRef_AniDB_Trakt + { + public int CrossRef_AniDB_TraktID { get; private set; } + public int AnimeID { get; set; } + public string TraktID { get; set; } + public int TraktSeasonNumber { get; set; } + public int CrossRefSource { get; set; } + + public Contract_CrossRef_AniDB_Trakt ToContract() + { + Contract_CrossRef_AniDB_Trakt contract = new Contract_CrossRef_AniDB_Trakt(); + + contract.CrossRef_AniDB_TraktID = CrossRef_AniDB_TraktID; + contract.AnimeID = AnimeID; + contract.TraktID = TraktID; + contract.TraktSeasonNumber = TraktSeasonNumber; + contract.CrossRefSource = CrossRefSource; + + return contract; + } + } +} diff --git a/JMMServer/Entities/CrossRef_AniDB_TvDB.cs b/JMMServer/Entities/CrossRef_AniDB_TvDB.cs new file mode 100644 index 000000000..70590ae0c --- /dev/null +++ b/JMMServer/Entities/CrossRef_AniDB_TvDB.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMContracts; + +namespace JMMServer.Entities +{ + public class CrossRef_AniDB_TvDB + { + public int CrossRef_AniDB_TvDBID { get; private set; } + public int AnimeID { get; set; } + public int TvDBID { get; set; } + public int TvDBSeasonNumber { get; set; } + public int CrossRefSource { get; set; } + + public Contract_CrossRef_AniDB_TvDB ToContract() + { + Contract_CrossRef_AniDB_TvDB contract = new Contract_CrossRef_AniDB_TvDB(); + contract.AnimeID = this.AnimeID; + contract.TvDBID = this.TvDBID; + contract.CrossRef_AniDB_TvDBID = this.CrossRef_AniDB_TvDBID; + contract.TvDBSeasonNumber = this.TvDBSeasonNumber; + contract.CrossRefSource = this.CrossRefSource; + return contract; + } + } +} diff --git a/JMMServer/Entities/CrossRef_File_Episode.cs b/JMMServer/Entities/CrossRef_File_Episode.cs new file mode 100644 index 000000000..ed7ad981e --- /dev/null +++ b/JMMServer/Entities/CrossRef_File_Episode.cs @@ -0,0 +1,56 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.IO; +using System.Xml.Serialization; +using JMMServer.Repositories; + +namespace JMMServer.Entities +{ + /// + /// Stores a reference between the AniDB_File record and an AniDB_Episode + /// We store the Hash and the FileSize, because this is what enables us to make a call the AniDB UDP API using the FILE command + /// We store the AnimeID so we can download all the episodes from HTTP API (ie the HTTP api call will return the + /// anime details and all the episodes + /// Note 1 - A file can have one to many episodes, and an episode can have one to many files + /// Note 2 - By storing this information when a user manually associates a file with an episode, we can recover the manual + /// associations even when they move the files around + /// Note 3 - We can use a combination of the FileName/FileSize to determine the Hash for a file, this enables us to handle the + /// moving of files to different locations without needing to re-hash the file again + /// + public class CrossRef_File_Episode + { + public int CrossRef_File_EpisodeID { get; private set; } + public string Hash { get; set; } + public string FileName { get; set; } + public long FileSize { get; set; } + public int CrossRefSource { get; set; } + public int AnimeID { get; set; } + public int EpisodeID { get; set; } + public int Percentage { get; set; } + public int EpisodeOrder { get; set; } + + public void PopulateManually(VideoLocal vid, AnimeEpisode ep) + { + Hash = vid.ED2KHash; + FileName = Path.GetFileName(vid.FullServerPath); + FileSize = vid.FileSize; + CrossRefSource = (int)JMMServer.CrossRefSource.User; + AnimeID = ep.AnimeSeries.AniDB_ID; + EpisodeID = ep.AniDB_EpisodeID; + Percentage = 100; + EpisodeOrder = 1; + } + + [XmlIgnore] + public AniDB_Episode Episode + { + get + { + AniDB_EpisodeRepository repEps = new AniDB_EpisodeRepository(); + return repEps.GetByEpisodeID(EpisodeID); + } + } + } +} diff --git a/JMMServer/Entities/CrossRef_Languages_AniDB_File.cs b/JMMServer/Entities/CrossRef_Languages_AniDB_File.cs new file mode 100644 index 000000000..922e503c7 --- /dev/null +++ b/JMMServer/Entities/CrossRef_Languages_AniDB_File.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace JMMServer.Entities +{ + public class CrossRef_Languages_AniDB_File + { + public int CrossRef_Languages_AniDB_FileID { get; private set; } + public int FileID { get; set; } + public int LanguageID { get; set; } + } +} diff --git a/JMMServer/Entities/CrossRef_Subtitles_AniDB_File.cs b/JMMServer/Entities/CrossRef_Subtitles_AniDB_File.cs new file mode 100644 index 000000000..4d915a488 --- /dev/null +++ b/JMMServer/Entities/CrossRef_Subtitles_AniDB_File.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace JMMServer.Entities +{ + public class CrossRef_Subtitles_AniDB_File + { + public int CrossRef_Subtitles_AniDB_FileID { get; private set; } + public int FileID { get; set; } + public int LanguageID { get; set; } + } +} diff --git a/JMMServer/Entities/DuplicateFile.cs b/JMMServer/Entities/DuplicateFile.cs new file mode 100644 index 000000000..fa52f6181 --- /dev/null +++ b/JMMServer/Entities/DuplicateFile.cs @@ -0,0 +1,107 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Repositories; +using System.IO; +using JMMContracts; + +namespace JMMServer.Entities +{ + public class DuplicateFile + { + public int DuplicateFileID { get; private set; } + public string FilePathFile1 { get; set; } + public string FilePathFile2 { get; set; } + public string Hash { get; set; } + public int ImportFolderIDFile1 { get; set; } + public int ImportFolderIDFile2 { get; set; } + public DateTime DateTimeUpdated { get; set; } + + public override string ToString() + { + return string.Format("{0} --- {1}", FilePathFile1, FilePathFile2); + } + + public ImportFolder ImportFolder1 + { + get + { + ImportFolderRepository repNS = new ImportFolderRepository(); + return repNS.GetByID(ImportFolderIDFile1); + } + } + + public string FullServerPath1 + { + get + { + return string.Format(Path.Combine(ImportFolder1.ImportFolderLocation, FilePathFile1)); + } + } + + public ImportFolder ImportFolder2 + { + get + { + ImportFolderRepository repNS = new ImportFolderRepository(); + return repNS.GetByID(ImportFolderIDFile2); + } + } + + public string FullServerPath2 + { + get + { + return string.Format(Path.Combine(ImportFolder2.ImportFolderLocation, FilePathFile2)); + } + } + + public AniDB_File AniDBFile + { + get + { + AniDB_FileRepository repAniFile = new AniDB_FileRepository(); + return repAniFile.GetByHash(Hash); + } + } + + public Contract_DuplicateFile ToContract() + { + Contract_DuplicateFile contract = new Contract_DuplicateFile(); + contract.DateTimeUpdated = this.DateTimeUpdated; + contract.DuplicateFileID = this.DuplicateFileID; + contract.FilePathFile1 = this.FilePathFile1; + contract.FilePathFile2 = this.FilePathFile2; + contract.Hash = this.Hash; + contract.ImportFolderIDFile1 = this.ImportFolderIDFile1; + contract.ImportFolderIDFile2 = this.ImportFolderIDFile2; + + if (this.ImportFolder1 != null) + contract.ImportFolder1 = this.ImportFolder1.ToContract(); + else contract.ImportFolder1 = null; + + if (this.ImportFolder2 != null) + contract.ImportFolder2 = this.ImportFolder2.ToContract(); + else contract.ImportFolder2 = null; + + if (AniDBFile != null) + { + List eps = AniDBFile.Episodes; + if (eps.Count > 0) + { + contract.EpisodeNumber = eps[0].EpisodeNumber; + contract.EpisodeType = eps[0].EpisodeType; + contract.EpisodeName = eps[0].RomajiName; + contract.AnimeID = eps[0].AnimeID; + AniDB_AnimeRepository repAnime = new AniDB_AnimeRepository(); + AniDB_Anime anime = repAnime.GetByAnimeID(eps[0].AnimeID); + if (anime != null) + contract.AnimeName = anime.MainTitle; + } + } + + return contract; + } + } +} diff --git a/JMMServer/Entities/FileNameHash.cs b/JMMServer/Entities/FileNameHash.cs new file mode 100644 index 000000000..44cd459ab --- /dev/null +++ b/JMMServer/Entities/FileNameHash.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace JMMServer.Entities +{ + public class FileNameHash + { + public int FileNameHashID { get; private set; } + public string FileName { get; set; } + public long FileSize { get; set; } + public string Hash { get; set; } + public DateTime DateTimeUpdated { get; set; } + + public void Populate(CrossRef_File_Episode cfe) + { + this.FileName = cfe.FileName; + this.FileSize = cfe.FileSize; + this.Hash = cfe.Hash; + DateTimeUpdated = DateTime.Now; + } + } +} diff --git a/JMMServer/Entities/GroupFilter.cs b/JMMServer/Entities/GroupFilter.cs new file mode 100644 index 000000000..a001b8967 --- /dev/null +++ b/JMMServer/Entities/GroupFilter.cs @@ -0,0 +1,72 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMContracts; +using JMMServer.Repositories; + +namespace JMMServer.Entities +{ + public class GroupFilter + { + public int GroupFilterID { get; private set; } + public string GroupFilterName { get; set; } + public int ApplyToSeries { get; set; } + public int BaseCondition { get; set; } + public string SortingCriteria { get; set; } + + public override string ToString() + { + return string.Format("{0} - {1}", GroupFilterID, GroupFilterName); + } + + public List FilterConditions + { + get + { + GroupFilterConditionRepository repConds = new GroupFilterConditionRepository(); + return repConds.GetByGroupFilterID(this.GroupFilterID); + } + } + + public Contract_GroupFilter ToContract() + { + Contract_GroupFilter contract = new Contract_GroupFilter(); + contract.GroupFilterID = this.GroupFilterID; + contract.GroupFilterName = this.GroupFilterName; + contract.ApplyToSeries = this.ApplyToSeries; + contract.BaseCondition = this.BaseCondition; + contract.SortingCriteria = this.SortingCriteria; + + contract.FilterConditions = new List(); + foreach (GroupFilterCondition gfc in FilterConditions) + contract.FilterConditions.Add(gfc.ToContract()); + + return contract; + } + + public Contract_GroupFilterExtended ToContractExtended(JMMUser user) + { + Contract_GroupFilterExtended contract = new Contract_GroupFilterExtended(); + contract.GroupFilter = this.ToContract(); + contract.GroupCount = 0; + contract.SeriesCount = 0; + + // find all the groups for thise group filter + AnimeGroupRepository repGroups = new AnimeGroupRepository(); + List allGrps = repGroups.GetAll(); + //TimeSpan ts = DateTime.Now - start; + //logger.Info("GetAllGroups (Database) in {0} ms", ts.TotalMilliseconds); + //start = DateTime.Now; + + foreach (AnimeGroup grp in allGrps) + { + // calculate stats + if (StatsCache.Instance.EvaluateGroupFilter(this, grp, user, grp.GetUserRecord(user.JMMUserID))) + contract.GroupCount++; + } + + return contract; + } + } +} diff --git a/JMMServer/Entities/GroupFilterCondition.cs b/JMMServer/Entities/GroupFilterCondition.cs new file mode 100644 index 000000000..788d1bf19 --- /dev/null +++ b/JMMServer/Entities/GroupFilterCondition.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMContracts; + +namespace JMMServer.Entities +{ + public class GroupFilterCondition + { + public int GroupFilterConditionID { get; private set; } + public int GroupFilterID { get; set; } + public int ConditionType { get; set; } + public int ConditionOperator { get; set; } + public string ConditionParameter { get; set; } + + public override string ToString() + { + return string.Format("{0} - {1} - {2} - {3}", GroupFilterConditionID, ConditionType, ConditionOperator, ConditionParameter); + } + + public GroupFilterConditionType ConditionTypeEnum + { + get { return (GroupFilterConditionType)ConditionType; } + } + + public GroupFilterOperator ConditionOperatorEnum + { + get { return (GroupFilterOperator)ConditionOperator; } + } + + public Contract_GroupFilterCondition ToContract() + { + Contract_GroupFilterCondition contract = new Contract_GroupFilterCondition(); + contract.GroupFilterConditionID = this.GroupFilterConditionID; + contract.GroupFilterID = this.GroupFilterID; + contract.ConditionType = this.ConditionType; + contract.ConditionOperator = this.ConditionOperator; + contract.ConditionParameter = this.ConditionParameter; + return contract; + } + } +} diff --git a/JMMServer/Entities/ImportFolder.cs b/JMMServer/Entities/ImportFolder.cs new file mode 100644 index 000000000..ba61d30a1 --- /dev/null +++ b/JMMServer/Entities/ImportFolder.cs @@ -0,0 +1,51 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMContracts; + +namespace JMMServer.Entities +{ + public class ImportFolder + { + public int ImportFolderID { get; private set; } + public int ImportFolderType { get; set; } + public string ImportFolderName { get; set; } + public string ImportFolderLocation { get; set; } + public int IsDropSource { get; set; } + public int IsDropDestination { get; set; } + + public bool FolderIsDropSource + { + get + { + return IsDropSource == 1; + } + } + + public bool FolderIsDropDestination + { + get + { + return IsDropDestination == 1; + } + } + + public override string ToString() + { + return string.Format("{0} - {1} ({2})", ImportFolderName, ImportFolderLocation, ImportFolderID); + } + + public Contract_ImportFolder ToContract() + { + Contract_ImportFolder contract = new Contract_ImportFolder(); + contract.ImportFolderID = this.ImportFolderID; + contract.ImportFolderType = this.ImportFolderType; + contract.ImportFolderLocation = this.ImportFolderLocation; + contract.ImportFolderName = this.ImportFolderName; + contract.IsDropSource = this.IsDropSource; + contract.IsDropDestination = this.IsDropDestination; + return contract; + } + } +} diff --git a/JMMServer/Entities/JMMUser.cs b/JMMServer/Entities/JMMUser.cs new file mode 100644 index 000000000..3a0547a4e --- /dev/null +++ b/JMMServer/Entities/JMMUser.cs @@ -0,0 +1,98 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMContracts; + +namespace JMMServer.Entities +{ + public class JMMUser + { + public int JMMUserID { get; private set; } + public string Username { get; set; } + public string Password { get; set; } + public int IsAdmin { get; set; } + public int IsAniDBUser { get; set; } + public int IsTraktUser { get; set; } + public string HideCategories { get; set; } + + public Contract_JMMUser ToContract() + { + Contract_JMMUser contract = new Contract_JMMUser(); + + contract.JMMUserID = this.JMMUserID; + contract.Username = this.Username; + contract.Password = this.Password; + contract.IsAdmin = this.IsAdmin; + contract.IsAniDBUser = this.IsAniDBUser; + contract.IsTraktUser = this.IsTraktUser; + contract.HideCategories = this.HideCategories; + + return contract; + } + + /// + /// Returns whether a user is allowed to view this series + /// + /// + /// + public bool AllowedSeries(AnimeSeries ser) + { + if (string.IsNullOrEmpty(HideCategories)) return true; + + string[] cats = HideCategories.ToLower().Split(','); + string[] animeCats = ser.Anime.AllCategories.ToLower().Split('|'); + foreach (string cat in cats) + { + if (!string.IsNullOrEmpty(cat) && animeCats.Contains(cat)) + { + return false; + } + } + + return true; + } + + /// + /// Returns whether a user is allowed to view this anime + /// + /// + /// + public bool AllowedAnime(AniDB_Anime anime) + { + if (string.IsNullOrEmpty(HideCategories)) return true; + + string[] cats = HideCategories.ToLower().Split(','); + string[] animeCats = anime.AllCategories.ToLower().Split('|'); + foreach (string cat in cats) + { + if (!string.IsNullOrEmpty(cat) && animeCats.Contains(cat)) + { + return false; + } + } + + return true; + } + + public bool AllowedGroup(AnimeGroup grp, AnimeGroup_User userRec) + { + if (grp.AnimeGroupID == 266) + Console.Write(""); + + if (string.IsNullOrEmpty(HideCategories)) return true; + + string[] cats = HideCategories.ToLower().Split(','); + string[] animeCats = grp.ToContract(userRec).Stat_AllCategories.ToLower().Split('|'); + foreach (string cat in cats) + { + if (!string.IsNullOrEmpty(cat) && animeCats.Contains(cat)) + { + return false; + } + } + + return true; + } + } +} diff --git a/JMMServer/Entities/Language.cs b/JMMServer/Entities/Language.cs new file mode 100644 index 000000000..66a3a04d7 --- /dev/null +++ b/JMMServer/Entities/Language.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace JMMServer.Entities +{ + public class Language + { + public int LanguageID { get; private set; } + public string LanguageName { get; set; } + } +} diff --git a/JMMServer/Entities/MovieDB_Fanart.cs b/JMMServer/Entities/MovieDB_Fanart.cs new file mode 100644 index 000000000..69a3ff163 --- /dev/null +++ b/JMMServer/Entities/MovieDB_Fanart.cs @@ -0,0 +1,68 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using NLog; +using JMMServer.Providers.MovieDB; +using System.IO; +using JMMServer.ImageDownload; +using JMMContracts; + +namespace JMMServer.Entities +{ + public class MovieDB_Fanart + { + private static Logger logger = LogManager.GetCurrentClassLogger(); + + public int MovieDB_FanartID { get; private set; } + public string ImageID { get; set; } + public int MovieId { get; set; } + public string ImageType { get; set; } + public string ImageSize { get; set; } + public string URL { get; set; } + public int ImageWidth { get; set; } + public int ImageHeight { get; set; } + public int Enabled { get; set; } + + public string FullImagePath + { + get + { + if (string.IsNullOrEmpty(URL)) return ""; + + //strip out the base URL + int pos = URL.IndexOf('/', 10); + string fname = URL.Substring(pos + 1, URL.Length - pos - 1); + fname = fname.Replace("/", @"\"); + return Path.Combine(ImageUtils.GetMovieDBImagePath(), fname); + } + } + + public void Populate(MovieDB_Image_Result searchResult, int movieID) + { + this.MovieId = movieID; + this.ImageID = searchResult.ImageID; + this.ImageType = searchResult.ImageType; + this.ImageSize = searchResult.ImageSize; + this.URL = searchResult.URL; + this.ImageWidth = searchResult.ImageWidth; + this.ImageHeight = searchResult.ImageHeight; + this.Enabled = 1; + } + + public Contract_MovieDB_Fanart ToContract() + { + Contract_MovieDB_Fanart contract = new Contract_MovieDB_Fanart(); + contract.MovieDB_FanartID = this.MovieDB_FanartID; + contract.ImageID = this.ImageID; + contract.MovieId = this.MovieId; + contract.ImageType = this.ImageType; + contract.ImageSize = this.ImageSize; + contract.URL = this.URL; + contract.ImageWidth = this.ImageWidth; + contract.ImageHeight = this.ImageHeight; + contract.Enabled = this.Enabled; + return contract; + } + } +} diff --git a/JMMServer/Entities/MovieDB_Movie.cs b/JMMServer/Entities/MovieDB_Movie.cs new file mode 100644 index 000000000..483c0dede --- /dev/null +++ b/JMMServer/Entities/MovieDB_Movie.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using NLog; +using JMMServer.Providers.MovieDB; +using JMMContracts; + +namespace JMMServer.Entities +{ + public class MovieDB_Movie + { + private static Logger logger = LogManager.GetCurrentClassLogger(); + + public int MovieDB_MovieID { get; private set; } + public int MovieId { get; set; } + public string MovieName { get; set; } + public string OriginalName { get; set; } + public string Overview { get; set; } + + public void Populate(MovieDB_Movie_Result searchResult) + { + this.MovieId = searchResult.MovieID; + this.MovieName = searchResult.MovieName; + this.OriginalName = searchResult.OriginalName; + this.Overview = searchResult.Overview; + } + + public Contract_MovieDB_Movie ToContract() + { + Contract_MovieDB_Movie contract = new Contract_MovieDB_Movie(); + contract.MovieId = this.MovieId; + contract.MovieName = this.MovieName; + contract.OriginalName = this.OriginalName; + contract.Overview = this.Overview; + contract.MovieDB_MovieID = this.MovieDB_MovieID; + return contract; + } + + } +} diff --git a/JMMServer/Entities/MovieDB_Poster.cs b/JMMServer/Entities/MovieDB_Poster.cs new file mode 100644 index 000000000..83468af4c --- /dev/null +++ b/JMMServer/Entities/MovieDB_Poster.cs @@ -0,0 +1,70 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using NLog; +using JMMServer.Providers.MovieDB; +using JMMServer.ImageDownload; +using System.IO; +using JMMContracts; + +namespace JMMServer.Entities +{ + public class MovieDB_Poster + { + private static Logger logger = LogManager.GetCurrentClassLogger(); + + public int MovieDB_PosterID { get; private set; } + public string ImageID { get; set; } + public int MovieId { get; set; } + public string ImageType { get; set; } + public string ImageSize { get; set; } + public string URL { get; set; } + public int ImageWidth { get; set; } + public int ImageHeight { get; set; } + public int Enabled { get; set; } + + + public string FullImagePath + { + get + { + if (string.IsNullOrEmpty(URL)) return ""; + + //strip out the base URL + int pos = URL.IndexOf('/', 10); + string fname = URL.Substring(pos + 1, URL.Length - pos - 1); + fname = fname.Replace("/", @"\"); + return Path.Combine(ImageUtils.GetMovieDBImagePath(), fname); + } + } + + public void Populate(MovieDB_Image_Result searchResult, int movieID) + { + this.MovieId = movieID; + this.ImageID = searchResult.ImageID; + this.ImageType = searchResult.ImageType; + this.ImageSize = searchResult.ImageSize; + this.URL = searchResult.URL; + this.ImageWidth = searchResult.ImageWidth; + this.ImageHeight = searchResult.ImageHeight; + this.Enabled = 1; + } + + public Contract_MovieDB_Poster ToContract() + { + Contract_MovieDB_Poster contract = new Contract_MovieDB_Poster(); + contract.MovieDB_PosterID = this.MovieDB_PosterID; + contract.ImageID = this.ImageID; + contract.MovieId = this.MovieId; + contract.ImageType = this.ImageType; + contract.ImageSize = this.ImageSize; + contract.URL = this.URL; + contract.ImageWidth = this.ImageWidth; + contract.ImageHeight = this.ImageHeight; + contract.Enabled = this.Enabled; + return contract; + } + } +} + diff --git a/JMMServer/Entities/ScheduledUpdate.cs b/JMMServer/Entities/ScheduledUpdate.cs new file mode 100644 index 000000000..18eea8f19 --- /dev/null +++ b/JMMServer/Entities/ScheduledUpdate.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace JMMServer.Entities +{ + public class ScheduledUpdate + { + public int ScheduledUpdateID { get; private set; } + public int UpdateType { get; set; } + public DateTime LastUpdate { get; set; } + public string UpdateDetails { get; set; } + } +} diff --git a/JMMServer/Entities/Trakt_Episode.cs b/JMMServer/Entities/Trakt_Episode.cs new file mode 100644 index 000000000..e7a1e800a --- /dev/null +++ b/JMMServer/Entities/Trakt_Episode.cs @@ -0,0 +1,79 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Xml; +using NLog; +using System.IO; +using JMMServer.ImageDownload; +using JMMContracts; + +namespace JMMServer.Entities +{ + public class Trakt_Episode + { + private static Logger logger = LogManager.GetCurrentClassLogger(); + + public int Trakt_EpisodeID { get; private set; } + public int Trakt_ShowID { get; set; } + public int Season { get; set; } + public int EpisodeNumber { get; set; } + public string Title { get; set; } + public string URL { get; set; } + public string Overview { get; set; } + public string EpisodeImage { get; set; } + + public string FullImagePath + { + get + { + // typical EpisodeImage url + // http://vicmackey.trakt.tv/images/episodes/3228-1-1.jpg + + // get the TraktID from the URL + // http://trakt.tv/show/11eyes/season/1/episode/1 (11 eyes) + + if (string.IsNullOrEmpty(EpisodeImage)) return ""; + if (string.IsNullOrEmpty(URL)) return ""; + + // on Trakt, if the episode doesn't have a proper screenshot, they will return the + // fanart instead, we will ignore this + int pos = EpisodeImage.IndexOf(@"episodes/"); + if (pos <= 0) return ""; + + int posID = URL.IndexOf(@"show/"); + if (posID <= 0) return ""; + + int posIDNext = URL.IndexOf(@"/", posID + 6); + if (posIDNext <= 0) return ""; + + string traktID = URL.Substring(posID + 5, posIDNext - posID - 5); + traktID = traktID.Replace("/", @"\"); + + string imageName = EpisodeImage.Substring(pos + 9, EpisodeImage.Length - pos - 9); + imageName = imageName.Replace("/", @"\"); + + string relativePath = Path.Combine("episodes", traktID); + relativePath = Path.Combine(relativePath, imageName); + + return Path.Combine(ImageUtils.GetTraktImagePath(), relativePath); + } + } + + public Contract_Trakt_Episode ToContract() + { + Contract_Trakt_Episode contract = new Contract_Trakt_Episode(); + + contract.Trakt_EpisodeID = Trakt_EpisodeID; + contract.Trakt_ShowID = Trakt_ShowID; + contract.Season = Season; + contract.EpisodeNumber = EpisodeNumber; + contract.Title = Title; + contract.URL = URL; + contract.Overview = Overview; + contract.EpisodeImage = EpisodeImage; + + return contract; + } + } +} diff --git a/JMMServer/Entities/Trakt_ImageFanart.cs b/JMMServer/Entities/Trakt_ImageFanart.cs new file mode 100644 index 000000000..26a35ea71 --- /dev/null +++ b/JMMServer/Entities/Trakt_ImageFanart.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Xml; +using NLog; +using System.IO; +using JMMServer.ImageDownload; +using JMMContracts; + +namespace JMMServer.Entities +{ + public class Trakt_ImageFanart + { + private static Logger logger = LogManager.GetCurrentClassLogger(); + + public int Trakt_ImageFanartID { get; private set; } + public int Trakt_ShowID { get; set; } + public int Season { get; set; } + public string ImageURL { get; set; } + public int Enabled { get; set; } + + public string FullImagePath + { + get + { + // typical url + // http://vicmackey.trakt.tv/images/fanart/3228.jpg + + if (string.IsNullOrEmpty(ImageURL)) return ""; + + int pos = ImageURL.IndexOf(@"images/"); + if (pos <= 0) return ""; + + string relativePath = ImageURL.Substring(pos + 7, ImageURL.Length - pos - 7); + relativePath = relativePath.Replace("/", @"\"); + + return Path.Combine(ImageUtils.GetTraktImagePath(), relativePath); + } + } + + public Contract_Trakt_ImageFanart ToContract() + { + Contract_Trakt_ImageFanart contract = new Contract_Trakt_ImageFanart(); + contract.Trakt_ImageFanartID = this.Trakt_ImageFanartID; + contract.Trakt_ShowID = this.Trakt_ShowID; + contract.Season = this.Season; + contract.ImageURL = this.ImageURL; + contract.Enabled = this.Enabled; + + return contract; + } + } +} diff --git a/JMMServer/Entities/Trakt_ImagePoster.cs b/JMMServer/Entities/Trakt_ImagePoster.cs new file mode 100644 index 000000000..0b4e56d1c --- /dev/null +++ b/JMMServer/Entities/Trakt_ImagePoster.cs @@ -0,0 +1,55 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Xml; +using NLog; +using System.IO; +using JMMServer.ImageDownload; +using JMMContracts; + +namespace JMMServer.Entities +{ + public class Trakt_ImagePoster + { + private static Logger logger = LogManager.GetCurrentClassLogger(); + + public int Trakt_ImagePosterID { get; private set; } + public int Trakt_ShowID { get; set; } + public int Season { get; set; } + public string ImageURL { get; set; } + public int Enabled { get; set; } + + public string FullImagePath + { + get + { + // typical url + // http://vicmackey.trakt.tv/images/seasons/3228-1.jpg + // http://vicmackey.trakt.tv/images/posters/1130.jpg + + if (string.IsNullOrEmpty(ImageURL)) return ""; + + int pos = ImageURL.IndexOf(@"images/"); + if (pos <= 0) return ""; + + string relativePath = ImageURL.Substring(pos + 7, ImageURL.Length - pos - 7); + relativePath = relativePath.Replace("/", @"\"); + + return Path.Combine(ImageUtils.GetTraktImagePath(), relativePath); + } + } + + public Contract_Trakt_ImagePoster ToContract() + { + Contract_Trakt_ImagePoster contract = new Contract_Trakt_ImagePoster(); + contract.Trakt_ImagePosterID = this.Trakt_ImagePosterID; + contract.Trakt_ShowID = this.Trakt_ShowID; + contract.Season = this.Season; + contract.ImageURL = this.ImageURL; + contract.Enabled = this.Enabled; + + return contract; + } + } +} diff --git a/JMMServer/Entities/Trakt_Season.cs b/JMMServer/Entities/Trakt_Season.cs new file mode 100644 index 000000000..276d52b98 --- /dev/null +++ b/JMMServer/Entities/Trakt_Season.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Xml; +using NLog; +using System.IO; +using JMMServer.ImageDownload; +using JMMContracts; +using JMMServer.Repositories; + +namespace JMMServer.Entities +{ + public class Trakt_Season + { + public int Trakt_SeasonID { get; private set; } + public int Trakt_ShowID { get; set; } + public int Season { get; set; } + public string URL { get; set; } + + public List Episodes + { + get + { + Trakt_EpisodeRepository repEps = new Trakt_EpisodeRepository(); + return repEps.GetByShowIDAndSeason(Trakt_ShowID, Season); + } + } + + public Contract_Trakt_Season ToContract() + { + Contract_Trakt_Season contract = new Contract_Trakt_Season(); + + contract.Trakt_SeasonID = Trakt_SeasonID; + contract.Trakt_ShowID = Trakt_ShowID; + contract.Season = Season; + contract.URL = URL; + contract.Episodes = new List(); + + foreach (Trakt_Episode ep in Episodes) + contract.Episodes.Add(ep.ToContract()); + + return contract; + } + } +} diff --git a/JMMServer/Entities/Trakt_Show.cs b/JMMServer/Entities/Trakt_Show.cs new file mode 100644 index 000000000..9fdd91220 --- /dev/null +++ b/JMMServer/Entities/Trakt_Show.cs @@ -0,0 +1,52 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Xml; +using NLog; +using System.IO; +using JMMServer.ImageDownload; +using JMMContracts; +using JMMServer.Repositories; + +namespace JMMServer.Entities +{ + public class Trakt_Show + { + public int Trakt_ShowID { get; private set; } + public string TraktID { get; set; } + public string Title { get; set; } + public string Year { get; set; } + public string URL { get; set; } + public string Overview { get; set; } + public int? TvDB_ID { get; set; } + + public List Seasons + { + get + { + Trakt_SeasonRepository repSeasons = new Trakt_SeasonRepository(); + return repSeasons.GetByShowID(Trakt_ShowID); + } + } + + public Contract_Trakt_Show ToContract() + { + Contract_Trakt_Show contract = new Contract_Trakt_Show(); + + contract.Trakt_ShowID = Trakt_ShowID; + contract.TraktID = TraktID; + contract.Title = Title; + contract.Year = Year; + contract.URL = URL; + contract.Overview = Overview; + contract.TvDB_ID = TvDB_ID; + contract.Seasons = new List(); + + foreach (Trakt_Season season in Seasons) + contract.Seasons.Add(season.ToContract()); + + return contract; + } + } +} diff --git a/JMMServer/Entities/TvDB_Episode.cs b/JMMServer/Entities/TvDB_Episode.cs new file mode 100644 index 000000000..2f5fc0b7e --- /dev/null +++ b/JMMServer/Entities/TvDB_Episode.cs @@ -0,0 +1,186 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Xml; +using NLog; +using System.IO; +using JMMServer.ImageDownload; +using JMMContracts; + +namespace JMMServer.Entities +{ + public class TvDB_Episode + { + private static Logger logger = LogManager.GetCurrentClassLogger(); + + public int TvDB_EpisodeID { get; private set; } + public int Id { get; set; } + public int SeriesID { get; set; } + public int SeasonID { get; set; } + public int SeasonNumber { get; set; } + public int EpisodeNumber { get; set; } + public string EpisodeName { get; set; } + public string Overview { get; set; } + public string Filename { get; set; } + public int EpImgFlag { get; set; } + public int? AbsoluteNumber { get; set; } + public int? AirsAfterSeason { get; set; } + public int? AirsBeforeEpisode { get; set; } + public int? AirsBeforeSeason { get; set; } + + public string FullImagePath + { + get + { + if (string.IsNullOrEmpty(Filename)) return ""; + + string fname = Filename; + fname = Filename.Replace("/", @"\"); + return Path.Combine(ImageUtils.GetTvDBImagePath(), fname); + } + } + + public TvDB_Episode() + { + } + + public void Populate(XmlDocument doc) + { + // used when getting information from episode info + // http://thetvdb.com/api/B178B8940CAF4A2C/episodes/306542/en.xml + + this.Id = int.Parse(TryGetProperty(doc, "id")); + this.SeriesID = int.Parse(TryGetProperty(doc, "seriesid")); + this.SeasonID = int.Parse(TryGetProperty(doc, "seasonid")); + this.SeasonNumber = int.Parse(TryGetProperty(doc, "SeasonNumber")); + this.EpisodeNumber = int.Parse(TryGetProperty(doc, "EpisodeNumber")); + + int flag = 0; + if (int.TryParse(TryGetProperty(doc, "EpImgFlag"), out flag)) + this.EpImgFlag = flag; + + int abnum = 0; + if (int.TryParse(TryGetProperty(doc, "absolute_number"), out abnum)) + this.AbsoluteNumber = abnum; + + this.EpisodeName = TryGetProperty(doc, "EpisodeName"); + this.Overview = TryGetProperty(doc, "Overview"); + this.Filename = TryGetProperty(doc, "filename"); + //this.FirstAired = TryGetProperty(doc, "FirstAired"); + + int aas = 0; + if (int.TryParse(TryGetProperty(doc, "airsafter_season"), out aas)) + this.AirsAfterSeason = aas; + else + this.AirsAfterSeason = null; + + int abe = 0; + if (int.TryParse(TryGetProperty(doc, "airsbefore_episode"), out abe)) + this.AirsBeforeEpisode = abe; + else + this.AirsBeforeEpisode = null; + + int abs = 0; + if (int.TryParse(TryGetProperty(doc, "airsbefore_season"), out abs)) + this.AirsBeforeSeason = abs; + else + this.AirsBeforeSeason = null; + } + + public void Populate(XmlNode node) + { + // used when getting information from full series info + // http://thetvdb.com/api/B178B8940CAF4A2C/series/84187/all/en.xml + + this.Id = int.Parse(TryGetProperty(node, "id")); + this.SeriesID = int.Parse(TryGetProperty(node, "seriesid")); + this.SeasonID = int.Parse(TryGetProperty(node, "seasonid")); + this.SeasonNumber = int.Parse(TryGetProperty(node, "SeasonNumber")); + this.EpisodeNumber = int.Parse(TryGetProperty(node, "EpisodeNumber")); + + int flag = 0; + if (int.TryParse(TryGetProperty(node, "EpImgFlag"), out flag)) + this.EpImgFlag = flag; + + int abnum = 0; + if (int.TryParse(TryGetProperty(node, "absolute_number"), out abnum)) + this.AbsoluteNumber = abnum; + + this.EpisodeName = TryGetProperty(node, "EpisodeName"); + this.Overview = TryGetProperty(node, "Overview"); + this.Filename = TryGetProperty(node, "filename"); + //this.FirstAired = TryGetProperty(node, "FirstAired"); + + int aas = 0; + if (int.TryParse(TryGetProperty(node, "airsafter_season"), out aas)) + this.AirsAfterSeason = aas; + else + this.AirsAfterSeason = null; + + int abe = 0; + if (int.TryParse(TryGetProperty(node, "airsbefore_episode"), out abe)) + this.AirsBeforeEpisode = abe; + else + this.AirsBeforeEpisode = null; + + int abs = 0; + if (int.TryParse(TryGetProperty(node, "airsbefore_season"), out abs)) + this.AirsBeforeSeason = abs; + else + this.AirsBeforeSeason = null; + } + + protected string TryGetProperty(XmlNode node, string propertyName) + { + try + { + string prop = node[propertyName].InnerText.Trim(); + return prop; + } + catch (Exception ex) + { + //logger.ErrorException("Error in TvDB_Episode.TryGetProperty: " + ex.ToString(), ex); + } + + return ""; + } + + protected string TryGetProperty(XmlDocument doc, string propertyName) + { + try + { + string prop = doc["Data"]["Episode"][propertyName].InnerText.Trim(); + return prop; + } + catch (Exception ex) + { + //logger.ErrorException("Error in TvDB_Episode.TryGetProperty: " + ex.ToString(), ex); + } + + return ""; + } + + public Contract_TvDB_Episode ToContract() + { + Contract_TvDB_Episode contract = new Contract_TvDB_Episode(); + contract.AbsoluteNumber = this.AbsoluteNumber; + contract.EpImgFlag = this.EpImgFlag; + contract.EpisodeName = this.EpisodeName; + contract.EpisodeNumber = this.EpisodeNumber; + contract.Filename = this.Filename; + contract.Id = this.Id; + contract.Overview = this.Overview; + contract.SeasonID = this.SeasonID; + contract.SeasonNumber = this.SeasonNumber; + contract.SeriesID = this.SeriesID; + contract.TvDB_EpisodeID = this.TvDB_EpisodeID; + + contract.AirsAfterSeason = this.AirsAfterSeason; + contract.AirsBeforeEpisode = this.AirsBeforeEpisode; + contract.AirsBeforeSeason = this.AirsBeforeSeason; + + return contract; + } + } +} diff --git a/JMMServer/Entities/TvDB_ImageFanart.cs b/JMMServer/Entities/TvDB_ImageFanart.cs new file mode 100644 index 000000000..db0839b4e --- /dev/null +++ b/JMMServer/Entities/TvDB_ImageFanart.cs @@ -0,0 +1,94 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.IO; +using JMMServer.ImageDownload; +using System.Xml; +using NLog; +using JMMContracts; + +namespace JMMServer.Entities +{ + public class TvDB_ImageFanart + { + private static Logger logger = LogManager.GetCurrentClassLogger(); + + public int TvDB_ImageFanartID { get; private set; } + public int Id { get; set; } + public int SeriesID { get; set; } + public string BannerPath { get; set; } + public string BannerType { get; set; } + public string BannerType2 { get; set; } + public string Colors { get; set; } + public string Language { get; set; } + public string ThumbnailPath { get; set; } + public string VignettePath { get; set; } + public int Enabled { get; set; } + public int Chosen { get; set; } + + public Contract_TvDB_ImageFanart ToContract() + { + Contract_TvDB_ImageFanart contract = new Contract_TvDB_ImageFanart(); + contract.TvDB_ImageFanartID = this.TvDB_ImageFanartID; + contract.Id = this.Id; + contract.SeriesID = this.SeriesID; + contract.BannerPath = this.BannerPath; + contract.BannerType = this.BannerType; + contract.BannerType2 = this.BannerType2; + contract.Colors = this.Colors; + contract.Language = this.Language; + contract.ThumbnailPath = this.ThumbnailPath; + contract.VignettePath = this.VignettePath; + contract.Enabled = this.Enabled; + contract.Chosen = this.Chosen; + + return contract; + } + + public string FullImagePath + { + get + { + if (string.IsNullOrEmpty(BannerPath)) return ""; + + string fname = BannerPath; + fname = BannerPath.Replace("/", @"\"); + return Path.Combine(ImageUtils.GetTvDBImagePath(), fname); + } + } + + public string FullThumbnailPath + { + get + { + string fname = ThumbnailPath; + fname = ThumbnailPath.Replace("/", @"\"); + return Path.Combine(ImageUtils.GetTvDBImagePath(), fname); + } + } + + public bool Populate(int seriesID, XmlNode node) + { + try + { + this.SeriesID = seriesID; + Id = int.Parse(node["id"].InnerText); + BannerPath = node["BannerPath"].InnerText; + BannerType = node["BannerType"].InnerText; + BannerType2 = node["BannerType2"].InnerText; + Colors = node["Colors"].InnerText; + Language = node["Language"].InnerText; + ThumbnailPath = node["ThumbnailPath"].InnerText; + VignettePath = node["VignettePath"].InnerText; + return true; + + } + catch (Exception ex) + { + logger.ErrorException("Error in TvDB_ImageFanart.Init: " + ex.ToString(), ex); + return false; + } + } + } +} diff --git a/JMMServer/Entities/TvDB_ImagePoster.cs b/JMMServer/Entities/TvDB_ImagePoster.cs new file mode 100644 index 000000000..2189d43cd --- /dev/null +++ b/JMMServer/Entities/TvDB_ImagePoster.cs @@ -0,0 +1,84 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.IO; +using JMMServer.ImageDownload; +using System.Xml; +using NLog; +using JMMContracts; + +namespace JMMServer.Entities +{ + public class TvDB_ImagePoster + { + private static Logger logger = LogManager.GetCurrentClassLogger(); + + public int TvDB_ImagePosterID { get; private set; } + public int Id { get; set; } + public int SeriesID { get; set; } + public string BannerPath { get; set; } + public string BannerType { get; set; } + public string BannerType2 { get; set; } + public string Language { get; set; } + public int Enabled { get; set; } + public int? SeasonNumber { get; set; } + + public Contract_TvDB_ImagePoster ToContract() + { + Contract_TvDB_ImagePoster contract = new Contract_TvDB_ImagePoster(); + contract.TvDB_ImagePosterID = this.TvDB_ImagePosterID; + contract.Id = this.Id; + contract.SeriesID = this.SeriesID; + contract.BannerPath = this.BannerPath; + contract.BannerType = this.BannerType; + contract.BannerType2 = this.BannerType2; + contract.Language = this.Language; + contract.Enabled = this.Enabled; + contract.SeasonNumber = this.SeasonNumber; + + return contract; + } + + public string FullImagePath + { + get + { + if (string.IsNullOrEmpty(BannerPath)) return ""; + + string fname = BannerPath; + fname = BannerPath.Replace("/", @"\"); + return Path.Combine(ImageUtils.GetTvDBImagePath(), fname); + } + } + + public bool Populate(int seriesID, XmlNode node, TvDBImageNodeType nodeType) + { + try + { + this.SeriesID = seriesID; + + if (nodeType == TvDBImageNodeType.Series) + SeasonNumber = null; + else + SeasonNumber = int.Parse(node["Season"].InnerText); + + + Id = int.Parse(node["id"].InnerText); + BannerPath = node["BannerPath"].InnerText; + BannerType = node["BannerType"].InnerText; + BannerType2 = node["BannerType2"].InnerText; + Language = node["Language"].InnerText; + + + return true; + + } + catch (Exception ex) + { + logger.ErrorException("Error in TvDB_ImagePoster.Populate: " + ex.ToString(), ex); + return false; + } + } + } +} diff --git a/JMMServer/Entities/TvDB_ImageWideBanner.cs b/JMMServer/Entities/TvDB_ImageWideBanner.cs new file mode 100644 index 000000000..34d3ca68e --- /dev/null +++ b/JMMServer/Entities/TvDB_ImageWideBanner.cs @@ -0,0 +1,83 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.IO; +using JMMServer.ImageDownload; +using System.Xml; +using NLog; +using JMMContracts; + +namespace JMMServer.Entities +{ + public class TvDB_ImageWideBanner + { + private static Logger logger = LogManager.GetCurrentClassLogger(); + + public int TvDB_ImageWideBannerID { get; private set; } + public int Id { get; set; } + public int SeriesID { get; set; } + public string BannerPath { get; set; } + public string BannerType { get; set; } + public string BannerType2 { get; set; } + public string Language { get; set; } + public int Enabled { get; set; } + public int? SeasonNumber { get; set; } + + public Contract_TvDB_ImageWideBanner ToContract() + { + Contract_TvDB_ImageWideBanner contract = new Contract_TvDB_ImageWideBanner(); + contract.TvDB_ImageWideBannerID = this.TvDB_ImageWideBannerID; + contract.Id = this.Id; + contract.SeriesID = this.SeriesID; + contract.BannerPath = this.BannerPath; + contract.BannerType = this.BannerType; + contract.BannerType2 = this.BannerType2; + contract.Language = this.Language; + contract.Enabled = this.Enabled; + contract.SeasonNumber = this.SeasonNumber; + + return contract; + } + + public string FullImagePath + { + get + { + if (string.IsNullOrEmpty(BannerPath)) return ""; + + string fname = BannerPath; + fname = BannerPath.Replace("/", @"\"); + return Path.Combine(ImageUtils.GetTvDBImagePath(), fname); + } + } + + public bool Populate(int seriesID, XmlNode node, TvDBImageNodeType nodeType) + { + try + { + this.SeriesID = seriesID; + + if (nodeType == TvDBImageNodeType.Series) + SeasonNumber = null; + else + SeasonNumber = int.Parse(node["Season"].InnerText); + + Id = int.Parse(node["id"].InnerText); + BannerPath = node["BannerPath"].InnerText; + BannerType = node["BannerType"].InnerText; + BannerType2 = node["BannerType2"].InnerText; + Language = node["Language"].InnerText; + + return true; + + } + catch (Exception ex) + { + logger.ErrorException("Error in TvDB_ImageWideBanner.Populate: " + ex.ToString(), ex); + return false; + } + } + + } +} diff --git a/JMMServer/Entities/TvDB_Series.cs b/JMMServer/Entities/TvDB_Series.cs new file mode 100644 index 000000000..8b2ee2e43 --- /dev/null +++ b/JMMServer/Entities/TvDB_Series.cs @@ -0,0 +1,89 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using NLog; +using System.Xml; +using JMMContracts; + +namespace JMMServer.Entities +{ + public class TvDB_Series + { + private static Logger logger = LogManager.GetCurrentClassLogger(); + + public int TvDB_SeriesID { get; private set; } + public int SeriesID { get; set; } + public string Overview { get; set; } + public string SeriesName { get; set; } + public string Status { get; set; } + public string Banner { get; set; } + public string Fanart { get; set; } + public string Lastupdated { get; set; } + public string Poster { get; set; } + + public Contract_TvDB_Series ToContract() + { + Contract_TvDB_Series contract = new Contract_TvDB_Series(); + contract.TvDB_SeriesID = this.TvDB_SeriesID; + contract.SeriesID = this.SeriesID; + contract.Overview = this.Overview; + contract.SeriesName = this.SeriesName; + contract.Status = this.Status; + contract.Banner = this.Banner; + contract.Fanart = this.Fanart; + contract.Lastupdated = this.Lastupdated; + contract.Poster = this.Poster; + + return contract; + } + + public TvDB_Series() + { + SeriesID = 0; + Overview = string.Empty; + SeriesName = string.Empty; + Status = string.Empty; + Banner = string.Empty; + Fanart = string.Empty; + Lastupdated = string.Empty; + Poster = string.Empty; + } + + public void PopulateFromSearch(XmlDocument doc) + { + this.SeriesID = int.Parse(TryGetProperty(doc, "seriesid")); + this.SeriesName = TryGetProperty(doc, "SeriesName"); + this.Overview = TryGetProperty(doc, "Overview"); + this.Banner = TryGetProperty(doc, "banner"); + } + + public void PopulateFromSeriesInfo(XmlDocument doc) + { + this.SeriesID = int.Parse(TryGetProperty(doc, "id")); + this.SeriesName = TryGetProperty(doc, "SeriesName"); + this.Overview = TryGetProperty(doc, "Overview"); + this.Banner = TryGetProperty(doc, "banner"); + + this.Status = TryGetProperty(doc, "Status"); + this.Fanart = TryGetProperty(doc, "fanart"); + this.Lastupdated = TryGetProperty(doc, "lastupdated"); + this.Poster = TryGetProperty(doc, "poster"); + } + + protected string TryGetProperty(XmlDocument doc, string propertyName) + { + try + { + string prop = doc["Data"]["Series"][propertyName].InnerText.Trim(); + return prop; + } + catch (Exception ex) + { + logger.ErrorException("Erorr in TryGetProperty: " + ex.ToString(), ex); + } + + return ""; + } + } +} diff --git a/JMMServer/Entities/Versions.cs b/JMMServer/Entities/Versions.cs new file mode 100644 index 000000000..7fec0d904 --- /dev/null +++ b/JMMServer/Entities/Versions.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace JMMServer.Entities +{ + public class Versions + { + public int VersionsID { get; private set; } + public string VersionType { get; set; } + public string VersionValue { get; set; } + } +} diff --git a/JMMServer/Entities/VideoInfo.cs b/JMMServer/Entities/VideoInfo.cs new file mode 100644 index 000000000..4408da94f --- /dev/null +++ b/JMMServer/Entities/VideoInfo.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace JMMServer.Entities +{ + public class VideoInfo + { + public int VideoInfoID { get; private set; } + public string Hash { get; set; } + public long FileSize { get; set; } + public string FileName { get; set; } + public DateTime DateTimeUpdated { get; set; } + public string VideoCodec { get; set; } + public string VideoBitrate { get; set; } + public string VideoFrameRate { get; set; } + public string VideoResolution { get; set; } + public string AudioCodec { get; set; } + public string AudioBitrate { get; set; } + public long Duration { get; set; } + } +} diff --git a/JMMServer/Entities/VideoLocal.cs b/JMMServer/Entities/VideoLocal.cs new file mode 100644 index 000000000..319bb9248 --- /dev/null +++ b/JMMServer/Entities/VideoLocal.cs @@ -0,0 +1,583 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using AniDBAPI; +using JMMServer.Repositories; +using JMMContracts; +using System.IO; +using JMMServer.Commands; +using NLog; +using BinaryNorthwest; + +namespace JMMServer.Entities +{ + public class VideoLocal : IHash + { + private static Logger logger = LogManager.GetCurrentClassLogger(); + + public int VideoLocalID { get; private set; } + public string FilePath { get; set; } + public int ImportFolderID { get; set; } + public string Hash { get; set; } + public string CRC32 { get; set; } + public string MD5 { get; set; } + public string SHA1 { get; set; } + public int HashSource { get; set; } + public long FileSize { get; set; } + public int IsIgnored { get; set; } + public DateTime DateTimeUpdated { get; set; } + + public string ED2KHash + { + get { return Hash; } + set { Hash = value; } + } + + public string Info + { + get + { + if (string.IsNullOrEmpty(FilePath)) + return ""; + return FilePath; + } + } + + public ImportFolder ImportFolder + { + get + { + ImportFolderRepository repNS = new ImportFolderRepository(); + return repNS.GetByID(ImportFolderID); + } + } + + public string FullServerPath + { + get + { + return string.Format(Path.Combine(ImportFolder.ImportFolderLocation, FilePath)); + } + } + + public AniDB_File AniDBFile + { + get + { + AniDB_FileRepository repAniFile = new AniDB_FileRepository(); + return repAniFile.GetByHash(Hash); + } + } + + public VideoInfo VideoInfo + { + get + { + VideoInfoRepository repVI = new VideoInfoRepository(); + return repVI.GetByHash(Hash); + } + } + + public VideoLocal_User GetUserRecord(int userID) + { + VideoLocal_UserRepository repVidUser = new VideoLocal_UserRepository(); + return repVidUser.GetByUserIDAndVideoLocalID(userID, this.VideoLocalID); + } + + public AniDB_ReleaseGroup ReleaseGroup + { + get + { + AniDB_File anifile = AniDBFile; + if (anifile == null) return null; + + AniDB_ReleaseGroupRepository repRG = new AniDB_ReleaseGroupRepository(); + return repRG.GetByGroupID(anifile.GroupID); + } + } + + public List AnimeEpisodes + { + get + { + AnimeEpisodeRepository repEps = new AnimeEpisodeRepository(); + return repEps.GetByHash(Hash); + } + } + + public List EpisodeCrossRefs + { + get + { + if (Hash.Length == 0) return new List(); + + CrossRef_File_EpisodeRepository rep = new CrossRef_File_EpisodeRepository(); + return rep.GetByHash(Hash); + } + } + + private void SaveWatchedStatus(bool watched, int userID, DateTime? watchedDate) + { + VideoLocal_UserRepository repVidUsers = new VideoLocal_UserRepository(); + VideoLocal_User vidUserRecord = this.GetUserRecord(userID); + if (watched) + { + if (vidUserRecord == null) vidUserRecord = new VideoLocal_User(); + vidUserRecord.JMMUserID = userID; + vidUserRecord.VideoLocalID = this.VideoLocalID; + + if (watchedDate.HasValue) + vidUserRecord.WatchedDate = watchedDate.Value; + else + vidUserRecord.WatchedDate = DateTime.Now; + + repVidUsers.Save(vidUserRecord); + } + else + { + if (vidUserRecord != null) + repVidUsers.Delete(vidUserRecord.VideoLocal_UserID); + } + } + + public void ToggleWatchedStatus(bool watched, int userID) + { + ToggleWatchedStatus(watched, true, null, true, userID); + } + + public void ToggleWatchedStatus(bool watched, bool updateOnline, DateTime? watchedDate, bool updateStats, int userID) + { + 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 aniDBUsers = repUsers.GetAniDBUsers(); + + // update the video file to watched + int mywatched = watched ? 1 : 0; + + if (user.IsAniDBUser == 0) + SaveWatchedStatus(watched, userID, watchedDate); + 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); + } + } + + + // 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); + + if (updateOnline) + { + if ((watched && ServerSettings.AniDB_MyList_SetWatched) || + (!watched && ServerSettings.AniDB_MyList_SetUnwatched)) + { + CommandRequest_UpdateMyListFileStatus cmd = new CommandRequest_UpdateMyListFileStatus(this.Hash, watched); + 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 xrefs = repCross.GetByHash(this.Hash); + if (watched) + { + foreach (CrossRef_File_Episode xref in xrefs) + { + // if setting a file watched, only update the episode to watched when the + // the file is the last file for the episode + // handles an episode being split across multiple files + if (xref.Percentage == 100) + { + AnimeEpisode ep = repEpisodes.GetByAniDBEpisodeID(xref.EpisodeID); + + if (ep == null) continue; + if (ser == null) ser = ep.AnimeSeries; + + if (user.IsAniDBUser == 0) + ep.SaveWatchedStatus(true, userID, watchedDate); + 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); + } + } + + CommandRequest_TraktShowScrobble cmdScrobble = new CommandRequest_TraktShowScrobble(ep.AnimeEpisodeID); + cmdScrobble.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; + if (ser == null) ser = ep.AnimeSeries; + + bool anyFilesWatched = false; + foreach (VideoLocal thisvid in ep.VideoLocals) + { + VideoLocal_User vidUserRecordTemp = thisvid.GetUserRecord(userID); + if (vidUserRecordTemp != null) + { + anyFilesWatched = true; + break; + } + } + + if (!anyFilesWatched) + { + if (user.IsAniDBUser == 0) + ep.SaveWatchedStatus(false, userID, watchedDate); + 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); + } + } + + CommandRequest_TraktShowEpisodeUnseen cmdUnseen = new CommandRequest_TraktShowEpisodeUnseen(ep.AnimeEpisodeID); + cmdUnseen.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); + } + } + + public override string ToString() + { + return string.Format("{0} --- {1}", FullServerPath, Hash); + } + + public void MoveFileIfRequired() + { + // check if this file is in the drop folder + // otherwise we don't need to move it + if (this.ImportFolder.IsDropSource == 0) return; + + if (!File.Exists(this.FullServerPath)) return; + + // find the default destination + ImportFolder destFolder = null; + ImportFolderRepository repFolders = new ImportFolderRepository(); + foreach (ImportFolder fldr in repFolders.GetAll()) + { + if (fldr.IsDropDestination == 1) + { + destFolder = fldr; + break; + } + } + + if (destFolder == null) return; + + if (!Directory.Exists(destFolder.ImportFolderLocation)) return; + + // we can only move the file if it has an anime associated with it + List 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 allEps = series.AnimeEpisodes; + List sortCriteria = new List(); + sortCriteria.Add(new SortPropOrFieldAndDirection("AniDB_EpisodeID", true, SortType.eInteger)); + allEps = Sorting.MultiSort(allEps, sortCriteria); + + foreach (AnimeEpisode ep in allEps) + { + foreach (VideoLocal vid in ep.VideoLocals) + { + if (vid.VideoLocalID != this.VideoLocalID) + { + destFolder = vid.ImportFolder; + // make sure this folder is not the drop source + if (destFolder.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.Anime.MainTitle); + newFullPath = Path.Combine(destFolder.ImportFolderLocation, newFolderName); + if (!Directory.Exists(newFullPath)) + Directory.CreateDirectory(newFullPath); + } + + int newFolderID = 0; + string newPartialPath = ""; + string newFullServerPath = Path.Combine(newFullPath, Path.GetFileName(this.FullServerPath)); + + DataAccessHelper.GetShareAndPath(newFullServerPath, repFolders.GetAll(), ref newFolderID, ref newPartialPath); + + logger.Info("Moving file from {0} to {1}", this.FullServerPath, newFullServerPath); + + if (File.Exists(newFullServerPath)) + { + // if the file already exists, we can just delete the source file instead + // this is safer than deleting and moving + File.Delete(this.FullServerPath); + } + else + { + // now move the file + File.Move(this.FullServerPath, newFullServerPath); + } + + this.ImportFolderID = newFolderID; + this.FilePath = newPartialPath; + VideoLocalRepository repVids = new VideoLocalRepository(); + repVids.Save(this); + + } + + public Contract_VideoLocal ToContract(int userID) + { + Contract_VideoLocal contract = new Contract_VideoLocal(); + contract.CRC32 = this.CRC32; + contract.DateTimeUpdated = this.DateTimeUpdated; + contract.FilePath = this.FilePath; + contract.FileSize = this.FileSize; + contract.Hash = this.Hash; + contract.HashSource = this.HashSource; + contract.ImportFolder = this.ImportFolder.ToContract(); + contract.ImportFolderID = this.ImportFolderID; + contract.IsIgnored = this.IsIgnored; + contract.MD5 = this.MD5; + contract.SHA1 = this.SHA1; + contract.VideoLocalID = this.VideoLocalID; + + VideoLocal_User userRecord = this.GetUserRecord(userID); + if (userRecord == null) + { + contract.IsWatched = 0; + contract.WatchedDate = null; + } + else + { + contract.IsWatched = 1; + contract.WatchedDate = userRecord.WatchedDate; + } + + return contract; + } + + public Contract_VideoDetailed ToContractDetailed(int userID) + { + Contract_VideoDetailed contract = new Contract_VideoDetailed(); + + // get the cross ref episode + List xrefs = this.EpisodeCrossRefs; + if (xrefs.Count == 0) return null; + + contract.Percentage = xrefs[0].Percentage; + contract.EpisodeOrder = xrefs[0].EpisodeOrder; + contract.CrossRefSource = xrefs[0].CrossRefSource; + contract.AnimeEpisodeID = xrefs[0].EpisodeID; + + contract.VideoLocal_FilePath = this.FilePath; + contract.VideoLocal_Hash = this.Hash; + contract.VideoLocal_FileSize = this.FileSize; + contract.VideoLocalID = this.VideoLocalID; + contract.VideoLocal_IsIgnored = this.IsIgnored; + + VideoLocal_User userRecord = this.GetUserRecord(userID); + if (userRecord == null) + contract.VideoLocal_IsWatched = 0; + else + contract.VideoLocal_IsWatched = 1; + + // Import Folder + ImportFolder ns = this.ImportFolder; // to prevent multiple db calls + if (ns != null) + { + contract.ImportFolderID = ns.ImportFolderID; + contract.ImportFolderLocation = ns.ImportFolderLocation; + contract.ImportFolderName = ns.ImportFolderName; + } + + // video info + VideoInfo vi = this.VideoInfo; // to prevent multiple db calls + if (vi != null) + { + contract.VideoInfo_AudioBitrate = vi.AudioBitrate; + contract.VideoInfo_AudioCodec = vi.AudioCodec; + contract.VideoInfo_Duration = vi.Duration; + contract.VideoInfo_VideoBitrate = vi.VideoBitrate; + contract.VideoInfo_VideoCodec = vi.VideoCodec; + contract.VideoInfo_VideoFrameRate = vi.VideoFrameRate; + contract.VideoInfo_VideoResolution = vi.VideoResolution; + contract.VideoInfo_VideoInfoID = vi.VideoInfoID; + } + + // AniDB File + AniDB_File anifile = this.AniDBFile; // to prevent multiple db calls + if (anifile != null) + { + contract.AniDB_Anime_GroupName = anifile.Anime_GroupName; + contract.AniDB_Anime_GroupNameShort = anifile.Anime_GroupNameShort; + contract.AniDB_AnimeID = anifile.AnimeID; + contract.AniDB_CRC = anifile.CRC; + contract.AniDB_Episode_Rating = anifile.Episode_Rating; + contract.AniDB_Episode_Votes = anifile.Episode_Votes; + contract.AniDB_File_AudioCodec = anifile.File_AudioCodec; + contract.AniDB_File_Description = anifile.File_Description; + contract.AniDB_File_FileExtension = anifile.File_FileExtension; + contract.AniDB_File_LengthSeconds = anifile.File_LengthSeconds; + contract.AniDB_File_ReleaseDate = anifile.File_ReleaseDate; + contract.AniDB_File_Source = anifile.File_Source; + contract.AniDB_File_VideoCodec = anifile.File_VideoCodec; + contract.AniDB_File_VideoResolution = anifile.File_VideoResolution; + contract.AniDB_FileID = anifile.FileID; + contract.AniDB_GroupID = anifile.GroupID; + contract.AniDB_MD5 = anifile.MD5; + contract.AniDB_SHA1 = anifile.SHA1; + + // languages + contract.LanguagesAudio = anifile.LanguagesRAW; + contract.LanguagesSubtitle = anifile.SubtitlesRAW; + } + else + { + contract.AniDB_Anime_GroupName = ""; + contract.AniDB_Anime_GroupNameShort = ""; + contract.AniDB_CRC = ""; + contract.AniDB_File_AudioCodec = ""; + contract.AniDB_File_Description = ""; + contract.AniDB_File_FileExtension = ""; + contract.AniDB_File_Source = ""; + contract.AniDB_File_VideoCodec = ""; + contract.AniDB_File_VideoResolution = ""; + contract.AniDB_MD5 = ""; + contract.AniDB_SHA1 = ""; + + // languages + contract.LanguagesAudio = ""; + contract.LanguagesSubtitle = ""; + } + + + + + AniDB_ReleaseGroup relGroup = this.ReleaseGroup; // to prevent multiple db calls + if (relGroup != null) + contract.ReleaseGroup = relGroup.ToContract(); + else + contract.ReleaseGroup = null; + + return contract; + } + + public Contract_VideoLocalManualLink ToContractManualLink(int userID) + { + Contract_VideoLocalManualLink contract = new Contract_VideoLocalManualLink(); + contract.CRC32 = this.CRC32; + contract.DateTimeUpdated = this.DateTimeUpdated; + contract.FilePath = this.FilePath; + contract.FileSize = this.FileSize; + contract.Hash = this.Hash; + contract.HashSource = this.HashSource; + contract.ImportFolder = this.ImportFolder.ToContract(); + contract.ImportFolderID = this.ImportFolderID; + contract.IsIgnored = this.IsIgnored; + contract.MD5 = this.MD5; + contract.SHA1 = this.SHA1; + contract.VideoLocalID = this.VideoLocalID; + + VideoLocal_User userRecord = this.GetUserRecord(userID); + if (userRecord == null) + { + contract.IsWatched = 0; + contract.WatchedDate = null; + } + else + { + contract.IsWatched = 1; + contract.WatchedDate = userRecord.WatchedDate; + } + + return contract; + } + } +} diff --git a/JMMServer/Entities/VideoLocal_User.cs b/JMMServer/Entities/VideoLocal_User.cs new file mode 100644 index 000000000..47254f93e --- /dev/null +++ b/JMMServer/Entities/VideoLocal_User.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using AniDBAPI; +using JMMServer.Repositories; +using JMMContracts; +using System.IO; +using JMMServer.Commands; +using NLog; +using BinaryNorthwest; + +namespace JMMServer.Entities +{ + public class VideoLocal_User + { + private static Logger logger = LogManager.GetCurrentClassLogger(); + + public int VideoLocal_UserID { get; private set; } + public int JMMUserID { get; set; } + public int VideoLocalID { get; set; } + public DateTime WatchedDate { get; set; } + + } +} diff --git a/JMMServer/Enums.cs b/JMMServer/Enums.cs new file mode 100644 index 000000000..8f349d5c3 --- /dev/null +++ b/JMMServer/Enums.cs @@ -0,0 +1,283 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace JMMServer +{ + public enum CommandRequestType + { + ProcessFile = 1, + AniDB_GetAnimeHTTP = 2, + AniDB_GetAnimeUDP = 3, + AniDB_GetFileUDP = 4, + AniDB_AddFileUDP = 5, + AniDB_UpdateWatchedUDP = 6, + TvDBSearch = 7, + AniDB_GetCharsCreators = 8, + AniDB_GetCharacter = 9, + AniDB_GetCreator = 10, + HashFile = 11, + WebCache_SendFileHash = 12, + WebCache_SendAniDBFile = 13, + WebCache_SendXRefFileEpisode = 14, + WebCache_DeleteXRefFileEpisode = 15, + WebCache_DeleteXRefTvDB = 16, + WebCache_DeleteXRefAniDBTvDB = 17, + WebCache_SendXRefAniDBTvDB = 18, + AniDB_GetReviews = 20, + AniDB_GetReleaseGroupStatus = 21, + AniDB_GetUpdated = 22, + AniDB_SyncMyList = 23, + AniDB_GetReleaseGroup = 24, + AniDB_GetCalendar = 25, + AniDB_GetTitles = 26, + AniDB_SyncVotes = 27, + AniDB_VoteAnime = 28, + AniDB_VoteEpisode = 29, + TvDB_SeriesEpisodes = 30, + TvDB_DownloadImages = 31, + TvDB_SearchAnime = 32, + ImageDownload = 33, + AniDB_DeleteFileUDP = 34, + WebCache_SendXRefAniDBOther = 35, + WebCache_DeleteXRefAniDBOther = 36, + MovieDB_SearchAnime = 37, + Trakt_SearchAnime = 38, + WebCache_SendXRefAniDBTrakt = 39, + WebCache_DeleteXRefAniDBTrakt = 40, + Trakt_UpdateInfoImages = 41, + Trakt_ShowScrobble = 42, + Trakt_SyncCollection = 43, + Trakt_SyncCollectionSeries = 44, + Trakt_ShowEpisodeUnseen = 45, + Trakt_UpdateAllSeries = 46 + } + + public enum CommandRequestPriority + { + Priority1 = 1, + Priority2 = 2, + Priority3 = 3, + Priority4 = 4, + Priority5 = 5, + Priority6 = 6, + Priority7 = 7, + Priority8 = 8, + Priority9 = 9, + Priority10 = 10, + Default = 99 + } + + public enum HashSource + { + DirectHash = 1, // the file was hashed by the user + WebCacheFileName = 2 // the hash was retrieved from the web cache based on file name + } + + public enum CrossRefSource + { + AniDB = 1, + User = 2, + WebCache = 3 + } + + public enum RenamingType + { + Raw = 1, + MetaData = 2 + } + + public enum enFanartSize + { + All = 1, + HD = 2, + FullHD = 3 + } + + public enum RenamingLanguage + { + Romaji = 1, + English = 2 + } + + public enum Storage + { + Unknown = 1, + HDD = 2, + CD = 3 + } + + public enum AnimeTypes + { + Movie, + OVA, + TV_Series, + TV_Special, + Web, + Other + } + + public enum ImportFolderType + { + HDD = 1, // files stored on a "permanent" hard drive + DVD = 2 // files stored on a cd/dvd + } + + public enum ScheduledUpdateType + { + AniDBCalendar = 1, + TvDBInfo = 2, + AniDBUpdates = 3, + AniDBTitles = 4, + AniDBMyListSync = 5, + TraktSync = 6, + TraktUpdate = 7 + } + + public enum JMMImageType + { + AniDB_Cover = 1, + AniDB_Character = 2, + AniDB_Creator = 3, + TvDB_Banner = 4, + TvDB_Cover = 5, + TvDB_Episode = 6, + TvDB_FanArt = 7, + MovieDB_FanArt = 8, + MovieDB_Poster = 9, + Trakt_Poster = 10, + Trakt_Fanart = 11, + Trakt_Episode = 12 + } + + public enum ImageSizeType + { + Poster = 1, + Fanart = 2, + WideBanner = 3 + } + + public enum ImageDownloadEventType + { + Started = 1, + Complete = 2 + } + + public enum AniDBVoteType + { + Anime = 1, + AnimeTemp = 2, + Group = 3, + Episode = 4 + } + + public enum TvDBImageNodeType + { + Series = 1, + Season = 2 + } + + public enum CrossRefType + { + MovieDB = 1, + MyAnimeList = 2, + AnimePlanet = 3, + BakaBT = 4, + TraktTV = 5, + AnimeNano = 6, + CrunchRoll = 7, + Konachan = 8 + } + + public enum ScheduledUpdateFrequency + { + Never = 1, + HoursSix = 2, + HoursTwelve = 3, + Daily = 4 + } + + public enum GroupFilterConditionType + { + CompletedSeries = 1, + MissingEpisodes = 2, + HasUnwatchedEpisodes = 3, + AllEpisodesWatched = 4, + UserVoted = 5, + Category = 6, + AirDate = 7, + Studio = 8, + AssignedTvDBInfo = 9, + ReleaseGroup = 11, + AnimeType = 12, + VideoQuality = 13, + Favourite = 14, + AnimeGroup = 15, + AniDBRating = 16, + UserRating = 17, + SeriesCreatedDate = 18, + EpisodeAddedDate = 19, + EpisodeWatchedDate = 20, + FinishedAiring = 21, + MissingEpisodesCollecting = 22, + AudioLanguage = 23, + SubtitleLanguage = 24, + AssignedTvDBOrMovieDBInfo = 25, + AssignedMovieDBInfo = 26 + } + + public enum GroupFilterOperator + { + Include = 1, + Exclude = 2, + GreaterThan = 3, + LessThan = 4, + Equals = 5, + NotEquals = 6, + In = 7, + NotIn = 8, + LastXDays = 9, + InAllEpisodes = 10, + NotInAllEpisodes = 11 + } + + public enum GroupFilterSorting + { + SeriesAddedDate = 1, + EpisodeAddedDate = 2, + EpisodeAirDate = 3, + EpisodeWatchedDate = 4, + GroupName = 5, + Year = 6, + SeriesCount = 7, + UnwatchedEpisodeCount = 8, + MissingEpisodeCount = 9, + UserRating = 10, + AniDBRating = 11, + SortName = 12 + } + + public enum GroupFilterSortDirection + { + Asc = 1, + Desc = 2 + } + + public enum GroupFilterBaseCondition + { + Include = 1, + Exclude = 2 + } + + + public enum enAnimeType + { + Movie = 0, + OVA = 1, + TVSeries = 2, + TVSpecial = 3, + Web = 4, + Other = 5 + } +} diff --git a/JMMServer/ImageDownload/ImageDownloadRequest.cs b/JMMServer/ImageDownload/ImageDownloadRequest.cs new file mode 100644 index 000000000..bd5d6bdbb --- /dev/null +++ b/JMMServer/ImageDownload/ImageDownloadRequest.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace JMMServer.ImageDownload +{ + public class ImageDownloadRequest + { + public JMMImageType ImageType { get; set; } + public object ImageData { get; set; } + public bool ForceDownload { get; set; } + + public ImageDownloadRequest(JMMImageType imageType, object data, bool forceDownload) + { + this.ImageType = imageType; + this.ImageData = data; + this.ForceDownload = forceDownload; + } + } + + + + +} diff --git a/JMMServer/ImageDownload/ImageUtils.cs b/JMMServer/ImageDownload/ImageUtils.cs new file mode 100644 index 000000000..a1e09c1b0 --- /dev/null +++ b/JMMServer/ImageDownload/ImageUtils.cs @@ -0,0 +1,119 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.IO; + +namespace JMMServer.ImageDownload +{ + public class ImageUtils + { + public static string GetBaseImagesPath() + { + string appPath = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location); + string filePath = Path.Combine(appPath, "Images"); + + if (!Directory.Exists(filePath)) + Directory.CreateDirectory(filePath); + + return filePath; + } + + public static string GetBaseAniDBImagesPath() + { + string filePath = Path.Combine(GetBaseImagesPath(), "AniDB"); + + if (!Directory.Exists(filePath)) + Directory.CreateDirectory(filePath); + + return filePath; + } + + public static string GetBaseTvDBImagesPath() + { + string filePath = Path.Combine(GetBaseImagesPath(), "TvDB"); + + if (!Directory.Exists(filePath)) + Directory.CreateDirectory(filePath); + + return filePath; + } + + public static string GetBaseMovieDBImagesPath() + { + string filePath = Path.Combine(GetBaseImagesPath(), "MovieDB"); + + if (!Directory.Exists(filePath)) + Directory.CreateDirectory(filePath); + + return filePath; + } + + public static string GetBaseTraktImagesPath() + { + string filePath = Path.Combine(GetBaseImagesPath(), "Trakt"); + + if (!Directory.Exists(filePath)) + Directory.CreateDirectory(filePath); + + return filePath; + } + + public static string GetImagesTempFolder() + { + string filePath = Path.Combine(GetBaseImagesPath(), "_Temp_"); + + if (!Directory.Exists(filePath)) + Directory.CreateDirectory(filePath); + + return filePath; + } + + public static string GetAniDBImagePath(int animeID) + { + string subFolder = ""; + string sid = animeID.ToString(); + if (sid.Length == 1) + subFolder = sid; + else + subFolder = sid.Substring(0, 2); + + string filePath = Path.Combine(GetBaseAniDBImagesPath(), subFolder); + + if (!Directory.Exists(filePath)) + Directory.CreateDirectory(filePath); + + return filePath; + } + + public static string GetTvDBImagePath() + { + string filePath = GetBaseTvDBImagesPath(); + + if (!Directory.Exists(filePath)) + Directory.CreateDirectory(filePath); + + return filePath; + } + + public static string GetMovieDBImagePath() + { + string filePath = GetBaseMovieDBImagesPath(); + + if (!Directory.Exists(filePath)) + Directory.CreateDirectory(filePath); + + return filePath; + } + + public static string GetTraktImagePath() + { + string filePath = GetBaseTraktImagesPath(); + + if (!Directory.Exists(filePath)) + Directory.CreateDirectory(filePath); + + return filePath; + } + } +} diff --git a/JMMServer/Images/16_arrow45.png b/JMMServer/Images/16_arrow45.png new file mode 100644 index 000000000..39225a1d3 Binary files /dev/null and b/JMMServer/Images/16_arrow45.png differ diff --git a/JMMServer/Images/16_exclamation.png b/JMMServer/Images/16_exclamation.png new file mode 100644 index 000000000..c37bd062e Binary files /dev/null and b/JMMServer/Images/16_exclamation.png differ diff --git a/JMMServer/Images/16_server_connect.png b/JMMServer/Images/16_server_connect.png new file mode 100644 index 000000000..49b269145 Binary files /dev/null and b/JMMServer/Images/16_server_connect.png differ diff --git a/JMMServer/Images/16_server_hash.png b/JMMServer/Images/16_server_hash.png new file mode 100644 index 000000000..bf49fad9d Binary files /dev/null and b/JMMServer/Images/16_server_hash.png differ diff --git a/JMMServer/Images/32_WebDatabase.png b/JMMServer/Images/32_WebDatabase.png new file mode 100644 index 000000000..be185a0e8 Binary files /dev/null and b/JMMServer/Images/32_WebDatabase.png differ diff --git a/JMMServer/Images/32_add.png b/JMMServer/Images/32_add.png new file mode 100644 index 000000000..2ee4e1d40 Binary files /dev/null and b/JMMServer/Images/32_add.png differ diff --git a/JMMServer/Images/32_cancel.png b/JMMServer/Images/32_cancel.png new file mode 100644 index 000000000..60cc8d3c0 Binary files /dev/null and b/JMMServer/Images/32_cancel.png differ diff --git a/JMMServer/Images/32_delete.png b/JMMServer/Images/32_delete.png new file mode 100644 index 000000000..50b604fb9 Binary files /dev/null and b/JMMServer/Images/32_delete.png differ diff --git a/JMMServer/Images/32_down.png b/JMMServer/Images/32_down.png new file mode 100644 index 000000000..274234753 Binary files /dev/null and b/JMMServer/Images/32_down.png differ diff --git a/JMMServer/Images/32_folder.png b/JMMServer/Images/32_folder.png new file mode 100644 index 000000000..e12fd19cc Binary files /dev/null and b/JMMServer/Images/32_folder.png differ diff --git a/JMMServer/Images/32_folder_add.png b/JMMServer/Images/32_folder_add.png new file mode 100644 index 000000000..e7c58fad9 Binary files /dev/null and b/JMMServer/Images/32_folder_add.png differ diff --git a/JMMServer/Images/32_folder_down.png b/JMMServer/Images/32_folder_down.png new file mode 100644 index 000000000..5429bd9e3 Binary files /dev/null and b/JMMServer/Images/32_folder_down.png differ diff --git a/JMMServer/Images/32_folder_edit.png b/JMMServer/Images/32_folder_edit.png new file mode 100644 index 000000000..3799c1d41 Binary files /dev/null and b/JMMServer/Images/32_folder_edit.png differ diff --git a/JMMServer/Images/32_folder_up.png b/JMMServer/Images/32_folder_up.png new file mode 100644 index 000000000..51369b6ca Binary files /dev/null and b/JMMServer/Images/32_folder_up.png differ diff --git a/JMMServer/Images/32_help.png b/JMMServer/Images/32_help.png new file mode 100644 index 000000000..443f45124 Binary files /dev/null and b/JMMServer/Images/32_help.png differ diff --git a/JMMServer/Images/32_image.png b/JMMServer/Images/32_image.png new file mode 100644 index 000000000..0cc0b0e90 Binary files /dev/null and b/JMMServer/Images/32_image.png differ diff --git a/JMMServer/Images/32_import.png b/JMMServer/Images/32_import.png new file mode 100644 index 000000000..e367a9dd6 Binary files /dev/null and b/JMMServer/Images/32_import.png differ diff --git a/JMMServer/Images/32_info.png b/JMMServer/Images/32_info.png new file mode 100644 index 000000000..35e220236 Binary files /dev/null and b/JMMServer/Images/32_info.png differ diff --git a/JMMServer/Images/32_pause.png b/JMMServer/Images/32_pause.png new file mode 100644 index 000000000..a84353547 Binary files /dev/null and b/JMMServer/Images/32_pause.png differ diff --git a/JMMServer/Images/32_play.png b/JMMServer/Images/32_play.png new file mode 100644 index 000000000..bacb0632e Binary files /dev/null and b/JMMServer/Images/32_play.png differ diff --git a/JMMServer/Images/32_save.png b/JMMServer/Images/32_save.png new file mode 100644 index 000000000..963337b2d Binary files /dev/null and b/JMMServer/Images/32_save.png differ diff --git a/JMMServer/Images/32_settings.png b/JMMServer/Images/32_settings.png new file mode 100644 index 000000000..307e64198 Binary files /dev/null and b/JMMServer/Images/32_settings.png differ diff --git a/JMMServer/Images/32_settings2.png b/JMMServer/Images/32_settings2.png new file mode 100644 index 000000000..e9f49586f Binary files /dev/null and b/JMMServer/Images/32_settings2.png differ diff --git a/JMMServer/Images/32_sync.png b/JMMServer/Images/32_sync.png new file mode 100644 index 000000000..e0c61a875 Binary files /dev/null and b/JMMServer/Images/32_sync.png differ diff --git a/JMMServer/Images/db.ico b/JMMServer/Images/db.ico new file mode 100644 index 000000000..ed0a90d0f Binary files /dev/null and b/JMMServer/Images/db.ico differ diff --git a/JMMServer/Importer.cs b/JMMServer/Importer.cs new file mode 100644 index 000000000..1c611e0d2 --- /dev/null +++ b/JMMServer/Importer.cs @@ -0,0 +1,574 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Repositories; +using JMMServer.Entities; +using JMMServer.Commands; +using NLog; +using System.IO; +using JMMFileHelper; +using JMMServer.Providers.TvDB; +using JMMServer.Providers.MovieDB; +using JMMServer.Providers.TraktTV; + +namespace JMMServer +{ + public class Importer + { + private static Logger logger = LogManager.GetCurrentClassLogger(); + + public static void RunImport_IntegrityCheck() + { + VideoLocalRepository repVidLocals = new VideoLocalRepository(); + AniDB_FileRepository repAniFile = new AniDB_FileRepository(); + AniDB_EpisodeRepository repAniEps = new AniDB_EpisodeRepository(); + AniDB_AnimeRepository repAniAnime = new AniDB_AnimeRepository(); + + // files which have not been hashed yet + // or files which do not have a VideoInfo record + List filesToHash = repVidLocals.GetVideosWithoutHash(); + Dictionary dictFilesToHash = new Dictionary(); + foreach (VideoLocal vl in filesToHash) + { + dictFilesToHash[vl.VideoLocalID] = vl; + CommandRequest_HashFile cmd = new CommandRequest_HashFile(vl.FullServerPath, false); + cmd.Save(); + } + + List filesToRehash = repVidLocals.GetVideosWithoutVideoInfo(); + Dictionary dictFilesToRehash = new Dictionary(); + foreach (VideoLocal vl in filesToHash) + { + dictFilesToRehash[vl.VideoLocalID] = vl; + // don't use if it is in the previous list + if (!dictFilesToHash.ContainsKey(vl.VideoLocalID)) + { + CommandRequest_HashFile cmd = new CommandRequest_HashFile(vl.FullServerPath, false); + cmd.Save(); + } + } + + // files which have been hashed, but don't have an associated episode + List filesWithoutEpisode = repVidLocals.GetVideosWithoutEpisode(); + Dictionary dictFilesWithoutEpisode = new Dictionary(); + foreach (VideoLocal vl in filesWithoutEpisode) + dictFilesWithoutEpisode[vl.VideoLocalID] = vl; + + + // check that all the episode data is populated + List filesAll = repVidLocals.GetAll(); + Dictionary dictFilesAllExisting = new Dictionary(); + foreach (VideoLocal vl in filesAll) + { + dictFilesAllExisting[vl.FullServerPath] = vl; + // check if it has an episode + if (dictFilesWithoutEpisode.ContainsKey(vl.VideoLocalID)) + { + CommandRequest_ProcessFile cmd = new CommandRequest_ProcessFile(vl.VideoLocalID); + cmd.Save(); + continue; + } + + // if the file is not manually associated, then check for AniDB_File info + AniDB_File aniFile = repAniFile.GetByHash(vl.Hash); + foreach (CrossRef_File_Episode xref in vl.EpisodeCrossRefs) + { + if (xref.CrossRefSource != (int)CrossRefSource.AniDB) continue; + if (aniFile == null) + { + CommandRequest_ProcessFile cmd = new CommandRequest_ProcessFile(vl.VideoLocalID); + cmd.Save(); + continue; + } + } + + if (aniFile == null) continue; + + // the cross ref is created before the actually episode data is downloaded + // so lets check for that + bool missingEpisodes = false; + foreach (CrossRef_File_Episode xref in aniFile.EpisodeCrossRefs) + { + AniDB_Episode ep = repAniEps.GetByEpisodeID(xref.EpisodeID); + if (ep == null) missingEpisodes = true; + } + + if (missingEpisodes) + { + // this will then download the anime etc + CommandRequest_ProcessFile cmd = new CommandRequest_ProcessFile(vl.VideoLocalID); + cmd.Save(); + continue; + } + } + } + + public static void RunImport_ScanFolder(int importFolderID) + { + // get a complete list of files + List fileList = new List(); + ImportFolderRepository repFolders = new ImportFolderRepository(); + int filesFound = 0, videosFound = 0; + int i = 0; + + try + { + ImportFolder fldr = repFolders.GetByID(importFolderID); + if (fldr == null) return; + + logger.Debug("ImportFolder: {0} || {1}", fldr.ImportFolderName, fldr.ImportFolderLocation); + + if (Directory.Exists(fldr.ImportFolderLocation)) + fileList.AddRange(Directory.GetFiles(fldr.ImportFolderLocation, "*.*", SearchOption.AllDirectories)); + + // get a list of all files in the share + foreach (string fileName in fileList) + { + i++; + filesFound++; + logger.Info("Processing File {0}/{1} --- {2}", i, fileList.Count, fileName); + + if (!FileHashHelper.IsVideo(fileName)) continue; + + videosFound++; + + CommandRequest_HashFile cr_hashfile = new CommandRequest_HashFile(fileName, false); + cr_hashfile.Save(); + + } + logger.Debug("Found {0} files", filesFound); + logger.Debug("Found {0} videos", videosFound); + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + } + } + + public static void RunImport_NewFiles() + { + VideoLocalRepository repVidLocals = new VideoLocalRepository(); + + // first build a list of files that we already know about, as we don't want to process them again + List filesAll = repVidLocals.GetAll(); + Dictionary dictFilesExisting = new Dictionary(); + foreach (VideoLocal vl in filesAll) + { + dictFilesExisting[vl.FullServerPath] = vl; + } + + + // Steps for processing a file + // 1. Check if it is a video file + // 2. Check if we have a VideoLocal record for that file + // ......... + + // get a complete list of files + List fileList = new List(); + ImportFolderRepository repNetShares = new ImportFolderRepository(); + foreach (ImportFolder share in repNetShares.GetAll()) + { + logger.Debug("ImportFolder: {0} || {1}", share.ImportFolderName, share.ImportFolderLocation); + try + { + if (Directory.Exists(share.ImportFolderLocation)) + fileList.AddRange(Directory.GetFiles(share.ImportFolderLocation, "*.*", SearchOption.AllDirectories)); + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + } + } + + // get a list fo files that we haven't processed before + List fileListNew = new List(); + foreach (string fileName in fileList) + { + if (!dictFilesExisting.ContainsKey(fileName)) + fileListNew.Add(fileName); + } + + // get a list of all the shares we are looking at + int filesFound = 0, videosFound = 0; + int i = 0; + + // get a list of all files in the share + foreach (string fileName in fileListNew) + { + i++; + filesFound++; + logger.Info("Processing File {0}/{1} --- {2}", i, fileList.Count, fileName); + + if (!FileHashHelper.IsVideo(fileName)) continue; + + videosFound++; + + CommandRequest_HashFile cr_hashfile = new CommandRequest_HashFile(fileName, false); + cr_hashfile.Save(); + + } + logger.Debug("Found {0} files", filesFound); + logger.Debug("Found {0} videos", videosFound); + } + + public static void RunImport_GetImages() + { + // AniDB posters + AniDB_AnimeRepository repAnime = new AniDB_AnimeRepository(); + foreach (AniDB_Anime anime in repAnime.GetAll()) + { + if (anime.AnimeID == 8580) + Console.Write(""); + + if (string.IsNullOrEmpty(anime.PosterPath)) continue; + + bool fileExists = File.Exists(anime.PosterPath); + if (!fileExists) + { + CommandRequest_DownloadImage cmd = new CommandRequest_DownloadImage(anime.AniDB_AnimeID, JMMImageType.AniDB_Cover, false); + cmd.Save(); + } + } + + // TvDB Posters + TvDB_ImagePosterRepository repTvPosters = new TvDB_ImagePosterRepository(); + foreach (TvDB_ImagePoster tvPoster in repTvPosters.GetAll()) + { + if (string.IsNullOrEmpty(tvPoster.FullImagePath)) continue; + bool fileExists = File.Exists(tvPoster.FullImagePath); + if (!fileExists) + { + CommandRequest_DownloadImage cmd = new CommandRequest_DownloadImage(tvPoster.TvDB_ImagePosterID, JMMImageType.TvDB_Cover, false); + cmd.Save(); + } + } + + // TvDB Fanart + TvDB_ImageFanartRepository repTvFanart = new TvDB_ImageFanartRepository(); + foreach (TvDB_ImageFanart tvFanart in repTvFanart.GetAll()) + { + if (tvFanart.SeriesID == 88651) + Console.Write(""); + + if (string.IsNullOrEmpty(tvFanart.FullImagePath)) continue; + bool fileExists = File.Exists(tvFanart.FullImagePath); + if (!fileExists) + { + CommandRequest_DownloadImage cmd = new CommandRequest_DownloadImage(tvFanart.TvDB_ImageFanartID, JMMImageType.TvDB_FanArt, false); + cmd.Save(); + } + } + + // TvDB Fanart + TvDB_ImageWideBannerRepository repTvBanners = new TvDB_ImageWideBannerRepository(); + foreach (TvDB_ImageWideBanner tvBanner in repTvBanners.GetAll()) + { + if (string.IsNullOrEmpty(tvBanner.FullImagePath)) continue; + bool fileExists = File.Exists(tvBanner.FullImagePath); + if (!fileExists) + { + CommandRequest_DownloadImage cmd = new CommandRequest_DownloadImage(tvBanner.TvDB_ImageWideBannerID, JMMImageType.TvDB_Banner, false); + cmd.Save(); + } + } + + // TvDB Episodes + TvDB_EpisodeRepository repTvEpisodes = new TvDB_EpisodeRepository(); + foreach (TvDB_Episode tvEpisode in repTvEpisodes.GetAll()) + { + if (string.IsNullOrEmpty(tvEpisode.FullImagePath)) continue; + bool fileExists = File.Exists(tvEpisode.FullImagePath); + if (!fileExists) + { + CommandRequest_DownloadImage cmd = new CommandRequest_DownloadImage(tvEpisode.TvDB_EpisodeID, JMMImageType.TvDB_Episode, false); + cmd.Save(); + } + } + + // MovieDB Posters + MovieDB_PosterRepository repMoviePosters = new MovieDB_PosterRepository(); + foreach (MovieDB_Poster moviePoster in repMoviePosters.GetAll()) + { + if (string.IsNullOrEmpty(moviePoster.FullImagePath)) continue; + bool fileExists = File.Exists(moviePoster.FullImagePath); + if (!fileExists) + { + CommandRequest_DownloadImage cmd = new CommandRequest_DownloadImage(moviePoster.MovieDB_PosterID, JMMImageType.MovieDB_Poster, false); + cmd.Save(); + } + } + + // MovieDB Fanart + MovieDB_FanartRepository repMovieFanarts = new MovieDB_FanartRepository(); + foreach (MovieDB_Fanart movieFanart in repMovieFanarts.GetAll()) + { + if (string.IsNullOrEmpty(movieFanart.FullImagePath)) continue; + bool fileExists = File.Exists(movieFanart.FullImagePath); + if (!fileExists) + { + CommandRequest_DownloadImage cmd = new CommandRequest_DownloadImage(movieFanart.MovieDB_FanartID, JMMImageType.MovieDB_FanArt, false); + cmd.Save(); + } + } + + // Trakt Posters + Trakt_ImagePosterRepository repTraktPosters = new Trakt_ImagePosterRepository(); + foreach (Trakt_ImagePoster traktPoster in repTraktPosters.GetAll()) + { + if (string.IsNullOrEmpty(traktPoster.FullImagePath)) continue; + bool fileExists = File.Exists(traktPoster.FullImagePath); + if (!fileExists) + { + CommandRequest_DownloadImage cmd = new CommandRequest_DownloadImage(traktPoster.Trakt_ImagePosterID, JMMImageType.Trakt_Poster, false); + cmd.Save(); + } + } + + // Trakt Fanart + Trakt_ImageFanartRepository repTraktFanarts = new Trakt_ImageFanartRepository(); + foreach (Trakt_ImageFanart traktFanart in repTraktFanarts.GetAll()) + { + if (string.IsNullOrEmpty(traktFanart.FullImagePath)) continue; + bool fileExists = File.Exists(traktFanart.FullImagePath); + if (!fileExists) + { + CommandRequest_DownloadImage cmd = new CommandRequest_DownloadImage(traktFanart.Trakt_ImageFanartID, JMMImageType.Trakt_Fanart, false); + cmd.Save(); + } + } + + // Trakt Episode + Trakt_EpisodeRepository repTraktEpisodes = new Trakt_EpisodeRepository(); + foreach (Trakt_Episode traktEp in repTraktEpisodes.GetAll()) + { + if (string.IsNullOrEmpty(traktEp.FullImagePath)) continue; + bool fileExists = File.Exists(traktEp.FullImagePath); + if (!fileExists) + { + CommandRequest_DownloadImage cmd = new CommandRequest_DownloadImage(traktEp.Trakt_EpisodeID, JMMImageType.Trakt_Episode, false); + cmd.Save(); + } + } + } + + public static void RunImport_ScanTvDB() + { + TvDBHelper.ScanForMatches(); + } + + public static void RunImport_ScanTrakt() + { + TraktTVHelper.ScanForMatches(); + } + + public static void RunImport_ScanMovieDB() + { + MovieDBHelper.ScanForMatches(); + } + + public static void RunImport_UpdateTvDB(bool forced) + { + TvDBHelper.UpdateAllInfo(forced); + } + + public static void RemoveRecordsWithoutPhysicalFiles() + { + VideoLocalRepository repVidLocals = new VideoLocalRepository(); + CrossRef_File_EpisodeRepository repXRefs = new CrossRef_File_EpisodeRepository(); + + // get a full list of files + List 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); + } + } + + UpdateAllStats(); + } + + public static void UpdateAllStats() + { + AnimeGroupRepository repGroups = new AnimeGroupRepository(); + foreach (AnimeGroup grp in repGroups.GetAllTopLevelGroups()) + { + grp.UpdateStatsFromTopLevel(true, true); + } + } + + + + public static void CheckForTvDBUpdates(bool forceRefresh) + { + if (ServerSettings.TvDB_UpdateFrequency == ScheduledUpdateFrequency.Never && !forceRefresh) return; + int freqHours = Utils.GetScheduledHours(ServerSettings.TvDB_UpdateFrequency); + + // update tvdb info every 12 hours + ScheduledUpdateRepository repSched = new ScheduledUpdateRepository(); + + ScheduledUpdate sched = repSched.GetByUpdateType((int)ScheduledUpdateType.TvDBInfo); + if (sched != null) + { + // if we have run this in the last 12 hours and are not forcing it, then exit + TimeSpan tsLastRun = DateTime.Now - sched.LastUpdate; + if (tsLastRun.TotalHours < freqHours) + { + if (!forceRefresh) return; + } + } + + List tvDBIDs = new List(); + bool tvDBOnline = false; + string serverTime = JMMService.TvdbHelper.IncrementalTvDBUpdate(ref tvDBIDs, ref tvDBOnline); + + if (tvDBOnline) + { + foreach (int tvid in tvDBIDs) + { + // download and update series info, episode info and episode images + // will also download fanart, posters and wide banners + CommandRequest_TvDBUpdateSeriesAndEpisodes cmdSeriesEps = new CommandRequest_TvDBUpdateSeriesAndEpisodes(tvid, false); + cmdSeriesEps.Save(); + } + } + + if (sched == null) + { + sched = new ScheduledUpdate(); + sched.UpdateType = (int)ScheduledUpdateType.TvDBInfo; + } + + sched.LastUpdate = DateTime.Now; + sched.UpdateDetails = serverTime; + repSched.Save(sched); + + TvDBHelper.ScanForMatches(); + } + + public static void CheckForCalendarUpdate(bool forceRefresh) + { + if (ServerSettings.AniDB_Calendar_UpdateFrequency == ScheduledUpdateFrequency.Never && !forceRefresh) return; + int freqHours = Utils.GetScheduledHours(ServerSettings.AniDB_Calendar_UpdateFrequency); + + // update the calendar every 12 hours + // we will always assume that an anime was downloaded via http first + ScheduledUpdateRepository repSched = new ScheduledUpdateRepository(); + AniDB_AnimeRepository repAnime = new AniDB_AnimeRepository(); + + ScheduledUpdate sched = repSched.GetByUpdateType((int)ScheduledUpdateType.AniDBCalendar); + if (sched != null) + { + // if we have run this in the last 12 hours and are not forcing it, then exit + TimeSpan tsLastRun = DateTime.Now - sched.LastUpdate; + if (tsLastRun.TotalHours < freqHours) + { + if (!forceRefresh) return; + } + } + + CommandRequest_GetCalendar cmd = new CommandRequest_GetCalendar(forceRefresh); + cmd.Save(); + } + + public static void CheckForAnimeUpdate(bool forceRefresh) + { + if (ServerSettings.AniDB_Anime_UpdateFrequency == ScheduledUpdateFrequency.Never && !forceRefresh) return; + int freqHours = Utils.GetScheduledHours(ServerSettings.AniDB_Anime_UpdateFrequency); + + // check for any updated anime info every 12 hours + ScheduledUpdateRepository repSched = new ScheduledUpdateRepository(); + AniDB_AnimeRepository repAnime = new AniDB_AnimeRepository(); + + ScheduledUpdate sched = repSched.GetByUpdateType((int)ScheduledUpdateType.AniDBUpdates); + if (sched != null) + { + // if we have run this in the last 12 hours and are not forcing it, then exit + TimeSpan tsLastRun = DateTime.Now - sched.LastUpdate; + if (tsLastRun.TotalHours < freqHours) + { + if (!forceRefresh) return; + } + } + + CommandRequest_GetUpdated cmd = new CommandRequest_GetUpdated(true); + cmd.Save(); + } + + public static void CheckForMyListSyncUpdate(bool forceRefresh) + { + if (ServerSettings.AniDB_MyList_UpdateFrequency == ScheduledUpdateFrequency.Never && !forceRefresh) return; + int freqHours = Utils.GetScheduledHours(ServerSettings.AniDB_MyList_UpdateFrequency); + + // update the calendar every 24 hours + ScheduledUpdateRepository repSched = new ScheduledUpdateRepository(); + + ScheduledUpdate sched = repSched.GetByUpdateType((int)ScheduledUpdateType.AniDBMyListSync); + if (sched != null) + { + // if we have run this in the last 24 hours and are not forcing it, then exit + TimeSpan tsLastRun = DateTime.Now - sched.LastUpdate; + logger.Trace("Last AniDB MyList Sync: {0} minutes ago", tsLastRun.TotalMinutes); + if (tsLastRun.TotalHours < freqHours) + { + if (!forceRefresh) return; + } + } + + CommandRequest_SyncMyList cmd = new CommandRequest_SyncMyList(forceRefresh); + cmd.Save(); + } + + public static void CheckForTraktSyncUpdate(bool forceRefresh) + { + if (ServerSettings.Trakt_SyncFrequency == ScheduledUpdateFrequency.Never && !forceRefresh) return; + int freqHours = Utils.GetScheduledHours(ServerSettings.Trakt_SyncFrequency); + + // update the calendar every xxx hours + ScheduledUpdateRepository repSched = new ScheduledUpdateRepository(); + + ScheduledUpdate sched = repSched.GetByUpdateType((int)ScheduledUpdateType.TraktSync); + if (sched != null) + { + // if we have run this in the last xxx hours and are not forcing it, then exit + TimeSpan tsLastRun = DateTime.Now - sched.LastUpdate; + logger.Trace("Last Trakt Sync: {0} minutes ago", tsLastRun.TotalMinutes); + if (tsLastRun.TotalHours < freqHours) + { + if (!forceRefresh) return; + } + } + + CommandRequest_TraktSyncCollection cmd = new CommandRequest_TraktSyncCollection(false); + cmd.Save(); + } + + public static void CheckForTraktAllSeriesUpdate(bool forceRefresh) + { + if (ServerSettings.Trakt_UpdateFrequency == ScheduledUpdateFrequency.Never && !forceRefresh) return; + int freqHours = Utils.GetScheduledHours(ServerSettings.Trakt_UpdateFrequency); + + // update the calendar every xxx hours + ScheduledUpdateRepository repSched = new ScheduledUpdateRepository(); + + ScheduledUpdate sched = repSched.GetByUpdateType((int)ScheduledUpdateType.TraktUpdate); + if (sched != null) + { + // if we have run this in the last xxx hours and are not forcing it, then exit + TimeSpan tsLastRun = DateTime.Now - sched.LastUpdate; + logger.Trace("Last Trakt Update: {0} minutes ago", tsLastRun.TotalMinutes); + if (tsLastRun.TotalHours < freqHours) + { + if (!forceRefresh) return; + } + } + + CommandRequest_TraktUpdateAllSeries cmd = new CommandRequest_TraktUpdateAllSeries(false); + cmd.Save(); + } + } +} diff --git a/JMMServer/JMMServer.csproj b/JMMServer/JMMServer.csproj new file mode 100644 index 000000000..9aae1daf4 --- /dev/null +++ b/JMMServer/JMMServer.csproj @@ -0,0 +1,578 @@ + + + + Debug + x86 + 8.0.30703 + 2.0 + {DA8F0783-0F82-4106-9860-6F09BA2EA522} + WinExe + Properties + JMMServer + JMMServer + v3.5 + 512 + {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 4 + + + x86 + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + x86 + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + db.ico + + + app.manifest + + + + ..\Dependencies\Antlr3.Runtime.dll + + + Dependencies\FluentNHibernate.dll + + + False + ..\Dependencies\ICSharpCode.SharpZipLib.dll + + + ..\Dependencies\Iesi.Collections.dll + + + Dependencies\NHibernate.dll + + + ..\Dependencies\NHibernate.ByteCode.Castle.dll + + + False + ..\Dependencies\NLog.dll + + + ..\Dependencies\Remotion.Data.Linq.dll + + + + + + Dependencies\System.Data.SQLite.dll + + + + + + + + + + + + + + + + + MSBuild:Compile + Designer + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + HyperLinkStandard.xaml + + + ImportFolderForm.xaml + + + ImportFolderAdmin.xaml + + + + + + + + + + + + + + + + + + + + + MSBuild:Compile + Designer + + + App.xaml + Code + + + + MainWindow.xaml + Code + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + Designer + MSBuild:Compile + + + + + Code + + + True + True + Resources.resx + + + True + Settings.settings + True + + + ResXFileCodeGenerator + Resources.Designer.cs + + + Designer + + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + + + + + + + + + + + + + + + + + + + + + + + + {D777636B-F927-4C7D-9D00-4A7858E75F3E} + JMMContracts + + + {73E4CFC4-291B-47A2-ACAA-78096CEBB7DF} + JMMFileHelper + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + xcopy "$(TargetDir)*.dll" "C:\Projects\SVN\JMM\[ JMM Binaries No Configs ]\Server\" /S /R /I /Y +xcopy "$(TargetDir)*.exe" "C:\Projects\SVN\JMM\[ JMM Binaries No Configs ]\Server\" /S /R /I /Y +xcopy "$(TargetDir)*.pdb" "C:\Projects\SVN\JMM\[ JMM Binaries No Configs ]\Server\" /S /R /I /Y +xcopy "$(TargetDir)*.manifest" "C:\Projects\SVN\JMM\[ JMM Binaries No Configs ]\Server\" /S /R /I /Y + + + + + \ No newline at end of file diff --git a/JMMServer/JMMServer.csproj.user b/JMMServer/JMMServer.csproj.user new file mode 100644 index 000000000..76fe5a55d --- /dev/null +++ b/JMMServer/JMMServer.csproj.user @@ -0,0 +1,6 @@ + + + + ProjectFiles + + \ No newline at end of file diff --git a/JMMServer/JMMService.cs b/JMMServer/JMMService.cs new file mode 100644 index 000000000..777b97409 --- /dev/null +++ b/JMMServer/JMMService.cs @@ -0,0 +1,172 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Commands; +using JMMServer.ImageDownload; +using NHibernate; +using JMMServer.Databases; +using NLog; +using JMMServer.Providers.TvDB; + +namespace JMMServer +{ + public class JMMService + { + private static Logger logger = LogManager.GetCurrentClassLogger(); + private static readonly object sessionLock = new object(); + private static readonly object cmdLockGeneral = new object(); + private static readonly object cmdLockHasher = new object(); + private static readonly object cmdLockImages = new object(); + private static readonly object lockLastAniDBMessage = new object(); + private static readonly object lockLastAniDBUDPMessage = new object(); + private static readonly object lockLastAniDBHTTPMessage = new object(); + private static readonly object lockLastAniDBMessageNonPing = new object(); + private static readonly object lockLastAniDBPing = new object(); + + private static DateTime lastAniDBMessage = DateTime.Now; + public static DateTime LastAniDBMessage + { + get + { + lock (lockLastAniDBMessage) + { + return JMMService.lastAniDBMessage; + } + } + set + { + lastAniDBMessage = value; + } + } + + private static DateTime lastAniDBUDPMessage = DateTime.Now; + public static DateTime LastAniDBUDPMessage + { + get + { + lock (lockLastAniDBUDPMessage) + { + return JMMService.lastAniDBUDPMessage; + } + } + set + { + lastAniDBUDPMessage = value; + } + } + + private static DateTime lastAniDBHTTPMessage = DateTime.Now; + public static DateTime LastAniDBHTTPMessage + { + get + { + lock (lockLastAniDBHTTPMessage) + { + return JMMService.lastAniDBHTTPMessage; + } + } + set + { + lastAniDBHTTPMessage = value; + } + } + + + private static DateTime lastAniDBMessageNonPing = DateTime.Now; + public static DateTime LastAniDBMessageNonPing + { + get + { + lock (lockLastAniDBMessageNonPing) + { + return JMMService.lastAniDBMessageNonPing; + } + } + set + { + lastAniDBMessageNonPing = value; + } + } + + private static DateTime lastAniDBPing = DateTime.Now; + public static DateTime LastAniDBPing + { + get + { + lock (lockLastAniDBPing) + { + return JMMService.lastAniDBPing; + } + } + set + { + lastAniDBPing = value; + } + } + + private static CommandProcessorGeneral cmdProcessorGeneral = new CommandProcessorGeneral(); + public static CommandProcessorGeneral CmdProcessorGeneral + { + get + { + lock (cmdLockGeneral) + { + return JMMService.cmdProcessorGeneral; + } + } + } + + private static CommandProcessorImages cmdProcessorImages = new CommandProcessorImages(); + public static CommandProcessorImages CmdProcessorImages + { + get + { + lock (cmdLockImages) + { + return JMMService.cmdProcessorImages; + } + } + } + + private static CommandProcessorHasher cmdProcessorHasher = new CommandProcessorHasher(); + public static CommandProcessorHasher CmdProcessorHasher + { + get + { + lock (cmdLockHasher) + { + return JMMService.cmdProcessorHasher; + } + } + } + + private static AniDBHelper anidbProcessor = new AniDBHelper(); + public static AniDBHelper AnidbProcessor + { + get { return JMMService.anidbProcessor; } + } + + private static TvDBHelper tvdbHelper = new TvDBHelper(); + public static TvDBHelper TvdbHelper + { + get { return JMMService.tvdbHelper; } + } + + private static ISessionFactory sessionFactory = null; + public static ISessionFactory SessionFactory + { + get + { + lock (sessionLock) + { + if (sessionFactory == null) + { + sessionFactory = DatabaseHelper.CreateSessionFactory(); + } + return JMMService.sessionFactory; + } + } + } + } +} diff --git a/JMMServer/JMMServiceImplementation.cs b/JMMServer/JMMServiceImplementation.cs new file mode 100644 index 000000000..b8b6b1d0d --- /dev/null +++ b/JMMServer/JMMServiceImplementation.cs @@ -0,0 +1,4540 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMContracts; +using JMMServer.Entities; +using JMMServer.Repositories; +using NLog; +using System.IO; +using JMMFileHelper; +using JMMServer.Commands; +using System.Threading; +using AniDBAPI; +using System.ServiceModel; +using JMMServer.WebCache; +using JMMServer.Providers.TvDB; +using JMMServer.Providers.MovieDB; +using BinaryNorthwest; +using JMMServer.Providers.TraktTV; + +namespace JMMServer +{ + [ServiceBehavior(MaxItemsInObjectGraph = int.MaxValue)] + public class JMMServiceImplementation : IJMMServer + { + private static Logger logger = LogManager.GetCurrentClassLogger(); + + /*public List GetAllGroups() + { + List grps = new List(); + try + { + DateTime start = DateTime.Now; + AnimeGroupRepository repGroups = new AnimeGroupRepository(); + AniDB_AnimeRepository repAnime = new AniDB_AnimeRepository(); + AnimeSeriesRepository repSeries = new AnimeSeriesRepository(); + AniDB_CategoryRepository repCats = new AniDB_CategoryRepository(); + AniDB_Anime_CategoryRepository repAnimeCat = new AniDB_Anime_CategoryRepository(); + AniDB_Anime_TitleRepository repTitles = new AniDB_Anime_TitleRepository(); + + List allGrps = repGroups.GetAll(); + TimeSpan ts = DateTime.Now - start; + logger.Info("GetAllGroups (Database) in {0} ms", ts.TotalMilliseconds); + start = DateTime.Now; + + // anime + List allAnime = repAnime.GetAll(); + Dictionary allAnimeDict = new Dictionary(); + foreach (AniDB_Anime anime in allAnime) + allAnimeDict[anime.AnimeID] = anime; + + // categories + List allCatgeories = repCats.GetAll(); + Dictionary allCatgeoriesDict = new Dictionary(); + foreach (AniDB_Category cat in allCatgeories) + allCatgeoriesDict[cat.CategoryID] = cat; + + + List allAnimeCatgeories = repAnimeCat.GetAll(); + Dictionary> allAnimeCatgeoriesDict = new Dictionary>(); // animeid / list of category id's + foreach (AniDB_Anime_Category aniCat in allAnimeCatgeories) + { + if (!allAnimeCatgeoriesDict.ContainsKey(aniCat.AnimeID)) + allAnimeCatgeoriesDict[aniCat.AnimeID] = new List(); + + allAnimeCatgeoriesDict[aniCat.AnimeID].Add(aniCat.CategoryID); + } + + // titles + List allTitles = repTitles.GetAll(); + Dictionary> allTitlesDict = new Dictionary>(); // animeid / list of titles + foreach (AniDB_Anime_Title aniTitle in allTitles) + { + if (!allTitlesDict.ContainsKey(aniTitle.AnimeID)) + allTitlesDict[aniTitle.AnimeID] = new List(); + + allTitlesDict[aniTitle.AnimeID].Add(aniTitle); + } + + // user votes + AniDB_VoteRepository repVotes = new AniDB_VoteRepository(); + List allVotes = repVotes.GetAll(); + + List allSeries = repSeries.GetAll(); + + ts = DateTime.Now - start; + logger.Info("GetAllGroups (Stats Data) in {0} ms", ts.TotalMilliseconds); + start = DateTime.Now; + + foreach (AnimeGroup ag in allGrps) + { + // calculate stats + Contract_AnimeGroup contract = ag.ToContract(); + GroupStatsCalculator.CalculateStats(ref contract, ag, allSeries, allAnimeDict, allCatgeoriesDict, allAnimeCatgeoriesDict, allTitlesDict, allVotes); + + grps.Add(contract); + } + + + + + grps.Sort(); + ts = DateTime.Now - start; + logger.Info("GetAllGroups (Contracts) in {0} ms", ts.TotalMilliseconds); + + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + } + return grps; + }*/ + + public List GetAllGroups(int userID) + { + List grps = new List(); + try + { + DateTime start = DateTime.Now; + AnimeGroupRepository repGroups = new AnimeGroupRepository(); + AnimeGroup_UserRepository repUserGroups = new AnimeGroup_UserRepository(); + + List allGrps = repGroups.GetAll(); + TimeSpan ts = DateTime.Now - start; + logger.Info("GetAllGroups (Database) in {0} ms", ts.TotalMilliseconds); + start = DateTime.Now; + + // user records + AnimeGroup_UserRepository repGroupUser = new AnimeGroup_UserRepository(); + List userRecordList = repGroupUser.GetByUserID(userID); + Dictionary dictUserRecords = new Dictionary(); + foreach (AnimeGroup_User grpUser in userRecordList) + dictUserRecords[grpUser.AnimeGroupID] = grpUser; + + foreach (AnimeGroup ag in allGrps) + { + AnimeGroup_User userRec = null; + if (dictUserRecords.ContainsKey(ag.AnimeGroupID)) + userRec = dictUserRecords[ag.AnimeGroupID]; + + // calculate stats + Contract_AnimeGroup contract = ag.ToContract(userRec); + grps.Add(contract); + } + + + + + grps.Sort(); + ts = DateTime.Now - start; + logger.Info("GetAllGroups (Contracts) in {0} ms", ts.TotalMilliseconds); + + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + } + return grps; + } + + public List GetAllGroupsAboveGroupInclusive(int animeGroupID, int userID) + { + List grps = new List(); + try + { + AnimeGroupRepository repGroups = new AnimeGroupRepository(); + + AnimeGroup grp = repGroups.GetByID(animeGroupID); + if (grp == null) + return grps; + + Contract_AnimeGroup contractGrp = grp.ToContract(grp.GetUserRecord(userID)); + grps.Add(contractGrp); + + int? groupID = grp.AnimeGroupParentID; + while (groupID.HasValue) + { + AnimeGroup grpTemp = repGroups.GetByID(groupID.Value); + if (grpTemp != null) + { + Contract_AnimeGroup contractGrpTemp = grpTemp.ToContract(grpTemp.GetUserRecord(userID)); + grps.Add(contractGrpTemp); + groupID = grpTemp.AnimeGroupParentID; + } + else + { + groupID = null; + } + } + + return grps; + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + } + return grps; + } + + public List GetAllGroupsAboveSeries(int animeSeriesID, int userID) + { + List grps = new List(); + try + { + AnimeSeriesRepository repSeries = new AnimeSeriesRepository(); + AnimeSeries series = repSeries.GetByID(animeSeriesID); + if (series == null) + return grps; + + foreach (AnimeGroup grp in series.AllGroupsAbove) + { + Contract_AnimeGroup contractGrpTemp = grp.ToContract(grp.GetUserRecord(userID)); + grps.Add(contractGrpTemp); + } + + return grps; + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + } + return grps; + } + + public Contract_AnimeGroup GetGroup(int animeGroupID, int userID) + { + try + { + AnimeGroupRepository repGroups = new AnimeGroupRepository(); + AnimeGroup grp = repGroups.GetByID(animeGroupID); + if (grp == null) return null; + + Contract_AnimeGroup contractGrpTemp = grp.ToContract(grp.GetUserRecord(userID)); + + return contractGrpTemp; + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + } + return null; + } + + public string DeleteAnimeGroup(int animeGroupID, bool deleteFiles) + { + try + { + AnimeSeriesRepository repAnimeSer = new AnimeSeriesRepository(); + AnimeGroupRepository repGroups = new AnimeGroupRepository(); + + AnimeGroup grp = repGroups.GetByID(animeGroupID); + if (grp == null) return "Group does not exist"; + + int? parentGroupID = grp.AnimeGroupParentID; + + foreach (AnimeSeries ser in grp.AllSeries) + { + DeleteAnimeSeries(ser.AnimeSeriesID, deleteFiles); + } + + // delete all sub groups + foreach (AnimeGroup subGroup in grp.AllChildGroups) + { + DeleteAnimeGroup(subGroup.AnimeGroupID, deleteFiles); + } + + GroupFilterConditionRepository repConditions = new GroupFilterConditionRepository(); + // delete any group filter conditions which reference these groups + foreach (GroupFilterCondition gfc in repConditions.GetByConditionType(GroupFilterConditionType.AnimeGroup)) + { + int thisGrpID = 0; + int.TryParse(gfc.ConditionParameter, out thisGrpID); + if (thisGrpID == animeGroupID) + repConditions.Delete(gfc.GroupFilterConditionID); + } + + + repGroups.Delete(grp.AnimeGroupID); + + // finally update stats + + if (parentGroupID.HasValue) + { + AnimeGroup grpParent = repGroups.GetByID(parentGroupID.Value); + + if (grpParent != null) + { + grpParent.TopLevelAnimeGroup.UpdateStatsFromTopLevel(true, true, true); + StatsCache.Instance.UpdateUsingGroup(grpParent.TopLevelAnimeGroup.AnimeGroupID); + } + } + + return ""; + + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + return ex.Message; + } + + } + + public List GetAnimeGroupsForFilter(int groupFilterID, int userID) + { + List retGroups = new List(); + try + { + + DateTime start = DateTime.Now; + GroupFilterRepository repGF = new GroupFilterRepository(); + + JMMUserRepository repUsers = new JMMUserRepository(); + JMMUser user = repUsers.GetByID(userID); + if (user == null) return retGroups; + + GroupFilter gf = null; + + if (groupFilterID == -999) + { + // all groups + gf = new GroupFilter(); + gf.GroupFilterName = "All"; + } + else + { + gf = repGF.GetByID(groupFilterID); + if (gf == null) return retGroups; + } + + Contract_GroupFilterExtended contract = gf.ToContractExtended(user); + + AnimeGroupRepository repGroups = new AnimeGroupRepository(); + List allGrps = repGroups.GetAll(); + + AnimeGroup_UserRepository repUserRecords = new AnimeGroup_UserRepository(); + List userRecords = repUserRecords.GetByUserID(userID); + Dictionary dictUserRecords = new Dictionary(); + foreach (AnimeGroup_User userRec in userRecords) + dictUserRecords[userRec.AnimeGroupID] = userRec; + + TimeSpan ts = DateTime.Now - start; + string msg = string.Format("Got groups for filter DB: {0} - {1} in {2} ms", gf.GroupFilterName, allGrps.Count, ts.TotalMilliseconds); + logger.Info(msg); + start = DateTime.Now; + + foreach (AnimeGroup grp in allGrps) + { + AnimeGroup_User userRec = null; + if (dictUserRecords.ContainsKey(grp.AnimeGroupID)) + userRec = dictUserRecords[grp.AnimeGroupID]; + + if (StatsCache.Instance.EvaluateGroupFilter(gf, grp, user, userRec)) + retGroups.Add(grp.ToContract(userRec)); + } + + ts = DateTime.Now - start; + msg = string.Format("Got groups for filter EVAL: {0} - {1} in {2} ms", gf.GroupFilterName, retGroups.Count, ts.TotalMilliseconds); + logger.Info(msg); + + return retGroups; + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + } + return retGroups; + } + + public Contract_GroupFilterExtended GetGroupFilterExtended(int groupFilterID, int userID) + { + try + { + GroupFilterRepository repGF = new GroupFilterRepository(); + GroupFilter gf = repGF.GetByID(groupFilterID); + if (gf == null) return null; + + JMMUserRepository repUsers = new JMMUserRepository(); + JMMUser user = repUsers.GetByID(userID); + if (user == null) return null; + + Contract_GroupFilterExtended contract = gf.ToContractExtended(user); + + return contract; + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + } + return null; + } + + public List GetAllGroupFiltersExtended(int userID) + { + List gfs = new List(); + try + { + DateTime start = DateTime.Now; + GroupFilterRepository repGF = new GroupFilterRepository(); + + JMMUserRepository repUsers = new JMMUserRepository(); + JMMUser user = repUsers.GetByID(userID); + if (user == null) return gfs; + + List allGfs = repGF.GetAll(); + TimeSpan ts = DateTime.Now - start; + logger.Info("GetAllGroupFilters (Database) in {0} ms", ts.TotalMilliseconds); + start = DateTime.Now; + + AnimeGroupRepository repGroups = new AnimeGroupRepository(); + List allGrps = repGroups.GetAll(); + ts = DateTime.Now - start; + logger.Info("GetAllGroups (Database) in {0} ms", ts.TotalMilliseconds); + start = DateTime.Now; + + AnimeGroup_UserRepository repUserRecords = new AnimeGroup_UserRepository(); + List userRecords = repUserRecords.GetByUserID(userID); + Dictionary dictUserRecords = new Dictionary(); + foreach (AnimeGroup_User userRec in userRecords) + dictUserRecords[userRec.AnimeGroupID] = userRec; + + start = DateTime.Now; + foreach (GroupFilter gf in allGfs) + { + Contract_GroupFilter gfContract = gf.ToContract(); + Contract_GroupFilterExtended gfeContract = new Contract_GroupFilterExtended(); + gfeContract.GroupFilter = gfContract; + gfeContract.GroupCount = 0; + gfeContract.SeriesCount = 0; + + foreach (AnimeGroup grp in allGrps) + { + AnimeGroup_User userRec = null; + if (dictUserRecords.ContainsKey(grp.AnimeGroupID)) + userRec = dictUserRecords[grp.AnimeGroupID]; + + // calculate stats + if (StatsCache.Instance.EvaluateGroupFilter(gf, grp, user, userRec)) + gfeContract.GroupCount++; + } + + gfs.Add(gfeContract); + } + + ts = DateTime.Now - start; + logger.Info("GetAllGroupFiltersExtended (FILTER) in {0} ms", ts.TotalMilliseconds); + + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + } + return gfs; + } + + public List GetAllGroupFilters() + { + List gfs = new List(); + try + { + DateTime start = DateTime.Now; + GroupFilterRepository repGF = new GroupFilterRepository(); + + + List allGfs = repGF.GetAll(); + TimeSpan ts = DateTime.Now - start; + logger.Info("GetAllGroupFilters (Database) in {0} ms", ts.TotalMilliseconds); + + start = DateTime.Now; + foreach (GroupFilter gf in allGfs) + { + gfs.Add(gf.ToContract()); + } + + //gfs.Sort(); + + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + } + return gfs; + } + + public Contract_GroupFilter_SaveResponse SaveGroupFilter(Contract_GroupFilter contract) + { + Contract_GroupFilter_SaveResponse response = new Contract_GroupFilter_SaveResponse(); + response.ErrorMessage = string.Empty; + response.GroupFilter = null; + + GroupFilterRepository repGF = new GroupFilterRepository(); + GroupFilterConditionRepository repGFC = new GroupFilterConditionRepository(); + + // Process the group + GroupFilter gf = null; + if (contract.GroupFilterID.HasValue) + { + gf = repGF.GetByID(contract.GroupFilterID.Value); + if (gf == null) + { + response.ErrorMessage = "Could not find existing Group Filter with ID: " + contract.GroupFilterID.Value.ToString(); + return response; + } + } + else + gf = new GroupFilter(); + + gf.GroupFilterName = contract.GroupFilterName; + gf.ApplyToSeries = contract.ApplyToSeries; + gf.BaseCondition = contract.BaseCondition; + gf.SortingCriteria = contract.SortingCriteria; + + if (string.IsNullOrEmpty(gf.GroupFilterName)) + { + response.ErrorMessage = "Must specify a group filter name"; + return response; + } + + repGF.Save(gf); + + // Process the filter conditions + + // check for any that have been deleted + foreach (GroupFilterCondition gfc in gf.FilterConditions) + { + bool gfcExists = false; + foreach (Contract_GroupFilterCondition gfc_con in contract.FilterConditions) + { + if (gfc_con.GroupFilterConditionID.HasValue && gfc_con.GroupFilterConditionID.Value == gfc.GroupFilterConditionID) + { + gfcExists = true; + break; + } + } + if (!gfcExists) + repGFC.Delete(gfc.GroupFilterConditionID); + } + + // save newly added or modified ones + foreach (Contract_GroupFilterCondition gfc_con in contract.FilterConditions) + { + GroupFilterCondition gfc = null; + if (gfc_con.GroupFilterConditionID.HasValue) + { + gfc = repGFC.GetByID(gfc_con.GroupFilterConditionID.Value); + if (gfc == null) + { + response.ErrorMessage = "Could not find existing Group Filter Condition with ID: " + gfc_con.GroupFilterConditionID.ToString(); + return response; + } + } + else + gfc = new GroupFilterCondition(); + + gfc.ConditionOperator = gfc_con.ConditionOperator; + gfc.ConditionParameter = gfc_con.ConditionParameter; + gfc.ConditionType = gfc_con.ConditionType; + gfc.GroupFilterID = gf.GroupFilterID; + + repGFC.Save(gfc); + } + + response.GroupFilter = gf.ToContract(); + + return response; + } + + public string DeleteGroupFilter(int groupFilterID) + { + try + { + GroupFilterRepository repGF = new GroupFilterRepository(); + GroupFilterConditionRepository repGFC = new GroupFilterConditionRepository(); + + GroupFilter gf = repGF.GetByID(groupFilterID); + if (gf == null) + return "Group Filter not found"; + + // delete all the conditions first + foreach (GroupFilterCondition gfc in gf.FilterConditions) + repGFC.Delete(gfc.GroupFilterConditionID); + + repGF.Delete(groupFilterID); + + return ""; + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + return ex.Message; + } + } + + public Contract_AnimeGroup_SaveResponse SaveGroup(Contract_AnimeGroup_Save contract, int userID) + { + Contract_AnimeGroup_SaveResponse contractout = new Contract_AnimeGroup_SaveResponse(); + contractout.ErrorMessage = ""; + contractout.AnimeGroup = null; + try + { + AnimeGroupRepository repGroup = new AnimeGroupRepository(); + AnimeGroup grp = null; + if (contract.AnimeGroupID.HasValue) + { + grp = repGroup.GetByID(contract.AnimeGroupID.Value); + if (grp == null) + { + contractout.ErrorMessage = "Could not find existing group with ID: " + contract.AnimeGroupID.Value.ToString(); + return contractout; + } + } + else + { + grp = new AnimeGroup(); + grp.Description = ""; + grp.IsManuallyNamed = 0; + grp.DateTimeCreated = DateTime.Now; + grp.DateTimeUpdated = DateTime.Now; + grp.SortName = ""; + grp.MissingEpisodeCount = 0; + grp.MissingEpisodeCountGroups = 0; + grp.OverrideDescription = 0; + } + + if (string.IsNullOrEmpty(contract.GroupName)) + { + contractout.ErrorMessage = "Must specify a group name"; + return contractout; + } + + grp.AnimeGroupParentID = contract.AnimeGroupParentID; + grp.Description = contract.Description; + grp.GroupName = contract.GroupName; + + grp.IsManuallyNamed = contract.IsManuallyNamed; + grp.OverrideDescription = 0; + + if (string.IsNullOrEmpty(contract.SortName)) + grp.SortName = contract.GroupName; + else + grp.SortName = contract.SortName; + + repGroup.Save(grp); + + AnimeGroup_User userRecord = grp.GetUserRecord(userID); + if (userRecord == null) userRecord = new AnimeGroup_User(userID, grp.AnimeGroupID); + userRecord.IsFave = contract.IsFave; + AnimeGroup_UserRepository repUserRecords = new AnimeGroup_UserRepository(); + repUserRecords.Save(userRecord); + + Contract_AnimeGroup contractGrp = grp.ToContract(grp.GetUserRecord(userID)); + contractout.AnimeGroup = contractGrp; + + + + return contractout; + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + contractout.ErrorMessage = ex.Message; + return contractout; + } + } + + public Contract_AnimeSeries_SaveResponse MoveSeries(int animeSeriesID, int newAnimeGroupID, int userID) + { + Contract_AnimeSeries_SaveResponse contractout = new Contract_AnimeSeries_SaveResponse(); + contractout.ErrorMessage = ""; + contractout.AnimeSeries = null; + try + { + AnimeSeriesRepository repSeries = new AnimeSeriesRepository(); + AnimeSeries ser = null; + + ser = repSeries.GetByID(animeSeriesID); + if (ser == null) + { + contractout.ErrorMessage = "Could not find existing series with ID: " + animeSeriesID.ToString(); + return contractout; + } + + // make sure the group exists + AnimeGroupRepository repGroups = new AnimeGroupRepository(); + AnimeGroup grpTemp = repGroups.GetByID(newAnimeGroupID); + if (grpTemp == null) + { + contractout.ErrorMessage = "Could not find existing group with ID: " + newAnimeGroupID.ToString(); + return contractout; + } + + int oldGroupID = ser.AnimeGroupID; + ser.AnimeGroupID = newAnimeGroupID; + ser.DateTimeUpdated = DateTime.Now; + + repSeries.Save(ser); + + // update stats for new groups + //ser.TopLevelAnimeGroup.UpdateStatsFromTopLevel(true, true, true); + ser.UpdateStats(true, true, true); + + // update stats for old groups + AnimeGroup grp = repGroups.GetByID(oldGroupID); + if (grp != null) + { + grp.TopLevelAnimeGroup.UpdateStatsFromTopLevel(true, true, true); + } + + AniDB_AnimeRepository repAnime = new AniDB_AnimeRepository(); + AniDB_Anime anime = repAnime.GetByAnimeID(ser.AniDB_ID); + if (anime == null) + { + contractout.ErrorMessage = string.Format("Could not find anime record with ID: {0}", ser.AniDB_ID); + return contractout; + } + + contractout.AnimeSeries = ser.ToContract(anime, ser.CrossRefTvDB, ser.CrossRefMovieDB, ser.GetUserRecord(userID)); + + return contractout; + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + contractout.ErrorMessage = ex.Message; + return contractout; + } + } + + public Contract_AnimeSeries_SaveResponse SaveSeries(Contract_AnimeSeries_Save contract, int userID) + { + Contract_AnimeSeries_SaveResponse contractout = new Contract_AnimeSeries_SaveResponse(); + contractout.ErrorMessage = ""; + contractout.AnimeSeries = null; + try + { + AnimeSeriesRepository repSeries = new AnimeSeriesRepository(); + AnimeSeries ser = null; + + int? oldGroupID = null; + if (contract.AnimeSeriesID.HasValue) + { + ser = repSeries.GetByID(contract.AnimeSeriesID.Value); + if (ser == null) + { + contractout.ErrorMessage = "Could not find existing series with ID: " + contract.AnimeSeriesID.Value.ToString(); + return contractout; + } + + // check if we are moving a series + oldGroupID = ser.AnimeGroupID; + } + else + { + ser = new AnimeSeries(); + ser.DateTimeCreated = DateTime.Now; + ser.DefaultAudioLanguage = ""; + ser.DefaultSubtitleLanguage = ""; + ser.MissingEpisodeCount = 0; + ser.MissingEpisodeCountGroups = 0; + ser.LatestLocalEpisodeNumber = 0; + } + + + + ser.AnimeGroupID = contract.AnimeGroupID; + ser.AniDB_ID = contract.AniDB_ID; + ser.DateTimeUpdated = DateTime.Now; + + AniDB_AnimeRepository repAnime = new AniDB_AnimeRepository(); + AniDB_Anime anime = repAnime.GetByAnimeID(ser.AniDB_ID); + if (anime == null) + { + contractout.ErrorMessage = string.Format("Could not find anime record with ID: {0}", ser.AniDB_ID); + return contractout; + } + + repSeries.Save(ser); + + // update stats for groups + //ser.TopLevelAnimeGroup.UpdateStatsFromTopLevel(true ,true, true); + ser.UpdateStats(true, true, true); + + if (oldGroupID.HasValue) + { + AnimeGroupRepository repGroups = new AnimeGroupRepository(); + AnimeGroup grp = repGroups.GetByID(oldGroupID.Value); + if (grp != null) + { + grp.TopLevelAnimeGroup.UpdateStatsFromTopLevel(true, true, true); + } + } + + contractout.AnimeSeries = ser.ToContract(anime, ser.CrossRefTvDB, ser.CrossRefMovieDB, ser.GetUserRecord(userID)); + + return contractout; + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + contractout.ErrorMessage = ex.Message; + return contractout; + } + } + + public Contract_AnimeEpisode GetEpisode(int animeEpisodeID, int userID) + { + try + { + AnimeEpisodeRepository repEps = new AnimeEpisodeRepository(); + AnimeEpisode ep = repEps.GetByID(animeEpisodeID); + if (ep == null) return null; + + return ep.ToContract(userID); + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + return null; + } + + } + + 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.AnimeEpisodes) + { + 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.UpdateStats(true, true, true); + } + + return ""; + + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + return ex.Message; + } + } + + public string SetIgnoreStatusOnFile(int videoLocalID, bool isIgnored) + { + + try + { + VideoLocalRepository repVids = new VideoLocalRepository(); + VideoLocal vid = repVids.GetByID(videoLocalID); + if (vid == null) + return "Could not find video record"; + + vid.IsIgnored = isIgnored ? 1 : 0; + repVids.Save(vid); + + return ""; + + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + return ex.Message; + } + } + + 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(); + xref.PopulateManually(vid, ep); + repXRefs.Save(xref); + + vid.MoveFileIfRequired(); + + CommandRequest_WebCacheSendXRefFileEpisode cr = new CommandRequest_WebCacheSendXRefFileEpisode(xref.CrossRef_File_EpisodeID); + cr.Save(); + + AnimeSeries ser = ep.AnimeSeries; + ser.UpdateStats(true, true, true); + + // 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); + } + + // 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.Anime.MainTitle); + cmdTrakt.Save(); + } + + return ""; + + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + } + + return ""; + } + + public string AssociateSingleFileWithMultipleEpisodes(int videoLocalID, int animeSeriesID, int startEpNum, int endEpNum) + { + + try + { + VideoLocalRepository repVids = new VideoLocalRepository(); + VideoLocal vid = repVids.GetByID(videoLocalID); + if (vid == null) + return "Could not find video record"; + + AnimeEpisodeRepository repEps = new AnimeEpisodeRepository(); + AnimeSeriesRepository repSeries = new AnimeSeriesRepository(); + AniDB_EpisodeRepository repAniEps = new AniDB_EpisodeRepository(); + CrossRef_File_EpisodeRepository repXRefs = new CrossRef_File_EpisodeRepository(); + + AnimeSeries ser = repSeries.GetByID(animeSeriesID); + if (ser == null) + return "Could not find anime series record"; + + for (int i = startEpNum; i <= endEpNum; i++) + { + List 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 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.MoveFileIfRequired(); + + ser.UpdateStats(true, true, true); + + // 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); + } + + // 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.Anime.MainTitle); + cmdTrakt.Save(); + } + + return ""; + + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + } + + return ""; + } + + public string AssociateMultipleFiles(List 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 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 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.MoveFileIfRequired(); + + CommandRequest_WebCacheSendXRefFileEpisode cr = new CommandRequest_WebCacheSendXRefFileEpisode(xref.CrossRef_File_EpisodeID); + cr.Save(); + + count++; + if (!singleEpisode) epNumber++; + } + + ser.UpdateStats(true, true, true); + + // 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); + } + + // 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.Anime.MainTitle); + cmdTrakt.Save(); + } + + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + } + + return ""; + } + + private int[] GetEpisodePercentages(int numEpisodes) + { + if (numEpisodes == 1) return new int[] { 100 }; + if (numEpisodes == 2) return new int[] { 50, 100 }; + if (numEpisodes == 3) return new int[] { 33, 66, 100 }; + if (numEpisodes == 4) return new int[] { 25, 50, 75, 100 }; + if (numEpisodes == 5) return new int[] { 20, 40, 60, 80, 100 }; + + return new int[] { 100 }; + } + + public Contract_AnimeSeries_SaveResponse CreateSeriesFromAnime(int animeID, int? animeGroupID, int userID) + { + Contract_AnimeSeries_SaveResponse response = new Contract_AnimeSeries_SaveResponse(); + response.AnimeSeries = null; + response.ErrorMessage = ""; + try + { + AnimeGroupRepository repGroups = new AnimeGroupRepository(); + if (animeGroupID.HasValue) + { + AnimeGroup grp = repGroups.GetByID(animeGroupID.Value); + if (grp == null) + { + response.ErrorMessage = "Could not find the specified group"; + return response; + } + } + + // make sure a series doesn't already exists for this anime + AnimeSeriesRepository repSeries = new AnimeSeriesRepository(); + AnimeSeries ser = repSeries.GetByAnimeID(animeID); + if (ser != null) + { + response.ErrorMessage = "A series already exists for this anime"; + return response; + } + + // make sure the anime exists first + AniDB_AnimeRepository repAnime = new AniDB_AnimeRepository(); + AniDB_Anime anime = repAnime.GetByAnimeID(animeID); + if (anime == null) + anime = JMMService.AnidbProcessor.GetAnimeInfoHTTP(animeID, false, false); + + if (anime == null) + { + response.ErrorMessage = "Could not get anime information from AniDB"; + return response; + } + + if (animeGroupID.HasValue) + { + ser = new AnimeSeries(); + ser.Populate(anime); + ser.AnimeGroupID = animeGroupID.Value; + repSeries.Save(ser); + } + else + { + 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(); + } + + + ser.UpdateStats(true, true, true); + + // check for TvDB associations + CommandRequest_TvDBSearchAnime cmd = new CommandRequest_TvDBSearchAnime(anime.AnimeID, false); + cmd.Save(); + + // check for Trakt associations + CommandRequest_TraktSearchAnime cmd2 = new CommandRequest_TraktSearchAnime(anime.AnimeID, false); + cmd2.Save(); + + response.AnimeSeries = ser.ToContract(anime, ser.CrossRefTvDB, ser.CrossRefMovieDB, ser.GetUserRecord(userID)); + return response; + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + response.ErrorMessage = ex.Message; + } + + return response; + } + + public string UpdateAnimeData(int animeID) + { + + try + { + JMMService.AnidbProcessor.GetAnimeInfoHTTP(animeID, true, false); + + // also find any files for this anime which don't have proper media info data + // we can usually tell this if the Resolution == '0x0' + VideoLocalRepository repVids = new VideoLocalRepository(); + AniDB_FileRepository repFiles = new AniDB_FileRepository(); + + foreach (VideoLocal vid in repVids.GetByAniDBAnimeID(animeID)) + { + AniDB_File aniFile = vid.AniDBFile; + if (aniFile == null) continue; + + if (aniFile.File_VideoResolution.Equals("0x0", StringComparison.InvariantCultureIgnoreCase)) + { + CommandRequest_GetFile cmd = new CommandRequest_GetFile(vid.VideoLocalID); + cmd.Save(); + } + } + + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + } + return ""; + } + + public string UpdateTvDBData(int seriesID) + { + + try + { + JMMService.TvdbHelper.UpdateAllInfoAndImages(seriesID, false); + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + } + return ""; + } + + public string UpdateTraktData(string traktD) + { + + try + { + TraktTVHelper.UpdateAllInfoAndImages(traktD, true); + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + } + return ""; + } + + public Contract_AniDBAnime GetAnime(int animeID) + { + AniDB_AnimeRepository repAnime = new AniDB_AnimeRepository(); + + try + { + AniDB_Anime anime = repAnime.GetByAnimeID(animeID); + if (anime == null) return null; + + Contract_AniDBAnime contract = anime.ToContract(); + + AniDB_Anime_DefaultImage defaultPoster = anime.DefaultPoster; + if (defaultPoster == null) + contract.DefaultImagePoster = null; + else + contract.DefaultImagePoster = defaultPoster.ToContract(); + + AniDB_Anime_DefaultImage defaultFanart = anime.DefaultFanart; + if (defaultFanart == null) + contract.DefaultImageFanart = null; + else + contract.DefaultImageFanart = defaultFanart.ToContract(); + + AniDB_Anime_DefaultImage defaultWideBanner = anime.DefaultWideBanner; + if (defaultWideBanner == null) + contract.DefaultImageWideBanner = null; + else + contract.DefaultImageWideBanner = defaultWideBanner.ToContract(); + + + return contract; + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + } + return null; + } + + public List GetAllAnime() + { + List contracts = new List(); + + try + { + DateTime start = DateTime.Now; + + AniDB_AnimeRepository repAnime = new AniDB_AnimeRepository(); + List animes = repAnime.GetAll(); + + AniDB_Anime_DefaultImageRepository repDefaults = new AniDB_Anime_DefaultImageRepository(); + List allDefaultImages = repDefaults.GetAll(); + + Dictionary dictDefaultsPosters = new Dictionary(); + Dictionary dictDefaultsFanart = new Dictionary(); + Dictionary dictDefaultsWideBanner = new Dictionary(); + + foreach (AniDB_Anime_DefaultImage defaultImage in allDefaultImages) + { + ImageSizeType sizeType = (ImageSizeType)defaultImage.ImageType; + + if (sizeType == ImageSizeType.Fanart) + dictDefaultsFanart[defaultImage.AnimeID] = defaultImage; + + if (sizeType == ImageSizeType.Poster) + dictDefaultsPosters[defaultImage.AnimeID] = defaultImage; + + if (sizeType == ImageSizeType.WideBanner) + dictDefaultsWideBanner[defaultImage.AnimeID] = defaultImage; + } + + foreach (AniDB_Anime anime in animes) + { + Contract_AniDBAnime contract = anime.ToContract(); + + if (dictDefaultsFanart.ContainsKey(anime.AnimeID)) + contract.DefaultImageFanart = dictDefaultsFanart[anime.AnimeID].ToContract(); + else contract.DefaultImageFanart = null; + + if (dictDefaultsPosters.ContainsKey(anime.AnimeID)) + contract.DefaultImagePoster = dictDefaultsPosters[anime.AnimeID].ToContract(); + else contract.DefaultImagePoster = null; + + if (dictDefaultsWideBanner.ContainsKey(anime.AnimeID)) + contract.DefaultImageWideBanner = dictDefaultsWideBanner[anime.AnimeID].ToContract(); + else contract.DefaultImageWideBanner = null; + + contracts.Add(contract); + //anime.ToContractDetailed(); + } + + TimeSpan ts = DateTime.Now - start; + logger.Info("GetAllAnimein {0} ms", ts.TotalMilliseconds); + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + } + return contracts; + } + + public List GetAllAnimeDetailed() + { + List contracts = new List(); + int countElements = 0; + try + { + DateTime start = DateTime.Now; + + AniDB_AnimeRepository repAnime = new AniDB_AnimeRepository(); + + + // build a dictionary of categories + AniDB_CategoryRepository repCats = new AniDB_CategoryRepository(); + AniDB_Anime_CategoryRepository repAnimeCat = new AniDB_Anime_CategoryRepository(); + + List allCatgeories = repCats.GetAll(); + Dictionary allCatgeoriesDict = new Dictionary(); + foreach (AniDB_Category cat in allCatgeories) + allCatgeoriesDict[cat.CategoryID] = cat; + + + List allAnimeCatgeories = repAnimeCat.GetAll(); + Dictionary> allAnimeCatgeoriesDict = new Dictionary>(); // + foreach (AniDB_Anime_Category aniCat in allAnimeCatgeories) + { + if (!allAnimeCatgeoriesDict.ContainsKey(aniCat.AnimeID)) + allAnimeCatgeoriesDict[aniCat.AnimeID] = new List(); + + allAnimeCatgeoriesDict[aniCat.AnimeID].Add(aniCat); + } + + // build a dictionary of titles + AniDB_Anime_TitleRepository repTitles = new AniDB_Anime_TitleRepository(); + + + List allTitles = repTitles.GetAll(); + Dictionary> allTitlesDict = new Dictionary>(); + foreach (AniDB_Anime_Title title in allTitles) + { + if (!allTitlesDict.ContainsKey(title.AnimeID)) + allTitlesDict[title.AnimeID] = new List(); + + allTitlesDict[title.AnimeID].Add(title); + } + + + // build a dictionary of tags + AniDB_TagRepository repTags = new AniDB_TagRepository(); + AniDB_Anime_TagRepository repAnimeTag = new AniDB_Anime_TagRepository(); + + List allTags = repTags.GetAll(); + Dictionary allTagsDict = new Dictionary(); + foreach (AniDB_Tag tag in allTags) + allTagsDict[tag.TagID] = tag; + + + List allAnimeTags = repAnimeTag.GetAll(); + Dictionary> allAnimeTagsDict = new Dictionary>(); // + foreach (AniDB_Anime_Tag aniTag in allAnimeTags) + { + if (!allAnimeTagsDict.ContainsKey(aniTag.AnimeID)) + allAnimeTagsDict[aniTag.AnimeID] = new List(); + + allAnimeTagsDict[aniTag.AnimeID].Add(aniTag); + } + + // build a dictionary of languages + AdhocRepository rep = new AdhocRepository(); + Dictionary dictAudioStats = rep.GetAudioLanguageStatsForAnime(); + Dictionary dictSubtitleStats = rep.GetSubtitleLanguageStatsForAnime(); + + Dictionary dictAnimeVideoQualStats = rep.GetAllVideoQualityByAnime(); + Dictionary dictAnimeEpisodeVideoQualStats = rep.GetEpisodeVideoQualityStatsByAnime(); + + List animes = repAnime.GetAll(); + + // user votes + AniDB_VoteRepository repVotes = new AniDB_VoteRepository(); + List allVotes = repVotes.GetAll(); + + int i = 0; + + + + foreach (AniDB_Anime anime in animes) + { + i++; + //if (i >= 10) continue; + + countElements++; + + Contract_AniDB_AnimeDetailed contract = new Contract_AniDB_AnimeDetailed(); + + contract.AnimeTitles = new List(); + contract.Categories = new List(); + contract.Tags = new List(); + contract.UserVote = null; + + contract.AniDBAnime = anime.ToContract(); + + if (dictAnimeVideoQualStats.ContainsKey(anime.AnimeID)) + contract.Stat_AllVideoQuality = dictAnimeVideoQualStats[anime.AnimeID]; + else contract.Stat_AllVideoQuality = ""; + + contract.Stat_AllVideoQuality_Episodes = ""; + + // 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 + if (dictAnimeEpisodeVideoQualStats.ContainsKey(anime.AnimeID)) + { + AnimeVideoQualityStat stat = dictAnimeEpisodeVideoQualStats[anime.AnimeID]; + foreach (KeyValuePair kvp in stat.VideoQualityEpisodeCount) + { + if (kvp.Value >= anime.EpisodeCountNormal) + { + if (contract.Stat_AllVideoQuality_Episodes.Length > 0) contract.Stat_AllVideoQuality_Episodes += ","; + contract.Stat_AllVideoQuality_Episodes += kvp.Key; + } + } + } + + List audioLanguageList = new List(); + List subtitleLanguageList = new List(); + + // get audio languages + if (dictAudioStats.ContainsKey(anime.AnimeID)) + { + foreach (string lanName in dictAudioStats[anime.AnimeID].LanguageNames) + { + if (!audioLanguageList.Contains(lanName)) audioLanguageList.Add(lanName); + } + } + + // get subtitle languages + if (dictSubtitleStats.ContainsKey(anime.AnimeID)) + { + foreach (string lanName in dictSubtitleStats[anime.AnimeID].LanguageNames) + { + if (!subtitleLanguageList.Contains(lanName)) subtitleLanguageList.Add(lanName); + } + } + + contract.Stat_AudioLanguages = ""; + foreach (string audioLan in audioLanguageList) + { + if (contract.Stat_AudioLanguages.Length > 0) contract.Stat_AudioLanguages += ","; + contract.Stat_AudioLanguages += audioLan; + } + + contract.Stat_SubtitleLanguages = ""; + foreach (string subLan in subtitleLanguageList) + { + if (contract.Stat_SubtitleLanguages.Length > 0) contract.Stat_SubtitleLanguages += ","; + contract.Stat_SubtitleLanguages += subLan; + } + + + if (allTitlesDict.ContainsKey(anime.AnimeID)) + { + foreach (AniDB_Anime_Title title in allTitlesDict[anime.AnimeID]) + { + Contract_AnimeTitle ctitle = new Contract_AnimeTitle(); + ctitle.AnimeID = title.AnimeID; + ctitle.Language = title.Language; + ctitle.Title = title.Title; + ctitle.TitleType = title.TitleType; + contract.AnimeTitles.Add(ctitle); + countElements++; + } + } + + + if (allAnimeCatgeoriesDict.ContainsKey(anime.AnimeID)) + { + List aniCats = allAnimeCatgeoriesDict[anime.AnimeID]; + foreach (AniDB_Anime_Category aniCat in aniCats) + { + if (allCatgeoriesDict.ContainsKey(aniCat.CategoryID)) + { + AniDB_Category cat = allCatgeoriesDict[aniCat.CategoryID]; + + Contract_AnimeCategory ccat = new Contract_AnimeCategory(); + ccat.CategoryDescription = cat.CategoryDescription; + ccat.CategoryID = cat.CategoryID; + ccat.CategoryName = cat.CategoryName; + ccat.IsHentai = cat.IsHentai; + ccat.ParentID = cat.ParentID; + ccat.Weighting = aniCat.Weighting; + contract.Categories.Add(ccat); + countElements++; + } + } + } + + if (allAnimeTagsDict.ContainsKey(anime.AnimeID)) + { + List aniTags = allAnimeTagsDict[anime.AnimeID]; + foreach (AniDB_Anime_Tag aniTag in aniTags) + { + if (allTagsDict.ContainsKey(aniTag.TagID)) + { + AniDB_Tag tag = allTagsDict[aniTag.TagID]; + + Contract_AnimeTag ctag = new Contract_AnimeTag(); + ctag.Approval = aniTag.Approval; + ctag.GlobalSpoiler = tag.GlobalSpoiler; + ctag.LocalSpoiler = tag.LocalSpoiler; + ctag.Spoiler = tag.Spoiler; + ctag.TagCount = tag.TagCount; + ctag.TagDescription = tag.TagDescription; + ctag.TagID = tag.TagID; + ctag.TagName = tag.TagName; + contract.Tags.Add(ctag); + countElements++; + } + } + } + + // get user vote + foreach (AniDB_Vote vote in allVotes) + { + if (vote.EntityID == anime.AnimeID && (vote.VoteType == (int)AniDBVoteType.Anime || vote.VoteType == (int)AniDBVoteType.AnimeTemp)) + { + contract.UserVote = vote.ToContract(); + break; + } + } + + contracts.Add(contract); + + } + + + TimeSpan ts = DateTime.Now - start; + logger.Info("GetAllAnimeDetailed in {0} ms {1}", ts.TotalMilliseconds, countElements); + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + } + return contracts; + } + + public List GetAllSeries(int userID) + { + DateTime start = DateTime.Now; + AnimeSeriesRepository repSeries = new AnimeSeriesRepository(); + AniDB_AnimeRepository repAnime = new AniDB_AnimeRepository(); + AniDB_Anime_TitleRepository repTitles = new AniDB_Anime_TitleRepository(); + AniDB_Anime_CategoryRepository repAnimeCats = new AniDB_Anime_CategoryRepository(); + AniDB_CategoryRepository repCats = new AniDB_CategoryRepository(); + AniDB_TagRepository repTags = new AniDB_TagRepository(); + AniDB_Anime_TagRepository repAnimeTags = new AniDB_Anime_TagRepository(); + + // get all the series + List seriesContractList = new List(); + + try + { + + List series = repSeries.GetAll(); + + List animes = repAnime.GetAll(); + Dictionary dictAnimes = new Dictionary(); + foreach (AniDB_Anime anime in animes) + dictAnimes[anime.AnimeID] = anime; + + // tvdb + CrossRef_AniDB_TvDBRepository repCrossRef = new CrossRef_AniDB_TvDBRepository(); + List allCrossRefs = repCrossRef.GetAll(); + Dictionary dictCrossRefs = new Dictionary(); + foreach (CrossRef_AniDB_TvDB xref in allCrossRefs) + dictCrossRefs[xref.AnimeID] = xref; + + + // moviedb + CrossRef_AniDB_OtherRepository repOtherCrossRef = new CrossRef_AniDB_OtherRepository(); + List allOtherCrossRefs = repOtherCrossRef.GetAll(); + Dictionary dictMovieCrossRefs = new Dictionary(); + foreach (CrossRef_AniDB_Other xref in allOtherCrossRefs) + { + if (xref.CrossRefType == (int)CrossRefType.MovieDB) + dictMovieCrossRefs[xref.AnimeID] = xref; + } + + // user records + AnimeSeries_UserRepository repSeriesUser = new AnimeSeries_UserRepository(); + List userRecordList = repSeriesUser.GetByUserID(userID); + Dictionary dictUserRecords = new Dictionary(); + foreach (AnimeSeries_User serUser in userRecordList) + dictUserRecords[serUser.AnimeSeriesID] = serUser; + + foreach (AnimeSeries aser in series) + { + if (!dictAnimes.ContainsKey(aser.AniDB_ID)) continue; + + CrossRef_AniDB_TvDB xref = null; + if (dictCrossRefs.ContainsKey(aser.AniDB_ID)) xref = dictCrossRefs[aser.AniDB_ID]; + + CrossRef_AniDB_Other xrefMovie = null; + if (dictMovieCrossRefs.ContainsKey(aser.AniDB_ID)) xrefMovie = dictMovieCrossRefs[aser.AniDB_ID]; + + AnimeSeries_User userRec = null; + if (dictUserRecords.ContainsKey(aser.AnimeSeriesID)) + userRec = dictUserRecords[aser.AnimeSeriesID]; + + seriesContractList.Add(aser.ToContract(dictAnimes[aser.AniDB_ID], xref, xrefMovie, userRec)); + } + + TimeSpan ts = DateTime.Now - start; + logger.Info("GetAllSeries in {0} ms", ts.TotalMilliseconds); + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + } + return seriesContractList; + } + + public Contract_AniDB_AnimeDetailed GetAnimeDetailed(int animeID) + { + try + { + DateTime start = DateTime.Now; + + Contract_AniDB_AnimeDetailed contract = null; + + AniDB_AnimeRepository repAnime = new AniDB_AnimeRepository(); + + AniDB_Anime anime = repAnime.GetByAnimeID(animeID); + if (anime == null) return null; + + contract = anime.ToContractDetailed(); + + TimeSpan ts = DateTime.Now - start; + logger.Info("GetAnimeDetailed in {0} ms", ts.TotalMilliseconds); + + return contract; + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + return null; + } + } + + public List GetAllCategoryNames() + { + AniDB_CategoryRepository repCats = new AniDB_CategoryRepository(); + List allCatNames = new List(); + + try + { + DateTime start = DateTime.Now; + + foreach (AniDB_Category cat in repCats.GetAll()) + { + allCatNames.Add(cat.CategoryName); + } + allCatNames.Sort(); + + + TimeSpan ts = DateTime.Now - start; + logger.Info("GetAllCategoryNames in {0} ms", ts.TotalMilliseconds); + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + } + + return allCatNames; + } + + public List GetSubGroupsForGroup(int animeGroupID, int userID) + { + List retGroups = new List(); + try + { + AnimeGroupRepository repGroups = new AnimeGroupRepository(); + AnimeGroup grp = repGroups.GetByID(animeGroupID); + if (grp == null) return retGroups; + + foreach (AnimeGroup grpChild in grp.ChildGroups) + retGroups.Add(grpChild.ToContract(grpChild.GetUserRecord(userID))); + + return retGroups; + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + } + return retGroups; + } + + public List GetSeriesForGroup(int animeGroupID, int userID) + { + List series = new List(); + try + { + AnimeGroupRepository repGroups = new AnimeGroupRepository(); + AnimeGroup grp = repGroups.GetByID(animeGroupID); + if (grp == null) return series; + + foreach (AnimeSeries ser in grp.Series) + series.Add(ser.ToContract(ser.GetUserRecord(userID))); + + return series; + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + return series; + } + } + + public List GetSeriesForGroupRecursive(int animeGroupID, int userID) + { + List series = new List(); + try + { + AnimeGroupRepository repGroups = new AnimeGroupRepository(); + AnimeGroup grp = repGroups.GetByID(animeGroupID); + if (grp == null) return series; + + foreach (AnimeSeries ser in grp.AllSeries) + series.Add(ser.ToContract(ser.GetUserRecord(userID))); + + return series; + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + return series; + } + } + + + + public List GetEpisodesForSeries(int animeSeriesID, int userID) + { + List eps = new List(); + 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 epList = repEps.GetBySeriesID(animeSeriesID); + List userRecordList = repEpUsers.GetByUserIDAndSeriesID(userID, animeSeriesID); + Dictionary dictUserRecords = new Dictionary(); + foreach (AnimeEpisode_User epuser in userRecordList) + dictUserRecords[epuser.AnimeEpisodeID] = epuser; + + AniDB_EpisodeRepository repAniEps = new AniDB_EpisodeRepository(); + List aniEpList = repAniEps.GetByAnimeID(series.AniDB_ID); + Dictionary dictAniEps = new Dictionary(); + foreach (AniDB_Episode aniep in aniEpList) + dictAniEps[aniep.EpisodeID] = aniep; + + // get all the video local records and cross refs + List vids = repVids.GetByAniDBAnimeID(series.AniDB_ID); + List crossRefs = repCrossRefs.GetByAnimeID(series.AniDB_ID); + + TimeSpan ts = DateTime.Now - start; + logger.Info("GetEpisodesForSeries: {0} (Database) in {1} ms", series.Anime.MainTitle, ts.TotalMilliseconds); + + + start = DateTime.Now; + foreach (AnimeEpisode ep in epList) + { + if (dictAniEps.ContainsKey(ep.AniDB_EpisodeID)) + { + List epVids = new List(); + foreach (CrossRef_File_Episode xref in crossRefs) + { + if (xref.EpisodeID == dictAniEps[ep.AniDB_EpisodeID].EpisodeID) + { + foreach (VideoLocal vl in vids) + { + if (string.Equals(xref.Hash,vl.Hash, StringComparison.InvariantCultureIgnoreCase)) + 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)); + } + } + + ts = DateTime.Now - start; + logger.Info("GetEpisodesForSeries: {0} (Contracts) in {1} ms", series.Anime.MainTitle, ts.TotalMilliseconds); + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + } + + return eps; + } + + public List GetEpisodesForSeriesOld(int animeSeriesID) + { + List eps = new List(); + 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 epList = repEps.GetBySeriesID(animeSeriesID); + + AniDB_EpisodeRepository repAniEps = new AniDB_EpisodeRepository(); + List aniEpList = repAniEps.GetByAnimeID(series.AniDB_ID); + Dictionary dictAniEps = new Dictionary(); + foreach (AniDB_Episode aniep in aniEpList) + dictAniEps[aniep.EpisodeID] = aniep; + + List crossRefList = repCrossRefs.GetByAnimeID(series.AniDB_ID); + + + + + TimeSpan ts = DateTime.Now - start; + logger.Info("GetEpisodesForSeries: {0} (Database) in {1} ms", series.Anime.MainTitle, ts.TotalMilliseconds); + + + start = DateTime.Now; + foreach (AnimeEpisode ep in epList) + { + List xrefs = new List(); + 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.Anime.MainTitle, ts.TotalMilliseconds); + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + } + + return eps; + } + + public Contract_AnimeSeries GetSeries(int animeSeriesID, int userID) + { + AnimeSeriesRepository repAnimeSer = new AnimeSeriesRepository(); + + try + { + AnimeSeries series = repAnimeSer.GetByID(animeSeriesID); + if (series == null) return null; + + AniDB_AnimeRepository repAnime = new AniDB_AnimeRepository(); + AniDB_Anime anime = repAnime.GetByAnimeID(series.AniDB_ID); + if (anime == null) return null; + + return series.ToContract(anime, series.CrossRefTvDB, series.CrossRefMovieDB, series.GetUserRecord(userID)); + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + } + return null; + } + + public bool GetSeriesExistingForAnime(int animeID) + { + AnimeSeriesRepository repAnimeSer = new AnimeSeriesRepository(); + + try + { + AnimeSeries series = repAnimeSer.GetByAnimeID(animeID); + if (series == null) + return false; + return true; + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + } + return true; + } + + public List GetFilesForEpisode(int episodeID, int userID) + { + + try + { + AnimeEpisodeRepository repEps = new AnimeEpisodeRepository(); + AnimeEpisode ep = repEps.GetByID(episodeID); + if (ep != null) + return ep.GetVideoDetailedContracts(userID); + else + return new List(); + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + } + return new List(); + } + + public List GetIgnoredFiles(int userID) + { + List contracts = new List(); + try + { + VideoLocalRepository repVids = new VideoLocalRepository(); + foreach (VideoLocal vid in repVids.GetIgnoredVideos()) + { + contracts.Add(vid.ToContract(userID)); + } + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + } + return contracts; + } + + public List GetManuallyLinkedFiles(int userID) + { + List contracts = new List(); + try + { + VideoLocalRepository repVids = new VideoLocalRepository(); + foreach (VideoLocal vid in repVids.GetManuallyLinkedVideos()) + { + contracts.Add(vid.ToContract(userID)); + } + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + } + return contracts; + } + + public List GetUnrecognisedFiles(int userID) + { + List contracts = new List(); + try + { + VideoLocalRepository repVids = new VideoLocalRepository(); + foreach (VideoLocal vid in repVids.GetVideosWithoutEpisode()) + { + contracts.Add(vid.ToContract(userID)); + } + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + } + return contracts; + } + + public Contract_ServerStatus GetServerStatus() + { + Contract_ServerStatus contract = new Contract_ServerStatus(); + + try + { + contract.HashQueueCount = JMMService.CmdProcessorHasher.QueueCount; + contract.HashQueueState = JMMService.CmdProcessorHasher.QueueState; + + contract.GeneralQueueCount = JMMService.CmdProcessorGeneral.QueueCount; + contract.GeneralQueueState = JMMService.CmdProcessorGeneral.QueueState; + + contract.ImagesQueueCount = JMMService.CmdProcessorImages.QueueCount; + contract.ImagesQueueState = JMMService.CmdProcessorImages.QueueState; + + contract.IsBanned = JMMService.AnidbProcessor.IsBanned; + contract.BanReason = JMMService.AnidbProcessor.BanTime.ToString(); + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + } + return contract; + } + + public Contract_ServerSettings_SaveResponse SaveServerSettings(Contract_ServerSettings contractIn) + { + Contract_ServerSettings_SaveResponse contract = new Contract_ServerSettings_SaveResponse(); + contract.ErrorMessage = ""; + + try + { + // validate the settings + bool anidbSettingsChanged = false; + if (contractIn.AniDB_ClientPort != ServerSettings.AniDB_ClientPort) + { + anidbSettingsChanged = true; + int cport = 0; + int.TryParse(contractIn.AniDB_ClientPort, out cport); + if (cport <= 0) + { + contract.ErrorMessage = "AniDB Client Port must be numeric and greater than 0" + Environment.NewLine; + } + } + + if (contractIn.AniDB_ServerPort != ServerSettings.AniDB_ServerPort) + { + anidbSettingsChanged = true; + int sport = 0; + int.TryParse(contractIn.AniDB_ServerPort, out sport); + if (sport <= 0) + { + contract.ErrorMessage = "AniDB Server Port must be numeric and greater than 0" + Environment.NewLine; + } + } + + if (contractIn.AniDB_Username != ServerSettings.AniDB_Username) + { + anidbSettingsChanged = true; + if (string.IsNullOrEmpty(contractIn.AniDB_Username)) + { + contract.ErrorMessage = "AniDB User Name must have a value" + Environment.NewLine; + } + } + + if (contractIn.AniDB_Password != ServerSettings.AniDB_Password) + { + anidbSettingsChanged = true; + if (string.IsNullOrEmpty(contractIn.AniDB_Password)) + { + contract.ErrorMessage = "AniDB Password must have a value" + Environment.NewLine; + } + } + + if (contractIn.AniDB_ServerAddress != ServerSettings.AniDB_ServerAddress) + { + anidbSettingsChanged = true; + if (string.IsNullOrEmpty(contractIn.AniDB_ServerAddress)) + { + contract.ErrorMessage = "AniDB Server Address must have a value" + Environment.NewLine; + } + } + + if (contract.ErrorMessage.Length > 0) return contract; + + ServerSettings.AniDB_ClientPort = contractIn.AniDB_ClientPort; + ServerSettings.AniDB_Password = contractIn.AniDB_Password; + ServerSettings.AniDB_ServerAddress = contractIn.AniDB_ServerAddress; + ServerSettings.AniDB_ServerPort = contractIn.AniDB_ServerPort; + ServerSettings.AniDB_Username = contractIn.AniDB_Username; + + ServerSettings.AniDB_DownloadCharactersCreators = contractIn.AniDB_DownloadCharactersCreators; + ServerSettings.AniDB_DownloadRelatedAnime = contractIn.AniDB_DownloadRelatedAnime; + ServerSettings.AniDB_DownloadReleaseGroups = contractIn.AniDB_DownloadReleaseGroups; + ServerSettings.AniDB_DownloadReviews = contractIn.AniDB_DownloadReviews; + ServerSettings.AniDB_DownloadSimilarAnime = contractIn.AniDB_DownloadSimilarAnime; + + ServerSettings.AniDB_MyList_AddFiles = contractIn.AniDB_MyList_AddFiles; + ServerSettings.AniDB_MyList_ReadUnwatched = contractIn.AniDB_MyList_ReadUnwatched; + ServerSettings.AniDB_MyList_ReadWatched = contractIn.AniDB_MyList_ReadWatched; + ServerSettings.AniDB_MyList_SetUnwatched = contractIn.AniDB_MyList_SetUnwatched; + ServerSettings.AniDB_MyList_SetWatched = contractIn.AniDB_MyList_SetWatched; + ServerSettings.AniDB_MyList_StorageState = (AniDBFileStatus)contractIn.AniDB_MyList_StorageState; + + ServerSettings.AniDB_MyList_UpdateFrequency = (ScheduledUpdateFrequency)contractIn.AniDB_MyList_UpdateFrequency; + ServerSettings.AniDB_Calendar_UpdateFrequency = (ScheduledUpdateFrequency)contractIn.AniDB_Calendar_UpdateFrequency; + ServerSettings.AniDB_Anime_UpdateFrequency = (ScheduledUpdateFrequency)contractIn.AniDB_Anime_UpdateFrequency; + + // Web Cache + ServerSettings.WebCache_Address = contractIn.WebCache_Address; + ServerSettings.WebCache_Anonymous = contractIn.WebCache_Anonymous; + ServerSettings.WebCache_FileHashes_Get = contractIn.WebCache_FileHashes_Get; + ServerSettings.WebCache_FileHashes_Send = contractIn.WebCache_FileHashes_Send; + ServerSettings.WebCache_XRefFileEpisode_Get = contractIn.WebCache_XRefFileEpisode_Get; + ServerSettings.WebCache_XRefFileEpisode_Send = contractIn.WebCache_XRefFileEpisode_Send; + ServerSettings.WebCache_TvDB_Get = contractIn.WebCache_TvDB_Get; + ServerSettings.WebCache_TvDB_Send = contractIn.WebCache_TvDB_Send; + + // TvDB + ServerSettings.TvDB_AutoFanart = contractIn.TvDB_AutoFanart; + ServerSettings.TvDB_AutoFanartAmount = contractIn.TvDB_AutoFanartAmount; + ServerSettings.TvDB_AutoPosters = contractIn.TvDB_AutoPosters; + ServerSettings.TvDB_AutoWideBanners = contractIn.TvDB_AutoWideBanners; + ServerSettings.TvDB_UpdateFrequency = (ScheduledUpdateFrequency)contractIn.TvDB_UpdateFrequency; + + // MovieDB + ServerSettings.MovieDB_AutoFanart = contractIn.MovieDB_AutoFanart; + ServerSettings.MovieDB_AutoFanartAmount = contractIn.MovieDB_AutoFanartAmount; + ServerSettings.MovieDB_AutoPosters = contractIn.MovieDB_AutoPosters; + + // Import settings + ServerSettings.VideoExtensions = contractIn.VideoExtensions; + ServerSettings.Import_UseExistingFileWatchedStatus = contractIn.Import_UseExistingFileWatchedStatus; + ServerSettings.WatchForNewFiles = contractIn.WatchForNewFiles; + ServerSettings.RunImportOnStart = contractIn.RunImportOnStart; + ServerSettings.Hash_CRC32 = contractIn.Hash_CRC32; + ServerSettings.Hash_MD5 = contractIn.Hash_MD5; + ServerSettings.Hash_SHA1 = contractIn.Hash_SHA1; + + // Language + ServerSettings.LanguagePreference = contractIn.LanguagePreference; + ServerSettings.LanguageUseSynonyms = contractIn.LanguageUseSynonyms; + + // Trakt + ServerSettings.Trakt_Username = contractIn.Trakt_Username; + ServerSettings.Trakt_Password = contractIn.Trakt_Password; + ServerSettings.Trakt_UpdateFrequency = (ScheduledUpdateFrequency)contractIn.Trakt_UpdateFrequency; + ServerSettings.Trakt_SyncFrequency = (ScheduledUpdateFrequency)contractIn.Trakt_SyncFrequency; + + if (anidbSettingsChanged) + { + JMMService.AnidbProcessor.ForceLogout(); + JMMService.AnidbProcessor.CloseConnections(); + + Thread.Sleep(1000); + JMMService.AnidbProcessor.Init(ServerSettings.AniDB_Username, ServerSettings.AniDB_Password, ServerSettings.AniDB_ServerAddress, + ServerSettings.AniDB_ServerPort, ServerSettings.AniDB_ClientPort); + } + + } + catch (Exception ex) + { + contract.ErrorMessage = ex.Message; + logger.ErrorException(ex.ToString(), ex); + } + return contract; + } + + public Contract_ServerSettings GetServerSettings() + { + Contract_ServerSettings contract = new Contract_ServerSettings(); + + try + { + return ServerSettings.ToContract(); + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + } + return contract; + } + + public string ToggleWatchedStatusOnVideo(int videoLocalID, bool watchedStatus, int userID) + { + try + { + VideoLocalRepository repVids = new VideoLocalRepository(); + VideoLocal vid = repVids.GetByID(videoLocalID); + if (vid == null) + return "Could not find video local record"; + + vid.ToggleWatchedStatus(watchedStatus, true, DateTime.Now, true, userID); + + return ""; + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + return ex.Message; + } + } + + public Contract_ToggleWatchedStatusOnEpisode_Response ToggleWatchedStatusOnEpisode(int animeEpisodeID, bool watchedStatus, int userID) + { + Contract_ToggleWatchedStatusOnEpisode_Response response = new Contract_ToggleWatchedStatusOnEpisode_Response(); + response.ErrorMessage = ""; + response.AnimeEpisode = null; + + try + { + AnimeEpisodeRepository repEps = new AnimeEpisodeRepository(); + AnimeEpisode ep = repEps.GetByID(animeEpisodeID); + if (ep == null) + { + response.ErrorMessage = "Could not find anime episode record"; + return response; + } + + ep.ToggleWatchedStatus(watchedStatus, true, DateTime.Now, userID); + + // refresh from db + ep = repEps.GetByID(animeEpisodeID); + + response.AnimeEpisode = ep.ToContract(userID); + + return response; + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + response.ErrorMessage = ex.Message; + return response; + } + } + + /// + /// Set watched status on all normal episodes + /// + /// + /// + /// Use this to specify a max episode number to apply to + /// + public string SetWatchedStatusOnSeries(int animeSeriesID, bool watchedStatus, int maxEpisodeNumber, int episodeType, int userID) + { + try + { + AnimeEpisodeRepository repEps = new AnimeEpisodeRepository(); + List eps = repEps.GetBySeriesID(animeSeriesID); + + AnimeSeries ser = null; + foreach (AnimeEpisode ep in eps) + { + if (ep.EpisodeTypeEnum == (enEpisodeType)episodeType && ep.AniDB_Episode.EpisodeNumber <= maxEpisodeNumber) + { + ep.ToggleWatchedStatus(watchedStatus, true, DateTime.Now, false, userID); + logger.Info("Updating episode: {0} to {1}", ep.AniDB_Episode.EpisodeNumber, watchedStatus); + } + + + ser = ep.AnimeSeries; + } + + // now update the stats + if (ser != null) + ser.UpdateStats(true, true, true); + return ""; + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + return ex.Message; + } + } + + public Contract_VideoDetailed GetVideoDetailed(int videoLocalID) + { + try + { + VideoLocalRepository repVids = new VideoLocalRepository(); + VideoLocal vid = repVids.GetByID(videoLocalID); + if (vid == null) + return null; + + return null; + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + return null; + } + } + + public List GetEpisodesForFile(int videoLocalID, int userID) + { + List contracts = new List(); + try + { + + + VideoLocalRepository repVids = new VideoLocalRepository(); + VideoLocal vid = repVids.GetByID(videoLocalID); + if (vid == null) + return contracts; + + foreach (AnimeEpisode ep in vid.AnimeEpisodes) + { + contracts.Add(ep.ToContract(userID)); + } + + return contracts; + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + return contracts; + } + } + + /// + /// Get all the release groups for an episode for which the user is collecting + /// + /// + /// + public List GetMyReleaseGroupsForAniDBEpisode(int aniDBEpisodeID) + { + DateTime start = DateTime.Now; + + List relGroups = new List(); + + try + { + AniDB_EpisodeRepository repAniEps = new AniDB_EpisodeRepository(); + AniDB_Episode aniEp = repAniEps.GetByEpisodeID(aniDBEpisodeID); + if (aniEp == null) return relGroups; + if (aniEp.EpisodeTypeEnum != AniDBAPI.enEpisodeType.Episode) return relGroups; + + AnimeSeriesRepository repSeries = new AnimeSeriesRepository(); + AnimeSeries series = repSeries.GetByAnimeID(aniEp.AnimeID); + if (series == null) return relGroups; + + // get a list of all the release groups the user is collecting + List userReleaseGroups = new List(); + foreach (AnimeEpisode ep in series.AnimeEpisodes) + { + List vids = ep.VideoLocals; + foreach (VideoLocal vid in vids) + { + AniDB_File anifile = vid.AniDBFile; + if (anifile != null) + { + if (!userReleaseGroups.Contains(anifile.GroupID)) userReleaseGroups.Add(anifile.GroupID); + } + } + } + + // get all the release groups for this series + AniDB_GroupStatusRepository repGrpStatus = new AniDB_GroupStatusRepository(); + List grpStatuses = repGrpStatus.GetByAnimeID(aniEp.AnimeID); + foreach (AniDB_GroupStatus gs in grpStatuses) + { + if (userReleaseGroups.Contains(gs.GroupID)) + { + if (gs.HasGroupReleasedEpisode(aniEp.EpisodeNumber)) + { + Contract_AniDBReleaseGroup contract = new Contract_AniDBReleaseGroup(); + contract.GroupID = gs.GroupID; + contract.GroupName = gs.GroupName; + relGroups.Add(contract); + } + } + } + TimeSpan ts = DateTime.Now - start; + logger.Info("GetMyReleaseGroupsForAniDBEpisode in {0} ms", ts.TotalMilliseconds); + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + } + return relGroups; + } + + public List GetImportFolders() + { + List ifolders = new List(); + try + { + ImportFolderRepository repNS = new ImportFolderRepository(); + foreach (ImportFolder ns in repNS.GetAll()) + { + ifolders.Add(ns.ToContract()); + } + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + } + return ifolders; + } + + public Contract_ImportFolder_SaveResponse SaveImportFolder(Contract_ImportFolder contract) + { + Contract_ImportFolder_SaveResponse response = new Contract_ImportFolder_SaveResponse(); + response.ErrorMessage = ""; + response.ImportFolder = null; + + try + { + + + ImportFolderRepository repNS = new ImportFolderRepository(); + ImportFolder ns = null; + if (contract.ImportFolderID.HasValue) + { + // update + ns = repNS.GetByID(contract.ImportFolderID.Value); + if (ns == null) + { + response.ErrorMessage = "Could not find Import Folder ID: " + contract.ImportFolderID.Value.ToString(); + return response; + } + } + else + { + // create + ns = new ImportFolder(); + } + + if (string.IsNullOrEmpty(contract.ImportFolderName)) + { + response.ErrorMessage = "Must specify an Import Folder name"; + return response; + } + + if (string.IsNullOrEmpty(contract.ImportFolderLocation)) + { + response.ErrorMessage = "Must specify an Import Folder location"; + return response; + } + + if (!Directory.Exists(contract.ImportFolderLocation)) + { + response.ErrorMessage = "Cannot find Import Folder location"; + return response; + } + + if (!contract.ImportFolderID.HasValue) + { + ImportFolder nsTemp = repNS.GetByImportLocation(contract.ImportFolderLocation); + if (nsTemp != null) + { + response.ErrorMessage = "An entry already exists for the specified Import Folder location"; + return response; + } + } + + if (contract.IsDropDestination == 1 && contract.IsDropSource == 1) + { + response.ErrorMessage = "A folder cannot be a drop source and a drop destination at the same time"; + return response; + } + + // check to make sure we don't have multiple drop folders + List allFolders = repNS.GetAll(); + + if (contract.IsDropDestination == 1) + { + foreach (ImportFolder imf in allFolders) + { + if (imf.IsDropDestination == 1 && (!contract.ImportFolderID.HasValue || (contract.ImportFolderID.Value != imf.ImportFolderID))) + { + imf.IsDropDestination = 0; + repNS.Save(imf); + } + } + } + + ns.ImportFolderName = contract.ImportFolderName; + ns.ImportFolderLocation = contract.ImportFolderLocation; + ns.IsDropDestination = contract.IsDropDestination; + ns.IsDropSource = contract.IsDropSource; + repNS.Save(ns); + + response.ImportFolder = ns.ToContract(); + + MainWindow.StopWatchingFiles(); + MainWindow.StartWatchingFiles(); + + return response; + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + response.ErrorMessage = ex.Message; + return response; + } + } + + public string DeleteImportFolder(int importFolderID) + { + try + { + ImportFolderRepository repNS = new ImportFolderRepository(); + ImportFolder ns = null; + + ns = repNS.GetByID(importFolderID); + if (ns == null) return "Could not find Import Folder ID: " + importFolderID; + + repNS.Delete(importFolderID); + + return ""; + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + return ex.Message; + } + } + + public void RunImport() + { + MainWindow.RunImport(); + } + + public void ScanFolder(int importFolderID) + { + MainWindow.ScanFolder(importFolderID); + } + + public void RemoveMissingFiles() + { + MainWindow.RemoveMissingFiles(); + } + + public void SyncMyList() + { + MainWindow.SyncMyList(); + } + + public void SyncVotes() + { + CommandRequest_SyncMyVotes cmdVotes = new CommandRequest_SyncMyVotes(); + cmdVotes.Save(); + } + + public void RescanUnlinkedFiles() + { + try + { + // files which have been hashed, but don't have an associated episode + VideoLocalRepository repVidLocals = new VideoLocalRepository(); + List filesWithoutEpisode = repVidLocals.GetVideosWithoutEpisode(); + + foreach (VideoLocal vl in filesWithoutEpisode) + { + CommandRequest_ProcessFile cmd = new CommandRequest_ProcessFile(vl.VideoLocalID); + cmd.Save(); + } + } + catch (Exception ex) + { + logger.ErrorException(ex.Message, ex); + } + } + + public void SetCommandProcessorHasherPaused(bool paused) + { + JMMService.CmdProcessorHasher.Paused = paused; + } + + public void SetCommandProcessorGeneralPaused(bool paused) + { + JMMService.CmdProcessorGeneral.Paused = paused; + } + + public void SetCommandProcessorImagesPaused(bool paused) + { + JMMService.CmdProcessorImages.Paused = paused; + } + + public void RehashFile(int videoLocalID) + { + VideoLocalRepository repVidLocals = new VideoLocalRepository(); + VideoLocal vl = repVidLocals.GetByID(videoLocalID); + + if (vl != null) + { + CommandRequest_HashFile cr_hashfile = new CommandRequest_HashFile(vl.FullServerPath, true); + cr_hashfile.Save(); + } + } + + public string TestAniDBConnection() + { + string log = ""; + try + { + log += "Disposing..." + Environment.NewLine; + JMMService.AnidbProcessor.ForceLogout(); + JMMService.AnidbProcessor.CloseConnections(); + Thread.Sleep(1000); + + log += "Init..." + Environment.NewLine; + JMMService.AnidbProcessor.Init(ServerSettings.AniDB_Username, ServerSettings.AniDB_Password, ServerSettings.AniDB_ServerAddress, + ServerSettings.AniDB_ServerPort, ServerSettings.AniDB_ClientPort); + + log += "Login..." + Environment.NewLine; + if (JMMService.AnidbProcessor.Login()) + { + log += "Login Success!" + Environment.NewLine; + log += "Logout..." + Environment.NewLine; + JMMService.AnidbProcessor.ForceLogout(); + log += "Logged out" + Environment.NewLine; + } + else + { + log += "Login FAILED!" + Environment.NewLine; + } + + return log; + } + catch (Exception ex) + { + log += ex.Message + Environment.NewLine; + } + + return log; + } + + public string TestTraktLogin() + { + try + { + return TraktTVHelper.TestUserLogin(); + } + catch (Exception ex) + { + logger.ErrorException("Error in TestTraktLogin: " + ex.ToString(), ex); + return ex.Message; + } + } + + /// + /// + /// + /// + /// Must be 1 or 2 (Anime or Anime Temp( + /// + public void VoteAnime(int animeID, decimal voteValue, int voteType) + { + // lets save to the database and assume it will work + AniDB_VoteRepository repVotes = new AniDB_VoteRepository(); + List dbVotes = repVotes.GetByEntity(animeID); + AniDB_Vote thisVote = null; + foreach (AniDB_Vote dbVote in dbVotes) + { + // we can only have anime permanent or anime temp but not both + if (voteType == (int)enAniDBVoteType.Anime || voteType == (int)enAniDBVoteType.AnimeTemp) + { + if (dbVote.VoteType == (int)enAniDBVoteType.Anime || dbVote.VoteType == (int)enAniDBVoteType.AnimeTemp) + { + thisVote = dbVote; + } + } + else + { + thisVote = dbVote; + } + } + + if (thisVote == null) + { + thisVote = new AniDB_Vote(); + thisVote.EntityID = animeID; + } + thisVote.VoteType = voteType; + + int iVoteValue = 0; + if (voteValue > 0) + iVoteValue = (int)(voteValue * 100); + else + iVoteValue = (int)voteValue; + + + thisVote.VoteValue = iVoteValue; + repVotes.Save(thisVote); + + CommandRequest_VoteAnime cmdVote = new CommandRequest_VoteAnime(animeID, voteType, voteValue); + cmdVote.Save(); + } + + public void VoteAnimeRevoke(int animeID) + { + // lets save to the database and assume it will work + AniDB_VoteRepository repVotes = new AniDB_VoteRepository(); + List dbVotes = repVotes.GetByEntity(animeID); + AniDB_Vote thisVote = null; + foreach (AniDB_Vote dbVote in dbVotes) + { + // we can only have anime permanent or anime temp but not both + if (dbVote.VoteType == (int)enAniDBVoteType.Anime || dbVote.VoteType == (int)enAniDBVoteType.AnimeTemp) + { + thisVote = dbVote; + } + } + + if (thisVote == null) return; + + CommandRequest_VoteAnime cmdVote = new CommandRequest_VoteAnime(animeID, thisVote.VoteType, -1); + cmdVote.Save(); + + repVotes.Delete(thisVote.AniDB_VoteID); + + } + + public string RenameAllGroups() + { + try + { + AnimeGroup.RenameAllGroups(); + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + return ex.Message; + } + + return string.Empty; + } + + public List GetAllUniqueVideoQuality() + { + try + { + AdhocRepository rep = new AdhocRepository(); + return rep.GetAllVideoQuality(); + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + return new List(); + } + + } + + public List GetAllUniqueAudioLanguages() + { + try + { + AdhocRepository rep = new AdhocRepository(); + return rep.GetAllUniqueAudioLanguages(); + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + return new List(); + } + + } + + public List GetAllUniqueSubtitleLanguages() + { + try + { + AdhocRepository rep = new AdhocRepository(); + return rep.GetAllUniqueSubtitleLanguages(); + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + return new List(); + } + + } + + public List GetAllDuplicateFiles() + { + List dupFiles = new List(); + try + { + DuplicateFileRepository repDupFiles = new DuplicateFileRepository(); + foreach (DuplicateFile df in repDupFiles.GetAll()) + { + dupFiles.Add(df.ToContract()); + } + + return dupFiles; + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + return dupFiles; + } + } + + /// + /// Delete a duplicate file entry, and also one of the physical files + /// + /// + /// 0 = Don't delete any physical files, 1 = Delete file 1, 2 = Deleet file 2 + /// + public string DeleteDuplicateFile(int duplicateFileID, int fileNumber) + { + try + { + DuplicateFileRepository repDupFiles = new DuplicateFileRepository(); + DuplicateFile df = repDupFiles.GetByID(duplicateFileID); + if (df == null) return "Database entry does not exist"; + + if (fileNumber == 1 || fileNumber == 2) + { + string fileName = ""; + if (fileNumber == 1) fileName = df.FullServerPath1; + if (fileNumber == 2) fileName = df.FullServerPath2; + + if (!File.Exists(fileName)) return "File could not be found"; + + File.Delete(fileName); + } + + repDupFiles.Delete(duplicateFileID); + + return ""; + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + return ex.Message; + } + } + + /// + /// Delets the VideoLocal record and the associated physical file + /// + /// + /// + public string DeleteVideoLocalAndFile(int videoLocalID) + { + try + { + VideoLocalRepository repVids = new VideoLocalRepository(); + VideoLocal vid = repVids.GetByID(videoLocalID); + if (vid == null) return "Database entry does not exist"; + + logger.Info("Deleting video local record and file: {0}", vid.FullServerPath); + if (!File.Exists(vid.FullServerPath)) return "File could not be found"; + File.Delete(vid.FullServerPath); + + AnimeSeries ser = null; + if (vid.AnimeEpisodes.Count > 0) + ser = vid.AnimeEpisodes[0].AnimeSeries; + + CommandRequest_DeleteFileFromMyList cmdDel = new CommandRequest_DeleteFileFromMyList(vid.Hash, vid.FileSize); + cmdDel.Save(); + + repVids.Delete(videoLocalID); + + if (ser != null) + { + ser.UpdateStats(true, true, true); + StatsCache.Instance.UpdateUsingSeries(ser.AnimeSeriesID); + } + + + return ""; + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + return ex.Message; + } + } + + public List GetAllManuallyLinkedFiles(int userID) + { + List manualFiles = new List(); + try + { + VideoLocalRepository repVids = new VideoLocalRepository(); + foreach (VideoLocal vid in repVids.GetManuallyLinkedVideos()) + { + manualFiles.Add(vid.ToContract(userID)); + } + + return manualFiles; + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + return manualFiles; + } + } + + public List GetAllEpisodesWithMultipleFiles(int userID) + { + List eps = new List(); + try + { + AnimeEpisodeRepository repEps = new AnimeEpisodeRepository(); + + foreach (AnimeEpisode ep in repEps.GetEpisodesWithMultipleFiles()) + eps.Add(ep.ToContract(true, userID)); + + return eps; + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + return eps; + } + } + + public void ReevaluateDuplicateFiles() + { + try + { + DuplicateFileRepository repDupFiles = new DuplicateFileRepository(); + foreach (DuplicateFile df in repDupFiles.GetAll()) + { + // check if both files still exist + if (!File.Exists(df.FullServerPath1) || !File.Exists(df.FullServerPath2)) + { + string msg = string.Format("Deleting duplicate file record as one of the files can't be found: {0} --- {1}", df.FullServerPath1, df.FullServerPath2); + logger.Info(msg); + repDupFiles.Delete(df.DuplicateFileID); + } + } + + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + } + } + + public List GetFilesByGroupAndResolution(int animeID, string relGroupName, string resolution, string videoSource, int userID) + { + List vids = new List(); + + List vidQuals = new List(); + AniDB_AnimeRepository repAnime = new AniDB_AnimeRepository(); + AnimeSeriesRepository repSeries = new AnimeSeriesRepository(); + VideoLocalRepository repVids = new VideoLocalRepository(); + AniDB_FileRepository repAniFile = new AniDB_FileRepository(); + + try + { + AniDB_Anime anime = repAnime.GetByAnimeID(animeID); + if (anime == null) return vids; + + foreach (VideoLocal vid in repVids.GetByAniDBAnimeID(animeID)) + { + List eps = vid.AnimeEpisodes; + if (eps.Count == 0) continue; + AnimeEpisode animeEp = eps[0]; + if (animeEp.EpisodeTypeEnum == enEpisodeType.Episode || animeEp.EpisodeTypeEnum == enEpisodeType.Special) + { + // get the anibd file info + AniDB_File aniFile = vid.AniDBFile; + if (aniFile != null) + { + // match based on group / video sorce / video res + if (relGroupName.Equals(aniFile.Anime_GroupName, StringComparison.InvariantCultureIgnoreCase) && + videoSource.Equals(aniFile.File_Source, StringComparison.InvariantCultureIgnoreCase) && + resolution.Equals(aniFile.File_VideoResolution, StringComparison.InvariantCultureIgnoreCase)) + { + vids.Add(vid.ToContractDetailed(userID)); + } + + } + } + } + return vids; + + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + return vids; + } + } + + public List GetGroupVideoQualitySummary(int animeID) + { + List vidQuals = new List(); + AniDB_AnimeRepository repAnime = new AniDB_AnimeRepository(); + AnimeSeriesRepository repSeries = new AnimeSeriesRepository(); + VideoLocalRepository repVids = new VideoLocalRepository(); + AniDB_FileRepository repAniFile = new AniDB_FileRepository(); + + try + { + AniDB_Anime anime = repAnime.GetByAnimeID(animeID); + if (anime == null) return vidQuals; + + foreach (VideoLocal vid in repVids.GetByAniDBAnimeID(animeID)) + { + List eps = vid.AnimeEpisodes; + if (eps.Count == 0) continue; + AnimeEpisode animeEp = eps[0]; + if (animeEp.EpisodeTypeEnum == enEpisodeType.Episode || animeEp.EpisodeTypeEnum == enEpisodeType.Special) + { + // get the anibd file info + AniDB_File aniFile = vid.AniDBFile; + if (aniFile != null) + { + // match based on group / video sorce / video res + bool foundSummaryRecord = false; + foreach (Contract_GroupVideoQuality contract in vidQuals) + { + if (contract.GroupName.Equals(aniFile.Anime_GroupName, StringComparison.InvariantCultureIgnoreCase) && + contract.VideoSource.Equals(aniFile.File_Source, StringComparison.InvariantCultureIgnoreCase) && + contract.Resolution.Equals(aniFile.File_VideoResolution, StringComparison.InvariantCultureIgnoreCase)) + { + foundSummaryRecord = true; + + if (animeEp.EpisodeTypeEnum == enEpisodeType.Episode) contract.FileCountNormal++; + if (animeEp.EpisodeTypeEnum == enEpisodeType.Special) contract.FileCountSpecials++; + } + } + if (!foundSummaryRecord) + { + Contract_GroupVideoQuality contract = new Contract_GroupVideoQuality(); + contract.FileCountNormal = 0; + contract.FileCountSpecials = 0; + if (animeEp.EpisodeTypeEnum == enEpisodeType.Episode) contract.FileCountNormal++; + if (animeEp.EpisodeTypeEnum == enEpisodeType.Special) contract.FileCountSpecials++; + contract.GroupName = aniFile.Anime_GroupName; + contract.GroupNameShort = aniFile.Anime_GroupNameShort; + contract.Resolution = aniFile.File_VideoResolution; + contract.VideoSource = aniFile.File_Source; + contract.Ranking = Utils.GetOverallVideoSourceRanking(contract.Resolution, contract.VideoSource); + vidQuals.Add(contract); + } + } + else + { + // look at the Video Info record + VideoInfo vinfo = vid.VideoInfo; + if (vinfo != null) + { + bool foundSummaryRecord = false; + foreach (Contract_GroupVideoQuality contract in vidQuals) + { + if (contract.GroupName.Equals("NO GROUP INFO", StringComparison.InvariantCultureIgnoreCase) && + contract.VideoSource.Equals("NO SOURCE INFO", StringComparison.InvariantCultureIgnoreCase) && + contract.Resolution.Equals(vinfo.VideoResolution, StringComparison.InvariantCultureIgnoreCase)) + { + foundSummaryRecord = true; + if (animeEp.EpisodeTypeEnum == enEpisodeType.Episode) contract.FileCountNormal++; + if (animeEp.EpisodeTypeEnum == enEpisodeType.Special) contract.FileCountSpecials++; + } + } + if (!foundSummaryRecord) + { + Contract_GroupVideoQuality contract = new Contract_GroupVideoQuality(); + contract.FileCountNormal = 0; + contract.FileCountSpecials = 0; + if (animeEp.EpisodeTypeEnum == enEpisodeType.Episode) contract.FileCountNormal++; + if (animeEp.EpisodeTypeEnum == enEpisodeType.Special) contract.FileCountSpecials++; + contract.GroupName = "NO GROUP INFO"; + contract.GroupNameShort = "NO GROUP INFO"; + contract.Resolution = vinfo.VideoResolution; + contract.VideoSource = "NO SOURCE INFO"; + contract.Ranking = Utils.GetOverallVideoSourceRanking(contract.Resolution, contract.VideoSource); + } + } + } + } + } + + foreach (Contract_GroupVideoQuality contract in vidQuals) + { + contract.NormalComplete = contract.FileCountNormal >= anime.EpisodeCountNormal; + contract.SpecialsComplete = (contract.FileCountSpecials >= anime.EpisodeCountSpecial) && (anime.EpisodeCountSpecial > 0); + } + + vidQuals.Sort(); + return vidQuals; + + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + return vidQuals; + } + } + + public Contract_AniDB_AnimeCrossRefs GetCrossRefDetails(int animeID) + { + Contract_AniDB_AnimeCrossRefs result = new Contract_AniDB_AnimeCrossRefs(); + result.AnimeID = animeID; + + try + { + AniDB_AnimeRepository repAnime = new AniDB_AnimeRepository(); + AniDB_Anime anime = repAnime.GetByAnimeID(animeID); + if (anime == null) return result; + + // TvDB + CrossRef_AniDB_TvDB xref = anime.CrossRefTvDB; + if (xref == null) + result.CrossRef_AniDB_TvDB = null; + else + result.CrossRef_AniDB_TvDB = xref.ToContract(); + + TvDB_Series tvseries = anime.TvDBSeries; + if (tvseries == null) + result.TvDBSeries = null; + else + result.TvDBSeries = tvseries.ToContract(); + + foreach (TvDB_Episode ep in anime.TvDBEpisodes) + result.TvDBEpisodes.Add(ep.ToContract()); + + foreach (TvDB_ImageFanart fanart in anime.TvDBImageFanarts) + result.TvDBImageFanarts.Add(fanart.ToContract()); + + foreach (TvDB_ImagePoster poster in anime.TvDBImagePosters) + result.TvDBImagePosters.Add(poster.ToContract()); + + foreach (TvDB_ImageWideBanner banner in anime.TvDBImageWideBanners) + result.TvDBImageWideBanners.Add(banner.ToContract()); + + // Trakt + CrossRef_AniDB_Trakt xrefTrakt = anime.CrossRefTrakt; + if (xrefTrakt == null) + result.CrossRef_AniDB_Trakt = null; + else + result.CrossRef_AniDB_Trakt = xrefTrakt.ToContract(); + + Trakt_Show show = anime.TraktShow; + if (show == null) + result.TraktShow = null; + else + result.TraktShow = show.ToContract(); + + Trakt_ImageFanart traktFanart = anime.TraktImageFanart; + if (traktFanart == null) + result.TraktImageFanart = null; + else + result.TraktImageFanart = traktFanart.ToContract(); + + Trakt_ImagePoster traktPoster = anime.TraktImagePoster; + if (traktPoster == null) + result.TraktImagePoster = null; + else + result.TraktImagePoster = traktPoster.ToContract(); + + + // MovieDB + CrossRef_AniDB_Other xrefMovie = anime.CrossRefMovieDB; + if (xrefMovie == null) + result.CrossRef_AniDB_MovieDB = null; + else + result.CrossRef_AniDB_MovieDB = xrefMovie.ToContract(); + + + MovieDB_Movie movie = anime.MovieDBMovie; + if (movie == null) + result.MovieDBMovie = null; + else + result.MovieDBMovie = movie.ToContract(); + + foreach (MovieDB_Fanart fanart in anime.MovieDBFanarts) + { + if (fanart.ImageSize.Equals(Constants.MovieDBImageSize.Original, StringComparison.InvariantCultureIgnoreCase)) + result.MovieDBFanarts.Add(fanart.ToContract()); + } + + foreach (MovieDB_Poster poster in anime.MovieDBPosters) + { + if (poster.ImageSize.Equals(Constants.MovieDBImageSize.Original, StringComparison.InvariantCultureIgnoreCase)) + result.MovieDBPosters.Add(poster.ToContract()); + } + + + return result; + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + return result; + } + } + + public string EnableDisableImage(bool enabled, int imageID, int imageType) + { + try + { + JMMImageType imgType = (JMMImageType)imageType; + + switch (imgType) + { + case JMMImageType.AniDB_Cover: + + AniDB_AnimeRepository repAnime = new AniDB_AnimeRepository(); + AniDB_Anime anime = repAnime.GetByAnimeID(imageID); + if (anime == null) return "Could not find anime"; + + anime.ImageEnabled = enabled ? 1 : 0; + repAnime.Save(anime); + + break; + + case JMMImageType.TvDB_Banner: + + TvDB_ImageWideBannerRepository repBanners = new TvDB_ImageWideBannerRepository(); + TvDB_ImageWideBanner banner = repBanners.GetByID(imageID); + + if (banner == null) return "Could not find image"; + + banner.Enabled = enabled ? 1 : 0; + repBanners.Save(banner); + + break; + + case JMMImageType.TvDB_Cover: + + TvDB_ImagePosterRepository repPosters = new TvDB_ImagePosterRepository(); + TvDB_ImagePoster poster = repPosters.GetByID(imageID); + + if (poster == null) return "Could not find image"; + + poster.Enabled = enabled ? 1 : 0; + repPosters.Save(poster); + + break; + + case JMMImageType.TvDB_FanArt: + + TvDB_ImageFanartRepository repFanart = new TvDB_ImageFanartRepository(); + TvDB_ImageFanart fanart = repFanart.GetByID(imageID); + + if (fanart == null) return "Could not find image"; + + fanart.Enabled = enabled ? 1 : 0; + repFanart.Save(fanart); + + break; + + case JMMImageType.MovieDB_Poster: + + MovieDB_PosterRepository repMoviePosters = new MovieDB_PosterRepository(); + MovieDB_Poster moviePoster = repMoviePosters.GetByID(imageID); + + if (moviePoster == null) return "Could not find image"; + + moviePoster.Enabled = enabled ? 1 : 0; + repMoviePosters.Save(moviePoster); + + break; + + case JMMImageType.MovieDB_FanArt: + + MovieDB_FanartRepository repMovieFanart = new MovieDB_FanartRepository(); + MovieDB_Fanart movieFanart = repMovieFanart.GetByID(imageID); + + if (movieFanart == null) return "Could not find image"; + + movieFanart.Enabled = enabled ? 1 : 0; + repMovieFanart.Save(movieFanart); + + break; + + case JMMImageType.Trakt_Poster: + + Trakt_ImagePosterRepository repTraktPosters = new Trakt_ImagePosterRepository(); + Trakt_ImagePoster traktPoster = repTraktPosters.GetByID(imageID); + + if (traktPoster == null) return "Could not find image"; + + traktPoster.Enabled = enabled ? 1 : 0; + repTraktPosters.Save(traktPoster); + + break; + + case JMMImageType.Trakt_Fanart: + + Trakt_ImageFanartRepository repTraktFanart = new Trakt_ImageFanartRepository(); + Trakt_ImageFanart traktFanart = repTraktFanart.GetByID(imageID); + + if (traktFanart == null) return "Could not find image"; + + traktFanart.Enabled = enabled ? 1 : 0; + repTraktFanart.Save(traktFanart); + + break; + } + + return ""; + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + return ex.Message; + } + } + + public string SetDefaultImage(bool isDefault, int animeID, int imageID, int imageType, int imageSizeType) + { + try + { + AniDB_Anime_DefaultImageRepository repDefaults = new AniDB_Anime_DefaultImageRepository(); + + JMMImageType imgType = (JMMImageType)imageType; + ImageSizeType sizeType = ImageSizeType.Poster; + + switch (imgType) + { + case JMMImageType.AniDB_Cover: + case JMMImageType.TvDB_Cover: + case JMMImageType.MovieDB_Poster: + case JMMImageType.Trakt_Poster: + sizeType = ImageSizeType.Poster; + break; + + case JMMImageType.TvDB_Banner: + sizeType = ImageSizeType.WideBanner; + break; + + case JMMImageType.TvDB_FanArt: + case JMMImageType.MovieDB_FanArt: + case JMMImageType.Trakt_Fanart: + sizeType = ImageSizeType.Fanart; + break; + } + + if (!isDefault) + { + // this mean we are removing an image as deafult + // which esssential means deleting the record + + AniDB_Anime_DefaultImage img = repDefaults.GetByAnimeIDAndImagezSizeType(animeID, (int)sizeType); + if (img != null) + repDefaults.Delete(img.AniDB_Anime_DefaultImageID); + } + else + { + // making the image the default for it's type (poster, fanart etc) + AniDB_Anime_DefaultImage img = repDefaults.GetByAnimeIDAndImagezSizeType(animeID, (int)sizeType); + if (img == null) + img = new AniDB_Anime_DefaultImage(); + + img.AnimeID = animeID; + img.ImageParentID = imageID; + img.ImageParentType = (int)imgType; + img.ImageType = (int)sizeType; + repDefaults.Save(img); + } + + + return ""; + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + return ex.Message; + } + } + + #region TvDB + + public Contract_CrossRef_AniDB_TvDBResult GetTVDBCrossRefWebCache(int animeID) + { + try + { + CrossRef_AniDB_TvDBResult result = XMLService.Get_CrossRef_AniDB_TvDB(animeID); + if (result == null) return null; + + return result.ToContract(); + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + return null; + } + } + + public Contract_CrossRef_AniDB_TvDB GetTVDBCrossRef(int animeID) + { + try + { + CrossRef_AniDB_TvDBRepository repCrossRef = new CrossRef_AniDB_TvDBRepository(); + CrossRef_AniDB_TvDB xref = repCrossRef.GetByAnimeID(animeID); + if (xref == null) return null; + + return xref.ToContract(); + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + return null; + } + } + + public List SearchTheTvDB(string criteria) + { + List results = new List(); + try + { + List tvResults = JMMService.TvdbHelper.SearchSeries(criteria); + + foreach (TVDBSeriesSearchResult res in tvResults) + results.Add(res.ToContract()); + + return results; + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + return results; + } + } + + public List GetSeasonNumbersForSeries(int seriesID) + { + List seasonNumbers = new List(); + try + { + TvDB_EpisodeRepository repEps = new TvDB_EpisodeRepository(); + seasonNumbers = repEps.GetSeasonNumbersForSeries(seriesID); + + // if no results try refreshing from TvDB + if (seasonNumbers.Count == 0) + JMMService.TvdbHelper.UpdateAllInfoAndImages(seriesID, true); + + seasonNumbers = repEps.GetSeasonNumbersForSeries(seriesID); + + return seasonNumbers; + + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + return seasonNumbers; + } + } + + public string LinkAniDBTvDB(int animeID, int tvDBID, int seasonNumber) + { + try + { + TvDBHelper.LinkAniDBTvDB(animeID, tvDBID, seasonNumber, false); + + return ""; + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + return ex.Message; + } + } + + public string RemoveLinkAniDBTvDB(int animeID) + { + try + { + AnimeSeriesRepository repSeries = new AnimeSeriesRepository(); + AnimeSeries ser = repSeries.GetByAnimeID(animeID); + + if (ser == null) return "Could not find Series for Anime!"; + + // check if there are default images used associated + AniDB_Anime_DefaultImageRepository repDefaults = new AniDB_Anime_DefaultImageRepository(); + List images = repDefaults.GetByAnimeID(animeID); + foreach (AniDB_Anime_DefaultImage image in images) + { + if (image.ImageParentType == (int)JMMImageType.TvDB_Banner || + image.ImageParentType == (int)JMMImageType.TvDB_Cover || + image.ImageParentType == (int)JMMImageType.TvDB_FanArt) + { + repDefaults.Delete(image.AniDB_Anime_DefaultImageID); + } + } + + TvDBHelper.RemoveLinkAniDBTvDB(ser); + + return ""; + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + return ex.Message; + } + } + + public List GetAllTvDBPosters(int? tvDBID) + { + List allImages = new List(); + try + { + TvDB_ImagePosterRepository repImages = new TvDB_ImagePosterRepository(); + List allPosters = null; + if (tvDBID.HasValue) + allPosters = repImages.GetBySeriesID(tvDBID.Value); + else + allPosters = repImages.GetAll(); + + foreach (TvDB_ImagePoster img in allPosters) + allImages.Add(img.ToContract()); + + return allImages; + + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + return allImages; + } + } + + public List GetAllTvDBWideBanners(int? tvDBID) + { + List allImages = new List(); + try + { + TvDB_ImageWideBannerRepository repImages = new TvDB_ImageWideBannerRepository(); + List allBanners = null; + if (tvDBID.HasValue) + allBanners = repImages.GetBySeriesID(tvDBID.Value); + else + allBanners = repImages.GetAll(); + + foreach (TvDB_ImageWideBanner img in allBanners) + allImages.Add(img.ToContract()); + + return allImages; + + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + return allImages; + } + } + + public List GetAllTvDBFanart(int? tvDBID) + { + List allImages = new List(); + try + { + TvDB_ImageFanartRepository repImages = new TvDB_ImageFanartRepository(); + List allFanart = null; + if (tvDBID.HasValue) + allFanart = repImages.GetBySeriesID(tvDBID.Value); + else + allFanart = repImages.GetAll(); + + foreach (TvDB_ImageFanart img in allFanart) + allImages.Add(img.ToContract()); + + return allImages; + + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + return allImages; + } + } + + public List GetAllTvDBEpisodes(int? tvDBID) + { + List allImages = new List(); + try + { + TvDB_EpisodeRepository repImages = new TvDB_EpisodeRepository(); + List allEpisodes = null; + if (tvDBID.HasValue) + allEpisodes = repImages.GetBySeriesID(tvDBID.Value); + else + allEpisodes = repImages.GetAll(); + + foreach (TvDB_Episode img in allEpisodes) + allImages.Add(img.ToContract()); + + return allImages; + + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + return allImages; + } + } + + #endregion + + #region Trakt + + public List GetAllTraktFanart(int? traktShowID) + { + List allImages = new List(); + try + { + Trakt_ImageFanartRepository repImages = new Trakt_ImageFanartRepository(); + List allFanart = null; + if (traktShowID.HasValue) + allFanart = repImages.GetByShowID(traktShowID.Value); + else + allFanart = repImages.GetAll(); + + foreach (Trakt_ImageFanart img in allFanart) + allImages.Add(img.ToContract()); + + return allImages; + + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + return allImages; + } + } + + public List GetAllTraktPosters(int? traktShowID) + { + List allImages = new List(); + try + { + Trakt_ImagePosterRepository repImages = new Trakt_ImagePosterRepository(); + List allPosters = null; + if (traktShowID.HasValue) + allPosters = repImages.GetByShowID(traktShowID.Value); + else + allPosters = repImages.GetAll(); + + foreach (Trakt_ImagePoster img in allPosters) + allImages.Add(img.ToContract()); + + return allImages; + + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + return allImages; + } + } + + public List GetAllTraktEpisodes(int? traktShowID) + { + List allImages = new List(); + try + { + Trakt_EpisodeRepository repImages = new Trakt_EpisodeRepository(); + List allEpisodes = null; + if (traktShowID.HasValue) + allEpisodes = repImages.GetByShowID(traktShowID.Value); + else + allEpisodes = repImages.GetAll(); + + foreach (Trakt_Episode img in allEpisodes) + allImages.Add(img.ToContract()); + + return allImages; + + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + return allImages; + } + } + + public Contract_CrossRef_AniDB_TraktResult GetTraktCrossRefWebCache(int animeID) + { + try + { + CrossRef_AniDB_TraktResult result = XMLService.Get_CrossRef_AniDB_Trakt(animeID); + if (result == null) return null; + + return result.ToContract(); + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + return null; + } + } + + public Contract_CrossRef_AniDB_Trakt GetTraktCrossRef(int animeID) + { + try + { + CrossRef_AniDB_TraktRepository repCrossRef = new CrossRef_AniDB_TraktRepository(); + CrossRef_AniDB_Trakt xref = repCrossRef.GetByAnimeID(animeID); + if (xref == null) return null; + + return xref.ToContract(); + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + return null; + } + } + + public List SearchTrakt(string criteria) + { + List results = new List(); + try + { + List traktResults = TraktTVHelper.SearchShow(criteria); + + foreach (TraktTVShowResponse res in traktResults) + results.Add(res.ToContract()); + + return results; + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + return results; + } + } + + public string LinkAniDBTrakt(int animeID, string traktID, int seasonNumber) + { + try + { + TraktTVHelper.LinkAniDBTrakt(animeID, traktID, seasonNumber, false); + + return ""; + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + return ex.Message; + } + } + + public string RemoveLinkAniDBTrakt(int animeID) + { + try + { + AnimeSeriesRepository repSeries = new AnimeSeriesRepository(); + AnimeSeries ser = repSeries.GetByAnimeID(animeID); + + if (ser == null) return "Could not find Series for Anime!"; + + // check if there are default images used associated + AniDB_Anime_DefaultImageRepository repDefaults = new AniDB_Anime_DefaultImageRepository(); + List images = repDefaults.GetByAnimeID(animeID); + foreach (AniDB_Anime_DefaultImage image in images) + { + if (image.ImageParentType == (int)JMMImageType.Trakt_Fanart || + image.ImageParentType == (int)JMMImageType.Trakt_Poster) + { + repDefaults.Delete(image.AniDB_Anime_DefaultImageID); + } + } + + TraktTVHelper.RemoveLinkAniDBTrakt(ser); + + return ""; + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + return ex.Message; + } + } + + public List GetSeasonNumbersForTrakt(string traktID) + { + List seasonNumbers = new List(); + try + { + Trakt_ShowRepository repShows = new Trakt_ShowRepository(); + Trakt_Show show = repShows.GetByTraktID(traktID); + if (show == null) return seasonNumbers; + + foreach (Trakt_Season season in show.Seasons) + seasonNumbers.Add(season.Season); + + return seasonNumbers; + + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + return seasonNumbers; + } + } + + #endregion + + + #region Other Cross Refs + + public Contract_CrossRef_AniDB_OtherResult GetOtherAnimeCrossRefWebCache(int animeID, int crossRefType) + { + try + { + CrossRef_AniDB_OtherResult result = XMLService.Get_CrossRef_AniDB_Other(animeID, (CrossRefType)crossRefType); + if (result == null) return null; + + return result.ToContract(); + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + return null; + } + } + + public Contract_CrossRef_AniDB_Other GetOtherAnimeCrossRef(int animeID, int crossRefType) + { + try + { + CrossRef_AniDB_OtherRepository repCrossRef = new CrossRef_AniDB_OtherRepository(); + CrossRef_AniDB_Other xref = repCrossRef.GetByAnimeIDAndType(animeID, (CrossRefType)crossRefType); + if (xref == null) return null; + + return xref.ToContract(); + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + return null; + } + } + + public string LinkAniDBOther(int animeID, int movieID, int crossRefType) + { + try + { + CrossRefType xrefType = (CrossRefType)crossRefType; + + switch (xrefType) + { + case CrossRefType.MovieDB: + MovieDBHelper.LinkAniDBMovieDB(animeID, movieID, false); + break; + } + + return ""; + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + return ex.Message; + } + } + + public string RemoveLinkAniDBOther(int animeID, int crossRefType) + { + try + { + AniDB_AnimeRepository repAnime = new AniDB_AnimeRepository(); + AniDB_Anime anime = repAnime.GetByAnimeID(animeID); + + if (anime == null) return "Could not find Anime!"; + + CrossRefType xrefType = (CrossRefType)crossRefType; + switch (xrefType) + { + case CrossRefType.MovieDB: + + // check if there are default images used associated + AniDB_Anime_DefaultImageRepository repDefaults = new AniDB_Anime_DefaultImageRepository(); + List images = repDefaults.GetByAnimeID(animeID); + foreach (AniDB_Anime_DefaultImage image in images) + { + if (image.ImageParentType == (int)JMMImageType.MovieDB_FanArt || + image.ImageParentType == (int)JMMImageType.MovieDB_Poster) + { + repDefaults.Delete(image.AniDB_Anime_DefaultImageID); + } + } + + MovieDBHelper.RemoveLinkAniDBMovieDB(animeID); + break; + } + + return ""; + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + return ex.Message; + } + } + + #endregion + + #region MovieDB + + public List SearchTheMovieDB(string criteria) + { + List results = new List(); + try + { + List movieResults = MovieDBHelper.Search(criteria); + + foreach (MovieDB_Movie_Result res in movieResults) + results.Add(res.ToContract()); + + return results; + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + return results; + } + } + + public List GetAllMovieDBPosters(int? movieID) + { + List allImages = new List(); + try + { + MovieDB_PosterRepository repImages = new MovieDB_PosterRepository(); + List allPosters = null; + if (movieID.HasValue) + allPosters = repImages.GetByMovieID(movieID.Value); + else + allPosters = repImages.GetAllOriginal(); + + foreach (MovieDB_Poster img in allPosters) + allImages.Add(img.ToContract()); + + return allImages; + + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + return allImages; + } + } + + public List GetAllMovieDBFanart(int? movieID) + { + List allImages = new List(); + try + { + MovieDB_FanartRepository repImages = new MovieDB_FanartRepository(); + List allFanart = null; + if (movieID.HasValue) + allFanart = repImages.GetByMovieID(movieID.Value); + else + allFanart = repImages.GetAllOriginal(); + + foreach (MovieDB_Fanart img in allFanart) + allImages.Add(img.ToContract()); + + return allImages; + + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + return allImages; + } + } + + #endregion + + public Contract_AnimeEpisode GetNextUnwatchedEpisode(int animeSeriesID, int userID) + { + try + { + AnimeEpisodeRepository repEps = new AnimeEpisodeRepository(); + AnimeSeriesRepository repAnimeSer = new AnimeSeriesRepository(); + + // 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 null; + + List epList = repEps.GetUnwatchedEpisodes(animeSeriesID, userID); + + AniDB_EpisodeRepository repAniEps = new AniDB_EpisodeRepository(); + List aniEpList = repAniEps.GetByAnimeID(series.AniDB_ID); + Dictionary dictAniEps = new Dictionary(); + foreach (AniDB_Episode aniep in aniEpList) + dictAniEps[aniep.EpisodeID] = aniep; + + List candidateEps = new List(); + foreach (AnimeEpisode ep in epList) + { + if (dictAniEps.ContainsKey(ep.AniDB_EpisodeID)) + { + AniDB_Episode anidbep = dictAniEps[ep.AniDB_EpisodeID]; + if (anidbep.EpisodeType == (int)enEpisodeType.Episode || anidbep.EpisodeType == (int)enEpisodeType.Special) + { + Contract_AnimeEpisode epContract = ep.ToContract(anidbep, new List(), ep.GetUserRecord(userID)); + candidateEps.Add(epContract); + } + } + } + + if (candidateEps.Count == 0) return null; + + // sort by episode type and number to find the next episode + List sortCriteria = new List(); + sortCriteria.Add(new SortPropOrFieldAndDirection("EpisodeType", false, SortType.eInteger)); + sortCriteria.Add(new SortPropOrFieldAndDirection("EpisodeNumber", false, SortType.eInteger)); + candidateEps = Sorting.MultiSort(candidateEps, sortCriteria); + + foreach (Contract_AnimeEpisode canEp in candidateEps) + { + // now refresh from the database to get file count + AnimeEpisode epFresh = repEps.GetByID(canEp.AnimeEpisodeID); + if (epFresh.VideoLocals.Count > 0) + return epFresh.ToContract(true, userID); + } + + return null; + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + return null; + } + } + + public Contract_AnimeEpisode GetNextUnwatchedEpisodeForGroup(int animeGroupID, int userID) + { + try + { + AnimeGroupRepository repGroups = new AnimeGroupRepository(); + AnimeEpisodeRepository repEps = new AnimeEpisodeRepository(); + AnimeSeriesRepository repAnimeSer = new AnimeSeriesRepository(); + + AnimeGroup grp = repGroups.GetByID(animeGroupID); + if (grp == null) return null; + + List allSeries = grp.AllSeries; + + List sortCriteria = new List(); + sortCriteria.Add(new SortPropOrFieldAndDirection("AirDate", false, SortType.eDateTime)); + allSeries = Sorting.MultiSort(allSeries, sortCriteria); + + foreach (AnimeSeries ser in allSeries) + { + Contract_AnimeEpisode contract = GetNextUnwatchedEpisode(ser.AnimeSeriesID, userID); + if (contract != null) return contract; + } + + return null; + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + return null; + } + } + + /// + /// Gets a list of episodes watched based on the most recently watched series + /// It will return the next episode to watch in the most recent 10 series + /// + /// + public List GetEpisodesToWatch_RecentlyWatched(int maxRecords, int jmmuserID) + { + List retEps = new List(); + try + { + AnimeEpisodeRepository repEps = new AnimeEpisodeRepository(); + AnimeSeriesRepository repAnimeSer = new AnimeSeriesRepository(); + AnimeSeries_UserRepository repSeriesUser = new AnimeSeries_UserRepository(); + JMMUserRepository repUsers = new JMMUserRepository(); + + JMMUser user = repUsers.GetByID(jmmuserID); + if (user == null) return retEps; + + // get a list of series that is applicable + List allSeriesUser = repSeriesUser.GetMostRecentlyWatched(jmmuserID); + foreach (AnimeSeries_User userRecord in allSeriesUser) + { + AnimeSeries series = repAnimeSer.GetByID(userRecord.AnimeSeriesID); + if (series == null) continue; + + if (!user.AllowedSeries(series)) continue; + + Contract_AnimeEpisode ep = GetNextUnwatchedEpisode(userRecord.AnimeSeriesID, jmmuserID); + if (ep != null) + { + retEps.Add(ep); + + // Lets only return the specified amount + if (retEps.Count == maxRecords) return retEps; + } + } + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + } + + return retEps; + } + + + /// + /// Delete a series, and everything underneath it (episodes, files) + /// + /// + /// also delete the physical files + /// + public string DeleteAnimeSeries(int animeSeriesID, bool deleteFiles) + { + try + { + AnimeEpisodeRepository repEps = new AnimeEpisodeRepository(); + AnimeSeriesRepository repAnimeSer = new AnimeSeriesRepository(); + VideoLocalRepository repVids = new VideoLocalRepository(); + AnimeGroupRepository repGroups = new AnimeGroupRepository(); + + AnimeSeries ser = repAnimeSer.GetByID(animeSeriesID); + if (ser == null) return "Series does not exist"; + + int animeGroupID = ser.AnimeGroupID; + + foreach (AnimeEpisode ep in ser.AnimeEpisodes) + { + foreach (VideoLocal vid in ep.VideoLocals) + { + if (deleteFiles) + { + logger.Info("Deleting video local record and file: {0}", vid.FullServerPath); + if (!File.Exists(vid.FullServerPath)) return "File could not be found"; + File.Delete(vid.FullServerPath); + } + CommandRequest_DeleteFileFromMyList cmdDel = new CommandRequest_DeleteFileFromMyList(vid.Hash, vid.FileSize); + cmdDel.Save(); + + repVids.Delete(vid.VideoLocalID); + } + + repEps.Delete(ep.AnimeEpisodeID); + } + repAnimeSer.Delete(ser.AnimeSeriesID); + + // finally update stats + AnimeGroup grp = repGroups.GetByID(animeGroupID); + if (grp != null) + { + grp.TopLevelAnimeGroup.UpdateStatsFromTopLevel(true, true, true); + StatsCache.Instance.UpdateUsingGroup(grp.TopLevelAnimeGroup.AnimeGroupID); + } + + return ""; + + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + return ex.Message; + } + + } + + + + public List GetSeriesWithMissingEpisodes(int maxRecords, int jmmuserID) + { + DateTime start = DateTime.Now; + AnimeSeriesRepository repSeries = new AnimeSeriesRepository(); + AniDB_AnimeRepository repAnime = new AniDB_AnimeRepository(); + JMMUserRepository repUsers = new JMMUserRepository(); + + + + // get all the series + List seriesContractList = new List(); + + try + { + JMMUser user = repUsers.GetByID(jmmuserID); + if (user == null) return seriesContractList; + + List series = repSeries.GetWithMissingEpisodes(); + + List animes = repAnime.GetAll(); + Dictionary dictAnimes = new Dictionary(); + foreach (AniDB_Anime anime in animes) + dictAnimes[anime.AnimeID] = anime; + + // tvdb + CrossRef_AniDB_TvDBRepository repCrossRef = new CrossRef_AniDB_TvDBRepository(); + List allCrossRefs = repCrossRef.GetAll(); + Dictionary dictCrossRefs = new Dictionary(); + foreach (CrossRef_AniDB_TvDB xref in allCrossRefs) + dictCrossRefs[xref.AnimeID] = xref; + + + // moviedb + CrossRef_AniDB_OtherRepository repOtherCrossRef = new CrossRef_AniDB_OtherRepository(); + List allOtherCrossRefs = repOtherCrossRef.GetAll(); + Dictionary dictMovieCrossRefs = new Dictionary(); + foreach (CrossRef_AniDB_Other xref in allOtherCrossRefs) + { + if (xref.CrossRefType == (int)CrossRefType.MovieDB) + dictMovieCrossRefs[xref.AnimeID] = xref; + } + + // user records + AnimeSeries_UserRepository repSeriesUser = new AnimeSeries_UserRepository(); + List userRecordList = repSeriesUser.GetByUserID(jmmuserID); + Dictionary dictUserRecords = new Dictionary(); + foreach (AnimeSeries_User serUser in userRecordList) + dictUserRecords[serUser.AnimeSeriesID] = serUser; + + int i = 1; + foreach (AnimeSeries aser in series) + { + if (!dictAnimes.ContainsKey(aser.AniDB_ID)) continue; + + AniDB_Anime anime = dictAnimes[aser.AniDB_ID]; + if (!user.AllowedAnime(anime)) continue; + + CrossRef_AniDB_TvDB xref = null; + if (dictCrossRefs.ContainsKey(aser.AniDB_ID)) xref = dictCrossRefs[aser.AniDB_ID]; + + CrossRef_AniDB_Other xrefMovie = null; + if (dictMovieCrossRefs.ContainsKey(aser.AniDB_ID)) xrefMovie = dictMovieCrossRefs[aser.AniDB_ID]; + + AnimeSeries_User userRec = null; + if (dictUserRecords.ContainsKey(aser.AnimeSeriesID)) + userRec = dictUserRecords[aser.AnimeSeriesID]; + + seriesContractList.Add(aser.ToContract(dictAnimes[aser.AniDB_ID], xref, xrefMovie, userRec)); + + if (i == maxRecords) break; + + i++; + } + + TimeSpan ts = DateTime.Now - start; + logger.Info("GetSeriesWithMissingEpisodes in {0} ms", ts.TotalMilliseconds); + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + } + return seriesContractList; + } + + public List GetMiniCalendar(int jmmuserID, int numberOfDays) + { + AniDB_AnimeRepository repAnime = new AniDB_AnimeRepository(); + JMMUserRepository repUsers = new JMMUserRepository(); + + // get all the series + List animeList = new List(); + + try + { + JMMUser user = repUsers.GetByID(jmmuserID); + if (user == null) return animeList; + + List animes = repAnime.GetForDate(DateTime.Today.AddDays(0 - numberOfDays), DateTime.Today.AddDays(numberOfDays)); + foreach (AniDB_Anime anime in animes) + { + bool useAnime = true; + + string[] cats = user.HideCategories.ToLower().Split(','); + string[] animeCats = anime.AllCategories.ToLower().Split('|'); + foreach (string cat in cats) + { + if (!string.IsNullOrEmpty(cat) && animeCats.Contains(cat)) + { + useAnime = false; + break; + } + } + + if (useAnime) + animeList.Add(anime.ToContract()); + } + + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + } + return animeList; + } + + /*public List GetMiniCalendar(int numberOfDays) + { + AniDB_AnimeRepository repAnime = new AniDB_AnimeRepository(); + JMMUserRepository repUsers = new JMMUserRepository(); + + // get all the series + List animeList = new List(); + + try + { + + List animes = repAnime.GetForDate(DateTime.Today.AddDays(0 - numberOfDays), DateTime.Today.AddDays(numberOfDays)); + foreach (AniDB_Anime anime in animes) + { + + animeList.Add(anime.ToContract()); + } + + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + } + return animeList; + }*/ + + public List GetAllUsers() + { + JMMUserRepository repUsers = new JMMUserRepository(); + + // get all the users + List userList = new List(); + + try + { + List users = repUsers.GetAll(); + foreach (JMMUser user in users) + userList.Add(user.ToContract()); + + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + } + return userList; + } + + public Contract_JMMUser AuthenticateUser(string username, string password) + { + JMMUserRepository repUsers = new JMMUserRepository(); + + try + { + JMMUser user = repUsers.AuthenticateUser(username, password); + if (user == null) return null; + + return user.ToContract(); + + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + return null; + } + } + + public string SaveUser(Contract_JMMUser user) + { + JMMUserRepository repUsers = new JMMUserRepository(); + + try + { + bool existingUser = false; + bool updateStats = false; + JMMUser jmmUser = null; + if (user.JMMUserID.HasValue) + { + jmmUser = repUsers.GetByID(user.JMMUserID.Value); + if (jmmUser == null) return "User not found"; + existingUser = true; + } + else + { + jmmUser = new JMMUser(); + updateStats = true; + } + + if (existingUser && jmmUser.IsAniDBUser != user.IsAniDBUser) + updateStats = true; + + jmmUser.HideCategories = user.HideCategories; + jmmUser.IsAniDBUser = user.IsAniDBUser; + jmmUser.IsTraktUser = user.IsTraktUser; + jmmUser.IsAdmin = user.IsAdmin; + jmmUser.Password = user.Password; + jmmUser.Username = user.Username; + + // make sure that at least one user is an admin + if (jmmUser.IsAdmin == 0) + { + bool adminExists = false; + List users = repUsers.GetAll(); + foreach (JMMUser userOld in users) + { + if (userOld.IsAdmin == 1) + { + if (existingUser) + { + if (userOld.JMMUserID != jmmUser.JMMUserID) adminExists = true; + } + else + adminExists = true; + + } + } + + if (!adminExists) return "At least one user must be an administrator"; + } + + repUsers.Save(jmmUser); + + // update stats + if (updateStats) + { + AnimeSeriesRepository repSeries = new AnimeSeriesRepository(); + foreach (AnimeSeries ser in repSeries.GetAll()) + ser.UpdateStats(true, false, true); + } + + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + return ex.Message; + } + + return ""; + } + + public string DeleteUser(int userID) + { + JMMUserRepository repUsers = new JMMUserRepository(); + + try + { + JMMUser jmmUser = repUsers.GetByID(userID); + if (jmmUser == null) return "User not found"; + + // make sure that at least one user is an admin + if (jmmUser.IsAdmin == 1) + { + bool adminExists = false; + List users = repUsers.GetAll(); + foreach (JMMUser userOld in users) + { + if (userOld.IsAdmin == 1) + { + if (userOld.JMMUserID != jmmUser.JMMUserID) adminExists = true; + } + } + + if (!adminExists) return "At least one user must be an administrator"; + } + + repUsers.Delete(userID); + + // delete all user records + AnimeSeries_UserRepository repSeries = new AnimeSeries_UserRepository(); + foreach (AnimeSeries_User ser in repSeries.GetByUserID(userID)) + repSeries.Delete(ser.AnimeSeries_UserID); + + AnimeGroup_UserRepository repGroup = new AnimeGroup_UserRepository(); + foreach (AnimeGroup_User grp in repGroup.GetByUserID(userID)) + repGroup.Delete(grp.AnimeGroup_UserID); + + AnimeEpisode_UserRepository repEpisode = new AnimeEpisode_UserRepository(); + foreach (AnimeEpisode_User ep in repEpisode.GetByUserID(userID)) + repEpisode.Delete(ep.AnimeEpisode_UserID); + + VideoLocal_UserRepository repVids = new VideoLocal_UserRepository(); + foreach (VideoLocal_User vid in repVids.GetByUserID(userID)) + repVids.Delete(vid.VideoLocal_UserID); + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + return ex.Message; + } + + return ""; + } + } + + +} diff --git a/JMMServer/JMMServiceImplementationImage.cs b/JMMServer/JMMServiceImplementationImage.cs new file mode 100644 index 000000000..656282f6e --- /dev/null +++ b/JMMServer/JMMServiceImplementationImage.cs @@ -0,0 +1,196 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.IO; +using JMMContracts; +using JMMServer.Repositories; +using JMMServer.Entities; +using NLog; +using JMMServer.Commands; + +namespace JMMServer +{ + public class JMMServiceImplementationImage : IJMMServerImage + { + private static Logger logger = LogManager.GetCurrentClassLogger(); + + public byte[] GetImage(string entityID, int entityType, bool thumnbnailOnly) + { + AniDB_AnimeRepository repAnime = new AniDB_AnimeRepository(); + TvDB_ImagePosterRepository repPosters = new TvDB_ImagePosterRepository(); + TvDB_EpisodeRepository repEpisodes = new TvDB_EpisodeRepository(); + TvDB_ImageFanartRepository repFanart = new TvDB_ImageFanartRepository(); + TvDB_ImageWideBannerRepository repWideBanners = new TvDB_ImageWideBannerRepository(); + + MovieDB_PosterRepository repMoviePosters = new MovieDB_PosterRepository(); + MovieDB_FanartRepository repMovieFanart = new MovieDB_FanartRepository(); + + Trakt_ImageFanartRepository repTraktFanart = new Trakt_ImageFanartRepository(); + Trakt_ImagePosterRepository repTraktPosters = new Trakt_ImagePosterRepository(); + Trakt_EpisodeRepository repTraktEpisodes = new Trakt_EpisodeRepository(); + + JMMImageType imageType = (JMMImageType)entityType; + + switch (imageType) + { + case JMMImageType.AniDB_Cover: + + AniDB_Anime anime = repAnime.GetByAnimeID(int.Parse(entityID)); + if (anime == null) return null; + + if (File.Exists(anime.PosterPath)) + return File.ReadAllBytes(anime.PosterPath); + else + { + logger.Trace("Could not find AniDB_Cover image: {0}", anime.PosterPath); + return null; + } + + case JMMImageType.TvDB_Cover: + + TvDB_ImagePoster poster = repPosters.GetByID(int.Parse(entityID)); + if (poster == null) return null; + + if (File.Exists(poster.FullImagePath)) + return File.ReadAllBytes(poster.FullImagePath); + else + { + logger.Trace("Could not find TvDB_Cover image: {0}", poster.FullImagePath); + return null; + } + + case JMMImageType.TvDB_Banner: + + TvDB_ImageWideBanner wideBanner = repWideBanners.GetByID(int.Parse(entityID)); + if (wideBanner == null) return null; + + if (File.Exists(wideBanner.FullImagePath)) + return File.ReadAllBytes(wideBanner.FullImagePath); + else + { + logger.Trace("Could not find TvDB_Banner image: {0}", wideBanner.FullImagePath); + return null; + } + + case JMMImageType.TvDB_Episode: + + TvDB_Episode ep = repEpisodes.GetByID(int.Parse(entityID)); + if (ep == null) return null; + + if (File.Exists(ep.FullImagePath)) + return File.ReadAllBytes(ep.FullImagePath); + else + { + logger.Trace("Could not find TvDB_Episode image: {0}", ep.FullImagePath); + return null; + } + + case JMMImageType.TvDB_FanArt: + + TvDB_ImageFanart fanart = repFanart.GetByID(int.Parse(entityID)); + if (fanart == null) return null; + + if (thumnbnailOnly) + { + if (File.Exists(fanart.FullThumbnailPath)) + return File.ReadAllBytes(fanart.FullThumbnailPath); + else + { + logger.Trace("Could not find TvDB_FanArt image: {0}", fanart.FullThumbnailPath); + return null; + } + } + else + { + if (File.Exists(fanart.FullImagePath)) + return File.ReadAllBytes(fanart.FullImagePath); + else + { + logger.Trace("Could not find TvDB_FanArt image: {0}", fanart.FullImagePath); + return null; + } + } + + case JMMImageType.MovieDB_Poster: + + MovieDB_Poster mPoster = repMoviePosters.GetByID(int.Parse(entityID)); + if (mPoster == null) return null; + + // now find only the original size + mPoster = repMoviePosters.GetByOnlineID(mPoster.ImageID, Constants.MovieDBImageSize.Original); + if (mPoster == null) return null; + + if (File.Exists(mPoster.FullImagePath)) + return File.ReadAllBytes(mPoster.FullImagePath); + else + { + logger.Trace("Could not find MovieDB_Poster image: {0}", mPoster.FullImagePath); + return null; + } + + case JMMImageType.MovieDB_FanArt: + + MovieDB_Fanart mFanart = repMovieFanart.GetByID(int.Parse(entityID)); + if (mFanart == null) return null; + + mFanart = repMovieFanart.GetByOnlineID(mFanart.ImageID, Constants.MovieDBImageSize.Original); + if (mFanart == null) return null; + + if (File.Exists(mFanart.FullImagePath)) + return File.ReadAllBytes(mFanart.FullImagePath); + else + { + logger.Trace("Could not find MovieDB_FanArt image: {0}", mFanart.FullImagePath); + return null; + } + + case JMMImageType.Trakt_Fanart: + + Trakt_ImageFanart tFanart = repTraktFanart.GetByID(int.Parse(entityID)); + if (tFanart == null) return null; + + if (File.Exists(tFanart.FullImagePath)) + return File.ReadAllBytes(tFanart.FullImagePath); + else + { + logger.Trace("Could not find Trakt_Fanart image: {0}", tFanart.FullImagePath); + return null; + } + + case JMMImageType.Trakt_Poster: + + Trakt_ImagePoster tPoster = repTraktPosters.GetByID(int.Parse(entityID)); + if (tPoster == null) return null; + + if (File.Exists(tPoster.FullImagePath)) + return File.ReadAllBytes(tPoster.FullImagePath); + else + { + logger.Trace("Could not find Trakt_Poster image: {0}", tPoster.FullImagePath); + return null; + } + + case JMMImageType.Trakt_Episode: + + Trakt_Episode tEpisode = repTraktEpisodes.GetByID(int.Parse(entityID)); + if (tEpisode == null) return null; + + if (File.Exists(tEpisode.FullImagePath)) + return File.ReadAllBytes(tEpisode.FullImagePath); + else + { + logger.Trace("Could not find Trakt_Episode image: {0}", tEpisode.FullImagePath); + return null; + } + + default: + + return null; + } + + + + } + } +} diff --git a/JMMServer/Languages.cs b/JMMServer/Languages.cs new file mode 100644 index 000000000..5d6f221f7 --- /dev/null +++ b/JMMServer/Languages.cs @@ -0,0 +1,115 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace JMMServer +{ + public class Languages + { + public static string[] AllLanguages + { + get + { + string[] lans = new string[] { "EN", "X-JAT", "JA", "AR", "BD", "BG", "CA", "CS", "CZ" + , "DA", "DK", "DE", "EL", "ES", "ET", "FI", "FR", "GL", "GR", "HE", "HU", "IL", "IT" + , "KO", "LT", "MN", "MS", "MY", "NL", "NO", "PL", "PT", "PT-BR", "RO", "RU", "SK", "SL" + , "SR", "SV", "SE", "TH", "TR", "UK", "UA", "VI", "ZH", "ZH-HANS", "ZH-HANT"}; + return lans; + } + } + + public static List AllNamingLanguages + { + get + { + List lans = new List(); + + foreach (string lan in Languages.AllLanguages) + { + NamingLanguage nlan = new NamingLanguage(lan); + lans.Add(nlan); + } + + return lans; + } + } + + public static string GetLanguageDescription(string language) + { + switch (language.Trim().ToUpper()) + { + case "EN": return "English (en)"; + case "X-JAT": return "Romaji (x-jat)"; + case "JA": return "Kanji"; + case "AR": return "Arabic (ar)"; + case "BD": return "Bangladesh (bd)"; + case "BG": return "Bulgarian (bd)"; + case "CA": return "Canadian-French (ca)"; + case "CS": return "Czech (cs)"; + case "CZ": return "Czech (cz)"; + case "DA": return "Danish (da)"; + case "DK": return "Danish (dk)"; + case "DE": return "German (de)"; + case "EL": return "Greek (el)"; + case "ES": return "Spanish (es)"; + case "ET": return "Estonian (et)"; + case "FI": return "Finnish (fi)"; + case "FR": return "French (fr)"; + case "GL": return "Galician (gl)"; + case "GR": return "Greek (gr)"; + case "HE": return "Hebrew (he)"; + case "HU": return "Hungarian (hu)"; + case "IL": return "Hebrew (il)"; + case "IT": return "Italian (it)"; + case "KO": return "Korean (ko)"; + case "LT": return "Lithuanian (lt)"; + case "MN": return "Mongolian (mn)"; + case "MS": return "Malaysian (ms)"; + case "MY": return "Malaysian (my)"; + case "NL": return "Dutch (nl)"; + case "NO": return "Norwegian (no)"; + case "PL": return "Polish (pl)"; + case "PT": return "Portuguese (pt)"; + case "PT-BR": return "Portuguese - Brazil (pt-br)"; + case "RO": return "Romanian (ro)"; + case "RU": return "Russian (ru)"; + case "SK": return "Slovak (sk)"; + case "SL": return "Slovenian (sl)"; + case "SR": return "Serbian (sr)"; + case "SV": return "Swedish (sv)"; + case "SE": return "Swedish (se)"; + case "TH": return "Thai (th)"; + case "TR": return "Turkish (tr)"; + case "UK": return "Ukrainian (uk)"; + case "UA": return "Ukrainian (ua)"; + case "VI": return "Vietnamese (vi)"; + case "ZH": return "Chinese"; + case "ZH-HANS": return "Chinese (zh-hans)"; + case "ZH-HANT": return "Chinese (zh-hant)"; + default: return language; + + } + } + + public static List PreferredNamingLanguages + { + get + { + List lans = new List(); + + string[] slans = ServerSettings.LanguagePreference.Split(','); + + foreach (string lan in slans) + { + if (string.IsNullOrEmpty(lan)) continue; + if (lan.Trim().Length < 2) continue; + NamingLanguage nlan = new NamingLanguage(lan); + lans.Add(nlan); + } + + return lans; + } + } + } +} diff --git a/JMMServer/MainWindow.xaml b/JMMServer/MainWindow.xaml new file mode 100644 index 000000000..165a1915b --- /dev/null +++ b/JMMServer/MainWindow.xaml @@ -0,0 +1,228 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/JMMServer/MainWindow.xaml.cs b/JMMServer/MainWindow.xaml.cs new file mode 100644 index 000000000..ce4bb213b --- /dev/null +++ b/JMMServer/MainWindow.xaml.cs @@ -0,0 +1,1120 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Databases; +using NHibernate; +using JMMServer.Commands; +using JMMServer.Repositories; +using JMMServer.Entities; +using NLog; +using System.Threading; +using System.IO; +using JMMFileHelper; +using System.ServiceModel; +using System.ServiceModel.Description; +using JMMContracts; +using JMMServer.WebCache; +using System.ComponentModel; +using System.ServiceModel.Channels; +using System.Runtime.Serialization; +using System.Xml; +using JMMServer.AniDB_API.Commands; +using System.Windows; +using NLog.Config; +using System.Collections.ObjectModel; +using System.Windows.Input; +using JMMServer.Providers.TvDB; +using JMMServer.Providers.MovieDB; +using JMMServer.Providers.TraktTV; + +namespace JMMServer +{ + /// + /// Interaction logic for MainWindow.xaml + /// + public partial class MainWindow : Window + { + private System.Windows.Forms.NotifyIcon TippuTrayNotify; + private System.Windows.Forms.ContextMenuStrip ctxTrayMenu; + private bool isAppExiting = false; + private static Logger logger = LogManager.GetCurrentClassLogger(); + + private static Uri baseAddress = new Uri("http://localhost:8111/JMMServer"); + private static Uri baseAddressImage = new Uri("http://localhost:8111/JMMServerImage"); + private static Uri baseAddressBinary = new Uri("http://localhost:8111/JMMServerBinary"); + private static Uri baseAddressTCP = new Uri("net.tcp://localhost:8112/JMMServerTCP"); + private static ServiceHost host = null; + private static ServiceHost hostTCP = null; + private static ServiceHost hostImage = null; + private static ServiceHost hostBinary = null; + + private static BackgroundWorker workerImport = new BackgroundWorker(); + private static BackgroundWorker workerScanFolder = new BackgroundWorker(); + private static BackgroundWorker workerRemoveMissing = new BackgroundWorker(); + private static System.Timers.Timer autoUpdateTimer = null; + private static List watcherVids = null; + + BackgroundWorker downloadImagesWorker = new BackgroundWorker(); + + + public MainWindow() + { + InitializeComponent(); + + ConfigurationItemFactory.Default.Targets.RegisterDefinition("InternalCache", typeof(JMMServer.CachedNLogTarget)); + + //Create an instance of the NotifyIcon Class + TippuTrayNotify = new System.Windows.Forms.NotifyIcon(); + + // This icon file needs to be in the bin folder of the application + TippuTrayNotify = new System.Windows.Forms.NotifyIcon(); + Stream iconStream = Application.GetResourceStream(new Uri("pack://application:,,,/JMMServer;component/db.ico")).Stream; + TippuTrayNotify.Icon = new System.Drawing.Icon(iconStream); + iconStream.Dispose(); + + //show the Tray Notify Icon + TippuTrayNotify.Visible = true; + + CreateMenus(); + + this.Closing += new System.ComponentModel.CancelEventHandler(MainWindow_Closing); + this.StateChanged += new EventHandler(MainWindow_StateChanged); + TippuTrayNotify.MouseDoubleClick += new System.Windows.Forms.MouseEventHandler(TippuTrayNotify_MouseDoubleClick); + + btnToolbarShutdown.Click += new RoutedEventHandler(btnToolbarShutdown_Click); + btnHasherPause.Click += new RoutedEventHandler(btnHasherPause_Click); + btnHasherResume.Click += new RoutedEventHandler(btnHasherResume_Click); + btnGeneralPause.Click += new RoutedEventHandler(btnGeneralPause_Click); + btnGeneralResume.Click += new RoutedEventHandler(btnGeneralResume_Click); + btnImagesPause.Click += new RoutedEventHandler(btnImagesPause_Click); + btnImagesResume.Click += new RoutedEventHandler(btnImagesResume_Click); + + btnRemoveMissingFiles.Click += new RoutedEventHandler(btnRemoveMissingFiles_Click); + btnRunImport.Click += new RoutedEventHandler(btnRunImport_Click); + btnSyncMyList.Click += new RoutedEventHandler(btnSyncMyList_Click); + btnSyncVotes.Click += new RoutedEventHandler(btnSyncVotes_Click); + btnUpdateTvDBInfo.Click += new RoutedEventHandler(btnUpdateTvDBInfo_Click); + btnUpdateAllStats.Click += new RoutedEventHandler(btnUpdateAllStats_Click); + btnSyncTrakt.Click += new RoutedEventHandler(btnSyncTrakt_Click); + + this.Loaded += new RoutedEventHandler(MainWindow_Loaded); + downloadImagesWorker.DoWork += new DoWorkEventHandler(downloadImagesWorker_DoWork); + + StartUp(); + } + + private void DownloadAllImages() + { + if (!downloadImagesWorker.IsBusy) + downloadImagesWorker.RunWorkerAsync(); + } + + void downloadImagesWorker_DoWork(object sender, DoWorkEventArgs e) + { + Importer.RunImport_GetImages(); + } + + void MainWindow_Loaded(object sender, RoutedEventArgs e) + { + ServerInfo.Instance.RefreshImportFolders(); + + //Importer.CheckForTvDBUpdates(true); + //TvDBHelper.LinkAniDBTvDB(6751, 117851, 1, false); + //JMMService.TvdbHelper.UpdateAllInfoAndImages(134181, true); + + //CommandRequest_TvDBSearchAnime cmd = new CommandRequest_TvDBSearchAnime(7103, false); + //cmd.ProcessCommand(); + + //List movies = MovieDBHelper.Search("Naruto"); + //XMLService.Get_CrossRef_AniDB_Other(1, CrossRefType.MovieDB); + //XMLService.Delete_CrossRef_AniDB_Other(1, CrossRefType.MovieDB); + + //CommandRequest_MovieDBSearchAnime cmd = new CommandRequest_MovieDBSearchAnime(5178, false); + //cmd.ProcessCommand(); + + //MovieDBHelper.ScanForMatches(); + + //JMMServiceImplementation jmm = new JMMServiceImplementation(); + //jmm.GetNextUnwatchedEpisode(157); + + //AnimeSeriesRepository rep = new AnimeSeriesRepository(); + //AnimeSeries ser = rep.GetByAnimeID(8148); + //ser.UpdateStats(true, true, true); + + //TraktTVHelper.GetShowInfo(117851); + //TraktTVHelper.SearchShow("narutobummm"); + //TraktTVHelper.GetShowInfo("never find this"); + //CommandRequest_TraktSearchAnime cmd = new CommandRequest_TraktSearchAnime(8039, true); + //cmd.ProcessCommand(); + + //TraktTVHelper.ScanForMatches(); + + //Trakt_ImageFanartRepository repFanart = new Trakt_ImageFanartRepository(); + //Trakt_ImageFanart fanart = repFanart.GetByShowIDAndSeason(5, 1); + + //Trakt_EpisodeRepository rep = new Trakt_EpisodeRepository(); + //Trakt_Episode ep = rep.GetByID(31); + //Console.Write(ep.FullImagePath); + + //AnimeEpisodeRepository rep = new AnimeEpisodeRepository(); + //AnimeEpisode ep = rep.GetByAniDBEpisodeID(85084); + //TraktTVHelper.MarkEpisodeWatched(ep); + + } + + + + #region UI events and methods + + private void CommandBinding_ScanFolder(object sender, ExecutedRoutedEventArgs e) + { + object obj = e.Parameter; + if (obj == null) return; + + try + { + if (obj.GetType() == typeof(ImportFolder)) + { + ImportFolder fldr = (ImportFolder)obj; + + ScanFolder(fldr.ImportFolderID); + MessageBox.Show("Process is Running", "Success", MessageBoxButton.OK, MessageBoxImage.Information); + } + } + catch (Exception ex) + { + Utils.ShowErrorMessage(ex); + } + + } + + void btnUpdateTvDBInfo_Click(object sender, RoutedEventArgs e) + { + Importer.RunImport_UpdateTvDB(false); + MessageBox.Show("Updates are queued", "Success", MessageBoxButton.OK, MessageBoxImage.Information); + } + + void btnUpdateAllStats_Click(object sender, RoutedEventArgs e) + { + this.Cursor = Cursors.Wait; + Importer.UpdateAllStats(); + this.Cursor = Cursors.Arrow; + MessageBox.Show("Stats have been updated", "Success", MessageBoxButton.OK, MessageBoxImage.Information); + } + + void btnSyncVotes_Click(object sender, RoutedEventArgs e) + { + CommandRequest_SyncMyVotes cmdVotes = new CommandRequest_SyncMyVotes(); + cmdVotes.Save(); + MessageBox.Show("Command added to queue", "Success", MessageBoxButton.OK, MessageBoxImage.Information); + //JMMService.AnidbProcessor.IsBanned = true; + } + + void btnSyncMyList_Click(object sender, RoutedEventArgs e) + { + SyncMyList(); + MessageBox.Show("Sync is Running", "Success", MessageBoxButton.OK, MessageBoxImage.Information); + } + + void btnSyncTrakt_Click(object sender, RoutedEventArgs e) + { + CommandRequest_TraktSyncCollection cmd = new CommandRequest_TraktSyncCollection(true); + cmd.Save(); + MessageBox.Show("Sync is Queued", "Success", MessageBoxButton.OK, MessageBoxImage.Information); + } + + void btnRunImport_Click(object sender, RoutedEventArgs e) + { + RunImport(); + MessageBox.Show("Import is Running", "Success", MessageBoxButton.OK, MessageBoxImage.Information); + } + + void btnRemoveMissingFiles_Click(object sender, RoutedEventArgs e) + { + RemoveMissingFiles(); + MessageBox.Show("Process is Running", "Success", MessageBoxButton.OK, MessageBoxImage.Information); + } + + void btnGeneralResume_Click(object sender, RoutedEventArgs e) + { + JMMService.CmdProcessorGeneral.Paused = false; + } + + void btnGeneralPause_Click(object sender, RoutedEventArgs e) + { + JMMService.CmdProcessorGeneral.Paused = true; + } + + void btnHasherResume_Click(object sender, RoutedEventArgs e) + { + JMMService.CmdProcessorHasher.Paused = false; + } + + void btnHasherPause_Click(object sender, RoutedEventArgs e) + { + JMMService.CmdProcessorHasher.Paused = true; + } + + void btnImagesResume_Click(object sender, RoutedEventArgs e) + { + JMMService.CmdProcessorImages.Paused = false; + } + + void btnImagesPause_Click(object sender, RoutedEventArgs e) + { + JMMService.CmdProcessorImages.Paused = true; + } + + void btnToolbarShutdown_Click(object sender, RoutedEventArgs e) + { + isAppExiting = true; + this.Close(); + TippuTrayNotify.Visible = false; + TippuTrayNotify.Dispose(); + } + + #endregion + + private void StartUp() + { + try + { + workerImport.WorkerReportsProgress = true; + workerImport.WorkerSupportsCancellation = true; + workerImport.DoWork += new DoWorkEventHandler(workerImport_DoWork); + + workerScanFolder.WorkerReportsProgress = true; + workerScanFolder.WorkerSupportsCancellation = true; + workerScanFolder.DoWork += new DoWorkEventHandler(workerScanFolder_DoWork); + + workerRemoveMissing.WorkerReportsProgress = true; + workerRemoveMissing.WorkerSupportsCancellation = true; + workerRemoveMissing.DoWork += new DoWorkEventHandler(workerRemoveMissing_DoWork); + + if (!DatabaseHelper.InitDB()) return; + + //init session factory + ISessionFactory temp = JMMService.SessionFactory; + + SetupAniDBProcessor(); + StartHost(); + StartImageHost(); + StartBinaryHost(); + //StartTCPHost(); + + //CreateImportFolders_Test(); + //CreateImportFolders2(); + + // Load all stats + StatsCache.Instance.InitStats(); + + JMMService.CmdProcessorGeneral.Init(); + JMMService.CmdProcessorHasher.Init(); + JMMService.CmdProcessorImages.Init(); + + //AdhocRepository rep = new AdhocRepository(); + //Dictionary dictStats = rep.GetAllVideoQualityByAnime(); + //Dictionary vidq = rep.GetAllVideoQualityByGroup(); + //StatsCache.Instance.UpdateUsingGroup(7); + + //JMMService.TvdbHelper.SearchSeries("Imouto"); + //TvDB_Series tvser = TvDBHelper.GetSeriesInfoOnline(78857); + + + /*CrossRef_AniDB_TvDB xref = new CrossRef_AniDB_TvDB(); + xref.AnimeID = 6107; + xref.TvDBID = 85249; + xref.TvDBSeasonNumber = 1; + XMLService.Send_CrossRef_AniDB_TvDB(xref);*/ + + //CrossRef_AniDB_TvDB xref = XMLService.Get_CrossRef_AniDB_TvDB(6107); + + #region Test Code + + //VideoLocalRepository repVids = new VideoLocalRepository(); + //VideoLocal vlocal = repVids.GetByID(1); + //if (vlocal == null) return; + + //XMLService.Send_FileHash(vlocal); + + //XMLService.Get_FileHash(@"Zettai Shogeki - Platonic Heart\[Chihiro]_Zettai_Shogeki_~Platonic_Heart~_01v2_[h264][A057F3B2].mkv", 240600302); + + //CommandRequest_GetCalendar cmd = new CommandRequest_GetCalendar(true); + //cmd.Save(); + + //CommandRequest_GetReleaseGroup cmd = new CommandRequest_GetReleaseGroup(3938, true); + //cmd.Save(); + + //CommandRequest_SyncMyList cmd = new CommandRequest_SyncMyList(true); + //cmd.ProcessCommand(); + + //OMMService.AnidbProcessor.GetMyListFileStatus(838983); + + //CommandRequest_GetReleaseGroupStatus cmd = new CommandRequest_GetReleaseGroupStatus(7948, false); + //cmd.Save(); + + //CommandRequest_AddFileToMyList cmd = new CommandRequest_AddFileToMyList("8E451EA0C43FC94B51A8B638425D95BA"); + //cmd.Save(); + + //CommandRequest_GetAnimeHTTP cmd = new CommandRequest_GetAnimeHTTP(6313, false); + //cmd.Save(); + + //VideoLocalRepository repVids = new VideoLocalRepository(); + //VideoLocal vid = repVids.GetByHash("0866E8D605F4DA96222A529A066CC35E"); + //repVids.Delete(vid.VideoLocalID); + //vid.ToggleWatchedStatus(true, true); + + + + //OMMServiceImplementation omm = new OMMServiceImplementation(); + //omm.GetAllSeries(); + + //ReorganiseGundam(); + //HashTest(); + //HashTest2(); + //ReviewsTest(); + + //CommandRequest_GetAnimeHTTP cmd = new CommandRequest_GetAnimeHTTP(7671, true, false); + //cmd.Save(); + + //ProcessFileTest(); + //ProcessFiles(); + //ReadFiles(); + + //CreateTestCommandRequests(); + //CreateSubGroupsTest(); + //UpdateStatsTest(); + + //WebCacheTest(); + + //OMMService.AnidbProcessor.Login(); + #endregion + + // timer for automatic updates + autoUpdateTimer = new System.Timers.Timer(); + autoUpdateTimer.AutoReset = true; + autoUpdateTimer.Interval = 10 * 60 * 1000; // 5 minutes * 60 seconds + autoUpdateTimer.Elapsed += new System.Timers.ElapsedEventHandler(autoUpdateTimer_Elapsed); + autoUpdateTimer.Start(); + + StartWatchingFiles(); + + DownloadAllImages(); + if (ServerSettings.RunImportOnStart) RunImport(); + + + //Console.WriteLine("Press ENTER to EXIT"); + //Console.ReadKey(); + + + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + } + } + + #region Tray Minimize + + void MainWindow_StateChanged(object sender, EventArgs e) + { + if (this.WindowState == System.Windows.WindowState.Minimized) this.Hide(); + } + + void TippuTrayNotify_MouseDoubleClick(object sender, System.Windows.Forms.MouseEventArgs e) + { + this.Show(); + } + + private void CreateMenus() + { + //Create a object for the context menu + ctxTrayMenu = new System.Windows.Forms.ContextMenuStrip(); + + //Add the Menu Item to the context menu + System.Windows.Forms.ToolStripMenuItem mnuShow = new System.Windows.Forms.ToolStripMenuItem(); + mnuShow.Text = "Show"; + mnuShow.Click += new EventHandler(mnuShow_Click); + ctxTrayMenu.Items.Add(mnuShow); + + //Add the Menu Item to the context menu + System.Windows.Forms.ToolStripMenuItem mnuExit = new System.Windows.Forms.ToolStripMenuItem(); + mnuExit.Text = "Shut Down"; + mnuExit.Click += new EventHandler(mnuExit_Click); + ctxTrayMenu.Items.Add(mnuExit); + + //Add the Context menu to the Notify Icon Object + TippuTrayNotify.ContextMenuStrip = ctxTrayMenu; + } + + void mnuShow_Click(object sender, EventArgs e) + { + this.Show(); + } + + private void ShutDown() + { + StopWatchingFiles(); + AniDBDispose(); + StopHost(); + } + + void MainWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e) + { + //When the application is closed, check wether the application is + //exiting from menu or forms close button + if (!isAppExiting) + { + //if the forms close button is triggered, cancel the event and hide the form + //then show the notification ballon tip + e.Cancel = true; + this.Hide(); + TippuTrayNotify.BalloonTipIcon = System.Windows.Forms.ToolTipIcon.Info; + TippuTrayNotify.BalloonTipTitle = "Tippu Tray Notify"; + TippuTrayNotify.BalloonTipText = "Tippu Tray Notify has been minimized to the system tray. To open the application, double-click the icon in the system tray."; + //TippuTrayNotify.ShowBalloonTip(400); + } + else + { + ShutDown(); + } + } + + void mnuExit_Click(object sender, EventArgs e) + { + isAppExiting = true; + this.Close(); + TippuTrayNotify.Visible = false; + TippuTrayNotify.Dispose(); + } + + #endregion + + static void autoUpdateTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) + { + Importer.CheckForCalendarUpdate(false); + Importer.CheckForAnimeUpdate(false); + Importer.CheckForTvDBUpdates(false); + Importer.CheckForMyListSyncUpdate(false); + Importer.CheckForTraktAllSeriesUpdate(false); + Importer.CheckForTraktSyncUpdate(false); + } + + public static void StartWatchingFiles() + { + if (!ServerSettings.WatchForNewFiles) return; + + StopWatchingFiles(); + + watcherVids = new List(); + + ImportFolderRepository repNetShares = new ImportFolderRepository(); + foreach (ImportFolder share in repNetShares.GetAll()) + { + try + { + if (Directory.Exists(share.ImportFolderLocation)) + { + logger.Info("Watching ImportFolder: {0} || {1}", share.ImportFolderName, share.ImportFolderLocation); + FileSystemWatcher fsw = new FileSystemWatcher(share.ImportFolderLocation); + fsw.IncludeSubdirectories = true; + fsw.Created += new FileSystemEventHandler(fsw_Created); + fsw.EnableRaisingEvents = true; + watcherVids.Add(fsw); + } + else + { + logger.Error("ImportFolder not found for watching: {0} || {1}", share.ImportFolderName, share.ImportFolderLocation); + } + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + } + } + + + + /*if (settings.DropFolder.Trim().Length > 0 && settings.DropFolderDestination.Trim().Length > 0) + { + FileSystemWatcher fsw = new FileSystemWatcher(settings.DropFolder); + fsw.IncludeSubdirectories = true; + fsw.Created += new FileSystemEventHandler(fsw_Created); + fsw.EnableRaisingEvents = true; + watcherVids.Add(fsw); + }*/ + } + + public static void StopWatchingFiles() + { + if (watcherVids == null) return; + + foreach (FileSystemWatcher fsw in watcherVids) + { + fsw.EnableRaisingEvents = false; + } + } + + static void fsw_Created(object sender, FileSystemEventArgs e) + { + logger.Info("New file created: {0}: {1}", e.FullPath, e.ChangeType); + if (e.ChangeType == WatcherChangeTypes.Created) + { + CommandRequest_HashFile cmd = new CommandRequest_HashFile(e.FullPath, false); + cmd.Save(); + } + } + + public static void ScanFolder(int importFolderID) + { + if (!workerScanFolder.IsBusy) + workerScanFolder.RunWorkerAsync(importFolderID); + } + + public static void RunImport() + { + if (!workerImport.IsBusy) + workerImport.RunWorkerAsync(); + } + + public static void RemoveMissingFiles() + { + if (!workerRemoveMissing.IsBusy) + workerRemoveMissing.RunWorkerAsync(); + } + + public static void SyncMyList() + { + Importer.CheckForMyListSyncUpdate(true); + } + + static void workerRemoveMissing_DoWork(object sender, DoWorkEventArgs e) + { + try + { + Importer.RemoveRecordsWithoutPhysicalFiles(); + } + catch (Exception ex) + { + logger.ErrorException(ex.Message, ex); + } + } + + static void workerScanFolder_DoWork(object sender, DoWorkEventArgs e) + { + try + { + Importer.RunImport_ScanFolder(int.Parse(e.Argument.ToString())); + + } + catch (Exception ex) + { + logger.ErrorException(ex.Message, ex); + } + } + + static void workerImport_DoWork(object sender, DoWorkEventArgs e) + { + + try + { + Importer.RunImport_NewFiles(); + Importer.RunImport_IntegrityCheck(); + + // TODO drop folder + + // TvDB association checks + Importer.RunImport_ScanTvDB(); + + // Trakt association checks + Importer.RunImport_ScanTrakt(); + + // MovieDB association checks + Importer.RunImport_ScanMovieDB(); + + // Check for missing images + Importer.RunImport_GetImages(); + + } + catch (Exception ex) + { + logger.ErrorException(ex.Message, ex); + } + } + + private static void StartHost() + { + // Create the ServiceHost. + host = new ServiceHost(typeof(JMMServiceImplementation), baseAddress); + // Enable metadata publishing. + ServiceMetadataBehavior smb = new ServiceMetadataBehavior(); + smb.HttpGetEnabled = true; + smb.MetadataExporter.PolicyVersion = PolicyVersion.Policy15; + host.Description.Behaviors.Add(smb); + + BasicHttpBinding binding = new BasicHttpBinding(); + //binding.MessageEncoding = WSMessageEncoding.Mtom; + binding.MaxReceivedMessageSize = 20971520; + binding.MaxBufferPoolSize = 20971520; // 20 megabytes + binding.MaxBufferSize = 20971520; // 20 megabytes + binding.SendTimeout = new TimeSpan(0, 0, 30); + + host.AddServiceEndpoint(typeof(IJMMServer), binding, baseAddress); + + // Open the ServiceHost to start listening for messages. Since + // no endpoints are explicitly configured, the runtime will create + // one endpoint per base address for each service contract implemented + // by the service. + host.Open(); + logger.Trace("Now Accepting client connections..."); + } + + private static void StartTCPHost() + { + // Create the ServiceHost. + hostTCP = new ServiceHost(typeof(JMMServiceImplementation), baseAddressTCP); + // Enable metadata publishing. + + ServiceMetadataBehavior behavior = new ServiceMetadataBehavior(); + + hostTCP.Description.Behaviors.Add(behavior); + hostTCP.AddServiceEndpoint(typeof(IMetadataExchange), MetadataExchangeBindings.CreateMexNamedPipeBinding(), "net.pipe://localhost/service/mex/"); + + + NetTcpBinding binding = new NetTcpBinding(); + binding.ReceiveTimeout = new TimeSpan(30, 0, 30); + binding.SendTimeout = new TimeSpan(30, 0, 30); + binding.OpenTimeout = new TimeSpan(30, 0, 30); + binding.CloseTimeout = new TimeSpan(30, 0, 30); + binding.MaxBufferPoolSize = int.MaxValue; + binding.MaxBufferSize = int.MaxValue; + binding.MaxReceivedMessageSize = int.MaxValue; + + + XmlDictionaryReaderQuotas quotas = new XmlDictionaryReaderQuotas(); + quotas.MaxArrayLength = int.MaxValue; + quotas.MaxBytesPerRead = int.MaxValue; + quotas.MaxDepth = int.MaxValue; + quotas.MaxNameTableCharCount = int.MaxValue; + quotas.MaxStringContentLength = int.MaxValue; + + binding.ReaderQuotas = quotas; + + hostTCP.AddServiceEndpoint(typeof(IJMMServer), binding, baseAddressTCP); + + + + hostTCP.Open(); + logger.Trace("Now Accepting client connections..."); + } + + private static void StartBinaryHost() + { + BinaryMessageEncodingBindingElement encoding = new BinaryMessageEncodingBindingElement(); + HttpTransportBindingElement transport = new HttpTransportBindingElement(); + Binding binding = new CustomBinding(encoding, transport); + binding.Name = "BinaryBinding"; + + + //binding.MessageEncoding = WSMessageEncoding.Mtom; + //binding.MaxReceivedMessageSize = 2147483647; + + + // Create the ServiceHost. + hostBinary = new ServiceHost(typeof(JMMServiceImplementation), baseAddressBinary); + // Enable metadata publishing. + ServiceMetadataBehavior smb = new ServiceMetadataBehavior(); + smb.HttpGetEnabled = true; + smb.MetadataExporter.PolicyVersion = PolicyVersion.Policy15; + hostBinary.Description.Behaviors.Add(smb); + + hostBinary.AddServiceEndpoint(typeof(IJMMServer), binding, baseAddressBinary); + + // Open the ServiceHost to start listening for messages. Since + // no endpoints are explicitly configured, the runtime will create + // one endpoint per base address for each service contract implemented + // by the service. + hostBinary.Open(); + logger.Trace("Now Accepting client connections for test host..."); + } + + private static void StartImageHost() + { + BasicHttpBinding binding = new BasicHttpBinding(); + binding.MessageEncoding = WSMessageEncoding.Mtom; + binding.MaxReceivedMessageSize = 2147483647; + binding.Name = "httpLargeMessageStream"; + + + // Create the ServiceHost. + hostImage = new ServiceHost(typeof(JMMServiceImplementationImage), baseAddressImage); + // Enable metadata publishing. + ServiceMetadataBehavior smb = new ServiceMetadataBehavior(); + smb.HttpGetEnabled = true; + smb.MetadataExporter.PolicyVersion = PolicyVersion.Policy15; + hostImage.Description.Behaviors.Add(smb); + + hostImage.AddServiceEndpoint(typeof(IJMMServerImage), binding, baseAddressImage); + + // Open the ServiceHost to start listening for messages. Since + // no endpoints are explicitly configured, the runtime will create + // one endpoint per base address for each service contract implemented + // by the service. + hostImage.Open(); + logger.Trace("Now Accepting client connections for images..."); + } + + private static void ReadFiles() + { + // Steps for processing a file + // 1. Check if it is a video file + // 2. Check if we have a VideoLocal record for that file + // ......... + + // get a complete list of files + List fileList = new List(); + ImportFolderRepository repNetShares = new ImportFolderRepository(); + foreach (ImportFolder share in repNetShares.GetAll()) + { + logger.Debug("Import Folder: {0} || {1}", share.ImportFolderName, share.ImportFolderLocation); + fileList.AddRange(Directory.GetFiles(share.ImportFolderLocation, "*.*", SearchOption.AllDirectories)); + } + + + // get a list of all the shares we are looking at + int filesFound = 0, videosFound = 0; + int i = 0; + + // get a list of all files in the share + foreach (string fileName in fileList) + { + i++; + filesFound++; + + if (fileName.Contains("Sennou")) + { + logger.Info("Processing File {0}/{1} --- {2}", i, fileList.Count, fileName); + } + + if (!FileHashHelper.IsVideo(fileName)) continue; + + videosFound++; + + + + } + logger.Debug("Found {0} files", filesFound); + logger.Debug("Found {0} videos", videosFound); + } + + private static void StopHost() + { + // Close the ServiceHost. + //host.Close(); + + if (hostImage != null) + hostImage.Close(); + + if (hostBinary != null) + hostBinary.Close(); + } + + private static void SetupAniDBProcessor() + { + JMMService.AnidbProcessor.Init(ServerSettings.AniDB_Username, ServerSettings.AniDB_Password, ServerSettings.AniDB_ServerAddress, + ServerSettings.AniDB_ServerPort, ServerSettings.AniDB_ClientPort); + } + + private static void AniDBDispose() + { + logger.Info("Disposing..."); + if (JMMService.AnidbProcessor != null) + { + JMMService.AnidbProcessor.ForceLogout(); + JMMService.AnidbProcessor.Dispose(); + Thread.Sleep(1000); + } + + } + + public static int OnHashProgress(string fileName, int percentComplete) + { + //string msg = Path.GetFileName(fileName); + //if (msg.Length > 35) msg = msg.Substring(0, 35); + //logger.Info("{0}% Hashing ({1})", percentComplete, Path.GetFileName(fileName)); + return 1; //continue hashing (return 0 to abort) + } + + + + #region Tests + + private static void ReviewsTest() + { + CommandRequest_GetReviews cmd = new CommandRequest_GetReviews(7525, true); + cmd.Save(); + + //CommandRequest_GetAnimeHTTP cmd = new CommandRequest_GetAnimeHTTP(7727, false); + //cmd.Save(); + } + + private static void WebCacheTest() + { + string hash = ""; + hash = XMLService.Get_FileHash("Full Metal Panic! The Second Raid - S2 [AonE-AnY] (XviD) (704x396).avi", 181274624); + hash = XMLService.Get_FileHash("Code_Geass_R2_Ep14_Geass_Hunt_[720p,BluRay,x264]_-_THORA.mkv", 601722047); + hash = XMLService.Get_FileHash("[Ayako]_Infinite_Stratos_-_IS_-_02_[H264][720p][05C376A9].mkv", 368502091); + } + + private static void HashTest() + { + string fileName = @"C:\Code_Geass_R2_Ep14_Geass_Hunt_[720p,BluRay,x264]_-_THORA.mkv"; + //string fileName = @"M:\[ Anime Test ]\Code_Geass_R2_Ep14_Geass_Hunt_[720p,BluRay,x264]_-_THORA.mkv"; + + DateTime start = DateTime.Now; + Hashes hashes = Hasher.CalculateHashes(fileName, OnHashProgress, true, false, false, false); + TimeSpan ts = DateTime.Now - start; + + double doubleED2k = ts.TotalMilliseconds; + + start = DateTime.Now; + Hashes hashes2 = Hasher.CalculateHashes(fileName, OnHashProgress, true, true, false, false); + ts = DateTime.Now - start; + + double doubleCRC32 = ts.TotalMilliseconds; + + start = DateTime.Now; + Hashes hashes3 = Hasher.CalculateHashes(fileName, OnHashProgress, true, false, true, false); + ts = DateTime.Now - start; + + double doubleMD5 = ts.TotalMilliseconds; + + start = DateTime.Now; + Hashes hashes4 = Hasher.CalculateHashes(fileName, OnHashProgress, true, false, false, true); + ts = DateTime.Now - start; + + double doubleSHA1 = ts.TotalMilliseconds; + + start = DateTime.Now; + Hashes hashes5 = Hasher.CalculateHashes(fileName, OnHashProgress, true, true, true, true); + ts = DateTime.Now - start; + + double doubleAll = ts.TotalMilliseconds; + + logger.Info("ED2K only took {0} ms --- {1}/{2}/{3}/{4}", doubleED2k, hashes.ed2k, hashes.crc32, hashes.md5, hashes.sha1); + logger.Info("ED2K + CRCR32 took {0} ms --- {1}/{2}/{3}/{4}", doubleCRC32, hashes2.ed2k, hashes2.crc32, hashes2.md5, hashes2.sha1); + logger.Info("ED2K + MD5 took {0} ms --- {1}/{2}/{3}/{4}", doubleMD5, hashes3.ed2k, hashes3.crc32, hashes3.md5, hashes3.sha1); + logger.Info("ED2K + SHA1 took {0} ms --- {1}/{2}/{3}/{4}", doubleSHA1, hashes4.ed2k, hashes4.crc32, hashes4.md5, hashes4.sha1); + logger.Info("Everything took {0} ms --- {1}/{2}/{3}/{4}", doubleAll, hashes5.ed2k, hashes5.crc32, hashes5.md5, hashes5.sha1); + } + + private static void HashTest2() + { + string fileName = @"C:\Anime\Code_Geass_R2_Ep14_Geass_Hunt_[720p,BluRay,x264]_-_THORA.mkv"; + FileInfo fi = new FileInfo(fileName); + string fileSize1 = Utils.FormatByteSize(fi.Length); + DateTime start = DateTime.Now; + Hashes hashes = Hasher.CalculateHashes(fileName, OnHashProgress, true, false, false, false); + TimeSpan ts = DateTime.Now - start; + + double doubleFile1 = ts.TotalMilliseconds; + + fileName = @"C:\Anime\[Coalgirls]_Bakemonogatari_01_(1280x720_Blu-Ray_FLAC)_[CA425D15].mkv"; + fi = new FileInfo(fileName); + string fileSize2 = Utils.FormatByteSize(fi.Length); + start = DateTime.Now; + Hashes hashes2 = Hasher.CalculateHashes(fileName, OnHashProgress, true, false, false, false); + ts = DateTime.Now - start; + + double doubleFile2 = ts.TotalMilliseconds; + + + fileName = @"C:\Anime\Highschool_of_the_Dead_Ep01_Spring_of_the_Dead_[1080p,BluRay,x264]_-_gg-THORA.mkv"; + fi = new FileInfo(fileName); + string fileSize3 = Utils.FormatByteSize(fi.Length); + start = DateTime.Now; + Hashes hashes3 = Hasher.CalculateHashes(fileName, OnHashProgress, true, false, false, false); + ts = DateTime.Now - start; + + double doubleFile3 = ts.TotalMilliseconds; + + logger.Info("Hashed {0} in {1} ms --- {2}", fileSize1, doubleFile1, hashes.ed2k); + logger.Info("Hashed {0} in {1} ms --- {2}", fileSize2, doubleFile2, hashes2.ed2k); + logger.Info("Hashed {0} in {1} ms --- {2}", fileSize3, doubleFile3, hashes3.ed2k); + + } + + + private static void UpdateStatsTest() + { + AnimeGroupRepository repGroups = new AnimeGroupRepository(); + foreach (AnimeGroup grp in repGroups.GetAllTopLevelGroups()) + { + grp.UpdateStatsFromTopLevel(true, true); + } + } + + + + private static void CreateImportFolders_Test() + { + logger.Debug("Creating import folders..."); + ImportFolderRepository repImportFolders = new ImportFolderRepository(); + + ImportFolder sn = repImportFolders.GetByImportLocation(@"M:\[ Anime Test ]"); + if (sn == null) + { + sn = new ImportFolder(); + sn.ImportFolderName = "Anime"; + sn.ImportFolderType = (int)ImportFolderType.HDD; + sn.ImportFolderLocation = @"M:\[ Anime Test ]"; + repImportFolders.Save(sn); + } + + logger.Debug("Complete!"); + } + + private static void ProcessFileTest() + { + //CommandRequest_HashFile cr_hashfile = new CommandRequest_HashFile(@"M:\[ Anime Test ]\[HorribleSubs] Dragon Crisis! - 02 [720p].mkv", false); + //CommandRequest_ProcessFile cr_procfile = new CommandRequest_ProcessFile(@"M:\[ Anime Test ]\[Doki] Saki - 01 (720x480 h264 DVD AAC) [DC73ACB9].mkv"); + //cr_hashfile.Save(); + + CommandRequest_ProcessFile cr_procfile = new CommandRequest_ProcessFile(15350); + cr_procfile.Save(); + } + + + + + + private static void CreateImportFolders() + { + logger.Debug("Creating shares..."); + ImportFolderRepository repNetShares = new ImportFolderRepository(); + + ImportFolder sn = repNetShares.GetByImportLocation(@"M:\[ Anime 2011 ]"); + if (sn == null) + { + sn = new ImportFolder(); + sn.ImportFolderType = (int)ImportFolderType.HDD; + sn.ImportFolderName = "Anime 2011"; + sn.ImportFolderLocation = @"M:\[ Anime 2011 ]"; + repNetShares.Save(sn); + } + + sn = repNetShares.GetByImportLocation(@"M:\[ Anime - DVD and Bluray IN PROGRESS ]"); + if (sn == null) + { + sn = new ImportFolder(); + sn.ImportFolderType = (int)ImportFolderType.HDD; + sn.ImportFolderName = "Anime - DVD and Bluray IN PROGRESS"; + sn.ImportFolderLocation = @"M:\[ Anime - DVD and Bluray IN PROGRESS ]"; + repNetShares.Save(sn); + } + + sn = repNetShares.GetByImportLocation(@"M:\[ Anime - DVD and Bluray COMPLETE ]"); + if (sn == null) + { + sn = new ImportFolder(); + sn.ImportFolderType = (int)ImportFolderType.HDD; + sn.ImportFolderName = "Anime - DVD and Bluray COMPLETE"; + sn.ImportFolderLocation = @"M:\[ Anime - DVD and Bluray COMPLETE ]"; + repNetShares.Save(sn); + } + + sn = repNetShares.GetByImportLocation(@"M:\[ Anime ]"); + if (sn == null) + { + sn = new ImportFolder(); + sn.ImportFolderType = (int)ImportFolderType.HDD; + sn.ImportFolderName = "Anime"; + sn.ImportFolderLocation = @"M:\[ Anime ]"; + repNetShares.Save(sn); + } + + logger.Debug("Creating shares complete!"); + } + + private static void CreateImportFolders2() + { + logger.Debug("Creating shares..."); + ImportFolderRepository repNetShares = new ImportFolderRepository(); + + ImportFolder sn = repNetShares.GetByImportLocation(@"F:\Anime1"); + if (sn == null) + { + sn = new ImportFolder(); + sn.ImportFolderType = (int)ImportFolderType.HDD; + sn.ImportFolderName = "Anime1"; + sn.ImportFolderLocation = @"F:\Anime1"; + repNetShares.Save(sn); + } + + sn = repNetShares.GetByImportLocation(@"H:\Anime2"); + if (sn == null) + { + sn = new ImportFolder(); + sn.ImportFolderType = (int)ImportFolderType.HDD; + sn.ImportFolderName = "Anime2"; + sn.ImportFolderLocation = @"H:\Anime2"; + repNetShares.Save(sn); + } + + sn = repNetShares.GetByImportLocation(@"G:\Anime3"); + if (sn == null) + { + sn = new ImportFolder(); + sn.ImportFolderType = (int)ImportFolderType.HDD; + sn.ImportFolderName = "Anime3"; + sn.ImportFolderLocation = @"G:\Anime3"; + repNetShares.Save(sn); + } + + logger.Debug("Creating shares complete!"); + } + + + + private static void CreateTestCommandRequests() + { + CommandRequest_GetAnimeHTTP cr_anime = new CommandRequest_GetAnimeHTTP(5415, false, true); + cr_anime.Save(); + + /* + cr_anime = new CommandRequest_GetAnimeHTTP(7382); cr_anime.Save(); + cr_anime = new CommandRequest_GetAnimeHTTP(6239); cr_anime.Save(); + cr_anime = new CommandRequest_GetAnimeHTTP(69); cr_anime.Save(); + cr_anime = new CommandRequest_GetAnimeHTTP(6751); cr_anime.Save(); + cr_anime = new CommandRequest_GetAnimeHTTP(3168); cr_anime.Save(); + cr_anime = new CommandRequest_GetAnimeHTTP(4196); cr_anime.Save(); + cr_anime = new CommandRequest_GetAnimeHTTP(634); cr_anime.Save(); + cr_anime = new CommandRequest_GetAnimeHTTP(2002); cr_anime.Save(); + + + + cr_anime = new CommandRequest_GetAnimeHTTP(1); cr_anime.Save(); + cr_anime = new CommandRequest_GetAnimeHTTP(2); cr_anime.Save(); + cr_anime = new CommandRequest_GetAnimeHTTP(3); cr_anime.Save(); + cr_anime = new CommandRequest_GetAnimeHTTP(4); cr_anime.Save(); + cr_anime = new CommandRequest_GetAnimeHTTP(5); cr_anime.Save(); + cr_anime = new CommandRequest_GetAnimeHTTP(6); cr_anime.Save(); + cr_anime = new CommandRequest_GetAnimeHTTP(7); cr_anime.Save(); + cr_anime = new CommandRequest_GetAnimeHTTP(8); cr_anime.Save(); + cr_anime = new CommandRequest_GetAnimeHTTP(9); cr_anime.Save(); + cr_anime = new CommandRequest_GetAnimeHTTP(10); cr_anime.Save(); + cr_anime = new CommandRequest_GetAnimeHTTP(11); cr_anime.Save(); + cr_anime = new CommandRequest_GetAnimeHTTP(12); cr_anime.Save(); + cr_anime = new CommandRequest_GetAnimeHTTP(13); cr_anime.Save(); + cr_anime = new CommandRequest_GetAnimeHTTP(14); cr_anime.Save(); + cr_anime = new CommandRequest_GetAnimeHTTP(15); cr_anime.Save(); + cr_anime = new CommandRequest_GetAnimeHTTP(16); cr_anime.Save(); + cr_anime = new CommandRequest_GetAnimeHTTP(17); cr_anime.Save(); + cr_anime = new CommandRequest_GetAnimeHTTP(18); cr_anime.Save(); + cr_anime = new CommandRequest_GetAnimeHTTP(19); cr_anime.Save();*/ + } + + #endregion + } +} diff --git a/JMMServer/Mappings/AniDB_AnimeMap.cs b/JMMServer/Mappings/AniDB_AnimeMap.cs new file mode 100644 index 000000000..65aae3bc0 --- /dev/null +++ b/JMMServer/Mappings/AniDB_AnimeMap.cs @@ -0,0 +1,52 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using FluentNHibernate.Mapping; +using JMMServer.Entities; + +namespace JMMServer.Mappings +{ + public class AniDB_AnimeMap : ClassMap + { + public AniDB_AnimeMap() + { + Not.LazyLoad(); + Id(x => x.AniDB_AnimeID); + + Map(x => x.AirDate); + Map(x => x.AllCinemaID); + Map(x => x.AllTitles); + Map(x => x.AllCategories); + Map(x => x.AllTags); + Map(x => x.AnimeNfo); + Map(x => x.AnimeID).Not.Nullable(); + Map(x => x.AnimePlanetID); + Map(x => x.AnimeType).Not.Nullable(); + Map(x => x.ANNID); + Map(x => x.AvgReviewRating).Not.Nullable(); + Map(x => x.AwardList).Not.Nullable(); + Map(x => x.BeginYear).Not.Nullable(); + Map(x => x.DateTimeDescUpdated).Not.Nullable(); + Map(x => x.DateTimeUpdated).Not.Nullable(); + Map(x => x.Description).Not.Nullable(); + Map(x => x.EndDate); + Map(x => x.EndYear).Not.Nullable(); + Map(x => x.EpisodeCount).Not.Nullable(); + Map(x => x.EpisodeCountNormal).Not.Nullable(); + Map(x => x.EpisodeCountSpecial).Not.Nullable(); + Map(x => x.ImageEnabled).Not.Nullable(); + Map(x => x.LatestEpisodeNumber); + Map(x => x.MainTitle).Not.Nullable(); + Map(x => x.Picname); + Map(x => x.Rating).Not.Nullable(); + Map(x => x.Restricted).Not.Nullable(); + Map(x => x.ReviewCount).Not.Nullable(); + Map(x => x.TempRating).Not.Nullable(); + Map(x => x.TempVoteCount).Not.Nullable(); + Map(x => x.URL).Not.Nullable(); + Map(x => x.VoteCount).Not.Nullable(); + + } + } +} diff --git a/JMMServer/Mappings/AniDB_Anime_CategoryMap.cs b/JMMServer/Mappings/AniDB_Anime_CategoryMap.cs new file mode 100644 index 000000000..650d2159d --- /dev/null +++ b/JMMServer/Mappings/AniDB_Anime_CategoryMap.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using FluentNHibernate.Mapping; +using JMMServer.Entities; + +namespace JMMServer.Mappings +{ + public class AniDB_Anime_CategoryMap : ClassMap + { + public AniDB_Anime_CategoryMap() + { + Not.LazyLoad(); + Id(x => x.AniDB_Anime_CategoryID); + + Map(x => x.AnimeID).Not.Nullable(); + Map(x => x.CategoryID).Not.Nullable(); + Map(x => x.Weighting).Not.Nullable(); + } + } +} diff --git a/JMMServer/Mappings/AniDB_Anime_CharacterMap.cs b/JMMServer/Mappings/AniDB_Anime_CharacterMap.cs new file mode 100644 index 000000000..fa166e344 --- /dev/null +++ b/JMMServer/Mappings/AniDB_Anime_CharacterMap.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using FluentNHibernate.Mapping; +using JMMServer.Entities; + +namespace JMMServer.Mappings +{ + public class AniDB_Anime_CharacterMap : ClassMap + { + public AniDB_Anime_CharacterMap() + { + Not.LazyLoad(); + Id(x => x.AniDB_Anime_CharacterID); + + Map(x => x.AnimeID).Not.Nullable(); + Map(x => x.CharID).Not.Nullable(); + Map(x => x.CharType).Not.Nullable(); + Map(x => x.EpisodeListRaw); + } + } +} diff --git a/JMMServer/Mappings/AniDB_Anime_DefaultImageMap.cs b/JMMServer/Mappings/AniDB_Anime_DefaultImageMap.cs new file mode 100644 index 000000000..20417e70d --- /dev/null +++ b/JMMServer/Mappings/AniDB_Anime_DefaultImageMap.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using FluentNHibernate.Mapping; +using JMMServer.Entities; + +namespace JMMServer.Mappings +{ + public class AniDB_Anime_DefaultImageMap : ClassMap + { + public AniDB_Anime_DefaultImageMap() + { + Not.LazyLoad(); + Id(x => x.AniDB_Anime_DefaultImageID); + + Map(x => x.AnimeID).Not.Nullable(); + Map(x => x.ImageParentID).Not.Nullable(); + Map(x => x.ImageParentType).Not.Nullable(); + Map(x => x.ImageType).Not.Nullable(); + } + } +} diff --git a/JMMServer/Mappings/AniDB_Anime_RelationMap.cs b/JMMServer/Mappings/AniDB_Anime_RelationMap.cs new file mode 100644 index 000000000..28e3fd0e5 --- /dev/null +++ b/JMMServer/Mappings/AniDB_Anime_RelationMap.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using FluentNHibernate.Mapping; +using JMMServer.Entities; + +namespace JMMServer.Mappings +{ + public class AniDB_Anime_RelationMap : ClassMap + { + public AniDB_Anime_RelationMap() + { + Not.LazyLoad(); + Id(x => x.AniDB_Anime_RelationID); + + Map(x => x.AnimeID).Not.Nullable(); + Map(x => x.RelatedAnimeID).Not.Nullable(); + Map(x => x.RelationType).Not.Nullable(); + } + } +} diff --git a/JMMServer/Mappings/AniDB_Anime_ReviewMap.cs b/JMMServer/Mappings/AniDB_Anime_ReviewMap.cs new file mode 100644 index 000000000..14521a1f8 --- /dev/null +++ b/JMMServer/Mappings/AniDB_Anime_ReviewMap.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using FluentNHibernate.Mapping; +using JMMServer.Entities; + +namespace JMMServer.Mappings +{ + public class AniDB_Anime_ReviewMap : ClassMap + { + public AniDB_Anime_ReviewMap() + { + Not.LazyLoad(); + Id(x => x.AniDB_Anime_ReviewID); + + Map(x => x.AnimeID).Not.Nullable(); + Map(x => x.ReviewID).Not.Nullable(); + } + } +} diff --git a/JMMServer/Mappings/AniDB_Anime_SimilarMap.cs b/JMMServer/Mappings/AniDB_Anime_SimilarMap.cs new file mode 100644 index 000000000..0450614da --- /dev/null +++ b/JMMServer/Mappings/AniDB_Anime_SimilarMap.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using FluentNHibernate.Mapping; +using JMMServer.Entities; + +namespace JMMServer.Mappings +{ + public class AniDB_Anime_SimilarMap : ClassMap + { + public AniDB_Anime_SimilarMap() + { + Not.LazyLoad(); + Id(x => x.AniDB_Anime_SimilarID); + + Map(x => x.AnimeID).Not.Nullable(); + Map(x => x.Approval).Not.Nullable(); + Map(x => x.SimilarAnimeID).Not.Nullable(); + Map(x => x.Total).Not.Nullable(); + } + } +} diff --git a/JMMServer/Mappings/AniDB_Anime_TagMap.cs b/JMMServer/Mappings/AniDB_Anime_TagMap.cs new file mode 100644 index 000000000..706f9651c --- /dev/null +++ b/JMMServer/Mappings/AniDB_Anime_TagMap.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using FluentNHibernate.Mapping; +using JMMServer.Entities; + +namespace JMMServer.Mappings +{ + public class AniDB_Anime_TagMap : ClassMap + { + public AniDB_Anime_TagMap() + { + Not.LazyLoad(); + Id(x => x.AniDB_Anime_TagID); + + Map(x => x.AnimeID).Not.Nullable(); + Map(x => x.Approval).Not.Nullable(); + Map(x => x.TagID).Not.Nullable(); + } + } +} diff --git a/JMMServer/Mappings/AniDB_Anime_TitleMap.cs b/JMMServer/Mappings/AniDB_Anime_TitleMap.cs new file mode 100644 index 000000000..7de105924 --- /dev/null +++ b/JMMServer/Mappings/AniDB_Anime_TitleMap.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using FluentNHibernate.Mapping; +using JMMServer.Entities; + +namespace JMMServer.Mappings +{ + public class AniDB_Anime_TitleMap : ClassMap + { + public AniDB_Anime_TitleMap() + { + Not.LazyLoad(); + Id(x => x.AniDB_Anime_TitleID); + + Map(x => x.AnimeID).Not.Nullable(); + Map(x => x.Language).Not.Nullable(); + Map(x => x.Title).Not.Nullable(); + Map(x => x.TitleType).Not.Nullable(); + } + } +} diff --git a/JMMServer/Mappings/AniDB_CategoryMap.cs b/JMMServer/Mappings/AniDB_CategoryMap.cs new file mode 100644 index 000000000..95a9876a1 --- /dev/null +++ b/JMMServer/Mappings/AniDB_CategoryMap.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using FluentNHibernate.Mapping; +using JMMServer.Entities; + +namespace JMMServer.Mappings +{ + public class AniDB_CategoryMap : ClassMap + { + public AniDB_CategoryMap() + { + Not.LazyLoad(); + Id(x => x.AniDB_CategoryID); + + Map(x => x.CategoryDescription).Not.Nullable(); + Map(x => x.CategoryID).Not.Nullable(); + Map(x => x.CategoryName).Not.Nullable(); + Map(x => x.IsHentai).Not.Nullable(); + Map(x => x.ParentID).Not.Nullable(); + } + } +} diff --git a/JMMServer/Mappings/AniDB_CharacterMap.cs b/JMMServer/Mappings/AniDB_CharacterMap.cs new file mode 100644 index 000000000..fa4acea39 --- /dev/null +++ b/JMMServer/Mappings/AniDB_CharacterMap.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using FluentNHibernate.Mapping; +using JMMServer.Entities; + +namespace JMMServer.Mappings +{ + public class AniDB_CharacterMap : ClassMap + { + public AniDB_CharacterMap() + { + Not.LazyLoad(); + Id(x => x.AniDB_CharacterID); + + Map(x => x.CharDescription).Not.Nullable(); + Map(x => x.CharID).Not.Nullable(); + Map(x => x.PicName).Not.Nullable(); + Map(x => x.CharKanjiName).Not.Nullable(); + Map(x => x.CharName).Not.Nullable(); + Map(x => x.CreatorListRaw).Not.Nullable(); + + } + } +} diff --git a/JMMServer/Mappings/AniDB_Character_CreatorMap.cs b/JMMServer/Mappings/AniDB_Character_CreatorMap.cs new file mode 100644 index 000000000..de9be67bc --- /dev/null +++ b/JMMServer/Mappings/AniDB_Character_CreatorMap.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using FluentNHibernate.Mapping; +using JMMServer.Entities; + +namespace JMMServer.Mappings +{ + public class AniDB_Character_CreatorMap : ClassMap + { + public AniDB_Character_CreatorMap() + { + Not.LazyLoad(); + Id(x => x.AniDB_Character_CreatorID); + + Map(x => x.CharID).Not.Nullable(); + Map(x => x.CreatorID).Not.Nullable(); + } + } +} diff --git a/JMMServer/Mappings/AniDB_CreatorMap.cs b/JMMServer/Mappings/AniDB_CreatorMap.cs new file mode 100644 index 000000000..91db46d44 --- /dev/null +++ b/JMMServer/Mappings/AniDB_CreatorMap.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using FluentNHibernate.Mapping; +using JMMServer.Entities; + +namespace JMMServer.Mappings +{ + public class AniDB_CreatorMap : ClassMap + { + public AniDB_CreatorMap() + { + Not.LazyLoad(); + Id(x => x.AniDB_CreatorID); + + Map(x => x.CreatorDescription); + Map(x => x.CreatorID).Not.Nullable(); + Map(x => x.CreatorKanjiName); + Map(x => x.CreatorName).Not.Nullable(); + Map(x => x.CreatorType).Not.Nullable(); + Map(x => x.PicName); + Map(x => x.URLEnglish); + Map(x => x.URLJapanese); + Map(x => x.URLWikiEnglish); + Map(x => x.URLWikiJapanese); + } + } +} diff --git a/JMMServer/Mappings/AniDB_EpisodeMap.cs b/JMMServer/Mappings/AniDB_EpisodeMap.cs new file mode 100644 index 000000000..0aaa44cc0 --- /dev/null +++ b/JMMServer/Mappings/AniDB_EpisodeMap.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using FluentNHibernate.Mapping; +using JMMServer.Entities; + +namespace JMMServer.Mappings +{ + public class AniDB_EpisodeMap : ClassMap + { + public AniDB_EpisodeMap() + { + Not.LazyLoad(); + Id(x => x.AniDB_EpisodeID); + + Map(x => x.AirDate).Not.Nullable(); + Map(x => x.AnimeID).Not.Nullable(); + Map(x => x.DateTimeUpdated).Not.Nullable(); + Map(x => x.EnglishName).Not.Nullable(); + Map(x => x.EpisodeID).Not.Nullable(); + Map(x => x.EpisodeNumber).Not.Nullable(); + Map(x => x.EpisodeType).Not.Nullable(); + Map(x => x.LengthSeconds).Not.Nullable(); + Map(x => x.Rating).Not.Nullable(); + Map(x => x.RomajiName).Not.Nullable(); + Map(x => x.Votes).Not.Nullable(); + } + } +} diff --git a/JMMServer/Mappings/AniDB_FileMap.cs b/JMMServer/Mappings/AniDB_FileMap.cs new file mode 100644 index 000000000..2cbfc68a9 --- /dev/null +++ b/JMMServer/Mappings/AniDB_FileMap.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using FluentNHibernate.Mapping; +using JMMServer.Entities; + +namespace JMMServer.Mappings +{ + public class AniDB_FileMap : ClassMap + { + public AniDB_FileMap() + { + Not.LazyLoad(); + Id(x => x.AniDB_FileID); + + Map(x => x.Anime_GroupName).Not.Nullable(); + Map(x => x.Anime_GroupNameShort).Not.Nullable(); + Map(x => x.AnimeID).Not.Nullable(); + Map(x => x.CRC).Not.Nullable(); + Map(x => x.DateTimeUpdated).Not.Nullable(); + Map(x => x.Episode_Rating).Not.Nullable(); + Map(x => x.Episode_Votes).Not.Nullable(); + Map(x => x.File_AudioCodec).Not.Nullable(); + Map(x => x.File_Description).Not.Nullable(); + Map(x => x.File_FileExtension).Not.Nullable(); + Map(x => x.File_LengthSeconds).Not.Nullable(); + Map(x => x.File_ReleaseDate).Not.Nullable(); + Map(x => x.File_Source).Not.Nullable(); + Map(x => x.File_VideoCodec).Not.Nullable(); + Map(x => x.File_VideoResolution).Not.Nullable(); + Map(x => x.FileID).Not.Nullable(); + Map(x => x.FileName).Not.Nullable(); + Map(x => x.FileSize).Not.Nullable(); + Map(x => x.GroupID).Not.Nullable(); + Map(x => x.Hash).Not.Nullable(); + Map(x => x.IsWatched).Not.Nullable(); + Map(x => x.MD5).Not.Nullable(); + Map(x => x.SHA1).Not.Nullable(); + Map(x => x.WatchedDate); + } + } +} diff --git a/JMMServer/Mappings/AniDB_GroupStatusMap.cs b/JMMServer/Mappings/AniDB_GroupStatusMap.cs new file mode 100644 index 000000000..e2ca676e9 --- /dev/null +++ b/JMMServer/Mappings/AniDB_GroupStatusMap.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using FluentNHibernate.Mapping; +using JMMServer.Entities; + +namespace JMMServer.Mappings +{ + public class AniDB_GroupStatusMap : ClassMap + { + public AniDB_GroupStatusMap() + { + Not.LazyLoad(); + Id(x => x.AniDB_GroupStatusID); + + Map(x => x.AnimeID).Not.Nullable(); + Map(x => x.CompletionState).Not.Nullable(); + Map(x => x.EpisodeRange); + Map(x => x.GroupID).Not.Nullable(); + Map(x => x.GroupName); + Map(x => x.LastEpisodeNumber).Not.Nullable(); + Map(x => x.Rating).Not.Nullable(); + Map(x => x.Votes).Not.Nullable(); + } + } +} diff --git a/JMMServer/Mappings/AniDB_ReleaseGroupMap.cs b/JMMServer/Mappings/AniDB_ReleaseGroupMap.cs new file mode 100644 index 000000000..14366ce33 --- /dev/null +++ b/JMMServer/Mappings/AniDB_ReleaseGroupMap.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using FluentNHibernate.Mapping; +using JMMServer.Entities; + +namespace JMMServer.Mappings +{ + public class AniDB_ReleaseGroupMap : ClassMap + { + public AniDB_ReleaseGroupMap() + { + Not.LazyLoad(); + Id(x => x.AniDB_ReleaseGroupID); + + Map(x => x.GroupID).Not.Nullable(); + Map(x => x.Rating).Not.Nullable(); + Map(x => x.Votes).Not.Nullable(); + Map(x => x.AnimeCount).Not.Nullable(); + Map(x => x.FileCount).Not.Nullable(); + + Map(x => x.GroupName); + Map(x => x.GroupNameShort); + Map(x => x.IRCChannel); + Map(x => x.IRCServer); + Map(x => x.URL); + Map(x => x.Picname); + } + } +} diff --git a/JMMServer/Mappings/AniDB_ReviewMap.cs b/JMMServer/Mappings/AniDB_ReviewMap.cs new file mode 100644 index 000000000..98d4f29b1 --- /dev/null +++ b/JMMServer/Mappings/AniDB_ReviewMap.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using FluentNHibernate.Mapping; +using JMMServer.Entities; + +namespace JMMServer.Mappings +{ + public class AniDB_ReviewMap : ClassMap + { + public AniDB_ReviewMap() + { + Not.LazyLoad(); + Id(x => x.AniDB_ReviewID); + + Map(x => x.AuthorID).Not.Nullable(); + Map(x => x.RatingAnimation).Not.Nullable(); + Map(x => x.RatingCharacter).Not.Nullable(); + Map(x => x.RatingEnjoyment).Not.Nullable(); + Map(x => x.RatingSound).Not.Nullable(); + Map(x => x.RatingStory).Not.Nullable(); + Map(x => x.RatingValue).Not.Nullable(); + Map(x => x.ReviewID).Not.Nullable(); + Map(x => x.ReviewText).Not.Nullable(); + } + } +} diff --git a/JMMServer/Mappings/AniDB_TagMap.cs b/JMMServer/Mappings/AniDB_TagMap.cs new file mode 100644 index 000000000..ea44ba07a --- /dev/null +++ b/JMMServer/Mappings/AniDB_TagMap.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using FluentNHibernate.Mapping; +using JMMServer.Entities; + +namespace JMMServer.Mappings +{ + public class AniDB_TagMap : ClassMap + { + public AniDB_TagMap() + { + Not.LazyLoad(); + Id(x => x.AniDB_TagID); + + Map(x => x.GlobalSpoiler).Not.Nullable(); + Map(x => x.LocalSpoiler).Not.Nullable(); + Map(x => x.Spoiler).Not.Nullable(); + Map(x => x.TagCount).Not.Nullable(); + Map(x => x.TagDescription).Not.Nullable(); + Map(x => x.TagID).Not.Nullable(); + Map(x => x.TagName).Not.Nullable(); + } + } +} diff --git a/JMMServer/Mappings/AniDB_VoteMap.cs b/JMMServer/Mappings/AniDB_VoteMap.cs new file mode 100644 index 000000000..c3a5a6cf3 --- /dev/null +++ b/JMMServer/Mappings/AniDB_VoteMap.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using FluentNHibernate.Mapping; +using JMMServer.Entities; + +namespace JMMServer.Mappings +{ + public class AniDB_VoteMap : ClassMap + { + public AniDB_VoteMap() + { + Not.LazyLoad(); + Id(x => x.AniDB_VoteID); + + Map(x => x.EntityID).Not.Nullable(); + Map(x => x.VoteValue).Not.Nullable(); + Map(x => x.VoteType).Not.Nullable(); + } + } +} diff --git a/JMMServer/Mappings/AnimeEpisodeMap.cs b/JMMServer/Mappings/AnimeEpisodeMap.cs new file mode 100644 index 000000000..ad54604b6 --- /dev/null +++ b/JMMServer/Mappings/AnimeEpisodeMap.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using FluentNHibernate.Mapping; +using JMMServer.Entities; + +namespace JMMServer.Mappings +{ + public class AnimeEpisodeMap : ClassMap + { + public AnimeEpisodeMap() + { + Not.LazyLoad(); + Id(x => x.AnimeEpisodeID); + + Map(x => x.AniDB_EpisodeID).Not.Nullable(); + Map(x => x.AnimeSeriesID).Not.Nullable(); + Map(x => x.DateTimeCreated).Not.Nullable(); + Map(x => x.DateTimeUpdated).Not.Nullable(); + } + } +} diff --git a/JMMServer/Mappings/AnimeEpisode_UserMap.cs b/JMMServer/Mappings/AnimeEpisode_UserMap.cs new file mode 100644 index 000000000..a4d9d1094 --- /dev/null +++ b/JMMServer/Mappings/AnimeEpisode_UserMap.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using FluentNHibernate.Mapping; +using JMMServer.Entities; + +namespace JMMServer.Mappings +{ + public class AnimeEpisode_UserMap : ClassMap + { + public AnimeEpisode_UserMap() + { + Not.LazyLoad(); + Id(x => x.AnimeEpisode_UserID); + + Map(x => x.AnimeEpisodeID).Not.Nullable(); + Map(x => x.AnimeSeriesID).Not.Nullable(); + Map(x => x.JMMUserID).Not.Nullable(); + Map(x => x.PlayedCount).Not.Nullable(); + Map(x => x.StoppedCount).Not.Nullable(); + Map(x => x.WatchedCount).Not.Nullable(); + Map(x => x.WatchedDate); + } + } +} diff --git a/JMMServer/Mappings/AnimeGroupMap.cs b/JMMServer/Mappings/AnimeGroupMap.cs new file mode 100644 index 000000000..8253fff67 --- /dev/null +++ b/JMMServer/Mappings/AnimeGroupMap.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using FluentNHibernate.Mapping; +using JMMServer.Entities; + +namespace JMMServer.Mappings +{ + public class AnimeGroupMap : ClassMap + { + public AnimeGroupMap() + { + Not.LazyLoad(); + Id(x => x.AnimeGroupID); + + Map(x => x.AnimeGroupParentID); + Map(x => x.DateTimeCreated).Not.Nullable(); + Map(x => x.DateTimeUpdated).Not.Nullable(); + Map(x => x.Description); + Map(x => x.GroupName); + Map(x => x.IsManuallyNamed).Not.Nullable(); + Map(x => x.OverrideDescription).Not.Nullable(); + Map(x => x.SortName); + Map(x => x.EpisodeAddedDate); + Map(x => x.MissingEpisodeCount).Not.Nullable(); + Map(x => x.MissingEpisodeCountGroups).Not.Nullable(); + } + } +} diff --git a/JMMServer/Mappings/AnimeGroup_UserMap.cs b/JMMServer/Mappings/AnimeGroup_UserMap.cs new file mode 100644 index 000000000..aa3e3df26 --- /dev/null +++ b/JMMServer/Mappings/AnimeGroup_UserMap.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using FluentNHibernate.Mapping; +using JMMServer.Entities; + +namespace JMMServer.Mappings +{ + public class AnimeGroup_UserMap : ClassMap + { + public AnimeGroup_UserMap() + { + Not.LazyLoad(); + Id(x => x.AnimeGroup_UserID); + + Map(x => x.JMMUserID); + Map(x => x.AnimeGroupID); + Map(x => x.IsFave).Not.Nullable(); + Map(x => x.PlayedCount).Not.Nullable(); + Map(x => x.StoppedCount).Not.Nullable(); + Map(x => x.UnwatchedEpisodeCount).Not.Nullable(); + Map(x => x.WatchedCount).Not.Nullable(); + Map(x => x.WatchedDate); + Map(x => x.WatchedEpisodeCount); + } + } +} diff --git a/JMMServer/Mappings/AnimeSeriesMap.cs b/JMMServer/Mappings/AnimeSeriesMap.cs new file mode 100644 index 000000000..1c9851ec1 --- /dev/null +++ b/JMMServer/Mappings/AnimeSeriesMap.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using FluentNHibernate.Mapping; +using JMMServer.Entities; + +namespace JMMServer.Mappings +{ + public class AnimeSeriesMap : ClassMap + { + public AnimeSeriesMap() + { + Not.LazyLoad(); + Id(x => x.AnimeSeriesID); + + Map(x => x.AniDB_ID).Not.Nullable(); + Map(x => x.AnimeGroupID).Not.Nullable(); + Map(x => x.DateTimeCreated).Not.Nullable(); + Map(x => x.DateTimeUpdated).Not.Nullable(); + Map(x => x.DefaultAudioLanguage); + Map(x => x.DefaultSubtitleLanguage); + Map(x => x.LatestLocalEpisodeNumber).Not.Nullable(); + Map(x => x.EpisodeAddedDate); + Map(x => x.MissingEpisodeCount).Not.Nullable(); + Map(x => x.MissingEpisodeCountGroups).Not.Nullable(); + } + } +} diff --git a/JMMServer/Mappings/AnimeSeries_UserMap.cs b/JMMServer/Mappings/AnimeSeries_UserMap.cs new file mode 100644 index 000000000..a7e7f11a5 --- /dev/null +++ b/JMMServer/Mappings/AnimeSeries_UserMap.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using FluentNHibernate.Mapping; +using JMMServer.Entities; + +namespace JMMServer.Mappings +{ + public class AnimeSeries_UserMap : ClassMap + { + public AnimeSeries_UserMap() + { + Not.LazyLoad(); + Id(x => x.AnimeSeries_UserID); + + Map(x => x.JMMUserID).Not.Nullable(); + Map(x => x.AnimeSeriesID).Not.Nullable(); + Map(x => x.PlayedCount).Not.Nullable(); + Map(x => x.StoppedCount).Not.Nullable(); + Map(x => x.UnwatchedEpisodeCount).Not.Nullable(); + Map(x => x.WatchedCount).Not.Nullable(); + Map(x => x.WatchedDate); + Map(x => x.WatchedEpisodeCount).Not.Nullable(); + } + } +} diff --git a/JMMServer/Mappings/CommandRequestMap.cs b/JMMServer/Mappings/CommandRequestMap.cs new file mode 100644 index 000000000..560bec788 --- /dev/null +++ b/JMMServer/Mappings/CommandRequestMap.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using FluentNHibernate.Mapping; +using JMMServer.Entities; + +namespace NHibernateTest.Mappings +{ + public class CommandRequestMap : ClassMap + { + public CommandRequestMap() + { + Not.LazyLoad(); + Id(x => x.CommandRequestID); + Map(x => x.CommandDetails).Not.Nullable(); + Map(x => x.CommandID).Not.Nullable(); + Map(x => x.CommandType).Not.Nullable(); + Map(x => x.DateTimeUpdated).Not.Nullable(); + Map(x => x.Priority).Not.Nullable(); + } + } +} diff --git a/JMMServer/Mappings/CrossRef_AniDB_OtherMap.cs b/JMMServer/Mappings/CrossRef_AniDB_OtherMap.cs new file mode 100644 index 000000000..18c834ab4 --- /dev/null +++ b/JMMServer/Mappings/CrossRef_AniDB_OtherMap.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using FluentNHibernate.Mapping; +using JMMServer.Entities; + +namespace JMMServer.Mappings +{ + public class CrossRef_AniDB_OtherMap : ClassMap + { + public CrossRef_AniDB_OtherMap() + { + Not.LazyLoad(); + Id(x => x.CrossRef_AniDB_OtherID); + + Map(x => x.AnimeID).Not.Nullable(); + Map(x => x.CrossRefID); + Map(x => x.CrossRefSource).Not.Nullable(); + Map(x => x.CrossRefType).Not.Nullable(); + } + } +} diff --git a/JMMServer/Mappings/CrossRef_AniDB_TraktMap.cs b/JMMServer/Mappings/CrossRef_AniDB_TraktMap.cs new file mode 100644 index 000000000..6f9552989 --- /dev/null +++ b/JMMServer/Mappings/CrossRef_AniDB_TraktMap.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using FluentNHibernate.Mapping; +using JMMServer.Entities; + +namespace JMMServer.Mappings +{ + public class CrossRef_AniDB_TraktMap : ClassMap + { + public CrossRef_AniDB_TraktMap() + { + Not.LazyLoad(); + Id(x => x.CrossRef_AniDB_TraktID); + + Map(x => x.AnimeID).Not.Nullable(); + Map(x => x.CrossRefSource).Not.Nullable(); + Map(x => x.TraktID); + Map(x => x.TraktSeasonNumber).Not.Nullable(); + + } + } +} diff --git a/JMMServer/Mappings/CrossRef_AniDB_TvDBMap.cs b/JMMServer/Mappings/CrossRef_AniDB_TvDBMap.cs new file mode 100644 index 000000000..027b3bedf --- /dev/null +++ b/JMMServer/Mappings/CrossRef_AniDB_TvDBMap.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using FluentNHibernate.Mapping; +using JMMServer.Entities; + +namespace JMMServer.Mappings +{ + public class CrossRef_AniDB_TvDBMap : ClassMap + { + public CrossRef_AniDB_TvDBMap() + { + Not.LazyLoad(); + Id(x => x.CrossRef_AniDB_TvDBID); + + Map(x => x.AnimeID).Not.Nullable(); + Map(x => x.CrossRefSource).Not.Nullable(); + Map(x => x.TvDBID).Not.Nullable(); + Map(x => x.TvDBSeasonNumber).Not.Nullable(); + } + } +} diff --git a/JMMServer/Mappings/CrossRef_File_EpisodeMap.cs b/JMMServer/Mappings/CrossRef_File_EpisodeMap.cs new file mode 100644 index 000000000..4f700e53b --- /dev/null +++ b/JMMServer/Mappings/CrossRef_File_EpisodeMap.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using FluentNHibernate.Mapping; +using JMMServer.Entities; + +namespace JMMServer.Mappings +{ + public class CrossRef_File_EpisodeMap : ClassMap + { + public CrossRef_File_EpisodeMap() + { + Not.LazyLoad(); + Id(x => x.CrossRef_File_EpisodeID); + + Map(x => x.CrossRefSource).Not.Nullable(); + Map(x => x.EpisodeID).Not.Nullable(); + Map(x => x.EpisodeOrder).Not.Nullable(); + Map(x => x.Hash).Not.Nullable(); + Map(x => x.Percentage).Not.Nullable(); + Map(x => x.FileName).Not.Nullable(); + Map(x => x.FileSize).Not.Nullable(); + Map(x => x.AnimeID).Not.Nullable(); + } + } +} diff --git a/JMMServer/Mappings/CrossRef_Languages_AniDB_FileMap.cs b/JMMServer/Mappings/CrossRef_Languages_AniDB_FileMap.cs new file mode 100644 index 000000000..95c252896 --- /dev/null +++ b/JMMServer/Mappings/CrossRef_Languages_AniDB_FileMap.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using FluentNHibernate.Mapping; +using JMMServer.Entities; + +namespace JMMServer.Mappings +{ + public class CrossRef_Languages_AniDB_FileMap : ClassMap + { + public CrossRef_Languages_AniDB_FileMap() + { + Not.LazyLoad(); + Id(x => x.CrossRef_Languages_AniDB_FileID); + + Map(x => x.FileID).Not.Nullable(); + Map(x => x.LanguageID).Not.Nullable(); + } + } +} diff --git a/JMMServer/Mappings/CrossRef_Subtitles_AniDB_FileMap.cs b/JMMServer/Mappings/CrossRef_Subtitles_AniDB_FileMap.cs new file mode 100644 index 000000000..d8c538132 --- /dev/null +++ b/JMMServer/Mappings/CrossRef_Subtitles_AniDB_FileMap.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using FluentNHibernate.Mapping; +using JMMServer.Entities; + +namespace JMMServer.Mappings +{ + public class CrossRef_Subtitles_AniDB_FileMap : ClassMap + { + public CrossRef_Subtitles_AniDB_FileMap() + { + Not.LazyLoad(); + Id(x => x.CrossRef_Subtitles_AniDB_FileID); + + Map(x => x.FileID).Not.Nullable(); + Map(x => x.LanguageID).Not.Nullable(); + } + } +} diff --git a/JMMServer/Mappings/DuplicateFileMap.cs b/JMMServer/Mappings/DuplicateFileMap.cs new file mode 100644 index 000000000..771886136 --- /dev/null +++ b/JMMServer/Mappings/DuplicateFileMap.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using FluentNHibernate.Mapping; +using JMMServer.Entities; + +namespace JMMServer.Mappings +{ + public class DuplicateFileMap : ClassMap + { + public DuplicateFileMap() + { + Not.LazyLoad(); + Id(x => x.DuplicateFileID); + + Map(x => x.DateTimeUpdated).Not.Nullable(); + Map(x => x.FilePathFile1); + Map(x => x.FilePathFile2); + Map(x => x.Hash); + Map(x => x.ImportFolderIDFile1).Not.Nullable(); + Map(x => x.ImportFolderIDFile2).Not.Nullable(); + + } + } +} diff --git a/JMMServer/Mappings/FileNameHashMap.cs b/JMMServer/Mappings/FileNameHashMap.cs new file mode 100644 index 000000000..a10f8bc5c --- /dev/null +++ b/JMMServer/Mappings/FileNameHashMap.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using FluentNHibernate.Mapping; +using JMMServer.Entities; + +namespace JMMServer.Mappings +{ + public class FileNameHashMap : ClassMap + { + public FileNameHashMap() + { + Not.LazyLoad(); + Id(x => x.FileNameHashID); + + Map(x => x.Hash); + Map(x => x.FileName); + Map(x => x.FileSize).Not.Nullable(); + Map(x => x.DateTimeUpdated).Not.Nullable(); + } + } +} diff --git a/JMMServer/Mappings/GroupFilterConditionMap.cs b/JMMServer/Mappings/GroupFilterConditionMap.cs new file mode 100644 index 000000000..8a7b30c8b --- /dev/null +++ b/JMMServer/Mappings/GroupFilterConditionMap.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using FluentNHibernate.Mapping; +using JMMServer.Entities; + +namespace JMMServer.Mappings +{ + public class GroupFilterConditionMap : ClassMap + { + public GroupFilterConditionMap() + { + Not.LazyLoad(); + Id(x => x.GroupFilterConditionID); + + Map(x => x.ConditionOperator).Not.Nullable(); + Map(x => x.ConditionParameter); + Map(x => x.ConditionType).Not.Nullable(); + Map(x => x.GroupFilterID).Not.Nullable(); + } + } +} diff --git a/JMMServer/Mappings/GroupFilterMap.cs b/JMMServer/Mappings/GroupFilterMap.cs new file mode 100644 index 000000000..b52125443 --- /dev/null +++ b/JMMServer/Mappings/GroupFilterMap.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using FluentNHibernate.Mapping; +using JMMServer.Entities; + +namespace JMMServer.Mappings +{ + public class GroupFilterMap : ClassMap + { + public GroupFilterMap() + { + Not.LazyLoad(); + Id(x => x.GroupFilterID); + + Map(x => x.GroupFilterName); + Map(x => x.ApplyToSeries).Not.Nullable(); + Map(x => x.BaseCondition).Not.Nullable(); + Map(x => x.SortingCriteria); + } + } +} diff --git a/JMMServer/Mappings/ImportFolderMap.cs b/JMMServer/Mappings/ImportFolderMap.cs new file mode 100644 index 000000000..d4375518d --- /dev/null +++ b/JMMServer/Mappings/ImportFolderMap.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using FluentNHibernate.Mapping; +using JMMServer.Entities; + +namespace JMMServer.Mappings +{ + public class ImportFolderMap : ClassMap + { + public ImportFolderMap() + { + Not.LazyLoad(); + Id(x => x.ImportFolderID); + + Map(x => x.ImportFolderType).Not.Nullable(); + Map(x => x.ImportFolderLocation).Not.Nullable(); + Map(x => x.ImportFolderName).Not.Nullable(); + Map(x => x.IsDropDestination).Not.Nullable(); + Map(x => x.IsDropSource).Not.Nullable(); + } + } +} diff --git a/JMMServer/Mappings/JMMUserMap.cs b/JMMServer/Mappings/JMMUserMap.cs new file mode 100644 index 000000000..f66c2416f --- /dev/null +++ b/JMMServer/Mappings/JMMUserMap.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using FluentNHibernate.Mapping; +using JMMServer.Entities; + +namespace JMMServer.Mappings +{ + public class JMMUserMap : ClassMap + { + public JMMUserMap() + { + Not.LazyLoad(); + Id(x => x.JMMUserID); + + Map(x => x.HideCategories); + Map(x => x.IsAniDBUser).Not.Nullable(); + Map(x => x.IsTraktUser).Not.Nullable(); + Map(x => x.IsAdmin).Not.Nullable(); + Map(x => x.Password); + Map(x => x.Username); + } + } +} diff --git a/JMMServer/Mappings/LanguageMap.cs b/JMMServer/Mappings/LanguageMap.cs new file mode 100644 index 000000000..0d60981aa --- /dev/null +++ b/JMMServer/Mappings/LanguageMap.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using FluentNHibernate.Mapping; +using JMMServer.Entities; + +namespace JMMServer.Mappings +{ + public class LanguageMap : ClassMap + { + public LanguageMap() + { + Not.LazyLoad(); + Id(x => x.LanguageID); + + Map(x => x.LanguageName).Not.Nullable(); + } + } +} diff --git a/JMMServer/Mappings/MovieDB_FanartMap.cs b/JMMServer/Mappings/MovieDB_FanartMap.cs new file mode 100644 index 000000000..72c838cf2 --- /dev/null +++ b/JMMServer/Mappings/MovieDB_FanartMap.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using FluentNHibernate.Mapping; +using JMMServer.Entities; + +namespace JMMServer.Mappings +{ + public class MovieDB_FanartMap : ClassMap + { + public MovieDB_FanartMap() + { + Not.LazyLoad(); + Id(x => x.MovieDB_FanartID); + + Map(x => x.Enabled).Not.Nullable(); + Map(x => x.ImageHeight).Not.Nullable(); + Map(x => x.ImageID).Not.Nullable(); + Map(x => x.ImageSize); + Map(x => x.ImageType); + Map(x => x.ImageWidth).Not.Nullable(); + Map(x => x.MovieId).Not.Nullable(); + Map(x => x.URL); + } + } +} diff --git a/JMMServer/Mappings/MovieDB_MovieMap.cs b/JMMServer/Mappings/MovieDB_MovieMap.cs new file mode 100644 index 000000000..2f552934e --- /dev/null +++ b/JMMServer/Mappings/MovieDB_MovieMap.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using FluentNHibernate.Mapping; +using JMMServer.Entities; + +namespace JMMServer.Mappings +{ + public class MovieDB_MovieMap : ClassMap + { + public MovieDB_MovieMap() + { + Not.LazyLoad(); + Id(x => x.MovieDB_MovieID); + + Map(x => x.MovieId).Not.Nullable(); + Map(x => x.MovieName); + Map(x => x.OriginalName); + Map(x => x.Overview); + + } + } +} diff --git a/JMMServer/Mappings/MovieDB_PosterMap.cs b/JMMServer/Mappings/MovieDB_PosterMap.cs new file mode 100644 index 000000000..5eba624b7 --- /dev/null +++ b/JMMServer/Mappings/MovieDB_PosterMap.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using FluentNHibernate.Mapping; +using JMMServer.Entities; + +namespace JMMServer.Mappings +{ + public class MovieDB_PosterMap : ClassMap + { + public MovieDB_PosterMap() + { + Not.LazyLoad(); + Id(x => x.MovieDB_PosterID); + + Map(x => x.Enabled).Not.Nullable(); + Map(x => x.ImageHeight).Not.Nullable(); + Map(x => x.ImageID).Not.Nullable(); + Map(x => x.ImageSize); + Map(x => x.ImageType); + Map(x => x.ImageWidth).Not.Nullable(); + Map(x => x.MovieId).Not.Nullable(); + Map(x => x.URL); + } + } +} diff --git a/JMMServer/Mappings/ScheduledUpdateMap.cs b/JMMServer/Mappings/ScheduledUpdateMap.cs new file mode 100644 index 000000000..7ea72a192 --- /dev/null +++ b/JMMServer/Mappings/ScheduledUpdateMap.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using FluentNHibernate.Mapping; +using JMMServer.Entities; + +namespace JMMServer.Mappings +{ + public class ScheduledUpdateMap : ClassMap + { + public ScheduledUpdateMap() + { + Not.LazyLoad(); + Id(x => x.ScheduledUpdateID); + + Map(x => x.LastUpdate).Not.Nullable(); + Map(x => x.UpdateDetails); + Map(x => x.UpdateType).Not.Nullable(); + } + } +} diff --git a/JMMServer/Mappings/Trakt_EpisodeMap.cs b/JMMServer/Mappings/Trakt_EpisodeMap.cs new file mode 100644 index 000000000..eab8983af --- /dev/null +++ b/JMMServer/Mappings/Trakt_EpisodeMap.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using FluentNHibernate.Mapping; +using JMMServer.Entities; + +namespace JMMServer.Mappings +{ + public class Trakt_EpisodeMap : ClassMap + { + public Trakt_EpisodeMap() + { + Not.LazyLoad(); + Id(x => x.Trakt_EpisodeID); + + Map(x => x.Trakt_ShowID).Not.Nullable(); + Map(x => x.EpisodeImage); + Map(x => x.EpisodeNumber); + Map(x => x.Overview); + Map(x => x.Season).Not.Nullable(); + Map(x => x.Title); + Map(x => x.URL); + } + } +} diff --git a/JMMServer/Mappings/Trakt_ImageFanartMap.cs b/JMMServer/Mappings/Trakt_ImageFanartMap.cs new file mode 100644 index 000000000..0b45ba58d --- /dev/null +++ b/JMMServer/Mappings/Trakt_ImageFanartMap.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using FluentNHibernate.Mapping; +using JMMServer.Entities; + + +namespace JMMServer.Mappings +{ + public class Trakt_ImageFanartMap : ClassMap + { + public Trakt_ImageFanartMap() + { + Not.LazyLoad(); + Id(x => x.Trakt_ImageFanartID); + + Map(x => x.Enabled).Not.Nullable(); + Map(x => x.ImageURL); + Map(x => x.Season).Not.Nullable(); + Map(x => x.Trakt_ShowID).Not.Nullable(); + } + } +} diff --git a/JMMServer/Mappings/Trakt_ImagePosterMap.cs b/JMMServer/Mappings/Trakt_ImagePosterMap.cs new file mode 100644 index 000000000..db13e87ee --- /dev/null +++ b/JMMServer/Mappings/Trakt_ImagePosterMap.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using FluentNHibernate.Mapping; +using JMMServer.Entities; + + +namespace JMMServer.Mappings +{ + public class Trakt_ImagePosterMap : ClassMap + { + public Trakt_ImagePosterMap() + { + Not.LazyLoad(); + Id(x => x.Trakt_ImagePosterID); + + Map(x => x.Enabled).Not.Nullable(); + Map(x => x.ImageURL); + Map(x => x.Season).Not.Nullable(); + Map(x => x.Trakt_ShowID).Not.Nullable(); + } + } +} diff --git a/JMMServer/Mappings/Trakt_SeasonMap.cs b/JMMServer/Mappings/Trakt_SeasonMap.cs new file mode 100644 index 000000000..34625a2d4 --- /dev/null +++ b/JMMServer/Mappings/Trakt_SeasonMap.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using FluentNHibernate.Mapping; +using JMMServer.Entities; + +namespace JMMServer.Mappings +{ + public class Trakt_SeasonMap : ClassMap + { + public Trakt_SeasonMap() + { + Not.LazyLoad(); + Id(x => x.Trakt_SeasonID); + + Map(x => x.Season).Not.Nullable(); + Map(x => x.Trakt_ShowID).Not.Nullable(); + Map(x => x.URL); + } + } +} diff --git a/JMMServer/Mappings/Trakt_ShowMap.cs b/JMMServer/Mappings/Trakt_ShowMap.cs new file mode 100644 index 000000000..5e0f627cb --- /dev/null +++ b/JMMServer/Mappings/Trakt_ShowMap.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using FluentNHibernate.Mapping; +using JMMServer.Entities; + +namespace JMMServer.Mappings +{ + public class Trakt_ShowMap : ClassMap + { + public Trakt_ShowMap() + { + Not.LazyLoad(); + Id(x => x.Trakt_ShowID); + + Map(x => x.Overview); + Map(x => x.Title); + Map(x => x.TraktID); + Map(x => x.TvDB_ID); + Map(x => x.URL); + Map(x => x.Year); + } + } +} diff --git a/JMMServer/Mappings/TvDB_EpisodeMap.cs b/JMMServer/Mappings/TvDB_EpisodeMap.cs new file mode 100644 index 000000000..b8c0538a0 --- /dev/null +++ b/JMMServer/Mappings/TvDB_EpisodeMap.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using FluentNHibernate.Mapping; +using JMMServer.Entities; + +namespace JMMServer.Mappings +{ + public class TvDB_EpisodeMap : ClassMap + { + public TvDB_EpisodeMap() + { + Not.LazyLoad(); + Id(x => x.TvDB_EpisodeID); + + Map(x => x.AbsoluteNumber); + Map(x => x.EpImgFlag).Not.Nullable(); + Map(x => x.EpisodeName); + Map(x => x.EpisodeNumber).Not.Nullable(); + Map(x => x.Filename); + Map(x => x.Id).Not.Nullable(); + Map(x => x.Overview); + Map(x => x.SeasonID).Not.Nullable(); + Map(x => x.SeasonNumber).Not.Nullable(); + Map(x => x.SeriesID).Not.Nullable(); + + Map(x => x.AirsAfterSeason); + Map(x => x.AirsBeforeEpisode); + Map(x => x.AirsBeforeSeason); + } + } +} diff --git a/JMMServer/Mappings/TvDB_ImageFanartMap.cs b/JMMServer/Mappings/TvDB_ImageFanartMap.cs new file mode 100644 index 000000000..fcd326015 --- /dev/null +++ b/JMMServer/Mappings/TvDB_ImageFanartMap.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using FluentNHibernate.Mapping; +using JMMServer.Entities; + +namespace JMMServer.Mappings +{ + public class TvDB_ImageFanartMap : ClassMap + { + public TvDB_ImageFanartMap() + { + Not.LazyLoad(); + Id(x => x.TvDB_ImageFanartID); + + Map(x => x.BannerPath); + Map(x => x.BannerType); + Map(x => x.BannerType2); + Map(x => x.Chosen).Not.Nullable(); + Map(x => x.Colors); + Map(x => x.Enabled).Not.Nullable(); + Map(x => x.Id).Not.Nullable(); + Map(x => x.Language); + Map(x => x.SeriesID).Not.Nullable(); + Map(x => x.ThumbnailPath); + Map(x => x.VignettePath); + } + } +} diff --git a/JMMServer/Mappings/TvDB_ImagePosterMap.cs b/JMMServer/Mappings/TvDB_ImagePosterMap.cs new file mode 100644 index 000000000..c033eace3 --- /dev/null +++ b/JMMServer/Mappings/TvDB_ImagePosterMap.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using FluentNHibernate.Mapping; +using JMMServer.Entities; + +namespace JMMServer.Mappings +{ + public class TvDB_ImagePosterMap : ClassMap + { + public TvDB_ImagePosterMap() + { + Not.LazyLoad(); + Id(x => x.TvDB_ImagePosterID); + + Map(x => x.BannerPath); + Map(x => x.BannerType); + Map(x => x.BannerType2); + Map(x => x.Enabled).Not.Nullable(); + Map(x => x.Id).Not.Nullable(); + Map(x => x.Language); + Map(x => x.SeriesID).Not.Nullable(); + Map(x => x.SeasonNumber); + } + } +} diff --git a/JMMServer/Mappings/TvDB_ImageWideBannerMap.cs b/JMMServer/Mappings/TvDB_ImageWideBannerMap.cs new file mode 100644 index 000000000..0d0428c8b --- /dev/null +++ b/JMMServer/Mappings/TvDB_ImageWideBannerMap.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using FluentNHibernate.Mapping; +using JMMServer.Entities; + +namespace JMMServer.Mappings +{ + public class TvDB_ImageWideBannerMap : ClassMap + { + public TvDB_ImageWideBannerMap() + { + Not.LazyLoad(); + Id(x => x.TvDB_ImageWideBannerID); + + Map(x => x.BannerPath); + Map(x => x.BannerType); + Map(x => x.BannerType2); + Map(x => x.Enabled).Not.Nullable(); + Map(x => x.Id).Not.Nullable(); + Map(x => x.Language); + Map(x => x.SeriesID).Not.Nullable(); + Map(x => x.SeasonNumber); + } + } +} diff --git a/JMMServer/Mappings/TvDB_SeriesMap.cs b/JMMServer/Mappings/TvDB_SeriesMap.cs new file mode 100644 index 000000000..66cacdd64 --- /dev/null +++ b/JMMServer/Mappings/TvDB_SeriesMap.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using FluentNHibernate.Mapping; +using JMMServer.Entities; + +namespace JMMServer.Mappings +{ + public class TvDB_SeriesMap : ClassMap + { + public TvDB_SeriesMap() + { + Not.LazyLoad(); + Id(x => x.TvDB_SeriesID); + + Map(x => x.SeriesID).Not.Nullable(); + Map(x => x.Banner); + Map(x => x.Fanart); + Map(x => x.Lastupdated); + Map(x => x.Overview); + Map(x => x.Poster); + Map(x => x.SeriesName); + Map(x => x.Status); + + } + } +} diff --git a/JMMServer/Mappings/VersionsMap.cs b/JMMServer/Mappings/VersionsMap.cs new file mode 100644 index 000000000..5e058411c --- /dev/null +++ b/JMMServer/Mappings/VersionsMap.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using FluentNHibernate.Mapping; +using JMMServer.Entities; + +namespace JMMServer.Mappings +{ + public class VersionsMap : ClassMap + { + public VersionsMap() + { + Not.LazyLoad(); + Id(x => x.VersionsID); + Map(x => x.VersionType).Not.Nullable(); + Map(x => x.VersionValue).Not.Nullable(); + } + } +} diff --git a/JMMServer/Mappings/VideoInfoMap.cs b/JMMServer/Mappings/VideoInfoMap.cs new file mode 100644 index 000000000..85cac45d3 --- /dev/null +++ b/JMMServer/Mappings/VideoInfoMap.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using FluentNHibernate.Mapping; +using JMMServer.Entities; + +namespace JMMServer.Mappings +{ + public class VideoInfoMap : ClassMap + { + public VideoInfoMap() + { + Not.LazyLoad(); + Id(x => x.VideoInfoID); + + Map(x => x.AudioBitrate).Not.Nullable(); + Map(x => x.AudioCodec).Not.Nullable(); + Map(x => x.DateTimeUpdated).Not.Nullable(); + Map(x => x.Duration).Not.Nullable(); + Map(x => x.FileName).Not.Nullable(); + Map(x => x.FileSize).Not.Nullable(); + Map(x => x.Hash).Not.Nullable(); + Map(x => x.VideoBitrate).Not.Nullable(); + Map(x => x.VideoCodec).Not.Nullable(); + Map(x => x.VideoFrameRate).Not.Nullable(); + Map(x => x.VideoResolution).Not.Nullable(); + } + } +} diff --git a/JMMServer/Mappings/VideoLocalMap.cs b/JMMServer/Mappings/VideoLocalMap.cs new file mode 100644 index 000000000..4162c9dc7 --- /dev/null +++ b/JMMServer/Mappings/VideoLocalMap.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using FluentNHibernate.Mapping; +using JMMServer.Entities; + +namespace JMMServer.Mappings +{ + public class VideoLocalMap : ClassMap + { + public VideoLocalMap() + { + Not.LazyLoad(); + Id(x => x.VideoLocalID); + + Map(x => x.DateTimeUpdated).Not.Nullable(); + Map(x => x.FilePath).Not.Nullable(); + Map(x => x.FileSize).Not.Nullable(); + Map(x => x.Hash).Not.Nullable(); + Map(x => x.CRC32); + Map(x => x.MD5); + Map(x => x.SHA1); + Map(x => x.HashSource).Not.Nullable(); + Map(x => x.ImportFolderID).Not.Nullable(); + Map(x => x.IsIgnored).Not.Nullable(); + } + } +} diff --git a/JMMServer/Mappings/VideoLocal_UserMap.cs b/JMMServer/Mappings/VideoLocal_UserMap.cs new file mode 100644 index 000000000..136bcf0e1 --- /dev/null +++ b/JMMServer/Mappings/VideoLocal_UserMap.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using FluentNHibernate.Mapping; +using JMMServer.Entities; + +namespace JMMServer.Mappings +{ + public class VideoLocal_UserMap : ClassMap + { + public VideoLocal_UserMap() + { + Not.LazyLoad(); + Id(x => x.VideoLocal_UserID); + + Map(x => x.JMMUserID).Not.Nullable(); + Map(x => x.VideoLocalID).Not.Nullable(); + Map(x => x.WatchedDate); + } + } +} diff --git a/JMMServer/MultiSortLib/MultiSort.cs b/JMMServer/MultiSortLib/MultiSort.cs new file mode 100644 index 000000000..81bca79a5 --- /dev/null +++ b/JMMServer/MultiSortLib/MultiSort.cs @@ -0,0 +1,219 @@ +using System; +using System.Threading; +using System.Collections.Generic; +using System.Diagnostics; +using System.Reflection; + +// Source code by Owen Emlen (owene_1998@yahoo.com, owen@binarynorthwest.com) +// http://www.braintechllc.com/owen.aspx, http://www.binarynorthwest.com + +namespace BinaryNorthwest +{ + /// + /// Determines how a property or field value is treated for comparison. For instance, + /// if you compare the strings "9" and "10", "9" will be placed AFTER "10". However, + /// if you specify Integer sorting, "9" and "10" will be converted to numeric values + /// prior to comparison, resulting in "9" being placed BEFORE "10" (usually a good thing) + /// + public enum SortType + { + eUsePropertyOrFieldType = 0, + eString = 1, + eDoubleOrFloat = 2, + eDateTime = 3, + eByte = 4, + eInteger = 5, + eLong = 6 + } + + /// + /// The sorting methods contained in the static class "Sorting" can be used to sort lists of classes + /// (of any class type) using the value of properties and fields contained within the class. + /// NOTE: Only property and field types are supported at the moment. + /// + public static class Sorting + { + + /// + /// Sorts a given list, in-place, using the specified sortBy (comparison) criterion. + /// This static method is thread-safe -- but only if you remember to lock the list elsewhere + /// if/when you use or modify the same instance of the list in another thread). + /// Those who don't need to worry about threading issues can remove the lock() statement. + /// + /// The business object type to be sorted + /// The list to be sorted, in place + /// Criteria describing the field or property name used in sorting the list + /// (and the direction of the sort) + /// + public static void SortInPlace(List ListToBeSorted, SortPropOrFieldAndDirection sortBy) where T : class + { + try + { + // Retrieve an IComparer that contains logic for sorting this specific business object + // type by the specified criteria + IComparer compare = sortBy.GetComparer(); + lock (ListToBeSorted) { ListToBeSorted.Sort(compare); } + } + catch (Exception ex) + { + throw new Exception("Error trying to sort list of " + typeof(T).Name + " using " + + (sortBy.NameIsPropertyName ? "property " : "field ") + sortBy.sPropertyOrFieldName, ex); + } + } + + /// + /// Sorts a given list using multiple sort (comparison) criteria, similar to a SQL "ORDER BY" clause + /// Example: Specifying the sort/comparison criteria (1) "State" and (2) "Zipcode" using a list of + /// address entries will result in a sorted list containing address entries FIRST sorted by state + /// (starting with the A* states - Alabama, Alaska, etc). Then, the address entries + /// associated with each respective state will be further sorted according to Zipcode. + /// + /// The type of elements in the list to sort + /// The original list. A new, sorted list will be returned. + /// A list of ordered criteria specifying how the list should be sorted. + /// A new list containing all elements of ListToBeSorted, sorted by the criteria + /// specified in rgSortBy. + /// + public static List MultiSort(List ListToBeSorted, List rgSortBy) where T : class + { + List results; + // For thread safety, make a copy of the list up front. Note that you still need to + // lock the same instance of the list when/if it is modified by other threads. + lock (ListToBeSorted) { results = new List(ListToBeSorted); } + + if (rgSortBy.Count == 1) + { + // if only sorting a single time, just call the basic in-place sorting on our copied "results" list + SortInPlace(results, rgSortBy[0]); + return results; + } + + try + { + List> rgCopies = new List>(1); + rgCopies.Add(results); + int sortByCount = rgSortBy.Count; + + // For each criterion in the list of comparison criteria, one or more lists must be sorted. + // Each time a list is sorted, one or more sublists may be created. Each sublist contains + // items that were deemed to be "equivalent" according to the comparison criterion. + // Example: After sorting addresses entries by state you may have multiple sublists, + // each containing all of the address entries associated with a given state. + // Note: this is not the most efficient method (especially in terms of memory!), but it + // is sufficient in most scenarios and is easier to understand than many other + // methods of sorting a list using multiple criteria. + for (int i = 0; i < sortByCount; i++) + { + SortPropOrFieldAndDirection sortBy = rgSortBy[i]; + if (string.IsNullOrEmpty(sortBy.sPropertyOrFieldName)) throw new Exception( + "MultiSort parameter rgSortBy was passed an empty field name in rgSortBy[" + i.ToString() + "]" + ); + + // Retrieve an IComparer that contains logic for sorting this specific business object + // type by the specified criteria + IComparer compare = sortBy.GetComparer(); + + // Sort each sublist using the created IComparer + foreach (List lst in rgCopies) { lst.Sort(compare); } + + if (i < sortByCount - 1) + { + // Create new sublists by searching for the sorted-by value boundaries/changes + // Our "best guess" (i.e. shot in the dark) is that we will create at least 8 sublists + // from the original list. NOT terribly efficient, but often sufficient. + // Some advanced methods involve tracking duplicate values DURING the sort iteself + List> rgNewCopies = new List>(rgCopies.Count * 8); + + for (int n = 0; n < rgCopies.Count; n++) + { + List rgList = rgCopies[n]; + // Be conservative and set the initial sublist capacity to a small number, but + // still honor the original list's item count. (Example: If you are sorting a list + // of "Address information" by Zipcode and the list has 32,000 entries, then initialize + // each sublist (each of which store all Address information entries with the same Zipcode) + // with a capacity of 1000. 32,000 / 32 = 1000 + List rgSublist = new List(rgList.Count / 32); + + // Compare items to the item that preceeded it to determine where the "value boundaries" + // are located. If you will be sorting frequently and do not have cpu cycles to burn :), + // a smarter boundary-finding algorithm should be used. (e.g. determine boundary locations + // when comparing elements during the sort routine). + // Another alternative is to take advantage of the fact that the list is sorted and to + // use a O(LogN) binary search rather than the (currently) linear O(N) search. + for (int j = 0; j < rgList.Count; j++) + { + T item = rgList[j]; + if (j > 0) + { + // Compare the item to the preceeding item using the same comparison criterion + // used during the sort + T itemprev = rgList[j - 1]; + + if (compare.Compare(item, itemprev) == 0) + { + // The item had the same property or field value as the preceeding item. + // Add it on to the same sublist. + rgSublist.Add(item); + } + else + { + // The item did NOT have the same property or field value as the preceeding item. + // "Close up" the previous sublist and start a new one. + rgNewCopies.Add(rgSublist); + rgSublist = new List(rgList.Count / 32); + rgSublist.Add(item); + } + } + else + { + // The first item has no predecessor - just add the item to the first sublist + rgSublist.Add(item); + } + + } // END: for (int j = 0; j < rgList.Count; j++) ... each item in a sublist + + // Add the last created sublist to our "master list of sublists" :P + // It may be that this list has 0 elements in some cases, but this is not a problem + rgNewCopies.Add(rgSublist); + + } // END: for (int n = 0; n < rgCopies.Count; n++) ... each sublist in rgCopies + + // Move to the next "level" of sublists in preparation for further sorting using the next + // sort/comparison criterion + rgCopies = rgNewCopies; + } + + } // END: for (int i = 0; i < sortByCount; i++) ... each sort by criteria: + + + // reconstruct all resorted sub-sub-sub-sub-sublists into a single, final (flat) results list + results.Clear(); + foreach (List rgList in rgCopies) { results.AddRange(rgList); } + + return results; + } + catch (Exception ex) + { + throw new Exception("Exception in MultiSort while sorting a list of " + typeof(T).Name, ex); + } + } + + /// + /// Converts a System.Type into a type comparison enumeration value that is used + /// to quickly convert values to a suitable type for comparison. + /// NOTE: unsigned short/int/long are not yet implemented + /// + /// + /// + public static SortType GetSortTypeEnumForType(Type t) + { + if (t == typeof(string)) return SortType.eString; + else if (t == typeof(DateTime)) return SortType.eDateTime; + else if (t == typeof(int) || t == typeof(short)) return SortType.eInteger; + else if (t == typeof(long)) return SortType.eLong; + else if (t == typeof(bool)) return SortType.eByte; + else if (t == typeof(double) || t == typeof(float)) return SortType.eDoubleOrFloat; + else return SortType.eString; + } + } +} \ No newline at end of file diff --git a/JMMServer/MultiSortLib/SortSearchCriteria.cs b/JMMServer/MultiSortLib/SortSearchCriteria.cs new file mode 100644 index 000000000..3f19592c6 --- /dev/null +++ b/JMMServer/MultiSortLib/SortSearchCriteria.cs @@ -0,0 +1,129 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using System.ComponentModel; + +// Source code by Owen Emlen (owene_1998@yahoo.com, owen@binarynorthwest.com) + +namespace BinaryNorthwest +{ + /// + /// Stores a property or field name that will be used to determine sort order. + /// Also contains a flag, fSortDescending, for specifying descending sort order. + /// + public class SortPropOrFieldAndDirection + { + #region "Constructors" + public SortPropOrFieldAndDirection() { } + + public SortPropOrFieldAndDirection(string sPropOrFieldNameToSort) + { + sPropertyOrFieldName = sPropOrFieldNameToSort; + } + + public SortPropOrFieldAndDirection(string sPropOrFieldNameToSort, bool fDescendingSort) + { + sPropertyOrFieldName = sPropOrFieldNameToSort; + fSortDescending = fDescendingSort; + } + + public SortPropOrFieldAndDirection(string sPropOrFieldNameToSort, SortType sortTyp) + { + sPropertyOrFieldName = sPropOrFieldNameToSort; + sortType = sortTyp; + } + + public SortPropOrFieldAndDirection(string sPropOrFieldNameToSort, bool fDescendingSort, SortType sortTyp) + { + sPropertyOrFieldName = sPropOrFieldNameToSort; + fSortDescending = fDescendingSort; + sortType = sortTyp; + } + + public SortPropOrFieldAndDirection(string sPropOrFieldNameToSort, bool fDescendingSort, SortType sortTyp, StringComparison stringComp) + { + sPropertyOrFieldName = sPropOrFieldNameToSort; + fSortDescending = fDescendingSort; + sortType = sortTyp; + stringComparison = stringComp; + } + #endregion + + /// + /// Retrieves a IComparer of type T, depending on whether the instance of this + /// class (or a derived class) references a property or field + /// + /// + /// + public IComparer GetComparer() where T : class + { + if (NameIsPropertyName) + { + CompareProperties comp = new CompareProperties(sPropertyOrFieldName, fSortDescending, sortType); + comp.pi = pi; + comp.Initialize(); + comp.SetStringComparisonType(stringComparison); + return comp; + } + else + { + CompareFields comp = new CompareFields(sPropertyOrFieldName, fSortDescending, sortType); + comp.fi = fi; + comp.Initialize(); + comp.SetStringComparisonType(stringComparison); + return comp; + } + } + + #region "Fields and Properties" + /// + /// This virtual property is overridden in the SortPropertyAndDirection and SortFieldAndDirection + /// (derived) classes. It indicates whether the "sPropertyOrFieldName" field refers to a + /// property name or a field name. + /// + internal virtual bool NameIsPropertyName { get { return true; } } + public string sPropertyOrFieldName; + public bool fSortDescending; + public SortType sortType = SortType.eUsePropertyOrFieldType; + public StringComparison stringComparison = StringComparison.OrdinalIgnoreCase; + + /// + /// (Cached PropertyInfo or FieldInfo) + /// These fields are made available to avoid repeat reflection (GetProperty/GetField) if the caller has + /// already obtained the PropertyInfo or FieldInfo class instances for the property/field + /// + public PropertyInfo pi; + + + public PropertyDescriptor property; + + public FieldInfo fi; + #endregion + } + + /// + /// A SortPropOrFieldAndDirection-derived class, SortPropertyAndDirection handles PropertyInfo caching and asc/desc logic + /// + public class SortPropertyAndDirection : SortPropOrFieldAndDirection + { + internal override bool NameIsPropertyName { get { return true; } } + public SortPropertyAndDirection() : base() { } + public SortPropertyAndDirection(string sPropOrFieldNameToSort) : base(sPropOrFieldNameToSort) { } + public SortPropertyAndDirection(string sPropOrFieldNameToSort, bool fDescendingSort) : base(sPropOrFieldNameToSort, fDescendingSort) { } + public SortPropertyAndDirection(string sPropOrFieldNameToSort, SortType sortTyp) : base(sPropOrFieldNameToSort, sortTyp) { } + public SortPropertyAndDirection(string sPropOrFieldNameToSort, bool fDescendingSort, SortType sortTyp) : base(sPropOrFieldNameToSort, fDescendingSort, sortTyp) { } + } + + /// + /// A SortPropOrFieldAndDirection-derived class, SortFieldAndDirection handles FieldInfo caching and asc/desc logic + /// + public class SortFieldAndDirection : SortPropOrFieldAndDirection + { + internal override bool NameIsPropertyName { get { return false; } } + public SortFieldAndDirection() : base() { } + public SortFieldAndDirection(string sPropOrFieldNameToSort) : base(sPropOrFieldNameToSort) { } + public SortFieldAndDirection(string sPropOrFieldNameToSort, bool fDescendingSort) : base(sPropOrFieldNameToSort, fDescendingSort) { } + public SortFieldAndDirection(string sPropOrFieldNameToSort, SortType sortTyp) : base(sPropOrFieldNameToSort, sortTyp) { } + public SortFieldAndDirection(string sPropOrFieldNameToSort, bool fDescendingSort, SortType sortTyp) : base(sPropOrFieldNameToSort, fDescendingSort, sortTyp) { } + } +} diff --git a/JMMServer/MultiSortLib/ValueComparison.cs b/JMMServer/MultiSortLib/ValueComparison.cs new file mode 100644 index 000000000..891784756 --- /dev/null +++ b/JMMServer/MultiSortLib/ValueComparison.cs @@ -0,0 +1,615 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Text; +using System.ComponentModel; + +// Source code by Owen Emlen (owene_1998@yahoo.com, owen@binarynorthwest.com) + +namespace BinaryNorthwest +{ + /// + /// Provides quick access to property values and handles value comparisons. + /// Note: This class uses PropertyDescriptor.GetValue(object) to retrieve property information. + /// The speed of property retrieval has been greatly improved by the addition of Marc Gravell's code for + /// HyperPropertyDescriptors, located at http://www.codeproject.com/csharp/HyperPropertyDescriptor.asp + /// + /// + public class CompareProperties : IComparer where T : class + { + private static Dictionary FastEnumLookup; + + public SortType sortType = SortType.eUsePropertyOrFieldType; + + #region "Fields" + /// + /// Stores the cached property info and type, used to retrieve values + /// Note: Retrieving property values used to involve invoking the property Get accessor + /// and thus was significantly slower that retrieving a field value. However, using Marc Gravell's + /// HyperPropertyDescriptor code, property retrieval is now much faster than retrieval of field values. + /// + public PropertyInfo pi; + public PropertyDescriptor property; + + internal Type typ; + internal bool fFoundProperty; + internal string sPropertyName; + internal bool fSortDescending; + internal StringComparison stringComparisonToUse = StringComparison.Ordinal; + #endregion + + #region "Constructors" + public CompareProperties(string sPropName, bool fDescendingSort) + { + sPropertyName = sPropName; + fSortDescending = fDescendingSort; + } + + public CompareProperties(string sPropName, bool fDescendingSort, SortType sortTyp) + { + sPropertyName = sPropName; + fSortDescending = fDescendingSort; + sortType = sortTyp; + } + #endregion + + #region "Manual Overrides" + /// + /// Override the sort type at your own peril. If any field/property value can't be converted + /// to the type you specify, an exception will be raised. + /// + /// + public void SetOverrideSortType(SortType sortTyp) { sortType = sortTyp; } + + /// + /// Default string comparison type is Ordinal. Using this method, you can specify + /// other options, such as OrdinalIgnoreCase (for case insensitive comparison), etc + /// + /// + public void SetStringComparisonType(StringComparison stringComparisonType) + { + stringComparisonToUse = stringComparisonType; + } + #endregion + + /// + /// For speed, a delegate is used when we know the type of value that will be returned + /// from the GetValue() method + /// + /// + /// + /// + public delegate int TypeSensitiveCompare(T x, T y); + public TypeSensitiveCompare DoCompare; + + /// + /// Sets up cached PropertyInfo and determines the best delegate to use to compare values + /// retrieved from that property. + /// + public void Initialize() + { + if (fFoundProperty == false) + { + fFoundProperty = true; + if (pi == null) + { + PropertyDescriptorCollection props = TypeDescriptor.GetProperties(typeof(T)); + property = props[sPropertyName]; + pi = typeof(T).GetProperty(sPropertyName); + + if (pi == null) + { + throw new Exception("Property name " + sPropertyName + + " not found while trying to compare objects of type " + typeof(T).Name); + } + } + typ = pi.PropertyType; + // Set up the property comparison delegate to use based on the type of values we will be comparing + if (sortType == SortType.eUsePropertyOrFieldType) + { + sortType = Sorting.GetSortTypeEnumForType(typ); + if (typ == typeof(string)) + { + if (stringComparisonToUse == StringComparison.Ordinal) DoCompare = StringCompareOrdinal; + else DoCompare = StringCompare; + } + else if (typ == typeof(int) && !fSortDescending) DoCompare = CompareInt; + else if (typ == typeof(int)) DoCompare = CompareIntDesc; + else if (typ == typeof(DateTime)) DoCompare = CompareDates; + else if (typ == typeof(long)) DoCompare = CompareTypeSensitive; + else if (typ == typeof(double)) DoCompare = CompareTypeSensitive; + else if (typ == typeof(float)) DoCompare = CompareTypeSensitive; + else if (typ == typeof(short)) DoCompare = CompareTypeSensitive; + else if (typ == typeof(byte)) DoCompare = CompareTypeSensitive; + else if (typ == typeof(bool)) DoCompare = CompareTypeSensitive; + else if (typ.BaseType == typeof(Enum)) + { + FastEnumLookup = new Dictionary(32); + if (fSortDescending) { DoCompare = FastCompareEnumsDesc; } + else { DoCompare = FastCompareEnumsAsc; } + } + else DoCompare = CompareUsingToString; + } + else + { + if (sortType == SortType.eString) DoCompare = CompareUsingToString; + else if (sortType == SortType.eByte) DoCompare = CompareUsingToByte; + else if (sortType == SortType.eDateTime) DoCompare = CompareUsingToDate; + else if (sortType == SortType.eInteger) DoCompare = CompareUsingToInt; + else if (sortType == SortType.eLong) DoCompare = CompareUsingToInt64; + else if (sortType == SortType.eDoubleOrFloat) DoCompare = CompareUsingToDouble; + else DoCompare = CompareUsingToString; + } + } + } + + #region "Compare method - handles value retrieval and value comparison" + /// + /// Compare to values, both of which are known to be of type string + /// + /// + /// + /// + public int StringCompare(T x, T y) + { + //int nComp = string.Compare((string)pi.GetValue(x, null), (string)pi.GetValue(y, null), stringComparisonToUse); + int nComp = string.Compare((string)property.GetValue(x), (string)property.GetValue(y), stringComparisonToUse); + return (!fSortDescending ? nComp : -nComp); + } + + public int StringCompareOrdinal(T x, T y) + { + //int nComp = string.Compare((string)pi.GetValue(x, null), (string)pi.GetValue(y, null), StringComparison.Ordinal); + int nComp = string.Compare((string)property.GetValue(x), (string)property.GetValue(y), StringComparison.Ordinal); + return (!fSortDescending ? nComp : -nComp); + } + + public int CompareIntDesc(T x, T y) + { + //int oX = (int)pi.GetValue(x, null); + //int oY = (int)pi.GetValue(y, null); + int oX = (int)property.GetValue(x); + int oY = (int)property.GetValue(y); + return (oX < oY) ? 1 : ((oX == oY) ? 0 : -1); + } + + public int CompareInt(T x, T y) + { + //int oX = (int)pi.GetValue(x, null); + //int oY = (int)pi.GetValue(y, null); + int oX = (int)property.GetValue(x); + int oY = (int)property.GetValue(y); + return (oX < oY) ? -1 : ((oX == oY) ? 0 : 1); + } + + /// + /// Compare to values, checking for null and converting to strings before comparison + /// + /// + /// + /// + public int CompareUsingToString(T x, T y) + { + //object oX = pi.GetValue(x, null); + //object oY = pi.GetValue(y, null); + object oX = property.GetValue(x); + object oY = property.GetValue(y); + int nComp; + // handle null appropriately only for string sorting + if (oX == null) { nComp = (oY != null) ? -1 : 0; } + else if (oY == null) { nComp = 1; } + else { nComp = string.Compare(oX.ToString(), oY.ToString(), stringComparisonToUse); } + return (!fSortDescending) ? nComp : -nComp; + } + + public int CompareUsingToByte(T x, T y) + { + //byte oX = Convert.ToByte(pi.GetValue(x, null)); + //byte oY = Convert.ToByte(pi.GetValue(y, null)); + byte oX = Convert.ToByte(property.GetValue(x)); + byte oY = Convert.ToByte(property.GetValue(y)); + int nComp = (oX > oY) ? 1 : ((oX < oY) ? -1 : 0); + return (!fSortDescending) ? nComp : -nComp; + } + + public int CompareUsingToInt(T x, T y) + { + //int oX = Convert.ToInt32(pi.GetValue(x, null)); + //int oY = Convert.ToInt32(pi.GetValue(y, null)); + int oX = Convert.ToInt32(property.GetValue(x)); + int oY = Convert.ToInt32(property.GetValue(y)); + int nComp = (oX > oY) ? 1 : ((oX < oY) ? -1 : 0); + return (!fSortDescending) ? nComp : -nComp; + } + + public int CompareUsingToInt64(T x, T y) + { + //Int64 oX = Convert.ToInt64(pi.GetValue(x, null)); + //Int64 oY = Convert.ToInt64(pi.GetValue(y, null)); + Int64 oX = Convert.ToInt64(property.GetValue(x)); + Int64 oY = Convert.ToInt64(property.GetValue(y)); + int nComp = (oX > oY) ? 1 : ((oX < oY) ? -1 : 0); + return (!fSortDescending) ? nComp : -nComp; + } + + public int CompareUsingToDouble(T x, T y) + { + //double oX = Convert.ToDouble(pi.GetValue(x, null)); + //double oY = Convert.ToDouble(pi.GetValue(y, null)); + double oX = Convert.ToDouble(property.GetValue(x)); + double oY = Convert.ToDouble(property.GetValue(y)); + int nComp = (oX > oY) ? 1 : ((oX < oY) ? -1 : 0); + return (!fSortDescending) ? nComp : -nComp; + } + + public int CompareUsingToDate(T x, T y) + { + //DateTime oX = Convert.ToDateTime(pi.GetValue(x, null)); + //DateTime oY = Convert.ToDateTime(pi.GetValue(y, null)); + DateTime oX = Convert.ToDateTime(property.GetValue(x)); + DateTime oY = Convert.ToDateTime(property.GetValue(y)); + int nComp = oX.CompareTo(oY); + return (!fSortDescending) ? nComp : -nComp; + } + + public int CompareDates(T x, T y) + { + //DateTime oX = (DateTime)pi.GetValue(x, null); + //DateTime oY = (DateTime)pi.GetValue(y, null); + DateTime oX = (DateTime)property.GetValue(x); + DateTime oY = (DateTime)property.GetValue(y); + int nComp = oX.CompareTo(oY); + return (!fSortDescending) ? nComp : -nComp; + } + + public int CompareTypeSensitive(T x, T y) where T2 : IComparable + { + //T2 oX = (T2)pi.GetValue(x, null); + //T2 oY = (T2)pi.GetValue(y, null); + T2 oX = (T2)property.GetValue(x); + T2 oY = (T2)property.GetValue(y); + int nComp = oX.CompareTo(oY); + return (!fSortDescending) ? nComp : -nComp; + } + + /// + /// Faster than comparing enums using .ToString() + /// (the Enum.ToString() method appears to be fairly expensive) + /// + /// + /// + /// + public int FastCompareEnumsAsc(T x, T y) + { + int oX = (int)property.GetValue(x); + int oY = (int)property.GetValue(y); + string s1, s2; + + if (!FastEnumLookup.TryGetValue(oX, out s1)) + { + Enum eX = (Enum)property.GetValue(x); + s1 = eX.ToString(); + FastEnumLookup.Add(oX, s1); + } + if (!FastEnumLookup.TryGetValue(oY, out s2)) + { + Enum eY = (Enum)property.GetValue(y); + s2 = eY.ToString(); + FastEnumLookup.Add(oY, s2); + } + return s1.CompareTo(s2); + } + + public int FastCompareEnumsDesc(T x, T y) + { + int oX = (int)property.GetValue(x); + int oY = (int)property.GetValue(y); + string s1, s2; + + if (!FastEnumLookup.TryGetValue(oX, out s1)) + { + Enum eX = (Enum)property.GetValue(x); + s1 = eX.ToString(); + FastEnumLookup.Add(oX, s1); + } + if (!FastEnumLookup.TryGetValue(oY, out s2)) + { + Enum eY = (Enum)property.GetValue(y); + s2 = eY.ToString(); + FastEnumLookup.Add(oY, s2); + } + return s2.CompareTo(s1); + } + #endregion + + int IComparer.Compare(T x, T y) { return DoCompare(x, y); } + } + + /// + /// Provides (fairly) quick access to field values and handles value comparisons. + /// Note: This class uses FieldInfo.GetValue to retrieve field values. Speed of field value retrieval is significantly + /// slower when retrieving the value of protected or private fields (due to a runtime security check when retrieving + /// protected/private field values). Also, due to the massive speed improvements in retrieving property values offered + /// by Marc Gravell in his article at http://www.codeproject.com/csharp/HyperPropertyDescriptor.asp, + /// property value retrieval is currently much faster than retrieving the value of a field. + /// + /// + public class CompareFields : IComparer where T : class + { + private static Dictionary FastEnumLookup; + + public SortType sortType = SortType.eUsePropertyOrFieldType; + + #region "Internal Fields" + /// + /// Stores the cached field info and type, used to retrieve field values + /// Note: Retrieving field values is moderately to significantly faster than + /// retrieving property values (even if the property's Get accessor only returns + /// the underlying field value). However, you should make sure that you + /// aren't bypassing critical logic, error checking, or code safety by directly + /// accessing field values. + /// + public FieldInfo fi; + internal Type typ; + internal bool fFoundField; + internal string sFieldName; + internal bool fSortDescending; + internal StringComparison stringComparisonToUse = StringComparison.Ordinal; + #endregion + + #region "Constructors" + public CompareFields(string sNameOfField, bool fDescendingSort) + { + sFieldName = sNameOfField; + fSortDescending = fDescendingSort; + } + + public CompareFields(string sNameOfField, bool fDescendingSort, SortType sortTyp) + { + sFieldName = sNameOfField; + fSortDescending = fDescendingSort; + sortType = sortTyp; + } + #endregion + + #region "Manual Overrides" + /// + /// Override the sort type at your own peril. If any field/property value can't be converted + /// to the type you specify, an exception will be raised. + /// + /// + public void SetOverrideSortType(SortType sortTyp) { sortType = sortTyp; } + + /// + /// Default string comparison type is Ordinal. Using this method, you can specify + /// other options, such as OrdinalIgnoreCase (for case insensitive comparison), etc + /// + /// + public void SetStringComparisonType(StringComparison stringComparisonType) + { + stringComparisonToUse = stringComparisonType; + } + #endregion + + /// + /// For speed, a delegate is used when we know the type of value that will be returned + /// from the GetValue() method + /// + /// + /// + /// + public delegate int TypeSensitiveCompare(T x, T y); + public TypeSensitiveCompare DoCompare; + + /// + /// Sets up cached FieldInfo and determines the best delegate to use to compare values + /// retrieved from that field. + /// + public void Initialize() + { + if (fFoundField == false) + { + fFoundField = true; + + if (fi == null) + { + // You can play around with binding flags if you really want to access nonpublic fields, etc... + // note that there is a significant performance hit on accessing protected and private fields, + // since security / permissions are checked every time, from what I can tell. It's better + // just to go through public properties if you're not accessing public fields. + // fi = typeof(T).GetField(sFieldName, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance); + fi = typeof(T).GetField(sFieldName); + if (fi == null) + { + throw new Exception("Field name " + sFieldName + + " not found while trying to compare objects of type " + typeof(T).Name); + } + } + typ = fi.FieldType; + if (sortType == SortType.eUsePropertyOrFieldType) + { + sortType = Sorting.GetSortTypeEnumForType(typ); + if (typ == typeof(string)) + { + if (stringComparisonToUse == StringComparison.Ordinal) DoCompare = StringCompareOrdinal; + else DoCompare = StringCompare; + } + else if (typ == typeof(int) && !fSortDescending) DoCompare = CompareInt; + else if (typ == typeof(int)) DoCompare = CompareIntDesc; + else if (typ == typeof(DateTime)) DoCompare = CompareDates; + else if (typ == typeof(long)) DoCompare = CompareTypeSensitive; + else if (typ == typeof(double)) DoCompare = CompareTypeSensitive; + else if (typ == typeof(float)) DoCompare = CompareTypeSensitive; + else if (typ == typeof(short)) DoCompare = CompareTypeSensitive; + else if (typ == typeof(byte)) DoCompare = CompareTypeSensitive; + else if (typ == typeof(bool)) DoCompare = CompareTypeSensitive; + else if (typ.BaseType == typeof(Enum)) + { + FastEnumLookup = new Dictionary(32); + if (fSortDescending) { DoCompare = FastCompareEnumsDesc; } + else { DoCompare = FastCompareEnumsAsc; } + } + else DoCompare = CompareUsingToString; + // optimize to use the ABOVE path if the property or field type matches + // the requested sort type (i.e. below) + } + else + { + if (sortType == SortType.eString) DoCompare = CompareUsingToString; + else if (sortType == SortType.eByte) DoCompare = CompareUsingToByte; + else if (sortType == SortType.eDateTime) DoCompare = CompareUsingToDate; + else if (sortType == SortType.eInteger) DoCompare = CompareUsingToInt; + else if (sortType == SortType.eLong) DoCompare = CompareUsingToInt64; + else if (sortType == SortType.eDoubleOrFloat) DoCompare = CompareUsingToDouble; + else DoCompare = CompareUsingToString; + } + } + } + + #region "Compare method - handles retrieval and comparison" + public int StringCompare(T x, T y) + { + int nComp = string.Compare((string)fi.GetValue(x), (string)fi.GetValue(y), stringComparisonToUse); + return (!fSortDescending ? nComp : -nComp); + } + + public int StringCompareOrdinal(T x, T y) + { + int nComp = string.Compare((string)fi.GetValue(x), (string)fi.GetValue(y), StringComparison.Ordinal); + return (!fSortDescending ? nComp : -nComp); + } + + public int CompareIntDesc(T x, T y) + { + int oX = (int)fi.GetValue(x); + int oY = (int)fi.GetValue(y); + return (oX < oY) ? 1 : ((oX == oY) ? 0 : -1); + } + public int CompareInt(T x, T y) + { + int oX = (int)fi.GetValue(x); + int oY = (int)fi.GetValue(y); + return (oX < oY) ? -1 : ((oX == oY) ? 0 : 1); + } + + public int CompareUsingToString(T x, T y) + { + object oX = fi.GetValue(x); + object oY = fi.GetValue(y); + int nComp; + // handle null appropriately only for string sorting + if (oX == null) { nComp = (oY != null) ? -1 : 0; } + else if (oY == null) { nComp = 1; } + else { nComp = string.Compare(oX.ToString(), oY.ToString(), stringComparisonToUse); } + return (!fSortDescending) ? nComp : -nComp; + } + + public int CompareUsingToByte(T x, T y) + { + byte oX = Convert.ToByte(fi.GetValue(x)); + byte oY = Convert.ToByte(fi.GetValue(y)); + int nComp = (oX > oY) ? 1 : ((oX < oY) ? -1 : 0); + return (!fSortDescending) ? nComp : -nComp; + } + + public int CompareUsingToInt(T x, T y) + { + int oX = Convert.ToInt32(fi.GetValue(x)); + int oY = Convert.ToInt32(fi.GetValue(y)); + int nComp = (oX > oY) ? 1 : ((oX < oY) ? -1 : 0); + return (!fSortDescending) ? nComp : -nComp; + } + + public int CompareUsingToInt64(T x, T y) + { + Int64 oX = Convert.ToInt64(fi.GetValue(x)); + Int64 oY = Convert.ToInt64(fi.GetValue(y)); + int nComp = (oX > oY) ? 1 : ((oX < oY) ? -1 : 0); + return (!fSortDescending) ? nComp : -nComp; + } + + public int CompareUsingToDouble(T x, T y) + { + double oX = Convert.ToDouble(fi.GetValue(x)); + double oY = Convert.ToDouble(fi.GetValue(y)); + int nComp = (oX > oY) ? 1 : ((oX < oY) ? -1 : 0); + return (!fSortDescending) ? nComp : -nComp; + } + + public int CompareUsingToDate(T x, T y) + { + DateTime oX = Convert.ToDateTime(fi.GetValue(x)); + DateTime oY = Convert.ToDateTime(fi.GetValue(y)); + int nComp = oX.CompareTo(oY); + return (!fSortDescending) ? nComp : -nComp; + } + + public int CompareDates(T x, T y) + { + DateTime oX = (DateTime)fi.GetValue(x); + DateTime oY = (DateTime)fi.GetValue(y); + int nComp = oX.CompareTo(oY); + return (!fSortDescending) ? nComp : -nComp; + } + + public int CompareTypeSensitive(T x, T y) where T2 : IComparable + { + T2 oX = (T2)fi.GetValue(x); + T2 oY = (T2)fi.GetValue(y); + int nComp = oX.CompareTo(oY); + return (!fSortDescending) ? nComp : -nComp; + } + + /// + /// Faster than comparing enums using .ToString() + /// (the Enum.ToString() method appears to be fairly expensive) + /// + /// + /// + /// + public int FastCompareEnumsAsc(T x, T y) + { + int oX = (int)fi.GetValue(x); + int oY = (int)fi.GetValue(y); + string s1, s2; + + if (!FastEnumLookup.TryGetValue(oX, out s1)) + { + Enum eX = (Enum)fi.GetValue(x); + s1 = eX.ToString(); + FastEnumLookup.Add(oX, s1); + } + if (!FastEnumLookup.TryGetValue(oY, out s2)) + { + Enum eY = (Enum)fi.GetValue(y); + s2 = eY.ToString(); + FastEnumLookup.Add(oY, s2); + } + return s1.CompareTo(s2); + } + + public int FastCompareEnumsDesc(T x, T y) + { + int oX = (int)fi.GetValue(x); + int oY = (int)fi.GetValue(y); + string s1, s2; + + if (!FastEnumLookup.TryGetValue(oX, out s1)) + { + Enum eX = (Enum)fi.GetValue(x); + s1 = eX.ToString(); + FastEnumLookup.Add(oX, s1); + } + if (!FastEnumLookup.TryGetValue(oY, out s2)) + { + Enum eY = (Enum)fi.GetValue(y); + s2 = eY.ToString(); + FastEnumLookup.Add(oY, s2); + } + return s2.CompareTo(s1); + } + #endregion + + int IComparer.Compare(T x, T y) { return DoCompare(x, y); } + } +} diff --git a/JMMServer/NamingLanguage.cs b/JMMServer/NamingLanguage.cs new file mode 100644 index 000000000..7221a22fe --- /dev/null +++ b/JMMServer/NamingLanguage.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace JMMServer +{ + public class NamingLanguage + { + public string Language { get; set; } + + public string LanguageDescription + { + get + { + return Languages.GetLanguageDescription(Language.Trim().ToUpper()); + + } + } + + public NamingLanguage() + { + } + + public NamingLanguage(string language) + { + this.Language = language; + } + + public override string ToString() + { + return string.Format("{0} - ({1})", Language, LanguageDescription); + } + } +} diff --git a/JMMServer/Properties/AssemblyInfo.cs b/JMMServer/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..13b2ac067 --- /dev/null +++ b/JMMServer/Properties/AssemblyInfo.cs @@ -0,0 +1,55 @@ +using System.Reflection; +using System.Resources; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Windows; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("JMMServer")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Microsoft")] +[assembly: AssemblyProduct("JMMServer")] +[assembly: AssemblyCopyright("Copyright © Microsoft 2011")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +//In order to begin building localizable applications, set +//CultureYouAreCodingWith in your .csproj file +//inside a . For example, if you are using US english +//in your source files, set the to en-US. Then uncomment +//the NeutralResourceLanguage attribute below. Update the "en-US" in +//the line below to match the UICulture setting in the project file. + +//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] + + +[assembly: ThemeInfo( + ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located + //(used if a resource is not found in the page, + // or application resource dictionaries) + ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located + //(used if a resource is not found in the page, + // app, or any theme specific resource dictionaries) +)] + + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/JMMServer/Properties/Resources.Designer.cs b/JMMServer/Properties/Resources.Designer.cs new file mode 100644 index 000000000..7727f9327 --- /dev/null +++ b/JMMServer/Properties/Resources.Designer.cs @@ -0,0 +1,71 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.225 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace JMMServer.Properties +{ + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources + { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() + { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager + { + get + { + if ((resourceMan == null)) + { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("JMMServer.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture + { + get + { + return resourceCulture; + } + set + { + resourceCulture = value; + } + } + } +} diff --git a/JMMServer/Properties/Resources.resx b/JMMServer/Properties/Resources.resx new file mode 100644 index 000000000..ffecec851 --- /dev/null +++ b/JMMServer/Properties/Resources.resx @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JMMServer/Properties/Settings.Designer.cs b/JMMServer/Properties/Settings.Designer.cs new file mode 100644 index 000000000..96b20d59d --- /dev/null +++ b/JMMServer/Properties/Settings.Designer.cs @@ -0,0 +1,30 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.225 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace JMMServer.Properties +{ + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "10.0.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase + { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default + { + get + { + return defaultInstance; + } + } + } +} diff --git a/JMMServer/Properties/Settings.settings b/JMMServer/Properties/Settings.settings new file mode 100644 index 000000000..8f2fd95d6 --- /dev/null +++ b/JMMServer/Properties/Settings.settings @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/JMMServer/Providers/JSONHelper.cs b/JMMServer/Providers/JSONHelper.cs new file mode 100644 index 000000000..08926df7b --- /dev/null +++ b/JMMServer/Providers/JSONHelper.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.IO; + +namespace JMMServer.Providers +{ + public class JSONHelper + { + public static string Serialize(T obj) + { + System.Runtime.Serialization.Json.DataContractJsonSerializer serializer = new System.Runtime.Serialization.Json.DataContractJsonSerializer(obj.GetType()); + MemoryStream ms = new MemoryStream(); + serializer.WriteObject(ms, obj); + string retVal = Encoding.Default.GetString(ms.ToArray()); + ms.Dispose(); + return retVal; + } + + public static T Deserialize(string json) + { + T obj = Activator.CreateInstance(); + MemoryStream ms = new MemoryStream(Encoding.Unicode.GetBytes(json)); + System.Runtime.Serialization.Json.DataContractJsonSerializer serializer = new System.Runtime.Serialization.Json.DataContractJsonSerializer(obj.GetType()); + obj = (T)serializer.ReadObject(ms); + ms.Close(); + ms.Dispose(); + return obj; + } + } +} diff --git a/JMMServer/Providers/MovieDB/MovieDBHelper.cs b/JMMServer/Providers/MovieDB/MovieDBHelper.cs new file mode 100644 index 000000000..e7aa7d8d8 --- /dev/null +++ b/JMMServer/Providers/MovieDB/MovieDBHelper.cs @@ -0,0 +1,235 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Xml; +using NLog; +using JMMServer.Repositories; +using JMMServer.Entities; +using JMMServer.Commands; +using System.IO; + +namespace JMMServer.Providers.MovieDB +{ + public class MovieDBHelper + { + private static Logger logger = LogManager.GetCurrentClassLogger(); + private static UTF8Encoding enc = new UTF8Encoding(); + private static string apiKey = "8192e8032758f0ef4f7caa1ab7b32dd3"; + + public static string SearchURL + { + get { return @"http://api.themoviedb.org/2.1/Movie.search/en/xml/{0}/{1}"; } + + } + + public static string InfoURL + { + get { return @"http://api.themoviedb.org/2.1/Movie.getInfo/en/xml/{0}/{1}"; } + } + + private static void SaveMovieToDatabase(MovieDB_Movie_Result searchResult, bool saveImages) + { + MovieDB_MovieRepository repMovies = new MovieDB_MovieRepository(); + MovieDB_FanartRepository repFanart = new MovieDB_FanartRepository(); + MovieDB_PosterRepository repPosters = new MovieDB_PosterRepository(); + + // save to the DB + MovieDB_Movie movie = repMovies.GetByOnlineID(searchResult.MovieID); + if (movie == null) movie = new MovieDB_Movie(); + movie.Populate(searchResult); + repMovies.Save(movie); + + if (!saveImages) return; + + foreach (MovieDB_Image_Result img in searchResult.Images) + { + if (img.ImageType.Equals("poster", StringComparison.InvariantCultureIgnoreCase)) + { + MovieDB_Poster poster = repPosters.GetByOnlineID(img.ImageID, img.ImageSize); + if (poster == null) poster = new MovieDB_Poster(); + poster.Populate(img, movie.MovieId); + repPosters.Save(poster); + + // download the image + if (!string.IsNullOrEmpty(poster.FullImagePath) && !File.Exists(poster.FullImagePath)) + { + CommandRequest_DownloadImage cmd = new CommandRequest_DownloadImage(poster.MovieDB_PosterID, JMMImageType.MovieDB_Poster, false); + cmd.Save(); + } + } + else + { + // fanart (backdrop) + MovieDB_Fanart fanart = repFanart.GetByOnlineID(img.ImageID, img.ImageSize); + if (fanart == null) fanart = new MovieDB_Fanart(); + fanart.Populate(img, movie.MovieId); + repFanart.Save(fanart); + + // download the image + if (!string.IsNullOrEmpty(fanart.FullImagePath) && !File.Exists(fanart.FullImagePath)) + { + CommandRequest_DownloadImage cmd = new CommandRequest_DownloadImage(fanart.MovieDB_FanartID, JMMImageType.MovieDB_FanArt, false); + cmd.Save(); + } + } + } + } + + public static List Search(string criteria) + { + List results = new List(); + + try + { + string url = string.Format(SearchURL, apiKey, criteria.Trim()); + // Search for a movie + string xmlSearch = Utils.DownloadWebPage(url); + + XmlDocument docSearchResult = new XmlDocument(); + docSearchResult.LoadXml(xmlSearch); + + bool hasData = docSearchResult["OpenSearchDescription"]["movies"].HasChildNodes; + if (hasData) + { + XmlNodeList movies = docSearchResult["OpenSearchDescription"]["movies"].GetElementsByTagName("movie"); + + foreach (XmlNode movieNode in movies) + { + MovieDB_Movie_Result searchResult = new MovieDB_Movie_Result(); + if (searchResult.Populate(movieNode)) + { + results.Add(searchResult); + SaveMovieToDatabase(searchResult, false); + } + } + + + } + + } + catch (Exception ex) + { + logger.Error("Error in MovieDB Search: " + ex.Message); + } + + return results; + } + + public static void UpdateMovieInfo(int movieID, bool saveImages) + { + + try + { + string url = string.Format(InfoURL, apiKey, movieID); + // Search for a movie + string xmlSearch = Utils.DownloadWebPage(url); + + XmlDocument docSearchResult = new XmlDocument(); + docSearchResult.LoadXml(xmlSearch); + + bool hasData = docSearchResult["OpenSearchDescription"]["movies"].HasChildNodes; + if (hasData) + { + XmlNodeList movies = docSearchResult["OpenSearchDescription"]["movies"].GetElementsByTagName("movie"); + + XmlNode movie = movies[0]; + MovieDB_Movie_Result searchResult = new MovieDB_Movie_Result(); + if (searchResult.Populate(movie)) + { + // save to the DB + SaveMovieToDatabase(searchResult, saveImages); + } + + } + + } + catch (Exception ex) + { + logger.ErrorException("Error in ParseBanners: " + ex.ToString(), ex); + } + } + + public static void LinkAniDBMovieDB(int animeID, int movieDBID, bool fromWebCache) + { + // check if we have this information locally + // if not download it now + MovieDB_MovieRepository repMovies = new MovieDB_MovieRepository(); + MovieDB_Movie movie = repMovies.GetByOnlineID(movieDBID); + if (movie == null) + { + // we download the series info here just so that we have the basic info in the + // database before the queued task runs later + UpdateMovieInfo(movieDBID, false); + movie = repMovies.GetByOnlineID(movieDBID); + if (movie == null) return; + } + + // download and update series info and images + UpdateMovieInfo(movieDBID, true); + + CrossRef_AniDB_OtherRepository repCrossRef = new CrossRef_AniDB_OtherRepository(); + CrossRef_AniDB_Other xref = repCrossRef.GetByAnimeIDAndType(animeID, CrossRefType.MovieDB); + if (xref == null) + xref = new CrossRef_AniDB_Other(); + + xref.AnimeID = animeID; + if (fromWebCache) + xref.CrossRefSource = (int)CrossRefSource.WebCache; + else + xref.CrossRefSource = (int)CrossRefSource.User; + + xref.CrossRefType = (int)CrossRefType.MovieDB; + xref.CrossRefID = movieDBID.ToString(); + repCrossRef.Save(xref); + + StatsCache.Instance.UpdateUsingAnime(animeID); + + logger.Trace("Changed moviedb association: {0}", animeID); + + CommandRequest_WebCacheSendXRefAniDBOther req = new CommandRequest_WebCacheSendXRefAniDBOther(xref.CrossRef_AniDB_OtherID); + req.Save(); + } + + public static void RemoveLinkAniDBMovieDB(int animeID) + { + CrossRef_AniDB_OtherRepository repCrossRef = new CrossRef_AniDB_OtherRepository(); + CrossRef_AniDB_Other xref = repCrossRef.GetByAnimeIDAndType(animeID, CrossRefType.MovieDB); + if (xref == null) return; + + repCrossRef.Delete(xref.CrossRef_AniDB_OtherID); + + CommandRequest_WebCacheDeleteXRefAniDBOther req = new CommandRequest_WebCacheDeleteXRefAniDBOther(animeID, CrossRefType.MovieDB); + req.Save(); + } + + public static void ScanForMatches() + { + AnimeSeriesRepository repSeries = new AnimeSeriesRepository(); + List allSeries = repSeries.GetAll(); + + CrossRef_AniDB_OtherRepository repCrossRef = new CrossRef_AniDB_OtherRepository(); + foreach (AnimeSeries ser in allSeries) + { + AniDB_Anime anime = ser.Anime; + if (anime == null) continue; + + // don't scan if it is associated on the TvDB + if (anime.CrossRefTvDB != null) continue; + + // don't scan if it is associated on the MovieDB + if (anime.CrossRefMovieDB != null) continue; + + // don't scan if it is not a movie + if (!anime.SearchOnMovieDB) + continue; + + logger.Trace("Found anime movie without MovieDB association: " + anime.MainTitle); + + CommandRequest_MovieDBSearchAnime cmd = new CommandRequest_MovieDBSearchAnime(ser.AniDB_ID, false); + cmd.Save(); + } + + } + } +} diff --git a/JMMServer/Providers/MovieDB/MovieDB_Image_Result.cs b/JMMServer/Providers/MovieDB/MovieDB_Image_Result.cs new file mode 100644 index 000000000..c3c201d82 --- /dev/null +++ b/JMMServer/Providers/MovieDB/MovieDB_Image_Result.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Xml; + +namespace JMMServer.Providers.MovieDB +{ + public class MovieDB_Image_Result + { + public string ImageID { get; set; } + public string ImageType { get; set; } + public string ImageSize { get; set; } + public string URL { get; set; } + public int ImageWidth { get; set; } + public int ImageHeight { get; set; } + + public MovieDB_Image_Result() + { + } + + public override string ToString() + { + return string.Format("{0} - {1} - {2}x{3} - {4}", ImageType, ImageSize, ImageWidth, ImageHeight, URL); + } + + public bool Populate(XmlNode result) + { + if (result.Attributes["id"] == null) return false; + + ImageType = string.Empty; + ImageSize = string.Empty; + URL = string.Empty; + ImageWidth = 0; + ImageHeight = 0; + + if (result.Attributes["id"] != null) ImageID = result.Attributes["id"].InnerText; + if (result.Attributes["type"] != null) ImageType = result.Attributes["type"].InnerText; + if (result.Attributes["size"] != null) ImageSize = result.Attributes["size"].InnerText; + if (result.Attributes["url"] != null) URL = result.Attributes["url"].InnerText; + if (result.Attributes["width"] != null) ImageWidth = int.Parse(result.Attributes["width"].InnerText); + if (result.Attributes["height"] != null) ImageHeight = int.Parse(result.Attributes["height"].InnerText); + + return true; + } + } +} diff --git a/JMMServer/Providers/MovieDB/MovieDB_Movie_Result.cs b/JMMServer/Providers/MovieDB/MovieDB_Movie_Result.cs new file mode 100644 index 000000000..6ff07e0c8 --- /dev/null +++ b/JMMServer/Providers/MovieDB/MovieDB_Movie_Result.cs @@ -0,0 +1,77 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Xml; +using NLog; +using JMMContracts; + +namespace JMMServer.Providers.MovieDB +{ + public class MovieDB_Movie_Result + { + private static Logger logger = LogManager.GetCurrentClassLogger(); + + public int MovieID { get; set;} + public string MovieName { get; set;} + public string OriginalName { get; set;} + public string Overview { get; set;} + + public List Images { get; set; } + + public override string ToString() + { + return "MovieDBSearchResult: " + MovieID + ": " + MovieName; + + } + + public MovieDB_Movie_Result() + { + } + + public bool Populate(XmlNode result) + { + if (result["id"] == null) return false; + try + { + MovieName = string.Empty; + OriginalName = string.Empty; + Overview = string.Empty; + Images = new List(); + + if (result["id"] != null) MovieID = int.Parse(result["id"].InnerText); + if (result["name"] != null) MovieName = result["name"].InnerText; + if (result["original_name"] != null) OriginalName = result["original_name"].InnerText; + if (result["overview"] != null) Overview = result["overview"].InnerText; + + //XmlNodeList imgs = result.SelectNodes("image"); + XmlNodeList imgs = result["images"].GetElementsByTagName("image"); + + foreach (XmlNode img in imgs) + { + MovieDB_Image_Result imageResult = new MovieDB_Image_Result(); + if (imageResult.Populate(img)) + Images.Add(imageResult); + + } + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + return false; + } + + return true; + } + + public Contract_MovieDBMovieSearchResult ToContract() + { + Contract_MovieDBMovieSearchResult contract = new Contract_MovieDBMovieSearchResult(); + contract.MovieID = this.MovieID; + contract.MovieName = this.MovieName; + contract.OriginalName = this.OriginalName; + contract.Overview = this.Overview; + return contract; + } + } +} diff --git a/JMMServer/Providers/TraktTV/TraktTVEpisodeResponse.cs b/JMMServer/Providers/TraktTV/TraktTVEpisodeResponse.cs new file mode 100644 index 000000000..45d8bd27a --- /dev/null +++ b/JMMServer/Providers/TraktTV/TraktTVEpisodeResponse.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Runtime.Serialization; + +namespace JMMServer.Providers.TraktTV +{ + [DataContract] + public class TraktTVEpisodeResponse + { + public TraktTVEpisodeResponse() { } + + [DataMember] + public string season { get; set; } + + [DataMember] + public string episode { get; set; } + + [DataMember] + public string title { get; set; } + + [DataMember] + public string overview { get; set; } + + [DataMember] + public string url { get; set; } + + [DataMember] + public string screen { get; set; } // episode image + + public override string ToString() + { + return string.Format("S{0} - EP {1} - {2}", season, episode, title); + } + } +} diff --git a/JMMServer/Providers/TraktTV/TraktTVGenericResponse.cs b/JMMServer/Providers/TraktTV/TraktTVGenericResponse.cs new file mode 100644 index 000000000..946df454b --- /dev/null +++ b/JMMServer/Providers/TraktTV/TraktTVGenericResponse.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Runtime.Serialization; +using JMMServer.Entities; +using NLog; + +namespace JMMServer.Providers.TraktTV +{ + [DataContract] + public class TraktTVGenericResponse + { + private static Logger logger = LogManager.GetCurrentClassLogger(); + + [DataMember] + public string status { get; set; } + + [DataMember] + public string message { get; set; } + + [DataMember] + public string error { get; set; } + + public bool IsSuccess + { + get + { + if (string.IsNullOrEmpty(status)) return false; + + return (status.Equals("success", StringComparison.InvariantCultureIgnoreCase)); + } + } + + public TraktTVGenericResponse() + { + } + } +} diff --git a/JMMServer/Providers/TraktTV/TraktTVHelper.cs b/JMMServer/Providers/TraktTV/TraktTVHelper.cs new file mode 100644 index 000000000..220f66627 --- /dev/null +++ b/JMMServer/Providers/TraktTV/TraktTVHelper.cs @@ -0,0 +1,868 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using NLog; +using JMMServer.Repositories; +using JMMServer.Entities; +using System.Xml; +using JMMServer.Commands; +using System.IO; +using System.Net; +using BinaryNorthwest; + +namespace JMMServer.Providers.TraktTV +{ + public class TraktTVHelper + { + private static Logger logger = LogManager.GetCurrentClassLogger(); + + public static TraktTVShowResponse GetShowInfo(string traktID) + { + TraktTVShowResponse tvshow = new TraktTVShowResponse(); + + try + { + string url = string.Format(Constants.TraktTvURLs.URLGetShowExtended, Constants.TraktTvURLs.APIKey, traktID); + logger.Trace("GetShowInfo: {0}", url); + + // Search for a series + string json = Utils.DownloadWebPage(url); + + if (json.Trim().Length == 0) return null; + + tvshow = JSONHelper.Deserialize(json); + + // save this data to the DB for use later + SaveExtendedShowInfo(tvshow); + + } + catch (Exception ex) + { + logger.ErrorException("Error in TraktTVHelper.GetShowInfo: " + ex.ToString(), ex); + return null; + } + + return tvshow; + } + + public static void SaveExtendedShowInfo(TraktTVShowResponse tvshow) + { + try + { + // save this data to the DB for use later + Trakt_ImageFanartRepository repFanart = new Trakt_ImageFanartRepository(); + Trakt_ShowRepository repShows = new Trakt_ShowRepository(); + Trakt_Show show = repShows.GetByTraktID(tvshow.TraktID); + if (show == null) + show = new Trakt_Show(); + + show.Overview = tvshow.overview; + show.Title = tvshow.title; + show.TraktID = tvshow.TraktID; + if (!string.IsNullOrEmpty(tvshow.tvdb_id)) show.TvDB_ID = int.Parse(tvshow.tvdb_id); + show.URL = tvshow.url; + show.Year = tvshow.year; + repShows.Save(show); + + + if (tvshow.images != null) + { + if (!string.IsNullOrEmpty(tvshow.images.fanart)) + { + Trakt_ImageFanart fanart = repFanart.GetByShowIDAndSeason(show.Trakt_ShowID, 1); + if (fanart == null) + { + fanart = new Trakt_ImageFanart(); + fanart.Enabled = 1; + } + + fanart.ImageURL = tvshow.images.fanart; + fanart.Season = 1; + fanart.Trakt_ShowID = show.Trakt_ShowID; + repFanart.Save(fanart); + } + } + + + // save the seasons + Trakt_SeasonRepository repSeasons = new Trakt_SeasonRepository(); + Trakt_EpisodeRepository repEpisodes = new Trakt_EpisodeRepository(); + Trakt_ImagePosterRepository repPosters = new Trakt_ImagePosterRepository(); + + foreach (TraktTVSeasonResponse sea in tvshow.seasons) + { + Trakt_Season season = repSeasons.GetByShowIDAndSeason(show.Trakt_ShowID, int.Parse(sea.season)); + if (season == null) + season = new Trakt_Season(); + + season.Season = int.Parse(sea.season); + season.URL = sea.url; + season.Trakt_ShowID = show.Trakt_ShowID; + repSeasons.Save(season); + + if (sea.images != null) + { + if (!string.IsNullOrEmpty(sea.images.poster)) + { + Trakt_ImagePoster poster = repPosters.GetByShowIDAndSeason(show.Trakt_ShowID, season.Season); + if (poster == null) + { + poster = new Trakt_ImagePoster(); + poster.Enabled = 1; + } + + poster.ImageURL = sea.images.poster; + poster.Season = season.Season; + poster.Trakt_ShowID = show.Trakt_ShowID; + repPosters.Save(poster); + } + } + + foreach (TraktTVEpisodeResponse ep in sea.episodes) + { + Trakt_Episode episode = repEpisodes.GetByShowIDSeasonAndEpisode(show.Trakt_ShowID, int.Parse(ep.season), int.Parse(ep.episode)); + if (episode == null) + episode = new Trakt_Episode(); + + episode.EpisodeImage = ep.screen; + episode.EpisodeNumber = int.Parse(ep.episode); + episode.Overview = ep.overview; + episode.Season = int.Parse(ep.season); + episode.Title = ep.title; + episode.URL = ep.url; + episode.Trakt_ShowID = show.Trakt_ShowID; + repEpisodes.Save(episode); + } + } + + + } + catch (Exception ex) + { + logger.ErrorException("Error in TraktTVHelper.SaveExtendedShowInfo: " + ex.ToString(), ex); + } + } + + public static void SaveShowInfo(TraktTVShowResponse tvshow) + { + try + { + // save this data to the DB for use later + Trakt_ImageFanartRepository repFanart = new Trakt_ImageFanartRepository(); + Trakt_ShowRepository repShows = new Trakt_ShowRepository(); + Trakt_Show show = repShows.GetByTraktID(tvshow.TraktID); + if (show == null) + show = new Trakt_Show(); + + show.Overview = tvshow.overview; + show.Title = tvshow.title; + show.TraktID = tvshow.TraktID; + if (!string.IsNullOrEmpty(tvshow.tvdb_id)) show.TvDB_ID = int.Parse(tvshow.tvdb_id); + show.URL = tvshow.url; + show.Year = tvshow.year; + repShows.Save(show); + + if (tvshow.images != null) + { + if (!string.IsNullOrEmpty(tvshow.images.fanart)) + { + Trakt_ImageFanart fanart = repFanart.GetByShowIDAndSeason(show.Trakt_ShowID, 1); + if (fanart == null) + { + fanart = new Trakt_ImageFanart(); + fanart.Enabled = 1; + } + + fanart.ImageURL = tvshow.images.fanart; + fanart.Season = 1; + fanart.Trakt_ShowID = show.Trakt_ShowID; + repFanart.Save(fanart); + } + } + + } + catch (Exception ex) + { + logger.ErrorException("Error in TraktTVHelper.SaveExtendedShowInfo: " + ex.ToString(), ex); + } + } + + public static TraktTVShowResponse GetShowInfo(int tvDBID) + { + return GetShowInfo(tvDBID.ToString()); + } + + public static void LinkAniDBTrakt(int animeID, string traktID, int seasonNumber, bool fromWebCache) + { + // check if we have this information locally + // if not download it now + Trakt_ShowRepository repShow = new Trakt_ShowRepository(); + Trakt_Show traktShow = repShow.GetByTraktID(traktID); + if (traktShow == null) + { + // we download the series info here + TraktTVShowResponse tvshow = GetShowInfo(traktID); + if (tvshow == null) return; + } + + // download fanart, posters + DownloadAllImages(traktID); + + CrossRef_AniDB_TraktRepository repCrossRef = new CrossRef_AniDB_TraktRepository(); + CrossRef_AniDB_Trakt xref = repCrossRef.GetByAnimeID(animeID); + if (xref == null) + xref = new CrossRef_AniDB_Trakt(); + + xref.AnimeID = animeID; + if (fromWebCache) + xref.CrossRefSource = (int)CrossRefSource.WebCache; + else + xref.CrossRefSource = (int)CrossRefSource.User; + + xref.TraktID = traktID; + xref.TraktSeasonNumber = seasonNumber; + repCrossRef.Save(xref); + + StatsCache.Instance.UpdateUsingAnime(animeID); + + logger.Trace("Changed trakt association: {0}", animeID); + + CommandRequest_WebCacheSendXRefAniDBTrakt req = new CommandRequest_WebCacheSendXRefAniDBTrakt(xref.CrossRef_AniDB_TraktID); + req.Save(); + } + + // Removes all Trakt information from a series, bringing it back to a blank state. + public static void RemoveLinkAniDBTrakt(AnimeSeries ser) + { + CrossRef_AniDB_TraktRepository repCrossRef = new CrossRef_AniDB_TraktRepository(); + CrossRef_AniDB_Trakt xref = repCrossRef.GetByAnimeID(ser.AniDB_ID); + if (xref == null) return; + + repCrossRef.Delete(xref.CrossRef_AniDB_TraktID); + + CommandRequest_WebCacheDeleteXRefAniDBTrakt req = new CommandRequest_WebCacheDeleteXRefAniDBTrakt(ser.AniDB_ID); + req.Save(); + } + + public static List SearchShow(string criteria) + { + List results = new List(); + + try + { + // replace spaces with a + symbo + criteria = criteria.Replace(' ', '+'); + + // Search for a series + string url = string.Format(Constants.TraktTvURLs.URLSearchShow, Constants.TraktTvURLs.APIKey, criteria); + logger.Trace("Search Trakt Show: {0}", url); + + // Search for a series + string json = Utils.DownloadWebPage(url); + + if (json.Trim().Length == 0) return new List(); + + results = JSONHelper.Deserialize>(json); + + // save this data for later use + //foreach (TraktTVShowResponse tvshow in results) + // SaveShowInfo(tvshow); + } + catch (Exception ex) + { + logger.ErrorException("Error in SearchSeries: " + ex.ToString(), ex); + } + + return results; + } + + /// + /// Updates the followung + /// 1. Series Info + /// 2. Episode Info + /// 3. Episode Images + /// 4. Fanart, Poster Images + /// + /// + /// + public static void UpdateAllInfoAndImages(string traktID, bool forceRefresh) + { + // this will do the first 3 steps + TraktTVShowResponse tvShow = GetShowInfo(traktID); + if (tvShow == null) return; + + try + { + //now download the images + DownloadAllImages(traktID); + } + catch (Exception ex) + { + logger.ErrorException("Error in TraktTVHelper.UpdateAllInfoAndImages: " + ex.ToString(), ex); + } + } + + public static void DownloadAllImages(string traktID) + { + try + { + //now download the images + Trakt_ShowRepository repShow = new Trakt_ShowRepository(); + Trakt_Show show = repShow.GetByTraktID(traktID); + if (show == null) return; + + //download the fanart image for the show + Trakt_ImageFanartRepository repFanart = new Trakt_ImageFanartRepository(); + Trakt_ImageFanart fanart = repFanart.GetByShowIDAndSeason(show.Trakt_ShowID, 1); + if (fanart != null) + { + if (!string.IsNullOrEmpty(fanart.FullImagePath)) + { + if (!File.Exists(fanart.FullImagePath)) + { + CommandRequest_DownloadImage cmd = new CommandRequest_DownloadImage(fanart.Trakt_ImageFanartID, JMMImageType.Trakt_Fanart, false); + cmd.Save(); + } + } + } + + // download the posters for seasons + Trakt_ImagePosterRepository repPosters = new Trakt_ImagePosterRepository(); + foreach (Trakt_Season season in show.Seasons) + { + Trakt_ImagePoster poster = repPosters.GetByShowIDAndSeason(season.Trakt_ShowID, season.Season); + if (poster != null) + { + if (!string.IsNullOrEmpty(poster.FullImagePath)) + { + if (!File.Exists(poster.FullImagePath)) + { + CommandRequest_DownloadImage cmd = new CommandRequest_DownloadImage(poster.Trakt_ImagePosterID, JMMImageType.Trakt_Poster, false); + cmd.Save(); + } + } + } + + // download the screenshots for episodes + foreach (Trakt_Episode ep in season.Episodes) + { + if (!string.IsNullOrEmpty(ep.FullImagePath)) + { + if (!File.Exists(ep.FullImagePath)) + { + CommandRequest_DownloadImage cmd = new CommandRequest_DownloadImage(ep.Trakt_EpisodeID, JMMImageType.Trakt_Episode, false); + cmd.Save(); + } + } + } + } + } + catch (Exception ex) + { + logger.ErrorException("Error in TraktTVHelper.UpdateAllInfoAndImages: " + ex.ToString(), ex); + } + } + + public static void ScanForMatches() + { + AnimeSeriesRepository repSeries = new AnimeSeriesRepository(); + List allSeries = repSeries.GetAll(); + + CrossRef_AniDB_TraktRepository repCrossRef = new CrossRef_AniDB_TraktRepository(); + List allCrossRefs = repCrossRef.GetAll(); + List alreadyLinked = new List(); + foreach (CrossRef_AniDB_Trakt xref in allCrossRefs) + { + alreadyLinked.Add(xref.AnimeID); + } + + foreach (AnimeSeries ser in allSeries) + { + if (alreadyLinked.Contains(ser.AniDB_ID)) continue; + + AniDB_Anime anime = ser.Anime; + + if (anime != null) + logger.Trace("Found anime without Trakt association: " + anime.MainTitle); + + CommandRequest_TraktSearchAnime cmd = new CommandRequest_TraktSearchAnime(ser.AniDB_ID, false); + cmd.Save(); + } + + } + + public static void UpdateAllInfo() + { + CrossRef_AniDB_TraktRepository repCrossRef = new CrossRef_AniDB_TraktRepository(); + List allCrossRefs = repCrossRef.GetAll(); + foreach (CrossRef_AniDB_Trakt xref in allCrossRefs) + { + CommandRequest_TraktUpdateInfoAndImages cmd = new CommandRequest_TraktUpdateInfoAndImages(xref.TraktID); + cmd.Save(); + } + + } + + /*public static void MarkEpisodeWatched(AnimeEpisode ep) + { + TraktTVPost_ShowScrobble tt = new TraktTVPost_ShowScrobble(); + if (!tt.Init(ep)) return; + + try + { + string url = string.Format(Constants.TraktTvURLs.URLPostShowScrobble, Constants.TraktTvURLs.APIKey); + logger.Trace("GetShowInfo: {0}", url); + + logger.Trace("Marking episode as unwatched on Trakt: {0} - S{1} - EP{2}", show.Title, retSeason, retEpNum); + + string json = JSONHelper.Serialize(tt); + + SendData(url, json); + + } + catch (Exception ex) + { + logger.ErrorException("Error in TraktTVHelper.MarkEpisodeWatched: " + ex.ToString(), ex); + } + + }*/ + + public static void MarkEpisodeWatched(AnimeEpisode ep) + { + try + { + + CrossRef_AniDB_Trakt xref = ep.AnimeSeries.CrossRefTrakt; + if (xref == null) return; + + Trakt_ShowRepository repShows = new Trakt_ShowRepository(); + Trakt_Show show = repShows.GetByTraktID(xref.TraktID); + if (show == null) return; + if (!show.TvDB_ID.HasValue) return; + + Dictionary dictTraktSeasons = null; + Dictionary dictTraktEpisodes = null; + Dictionary dictTraktSpecials = null; + GetDictTraktEpisodesAndSeasons(show, ref dictTraktEpisodes, ref dictTraktSpecials, ref dictTraktSeasons); + + int retEpNum = -1; + int retSeason = -1; + + GetTraktEpisodeNumber(ep, ep.AnimeSeries, show, xref.TraktSeasonNumber, ref retEpNum, ref retSeason, dictTraktEpisodes, dictTraktSpecials, dictTraktSeasons); + if (retEpNum < 0) return; + + TraktTVPost_ShowScrobble postScrobble = new TraktTVPost_ShowScrobble(); + postScrobble.SetCredentials(); + postScrobble.imdb_id = ""; + postScrobble.title = show.Title; + postScrobble.year = show.Year; + postScrobble.tvdb_id = show.TvDB_ID.Value.ToString(); + postScrobble.episode = retEpNum.ToString(); + postScrobble.season = retSeason.ToString(); + + AniDB_Episode aniep = ep.AniDB_Episode; + if (aniep != null) + { + TimeSpan t = TimeSpan.FromSeconds(aniep.LengthSeconds + 14); + int toMinutes = int.Parse(Math.Round(t.TotalMinutes).ToString()); + postScrobble.duration = toMinutes.ToString(); + } + else + postScrobble.duration = "25"; + + postScrobble.progress = "100"; + + postScrobble.plugin_version = "0.4"; + postScrobble.media_center_version = "1.2.0.1"; + postScrobble.media_center_date = "Dec 17 2010"; + + logger.Trace("Marking episode as watched (scrobble) on Trakt: {0} - S{1} - EP{2}", show.Title, retSeason, retEpNum); + + string url = string.Format(Constants.TraktTvURLs.URLPostShowScrobble, Constants.TraktTvURLs.APIKey); + string json = JSONHelper.Serialize(postScrobble); + + SendData(url, json); + + } + catch (Exception ex) + { + logger.ErrorException("Error in TraktTVHelper.MarkEpisodeWatched: " + ex.ToString(), ex); + } + + } + + public static void MarkEpisodeUnwatched(AnimeEpisode ep) + { + try + { + + CrossRef_AniDB_Trakt xref = ep.AnimeSeries.CrossRefTrakt; + if (xref == null) return; + + Trakt_ShowRepository repShows = new Trakt_ShowRepository(); + Trakt_Show show = repShows.GetByTraktID(xref.TraktID); + if (show == null) return; + if (!show.TvDB_ID.HasValue) return; + + Dictionary dictTraktSeasons = null; + Dictionary dictTraktEpisodes = null; + Dictionary dictTraktSpecials = null; + GetDictTraktEpisodesAndSeasons(show, ref dictTraktEpisodes, ref dictTraktSpecials, ref dictTraktSeasons); + + TraktTVPost_ShowEpisodeUnseen postUnseen = new TraktTVPost_ShowEpisodeUnseen(); + postUnseen.episodes = new List(); + postUnseen.SetCredentials(); + postUnseen.imdb_id = ""; + postUnseen.title = show.Title; + postUnseen.year = show.Year; + postUnseen.tvdb_id = show.TvDB_ID.Value.ToString(); + + int retEpNum = -1; + int retSeason = -1; + + GetTraktEpisodeNumber(ep, ep.AnimeSeries, show, xref.TraktSeasonNumber, ref retEpNum, ref retSeason, dictTraktEpisodes, dictTraktSpecials, dictTraktSeasons); + if (retEpNum < 0) return; + + TraktTVSeasonEpisode traktEp = new TraktTVSeasonEpisode(); + traktEp.episode = retEpNum.ToString(); + traktEp.season = retSeason.ToString(); + postUnseen.episodes.Add(traktEp); + + logger.Trace("Marking episode as unwatched on Trakt: {0} - S{1} - EP{2}", show.Title, retSeason, retEpNum); + + string urlUnseen = string.Format(Constants.TraktTvURLs.URLPostShowEpisodeUnseen, Constants.TraktTvURLs.APIKey); + string json = JSONHelper.Serialize(postUnseen); + + SendData(urlUnseen, json); + + } + catch (Exception ex) + { + logger.ErrorException("Error in TraktTVHelper.MarkEpisodeWatched: " + ex.ToString(), ex); + } + + } + + + private static string SendData(string uri, string json) + { + WebRequest req = null; + WebResponse rsp = null; + string output = ""; + try + { + DateTime start = DateTime.Now; + + + req = WebRequest.Create(uri); + req.Method = "POST"; // Post method + req.ContentType = "text/json"; // content type + req.Proxy = null; + + // Wrap the request stream with a text-based writer + StreamWriter writer = new StreamWriter(req.GetRequestStream()); + // Write the XML text into the stream + writer.WriteLine(json); + writer.Close(); + // Send the data to the webserver + //rsp = req.GetResponse(); + + HttpWebResponse WebResponse = (HttpWebResponse)req.GetResponse(); + + Stream responseStream = WebResponse.GetResponseStream(); + String enco = WebResponse.CharacterSet; + Encoding encoding = null; + if (!String.IsNullOrEmpty(enco)) + encoding = Encoding.GetEncoding(WebResponse.CharacterSet); + if (encoding == null) + encoding = Encoding.Default; + StreamReader Reader = new StreamReader(responseStream, encoding); + + output = Reader.ReadToEnd(); + + + TimeSpan ts = DateTime.Now - start; + logger.Trace("Sent TraktPost in {0} ms: {1} --- {2}", ts.TotalMilliseconds, uri, output); + + } + catch (WebException webEx) + { + logger.Error("Error(1) in XMLServiceQueue.SendData: {0}", webEx); + } + catch (Exception ex) + { + logger.ErrorException("Error(2) in XMLServiceQueue.SendData: {0}", ex); + } + finally + { + if (req != null) req.GetRequestStream().Close(); + if (rsp != null) rsp.GetResponseStream().Close(); + } + + return output; + } + + public static string TestUserLogin() + { + try + { + if (string.IsNullOrEmpty(ServerSettings.Trakt_Username) || string.IsNullOrEmpty(ServerSettings.Trakt_Password)) + return "Please enter a username and password"; + + TraktTVPost_AccountTest cmd = new TraktTVPost_AccountTest(); + cmd.Init(); + + string url = string.Format(Constants.TraktTvURLs.URLPostAccountTest, Constants.TraktTvURLs.APIKey); + logger.Trace("TestUserLogin: {0}", url); + + string json = JSONHelper.Serialize(cmd); + string jsonResponse = SendData(url, json); + if (string.IsNullOrEmpty(jsonResponse)) return "Invalid login"; + + TraktTVGenericResponse genResponse = JSONHelper.Deserialize(jsonResponse); + if (genResponse.IsSuccess) + return ""; + else + return genResponse.error; + + } + catch (Exception ex) + { + logger.ErrorException("Error in TraktTVHelper.TestUserLogin: " + ex.ToString(), ex); + return ex.Message; + } + } + + public static void SyncCollectionToTrakt_Series(AnimeSeries series) + { + try + { + // check that we have at least one user nominated for Trakt + JMMUserRepository repUsers = new JMMUserRepository(); + List traktUsers = repUsers.GetTraktUsers(); + if (traktUsers.Count == 0) return; + + string url = string.Format(Constants.TraktTvURLs.URLPostShowEpisodeLibrary, Constants.TraktTvURLs.APIKey); + string urlSeen = string.Format(Constants.TraktTvURLs.URLPostShowEpisodeSeen, Constants.TraktTvURLs.APIKey); + + int retEpNum = 0, retSeason = 0; + + CrossRef_AniDB_Trakt xref = series.CrossRefTrakt; + if (xref == null) return; + + Trakt_ShowRepository repShows = new Trakt_ShowRepository(); + Trakt_Show show = repShows.GetByTraktID(xref.TraktID); + if (show == null) return; + if (!show.TvDB_ID.HasValue) return; + + Dictionary dictTraktSeasons = null; + Dictionary dictTraktEpisodes = null; + Dictionary dictTraktSpecials = null; + GetDictTraktEpisodesAndSeasons(show, ref dictTraktEpisodes, ref dictTraktSpecials, ref dictTraktSeasons); + + + TraktTVPost_ShowEpisodeLibrary postLibrary = new TraktTVPost_ShowEpisodeLibrary(); + postLibrary.episodes = new List(); + postLibrary.SetCredentials(); + postLibrary.imdb_id = ""; + postLibrary.title = show.Title; + postLibrary.year = show.Year; + postLibrary.tvdb_id = show.TvDB_ID.Value.ToString(); + + TraktTVPost_ShowEpisodeSeen postSeen = new TraktTVPost_ShowEpisodeSeen(); + postSeen.episodes = new List(); + postSeen.SetCredentials(); + postSeen.imdb_id = ""; + postSeen.title = show.Title; + postSeen.year = show.Year; + postSeen.tvdb_id = show.TvDB_ID.Value.ToString(); + + foreach (AnimeEpisode ep in series.AnimeEpisodes) + { + if (ep.VideoLocals.Count > 0) + { + retEpNum = -1; + retSeason = -1; + + GetTraktEpisodeNumber(ep, series, show, xref.TraktSeasonNumber, ref retEpNum, ref retSeason, dictTraktEpisodes, dictTraktSpecials, dictTraktSeasons); + if (retEpNum < 0) continue; + + TraktTVSeasonEpisode traktEp = new TraktTVSeasonEpisode(); + traktEp.episode = retEpNum.ToString(); + traktEp.season = retSeason.ToString(); + postLibrary.episodes.Add(traktEp); + + AnimeEpisode_User userRecord = null; + foreach (JMMUser juser in traktUsers) + { + userRecord = ep.GetUserRecord(juser.JMMUserID); + if (userRecord != null) break; + } + + if (userRecord != null) + postSeen.episodes.Add(traktEp); + } + } + + if (postLibrary.episodes.Count > 0) + { + logger.Info("PostShowEpisodeLibrary: {0}/{1}/{2} eps", show.Title, show.TraktID, postLibrary.episodes.Count); + + string json = JSONHelper.Serialize(postLibrary); + string jsonResponse = SendData(url, json); + logger.Info("PostShowEpisodeLibrary RESPONSE: {0}", jsonResponse); + } + + if (postSeen.episodes.Count > 0) + { + logger.Info("PostShowEpisodeSeen: {0}/{1}/{2} eps", show.Title, show.TraktID, postSeen.episodes.Count); + + string json = JSONHelper.Serialize(postSeen); + string jsonResponse = SendData(urlSeen, json); + logger.Info("PostShowEpisodeSeen RESPONSE: {0}", jsonResponse); + } + } + catch (Exception ex) + { + logger.ErrorException("Error in TraktTVHelper.SyncCollectionToTrakt_Series: " + ex.ToString(), ex); + } + } + + public static void SyncCollectionToTrakt() + { + try + { + if (string.IsNullOrEmpty(ServerSettings.Trakt_Username) || string.IsNullOrEmpty(ServerSettings.Trakt_Password)) return; + + AnimeSeriesRepository repSeries = new AnimeSeriesRepository(); + List allSeries = repSeries.GetAll(); + + foreach (AnimeSeries series in allSeries) + { + //SyncCollectionToTrakt_Series(series); + CommandRequest_TraktSyncCollectionSeries cmd = new CommandRequest_TraktSyncCollectionSeries(series.AnimeSeriesID, series.Anime.MainTitle); + cmd.Save(); + } + + } + catch (Exception ex) + { + logger.ErrorException("Error in TraktTVHelper.SyncCollectionToTrakt: " + ex.ToString(), ex); + } + } + + private static void GetTraktEpisodeNumber(AnimeEpisode aniepisode, AnimeSeries ser, Trakt_Show show, int season, ref int traktEpNum, ref int traktSeason) + { + Dictionary dictTraktSeasons = null; + Dictionary dictTraktEpisodes = null; + Dictionary dictTraktSpecials = null; + GetDictTraktEpisodesAndSeasons(show, ref dictTraktEpisodes, ref dictTraktSpecials, ref dictTraktSeasons); + + GetTraktEpisodeNumber(aniepisode, ser, show, season, ref traktEpNum, ref traktSeason, dictTraktEpisodes, dictTraktSpecials, dictTraktSeasons); + } + + private static void GetTraktEpisodeNumber(AnimeEpisode aniepisode, AnimeSeries ser, Trakt_Show show, int season, ref int traktEpNum, ref int traktSeason, + Dictionary dictTraktEpisodes, Dictionary dictTraktSpecials, Dictionary dictTraktSeasons) + { + try + { + traktEpNum = -1; + traktSeason = -1; + + int epNum = aniepisode.AniDB_Episode.EpisodeNumber; + + if (season > 0) + { + //episode + if (aniepisode.EpisodeTypeEnum == AniDBAPI.enEpisodeType.Episode) + { + if (dictTraktEpisodes != null && dictTraktSeasons != null) + { + if (dictTraktSeasons.ContainsKey(season)) + { + int absEpisodeNumber = dictTraktSeasons[season] + epNum - 1; + if (dictTraktEpisodes.ContainsKey(absEpisodeNumber)) + { + Trakt_Episode tvep = dictTraktEpisodes[absEpisodeNumber]; + traktEpNum = tvep.EpisodeNumber; + traktSeason = tvep.Season; + } + } + } + } + + if (aniepisode.EpisodeTypeEnum == AniDBAPI.enEpisodeType.Special) + { + traktSeason = 0; + traktEpNum = epNum; + } + } + else + { + traktSeason = 0; + traktEpNum = epNum; + } + + return; + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + return; + } + } + + private static void GetDictTraktEpisodesAndSeasons(Trakt_Show show, ref Dictionary dictTraktEpisodes, + ref Dictionary dictTraktSpecials, ref Dictionary dictTraktSeasons) + { + dictTraktEpisodes = new Dictionary(); + dictTraktSpecials = new Dictionary(); + dictTraktSeasons = new Dictionary(); + try + { + Trakt_EpisodeRepository repEps = new Trakt_EpisodeRepository(); + + // create a dictionary of absolute episode numbers for trakt episodes + // sort by season and episode number + // ignore season 0, which is used for specials + List eps = repEps.GetByShowID(show.Trakt_ShowID); + + List sortCriteria = new List(); + sortCriteria.Add(new SortPropOrFieldAndDirection("Season", false, SortType.eInteger)); + sortCriteria.Add(new SortPropOrFieldAndDirection("EpisodeNumber", false, SortType.eInteger)); + eps = Sorting.MultiSort(eps, sortCriteria); + + int i = 1; + int iSpec = 1; + int lastSeason = -999; + foreach (Trakt_Episode ep in eps) + { + //if (ep.Season == 0) continue; + if (ep.Season > 0) + { + dictTraktEpisodes[i] = ep; + if (ep.Season != lastSeason) + dictTraktSeasons[ep.Season] = i; + + i++; + } + else + { + dictTraktSpecials[iSpec] = ep; + if (ep.Season != lastSeason) + dictTraktSeasons[ep.Season] = iSpec; + + iSpec++; + } + + lastSeason = ep.Season; + } + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + } + } + } +} diff --git a/JMMServer/Providers/TraktTV/TraktTVImagesResponse.cs b/JMMServer/Providers/TraktTV/TraktTVImagesResponse.cs new file mode 100644 index 000000000..71d92df77 --- /dev/null +++ b/JMMServer/Providers/TraktTV/TraktTVImagesResponse.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Runtime.Serialization; + +namespace JMMServer.Providers.TraktTV +{ + [DataContract] + public class TraktTVImagesResponse + { + public TraktTVImagesResponse() { } + + [DataMember] + public string poster { get; set; } + + [DataMember] + public string fanart { get; set; } + + public override string ToString() + { + return string.Format("{0} - {1}", poster, fanart); + } + } +} diff --git a/JMMServer/Providers/TraktTV/TraktTVPost_AccountTest.cs b/JMMServer/Providers/TraktTV/TraktTVPost_AccountTest.cs new file mode 100644 index 000000000..59804cdb5 --- /dev/null +++ b/JMMServer/Providers/TraktTV/TraktTVPost_AccountTest.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Runtime.Serialization; +using JMMServer.Entities; +using NLog; + +namespace JMMServer.Providers.TraktTV +{ + [DataContract] + public class TraktTVPost_AccountTest + { + private static Logger logger = LogManager.GetCurrentClassLogger(); + + // http://trakt.tv/api-docs/account-test + + [DataMember] + public string username { get; set; } + + [DataMember] + public string password { get; set; } + + public TraktTVPost_AccountTest() + { + } + + public void Init() + { + username = ServerSettings.Trakt_Username; + password = Utils.CalculateSHA1(ServerSettings.Trakt_Password, Encoding.Default); + } + } +} diff --git a/JMMServer/Providers/TraktTV/TraktTVPost_ShowEpisodeLibrary.cs b/JMMServer/Providers/TraktTV/TraktTVPost_ShowEpisodeLibrary.cs new file mode 100644 index 000000000..97412dc34 --- /dev/null +++ b/JMMServer/Providers/TraktTV/TraktTVPost_ShowEpisodeLibrary.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Runtime.Serialization; +using JMMServer.Entities; +using NLog; +using JMMServer.Repositories; + +namespace JMMServer.Providers.TraktTV +{ + [DataContract] + public class TraktTVPost_ShowEpisodeLibrary + { + private static Logger logger = LogManager.GetCurrentClassLogger(); + + // http://trakt.tv/api-docs/show-watching + + [DataMember] + public string username { get; set; } + + [DataMember] + public string password { get; set; } + + [DataMember] + public string imdb_id { get; set; } + + [DataMember] + public string tvdb_id { get; set; } + + [DataMember] + public string title { get; set; } + + [DataMember] + public string year { get; set; } + + [DataMember] + public List episodes { get; set; } + + public void SetCredentials() + { + username = ServerSettings.Trakt_Username; + password = Utils.CalculateSHA1(ServerSettings.Trakt_Password, Encoding.Default); + } + } +} diff --git a/JMMServer/Providers/TraktTV/TraktTVPost_ShowEpisodeSeen.cs b/JMMServer/Providers/TraktTV/TraktTVPost_ShowEpisodeSeen.cs new file mode 100644 index 000000000..cec9a6e14 --- /dev/null +++ b/JMMServer/Providers/TraktTV/TraktTVPost_ShowEpisodeSeen.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Runtime.Serialization; +using JMMServer.Entities; +using NLog; +using JMMServer.Repositories; + +namespace JMMServer.Providers.TraktTV +{ + [DataContract] + public class TraktTVPost_ShowEpisodeSeen + { + private static Logger logger = LogManager.GetCurrentClassLogger(); + + // http://trakt.tv/api-docs/show-episode-seen + + [DataMember] + public string username { get; set; } + + [DataMember] + public string password { get; set; } + + [DataMember] + public string imdb_id { get; set; } + + [DataMember] + public string tvdb_id { get; set; } + + [DataMember] + public string title { get; set; } + + [DataMember] + public string year { get; set; } + + [DataMember] + public List episodes { get; set; } + + public void SetCredentials() + { + username = ServerSettings.Trakt_Username; + password = Utils.CalculateSHA1(ServerSettings.Trakt_Password, Encoding.Default); + } + } +} diff --git a/JMMServer/Providers/TraktTV/TraktTVPost_ShowEpisodeUnseen.cs b/JMMServer/Providers/TraktTV/TraktTVPost_ShowEpisodeUnseen.cs new file mode 100644 index 000000000..c48218018 --- /dev/null +++ b/JMMServer/Providers/TraktTV/TraktTVPost_ShowEpisodeUnseen.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Runtime.Serialization; +using JMMServer.Entities; +using NLog; +using JMMServer.Repositories; + +namespace JMMServer.Providers.TraktTV +{ + [DataContract] + public class TraktTVPost_ShowEpisodeUnseen + { + private static Logger logger = LogManager.GetCurrentClassLogger(); + + // http://trakt.tv/api-docs/show-episode-seen + + [DataMember] + public string username { get; set; } + + [DataMember] + public string password { get; set; } + + [DataMember] + public string imdb_id { get; set; } + + [DataMember] + public string tvdb_id { get; set; } + + [DataMember] + public string title { get; set; } + + [DataMember] + public string year { get; set; } + + [DataMember] + public List episodes { get; set; } + + public void SetCredentials() + { + username = ServerSettings.Trakt_Username; + password = Utils.CalculateSHA1(ServerSettings.Trakt_Password, Encoding.Default); + } + } +} diff --git a/JMMServer/Providers/TraktTV/TraktTVPost_ShowScrobble.cs b/JMMServer/Providers/TraktTV/TraktTVPost_ShowScrobble.cs new file mode 100644 index 000000000..3012173f8 --- /dev/null +++ b/JMMServer/Providers/TraktTV/TraktTVPost_ShowScrobble.cs @@ -0,0 +1,225 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Runtime.Serialization; +using JMMServer.Entities; +using NLog; +using JMMServer.Repositories; +using BinaryNorthwest; + + +namespace JMMServer.Providers.TraktTV +{ + [DataContract] + public class TraktTVPost_ShowScrobble + { + private static Logger logger = LogManager.GetCurrentClassLogger(); + + // http://trakt.tv/api-docs/show-watching + + [DataMember] + public string username { get; set; } + + [DataMember] + public string password { get; set; } + + [DataMember] + public string imdb_id { get; set; } + + [DataMember] + public string tvdb_id { get; set; } + + [DataMember] + public string title { get; set; } + + [DataMember] + public string year { get; set; } + + [DataMember] + public string season { get; set; } + + [DataMember] + public string episode { get; set; } + + [DataMember] + public string duration { get; set; } + + [DataMember] + public string progress { get; set; } + + [DataMember] + public string plugin_version { get; set; } + + [DataMember] + public string media_center_version { get; set; } + + [DataMember] + public string media_center_date { get; set; } + + public TraktTVPost_ShowScrobble() + { + } + + public void SetCredentials() + { + username = ServerSettings.Trakt_Username; + password = Utils.CalculateSHA1(ServerSettings.Trakt_Password, Encoding.Default); + } + + public bool Init(AnimeEpisode aniepisode) + { + try + { + if (string.IsNullOrEmpty(ServerSettings.Trakt_Username) || string.IsNullOrEmpty(ServerSettings.Trakt_Password)) + return false; + + username = ServerSettings.Trakt_Username; + password = Utils.CalculateSHA1(ServerSettings.Trakt_Password, Encoding.Default); + + imdb_id = ""; + AnimeSeries ser = aniepisode.AnimeSeries; + if (ser == null) return false; + + CrossRef_AniDB_TraktRepository repCrossRef = new CrossRef_AniDB_TraktRepository(); + CrossRef_AniDB_Trakt xref = repCrossRef.GetByAnimeID(ser.AniDB_ID); + if (xref == null) return false; + + Trakt_ShowRepository repShows = new Trakt_ShowRepository(); + Trakt_Show show = repShows.GetByTraktID(xref.TraktID); + if (show == null) return false; + if (!show.TvDB_ID.HasValue) return false; + + tvdb_id = show.TvDB_ID.Value.ToString(); + title = show.Title; + year = show.Year; + + int retEpNum = 0, retSeason = 0; + GetTraktEpisodeNumber(aniepisode, show, xref.TraktSeasonNumber, ref retEpNum, ref retSeason); + if (retEpNum < 0) return false; + + episode = retEpNum.ToString(); + season = retSeason.ToString(); + + AniDB_Episode aniep = aniepisode.AniDB_Episode; + if (aniep != null) + { + TimeSpan t = TimeSpan.FromSeconds(aniep.LengthSeconds + 14); + int toMinutes = int.Parse(Math.Round(t.TotalMinutes).ToString()); + duration = toMinutes.ToString(); + } + else + duration = "25"; + + progress = "100"; + + plugin_version = "0.4"; + media_center_version = "1.2.0.1"; + media_center_date = "Dec 17 2010"; + + + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + return false; + } + + return true; + } + + private void GetTraktEpisodeNumber(AnimeEpisode aniepisode, Trakt_Show show, int season, ref int traktEpNum, ref int traktSeason) + { + try + { + traktEpNum = -1; + traktSeason = -1; + + AnimeSeries ser = aniepisode.AnimeSeries; + if (ser == null) return; + + //Dictionary dictTraktSeasons = GetDictTraktSeasons(show); + //Dictionary dictTraktEpisodes = GetDictTraktEpisodes(show); + + Dictionary dictTraktSeasons = null; + Dictionary dictTraktEpisodes = null; + GetDictTraktEpisodesAndSeasons(show, ref dictTraktEpisodes, ref dictTraktSeasons); + + int epNum = aniepisode.AniDB_Episode.EpisodeNumber; + + //episode + if (aniepisode.EpisodeTypeEnum == AniDBAPI.enEpisodeType.Episode) + { + if (dictTraktEpisodes != null && dictTraktSeasons != null) + { + if (dictTraktSeasons.ContainsKey(season)) + { + int absEpisodeNumber = dictTraktSeasons[season] + epNum - 1; + if (dictTraktEpisodes.ContainsKey(absEpisodeNumber)) + { + Trakt_Episode tvep = dictTraktEpisodes[absEpisodeNumber]; + traktEpNum = tvep.EpisodeNumber; + traktSeason = tvep.Season; + } + } + } + } + + if (aniepisode.EpisodeTypeEnum == AniDBAPI.enEpisodeType.Special) + { + traktSeason = 0; + traktEpNum = epNum; + } + + return; + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + return; + } + } + + private void GetDictTraktEpisodesAndSeasons(Trakt_Show show, ref Dictionary dictTraktEpisodes, ref Dictionary dictTraktSeasons) + { + dictTraktEpisodes = new Dictionary(); + dictTraktSeasons = new Dictionary(); + try + { + Trakt_EpisodeRepository repEps = new Trakt_EpisodeRepository(); + + // create a dictionary of absolute episode numbers for trakt episodes + // sort by season and episode number + // ignore season 0, which is used for specials + List eps = repEps.GetByShowID(show.Trakt_ShowID); + + List sortCriteria = new List(); + sortCriteria.Add(new SortPropOrFieldAndDirection("Season", false, SortType.eInteger)); + sortCriteria.Add(new SortPropOrFieldAndDirection("EpisodeNumber", false, SortType.eInteger)); + eps = Sorting.MultiSort(eps, sortCriteria); + + int i = 1; + int lastSeason = -999; + foreach (Trakt_Episode ep in eps) + { + if (ep.Season == 0) continue; + + dictTraktEpisodes[i] = ep; + + if (ep.Season != lastSeason) + dictTraktSeasons[ep.Season] = i; + + lastSeason = ep.Season; + + i++; + + } + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + } + } + + } +} diff --git a/JMMServer/Providers/TraktTV/TraktTVPost_ShowWatching.cs b/JMMServer/Providers/TraktTV/TraktTVPost_ShowWatching.cs new file mode 100644 index 000000000..5829ce9d2 --- /dev/null +++ b/JMMServer/Providers/TraktTV/TraktTVPost_ShowWatching.cs @@ -0,0 +1,66 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Runtime.Serialization; +using JMMServer.Entities; + +namespace JMMServer.Providers.TraktTV +{ + [DataContract] + public class TraktTVPost_ShowWatching + { + // http://trakt.tv/api-docs/show-watching + + [DataMember] + public string username { get; set; } + + [DataMember] + public string password { get; set; } + + [DataMember] + public string imdb_id { get; set; } + + [DataMember] + public string tvdb_id { get; set; } + + [DataMember] + public string title { get; set; } + + [DataMember] + public string year { get; set; } + + [DataMember] + public string season { get; set; } + + [DataMember] + public string episode { get; set; } + + [DataMember] + public string duration { get; set; } + + [DataMember] + public string progress { get; set; } + + [DataMember] + public string plugin_version { get; set; } + + [DataMember] + public string media_center_version { get; set; } + + [DataMember] + public string media_center_date { get; set; } + + public TraktTVPost_ShowWatching() + { + } + + public void Init(AnimeEpisode episode) + { + username = ServerSettings.Trakt_Username; + password = Utils.CalculateSHA1(ServerSettings.Trakt_Password, Encoding.Default); + + + } + } +} diff --git a/JMMServer/Providers/TraktTV/TraktTVSeasonEpisode.cs b/JMMServer/Providers/TraktTV/TraktTVSeasonEpisode.cs new file mode 100644 index 000000000..b1b445995 --- /dev/null +++ b/JMMServer/Providers/TraktTV/TraktTVSeasonEpisode.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Runtime.Serialization; +using JMMServer.Entities; +using NLog; +using JMMServer.Repositories; + +namespace JMMServer.Providers.TraktTV +{ + [DataContract] + public class TraktTVSeasonEpisode + { + private static Logger logger = LogManager.GetCurrentClassLogger(); + + [DataMember] + public string season { get; set; } + + [DataMember] + public string episode { get; set; } + } +} diff --git a/JMMServer/Providers/TraktTV/TraktTVSeasonResponse.cs b/JMMServer/Providers/TraktTV/TraktTVSeasonResponse.cs new file mode 100644 index 000000000..5de531c42 --- /dev/null +++ b/JMMServer/Providers/TraktTV/TraktTVSeasonResponse.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Runtime.Serialization; + +namespace JMMServer.Providers.TraktTV +{ + [DataContract] + public class TraktTVSeasonResponse + { + public TraktTVSeasonResponse() { } + + [DataMember] + public string season { get; set; } + + [DataMember] + public string url { get; set; } + + [DataMember] + public TraktTVImagesResponse images { get; set; } + + [DataMember] + public List episodes { get; set; } + + public override string ToString() + { + return string.Format("S{0} - {1} episodes", season, episodes.Count); + } + } +} diff --git a/JMMServer/Providers/TraktTV/TraktTVShowResponse.cs b/JMMServer/Providers/TraktTV/TraktTVShowResponse.cs new file mode 100644 index 000000000..247f33e73 --- /dev/null +++ b/JMMServer/Providers/TraktTV/TraktTVShowResponse.cs @@ -0,0 +1,76 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Runtime.Serialization; +using JMMContracts; + +namespace JMMServer.Providers.TraktTV +{ + [DataContract] + public class TraktTVShowResponse + { + public TraktTVShowResponse() { } + + [DataMember] + public string title { get; set; } + + [DataMember] + public string year { get; set; } + + [DataMember] + public string url { get; set; } + + [DataMember] + public string first_aired { get; set; } + + [DataMember] + public string country { get; set; } + + [DataMember] + public string overview { get; set; } + + [DataMember] + public string tvdb_id { get; set; } + + [DataMember] + public TraktTVImagesResponse images { get; set; } + + [DataMember] + public List seasons { get; set; } + + public string TraktID + { + get + { + if (string.IsNullOrEmpty(url)) return ""; + + int pos = url.LastIndexOf("/"); + if (pos < 0) return ""; + + string id = url.Substring(pos + 1, url.Length - pos - 1); + return id; + } + } + + public override string ToString() + { + return string.Format("{0} - {1} - {2}", title, year, overview); + } + + public Contract_TraktTVShowResponse ToContract() + { + Contract_TraktTVShowResponse contract = new Contract_TraktTVShowResponse(); + + contract.title = title; + contract.year = year; + contract.url = url; + contract.first_aired = first_aired; + contract.country = country; + contract.overview = overview; + contract.tvdb_id = tvdb_id; + + return contract; + } + } +} diff --git a/JMMServer/Providers/TvDB/TVDBSeriesSearchResult.cs b/JMMServer/Providers/TvDB/TVDBSeriesSearchResult.cs new file mode 100644 index 000000000..2d3da5585 --- /dev/null +++ b/JMMServer/Providers/TvDB/TVDBSeriesSearchResult.cs @@ -0,0 +1,56 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Xml; +using JMMContracts; + +namespace JMMServer.Providers.TvDB +{ + public class TVDBSeriesSearchResult + { + public string Id { get; set; } + public int SeriesID { get; set; } + public string Overview { get; set; } + public string SeriesName { get; set; } + public string Banner { get; set; } + public string Language { get; set; } + + public override string ToString() + { + return "TVDBSeriesSearchResult: " + Id + ":" + SeriesID + ":" + SeriesName + " - banner: " + Banner; + + } + + public TVDBSeriesSearchResult() + { + Id = string.Empty; + SeriesID = 0; + Overview = string.Empty; + SeriesName = string.Empty; + Banner = string.Empty; + } + + public TVDBSeriesSearchResult(XmlNode series) + { + if (series["seriesid"] != null) SeriesID = int.Parse(series["seriesid"].InnerText); + if (series["SeriesName"] != null) SeriesName = series["SeriesName"].InnerText; + if (series["id"] != null) Id = series["id"].InnerText; + if (series["Overview"] != null) Overview = series["Overview"].InnerText; + if (series["banner"] != null) Banner = series["banner"].InnerText; + if (series["language"] != null) Language = series["language"].InnerText; + } + + public Contract_TVDBSeriesSearchResult ToContract() + { + Contract_TVDBSeriesSearchResult contract = new Contract_TVDBSeriesSearchResult(); + contract.Id = this.Id; + contract.SeriesID = this.SeriesID; + contract.Overview = this.Overview; + contract.SeriesName = this.SeriesName; + contract.Banner = this.Banner; + contract.Language = this.Language; + return contract; + } + } +} diff --git a/JMMServer/Providers/TvDB/TvDBHelper.cs b/JMMServer/Providers/TvDB/TvDBHelper.cs new file mode 100644 index 000000000..baa938528 --- /dev/null +++ b/JMMServer/Providers/TvDB/TvDBHelper.cs @@ -0,0 +1,959 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Net; +using JMMServer.ImageDownload; +using System.Xml; +using NLog; +using System.IO; +using ICSharpCode.SharpZipLib.Zip; +using JMMServer.Entities; +using JMMServer.Repositories; +using JMMServer.Commands; + +namespace JMMServer.Providers.TvDB +{ + public class TvDBHelper + { + // http://thetvdb.com + //API Key: B178B8940CAF4A2C + + private static Logger logger = LogManager.GetCurrentClassLogger(); + private bool initialised = false; + private static UTF8Encoding enc = new UTF8Encoding(); + static Dictionary webClientList = new Dictionary(); + static int nDownloadGUIDGenerator = 1; + + public string urlMirrorsList + { + get { return @"http://www.thetvdb.com/api/" + Constants.TvDBURLs.apiKey + @"/mirrors.xml"; } + } + + public string urlServerTime + { + get { return @"http://www.thetvdb.com/api/Updates.php?type=none"; } + } + + public string urlUpdatesList + { + get { return @"http://www.thetvdb.com/api/Updates.php?type=all&time={0}"; } + } + + private string urlMirror = "http://thetvdb.com"; + public string UrlMirror + { + get + { + Init(); + return urlMirror; + } + } + + public static string URLMirror + { + get + { + return "http://thetvdb.com"; // they have said now that this will never change + } + } + + public static string GetRootImagesPath() + { + return ImageUtils.GetTvDBImagePath(); + } + + private string serverTime = ""; + + + public TvDBHelper() + { + + } + + public string CurrentServerTime + { + get + { + try + { + string xmlServerTime = Utils.DownloadWebPage(urlServerTime); + XmlDocument docServer = new XmlDocument(); + docServer.LoadXml(xmlServerTime); + + string serverTime = docServer["Items"]["Time"].InnerText; + + return serverTime; + } + catch + { + return ""; + } + } + } + + private void Init() + { + try + { + if (initialised) return; + + // 01. try and download the list of mirrors + string xmlMirrors = Utils.DownloadWebPage(urlMirrorsList); + + XmlDocument xmlDoc = new XmlDocument(); + xmlDoc.LoadXml(xmlMirrors); + + XmlNodeList mirrorItems = xmlDoc["Mirrors"].GetElementsByTagName("Mirror"); + + if (mirrorItems.Count <= 0) + return; + + string id = mirrorItems[0]["id"].InnerText; + urlMirror = mirrorItems[0]["mirrorpath"].InnerText; + string typemask = mirrorItems[0]["typemask"].InnerText; + + logger.Info("TVDB Mirror: {0}", urlMirror); + + // 02. get the server time + string xmlServerTime = Utils.DownloadWebPage(urlServerTime); + XmlDocument docServer = new XmlDocument(); + docServer.LoadXml(xmlServerTime); + + serverTime = docServer["Items"]["Time"].InnerText; + + logger.Info("serverTime: {0}", serverTime); + + initialised = true; + + } + catch (Exception ex) + { + logger.ErrorException("Error in TVDBHelper.Init: " + ex.ToString(), ex); + } + } + + public static bool ConfirmTvDBOnline() + { + TvDB_Series tvser = GetSeriesInfoOnline(73255); + if (tvser == null) + return false; + else + return true; + } + + public static TvDB_Series GetSeriesInfoOnline(int seriesID) + { + try + { + //Init(); + + string url = string.Format(Constants.TvDBURLs.urlSeriesBaseXML, URLMirror, Constants.TvDBURLs.apiKey, seriesID); + logger.Trace("GetSeriesInfo: {0}", url); + + // Search for a series + string xmlSeries = Utils.DownloadWebPage(url); + logger.Trace("GetSeriesInfo RESULT: {0}", xmlSeries); + + if (xmlSeries.Trim().Length == 0) return null; + + XmlDocument docSeries = new XmlDocument(); + docSeries.LoadXml(xmlSeries); + + TvDB_Series tvSeries = null; + if (docSeries != null) + { + TvDB_SeriesRepository repSeries = new TvDB_SeriesRepository(); + tvSeries = repSeries.GetByTvDBID(seriesID); + if (tvSeries == null) + tvSeries = new TvDB_Series(); + + tvSeries.PopulateFromSeriesInfo(docSeries); + repSeries.Save(tvSeries); + } + + return tvSeries; + + } + catch (Exception ex) + { + logger.ErrorException("Error in TVDBHelper.GetSeriesInfoOnline: " + ex.ToString(), ex); + } + + return null; + } + + public XmlDocument GetSeriesBannersOnline(int seriesID) + { + try + { + Init(); + + string url = string.Format(Constants.TvDBURLs.urlBannersXML, urlMirror, Constants.TvDBURLs.apiKey, seriesID); + logger.Trace("GetSeriesBannersOnline: {0}", url); + + // Search for a series + string xmlSeries = Utils.DownloadWebPage(url); + + XmlDocument docBanners = new XmlDocument(); + docBanners.LoadXml(xmlSeries); + + return docBanners; + + } + catch (Exception ex) + { + logger.ErrorException("Error in TVDBHelper.GetSeriesBannersOnline: " + ex.ToString(), ex); + } + + return null; + } + + public Dictionary GetFullSeriesInfo(int seriesID) + { + try + { + Init(); + + string url = string.Format(Constants.TvDBURLs.urlFullSeriesData, urlMirror, Constants.TvDBURLs.apiKey, seriesID); + logger.Trace("GetFullSeriesInfo: {0}", url); + + Stream data = Utils.DownloadWebBinary(url); + if (data != null) + { + // this will get following xml files: en.xml, actors.xml, banners.xml + return DecompressZipToXmls(data); + } + else + logger.Trace("GetFullSeriesInfo: data was null"); + + } + catch (Exception ex) + { + logger.ErrorException("Error in TVDBHelper.GetFullSeriesInfo: " + ex.ToString(), ex); + } + + return null; + } + + private static Dictionary DecompressZipToXmls(Stream s) + { + int bytes = 2048; + byte[] data = new byte[2048]; + Dictionary docsInZip = new Dictionary(); + ZipInputStream zis = new ZipInputStream(s); + ZipEntry currEntry = null; + StringBuilder b = new StringBuilder(); + + while ((currEntry = zis.GetNextEntry()) != null) + { + //BaseConfig.MyAnimeLog.Write("Decompressing Entry: {0}", currEntry.Name); + XmlDocument d = new XmlDocument(); + while ((bytes = zis.Read(data, 0, data.Length)) > 0) + b.Append(enc.GetString(data, 0, bytes)); + + //BaseConfig.MyAnimeLog.Write("Decompression done, now loading as XML..."); + try + { + d.LoadXml(b.ToString()); + //BaseConfig.MyAnimeLog.Write("Loaded as valid XML"); + docsInZip.Add(currEntry.Name, d); + } + catch (XmlException e) + { + logger.ErrorException("Error in TVDBHelper.DecompressZipToXmls: " + e.ToString(), e); + } + b.Remove(0, b.Length); + } + return docsInZip; + } + + public List GetFanart(int seriesID, bool forceRefresh) + { + List fanarts = new List(); + + if (forceRefresh) + { + fanarts = GetFanartOnline(seriesID); + } + else + { + TvDB_ImageFanartRepository repFanart = new TvDB_ImageFanartRepository(); + fanarts = repFanart.GetBySeriesID(seriesID); + if (fanarts.Count == 0) + fanarts = GetFanartOnline(seriesID); + } + + return fanarts; + } + + public List GetFanartOnline(int seriesID) + { + List fanarts = new List(); + + XmlDocument doc = GetSeriesBannersOnline(seriesID); + List banners = ParseBanners(seriesID, doc); + + foreach (object obj in banners) + { + if (obj.GetType() == typeof(TvDB_ImageFanart)) + fanarts.Add((TvDB_ImageFanart)obj); + } + + return fanarts; + } + + public List GetWideBannersOnline(int seriesID) + { + List wideBanners = new List(); + + XmlDocument doc = GetSeriesBannersOnline(seriesID); + List banners = ParseBanners(seriesID, doc); + + foreach (object obj in banners) + { + if (obj.GetType() == typeof(TvDB_ImageWideBanner)) + wideBanners.Add((TvDB_ImageWideBanner)obj); + } + + return wideBanners; + } + + public List GetPostersOnline(int seriesID) + { + //BaseConfig.MyAnimeLog.Write("Getting posters online: {0}", seriesID); + List posters = new List(); + + XmlDocument doc = GetSeriesBannersOnline(seriesID); + List banners = ParseBanners(seriesID, doc); + + foreach (object obj in banners) + { + if (obj.GetType() == typeof(TvDB_ImagePoster)) + posters.Add((TvDB_ImagePoster)obj); + } + + return posters; + } + + public void DownloadAutomaticImages(int seriesID, bool forceDownload) + { + XmlDocument doc = GetSeriesBannersOnline(seriesID); + DownloadAutomaticImages(doc, seriesID, forceDownload); + } + + public void DownloadAutomaticImages(XmlDocument doc, int seriesID, bool forceDownload) + { + List banners = ParseBanners(seriesID, doc); + + int numFanartDownloaded = 0; + foreach (object obj in banners) + { + if (obj.GetType() == typeof(TvDB_ImageFanart)) + { + TvDB_ImageFanart img = obj as TvDB_ImageFanart; + if (ServerSettings.TvDB_AutoFanart && numFanartDownloaded < ServerSettings.TvDB_AutoFanartAmount) + { + bool fileExists = File.Exists(img.FullImagePath); + if (!fileExists || (fileExists && forceDownload)) + { + CommandRequest_DownloadImage cmd = new CommandRequest_DownloadImage(img.TvDB_ImageFanartID, JMMImageType.TvDB_FanArt, forceDownload); + cmd.Save(); + numFanartDownloaded++; + } + } + } + + if (obj.GetType() == typeof(TvDB_ImagePoster)) + { + TvDB_ImagePoster img = obj as TvDB_ImagePoster; + if (ServerSettings.TvDB_AutoPosters) + { + bool fileExists = File.Exists(img.FullImagePath); + if (!fileExists || (fileExists && forceDownload)) + { + CommandRequest_DownloadImage cmd = new CommandRequest_DownloadImage(img.TvDB_ImagePosterID, JMMImageType.TvDB_Cover, forceDownload); + cmd.Save(); + } + } + } + + if (obj.GetType() == typeof(TvDB_ImageWideBanner)) + { + TvDB_ImageWideBanner img = obj as TvDB_ImageWideBanner; + if (ServerSettings.TvDB_AutoWideBanners) + { + bool fileExists = File.Exists(img.FullImagePath); + if (!fileExists || (fileExists && forceDownload)) + { + CommandRequest_DownloadImage cmd = new CommandRequest_DownloadImage(img.TvDB_ImageWideBannerID, JMMImageType.TvDB_Banner, forceDownload); + cmd.Save(); + } + } + } + } + } + + private List ParseBanners(int seriesID, XmlDocument xmlDoc) + { + List banners = new List(); + try + { + XmlNodeList bannerItems = xmlDoc["Banners"].GetElementsByTagName("Banner"); + + //BaseConfig.MyAnimeLog.Write("Found {0} banner nodes", bannerItems.Count); + + if (bannerItems.Count <= 0) + return banners; + + // banner types + // series = wide banner + // fanart = fanart + // poster = filmstrip poster/dvd cover + + TvDB_ImageFanartRepository repFanart = new TvDB_ImageFanartRepository(); + TvDB_ImagePosterRepository repPosters = new TvDB_ImagePosterRepository(); + TvDB_ImageWideBannerRepository repWideBanners = new TvDB_ImageWideBannerRepository(); + + foreach (XmlNode node in bannerItems) + { + JMMImageType imageType = JMMImageType.TvDB_Cover; + + string bannerType = node["BannerType"].InnerText.Trim().ToUpper(); + string bannerType2 = node["BannerType2"].InnerText.Trim().ToUpper(); + + + if (bannerType == "FANART") + imageType = JMMImageType.TvDB_FanArt; + else if (bannerType == "POSTER") + imageType = JMMImageType.TvDB_Cover; + else if (bannerType == "SEASON") + { + if (bannerType2 == "SEASON") + imageType = JMMImageType.TvDB_Cover; + else + imageType = JMMImageType.TvDB_Banner; + } + else if (bannerType == "SERIES") + { + if (bannerType2 == "SEASONWIDE" || bannerType2 == "GRAPHICAL" || bannerType2 == "TEXT" || bannerType2 == "BLANK") + imageType = JMMImageType.TvDB_Banner; + else + imageType = JMMImageType.TvDB_Cover; + } + + if (imageType == JMMImageType.TvDB_FanArt) + { + int id = int.Parse(node["id"].InnerText); + TvDB_ImageFanart img = repFanart.GetByTvDBID(id); + if (img == null) + { + img = new TvDB_ImageFanart(); + img.Enabled = 1; + } + + img.Populate(seriesID, node); + repFanart.Save(img); + + banners.Add(img); + } + + if (imageType == JMMImageType.TvDB_Banner) + { + int id = int.Parse(node["id"].InnerText); + + TvDB_ImageWideBanner img = repWideBanners.GetByTvDBID(id); + if (img == null) + { + img = new TvDB_ImageWideBanner(); + img.Enabled = 1; + } + + img.Populate(seriesID, node, TvDBImageNodeType.Series); + repWideBanners.Save(img); + + banners.Add(img); + } + + if (imageType == JMMImageType.TvDB_Cover) + { + int id = int.Parse(node["id"].InnerText); + + TvDB_ImagePoster img = repPosters.GetByTvDBID(id); + if (img == null) + { + img = new TvDB_ImagePoster(); + img.Enabled = 1; + } + + TvDBImageNodeType nodeType = TvDBImageNodeType.Series; + if (bannerType == "SEASON") nodeType = TvDBImageNodeType.Season; + + + img.Populate(seriesID, node, nodeType); + repPosters.Save(img); + + banners.Add(img); + } + } + } + catch (Exception ex) + { + logger.ErrorException("Error in ParseBanners: " + ex.ToString(), ex); + } + + return banners; + } + + + public List SearchSeries(string criteria) + { + List results = new List(); + + try + { + Init(); + + if (!initialised) return results; + + // Search for a series + string url = string.Format(Constants.TvDBURLs.urlSeriesSearch, criteria); + logger.Trace("Search TvDB Series: {0}", url); + + string xmlSeries = Utils.DownloadWebPage(url); + + XmlDocument docSeries = new XmlDocument(); + docSeries.LoadXml(xmlSeries); + + bool hasData = docSeries["Data"].HasChildNodes; + if (hasData) + { + XmlNodeList seriesItems = docSeries["Data"].GetElementsByTagName("Series"); + + foreach (XmlNode series in seriesItems) + { + TVDBSeriesSearchResult searchResult = new TVDBSeriesSearchResult(series); + results.Add(searchResult); + } + } + } + catch (Exception ex) + { + logger.ErrorException("Error in SearchSeries: " + ex.ToString(), ex); + } + + return results; + } + + + public static List GetUpdatedSeriesList(string serverTime) + { + List seriesList = new List(); + try + { + string url = string.Format(Constants.TvDBURLs.urlUpdatesList, URLMirror, serverTime); + + // Search for a series + string xmlUpdateList = Utils.DownloadWebPage(url); + //BaseConfig.MyAnimeLog.Write("GetSeriesInfo RESULT: {0}", xmlSeries); + + XmlDocument docUpdates = new XmlDocument(); + docUpdates.LoadXml(xmlUpdateList); + + XmlNodeList nodes = docUpdates["Items"].GetElementsByTagName("Series"); + foreach (XmlNode node in nodes) + { + string sid = node.InnerText; + int id = -1; + int.TryParse(sid, out id); + if (id > 0) seriesList.Add(id); + + //BaseConfig.MyAnimeLog.Write("Updated series: {0}", sid); + } + + return seriesList; + + } + catch (Exception ex) + { + logger.ErrorException("Error in GetUpdatedSeriesList: " + ex.ToString(), ex); + return seriesList; + } + } + + + /// + /// Updates the followung + /// 1. Series Info + /// 2. Episode Info + /// 3. Episode Images + /// 4. Fanart, Poster and Wide Banner Images + /// + /// + /// + public void UpdateAllInfoAndImages(int seriesID, bool forceRefresh) + { + TvDB_EpisodeRepository repEpisodes = new TvDB_EpisodeRepository(); + TvDB_SeriesRepository repSeries = new TvDB_SeriesRepository(); + + Dictionary docSeries = GetFullSeriesInfo(seriesID); + if (docSeries.ContainsKey("en.xml")) + { + try + { + // update the series info + XmlDocument xmlDoc = docSeries["en.xml"]; + if (xmlDoc != null) + { + TvDB_Series tvSeries = repSeries.GetByTvDBID(seriesID); + if (tvSeries == null) + tvSeries = new TvDB_Series(); + + tvSeries.PopulateFromSeriesInfo(xmlDoc); + repSeries.Save(tvSeries); + } + + // get all fanart, posters and wide banners + if (docSeries.ContainsKey("banners.xml")) + { + XmlDocument xmlDocBanners = docSeries["banners.xml"]; + if (xmlDocBanners != null) + DownloadAutomaticImages(xmlDocBanners, seriesID, forceRefresh); + } + + // update all the episodes and download episode images + XmlNodeList episodeItems = xmlDoc["Data"].GetElementsByTagName("Episode"); + logger.Trace("Found {0} Episode nodes", episodeItems.Count.ToString()); + + foreach (XmlNode node in episodeItems) + { + try + { + // the episode id + int id = int.Parse(node["id"].InnerText.Trim()); + TvDB_Episode ep = repEpisodes.GetByTvDBID(id); + if (ep == null) + ep = new TvDB_Episode(); + ep.Populate(node); + repEpisodes.Save(ep); + + //BaseConfig.MyAnimeLog.Write("Refreshing episode info for: {0}", ep.ToString()); + + // download the image for this episode + if (!string.IsNullOrEmpty(ep.Filename)) + { + bool fileExists = File.Exists(ep.FullImagePath); + if (!fileExists || (fileExists && forceRefresh)) + { + CommandRequest_DownloadImage cmd = new CommandRequest_DownloadImage(ep.TvDB_EpisodeID, JMMImageType.TvDB_Episode, forceRefresh); + cmd.Save(); + } + } + } + catch (Exception ex) + { + logger.ErrorException("Error in TVDBHelper.GetEpisodes: " + ex.ToString(), ex); + } + } + } + catch (Exception ex) + { + logger.ErrorException("Error in TVDBHelper.GetEpisodes: " + ex.ToString(), ex); + } + } + } + + + public static void LinkAniDBTvDB(int animeID, int tvDBID, int seasonNumber, bool fromWebCache) + { + // check if we have this information locally + // if not download it now + TvDB_SeriesRepository repSeries = new TvDB_SeriesRepository(); + TvDB_Series tvSeries = repSeries.GetByTvDBID(tvDBID); + if (tvSeries == null) + { + // we download the series info here just so that we have the basic info in the + // database before the queued task runs later + tvSeries = GetSeriesInfoOnline(tvDBID); + } + + // download and update series info, episode info and episode images + // will also download fanart, posters and wide banners + CommandRequest_TvDBUpdateSeriesAndEpisodes cmdSeriesEps = new CommandRequest_TvDBUpdateSeriesAndEpisodes(tvDBID, false); + cmdSeriesEps.Save(); + + CrossRef_AniDB_TvDBRepository repCrossRef = new CrossRef_AniDB_TvDBRepository(); + CrossRef_AniDB_TvDB xref = repCrossRef.GetByAnimeID(animeID); + if (xref == null) + xref = new CrossRef_AniDB_TvDB(); + + xref.AnimeID = animeID; + if (fromWebCache) + xref.CrossRefSource = (int)CrossRefSource.WebCache; + else + xref.CrossRefSource = (int)CrossRefSource.User; + + xref.TvDBID = tvDBID; + xref.TvDBSeasonNumber = seasonNumber; + repCrossRef.Save(xref); + + StatsCache.Instance.UpdateUsingAnime(animeID); + + logger.Trace("Changed tvdb association: {0}", animeID); + + CommandRequest_WebCacheSendXRefAniDBTvDB req = new CommandRequest_WebCacheSendXRefAniDBTvDB(xref.CrossRef_AniDB_TvDBID); + req.Save(); + } + + // Removes all TVDB information from a series, bringing it back to a blank state. + public static void RemoveLinkAniDBTvDB(AnimeSeries ser) + { + CrossRef_AniDB_TvDBRepository repCrossRef = new CrossRef_AniDB_TvDBRepository(); + CrossRef_AniDB_TvDB xref = repCrossRef.GetByAnimeID(ser.AniDB_ID); + if (xref == null) return; + + repCrossRef.Delete(xref.CrossRef_AniDB_TvDBID); + + CommandRequest_WebCacheDeleteXRefAniDBTvDB req = new CommandRequest_WebCacheDeleteXRefAniDBTvDB(ser.AniDB_ID); + req.Save(); + } + + public static void DownloadAllEpisodes() + { + CrossRef_AniDB_TvDBRepository repCrossRef = new CrossRef_AniDB_TvDBRepository(); + List allCrossRefs = repCrossRef.GetAll(); + + List tvDBIDs = new List(); + foreach (CrossRef_AniDB_TvDB xref in allCrossRefs) + { + if (!tvDBIDs.Contains(xref.TvDBID)) tvDBIDs.Add(xref.TvDBID); + } + + DownloadAllEpisodes(tvDBIDs); + } + + public static void DownloadAllEpisodes(List tvDBIDs) + { + foreach (int tvid in tvDBIDs) + { + CommandRequest_TvDBUpdateSeriesAndEpisodes cmd = new CommandRequest_TvDBUpdateSeriesAndEpisodes(tvid, false); + cmd.Save(); + } + } + + public static void ScanForMatches() + { + AnimeSeriesRepository repSeries = new AnimeSeriesRepository(); + List allSeries = repSeries.GetAll(); + + CrossRef_AniDB_TvDBRepository repCrossRef = new CrossRef_AniDB_TvDBRepository(); + List allCrossRefs = repCrossRef.GetAll(); + List alreadyLinked = new List(); + foreach (CrossRef_AniDB_TvDB xref in allCrossRefs) + { + alreadyLinked.Add(xref.AnimeID); + } + + foreach (AnimeSeries ser in allSeries) + { + if (alreadyLinked.Contains(ser.AniDB_ID)) continue; + + AniDB_Anime anime = ser.Anime; + + if (anime!= null) + { + logger.Trace("Found anime without tvDB association: " + anime.MainTitle); + if (!anime.SearchOnTvDB) + continue; + } + + CommandRequest_TvDBSearchAnime cmd = new CommandRequest_TvDBSearchAnime(ser.AniDB_ID, false); + cmd.Save(); + } + + } + + public static void UpdateAllInfo(bool force) + { + CrossRef_AniDB_TvDBRepository repCrossRef = new CrossRef_AniDB_TvDBRepository(); + List allCrossRefs = repCrossRef.GetAll(); + List alreadyLinked = new List(); + foreach (CrossRef_AniDB_TvDB xref in allCrossRefs) + { + CommandRequest_TvDBUpdateSeriesAndEpisodes cmd = new CommandRequest_TvDBUpdateSeriesAndEpisodes(xref.TvDBID, force); + cmd.Save(); + } + + } + + /// + /// Used to get a list of TvDB Series ID's that require updating + /// + /// The list Of Series ID's that need to be updated. Pass in an empty list + /// The current server time before the update started + public string IncrementalTvDBUpdate(ref List tvDBIDs, ref bool tvDBOnline) + { + // check if we have record of doing an automated update for the TvDB previously + // if we have then we have kept a record of the server time and can do a delta update + // otherwise we need to do a full update and keep a record of the time + + List allTvDBIDs = new List(); + tvDBIDs = new List(); + tvDBOnline = true; + + try + { + CrossRef_AniDB_TvDBRepository repCrossRef = new CrossRef_AniDB_TvDBRepository(); + AnimeSeriesRepository repSeries = new AnimeSeriesRepository(); + + // record the tvdb server time when we started + // we record the time now instead of after we finish, to include any possible misses + string currentTvDBServerTime = CurrentServerTime; + if (currentTvDBServerTime.Length == 0) + { + tvDBOnline = false; + return currentTvDBServerTime; + } + + foreach (AnimeSeries ser in repSeries.GetAll()) + { + CrossRef_AniDB_TvDB xref = ser.CrossRefTvDB; + if (xref == null) continue; + + if (!allTvDBIDs.Contains(xref.TvDBID)) allTvDBIDs.Add(xref.TvDBID); + } + + // get the time we last did a TvDB update + // if this is the first time it will be null + // update the anidb info ever 24 hours + ScheduledUpdateRepository repSched = new ScheduledUpdateRepository(); + ScheduledUpdate sched = repSched.GetByUpdateType((int)ScheduledUpdateType.TvDBInfo); + + string lastServerTime = ""; + if (sched != null) + { + TimeSpan ts = DateTime.Now - sched.LastUpdate; + logger.Trace("Last tvdb info update was {0} hours ago", ts.TotalHours.ToString()); + if (!string.IsNullOrEmpty(sched.UpdateDetails)) + lastServerTime = sched.UpdateDetails; + + // the UpdateDetails field for this type will actually contain the last server time from + // TheTvDB that a full update was performed + } + + + // get a list of updates from TvDB since that time + if (lastServerTime.Length > 0) + { + List seriesList = GetUpdatedSeriesList(lastServerTime); + logger.Trace("{0} series have been updated since last download", seriesList.Count.ToString()); + logger.Trace("{0} TvDB series locally", allTvDBIDs.Count.ToString()); + + foreach (int id in seriesList) + { + if (allTvDBIDs.Contains(id)) tvDBIDs.Add(id); + } + logger.Trace("{0} TvDB local series have been updated since last download", tvDBIDs.Count.ToString()); + } + else + { + // use the full list + tvDBIDs = allTvDBIDs; + } + + return currentTvDBServerTime; + } + catch (Exception ex) + { + logger.ErrorException("IncrementalTvDBUpdate: "+ ex.ToString(), ex); + return ""; + } + } + + /*public static void RemoveEpisodeAssociation(int aniDB_EpisodeID) + { + CrossRef_Episode_AniDB_TvDB xref = new CrossRef_Episode_AniDB_TvDB(); + if (xref.Load(aniDB_EpisodeID)) + { + xref.Delete(); + } + } + + public static TvDB_Episode PromptForEpisode(int tvDBID, AniDB_Episode aniep) + { + // get all the seasons for this episode + try + { + Dictionary seasons = new Dictionary(); + List seasonNumbers = new List(); + List info = TvDB_Episode.GetFromTvDBID(tvDBID); + if (info.Count == 0) + { + GUIDialogOK dlgOK = (GUIDialogOK)GUIWindowManager.GetWindow((int)GUIWindow.Window.WINDOW_DIALOG_OK); + if (null == dlgOK) + return null; + dlgOK.SetHeading("Error"); + dlgOK.SetLine(1, string.Empty); + dlgOK.SetLine(2, "No series found"); + dlgOK.DoModal(GUIWindowManager.ActiveWindow); + return null; + } + + IDialogbox dlg2 = (IDialogbox)GUIWindowManager.GetWindow((int)GUIWindow.Window.WINDOW_DIALOG_MENU); + dlg2.Reset(); + dlg2.SetHeading("Select Season"); + GUIListItem pItem2 = null; + + for (int i = 0; i < info.Count; i++) + { + int id = int.Parse(info[i][0]); + int season = int.Parse(info[i][1]); + seasons[id] = season; + seasonNumbers.Add(season); + + pItem2 = new GUIListItem(string.Format("Season {0}", season.ToString())); + dlg2.Add(pItem2); + } + + dlg2.DoModal(GUIWindowManager.ActiveWindow); + + if (dlg2.SelectedId > 0) + { + int season = seasonNumbers[dlg2.SelectedId - 1]; + List eps = TvDB_Episode.GetEpisodesForSeason(tvDBID, season); + + IDialogbox dlg3 = (IDialogbox)GUIWindowManager.GetWindow((int)GUIWindow.Window.WINDOW_DIALOG_MENU); + dlg3.Reset(); + dlg3.SetHeading(string.Format("{0} - {1}", aniep.EpisodeNumber, aniep.DefaultEpisodeName)); + GUIListItem pItem3 = null; + + foreach (TvDB_Episode ep in eps) + { + pItem3 = new GUIListItem(string.Format("Ep: {0} - {1}", ep.EpisodeNumber, ep.EpisodeName)); + dlg3.Add(pItem3); + } + dlg3.DoModal(GUIWindowManager.ActiveWindow); + if (dlg3.SelectedId > 0) + { + TvDB_Episode selEp = eps[dlg3.SelectedId - 1]; + CrossRef_Episode_AniDB_TvDB xref = new CrossRef_Episode_AniDB_TvDB(); + if (!xref.Load(aniep.EpisodeID)) + { + xref.AniDB_ID = aniep.EpisodeID; + } + xref.TvDB_ID = selEp.Id; + xref.Save(); + XMLService.Send_CrossRef_Episode_AniDB_TvDB(xref); + } + } + } + catch (Exception ex) + { + BaseConfig.MyAnimeLog.Write("Error in PromptForEpisode: {0}", ex.ToString()); + return null; + } + + return null; + }*/ + } +} diff --git a/JMMServer/RecentLog.cs b/JMMServer/RecentLog.cs new file mode 100644 index 000000000..8a04cbefe --- /dev/null +++ b/JMMServer/RecentLog.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using NLog; +using System.Collections.ObjectModel; +using JMMServer.Commands; + +namespace JMMServer +{ + public class RecentLog + { + /*public static ObservableCollection LogList { get; set; } + + private static RecentLog _instance; + public static RecentLog Instance + { + get + { + if (_instance == null) + { + _instance = new RecentLog(); + } + return _instance; + } + } + + public RecentLog() + { + LogList = new ObservableCollection(); + } + + public void AddLogEntry(string evt) + { + try + { + System.Windows.Application.Current.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, (Action)delegate() + { + LogList.Insert(0, evt); + if (LogList.Count == 1000) LogList.RemoveAt(999); + + }); + } + catch (Exception ex) + { + } + }*/ + } +} diff --git a/JMMServer/Repositories/AdhocRepository.cs b/JMMServer/Repositories/AdhocRepository.cs new file mode 100644 index 000000000..9707114bf --- /dev/null +++ b/JMMServer/Repositories/AdhocRepository.cs @@ -0,0 +1,623 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Entities; +using System.Data; +using System.Diagnostics; + +namespace JMMServer.Repositories +{ + /* NOTES + * Note 1 - I had a performance problem in sqlite where getting the video quality stats was taking a couple of minutes + * Adding this extra unncessary join reduced that query down to less than a second + */ + public class AdhocRepository + { + #region Video Quality + /// + /// Gets a list fo all the possible video quality settings for the user e.g. dvd, blu-ray + /// + /// + public List GetAllVideoQuality() + { + List allVidQuality = new List(); + + using (var session = JMMService.SessionFactory.OpenSession()) + { + System.Data.IDbCommand command = session.Connection.CreateCommand(); + command.CommandText = "SELECT Distinct(File_Source) FROM AniDB_File"; + + using (IDataReader rdr = command.ExecuteReader()) + { + while (rdr.Read()) + { + string vidQual = rdr[0].ToString().Trim(); + allVidQuality.Add(vidQual); + } + } + } + + return allVidQuality; + } + + /// + /// Get's all the video quality settings (comma separated) that apply to each group + /// + /// + public Dictionary GetAllVideoQualityByGroup() + { + Dictionary allVidQuality = new Dictionary(); + + using (var session = JMMService.SessionFactory.OpenSession()) + { + System.Data.IDbCommand command = session.Connection.CreateCommand(); + command.CommandText = "SELECT ag.AnimeGroupID, anifile.File_Source "; + command.CommandText += "from AnimeGroup ag "; + command.CommandText += "INNER JOIN AnimeSeries ser on ser.AnimeGroupID = ag.AnimeGroupID "; + command.CommandText += "INNER JOIN AnimeEpisode ep on ep.AnimeSeriesID = ser.AnimeSeriesID "; + command.CommandText += "INNER JOIN AniDB_Episode aniep on ep.AniDB_EpisodeID = aniep.EpisodeID "; + command.CommandText += "INNER JOIN CrossRef_File_Episode xref on aniep.EpisodeID = xref.EpisodeID "; + command.CommandText += "INNER JOIN AniDB_File anifile on anifile.Hash = xref.Hash "; + command.CommandText += "INNER JOIN CrossRef_Subtitles_AniDB_File subt on subt.FileID = anifile.FileID "; // See Note 1 + command.CommandText += "GROUP BY ag.AnimeGroupID, anifile.File_Source "; + + + + using (IDataReader rdr = command.ExecuteReader()) + { + while (rdr.Read()) + { + int groupID = int.Parse(rdr[0].ToString()); + string vidQual = rdr[1].ToString().Trim(); + + if (!allVidQuality.ContainsKey(groupID)) + allVidQuality[groupID] = ""; + + if (allVidQuality[groupID].Length > 0) + allVidQuality[groupID] += ","; + + allVidQuality[groupID] += vidQual; + } + } + } + + return allVidQuality; + } + + /// + /// Get's all the video quality settings (comma separated) that apply to each group + /// + /// + public Dictionary GetAllVideoQualityByAnime() + { + Dictionary allVidQuality = new Dictionary(); + + using (var session = JMMService.SessionFactory.OpenSession()) + { + System.Data.IDbCommand command = session.Connection.CreateCommand(); + command.CommandText = "SELECT anime.AnimeID, anime.MainTitle, anifile.File_Source "; + command.CommandText += "FROM AnimeSeries ser "; + command.CommandText += "INNER JOIN AniDB_Anime anime on anime.AnimeID = ser.AniDB_ID "; + command.CommandText += "INNER JOIN AnimeEpisode ep on ep.AnimeSeriesID = ser.AnimeSeriesID "; + command.CommandText += "INNER JOIN AniDB_Episode aniep on ep.AniDB_EpisodeID = aniep.EpisodeID "; + command.CommandText += "INNER JOIN CrossRef_File_Episode xref on aniep.EpisodeID = xref.EpisodeID "; + command.CommandText += "INNER JOIN AniDB_File anifile on anifile.Hash = xref.Hash "; + command.CommandText += "INNER JOIN CrossRef_Subtitles_AniDB_File subt on subt.FileID = anifile.FileID "; // See Note 1 + command.CommandText += "GROUP BY anime.AnimeID, anime.MainTitle, anifile.File_Source "; + + + + using (IDataReader rdr = command.ExecuteReader()) + { + while (rdr.Read()) + { + int groupID = int.Parse(rdr[0].ToString()); + string vidQual = rdr[2].ToString().Trim(); + + if (!allVidQuality.ContainsKey(groupID)) + allVidQuality[groupID] = ""; + + if (allVidQuality[groupID].Length > 0) + allVidQuality[groupID] += ","; + + allVidQuality[groupID] += vidQual; + } + } + } + + return allVidQuality; + } + + public string GetAllVideoQualityForGroup(int animeGroupID) + { + string vidQuals = ""; + + using (var session = JMMService.SessionFactory.OpenSession()) + { + System.Data.IDbCommand command = session.Connection.CreateCommand(); + command.CommandText = "SELECT anifile.File_Source "; + command.CommandText += "from AnimeGroup ag "; + command.CommandText += "INNER JOIN AnimeSeries ser on ser.AnimeGroupID = ag.AnimeGroupID "; + command.CommandText += "INNER JOIN AnimeEpisode ep on ep.AnimeSeriesID = ser.AnimeSeriesID "; + command.CommandText += "INNER JOIN AniDB_Episode aniep on ep.AniDB_EpisodeID = aniep.EpisodeID "; + command.CommandText += "INNER JOIN CrossRef_File_Episode xref on aniep.EpisodeID = xref.EpisodeID "; + command.CommandText += "INNER JOIN AniDB_File anifile on anifile.Hash = xref.Hash "; + command.CommandText += "INNER JOIN CrossRef_Subtitles_AniDB_File subt on subt.FileID = anifile.FileID "; // See Note 1 + command.CommandText += "where ag.AnimeGroupID = " + animeGroupID.ToString(); + command.CommandText += " GROUP BY anifile.File_Source "; + + using (IDataReader rdr = command.ExecuteReader()) + { + while (rdr.Read()) + { + string vidQual = rdr[0].ToString().Trim(); + + if (vidQuals.Length > 0) + vidQuals += ","; + + vidQuals += vidQual; + } + } + } + + return vidQuals; + } + + public string GetAllVideoQualityForAnime(int animeID) + { + string vidQuals = ""; + + using (var session = JMMService.SessionFactory.OpenSession()) + { + System.Data.IDbCommand command = session.Connection.CreateCommand(); + command.CommandText = "SELECT anifile.File_Source "; + command.CommandText += "FROM AnimeSeries ser "; + command.CommandText += "INNER JOIN AniDB_Anime anime on anime.AnimeID = ser.AniDB_ID "; + command.CommandText += "INNER JOIN AnimeEpisode ep on ep.AnimeSeriesID = ser.AnimeSeriesID "; + command.CommandText += "INNER JOIN AniDB_Episode aniep on ep.AniDB_EpisodeID = aniep.EpisodeID "; + command.CommandText += "INNER JOIN CrossRef_File_Episode xref on aniep.EpisodeID = xref.EpisodeID "; + command.CommandText += "INNER JOIN AniDB_File anifile on anifile.Hash = xref.Hash "; + command.CommandText += "INNER JOIN CrossRef_Subtitles_AniDB_File subt on subt.FileID = anifile.FileID "; // See Note 1 + command.CommandText += "where anime.AnimeID = " + animeID.ToString(); + command.CommandText += " GROUP BY anifile.File_Source "; + + using (IDataReader rdr = command.ExecuteReader()) + { + while (rdr.Read()) + { + string vidQual = rdr[0].ToString().Trim(); + + if (vidQuals.Length > 0) + vidQuals += ","; + + vidQuals += vidQual; + } + } + } + + return vidQuals; + } + + public Dictionary GetEpisodeVideoQualityStatsByAnime() + { + Dictionary dictStats = new Dictionary(); + + + using (var session = JMMService.SessionFactory.OpenSession()) + { + System.Data.IDbCommand command = session.Connection.CreateCommand(); + command.CommandText = "SELECT anime.AnimeID, anime.MainTitle, anifile.File_Source, aniep.EpisodeNumber "; + command.CommandText += "from AnimeSeries ser "; + command.CommandText += "INNER JOIN AniDB_Anime anime on anime.AnimeID = ser.AniDB_ID "; + command.CommandText += "INNER JOIN AnimeEpisode ep on ep.AnimeSeriesID = ser.AnimeSeriesID "; + command.CommandText += "INNER JOIN AniDB_Episode aniep on ep.AniDB_EpisodeID = aniep.EpisodeID "; + command.CommandText += "INNER JOIN CrossRef_File_Episode xref on aniep.EpisodeID = xref.EpisodeID "; + command.CommandText += "INNER JOIN AniDB_File anifile on anifile.Hash = xref.Hash "; + command.CommandText += "INNER JOIN CrossRef_Subtitles_AniDB_File subt on subt.FileID = anifile.FileID "; // See Note 1 + command.CommandText += "WHERE aniep.EpisodeType = 1 "; // normal episodes only + command.CommandText += "GROUP BY anime.AnimeID, anime.MainTitle, anifile.File_Source, aniep.EpisodeNumber "; + command.CommandText += "ORDER BY anime.AnimeID, anime.MainTitle, anifile.File_Source, aniep.EpisodeNumber "; + + using (IDataReader rdr = command.ExecuteReader()) + { + while (rdr.Read()) + { + int animeID = int.Parse(rdr[0].ToString()); + string mainTitle = rdr[1].ToString().Trim(); + string vidQual = rdr[2].ToString().Trim(); + int epNumber = int.Parse(rdr[3].ToString()); + + if (animeID == 7656) + { + Debug.Print(""); + } + + if (!dictStats.ContainsKey(animeID)) + { + AnimeVideoQualityStat stat = new AnimeVideoQualityStat(); + stat.AnimeID = animeID; + stat.MainTitle = mainTitle; + stat.VideoQualityEpisodeCount = new Dictionary(); + stat.VideoQualityEpisodeCount[vidQual] = 1; + dictStats[animeID] = stat; + } + else + { + if (dictStats[animeID].VideoQualityEpisodeCount.ContainsKey(vidQual)) + dictStats[animeID].VideoQualityEpisodeCount[vidQual]++; + else + dictStats[animeID].VideoQualityEpisodeCount[vidQual] = 1; + } + } + } + } + + return dictStats; + } + + public AnimeVideoQualityStat GetEpisodeVideoQualityStatsForAnime(int aID) + { + AnimeVideoQualityStat stat = new AnimeVideoQualityStat(); + stat.VideoQualityEpisodeCount = new Dictionary(); + + using (var session = JMMService.SessionFactory.OpenSession()) + { + System.Data.IDbCommand command = session.Connection.CreateCommand(); + command.CommandText = "SELECT anime.AnimeID, anime.MainTitle, anifile.File_Source, aniep.EpisodeNumber "; + command.CommandText += "from AnimeSeries ser "; + command.CommandText += "INNER JOIN AniDB_Anime anime on anime.AnimeID = ser.AniDB_ID "; + command.CommandText += "INNER JOIN AnimeEpisode ep on ep.AnimeSeriesID = ser.AnimeSeriesID "; + command.CommandText += "INNER JOIN AniDB_Episode aniep on ep.AniDB_EpisodeID = aniep.EpisodeID "; + command.CommandText += "INNER JOIN CrossRef_File_Episode xref on aniep.EpisodeID = xref.EpisodeID "; + command.CommandText += "INNER JOIN AniDB_File anifile on anifile.Hash = xref.Hash "; + command.CommandText += "INNER JOIN CrossRef_Subtitles_AniDB_File subt on subt.FileID = anifile.FileID "; // See Note 1 + command.CommandText += "WHERE aniep.EpisodeType = 1 "; // normal episodes only + command.CommandText += "AND anime.AnimeID = " + aID.ToString(); + command.CommandText += " GROUP BY anime.AnimeID, anime.MainTitle, anifile.File_Source, aniep.EpisodeNumber "; + + using (IDataReader rdr = command.ExecuteReader()) + { + while (rdr.Read()) + { + stat.AnimeID = int.Parse(rdr[0].ToString()); + stat.MainTitle = rdr[1].ToString().Trim(); + + string vidQual = rdr[2].ToString().Trim(); + int epNumber = int.Parse(rdr[3].ToString()); + + if (!stat.VideoQualityEpisodeCount.ContainsKey(vidQual)) + stat.VideoQualityEpisodeCount[vidQual] = 1; + else + stat.VideoQualityEpisodeCount[vidQual]++; + } + } + } + + return stat; + } + + #endregion + + #region Release Groups + /// + /// Gets a list of all the possible release groups for the user e.g. doki, chihiro + /// + /// + public List GetAllReleaseGroups() + { + List allReleaseGroups = new List(); + + /* + -- Release groups by anime group + SELECT ag.AnimeGroupID, ag.GroupName, anifile.Anime_GroupName + from AnimeGroup ag + INNER JOIN AnimeSeries ser on ser.AnimeGroupID = ag.AnimeGroupID + INNER JOIN AnimeEpisode ep on ep.AnimeSeriesID = ser.AnimeSeriesID + INNER JOIN AniDB_Episode aniep on ep.AniDB_EpisodeID = aniep.EpisodeID + INNER JOIN CrossRef_File_Episode xref on aniep.EpisodeID = xref.EpisodeID + INNER JOIN AniDB_File anifile on anifile.Hash = xref.Hash + --where ag.AnimeGroupID = 127 + GROUP BY ag.AnimeGroupID, ag.GroupName, anifile.Anime_GroupName + + -- Unique release groups + SELECT anifile.Anime_GroupName, anifile.Anime_GroupNameShort + from AniDB_Episode aniep + INNER JOIN CrossRef_File_Episode xref on aniep.EpisodeID = xref.EpisodeID + INNER JOIN AniDB_File anifile on anifile.Hash = xref.Hash + GROUP BY anifile.Anime_GroupName, anifile.Anime_GroupNameShort + */ + + return allReleaseGroups; + } + + #endregion + + #region Audio and Subtitle Languages + /// + /// Gets a list of all the possible audio languages + /// + /// + public List GetAllUniqueAudioLanguages() + { + List allLanguages = new List(); + + using (var session = JMMService.SessionFactory.OpenSession()) + { + System.Data.IDbCommand command = session.Connection.CreateCommand(); + command.CommandText = "SELECT Distinct(lan.LanguageName) "; + command.CommandText += "FROM CrossRef_Languages_AniDB_File audio "; + command.CommandText += "INNER JOIN Language lan on audio.LanguageID = lan.LanguageID "; + command.CommandText += "ORDER BY lan.LanguageName "; + + using (IDataReader rdr = command.ExecuteReader()) + { + while (rdr.Read()) + { + string lan = rdr[0].ToString().Trim(); + allLanguages.Add(lan); + } + } + } + + return allLanguages; + } + + /// + /// Gets a list of all the possible subtitle languages + /// + /// + public List GetAllUniqueSubtitleLanguages() + { + List allLanguages = new List(); + + using (var session = JMMService.SessionFactory.OpenSession()) + { + System.Data.IDbCommand command = session.Connection.CreateCommand(); + command.CommandText = "SELECT Distinct(lan.LanguageName) "; + command.CommandText += "FROM CrossRef_Subtitles_AniDB_File subt "; + command.CommandText += "INNER JOIN Language lan on subt.LanguageID = lan.LanguageID "; + command.CommandText += "ORDER BY lan.LanguageName "; + + using (IDataReader rdr = command.ExecuteReader()) + { + while (rdr.Read()) + { + string lan = rdr[0].ToString().Trim(); + allLanguages.Add(lan); + } + } + } + + return allLanguages; + } + + public Dictionary GetAudioLanguageStatsForAnime() + { + Dictionary dictStats = new Dictionary(); + + + using (var session = JMMService.SessionFactory.OpenSession()) + { + System.Data.IDbCommand command = session.Connection.CreateCommand(); + command.CommandText = "SELECT anime.AnimeID, anime.MainTitle, lan.LanguageName "; + command.CommandText += "FROM AnimeSeries ser "; + command.CommandText += "INNER JOIN AniDB_Anime anime on anime.AnimeID = ser.AniDB_ID "; + command.CommandText += "INNER JOIN AnimeEpisode ep on ep.AnimeSeriesID = ser.AnimeSeriesID "; + command.CommandText += "INNER JOIN AniDB_Episode aniep on ep.AniDB_EpisodeID = aniep.EpisodeID "; + command.CommandText += "INNER JOIN CrossRef_File_Episode xref on aniep.EpisodeID = xref.EpisodeID "; + command.CommandText += "INNER JOIN AniDB_File anifile on anifile.Hash = xref.Hash "; + command.CommandText += "INNER JOIN CrossRef_Languages_AniDB_File audio on audio.FileID = anifile.FileID "; + command.CommandText += "INNER JOIN Language lan on audio.LanguageID = lan.LanguageID "; + command.CommandText += "GROUP BY anime.AnimeID, anime.MainTitle, lan.LanguageName "; + + using (IDataReader rdr = command.ExecuteReader()) + { + while (rdr.Read()) + { + int animeID = int.Parse(rdr[0].ToString()); + string mainTitle = rdr[1].ToString().Trim(); + string lanName = rdr[2].ToString().Trim(); + + + if (animeID == 7656) + { + Debug.Print(""); + } + + if (!dictStats.ContainsKey(animeID)) + { + LanguageStat stat = new LanguageStat(); + stat.AnimeID = animeID; + stat.MainTitle = mainTitle; + stat.LanguageNames = new List(); + stat.LanguageNames.Add(lanName); + dictStats[animeID] = stat; + } + else + dictStats[animeID].LanguageNames.Add(lanName); + + } + } + } + + return dictStats; + } + + public Dictionary GetSubtitleLanguageStatsForAnime() + { + Dictionary dictStats = new Dictionary(); + + + using (var session = JMMService.SessionFactory.OpenSession()) + { + System.Data.IDbCommand command = session.Connection.CreateCommand(); + command.CommandText = "SELECT anime.AnimeID, anime.MainTitle, lan.LanguageName "; + command.CommandText += "FROM AnimeSeries ser "; + command.CommandText += "INNER JOIN AniDB_Anime anime on anime.AnimeID = ser.AniDB_ID "; + command.CommandText += "INNER JOIN AnimeEpisode ep on ep.AnimeSeriesID = ser.AnimeSeriesID "; + command.CommandText += "INNER JOIN AniDB_Episode aniep on ep.AniDB_EpisodeID = aniep.EpisodeID "; + command.CommandText += "INNER JOIN CrossRef_File_Episode xref on aniep.EpisodeID = xref.EpisodeID "; + command.CommandText += "INNER JOIN AniDB_File anifile on anifile.Hash = xref.Hash "; + command.CommandText += "INNER JOIN CrossRef_Subtitles_AniDB_File subt on subt.FileID = anifile.FileID "; + command.CommandText += "INNER JOIN Language lan on subt.LanguageID = lan.LanguageID "; + command.CommandText += "GROUP BY anime.AnimeID, anime.MainTitle, lan.LanguageName "; + + using (IDataReader rdr = command.ExecuteReader()) + { + while (rdr.Read()) + { + int animeID = int.Parse(rdr[0].ToString()); + string mainTitle = rdr[1].ToString().Trim(); + string lanName = rdr[2].ToString().Trim(); + + + if (animeID == 7656) + { + Debug.Print(""); + } + + if (!dictStats.ContainsKey(animeID)) + { + LanguageStat stat = new LanguageStat(); + stat.AnimeID = animeID; + stat.MainTitle = mainTitle; + stat.LanguageNames = new List(); + stat.LanguageNames.Add(lanName); + dictStats[animeID] = stat; + } + else + dictStats[animeID].LanguageNames.Add(lanName); + + } + } + } + + return dictStats; + } + + public Dictionary GetAudioLanguageStatsByAnime(int aID) + { + Dictionary dictStats = new Dictionary(); + + + using (var session = JMMService.SessionFactory.OpenSession()) + { + System.Data.IDbCommand command = session.Connection.CreateCommand(); + command.CommandText = "SELECT anime.AnimeID, anime.MainTitle, lan.LanguageName "; + command.CommandText += "FROM AnimeSeries ser "; + command.CommandText += "INNER JOIN AniDB_Anime anime on anime.AnimeID = ser.AniDB_ID "; + command.CommandText += "INNER JOIN AnimeEpisode ep on ep.AnimeSeriesID = ser.AnimeSeriesID "; + command.CommandText += "INNER JOIN AniDB_Episode aniep on ep.AniDB_EpisodeID = aniep.EpisodeID "; + command.CommandText += "INNER JOIN CrossRef_File_Episode xref on aniep.EpisodeID = xref.EpisodeID "; + command.CommandText += "INNER JOIN AniDB_File anifile on anifile.Hash = xref.Hash "; + command.CommandText += "INNER JOIN CrossRef_Languages_AniDB_File audio on audio.FileID = anifile.FileID "; + command.CommandText += "INNER JOIN Language lan on audio.LanguageID = lan.LanguageID "; + command.CommandText += "WHERE anime.AnimeID = " + aID.ToString(); + command.CommandText += " GROUP BY anime.AnimeID, anime.MainTitle, lan.LanguageName "; + + using (IDataReader rdr = command.ExecuteReader()) + { + while (rdr.Read()) + { + int animeID = int.Parse(rdr[0].ToString()); + string mainTitle = rdr[1].ToString().Trim(); + string lanName = rdr[2].ToString().Trim(); + + + if (animeID == 7656) + { + Debug.Print(""); + } + + if (!dictStats.ContainsKey(animeID)) + { + LanguageStat stat = new LanguageStat(); + stat.AnimeID = animeID; + stat.MainTitle = mainTitle; + stat.LanguageNames = new List(); + stat.LanguageNames.Add(lanName); + dictStats[animeID] = stat; + } + else + dictStats[animeID].LanguageNames.Add(lanName); + + } + } + } + + return dictStats; + } + + public Dictionary GetSubtitleLanguageStatsByAnime(int aID) + { + Dictionary dictStats = new Dictionary(); + + + using (var session = JMMService.SessionFactory.OpenSession()) + { + System.Data.IDbCommand command = session.Connection.CreateCommand(); + command.CommandText = "SELECT anime.AnimeID, anime.MainTitle, lan.LanguageName "; + command.CommandText += "FROM AnimeSeries ser "; + command.CommandText += "INNER JOIN AniDB_Anime anime on anime.AnimeID = ser.AniDB_ID "; + command.CommandText += "INNER JOIN AnimeEpisode ep on ep.AnimeSeriesID = ser.AnimeSeriesID "; + command.CommandText += "INNER JOIN AniDB_Episode aniep on ep.AniDB_EpisodeID = aniep.EpisodeID "; + command.CommandText += "INNER JOIN CrossRef_File_Episode xref on aniep.EpisodeID = xref.EpisodeID "; + command.CommandText += "INNER JOIN AniDB_File anifile on anifile.Hash = xref.Hash "; + command.CommandText += "INNER JOIN CrossRef_Subtitles_AniDB_File subt on subt.FileID = anifile.FileID "; + command.CommandText += "INNER JOIN Language lan on subt.LanguageID = lan.LanguageID "; + command.CommandText += "WHERE anime.AnimeID = " + aID.ToString(); + command.CommandText += " GROUP BY anime.AnimeID, anime.MainTitle, lan.LanguageName "; + + using (IDataReader rdr = command.ExecuteReader()) + { + while (rdr.Read()) + { + int animeID = int.Parse(rdr[0].ToString()); + string mainTitle = rdr[1].ToString().Trim(); + string lanName = rdr[2].ToString().Trim(); + + + if (animeID == 7656) + { + Debug.Print(""); + } + + if (!dictStats.ContainsKey(animeID)) + { + LanguageStat stat = new LanguageStat(); + stat.AnimeID = animeID; + stat.MainTitle = mainTitle; + stat.LanguageNames = new List(); + stat.LanguageNames.Add(lanName); + dictStats[animeID] = stat; + } + else + dictStats[animeID].LanguageNames.Add(lanName); + + } + } + } + + return dictStats; + } + + #endregion + } + + public class AnimeVideoQualityStat + { + public int AnimeID { get; set; } + public string MainTitle { get; set; } + public Dictionary VideoQualityEpisodeCount { get; set; } // video quality / number of episodes that match that quality + + } + + public class LanguageStat + { + public int AnimeID { get; set; } + public string MainTitle { get; set; } + public List LanguageNames { get; set; } // a list of all the languages that apply to this anime + + } +} diff --git a/JMMServer/Repositories/AniDB_AnimeRepository.cs b/JMMServer/Repositories/AniDB_AnimeRepository.cs new file mode 100644 index 000000000..f75a8df63 --- /dev/null +++ b/JMMServer/Repositories/AniDB_AnimeRepository.cs @@ -0,0 +1,90 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using NHibernateTest; +using JMMServer.Entities; +using NHibernate.Criterion; + +namespace JMMServer.Repositories +{ + public class AniDB_AnimeRepository + { + public void Save(AniDB_Anime obj) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + session.SaveOrUpdate(obj); + transaction.Commit(); + } + } + } + + public AniDB_Anime GetByID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + return session.Get(id); + } + } + + public AniDB_Anime GetByAnimeID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + AniDB_Anime cr = session + .CreateCriteria(typeof(AniDB_Anime)) + .Add(Restrictions.Eq("AnimeID", id)) + .UniqueResult(); + return cr; + } + } + + public List GetAll() + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var objs = session + .CreateCriteria(typeof(AniDB_Anime)) + .List(); + + return new List(objs); + } + } + + public List GetForDate(DateTime startDate, DateTime endDate) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var objs = session + .CreateCriteria(typeof(AniDB_Anime)) + .Add(Restrictions.Ge("AirDate", startDate)) + .Add(Restrictions.Le("AirDate", endDate)) + .AddOrder(Order.Asc("AirDate")) + .List(); + + return new List(objs); + } + } + + public void Delete(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + AniDB_Anime cr = GetByID(id); + if (cr != null) + { + session.Delete(cr); + transaction.Commit(); + } + } + } + } + } +} diff --git a/JMMServer/Repositories/AniDB_Anime_CategoryRepository.cs b/JMMServer/Repositories/AniDB_Anime_CategoryRepository.cs new file mode 100644 index 000000000..660a33021 --- /dev/null +++ b/JMMServer/Repositories/AniDB_Anime_CategoryRepository.cs @@ -0,0 +1,104 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Entities; +using NHibernate.Criterion; + +namespace JMMServer.Repositories +{ + public class AniDB_Anime_CategoryRepository + { + public void Save(AniDB_Anime_Category obj) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + session.SaveOrUpdate(obj); + transaction.Commit(); + } + } + } + + public AniDB_Anime_Category GetByID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + return session.Get(id); + } + } + + public List GetAll() + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var objs = session + .CreateCriteria(typeof(AniDB_Anime_Category)) + .List(); + + return new List(objs); ; + } + } + + public AniDB_Anime_Category GetByAnimeIDAndCategoryID(int animeid, int catid) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + AniDB_Anime_Category cr = session + .CreateCriteria(typeof(AniDB_Anime_Category)) + .Add(Restrictions.Eq("AnimeID", animeid)) + .Add(Restrictions.Eq("CategoryID", catid)) + .UniqueResult(); + return cr; + } + } + + public List GetByAnimeID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var cats = session + .CreateCriteria(typeof(AniDB_Anime_Category)) + .Add(Restrictions.Eq("AnimeID", id)) + .AddOrder(Order.Desc("Weighting")) + .List(); + + return new List(cats); + } + } + + /// + /// Gets all the anime categories, but only if we have the anime locally + /// + /// + public List GetAllForLocalSeries() + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var animeCats = session.CreateQuery("FROM AniDB_Anime_Category aac WHERE aac.AnimeID in (Select aser.AniDB_ID From AnimeSeries aser)") + .List(); + + return new List(animeCats); + } + } + + public void Delete(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + AniDB_Anime_Category cr = GetByID(id); + if (cr != null) + { + session.Delete(cr); + transaction.Commit(); + } + } + } + } + } +} diff --git a/JMMServer/Repositories/AniDB_Anime_CharacterRepository.cs b/JMMServer/Repositories/AniDB_Anime_CharacterRepository.cs new file mode 100644 index 000000000..c089225c8 --- /dev/null +++ b/JMMServer/Repositories/AniDB_Anime_CharacterRepository.cs @@ -0,0 +1,77 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Entities; +using NHibernate.Criterion; + +namespace JMMServer.Repositories +{ + public class AniDB_Anime_CharacterRepository + { + public void Save(AniDB_Anime_Character obj) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + session.SaveOrUpdate(obj); + transaction.Commit(); + } + } + } + + public AniDB_Anime_Character GetByID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + return session.Get(id); + } + } + + public List GetByAnimeID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var cats = session + .CreateCriteria(typeof(AniDB_Anime_Character)) + .Add(Restrictions.Eq("AnimeID", id)) + .List(); + + return new List(cats); + } + } + + public AniDB_Anime_Character GetByAnimeIDAndCharID(int animeid, int charid) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + AniDB_Anime_Character cr = session + .CreateCriteria(typeof(AniDB_Anime_Character)) + .Add(Restrictions.Eq("AnimeID", animeid)) + .Add(Restrictions.Eq("CharID", charid)) + .UniqueResult(); + + return cr; + } + } + + public void Delete(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + AniDB_Anime_Character cr = GetByID(id); + if (cr != null) + { + session.Delete(cr); + transaction.Commit(); + } + } + } + } + } +} diff --git a/JMMServer/Repositories/AniDB_Anime_DefaultImageRepository.cs b/JMMServer/Repositories/AniDB_Anime_DefaultImageRepository.cs new file mode 100644 index 000000000..debdbeb63 --- /dev/null +++ b/JMMServer/Repositories/AniDB_Anime_DefaultImageRepository.cs @@ -0,0 +1,88 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Entities; +using NHibernate.Criterion; + +namespace JMMServer.Repositories +{ + public class AniDB_Anime_DefaultImageRepository + { + public void Save(AniDB_Anime_DefaultImage obj) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + session.SaveOrUpdate(obj); + transaction.Commit(); + } + } + } + + public AniDB_Anime_DefaultImage GetByID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + return session.Get(id); + } + } + + public List GetAll() + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var objs = session + .CreateCriteria(typeof(AniDB_Anime_DefaultImage)) + .List(); + + return new List(objs); ; + } + } + + public AniDB_Anime_DefaultImage GetByAnimeIDAndImagezSizeType(int animeid, int imageType) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + AniDB_Anime_DefaultImage cr = session + .CreateCriteria(typeof(AniDB_Anime_DefaultImage)) + .Add(Restrictions.Eq("AnimeID", animeid)) + .Add(Restrictions.Eq("ImageType", imageType)) + .UniqueResult(); + return cr; + } + } + + public List GetByAnimeID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var cats = session + .CreateCriteria(typeof(AniDB_Anime_DefaultImage)) + .Add(Restrictions.Eq("AnimeID", id)) + .List(); + + return new List(cats); + } + } + + public void Delete(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + AniDB_Anime_DefaultImage cr = GetByID(id); + if (cr != null) + { + session.Delete(cr); + transaction.Commit(); + } + } + } + } + } +} diff --git a/JMMServer/Repositories/AniDB_Anime_RelationRepository.cs b/JMMServer/Repositories/AniDB_Anime_RelationRepository.cs new file mode 100644 index 000000000..c8aa76b7d --- /dev/null +++ b/JMMServer/Repositories/AniDB_Anime_RelationRepository.cs @@ -0,0 +1,76 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Entities; +using NHibernate.Criterion; + +namespace JMMServer.Repositories +{ + public class AniDB_Anime_RelationRepository + { + public void Save(AniDB_Anime_Relation obj) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + session.SaveOrUpdate(obj); + transaction.Commit(); + } + } + } + + public AniDB_Anime_Relation GetByID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + return session.Get(id); + } + } + + public AniDB_Anime_Relation GetByAnimeIDAndRelationID(int animeid, int relatedanimeid) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + AniDB_Anime_Relation cr = session + .CreateCriteria(typeof(AniDB_Anime_Relation)) + .Add(Restrictions.Eq("AnimeID", animeid)) + .Add(Restrictions.Eq("RelatedAnimeID", relatedanimeid)) + .UniqueResult(); + return cr; + } + } + + public List GetByAnimeID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var cats = session + .CreateCriteria(typeof(AniDB_Anime_Relation)) + .Add(Restrictions.Eq("AnimeID", id)) + .List(); + + return new List(cats); + } + } + + public void Delete(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + AniDB_Anime_Relation cr = GetByID(id); + if (cr != null) + { + session.Delete(cr); + transaction.Commit(); + } + } + } + } + } +} diff --git a/JMMServer/Repositories/AniDB_Anime_ReviewRepository.cs b/JMMServer/Repositories/AniDB_Anime_ReviewRepository.cs new file mode 100644 index 000000000..aa5cd2452 --- /dev/null +++ b/JMMServer/Repositories/AniDB_Anime_ReviewRepository.cs @@ -0,0 +1,76 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Entities; +using NHibernate.Criterion; + +namespace JMMServer.Repositories +{ + public class AniDB_Anime_ReviewRepository + { + public void Save(AniDB_Anime_Review obj) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + session.SaveOrUpdate(obj); + transaction.Commit(); + } + } + } + + public AniDB_Anime_Review GetByID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + return session.Get(id); + } + } + + public AniDB_Anime_Review GetByAnimeIDAndReviewID(int animeid, int reviewid) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + AniDB_Anime_Review cr = session + .CreateCriteria(typeof(AniDB_Anime_Review)) + .Add(Restrictions.Eq("AnimeID", animeid)) + .Add(Restrictions.Eq("ReviewID", reviewid)) + .UniqueResult(); + return cr; + } + } + + public List GetByAnimeID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var cats = session + .CreateCriteria(typeof(AniDB_Anime_Review)) + .Add(Restrictions.Eq("AnimeID", id)) + .List(); + + return new List(cats); + } + } + + public void Delete(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + AniDB_Anime_Review cr = GetByID(id); + if (cr != null) + { + session.Delete(cr); + transaction.Commit(); + } + } + } + } + } +} diff --git a/JMMServer/Repositories/AniDB_Anime_SimilarRepository.cs b/JMMServer/Repositories/AniDB_Anime_SimilarRepository.cs new file mode 100644 index 000000000..3a6a8c03b --- /dev/null +++ b/JMMServer/Repositories/AniDB_Anime_SimilarRepository.cs @@ -0,0 +1,76 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Entities; +using NHibernate.Criterion; + +namespace JMMServer.Repositories +{ + public class AniDB_Anime_SimilarRepository + { + public void Save(AniDB_Anime_Similar obj) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + session.SaveOrUpdate(obj); + transaction.Commit(); + } + } + } + + public AniDB_Anime_Similar GetByID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + return session.Get(id); + } + } + + public AniDB_Anime_Similar GetByAnimeIDAndSimilarID(int animeid, int similaranimeid) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + AniDB_Anime_Similar cr = session + .CreateCriteria(typeof(AniDB_Anime_Similar)) + .Add(Restrictions.Eq("AnimeID", animeid)) + .Add(Restrictions.Eq("SimilarAnimeID", similaranimeid)) + .UniqueResult(); + return cr; + } + } + + public List GetByAnimeID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var cats = session + .CreateCriteria(typeof(AniDB_Anime_Similar)) + .Add(Restrictions.Eq("AnimeID", id)) + .List(); + + return new List(cats); + } + } + + public void Delete(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + AniDB_Anime_Similar cr = GetByID(id); + if (cr != null) + { + session.Delete(cr); + transaction.Commit(); + } + } + } + } + } +} diff --git a/JMMServer/Repositories/AniDB_Anime_TagRepository.cs b/JMMServer/Repositories/AniDB_Anime_TagRepository.cs new file mode 100644 index 000000000..c07789c03 --- /dev/null +++ b/JMMServer/Repositories/AniDB_Anime_TagRepository.cs @@ -0,0 +1,103 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Entities; +using NHibernate.Criterion; + +namespace JMMServer.Repositories +{ + public class AniDB_Anime_TagRepository + { + public void Save(AniDB_Anime_Tag obj) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + session.SaveOrUpdate(obj); + transaction.Commit(); + } + } + } + + public AniDB_Anime_Tag GetByID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + return session.Get(id); + } + } + + public List GetAll() + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var objs = session + .CreateCriteria(typeof(AniDB_Anime_Tag)) + .List(); + + return new List(objs); ; + } + } + + public AniDB_Anime_Tag GetByAnimeIDAndTagID(int animeid, int tagid) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + AniDB_Anime_Tag cr = session + .CreateCriteria(typeof(AniDB_Anime_Tag)) + .Add(Restrictions.Eq("AnimeID", animeid)) + .Add(Restrictions.Eq("TagID", tagid)) + .UniqueResult(); + return cr; + } + } + + public List GetByAnimeID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var tags = session + .CreateCriteria(typeof(AniDB_Anime_Tag)) + .Add(Restrictions.Eq("AnimeID", id)) + .List(); + + return new List(tags); + } + } + + /// + /// Gets all the anime tags, but only if we have the anime locally + /// + /// + public List GetAllForLocalSeries() + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var tags = session.CreateQuery("FROM AniDB_Anime_Tag tag WHERE tag.AnimeID in (Select aser.AniDB_ID From AnimeSeries aser)") + .List(); + + return new List(tags); + } + } + + public void Delete(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + AniDB_Anime_Tag cr = GetByID(id); + if (cr != null) + { + session.Delete(cr); + transaction.Commit(); + } + } + } + } + } +} diff --git a/JMMServer/Repositories/AniDB_Anime_TitleRepository.cs b/JMMServer/Repositories/AniDB_Anime_TitleRepository.cs new file mode 100644 index 000000000..60d3b559f --- /dev/null +++ b/JMMServer/Repositories/AniDB_Anime_TitleRepository.cs @@ -0,0 +1,106 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Entities; +using NHibernate.Criterion; + +namespace JMMServer.Repositories +{ + public class AniDB_Anime_TitleRepository + { + public void Save(AniDB_Anime_Title obj) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + session.SaveOrUpdate(obj); + transaction.Commit(); + } + } + } + + public AniDB_Anime_Title GetByID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + return session.Get(id); + } + } + + public List GetAll() + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var objs = session + .CreateCriteria(typeof(AniDB_Anime_Title)) + .List(); + + return new List(objs); ; + } + } + + public List GetByAnimeID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var titles = session + .CreateCriteria(typeof(AniDB_Anime_Title)) + .Add(Restrictions.Eq("AnimeID", id)) + .List(); + + return new List(titles); + } + } + + public List GetByAnimeIDLanguageTypeValue(int animeID, string language, string titleType, string titleValue) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var titles = session + .CreateCriteria(typeof(AniDB_Anime_Title)) + .Add(Restrictions.Eq("AnimeID", animeID)) + .Add(Restrictions.Eq("TitleType", titleType)) + .Add(Restrictions.Eq("Language", language)) + .Add(Restrictions.Eq("Title", titleValue)) + .List(); + + return new List(titles); + } + } + + /// + /// Gets all the anime titles, but only if we have the anime locally + /// + /// + public List GetAllForLocalSeries() + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var titles = session.CreateQuery("FROM AniDB_Anime_Title aat WHERE aat.AnimeID IN (Select aser.AniDB_ID From AnimeSeries aser)") + .List(); + + return new List(titles); + } + } + + public void Delete(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + AniDB_Anime_Title cr = GetByID(id); + if (cr != null) + { + session.Delete(cr); + transaction.Commit(); + } + } + } + } + } +} diff --git a/JMMServer/Repositories/AniDB_CategoryRepository.cs b/JMMServer/Repositories/AniDB_CategoryRepository.cs new file mode 100644 index 000000000..8e5afe549 --- /dev/null +++ b/JMMServer/Repositories/AniDB_CategoryRepository.cs @@ -0,0 +1,111 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Entities; +using NHibernate.Criterion; + +namespace JMMServer.Repositories +{ + public class AniDB_CategoryRepository + { + public void Save(AniDB_Category obj) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + session.SaveOrUpdate(obj); + transaction.Commit(); + } + } + } + + public AniDB_Category GetByID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + return session.Get(id); + } + } + + public AniDB_Category GetByCategoryID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + AniDB_Category cr = session + .CreateCriteria(typeof(AniDB_Category)) + .Add(Restrictions.Eq("CategoryID", id)) + .UniqueResult(); + return cr; + } + } + + public List GetAll() + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var objs = session + .CreateCriteria(typeof(AniDB_Category)) + .List(); + + return new List(objs); ; + } + } + + public List GetByAnimeGroupID(int animeGroupID) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + string sql = ""; + sql += " FROM AniDB_Category ac "; + sql += " WHERE ac.CategoryID in"; + sql += " ("; + sql += " SELECT aac.CategoryID "; + sql += " FROM AniDB_Anime_Category aac, AnimeSeries aser"; + sql += " WHERE aac.AnimeID = aser.AniDB_ID"; + sql += " AND aser.AnimeGroupID = :groupid"; + sql += " )"; + + var vidfiles = session.CreateQuery(sql) + .SetParameter("groupid", animeGroupID) + .List(); + + return new List(vidfiles); + } + } + + /// + /// Gets all the categories, but only if we have the anime locally + /// + /// + public List GetAllForLocalSeries() + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var animeCats = session.CreateQuery("FROM AniDB_Category ac WHERE ac.CategoryID in (SELECT aac.CategoryID FROM AniDB_Anime_Category aac, AnimeSeries aser WHERE aac.AnimeID = aser.AniDB_ID)") + .List(); + + return new List(animeCats); + } + } + + public void Delete(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + AniDB_Category cr = GetByID(id); + if (cr != null) + { + session.Delete(cr); + transaction.Commit(); + } + } + } + } + } +} diff --git a/JMMServer/Repositories/AniDB_CharacterRepository.cs b/JMMServer/Repositories/AniDB_CharacterRepository.cs new file mode 100644 index 000000000..e249617d5 --- /dev/null +++ b/JMMServer/Repositories/AniDB_CharacterRepository.cs @@ -0,0 +1,62 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Entities; +using NHibernate.Criterion; + +namespace JMMServer.Repositories +{ + public class AniDB_CharacterRepository + { + public void Save(AniDB_Character obj) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + session.SaveOrUpdate(obj); + transaction.Commit(); + } + } + } + + public AniDB_Character GetByID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + return session.Get(id); + } + } + + public AniDB_Character GetByCharID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + AniDB_Character cr = session + .CreateCriteria(typeof(AniDB_Character)) + .Add(Restrictions.Eq("CharID", id)) + .UniqueResult(); + return cr; + } + } + + public void Delete(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + AniDB_Character cr = GetByID(id); + if (cr != null) + { + session.Delete(cr); + transaction.Commit(); + } + } + } + } + } +} diff --git a/JMMServer/Repositories/AniDB_Character_CreatorRepository.cs b/JMMServer/Repositories/AniDB_Character_CreatorRepository.cs new file mode 100644 index 000000000..2c6f833b2 --- /dev/null +++ b/JMMServer/Repositories/AniDB_Character_CreatorRepository.cs @@ -0,0 +1,76 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Entities; +using NHibernate.Criterion; + +namespace JMMServer.Repositories +{ + public class AniDB_Character_CreatorRepository + { + public void Save(AniDB_Character_Creator obj) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + session.SaveOrUpdate(obj); + transaction.Commit(); + } + } + } + + public AniDB_Character_Creator GetByID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + return session.Get(id); + } + } + + public AniDB_Character_Creator GetByCharIDAndCreatorID(int animeid, int catid) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + AniDB_Character_Creator cr = session + .CreateCriteria(typeof(AniDB_Character_Creator)) + .Add(Restrictions.Eq("CharID", animeid)) + .Add(Restrictions.Eq("CreatorID", catid)) + .UniqueResult(); + return cr; + } + } + + public List GetByCharID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var objs = session + .CreateCriteria(typeof(AniDB_Character_Creator)) + .Add(Restrictions.Eq("CharID", id)) + .List(); + + return new List(objs); + } + } + + public void Delete(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + AniDB_Character_Creator cr = GetByID(id); + if (cr != null) + { + session.Delete(cr); + transaction.Commit(); + } + } + } + } + } +} diff --git a/JMMServer/Repositories/AniDB_CreatorRepository.cs b/JMMServer/Repositories/AniDB_CreatorRepository.cs new file mode 100644 index 000000000..17d19a239 --- /dev/null +++ b/JMMServer/Repositories/AniDB_CreatorRepository.cs @@ -0,0 +1,62 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Entities; +using NHibernate.Criterion; + +namespace JMMServer.Repositories +{ + public class AniDB_CreatorRepository + { + public void Save(AniDB_Creator obj) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + session.SaveOrUpdate(obj); + transaction.Commit(); + } + } + } + + public AniDB_Creator GetByID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + return session.Get(id); + } + } + + public AniDB_Creator GetByCreatorID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + AniDB_Creator cr = session + .CreateCriteria(typeof(AniDB_Creator)) + .Add(Restrictions.Eq("CreatorID", id)) + .UniqueResult(); + return cr; + } + } + + public void Delete(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + AniDB_Creator cr = GetByID(id); + if (cr != null) + { + session.Delete(cr); + transaction.Commit(); + } + } + } + } + } +} diff --git a/JMMServer/Repositories/AniDB_EpisodeRepository.cs b/JMMServer/Repositories/AniDB_EpisodeRepository.cs new file mode 100644 index 000000000..3e09c9081 --- /dev/null +++ b/JMMServer/Repositories/AniDB_EpisodeRepository.cs @@ -0,0 +1,117 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Entities; +using NHibernate.Criterion; +using AniDBAPI; + +namespace JMMServer.Repositories +{ + public class AniDB_EpisodeRepository + { + public void Save(AniDB_Episode obj) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + session.SaveOrUpdate(obj); + transaction.Commit(); + } + } + } + + public AniDB_Episode GetByID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + return session.Get(id); + } + } + + public AniDB_Episode GetByEpisodeID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + AniDB_Episode cr = session + .CreateCriteria(typeof(AniDB_Episode)) + .Add(Restrictions.Eq("EpisodeID", id)) + .UniqueResult(); + return cr; + } + } + + public List GetByAnimeID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var eps = session + .CreateCriteria(typeof(AniDB_Episode)) + .Add(Restrictions.Eq("AnimeID", id)) + .List(); + + return new List(eps); + } + } + + public List GetByAnimeIDAndEpisodeNumber(int animeid, int epnumber) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var eps = session + .CreateCriteria(typeof(AniDB_Episode)) + .Add(Restrictions.Eq("AnimeID", animeid)) + .Add(Restrictions.Eq("EpisodeNumber", epnumber)) + .Add(Restrictions.Eq("EpisodeType", (int)enEpisodeType.Episode)) + .List(); + + return new List(eps); + } + } + + public List GetByAnimeIDAndEpisodeTypeNumber(int animeid, enEpisodeType epType, int epnumber) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var eps = session + .CreateCriteria(typeof(AniDB_Episode)) + .Add(Restrictions.Eq("AnimeID", animeid)) + .Add(Restrictions.Eq("EpisodeNumber", epnumber)) + .Add(Restrictions.Eq("EpisodeType", (int)epType)) + .List(); + + return new List(eps); + } + } + + public List GetEpisodesWithMultipleFiles() + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var eps = session.CreateQuery("FROM AniDB_Episode x WHERE x.EpisodeID IN (Select xref.EpisodeID FROM CrossRef_File_Episode xref GROUP BY xref.EpisodeID HAVING COUNT(xref.EpisodeID) > 1)") + .List(); + + return new List(eps); + } + } + + public void Delete(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + AniDB_Episode cr = GetByID(id); + if (cr != null) + { + session.Delete(cr); + transaction.Commit(); + } + } + } + } + } +} diff --git a/JMMServer/Repositories/AniDB_FileRepository.cs b/JMMServer/Repositories/AniDB_FileRepository.cs new file mode 100644 index 000000000..c79833381 --- /dev/null +++ b/JMMServer/Repositories/AniDB_FileRepository.cs @@ -0,0 +1,105 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Entities; +using NHibernate.Criterion; +using NLog; + +namespace JMMServer.Repositories +{ + public class AniDB_FileRepository + { + private static Logger logger = LogManager.GetCurrentClassLogger(); + + public void Save(AniDB_File obj) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + session.SaveOrUpdate(obj); + transaction.Commit(); + } + } + + logger.Trace("Updating group stats by file from AniDB_FileRepository.Save: {0}", obj.Hash); + StatsCache.Instance.UpdateUsingAniDBFile(obj.Hash); + } + + public AniDB_File GetByID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + return session.Get(id); + } + } + + public AniDB_File GetByHash(string hash) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + AniDB_File cr = session + .CreateCriteria(typeof(AniDB_File)) + .Add(Restrictions.Eq("Hash", hash)) + .UniqueResult(); + return cr; + } + } + + public AniDB_File GetByFileID(int fileID) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + AniDB_File cr = session + .CreateCriteria(typeof(AniDB_File)) + .Add(Restrictions.Eq("FileID", fileID)) + .UniqueResult(); + return cr; + } + } + + public List GetAll() + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var objs = session + .CreateCriteria(typeof(AniDB_File)) + .List(); + + return new List(objs); + } + } + + public List GetByAnimeID(int animeID) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var objs = session + .CreateCriteria(typeof(AniDB_File)) + .Add(Restrictions.Eq("AnimeID", animeID)) + .List(); + + return new List(objs); + } + } + + public void Delete(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + AniDB_File cr = GetByID(id); + if (cr != null) + { + session.Delete(cr); + transaction.Commit(); + } + } + } + } + } +} diff --git a/JMMServer/Repositories/AniDB_GroupStatusRepository.cs b/JMMServer/Repositories/AniDB_GroupStatusRepository.cs new file mode 100644 index 000000000..a5a6090ca --- /dev/null +++ b/JMMServer/Repositories/AniDB_GroupStatusRepository.cs @@ -0,0 +1,102 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Entities; +using NHibernate.Criterion; +using NLog; + +namespace JMMServer.Repositories +{ + public class AniDB_GroupStatusRepository + { + private static Logger logger = LogManager.GetCurrentClassLogger(); + + public void Save(AniDB_GroupStatus obj) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + session.SaveOrUpdate(obj); + transaction.Commit(); + } + } + } + + public AniDB_GroupStatus GetByID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + return session.Get(id); + } + } + + public AniDB_GroupStatus GetByAnimeIDAndGroupID(int animeid, int groupid) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + AniDB_GroupStatus cr = session + .CreateCriteria(typeof(AniDB_GroupStatus)) + .Add(Restrictions.Eq("AnimeID", animeid)) + .Add(Restrictions.Eq("GroupID", groupid)) + .UniqueResult(); + return cr; + } + } + + public List GetByAnimeID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var objs = session + .CreateCriteria(typeof(AniDB_GroupStatus)) + .Add(Restrictions.Eq("AnimeID", id)) + .List(); + + return new List(objs); + } + } + + public void DeleteForAnime(int animeid) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + List grpStatuses = GetByAnimeID(animeid); + foreach (AniDB_GroupStatus grp in grpStatuses) + Delete(grp.AniDB_GroupStatusID); + + } + } + } + + public void Delete(int id) + { + int animeID = 0; + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + AniDB_GroupStatus cr = GetByID(id); + if (cr != null) + { + animeID = cr.AnimeID; + session.Delete(cr); + transaction.Commit(); + } + } + } + + if (animeID > 0) + { + logger.Trace("Updating group stats by anime from AniDB_GroupStatusRepository.Delete: {0}", animeID); + StatsCache.Instance.UpdateUsingAnime(animeID); + } + } + } +} diff --git a/JMMServer/Repositories/AniDB_ReleaseGroupRepository.cs b/JMMServer/Repositories/AniDB_ReleaseGroupRepository.cs new file mode 100644 index 000000000..88e8c7d63 --- /dev/null +++ b/JMMServer/Repositories/AniDB_ReleaseGroupRepository.cs @@ -0,0 +1,66 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Entities; +using NHibernate.Criterion; +using NLog; + +namespace JMMServer.Repositories +{ + public class AniDB_ReleaseGroupRepository + { + private static Logger logger = LogManager.GetCurrentClassLogger(); + + public void Save(AniDB_ReleaseGroup obj) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + session.SaveOrUpdate(obj); + transaction.Commit(); + } + } + } + + public AniDB_ReleaseGroup GetByID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + return session.Get(id); + } + } + + public AniDB_ReleaseGroup GetByGroupID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + AniDB_ReleaseGroup cr = session + .CreateCriteria(typeof(AniDB_ReleaseGroup)) + .Add(Restrictions.Eq("GroupID", id)) + .UniqueResult(); + return cr; + } + } + + + public void Delete(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + AniDB_ReleaseGroup cr = GetByID(id); + if (cr != null) + { + session.Delete(cr); + transaction.Commit(); + } + } + } + } + } +} diff --git a/JMMServer/Repositories/AniDB_ReviewRepository.cs b/JMMServer/Repositories/AniDB_ReviewRepository.cs new file mode 100644 index 000000000..13c9052a1 --- /dev/null +++ b/JMMServer/Repositories/AniDB_ReviewRepository.cs @@ -0,0 +1,62 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Entities; +using NHibernate.Criterion; + +namespace JMMServer.Repositories +{ + public class AniDB_ReviewRepository + { + public void Save(AniDB_Review obj) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + session.SaveOrUpdate(obj); + transaction.Commit(); + } + } + } + + public AniDB_Review GetByID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + return session.Get(id); + } + } + + public AniDB_Review GetByReviewID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + AniDB_Review cr = session + .CreateCriteria(typeof(AniDB_Review)) + .Add(Restrictions.Eq("ReviewID", id)) + .UniqueResult(); + return cr; + } + } + + public void Delete(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + AniDB_Review cr = GetByID(id); + if (cr != null) + { + session.Delete(cr); + transaction.Commit(); + } + } + } + } + } +} diff --git a/JMMServer/Repositories/AniDB_TagRepository.cs b/JMMServer/Repositories/AniDB_TagRepository.cs new file mode 100644 index 000000000..0959afc9d --- /dev/null +++ b/JMMServer/Repositories/AniDB_TagRepository.cs @@ -0,0 +1,90 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Entities; +using NHibernate.Criterion; + +namespace JMMServer.Repositories +{ + public class AniDB_TagRepository + { + public void Save(AniDB_Tag obj) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + session.SaveOrUpdate(obj); + transaction.Commit(); + } + } + } + + public AniDB_Tag GetByID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + return session.Get(id); + } + } + + public List GetAll() + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var objs = session + .CreateCriteria(typeof(AniDB_Tag)) + .List(); + + return new List(objs); ; + } + } + + public AniDB_Tag GetByTagID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + AniDB_Tag cr = session + .CreateCriteria(typeof(AniDB_Tag)) + .Add(Restrictions.Eq("TagID", id)) + .UniqueResult(); + + return cr; + } + } + + /// + /// Gets all the tags, but only if we have the anime locally + /// + /// + public List GetAllForLocalSeries() + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var tags = session.CreateQuery("FROM AniDB_Tag tag WHERE tag.TagID in (SELECT aat.TagID FROM AniDB_Anime_Tag aat, AnimeSeries aser WHERE aat.AnimeID = aser.AniDB_ID)") + .List(); + + return new List(tags); + } + } + + public void Delete(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + AniDB_Tag cr = GetByID(id); + if (cr != null) + { + session.Delete(cr); + transaction.Commit(); + } + } + } + } + } +} diff --git a/JMMServer/Repositories/AniDB_VoteRepository.cs b/JMMServer/Repositories/AniDB_VoteRepository.cs new file mode 100644 index 000000000..99e755ac5 --- /dev/null +++ b/JMMServer/Repositories/AniDB_VoteRepository.cs @@ -0,0 +1,119 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Entities; +using NHibernate.Criterion; + +namespace JMMServer.Repositories +{ + public class AniDB_VoteRepository + { + public void Save(AniDB_Vote obj) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + session.SaveOrUpdate(obj); + transaction.Commit(); + } + } + if (obj.VoteType == (int)AniDBVoteType.Anime || obj.VoteType == (int)AniDBVoteType.AnimeTemp) + StatsCache.Instance.UpdateUsingAnime(obj.EntityID); + } + + public AniDB_Vote GetByID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + return session.Get(id); + } + } + + public List GetAll() + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var objs = session + .CreateCriteria(typeof(AniDB_Vote)) + .List(); + + return new List(objs); ; + } + } + + public AniDB_Vote GetByEntityAndType(int entID, AniDBVoteType voteType) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + AniDB_Vote cr = session + .CreateCriteria(typeof(AniDB_Vote)) + .Add(Restrictions.Eq("EntityID", entID)) + .Add(Restrictions.Eq("VoteType", (int)voteType)) + .UniqueResult(); + + return cr; + } + } + + public List GetByEntity(int entID) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var votes = session + .CreateCriteria(typeof(AniDB_Vote)) + .Add(Restrictions.Eq("EntityID", entID)) + .List(); + + return new List(votes); + } + } + + public AniDB_Vote GetByAnimeID(int animeID) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var votes = session + .CreateCriteria(typeof(AniDB_Vote)) + .Add(Restrictions.Eq("EntityID", animeID)) + .List(); + + List tempList = new List(votes); + List retList = new List(); + + foreach (AniDB_Vote vt in tempList) + { + if (vt.VoteType == (int)AniDBVoteType.Anime || vt.VoteType == (int)AniDBVoteType.AnimeTemp) + return vt; + } + + return null; + } + } + + public void Delete(int id) + { + int? animeID = null; + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + AniDB_Vote cr = GetByID(id); + if (cr != null) + { + if (cr.VoteType == (int)AniDBVoteType.Anime || cr.VoteType == (int)AniDBVoteType.AnimeTemp) + animeID = cr.EntityID; + + session.Delete(cr); + transaction.Commit(); + } + } + } + if (animeID.HasValue) + StatsCache.Instance.UpdateUsingAnime(animeID.Value); + } + } +} diff --git a/JMMServer/Repositories/AnimeEpisodeRepository.cs b/JMMServer/Repositories/AnimeEpisodeRepository.cs new file mode 100644 index 000000000..f5402a7a2 --- /dev/null +++ b/JMMServer/Repositories/AnimeEpisodeRepository.cs @@ -0,0 +1,149 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Entities; +using NHibernate.Criterion; +using BinaryNorthwest; + +namespace JMMServer.Repositories +{ + public class AnimeEpisodeRepository + { + public void Save(AnimeEpisode obj) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + session.SaveOrUpdate(obj); + transaction.Commit(); + } + } + } + + public AnimeEpisode GetByID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + return session.Get(id); + } + } + + public List GetBySeriesID(int seriesid) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var eps = session + .CreateCriteria(typeof(AnimeEpisode)) + .Add(Restrictions.Eq("AnimeSeriesID", seriesid)) + .List(); + + return new List(eps); + } + } + + public AnimeEpisode GetByAniDBEpisodeID(int epid) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + AnimeEpisode obj = session + .CreateCriteria(typeof(AnimeEpisode)) + .Add(Restrictions.Eq("AniDB_EpisodeID", epid)) + .UniqueResult(); + + return obj; + } + } + + public List GetByAniEpisodeIDAndSeriesID(int epid, int seriesid) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var eps = session + .CreateCriteria(typeof(AnimeEpisode)) + .Add(Restrictions.Eq("AniDB_EpisodeID", epid)) + .Add(Restrictions.Eq("AnimeSeriesID", seriesid)) + .List(); + + return new List(eps); + } + } + + /// + /// Get all the AnimeEpisode records associate with an AniDB_File record + /// AnimeEpisode.AniDB_EpisodeID -> AniDB_Episode.EpisodeID + /// AniDB_Episode.EpisodeID -> CrossRef_File_Episode.EpisodeID + /// CrossRef_File_Episode.Hash -> VideoLocal.Hash + /// + /// + /// + public List GetByHash(string hash) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var eps = session.CreateQuery("FROM AnimeEpisode ae WHERE ae.AniDB_EpisodeID IN (Select EpisodeID FROM CrossRef_File_Episode xref WHERE xref.Hash= :Hash)") + .SetParameter("Hash", hash) + .List(); + + /*var eps = session + .CreateCriteria(typeof(AnimeEpisode)) + .Add(Restrictions.Eq("AniDB_EpisodeID", epid)) + .Add(Restrictions.Eq("AnimeSeriesID", seriesid)) + .List();*/ + + return new List(eps); + } + } + + public List GetEpisodesWithMultipleFiles() + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var eps = session.CreateQuery("FROM AnimeEpisode x WHERE x.AniDB_EpisodeID IN (Select xref.EpisodeID FROM CrossRef_File_Episode xref WHERE xref.Hash IN (Select vl.Hash from VideoLocal vl) GROUP BY xref.EpisodeID HAVING COUNT(xref.EpisodeID) > 1)") + .List(); + + return new List(eps); + } + } + + public List GetUnwatchedEpisodes(int seriesid, int userid) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var eps = session.CreateQuery("FROM AnimeEpisode x WHERE x.AnimeEpisodeID NOT IN (SELECT AnimeEpisodeID FROM AnimeEpisode_User WHERE AnimeSeriesID = :AnimeSeriesID AND JMMUserID = :JMMUserID)") + .SetParameter("AnimeSeriesID", seriesid) + .SetParameter("JMMUserID", userid) + .List(); + + return new List(eps); + } + } + + public void Delete(int id) + { + AnimeEpisode cr = GetByID(id); + if (cr != null) + { + // delete user records + AnimeEpisode_UserRepository repUsers = new AnimeEpisode_UserRepository(); + foreach (AnimeEpisode_User epuser in repUsers.GetByEpisodeID(id)) + repUsers.Delete(epuser.AnimeEpisode_UserID); + } + + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + if (cr != null) + { + session.Delete(cr); + transaction.Commit(); + } + } + } + } + } +} diff --git a/JMMServer/Repositories/AnimeEpisode_UserRepository.cs b/JMMServer/Repositories/AnimeEpisode_UserRepository.cs new file mode 100644 index 000000000..e7cc0cc30 --- /dev/null +++ b/JMMServer/Repositories/AnimeEpisode_UserRepository.cs @@ -0,0 +1,119 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Entities; +using NHibernate.Criterion; +using BinaryNorthwest; + + +namespace JMMServer.Repositories +{ + public class AnimeEpisode_UserRepository + { + public void Save(AnimeEpisode_User obj) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + session.SaveOrUpdate(obj); + transaction.Commit(); + } + } + } + + public AnimeEpisode_User GetByID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + return session.Get(id); + } + } + + public List GetBySeriesID(int seriesid) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var eps = session + .CreateCriteria(typeof(AnimeEpisode_User)) + .Add(Restrictions.Eq("AnimeSeriesID", seriesid)) + .List(); + + return new List(eps); + } + } + + public AnimeEpisode_User GetByUserIDAndEpisodeID(int userid, int epid) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + AnimeEpisode_User obj = session + .CreateCriteria(typeof(AnimeEpisode_User)) + .Add(Restrictions.Eq("JMMUserID", userid)) + .Add(Restrictions.Eq("AnimeEpisodeID", epid)) + .UniqueResult(); + + return obj; + } + } + + public List GetByUserID(int userid) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var eps = session + .CreateCriteria(typeof(AnimeEpisode_User)) + .Add(Restrictions.Eq("JMMUserID", userid)) + .List(); + + return new List(eps); + } + } + + public List GetByEpisodeID(int epid) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var eps = session + .CreateCriteria(typeof(AnimeEpisode_User)) + .Add(Restrictions.Eq("AnimeEpisodeID", epid)) + .List(); + + return new List(eps); + } + } + + public List GetByUserIDAndSeriesID(int userid, int seriesid) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var eps = session + .CreateCriteria(typeof(AnimeEpisode_User)) + .Add(Restrictions.Eq("JMMUserID", userid)) + .Add(Restrictions.Eq("AnimeSeriesID", seriesid)) + .List(); + + return new List(eps); + } + } + + public void Delete(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + AnimeEpisode_User cr = GetByID(id); + if (cr != null) + { + session.Delete(cr); + transaction.Commit(); + } + } + } + } + } +} diff --git a/JMMServer/Repositories/AnimeGroupRepository.cs b/JMMServer/Repositories/AnimeGroupRepository.cs new file mode 100644 index 000000000..ff9386f0b --- /dev/null +++ b/JMMServer/Repositories/AnimeGroupRepository.cs @@ -0,0 +1,111 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Entities; +using NHibernate.Criterion; +using NLog; + +namespace JMMServer.Repositories +{ + public class AnimeGroupRepository + { + private static Logger logger = LogManager.GetCurrentClassLogger(); + + public void Save(AnimeGroup obj) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + session.SaveOrUpdate(obj); + transaction.Commit(); + } + } + logger.Trace("Updating group stats by group from AnimeGroupRepository.Save: {0}", obj.AnimeGroupID); + StatsCache.Instance.UpdateUsingGroup(obj.AnimeGroupID); + } + + public AnimeGroup GetByID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + return session.Get(id); + } + } + + public List GetByParentID(int parentid) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var grps = session + .CreateCriteria(typeof(AnimeGroup)) + .Add(Restrictions.Eq("AnimeGroupParentID", parentid)) + .List(); + + return new List(grps); + } + } + + public List GetAll() + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var grps = session + .CreateCriteria(typeof(AnimeGroup)) + .List(); + + return new List(grps); + } + } + + public List GetAllTopLevelGroups() + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var grps = session + .CreateCriteria(typeof(AnimeGroup)) + //.Add(Restrictions.Eq("AnimeGroupParentID", "null")) + //.Add(Restrictions.IsEmpty("OrgUnits")) + .Add(Restrictions.IsNull("AnimeGroupParentID")) + .List(); + + return new List(grps); + } + } + + public void Delete(int id) + { + AnimeGroup cr = GetByID(id); + if (cr != null) + { + // delete user records + AnimeGroup_UserRepository repUsers = new AnimeGroup_UserRepository(); + foreach (AnimeGroup_User grpUser in repUsers.GetByGroupID(id)) + repUsers.Delete(grpUser.AnimeGroup_UserID); + } + + int parentID = 0; + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + if (cr != null) + { + if (cr.AnimeGroupParentID.HasValue) parentID = cr.AnimeGroupParentID.Value; + session.Delete(cr); + transaction.Commit(); + } + } + } + + if (parentID > 0) + { + logger.Trace("Updating group stats by group from AnimeGroupRepository.Delete: {0}", parentID); + StatsCache.Instance.UpdateUsingGroup(parentID); + } + } + } +} diff --git a/JMMServer/Repositories/AnimeGroup_UserRepository.cs b/JMMServer/Repositories/AnimeGroup_UserRepository.cs new file mode 100644 index 000000000..6372ac4e9 --- /dev/null +++ b/JMMServer/Repositories/AnimeGroup_UserRepository.cs @@ -0,0 +1,113 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Entities; +using NHibernate.Criterion; +using NLog; + +namespace JMMServer.Repositories +{ + public class AnimeGroup_UserRepository + { + private static Logger logger = LogManager.GetCurrentClassLogger(); + + public void Save(AnimeGroup_User obj) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + session.SaveOrUpdate(obj); + transaction.Commit(); + } + } + //logger.Trace("Updating group stats by group from AnimeGroup_UserRepository.Save: {0}", obj.AnimeGroupID); + //StatsCache.Instance.UpdateUsingGroup(obj.AnimeGroupID); + } + + public AnimeGroup_User GetByID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + return session.Get(id); + } + } + + public AnimeGroup_User GetByUserAndGroupID(int userid, int groupid) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + AnimeGroup_User cr = session + .CreateCriteria(typeof(AnimeGroup_User)) + .Add(Restrictions.Eq("JMMUserID", userid)) + .Add(Restrictions.Eq("AnimeGroupID", groupid)) + .UniqueResult(); + return cr; + } + } + + public List GetByUserID(int userid) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var grps = session + .CreateCriteria(typeof(AnimeGroup_User)) + .Add(Restrictions.Eq("JMMUserID", userid)) + .List(); + + return new List(grps); + } + } + + public List GetByGroupID(int groupid) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var grps = session + .CreateCriteria(typeof(AnimeGroup_User)) + .Add(Restrictions.Eq("AnimeGroupID", groupid)) + .List(); + + return new List(grps); + } + } + + public List GetAll() + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var grps = session + .CreateCriteria(typeof(AnimeGroup_User)) + .List(); + + return new List(grps); + } + } + + public void Delete(int id) + { + AnimeGroup_User cr = null; + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + cr = GetByID(id); + if (cr != null) + { + session.Delete(cr); + transaction.Commit(); + } + } + } + + //if (cr != null) + //{ + // logger.Trace("Updating group stats by group from AnimeGroupRepository.Delete: {0}", cr.AnimeGroupID); + // StatsCache.Instance.UpdateUsingGroup(cr.AnimeGroupID); + //} + } + } +} diff --git a/JMMServer/Repositories/AnimeSeriesRepository.cs b/JMMServer/Repositories/AnimeSeriesRepository.cs new file mode 100644 index 000000000..e2eb3255c --- /dev/null +++ b/JMMServer/Repositories/AnimeSeriesRepository.cs @@ -0,0 +1,146 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Entities; +using NHibernate.Criterion; +using NLog; + +namespace JMMServer.Repositories +{ + public class AnimeSeriesRepository + { + private static Logger logger = LogManager.GetCurrentClassLogger(); + + public void Save(AnimeSeries obj) + { + bool updateStatsCache = false; + AnimeGroup oldGroup = null; + if (obj.AnimeSeriesID == 0) updateStatsCache = true; // a new series + else + { + // get the old version from the DB + AnimeSeries oldSeries = GetByID(obj.AnimeSeriesID); + if (oldSeries != null) + { + // means we are moving series to a different group + if (oldSeries.AnimeGroupID != obj.AnimeGroupID) + { + AnimeGroupRepository repGroups = new AnimeGroupRepository(); + oldGroup = repGroups.GetByID(oldSeries.AnimeGroupID); + updateStatsCache = true; + } + } + } + + + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + session.SaveOrUpdate(obj); + transaction.Commit(); + } + } + + if (updateStatsCache) + { + logger.Trace("Updating group stats by series from AnimeSeriesRepository.Save: {0}", obj.AnimeSeriesID); + StatsCache.Instance.UpdateUsingSeries(obj.AnimeSeriesID); + } + + if (oldGroup != null) + { + logger.Trace("Updating group stats by group from AnimeSeriesRepository.Save: {0}", oldGroup.AnimeGroupID); + StatsCache.Instance.UpdateUsingGroup(oldGroup.AnimeGroupID); + } + } + + public AnimeSeries GetByID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + return session.Get(id); + } + } + + public AnimeSeries GetByAnimeID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + AnimeSeries cr = session + .CreateCriteria(typeof(AnimeSeries)) + .Add(Restrictions.Eq("AniDB_ID", id)) + .UniqueResult(); + return cr; + } + } + + public List GetAll() + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var series = session + .CreateCriteria(typeof(AnimeSeries)) + .List(); + + return new List(series); + } + } + + public List GetByGroupID(int groupid) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var series = session + .CreateCriteria(typeof(AnimeSeries)) + .Add(Restrictions.Eq("AnimeGroupID", groupid)) + .List(); + + return new List(series); + } + } + + + + public List GetWithMissingEpisodes() + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var series = session + .CreateCriteria(typeof(AnimeSeries)) + .Add(Restrictions.Gt("MissingEpisodeCountGroups", 0)) + .AddOrder(Order.Desc("EpisodeAddedDate")) + .List(); + + return new List(series); + } + } + + public void Delete(int id) + { + int oldGroupID = 0; + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + AnimeSeries cr = GetByID(id); + if (cr != null) + { + oldGroupID = cr.AnimeGroupID; + session.Delete(cr); + transaction.Commit(); + } + } + } + + if (oldGroupID > 0) + { + logger.Trace("Updating group stats by group from AnimeSeriesRepository.Delete: {0}", oldGroupID); + StatsCache.Instance.UpdateUsingGroup(oldGroupID); + } + } + } +} diff --git a/JMMServer/Repositories/AnimeSeries_UserRepository.cs b/JMMServer/Repositories/AnimeSeries_UserRepository.cs new file mode 100644 index 000000000..e0fea037d --- /dev/null +++ b/JMMServer/Repositories/AnimeSeries_UserRepository.cs @@ -0,0 +1,129 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Entities; +using NHibernate.Criterion; +using NLog; + +namespace JMMServer.Repositories +{ + public class AnimeSeries_UserRepository + { + private static Logger logger = LogManager.GetCurrentClassLogger(); + + public void Save(AnimeSeries_User obj) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + session.SaveOrUpdate(obj); + transaction.Commit(); + } + } + + //logger.Trace("Updating group stats by series from AnimeSeries_UserRepository.Save: {0}", obj.AnimeSeriesID); + //StatsCache.Instance.UpdateUsingSeries(obj.AnimeSeriesID); + } + + public AnimeSeries_User GetByID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + return session.Get(id); + } + } + + public AnimeSeries_User GetByUserAndSeriesID(int userid, int seriesid) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + AnimeSeries_User cr = session + .CreateCriteria(typeof(AnimeSeries_User)) + .Add(Restrictions.Eq("JMMUserID", userid)) + .Add(Restrictions.Eq("AnimeSeriesID", seriesid)) + .UniqueResult(); + return cr; + } + } + + public List GetByUserID(int userid) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var sers = session + .CreateCriteria(typeof(AnimeSeries_User)) + .Add(Restrictions.Eq("JMMUserID", userid)) + .List(); + + return new List(sers); + } + } + + public List GetBySeriesID(int seriesid) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var sers = session + .CreateCriteria(typeof(AnimeSeries_User)) + .Add(Restrictions.Eq("AnimeSeriesID", seriesid)) + .List(); + + return new List(sers); + } + } + + public List GetAll() + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var grps = session + .CreateCriteria(typeof(AnimeSeries_User)) + .List(); + + return new List(grps); + } + } + + public List GetMostRecentlyWatched(int userID) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var series = session + .CreateCriteria(typeof(AnimeSeries_User)) + .Add(Restrictions.Eq("JMMUserID", userID)) + .Add(Restrictions.Gt("UnwatchedEpisodeCount", 0)) + .AddOrder(Order.Desc("WatchedDate")) + .List(); + + return new List(series); + } + } + + public void Delete(int id) + { + AnimeSeries_User cr = null; + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + cr = GetByID(id); + if (cr != null) + { + session.Delete(cr); + transaction.Commit(); + } + } + } + + //if (cr != null) + //{ + // logger.Trace("Updating group stats by series from AnimeSeries_UserRepository.Delete: {0}", cr.AnimeSeriesID); + // StatsCache.Instance.UpdateUsingSeries(cr.AnimeSeriesID); + //} + } + } +} diff --git a/JMMServer/Repositories/CommandRequestRepository.cs b/JMMServer/Repositories/CommandRequestRepository.cs new file mode 100644 index 000000000..b476dd0c0 --- /dev/null +++ b/JMMServer/Repositories/CommandRequestRepository.cs @@ -0,0 +1,166 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using NHibernate.Criterion; +using JMMServer; +using JMMServer.Entities; + +namespace JMMServer.Repositories +{ + public class CommandRequestRepository + { + public void Save(CommandRequest obj) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + session.SaveOrUpdate(obj); + transaction.Commit(); + } + } + } + + public CommandRequest GetByID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + return session.Get(id); + /*CommandRequest cr = session + .CreateCriteria(typeof(CommandRequest)) + .Add(Restrictions.Eq("CommandRequestID", id)) + .UniqueResult(); + return cr;*/ + } + } + + public CommandRequest GetByCommandID(string cmdid) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + CommandRequest cr = session + .CreateCriteria(typeof(CommandRequest)) + .Add(Restrictions.Eq("CommandID", cmdid)) + .UniqueResult(); + return cr; + } + } + + public void Delete(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + CommandRequest cr = GetByID(id); + if (cr != null) + { + session.Delete(cr); + transaction.Commit(); + } + } + } + } + + public CommandRequest GetNextDBCommandRequestGeneral() + { + /*SELECT TOP 1 CommandRequestID + FROM CommandRequest + ORDER BY Priority ASC, DateTimeUpdated ASC*/ + using (var session = JMMService.SessionFactory.OpenSession()) + { + IList crs = session + .CreateCriteria(typeof(CommandRequest)) + .Add(!Restrictions.Eq("CommandType", (int)CommandRequestType.HashFile)) + .Add(!Restrictions.Eq("CommandType", (int)CommandRequestType.ImageDownload)) + .AddOrder(Order.Asc("Priority")) + .AddOrder(Order.Asc("DateTimeUpdated")) + .SetMaxResults(1) + .List(); + + if (crs.Count > 0) return crs[0]; + + return null; + } + } + + public CommandRequest GetNextDBCommandRequestHasher() + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + IList crs = session + .CreateCriteria(typeof(CommandRequest)) + .Add(Restrictions.Eq("CommandType", (int)CommandRequestType.HashFile)) + .AddOrder(Order.Asc("Priority")) + .AddOrder(Order.Asc("DateTimeUpdated")) + .SetMaxResults(1) + .List(); + + if (crs.Count > 0) return crs[0]; + + return null; + } + } + + public CommandRequest GetNextDBCommandRequestImages() + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + IList crs = session + .CreateCriteria(typeof(CommandRequest)) + .Add(Restrictions.Eq("CommandType", (int)CommandRequestType.ImageDownload)) + .AddOrder(Order.Asc("Priority")) + .AddOrder(Order.Asc("DateTimeUpdated")) + .SetMaxResults(1) + .List(); + + if (crs.Count > 0) return crs[0]; + + return null; + } + } + + public int GetQueuedCommandCountGeneral() + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var cnt = session + .CreateCriteria(typeof(CommandRequest)) + .Add(!Restrictions.Eq("CommandType", (int)CommandRequestType.HashFile)) + .Add(!Restrictions.Eq("CommandType", (int)CommandRequestType.ImageDownload)) + .SetProjection(Projections.Count("CommandRequestID")).UniqueResult(); + + return (int)cnt; + } + } + + public int GetQueuedCommandCountHasher() + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var cnt = session + .CreateCriteria(typeof(CommandRequest)) + .Add(Restrictions.Eq("CommandType", (int)CommandRequestType.HashFile)) + .SetProjection(Projections.Count("CommandRequestID")).UniqueResult(); + + return (int)cnt; + } + } + + public int GetQueuedCommandCountImages() + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var cnt = session + .CreateCriteria(typeof(CommandRequest)) + .Add(Restrictions.Eq("CommandType", (int)CommandRequestType.ImageDownload)) + .SetProjection(Projections.Count("CommandRequestID")).UniqueResult(); + + return (int)cnt; + } + } + } +} diff --git a/JMMServer/Repositories/CrossRef_AniDB_OtherRepository.cs b/JMMServer/Repositories/CrossRef_AniDB_OtherRepository.cs new file mode 100644 index 000000000..67d3e04a7 --- /dev/null +++ b/JMMServer/Repositories/CrossRef_AniDB_OtherRepository.cs @@ -0,0 +1,101 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Entities; +using NHibernate.Criterion; + +namespace JMMServer.Repositories +{ + public class CrossRef_AniDB_OtherRepository + { + public void Save(CrossRef_AniDB_Other obj) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + session.SaveOrUpdate(obj); + transaction.Commit(); + } + } + } + + public CrossRef_AniDB_Other GetByID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + return session.Get(id); + } + } + + public CrossRef_AniDB_Other GetByAnimeIDAndType(int animeID, CrossRefType xrefType) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + CrossRef_AniDB_Other cr = session + .CreateCriteria(typeof(CrossRef_AniDB_Other)) + .Add(Restrictions.Eq("AnimeID", animeID)) + .Add(Restrictions.Eq("CrossRefType", (int)xrefType)) + .UniqueResult(); + return cr; + } + } + + public List GetByType(CrossRefType xrefType) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var xrefs = session + .CreateCriteria(typeof(CrossRef_AniDB_Other)) + .Add(Restrictions.Eq("CrossRefType", (int)xrefType)) + .List(); + + return new List(xrefs); + } + } + + public List GetByAnimeID(int animeID) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var xrefs = session + .CreateCriteria(typeof(CrossRef_AniDB_Other)) + .Add(Restrictions.Eq("AnimeID", animeID)) + .List(); + + return new List(xrefs); + } + } + + public List GetAll() + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var series = session + .CreateCriteria(typeof(CrossRef_AniDB_Other)) + .List(); + + return new List(series); + } + } + + public void Delete(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + CrossRef_AniDB_Other cr = GetByID(id); + if (cr != null) + { + session.Delete(cr); + transaction.Commit(); + } + } + } + } + } +} diff --git a/JMMServer/Repositories/CrossRef_AniDB_TraktRepository.cs b/JMMServer/Repositories/CrossRef_AniDB_TraktRepository.cs new file mode 100644 index 000000000..002173853 --- /dev/null +++ b/JMMServer/Repositories/CrossRef_AniDB_TraktRepository.cs @@ -0,0 +1,74 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Entities; +using NHibernate.Criterion; + +namespace JMMServer.Repositories +{ + public class CrossRef_AniDB_TraktRepository + { + public void Save(CrossRef_AniDB_Trakt obj) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + session.SaveOrUpdate(obj); + transaction.Commit(); + } + } + } + + public CrossRef_AniDB_Trakt GetByID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + return session.Get(id); + } + } + + public CrossRef_AniDB_Trakt GetByAnimeID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + CrossRef_AniDB_Trakt cr = session + .CreateCriteria(typeof(CrossRef_AniDB_Trakt)) + .Add(Restrictions.Eq("AnimeID", id)) + .UniqueResult(); + return cr; + } + } + + public List GetAll() + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var series = session + .CreateCriteria(typeof(CrossRef_AniDB_Trakt)) + .List(); + + return new List(series); + } + } + + public void Delete(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + CrossRef_AniDB_Trakt cr = GetByID(id); + if (cr != null) + { + session.Delete(cr); + transaction.Commit(); + } + } + } + } + } +} diff --git a/JMMServer/Repositories/CrossRef_AniDB_TvDBRepository.cs b/JMMServer/Repositories/CrossRef_AniDB_TvDBRepository.cs new file mode 100644 index 000000000..3ecc6b77f --- /dev/null +++ b/JMMServer/Repositories/CrossRef_AniDB_TvDBRepository.cs @@ -0,0 +1,74 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Entities; +using NHibernate.Criterion; + +namespace JMMServer.Repositories +{ + public class CrossRef_AniDB_TvDBRepository + { + public void Save(CrossRef_AniDB_TvDB obj) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + session.SaveOrUpdate(obj); + transaction.Commit(); + } + } + } + + public CrossRef_AniDB_TvDB GetByID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + return session.Get(id); + } + } + + public CrossRef_AniDB_TvDB GetByAnimeID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + CrossRef_AniDB_TvDB cr = session + .CreateCriteria(typeof(CrossRef_AniDB_TvDB)) + .Add(Restrictions.Eq("AnimeID", id)) + .UniqueResult(); + return cr; + } + } + + public List GetAll() + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var series = session + .CreateCriteria(typeof(CrossRef_AniDB_TvDB)) + .List(); + + return new List(series); + } + } + + public void Delete(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + CrossRef_AniDB_TvDB cr = GetByID(id); + if (cr != null) + { + session.Delete(cr); + transaction.Commit(); + } + } + } + } + } +} diff --git a/JMMServer/Repositories/CrossRef_File_EpisodeRepository.cs b/JMMServer/Repositories/CrossRef_File_EpisodeRepository.cs new file mode 100644 index 000000000..3673673c3 --- /dev/null +++ b/JMMServer/Repositories/CrossRef_File_EpisodeRepository.cs @@ -0,0 +1,137 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Entities; +using NHibernate.Criterion; +using NLog; + +namespace JMMServer.Repositories +{ + public class CrossRef_File_EpisodeRepository + { + private static Logger logger = LogManager.GetCurrentClassLogger(); + + public void Save(CrossRef_File_Episode obj) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + session.SaveOrUpdate(obj); + transaction.Commit(); + } + } + logger.Trace("Updating group stats by file from CrossRef_File_EpisodeRepository.Save: {0}", obj.Hash); + StatsCache.Instance.UpdateUsingAniDBFile(obj.Hash); + } + + public CrossRef_File_Episode GetByID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + return session.Get(id); + } + } + + public List GetByHash(string hash) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var xrefs = session + .CreateCriteria(typeof(CrossRef_File_Episode)) + .Add(Restrictions.Eq("Hash", hash)) + .AddOrder(Order.Asc("EpisodeOrder")) + .List(); + + return new List(xrefs); + } + } + + public List GetByAnimeID(int animeID) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var xrefs = session + .CreateCriteria(typeof(CrossRef_File_Episode)) + .Add(Restrictions.Eq("AnimeID", animeID)) + .List(); + + return new List(xrefs); + } + } + + public List GetByFileNameAndSize(string filename, long filesize) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var vidfiles = session + .CreateCriteria(typeof(CrossRef_File_Episode)) + .Add(Restrictions.Eq("FileName", filename)) + .Add(Restrictions.Eq("FileSize", filesize)) + .List(); + + return new List(vidfiles); + } + } + + /// + /// This is the only way to uniquely identify the record other than the IDENTITY + /// + /// + /// + /// + public CrossRef_File_Episode GetByHashAndEpisodeID(string hash, int episodeID) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + CrossRef_File_Episode obj = session + .CreateCriteria(typeof(CrossRef_File_Episode)) + .Add(Restrictions.Eq("Hash", hash)) + .Add(Restrictions.Eq("EpisodeID", episodeID)) + .UniqueResult(); + + return obj; + } + } + + public List GetByEpisodeID(int episodeID) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var xrefs = session + .CreateCriteria(typeof(CrossRef_File_Episode)) + .Add(Restrictions.Eq("EpisodeID", episodeID)) + .List(); + + return new List(xrefs); + } + } + + public void Delete(int id) + { + int animeID = 0; + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + CrossRef_File_Episode cr = GetByID(id); + if (cr != null) + { + animeID = cr.AnimeID; + session.Delete(cr); + transaction.Commit(); + } + } + } + + if (animeID > 0) + { + logger.Trace("Updating group stats by anime from CrossRef_File_EpisodeRepository.Delete: {0}", animeID); + StatsCache.Instance.UpdateUsingAnime(animeID); + } + } + } +} diff --git a/JMMServer/Repositories/CrossRef_Languages_AniDB_FileRepository.cs b/JMMServer/Repositories/CrossRef_Languages_AniDB_FileRepository.cs new file mode 100644 index 000000000..f56216442 --- /dev/null +++ b/JMMServer/Repositories/CrossRef_Languages_AniDB_FileRepository.cs @@ -0,0 +1,63 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Entities; +using NHibernate.Criterion; + +namespace JMMServer.Repositories +{ + public class CrossRef_Languages_AniDB_FileRepository + { + public void Save(CrossRef_Languages_AniDB_File obj) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + session.SaveOrUpdate(obj); + transaction.Commit(); + } + } + } + + public CrossRef_Languages_AniDB_File GetByID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + return session.Get(id); + } + } + + public List GetByFileID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var files = session + .CreateCriteria(typeof(CrossRef_Languages_AniDB_File)) + .Add(Restrictions.Eq("FileID", id)) + .List(); + + return new List(files); + } + } + + public void Delete(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + CrossRef_Languages_AniDB_File cr = GetByID(id); + if (cr != null) + { + session.Delete(cr); + transaction.Commit(); + } + } + } + } + } +} diff --git a/JMMServer/Repositories/CrossRef_Subtitles_AniDB_FileRepository.cs b/JMMServer/Repositories/CrossRef_Subtitles_AniDB_FileRepository.cs new file mode 100644 index 000000000..20cd488d3 --- /dev/null +++ b/JMMServer/Repositories/CrossRef_Subtitles_AniDB_FileRepository.cs @@ -0,0 +1,63 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Entities; +using NHibernate.Criterion; + +namespace JMMServer.Repositories +{ + public class CrossRef_Subtitles_AniDB_FileRepository + { + public void Save(CrossRef_Subtitles_AniDB_File obj) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + session.SaveOrUpdate(obj); + transaction.Commit(); + } + } + } + + public CrossRef_Subtitles_AniDB_File GetByID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + return session.Get(id); + } + } + + public List GetByFileID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var files = session + .CreateCriteria(typeof(CrossRef_Subtitles_AniDB_File)) + .Add(Restrictions.Eq("FileID", id)) + .List(); + + return new List(files); + } + } + + public void Delete(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + CrossRef_Subtitles_AniDB_File cr = GetByID(id); + if (cr != null) + { + session.Delete(cr); + transaction.Commit(); + } + } + } + } + } +} diff --git a/JMMServer/Repositories/DuplicateFileRepository.cs b/JMMServer/Repositories/DuplicateFileRepository.cs new file mode 100644 index 000000000..3e7827fe4 --- /dev/null +++ b/JMMServer/Repositories/DuplicateFileRepository.cs @@ -0,0 +1,79 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Entities; +using NHibernate.Criterion; + +namespace JMMServer.Repositories +{ + public class DuplicateFileRepository + { + public void Save(DuplicateFile obj) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + session.SaveOrUpdate(obj); + transaction.Commit(); + } + } + } + + public DuplicateFile GetByID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + return session.Get(id); + } + } + + public List GetByFilePathsAndImportFolder(string filePath1, string filePath2, int folderID1, int folderID2) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var dfiles = session + .CreateCriteria(typeof(DuplicateFile)) + .Add(Restrictions.Eq("FilePathFile1", filePath1)) + .Add(Restrictions.Eq("FilePathFile2", filePath2)) + .Add(Restrictions.Eq("ImportFolderIDFile1", folderID1)) + .Add(Restrictions.Eq("ImportFolderIDFile2", folderID2)) + .List(); + return new List(dfiles); + } + } + + + public List GetAll() + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var objs = session + .CreateCriteria(typeof(DuplicateFile)) + .List(); + + return new List(objs); + } + } + + + public void Delete(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + DuplicateFile cr = GetByID(id); + if (cr != null) + { + session.Delete(cr); + transaction.Commit(); + } + } + } + } + } +} diff --git a/JMMServer/Repositories/FileNameHashRepository.cs b/JMMServer/Repositories/FileNameHashRepository.cs new file mode 100644 index 000000000..18f7e1bb6 --- /dev/null +++ b/JMMServer/Repositories/FileNameHashRepository.cs @@ -0,0 +1,92 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Entities; +using NHibernate.Criterion; + +namespace JMMServer.Repositories +{ + public class FileNameHashRepository + { + public void Save(FileNameHash obj) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + session.SaveOrUpdate(obj); + transaction.Commit(); + } + } + } + + public FileNameHash GetByID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + return session.Get(id); + } + } + + public List GetByHash(string hash) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var xrefs = session + .CreateCriteria(typeof(FileNameHash)) + .Add(Restrictions.Eq("Hash", hash)) + .List(); + + return new List(xrefs); + } + } + + public List GetByFileNameAndSize(string filename, long filesize) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var fnhashes = session + .CreateCriteria(typeof(FileNameHash)) + .Add(Restrictions.Eq("FileName", filename)) + .Add(Restrictions.Eq("FileSize", filesize)) + .List(); + + return new List(fnhashes); + } + } + + public FileNameHash GetByNameSizeAndHash(string filename, long filesize, string hash) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + FileNameHash fnhash = session + .CreateCriteria(typeof(FileNameHash)) + .Add(Restrictions.Eq("Hash", hash)) + .Add(Restrictions.Eq("FileName", filename)) + .Add(Restrictions.Eq("FileSize", filesize)) + .UniqueResult(); + + return fnhash; + } + } + + public void Delete(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + FileNameHash cr = GetByID(id); + if (cr != null) + { + session.Delete(cr); + transaction.Commit(); + } + } + } + } + } +} diff --git a/JMMServer/Repositories/GroupFilterConditionRepository.cs b/JMMServer/Repositories/GroupFilterConditionRepository.cs new file mode 100644 index 000000000..3c639f318 --- /dev/null +++ b/JMMServer/Repositories/GroupFilterConditionRepository.cs @@ -0,0 +1,87 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Entities; +using NHibernate.Criterion; + +namespace JMMServer.Repositories +{ + public class GroupFilterConditionRepository + { + public void Save(GroupFilterCondition obj) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + session.SaveOrUpdate(obj); + transaction.Commit(); + } + } + } + + public GroupFilterCondition GetByID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + return session.Get(id); + } + } + + public List GetByGroupFilterID(int gfid) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var gfcs = session + .CreateCriteria(typeof(GroupFilterCondition)) + .Add(Restrictions.Eq("GroupFilterID", gfid)) + .List(); + + return new List(gfcs); + } + } + + public List GetByConditionType(GroupFilterConditionType ctype) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var gfcs = session + .CreateCriteria(typeof(GroupFilterCondition)) + .Add(Restrictions.Eq("ConditionType", (int)ctype)) + .List(); + + return new List(gfcs); + } + } + + public List GetAll() + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var gfcs = session + .CreateCriteria(typeof(GroupFilterCondition)) + .List(); + return new List(gfcs); + } + } + + public void Delete(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + GroupFilterCondition cr = GetByID(id); + if (cr != null) + { + session.Delete(cr); + transaction.Commit(); + } + } + } + } + } +} diff --git a/JMMServer/Repositories/GroupFilterRepository.cs b/JMMServer/Repositories/GroupFilterRepository.cs new file mode 100644 index 000000000..876d2f194 --- /dev/null +++ b/JMMServer/Repositories/GroupFilterRepository.cs @@ -0,0 +1,61 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Entities; +using NHibernate.Criterion; + +namespace JMMServer.Repositories +{ + public class GroupFilterRepository + { + public void Save(GroupFilter obj) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + session.SaveOrUpdate(obj); + transaction.Commit(); + } + } + } + + public GroupFilter GetByID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + return session.Get(id); + } + } + + public List GetAll() + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var gfs = session + .CreateCriteria(typeof(GroupFilter)) + .List(); + return new List(gfs); + } + } + + public void Delete(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + GroupFilter cr = GetByID(id); + if (cr != null) + { + session.Delete(cr); + transaction.Commit(); + } + } + } + } + } +} diff --git a/JMMServer/Repositories/ImportFolderRepository.cs b/JMMServer/Repositories/ImportFolderRepository.cs new file mode 100644 index 000000000..8dbbbcaa4 --- /dev/null +++ b/JMMServer/Repositories/ImportFolderRepository.cs @@ -0,0 +1,73 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Entities; +using NHibernate.Criterion; + +namespace JMMServer.Repositories +{ + public class ImportFolderRepository + { + public void Save(ImportFolder obj) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + session.SaveOrUpdate(obj); + transaction.Commit(); + } + } + } + + public ImportFolder GetByID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + return session.Get(id); + } + } + + public ImportFolder GetByImportLocation(string importloc) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + ImportFolder cr = session + .CreateCriteria(typeof(ImportFolder)) + .Add(Restrictions.Eq("ImportFolderLocation", importloc)) + .UniqueResult(); + return cr; + } + } + + public List GetAll() + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var importFolders = session + .CreateCriteria(typeof(ImportFolder)) + .List(); + return new List(importFolders); + } + } + + public void Delete(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + ImportFolder cr = GetByID(id); + if (cr != null) + { + session.Delete(cr); + transaction.Commit(); + } + } + } + } + } +} diff --git a/JMMServer/Repositories/JMMUserRepository.cs b/JMMServer/Repositories/JMMUserRepository.cs new file mode 100644 index 000000000..c1121c5a6 --- /dev/null +++ b/JMMServer/Repositories/JMMUserRepository.cs @@ -0,0 +1,106 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Entities; +using NHibernate.Criterion; +using NLog; + +namespace JMMServer.Repositories +{ + public class JMMUserRepository + { + private static Logger logger = LogManager.GetCurrentClassLogger(); + + public void Save(JMMUser obj) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + session.SaveOrUpdate(obj); + transaction.Commit(); + } + } + } + + public JMMUser GetByID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + return session.Get(id); + } + } + + public List GetAll() + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var objs = session + .CreateCriteria(typeof(JMMUser)) + .List(); + + return new List(objs); + } + } + + public List GetAniDBUsers() + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var objs = session + .CreateCriteria(typeof(JMMUser)) + .Add(Restrictions.Eq("IsAniDBUser", 1)) + .List(); + + return new List(objs); + } + } + + public List GetTraktUsers() + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var objs = session + .CreateCriteria(typeof(JMMUser)) + .Add(Restrictions.Eq("IsTraktUser", 1)) + .List(); + + return new List(objs); + } + } + + public JMMUser AuthenticateUser(string userName, string password) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + JMMUser cr = session + .CreateCriteria(typeof(JMMUser)) + .Add(Restrictions.Eq("Username", userName)) + .Add(Restrictions.Eq("Password", password)) + .UniqueResult(); + return cr; + } + } + + + + public void Delete(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + JMMUser cr = GetByID(id); + if (cr != null) + { + session.Delete(cr); + transaction.Commit(); + } + } + } + } + } +} diff --git a/JMMServer/Repositories/LanguageRepository.cs b/JMMServer/Repositories/LanguageRepository.cs new file mode 100644 index 000000000..8a275753c --- /dev/null +++ b/JMMServer/Repositories/LanguageRepository.cs @@ -0,0 +1,62 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Entities; +using NHibernate.Criterion; + +namespace JMMServer.Repositories +{ + public class LanguageRepository + { + public void Save(Language obj) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + session.SaveOrUpdate(obj); + transaction.Commit(); + } + } + } + + public Language GetByID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + return session.Get(id); + } + } + + public Language GetByLanguageName(string lanname) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + Language cr = session + .CreateCriteria(typeof(Language)) + .Add(Restrictions.Eq("LanguageName", lanname)) + .UniqueResult(); + return cr; + } + } + + public void Delete(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + Language cr = GetByID(id); + if (cr != null) + { + session.Delete(cr); + transaction.Commit(); + } + } + } + } + } +} diff --git a/JMMServer/Repositories/MovieDB_FanartRepository.cs b/JMMServer/Repositories/MovieDB_FanartRepository.cs new file mode 100644 index 000000000..f981c73c5 --- /dev/null +++ b/JMMServer/Repositories/MovieDB_FanartRepository.cs @@ -0,0 +1,101 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Entities; +using NHibernate.Criterion; + +namespace JMMServer.Repositories +{ + public class MovieDB_FanartRepository + { + public void Save(MovieDB_Fanart obj) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + session.SaveOrUpdate(obj); + transaction.Commit(); + } + } + } + + public MovieDB_Fanart GetByID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + return session.Get(id); + } + } + + public MovieDB_Fanart GetByOnlineID(string id, string imageSize) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + MovieDB_Fanart cr = session + .CreateCriteria(typeof(MovieDB_Fanart)) + .Add(Restrictions.Eq("ImageID", id)) + .Add(Restrictions.Eq("ImageSize", imageSize)) + .UniqueResult(); + return cr; + } + } + + public List GetByMovieID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var objs = session + .CreateCriteria(typeof(MovieDB_Fanart)) + .Add(Restrictions.Eq("MovieId", id)) + .List(); + + return new List(objs); + } + } + + public List GetAllOriginal() + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var objs = session + .CreateCriteria(typeof(MovieDB_Fanart)) + .Add(Restrictions.Eq("ImageSize", "original")) + .List(); + + return new List(objs); + } + } + + public List GetAll() + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var objs = session + .CreateCriteria(typeof(MovieDB_Fanart)) + .List(); + + return new List(objs); + } + } + + public void Delete(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + MovieDB_Fanart cr = GetByID(id); + if (cr != null) + { + session.Delete(cr); + transaction.Commit(); + } + } + } + } + } +} diff --git a/JMMServer/Repositories/MovieDB_MovieRepository.cs b/JMMServer/Repositories/MovieDB_MovieRepository.cs new file mode 100644 index 000000000..5ff3c0804 --- /dev/null +++ b/JMMServer/Repositories/MovieDB_MovieRepository.cs @@ -0,0 +1,74 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Entities; +using NHibernate.Criterion; + +namespace JMMServer.Repositories +{ + public class MovieDB_MovieRepository + { + public void Save(MovieDB_Movie obj) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + session.SaveOrUpdate(obj); + transaction.Commit(); + } + } + } + + public MovieDB_Movie GetByID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + return session.Get(id); + } + } + + public MovieDB_Movie GetByOnlineID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + MovieDB_Movie cr = session + .CreateCriteria(typeof(MovieDB_Movie)) + .Add(Restrictions.Eq("MovieId", id)) + .UniqueResult(); + return cr; + } + } + + public List GetAll() + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var objs = session + .CreateCriteria(typeof(MovieDB_Movie)) + .List(); + + return new List(objs); + } + } + + public void Delete(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + MovieDB_Movie cr = GetByID(id); + if (cr != null) + { + session.Delete(cr); + transaction.Commit(); + } + } + } + } + } +} diff --git a/JMMServer/Repositories/MovieDB_PosterRepository.cs b/JMMServer/Repositories/MovieDB_PosterRepository.cs new file mode 100644 index 000000000..ab94a979b --- /dev/null +++ b/JMMServer/Repositories/MovieDB_PosterRepository.cs @@ -0,0 +1,101 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Entities; +using NHibernate.Criterion; + +namespace JMMServer.Repositories +{ + public class MovieDB_PosterRepository + { + public void Save(MovieDB_Poster obj) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + session.SaveOrUpdate(obj); + transaction.Commit(); + } + } + } + + public MovieDB_Poster GetByID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + return session.Get(id); + } + } + + public MovieDB_Poster GetByOnlineID(string id, string imageSize) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + MovieDB_Poster cr = session + .CreateCriteria(typeof(MovieDB_Poster)) + .Add(Restrictions.Eq("ImageID", id)) + .Add(Restrictions.Eq("ImageSize", imageSize)) + .UniqueResult(); + return cr; + } + } + + public List GetByMovieID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var objs = session + .CreateCriteria(typeof(MovieDB_Poster)) + .Add(Restrictions.Eq("MovieId", id)) + .List(); + + return new List(objs); + } + } + + public List GetAllOriginal() + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var objs = session + .CreateCriteria(typeof(MovieDB_Poster)) + .Add(Restrictions.Eq("ImageSize", "original")) + .List(); + + return new List(objs); + } + } + + public List GetAll() + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var objs = session + .CreateCriteria(typeof(MovieDB_Poster)) + .List(); + + return new List(objs); + } + } + + public void Delete(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + MovieDB_Poster cr = GetByID(id); + if (cr != null) + { + session.Delete(cr); + transaction.Commit(); + } + } + } + } + } +} diff --git a/JMMServer/Repositories/ScheduledUpdateRepository.cs b/JMMServer/Repositories/ScheduledUpdateRepository.cs new file mode 100644 index 000000000..a498e4824 --- /dev/null +++ b/JMMServer/Repositories/ScheduledUpdateRepository.cs @@ -0,0 +1,62 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Entities; +using NHibernate.Criterion; + +namespace JMMServer.Repositories +{ + public class ScheduledUpdateRepository + { + public void Save(ScheduledUpdate obj) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + session.SaveOrUpdate(obj); + transaction.Commit(); + } + } + } + + public ScheduledUpdate GetByID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + return session.Get(id); + } + } + + public ScheduledUpdate GetByUpdateType(int uptype) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + ScheduledUpdate cr = session + .CreateCriteria(typeof(ScheduledUpdate)) + .Add(Restrictions.Eq("UpdateType", uptype)) + .UniqueResult(); + return cr; + } + } + + public void Delete(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + ScheduledUpdate cr = GetByID(id); + if (cr != null) + { + session.Delete(cr); + transaction.Commit(); + } + } + } + } + } +} diff --git a/JMMServer/Repositories/Trakt_EpisodeRepository.cs b/JMMServer/Repositories/Trakt_EpisodeRepository.cs new file mode 100644 index 000000000..f60eba312 --- /dev/null +++ b/JMMServer/Repositories/Trakt_EpisodeRepository.cs @@ -0,0 +1,104 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Entities; +using NHibernate.Criterion; + +namespace JMMServer.Repositories +{ + public class Trakt_EpisodeRepository + { + public void Save(Trakt_Episode obj) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + session.SaveOrUpdate(obj); + transaction.Commit(); + } + } + } + + public Trakt_Episode GetByID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + return session.Get(id); + } + } + + public List GetByShowID(int showID) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var objs = session + .CreateCriteria(typeof(Trakt_Episode)) + .Add(Restrictions.Eq("Trakt_ShowID", showID)) + .List(); + + return new List(objs); + } + } + + public List GetByShowIDAndSeason(int showID, int seasonNumber) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var objs = session + .CreateCriteria(typeof(Trakt_Episode)) + .Add(Restrictions.Eq("Trakt_ShowID", showID)) + .Add(Restrictions.Eq("Season", seasonNumber)) + .List(); + + return new List(objs); + } + } + + public Trakt_Episode GetByShowIDSeasonAndEpisode(int showID, int seasonNumber, int epnumber) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + Trakt_Episode obj = session + .CreateCriteria(typeof(Trakt_Episode)) + .Add(Restrictions.Eq("Trakt_ShowID", showID)) + .Add(Restrictions.Eq("Season", seasonNumber)) + .Add(Restrictions.Eq("EpisodeNumber", epnumber)) + .UniqueResult(); + + return obj; + } + } + + public List GetAll() + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var objs = session + .CreateCriteria(typeof(Trakt_Episode)) + .List(); + + return new List(objs); + } + } + + public void Delete(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + Trakt_Episode cr = GetByID(id); + if (cr != null) + { + session.Delete(cr); + transaction.Commit(); + } + } + } + } + } +} diff --git a/JMMServer/Repositories/Trakt_ImageFanartRepository.cs b/JMMServer/Repositories/Trakt_ImageFanartRepository.cs new file mode 100644 index 000000000..a8ed26dd1 --- /dev/null +++ b/JMMServer/Repositories/Trakt_ImageFanartRepository.cs @@ -0,0 +1,89 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Entities; +using NHibernate.Criterion; + +namespace JMMServer.Repositories +{ + public class Trakt_ImageFanartRepository + { + public void Save(Trakt_ImageFanart obj) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + session.SaveOrUpdate(obj); + transaction.Commit(); + } + } + } + + public Trakt_ImageFanart GetByID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + return session.Get(id); + } + } + + public List GetByShowID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var objs = session + .CreateCriteria(typeof(Trakt_ImageFanart)) + .Add(Restrictions.Eq("Trakt_ShowID", id)) + .List(); + + return new List(objs); + } + } + + public Trakt_ImageFanart GetByShowIDAndSeason(int showID, int seasonNumber) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + Trakt_ImageFanart obj = session + .CreateCriteria(typeof(Trakt_ImageFanart)) + .Add(Restrictions.Eq("Trakt_ShowID", showID)) + .Add(Restrictions.Eq("Season", seasonNumber)) + .UniqueResult(); + + return obj; + } + } + + public List GetAll() + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var objs = session + .CreateCriteria(typeof(Trakt_ImageFanart)) + .List(); + + return new List(objs); + } + } + + public void Delete(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + Trakt_ImageFanart cr = GetByID(id); + if (cr != null) + { + session.Delete(cr); + transaction.Commit(); + } + } + } + } + } +} diff --git a/JMMServer/Repositories/Trakt_ImagePosterRepository.cs b/JMMServer/Repositories/Trakt_ImagePosterRepository.cs new file mode 100644 index 000000000..70bdd1fbf --- /dev/null +++ b/JMMServer/Repositories/Trakt_ImagePosterRepository.cs @@ -0,0 +1,89 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Entities; +using NHibernate.Criterion; + +namespace JMMServer.Repositories +{ + public class Trakt_ImagePosterRepository + { + public void Save(Trakt_ImagePoster obj) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + session.SaveOrUpdate(obj); + transaction.Commit(); + } + } + } + + public Trakt_ImagePoster GetByID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + return session.Get(id); + } + } + + public List GetByShowID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var objs = session + .CreateCriteria(typeof(Trakt_ImagePoster)) + .Add(Restrictions.Eq("Trakt_ShowID", id)) + .List(); + + return new List(objs); + } + } + + public Trakt_ImagePoster GetByShowIDAndSeason(int showID, int seasonNumber) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + Trakt_ImagePoster obj = session + .CreateCriteria(typeof(Trakt_ImagePoster)) + .Add(Restrictions.Eq("Trakt_ShowID", showID)) + .Add(Restrictions.Eq("Season", seasonNumber)) + .UniqueResult(); + + return obj; + } + } + + public List GetAll() + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var objs = session + .CreateCriteria(typeof(Trakt_ImagePoster)) + .List(); + + return new List(objs); + } + } + + public void Delete(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + Trakt_ImagePoster cr = GetByID(id); + if (cr != null) + { + session.Delete(cr); + transaction.Commit(); + } + } + } + } + } +} diff --git a/JMMServer/Repositories/Trakt_SeasonRepository.cs b/JMMServer/Repositories/Trakt_SeasonRepository.cs new file mode 100644 index 000000000..993ede610 --- /dev/null +++ b/JMMServer/Repositories/Trakt_SeasonRepository.cs @@ -0,0 +1,89 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Entities; +using NHibernate.Criterion; + +namespace JMMServer.Repositories +{ + public class Trakt_SeasonRepository + { + public void Save(Trakt_Season obj) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + session.SaveOrUpdate(obj); + transaction.Commit(); + } + } + } + + public Trakt_Season GetByID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + return session.Get(id); + } + } + + public List GetByShowID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var objs = session + .CreateCriteria(typeof(Trakt_Season)) + .Add(Restrictions.Eq("Trakt_ShowID", id)) + .List(); + + return new List(objs); + } + } + + public Trakt_Season GetByShowIDAndSeason(int id, int season) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + Trakt_Season obj = session + .CreateCriteria(typeof(Trakt_Season)) + .Add(Restrictions.Eq("Trakt_ShowID", id)) + .Add(Restrictions.Eq("Season", season)) + .UniqueResult(); + + return obj; + } + } + + public List GetAll() + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var objs = session + .CreateCriteria(typeof(Trakt_Season)) + .List(); + + return new List(objs); + } + } + + public void Delete(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + Trakt_Season cr = GetByID(id); + if (cr != null) + { + session.Delete(cr); + transaction.Commit(); + } + } + } + } + } +} diff --git a/JMMServer/Repositories/Trakt_ShowRepository.cs b/JMMServer/Repositories/Trakt_ShowRepository.cs new file mode 100644 index 000000000..4f1c19f05 --- /dev/null +++ b/JMMServer/Repositories/Trakt_ShowRepository.cs @@ -0,0 +1,74 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Entities; +using NHibernate.Criterion; + +namespace JMMServer.Repositories +{ + public class Trakt_ShowRepository + { + public void Save(Trakt_Show obj) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + session.SaveOrUpdate(obj); + transaction.Commit(); + } + } + } + + public Trakt_Show GetByID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + return session.Get(id); + } + } + + public Trakt_Show GetByShowID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + Trakt_Show cr = session + .CreateCriteria(typeof(Trakt_Show)) + .Add(Restrictions.Eq("Trakt_ShowID", id)) + .UniqueResult(); + return cr; + } + } + + public Trakt_Show GetByTraktID(string id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + Trakt_Show cr = session + .CreateCriteria(typeof(Trakt_Show)) + .Add(Restrictions.Eq("TraktID", id)) + .UniqueResult(); + return cr; + } + } + + public void Delete(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + Trakt_Show cr = GetByID(id); + if (cr != null) + { + session.Delete(cr); + transaction.Commit(); + } + } + } + } + } +} diff --git a/JMMServer/Repositories/TvDB_EpisodeRepository.cs b/JMMServer/Repositories/TvDB_EpisodeRepository.cs new file mode 100644 index 000000000..c8d1add20 --- /dev/null +++ b/JMMServer/Repositories/TvDB_EpisodeRepository.cs @@ -0,0 +1,124 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Entities; +using NHibernate.Criterion; + +namespace JMMServer.Repositories +{ + public class TvDB_EpisodeRepository + { + public void Save(TvDB_Episode obj) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + session.SaveOrUpdate(obj); + transaction.Commit(); + } + } + } + + public TvDB_Episode GetByID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + return session.Get(id); + } + } + + public TvDB_Episode GetByTvDBID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + TvDB_Episode cr = session + .CreateCriteria(typeof(TvDB_Episode)) + .Add(Restrictions.Eq("Id", id)) + .UniqueResult(); + return cr; + } + } + + public List GetBySeriesID(int seriesID) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var objs = session + .CreateCriteria(typeof(TvDB_Episode)) + .Add(Restrictions.Eq("SeriesID", seriesID)) + .List(); + + return new List(objs); + } + } + + public List GetSeasonNumbersForSeries(int seriesID) + { + List seasonNumbers = new List(); + using (var session = JMMService.SessionFactory.OpenSession()) + { + var objs = session + .CreateCriteria(typeof(TvDB_Episode)) + .Add(Restrictions.Eq("SeriesID", seriesID)) + .AddOrder(Order.Asc("SeasonNumber")) + .List(); + + List eps= new List(objs); + + foreach (TvDB_Episode ep in eps) + { + if (!seasonNumbers.Contains(ep.SeasonNumber)) + seasonNumbers.Add(ep.SeasonNumber); + } + } + + return seasonNumbers; + } + + public List GetBySeriesIDAndSeasonNumber(int seriesID, int seasonNumber) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var objs = session + .CreateCriteria(typeof(TvDB_Episode)) + .Add(Restrictions.Eq("SeriesID", seriesID)) + .Add(Restrictions.Eq("SeasonNumber", seasonNumber)) + .List(); + + return new List(objs); + } + } + + public List GetAll() + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var objs = session + .CreateCriteria(typeof(TvDB_Episode)) + .List(); + + return new List(objs); + } + } + + public void Delete(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + TvDB_Episode cr = GetByID(id); + if (cr != null) + { + session.Delete(cr); + transaction.Commit(); + } + } + } + } + } +} diff --git a/JMMServer/Repositories/TvDB_ImageFanartRepository.cs b/JMMServer/Repositories/TvDB_ImageFanartRepository.cs new file mode 100644 index 000000000..a5bc239b6 --- /dev/null +++ b/JMMServer/Repositories/TvDB_ImageFanartRepository.cs @@ -0,0 +1,87 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Entities; +using NHibernate.Criterion; + +namespace JMMServer.Repositories +{ + public class TvDB_ImageFanartRepository + { + public void Save(TvDB_ImageFanart obj) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + session.SaveOrUpdate(obj); + transaction.Commit(); + } + } + } + + public TvDB_ImageFanart GetByID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + return session.Get(id); + } + } + + public TvDB_ImageFanart GetByTvDBID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + TvDB_ImageFanart cr = session + .CreateCriteria(typeof(TvDB_ImageFanart)) + .Add(Restrictions.Eq("Id", id)) + .UniqueResult(); + return cr; + } + } + + public List GetBySeriesID(int seriesID) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var objs = session + .CreateCriteria(typeof(TvDB_ImageFanart)) + .Add(Restrictions.Eq("SeriesID", seriesID)) + .List(); + + return new List(objs); + } + } + + public List GetAll() + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var objs = session + .CreateCriteria(typeof(TvDB_ImageFanart)) + .List(); + + return new List(objs); + } + } + + public void Delete(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + TvDB_ImageFanart cr = GetByID(id); + if (cr != null) + { + session.Delete(cr); + transaction.Commit(); + } + } + } + } + } +} diff --git a/JMMServer/Repositories/TvDB_ImagePosterRepository.cs b/JMMServer/Repositories/TvDB_ImagePosterRepository.cs new file mode 100644 index 000000000..b700feb3f --- /dev/null +++ b/JMMServer/Repositories/TvDB_ImagePosterRepository.cs @@ -0,0 +1,87 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Entities; +using NHibernate.Criterion; + +namespace JMMServer.Repositories +{ + public class TvDB_ImagePosterRepository + { + public void Save(TvDB_ImagePoster obj) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + session.SaveOrUpdate(obj); + transaction.Commit(); + } + } + } + + public TvDB_ImagePoster GetByID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + return session.Get(id); + } + } + + public TvDB_ImagePoster GetByTvDBID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + TvDB_ImagePoster cr = session + .CreateCriteria(typeof(TvDB_ImagePoster)) + .Add(Restrictions.Eq("Id", id)) + .UniqueResult(); + return cr; + } + } + + public List GetAll() + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var objs = session + .CreateCriteria(typeof(TvDB_ImagePoster)) + .List(); + + return new List(objs); + } + } + + public List GetBySeriesID(int seriesID) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var objs = session + .CreateCriteria(typeof(TvDB_ImagePoster)) + .Add(Restrictions.Eq("SeriesID", seriesID)) + .List(); + + return new List(objs); + } + } + + public void Delete(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + TvDB_ImagePoster cr = GetByID(id); + if (cr != null) + { + session.Delete(cr); + transaction.Commit(); + } + } + } + } + } +} diff --git a/JMMServer/Repositories/TvDB_ImageWideBannerRepository.cs b/JMMServer/Repositories/TvDB_ImageWideBannerRepository.cs new file mode 100644 index 000000000..1a529169c --- /dev/null +++ b/JMMServer/Repositories/TvDB_ImageWideBannerRepository.cs @@ -0,0 +1,87 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Entities; +using NHibernate.Criterion; + +namespace JMMServer.Repositories +{ + public class TvDB_ImageWideBannerRepository + { + public void Save(TvDB_ImageWideBanner obj) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + session.SaveOrUpdate(obj); + transaction.Commit(); + } + } + } + + public TvDB_ImageWideBanner GetByID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + return session.Get(id); + } + } + + public TvDB_ImageWideBanner GetByTvDBID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + TvDB_ImageWideBanner cr = session + .CreateCriteria(typeof(TvDB_ImageWideBanner)) + .Add(Restrictions.Eq("Id", id)) + .UniqueResult(); + return cr; + } + } + + public List GetBySeriesID(int seriesID) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var objs = session + .CreateCriteria(typeof(TvDB_ImageWideBanner)) + .Add(Restrictions.Eq("SeriesID", seriesID)) + .List(); + + return new List(objs); + } + } + + public List GetAll() + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var objs = session + .CreateCriteria(typeof(TvDB_ImageWideBanner)) + .List(); + + return new List(objs); + } + } + + public void Delete(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + TvDB_ImageWideBanner cr = GetByID(id); + if (cr != null) + { + session.Delete(cr); + transaction.Commit(); + } + } + } + } + } +} diff --git a/JMMServer/Repositories/TvDB_SeriesRepository.cs b/JMMServer/Repositories/TvDB_SeriesRepository.cs new file mode 100644 index 000000000..2f99390d7 --- /dev/null +++ b/JMMServer/Repositories/TvDB_SeriesRepository.cs @@ -0,0 +1,62 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Entities; +using NHibernate.Criterion; + +namespace JMMServer.Repositories +{ + public class TvDB_SeriesRepository + { + public void Save(TvDB_Series obj) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + session.SaveOrUpdate(obj); + transaction.Commit(); + } + } + } + + public TvDB_Series GetByID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + return session.Get(id); + } + } + + public TvDB_Series GetByTvDBID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + TvDB_Series cr = session + .CreateCriteria(typeof(TvDB_Series)) + .Add(Restrictions.Eq("SeriesID", id)) + .UniqueResult(); + return cr; + } + } + + public void Delete(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + TvDB_Series cr = GetByID(id); + if (cr != null) + { + session.Delete(cr); + transaction.Commit(); + } + } + } + } + } +} diff --git a/JMMServer/Repositories/VersionsRepository.cs b/JMMServer/Repositories/VersionsRepository.cs new file mode 100644 index 000000000..fcd23efe4 --- /dev/null +++ b/JMMServer/Repositories/VersionsRepository.cs @@ -0,0 +1,62 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Entities; +using NHibernate.Criterion; + +namespace JMMServer.Repositories +{ + public class VersionsRepository + { + public void Save(Versions obj) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + session.SaveOrUpdate(obj); + transaction.Commit(); + } + } + } + + public Versions GetByID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + return session.Get(id); + } + } + + public Versions GetByVersionType(string vertype) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + Versions cr = session + .CreateCriteria(typeof(Versions)) + .Add(Restrictions.Eq("VersionType", vertype)) + .UniqueResult(); + return cr; + } + } + + public void Delete(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + Versions cr = GetByID(id); + if (cr != null) + { + session.Delete(cr); + transaction.Commit(); + } + } + } + } + } +} diff --git a/JMMServer/Repositories/VideoInfoRepository.cs b/JMMServer/Repositories/VideoInfoRepository.cs new file mode 100644 index 000000000..d6581139d --- /dev/null +++ b/JMMServer/Repositories/VideoInfoRepository.cs @@ -0,0 +1,64 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Entities; +using NHibernate.Criterion; + +namespace JMMServer.Repositories +{ + public class VideoInfoRepository + { + public void Save(VideoInfo obj) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + session.SaveOrUpdate(obj); + transaction.Commit(); + } + } + } + + public VideoInfo GetByID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + return session.Get(id); + } + } + + public VideoInfo GetByHash(string hash) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + VideoInfo obj = session + .CreateCriteria(typeof(VideoInfo)) + .Add(Restrictions.Eq("Hash", hash)) + .UniqueResult(); + + return obj; + } + } + + + public void Delete(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + VideoInfo cr = GetByID(id); + if (cr != null) + { + session.Delete(cr); + transaction.Commit(); + } + } + } + } + } +} diff --git a/JMMServer/Repositories/VideoLocalRepository.cs b/JMMServer/Repositories/VideoLocalRepository.cs new file mode 100644 index 000000000..93db64c3a --- /dev/null +++ b/JMMServer/Repositories/VideoLocalRepository.cs @@ -0,0 +1,194 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Entities; +using NHibernate.Criterion; + +namespace JMMServer.Repositories +{ + public class VideoLocalRepository + { + public void Save(VideoLocal obj) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + session.SaveOrUpdate(obj); + transaction.Commit(); + } + } + } + + public VideoLocal GetByID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + return session.Get(id); + } + } + + + public VideoLocal GetByHash(string hash) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + VideoLocal obj = session + .CreateCriteria(typeof(VideoLocal)) + .Add(Restrictions.Eq("Hash", hash)) + .UniqueResult(); + + return obj; + } + } + + public List GetByFilePathAndShareID(string filePath, int nshareID) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var vidfiles = session + .CreateCriteria(typeof(VideoLocal)) + .Add(Restrictions.Eq("FilePath", filePath)) + .Add(Restrictions.Eq("ImportFolderID", nshareID)) + .List(); + return new List(vidfiles); + } + } + + /// + /// returns all the VideoLocal records associate with an AnimeEpisode Record + /// + /// + /// + public List GetByAniDBEpisodeID(int episodeID) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var vidfiles = session.CreateQuery("FROM VideoLocal vl WHERE vl.Hash IN (Select Hash FROM CrossRef_File_Episode xref WHERE xref.EpisodeID= :episodeid)") + .SetParameter("episodeid", episodeID) + .List(); + + return new List(vidfiles); + } + } + + /// + /// returns all the VideoLocal records associate with an AniDB_Anime Record + /// + /// + /// + public List GetByAniDBAnimeID(int animeID) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var vidfiles = session.CreateQuery("FROM VideoLocal vl WHERE vl.Hash IN (Select Hash FROM CrossRef_File_Episode xref WHERE xref.AnimeID= :animeID )") + .SetParameter("animeID", animeID) + .List(); + + return new List(vidfiles); + } + } + + public List GetVideosWithoutHash() + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var vidfiles = session.CreateQuery("FROM VideoLocal vl WHERE vl.Hash = ''") + .List(); + + return new List(vidfiles); + } + } + + public List GetVideosWithoutVideoInfo() + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var vidfiles = session.CreateQuery("FROM VideoLocal vl WHERE vl.Hash NOT IN (Select Hash FROM VideoInfo vi)") + .List(); + + return new List(vidfiles); + } + } + + public List GetVideosWithoutEpisode() + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var vidfiles = session.CreateQuery("FROM VideoLocal vl WHERE vl.Hash NOT IN (Select Hash FROM CrossRef_File_Episode xref) AND vl.IsIgnored = 0") + .List(); + + return new List(vidfiles); + } + } + + public List GetManuallyLinkedVideos() + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var vidfiles = session.CreateQuery("FROM VideoLocal vl WHERE vl.Hash IN (Select Hash FROM CrossRef_File_Episode xref WHERE xref.CrossRefSource <> 1)") + .List(); + + return new List(vidfiles); + } + } + + public List GetIgnoredVideos() + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var vidfiles = session + .CreateCriteria(typeof(VideoLocal)) + .Add(Restrictions.Eq("IsIgnored", 1)) + .List(); + return new List(vidfiles); + } + } + + public List GetAll() + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var objs = session + .CreateCriteria(typeof(VideoLocal)) + .List(); + + return new List(objs); + } + } + + + public void Delete(int id) + { + VideoLocal cr = GetByID(id); + if (cr != null) + { + // delete video info record + VideoInfoRepository repVI = new VideoInfoRepository(); + VideoInfo vi = cr.VideoInfo; + if (vi != null) + repVI.Delete(vi.VideoInfoID); + + // delete user records + VideoLocal_UserRepository repUsers = new VideoLocal_UserRepository(); + foreach (VideoLocal_User viduser in repUsers.GetByVideoLocalID(id)) + repUsers.Delete(viduser.VideoLocal_UserID); + } + + using (var session = JMMService.SessionFactory.OpenSession()) + { + // populate the database + using (var transaction = session.BeginTransaction()) + { + if (cr != null) + { + session.Delete(cr); + transaction.Commit(); + } + } + } + } + } +} diff --git a/JMMServer/Repositories/VideoLocal_UserRepository.cs b/JMMServer/Repositories/VideoLocal_UserRepository.cs new file mode 100644 index 000000000..7381130e3 --- /dev/null +++ b/JMMServer/Repositories/VideoLocal_UserRepository.cs @@ -0,0 +1,103 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Entities; +using NHibernate.Criterion; + + +namespace JMMServer.Repositories +{ + public class VideoLocal_UserRepository + { + 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 GetByID(int id) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + return session.Get(id); + } + } + + public List GetAll() + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var objs = session + .CreateCriteria(typeof(VideoLocal_User)) + .List(); + + return new List(objs); + } + } + + public List GetByVideoLocalID(int vidid) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var eps = session + .CreateCriteria(typeof(VideoLocal_User)) + .Add(Restrictions.Eq("VideoLocalID", vidid)) + .List(); + + return new List(eps); + } + } + + public List GetByUserID(int userid) + { + using (var session = JMMService.SessionFactory.OpenSession()) + { + var vids = session + .CreateCriteria(typeof(VideoLocal_User)) + .Add(Restrictions.Eq("JMMUserID", userid)) + .List(); + + return new List(vids); + } + } + + 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(); + + return obj; + } + } + + 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(); + } + } + } + } + } +} diff --git a/JMMServer/ServerSettings.cs b/JMMServer/ServerSettings.cs new file mode 100644 index 000000000..5e46e07a1 --- /dev/null +++ b/JMMServer/ServerSettings.cs @@ -0,0 +1,954 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Collections.Specialized; +using System.Configuration; +using AniDBAPI; +using JMMContracts; + +namespace JMMServer +{ + public class ServerSettings + { + #region Database + + public static string DatabaseType + { + get + { + NameValueCollection appSettings = ConfigurationManager.AppSettings; + return appSettings["DatabaseType"]; + } + set + { + UpdateSetting("DatabaseType", value); + } + } + + public static string DatabaseServer + { + get + { + NameValueCollection appSettings = ConfigurationManager.AppSettings; + return appSettings["SQLServer_DatabaseServer"]; + } + set + { + UpdateSetting("SQLServer_DatabaseServer", value); + } + } + + public static string DatabaseName + { + get + { + NameValueCollection appSettings = ConfigurationManager.AppSettings; + return appSettings["SQLServer_DatabaseName"]; + } + set + { + UpdateSetting("SQLServer_DatabaseName", value); + } + } + + public static string DatabaseUsername + { + get + { + NameValueCollection appSettings = ConfigurationManager.AppSettings; + return appSettings["SQLServer_Username"]; + } + set + { + UpdateSetting("SQLServer_Username", value); + } + } + + public static string DatabasePassword + { + get + { + NameValueCollection appSettings = ConfigurationManager.AppSettings; + return appSettings["SQLServer_Password"]; + } + set + { + UpdateSetting("SQLServer_Password", value); + } + } + + public static string DatabaseFile + { + get + { + NameValueCollection appSettings = ConfigurationManager.AppSettings; + return appSettings["SQLite_DatabaseFile"]; + } + set + { + UpdateSetting("SQLite_DatabaseFile", value); + } + } + + #endregion + + #region AniDB + + public static string AniDB_Username + { + get + { + NameValueCollection appSettings = ConfigurationManager.AppSettings; + return appSettings["AniDB_Username"]; + } + set + { + UpdateSetting("AniDB_Username", value); + } + } + + public static string AniDB_Password + { + get + { + NameValueCollection appSettings = ConfigurationManager.AppSettings; + return appSettings["AniDB_Password"]; + } + set + { + UpdateSetting("AniDB_Password", value); + } + } + + public static string AniDB_ServerAddress + { + get + { + NameValueCollection appSettings = ConfigurationManager.AppSettings; + return appSettings["AniDB_ServerAddress"]; + } + set + { + UpdateSetting("AniDB_ServerAddress", value); + } + } + + public static string AniDB_ServerPort + { + get + { + NameValueCollection appSettings = ConfigurationManager.AppSettings; + return appSettings["AniDB_ServerPort"]; + } + set + { + UpdateSetting("AniDB_ServerPort", value); + } + } + + public static string AniDB_ClientPort + { + get + { + NameValueCollection appSettings = ConfigurationManager.AppSettings; + return appSettings["AniDB_ClientPort"]; + } + set + { + UpdateSetting("AniDB_ClientPort", value); + } + } + + public static bool AniDB_DownloadRelatedAnime + { + get + { + NameValueCollection appSettings = ConfigurationManager.AppSettings; + bool download = false; + bool.TryParse(appSettings["AniDB_DownloadRelatedAnime"], out download); + return download; + } + set + { + UpdateSetting("AniDB_DownloadRelatedAnime", value.ToString()); + } + } + + public static bool AniDB_DownloadSimilarAnime + { + get + { + NameValueCollection appSettings = ConfigurationManager.AppSettings; + bool download = false; + bool.TryParse(appSettings["AniDB_DownloadSimilarAnime"], out download); + return download; + } + set + { + UpdateSetting("AniDB_DownloadSimilarAnime", value.ToString()); + } + } + + public static bool AniDB_DownloadCharactersCreators + { + get + { + NameValueCollection appSettings = ConfigurationManager.AppSettings; + bool download = false; + bool.TryParse(appSettings["AniDB_DownloadCharactersCreators"], out download); + return download; + } + set + { + UpdateSetting("AniDB_DownloadCharactersCreators", value.ToString()); + } + } + + public static bool AniDB_DownloadReviews + { + get + { + NameValueCollection appSettings = ConfigurationManager.AppSettings; + bool download = false; + bool.TryParse(appSettings["AniDB_DownloadReviews"], out download); + return download; + } + set + { + UpdateSetting("AniDB_DownloadReviews", value.ToString()); + } + } + + public static bool AniDB_DownloadReleaseGroups + { + get + { + NameValueCollection appSettings = ConfigurationManager.AppSettings; + bool download = false; + bool.TryParse(appSettings["AniDB_DownloadReleaseGroups"], out download); + return download; + } + set + { + UpdateSetting("AniDB_DownloadReleaseGroups", value.ToString()); + } + } + + public static bool AniDB_MyList_AddFiles + { + get + { + NameValueCollection appSettings = ConfigurationManager.AppSettings; + bool val = false; + bool.TryParse(appSettings["AniDB_MyList_AddFiles"], out val); + return val; + } + set + { + UpdateSetting("AniDB_MyList_AddFiles", value.ToString()); + } + } + + public static AniDBFileStatus AniDB_MyList_StorageState + { + get + { + NameValueCollection appSettings = ConfigurationManager.AppSettings; + int val = 1; + int.TryParse(appSettings["AniDB_MyList_StorageState"], out val); + + return (AniDBFileStatus)val; + } + set + { + UpdateSetting("AniDB_MyList_StorageState", ((int)value).ToString()); + } + } + + public static bool AniDB_MyList_ReadUnwatched + { + get + { + NameValueCollection appSettings = ConfigurationManager.AppSettings; + bool val = false; + bool.TryParse(appSettings["AniDB_MyList_ReadUnwatched"], out val); + return val; + } + set + { + UpdateSetting("AniDB_MyList_ReadUnwatched", value.ToString()); + } + } + + public static bool AniDB_MyList_ReadWatched + { + get + { + NameValueCollection appSettings = ConfigurationManager.AppSettings; + bool val = false; + bool.TryParse(appSettings["AniDB_MyList_ReadWatched"], out val); + return val; + } + set + { + UpdateSetting("AniDB_MyList_ReadWatched", value.ToString()); + } + } + + public static bool AniDB_MyList_SetWatched + { + get + { + NameValueCollection appSettings = ConfigurationManager.AppSettings; + bool val = false; + bool.TryParse(appSettings["AniDB_MyList_SetWatched"], out val); + return val; + } + set + { + UpdateSetting("AniDB_MyList_SetWatched", value.ToString()); + } + } + + public static bool AniDB_MyList_SetUnwatched + { + get + { + NameValueCollection appSettings = ConfigurationManager.AppSettings; + bool val = false; + bool.TryParse(appSettings["AniDB_MyList_SetUnwatched"], out val); + return val; + } + set + { + UpdateSetting("AniDB_MyList_SetUnwatched", value.ToString()); + } + } + + public static ScheduledUpdateFrequency AniDB_MyList_UpdateFrequency + { + get + { + NameValueCollection appSettings = ConfigurationManager.AppSettings; + int val = 1; + if (int.TryParse(appSettings["AniDB_MyList_UpdateFrequency"], out val)) + return (ScheduledUpdateFrequency)val; + else + return ScheduledUpdateFrequency.Daily; // default value + } + set + { + UpdateSetting("AniDB_MyList_UpdateFrequency", ((int)value).ToString()); + } + } + + public static ScheduledUpdateFrequency AniDB_Calendar_UpdateFrequency + { + get + { + NameValueCollection appSettings = ConfigurationManager.AppSettings; + int val = 1; + if (int.TryParse(appSettings["AniDB_Calendar_UpdateFrequency"], out val)) + return (ScheduledUpdateFrequency)val; + else + return ScheduledUpdateFrequency.HoursTwelve; // default value + } + set + { + UpdateSetting("AniDB_Calendar_UpdateFrequency", ((int)value).ToString()); + } + } + + public static ScheduledUpdateFrequency AniDB_Anime_UpdateFrequency + { + get + { + NameValueCollection appSettings = ConfigurationManager.AppSettings; + int val = 1; + if (int.TryParse(appSettings["AniDB_Anime_UpdateFrequency"], out val)) + return (ScheduledUpdateFrequency)val; + else + return ScheduledUpdateFrequency.HoursTwelve; // default value + } + set + { + UpdateSetting("AniDB_Anime_UpdateFrequency", ((int)value).ToString()); + } + } + + + #endregion + + #region Web Cache + + public static string WebCache_Address + { + get + { + NameValueCollection appSettings = ConfigurationManager.AppSettings; + return appSettings["WebCache_Address"]; + } + set + { + UpdateSetting("WebCache_Address", value); + } + } + + public static bool WebCache_Anonymous + { + get + { + NameValueCollection appSettings = ConfigurationManager.AppSettings; + bool val = false; + bool.TryParse(appSettings["WebCache_Anonymous"], out val); + return val; + } + set + { + UpdateSetting("WebCache_Anonymous", value.ToString()); + } + } + + public static bool WebCache_FileHashes_Get + { + get + { + NameValueCollection appSettings = ConfigurationManager.AppSettings; + bool usecache = false; + bool.TryParse(appSettings["WebCache_FileHashes_Get"], out usecache); + return usecache; + } + set + { + UpdateSetting("WebCache_FileHashes_Get", value.ToString()); + } + } + + public static bool WebCache_FileHashes_Send + { + get + { + NameValueCollection appSettings = ConfigurationManager.AppSettings; + bool usecache = false; + bool.TryParse(appSettings["WebCache_FileHashes_Send"], out usecache); + return usecache; + } + set + { + UpdateSetting("WebCache_FileHashes_Send", value.ToString()); + } + } + + public static bool WebCache_XRefFileEpisode_Get + { + get + { + NameValueCollection appSettings = ConfigurationManager.AppSettings; + bool usecache = false; + bool.TryParse(appSettings["WebCache_XRefFileEpisode_Get"], out usecache); + return usecache; + } + set + { + UpdateSetting("WebCache_XRefFileEpisode_Get", value.ToString()); + } + } + + public static bool WebCache_XRefFileEpisode_Send + { + get + { + NameValueCollection appSettings = ConfigurationManager.AppSettings; + bool usecache = false; + bool.TryParse(appSettings["WebCache_XRefFileEpisode_Send"], out usecache); + return usecache; + } + set + { + UpdateSetting("WebCache_XRefFileEpisode_Send", value.ToString()); + } + } + + public static bool WebCache_TvDB_Get + { + get + { + NameValueCollection appSettings = ConfigurationManager.AppSettings; + bool usecache = false; + bool.TryParse(appSettings["WebCache_TvDB_Get"], out usecache); + return usecache; + } + set + { + UpdateSetting("WebCache_TvDB_Get", value.ToString()); + } + } + + public static bool WebCache_TvDB_Send + { + get + { + NameValueCollection appSettings = ConfigurationManager.AppSettings; + bool usecache = false; + bool.TryParse(appSettings["WebCache_TvDB_Send"], out usecache); + return usecache; + } + set + { + UpdateSetting("WebCache_TvDB_Send", value.ToString()); + } + } + + #endregion + + #region TvDB + + public static bool TvDB_AutoFanart + { + get + { + NameValueCollection appSettings = ConfigurationManager.AppSettings; + bool val = false; + bool.TryParse(appSettings["TvDB_AutoFanart"], out val); + return val; + } + set + { + UpdateSetting("TvDB_AutoFanart", value.ToString()); + } + } + + public static int TvDB_AutoFanartAmount + { + get + { + NameValueCollection appSettings = ConfigurationManager.AppSettings; + int val = 0; + int.TryParse(appSettings["TvDB_AutoFanartAmount"], out val); + return val; + } + set + { + UpdateSetting("TvDB_AutoFanartAmount", value.ToString()); + } + } + + public static bool TvDB_AutoWideBanners + { + get + { + NameValueCollection appSettings = ConfigurationManager.AppSettings; + bool val = false; + bool.TryParse(appSettings["TvDB_AutoWideBanners"], out val); + return val; + } + set + { + UpdateSetting("TvDB_AutoWideBanners", value.ToString()); + } + } + + public static bool TvDB_AutoPosters + { + get + { + NameValueCollection appSettings = ConfigurationManager.AppSettings; + bool val = false; + bool.TryParse(appSettings["TvDB_AutoPosters"], out val); + return val; + } + set + { + UpdateSetting("TvDB_AutoPosters", value.ToString()); + } + } + + public static ScheduledUpdateFrequency TvDB_UpdateFrequency + { + get + { + NameValueCollection appSettings = ConfigurationManager.AppSettings; + int val = 1; + if (int.TryParse(appSettings["TvDB_UpdateFrequency"], out val)) + return (ScheduledUpdateFrequency)val; + else + return ScheduledUpdateFrequency.HoursTwelve; // default value + } + set + { + UpdateSetting("TvDB_UpdateFrequency", ((int)value).ToString()); + } + } + + #endregion + + #region MovieDB + + public static bool MovieDB_AutoFanart + { + get + { + NameValueCollection appSettings = ConfigurationManager.AppSettings; + bool val = false; + bool.TryParse(appSettings["MovieDB_AutoFanart"], out val); + return val; + } + set + { + UpdateSetting("MovieDB_AutoFanart", value.ToString()); + } + } + + public static int MovieDB_AutoFanartAmount + { + get + { + NameValueCollection appSettings = ConfigurationManager.AppSettings; + int val = 0; + int.TryParse(appSettings["MovieDB_AutoFanartAmount"], out val); + return val; + } + set + { + UpdateSetting("MovieDB_AutoFanartAmount", value.ToString()); + } + } + + public static bool MovieDB_AutoPosters + { + get + { + NameValueCollection appSettings = ConfigurationManager.AppSettings; + bool val = false; + bool.TryParse(appSettings["MovieDB_AutoPosters"], out val); + return val; + } + set + { + UpdateSetting("MovieDB_AutoPosters", value.ToString()); + } + } + + #endregion + + #region Import Settings + + public static string VideoExtensions + { + get + { + NameValueCollection appSettings = ConfigurationManager.AppSettings; + return appSettings["VideoExtensions"]; + } + set + { + UpdateSetting("VideoExtensions", value); + } + } + + public static RenamingLanguage DefaultSeriesLanguage + { + get + { + RenamingLanguage rl = RenamingLanguage.Romaji; + NameValueCollection appSettings = ConfigurationManager.AppSettings; + + string rls = appSettings["DefaultSeriesLanguage"]; + if (string.IsNullOrEmpty(rls)) return rl; + + rl = (RenamingLanguage)int.Parse(rls); + + return rl; + } + set + { + UpdateSetting("DefaultSeriesLanguage", ((int)value).ToString()); + } + } + + public static RenamingLanguage DefaultEpisodeLanguage + { + get + { + RenamingLanguage rl = RenamingLanguage.Romaji; + NameValueCollection appSettings = ConfigurationManager.AppSettings; + + string rls = appSettings["DefaultEpisodeLanguage"]; + if (string.IsNullOrEmpty(rls)) return rl; + + rl = (RenamingLanguage)int.Parse(rls); + + return rl; + } + set + { + UpdateSetting("DefaultEpisodeLanguage", ((int)value).ToString()); + } + } + + public static bool WatchForNewFiles + { + get + { + NameValueCollection appSettings = ConfigurationManager.AppSettings; + bool val = false; + bool.TryParse(appSettings["WatchForNewFiles"], out val); + return val; + } + set + { + UpdateSetting("WatchForNewFiles", value.ToString()); + } + } + + public static bool RunImportOnStart + { + get + { + NameValueCollection appSettings = ConfigurationManager.AppSettings; + bool val = false; + bool.TryParse(appSettings["RunImportOnStart"], out val); + return val; + } + set + { + UpdateSetting("RunImportOnStart", value.ToString()); + } + } + + public static bool Hash_CRC32 + { + get + { + NameValueCollection appSettings = ConfigurationManager.AppSettings; + bool bval = false; + bool.TryParse(appSettings["Hash_CRC32"], out bval); + return bval; + } + set + { + UpdateSetting("Hash_CRC32", value.ToString()); + } + } + + public static bool Hash_MD5 + { + get + { + NameValueCollection appSettings = ConfigurationManager.AppSettings; + bool bval = false; + bool.TryParse(appSettings["Hash_MD5"], out bval); + return bval; + } + set + { + UpdateSetting("Hash_MD5", value.ToString()); + } + } + + public static bool Hash_SHA1 + { + get + { + NameValueCollection appSettings = ConfigurationManager.AppSettings; + bool bval = false; + bool.TryParse(appSettings["Hash_SHA1"], out bval); + return bval; + } + set + { + UpdateSetting("Hash_SHA1", value.ToString()); + } + } + + public static bool Import_UseExistingFileWatchedStatus + { + get + { + NameValueCollection appSettings = ConfigurationManager.AppSettings; + bool bval = false; + bool.TryParse(appSettings["Import_UseExistingFileWatchedStatus"], out bval); + return bval; + } + set + { + UpdateSetting("Import_UseExistingFileWatchedStatus", value.ToString()); + } + } + + #endregion + + public static string LanguagePreference + { + get + { + NameValueCollection appSettings = ConfigurationManager.AppSettings; + return appSettings["LanguagePreference"]; + } + set + { + UpdateSetting("LanguagePreference", value); + } + } + + public static bool LanguageUseSynonyms + { + get + { + NameValueCollection appSettings = ConfigurationManager.AppSettings; + bool val = false; + bool.TryParse(appSettings["LanguageUseSynonyms"], out val); + return val; + } + set + { + UpdateSetting("LanguageUseSynonyms", value.ToString()); + } + } + + public static string Trakt_Username + { + get + { + NameValueCollection appSettings = ConfigurationManager.AppSettings; + return appSettings["Trakt_Username"]; + } + set + { + UpdateSetting("Trakt_Username", value); + } + } + + public static string Trakt_Password + { + get + { + NameValueCollection appSettings = ConfigurationManager.AppSettings; + return appSettings["Trakt_Password"]; + } + set + { + UpdateSetting("Trakt_Password", value); + } + } + + public static ScheduledUpdateFrequency Trakt_UpdateFrequency + { + get + { + NameValueCollection appSettings = ConfigurationManager.AppSettings; + int val = 1; + if (int.TryParse(appSettings["Trakt_UpdateFrequency"], out val)) + return (ScheduledUpdateFrequency)val; + else + return ScheduledUpdateFrequency.Daily; // default value + } + set + { + UpdateSetting("Trakt_UpdateFrequency", ((int)value).ToString()); + } + } + + public static ScheduledUpdateFrequency Trakt_SyncFrequency + { + get + { + NameValueCollection appSettings = ConfigurationManager.AppSettings; + int val = 1; + if (int.TryParse(appSettings["Trakt_SyncFrequency"], out val)) + return (ScheduledUpdateFrequency)val; + else + return ScheduledUpdateFrequency.Daily; // default value + } + set + { + UpdateSetting("Trakt_SyncFrequency", ((int)value).ToString()); + } + } + + public static void UpdateSetting(string key, string value) + { + System.Configuration.Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None); + + if (config.AppSettings.Settings.AllKeys.Contains(key)) + config.AppSettings.Settings[key].Value = value; + else + config.AppSettings.Settings.Add(key, value); + + config.Save(ConfigurationSaveMode.Modified); + ConfigurationManager.RefreshSection("appSettings"); + } + + public static Contract_ServerSettings ToContract() + { + Contract_ServerSettings contract = new Contract_ServerSettings(); + + contract.AniDB_Username = ServerSettings.AniDB_Username; + contract.AniDB_Password = ServerSettings.AniDB_Password; + contract.AniDB_ServerAddress = ServerSettings.AniDB_ServerAddress; + contract.AniDB_ServerPort = ServerSettings.AniDB_ServerPort; + contract.AniDB_ClientPort = ServerSettings.AniDB_ClientPort; + + contract.AniDB_DownloadRelatedAnime = ServerSettings.AniDB_DownloadRelatedAnime; + contract.AniDB_DownloadSimilarAnime = ServerSettings.AniDB_DownloadSimilarAnime; + contract.AniDB_DownloadCharactersCreators = ServerSettings.AniDB_DownloadCharactersCreators; + contract.AniDB_DownloadReviews = ServerSettings.AniDB_DownloadReviews; + contract.AniDB_DownloadReleaseGroups = ServerSettings.AniDB_DownloadReleaseGroups; + + contract.AniDB_MyList_AddFiles = ServerSettings.AniDB_MyList_AddFiles; + contract.AniDB_MyList_StorageState = (int)ServerSettings.AniDB_MyList_StorageState; + contract.AniDB_MyList_ReadWatched = ServerSettings.AniDB_MyList_ReadWatched; + contract.AniDB_MyList_ReadUnwatched = ServerSettings.AniDB_MyList_ReadUnwatched; + contract.AniDB_MyList_SetWatched = ServerSettings.AniDB_MyList_SetWatched; + contract.AniDB_MyList_SetUnwatched = ServerSettings.AniDB_MyList_SetUnwatched; + + contract.AniDB_MyList_UpdateFrequency = (int)ServerSettings.AniDB_MyList_UpdateFrequency; + contract.AniDB_Calendar_UpdateFrequency = (int)ServerSettings.AniDB_Calendar_UpdateFrequency; + contract.AniDB_Anime_UpdateFrequency = (int)ServerSettings.AniDB_Anime_UpdateFrequency; + + // Web Cache + contract.WebCache_Address = ServerSettings.WebCache_Address; + contract.WebCache_Anonymous = ServerSettings.WebCache_Anonymous; + contract.WebCache_FileHashes_Get = ServerSettings.WebCache_FileHashes_Get; + contract.WebCache_FileHashes_Send = ServerSettings.WebCache_FileHashes_Send; + contract.WebCache_XRefFileEpisode_Get = ServerSettings.WebCache_XRefFileEpisode_Get; + contract.WebCache_XRefFileEpisode_Send = ServerSettings.WebCache_XRefFileEpisode_Send; + contract.WebCache_TvDB_Get = ServerSettings.WebCache_TvDB_Get; + contract.WebCache_TvDB_Send = ServerSettings.WebCache_TvDB_Send; + + // TvDB + contract.TvDB_AutoFanart = ServerSettings.TvDB_AutoFanart; + contract.TvDB_AutoFanartAmount = ServerSettings.TvDB_AutoFanartAmount; + contract.TvDB_AutoPosters = ServerSettings.TvDB_AutoPosters; + contract.TvDB_AutoWideBanners = ServerSettings.TvDB_AutoWideBanners; + contract.TvDB_UpdateFrequency = (int)ServerSettings.TvDB_UpdateFrequency; + + // MovieDB + contract.MovieDB_AutoFanart = ServerSettings.MovieDB_AutoFanart; + contract.MovieDB_AutoFanartAmount = ServerSettings.MovieDB_AutoFanartAmount; + contract.MovieDB_AutoPosters = ServerSettings.MovieDB_AutoPosters; + + // Import settings + contract.VideoExtensions = ServerSettings.VideoExtensions; + contract.WatchForNewFiles = ServerSettings.WatchForNewFiles; + contract.Import_UseExistingFileWatchedStatus = ServerSettings.Import_UseExistingFileWatchedStatus; + contract.RunImportOnStart = ServerSettings.RunImportOnStart; + contract.Hash_CRC32 = ServerSettings.Hash_CRC32; + contract.Hash_MD5 = ServerSettings.Hash_MD5; + contract.Hash_SHA1 = ServerSettings.Hash_SHA1; + + // Language + contract.LanguagePreference = ServerSettings.LanguagePreference; + contract.LanguageUseSynonyms = ServerSettings.LanguageUseSynonyms; + + // trakt + contract.Trakt_Username = ServerSettings.Trakt_Username; + contract.Trakt_Password = ServerSettings.Trakt_Password; + contract.Trakt_UpdateFrequency = (int)ServerSettings.Trakt_UpdateFrequency; + contract.Trakt_SyncFrequency = (int)ServerSettings.Trakt_SyncFrequency; + + return contract; + } + } +} diff --git a/JMMServer/StatsCache.cs b/JMMServer/StatsCache.cs new file mode 100644 index 000000000..cd38beb2e --- /dev/null +++ b/JMMServer/StatsCache.cs @@ -0,0 +1,1199 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMServer.Entities; +using JMMServer.Repositories; +using NLog; +using JMMContracts; +using System.Diagnostics; + +namespace JMMServer +{ + public class StatsCache + { + private static Logger logger = LogManager.GetCurrentClassLogger(); + + private static StatsCache _instance; + public static StatsCache Instance + { + get + { + if (_instance == null) + { + _instance = new StatsCache(); + } + return _instance; + } + } + + + + public Dictionary StatGroupCategories = null; // AnimeGroupID / Categories List + public Dictionary StatGroupTitles = null; // AnimeGroupID / Titles List + public Dictionary StatGroupAirDate_Min = null; // AnimeGroupID / AirDate_Min + public Dictionary StatGroupAirDate_Max = null; // AnimeGroupID / AirDate_Max + public Dictionary StatGroupEndDate = null; // AnimeGroupID / EndDate + public Dictionary StatGroupSeriesCreatedDate = null; // AnimeGroupID / SeriesCreatedDate + public Dictionary StatGroupUserVoteOverall = null; // AnimeGroupID / UserVoteOverall + public Dictionary StatGroupUserVotePermanent = null; // AnimeGroupID / UserVotePermanent + public Dictionary StatGroupUserVoteTemporary = null; // AnimeGroupID / UserVoteTemporary + public Dictionary StatGroupIsComplete = null; // AnimeGroupID + public Dictionary StatGroupIsFinishedAiring = null; // AnimeGroupID + public Dictionary StatGroupVideoQuality = null; // AnimeGroupID / Video Quality List + public Dictionary StatGroupVideoQualityEpisodes = null; // AnimeGroupID / Video Quality List + public Dictionary StatGroupAudioLanguages = null; // AnimeGroupID / audio language List + public Dictionary StatGroupSubtitleLanguages = null; // AnimeGroupID / subtitle language List + public Dictionary StatGroupHasTvDB = null; // AnimeGroupID + public Dictionary StatGroupHasMovieDB = null; // AnimeGroupID + public Dictionary StatGroupHasMovieDBOrTvDB = null; // AnimeGroupID + public Dictionary StatGroupSeriesCount = null; // AnimeGroupID + + + public StatsCache() + { + StatGroupCategories = new Dictionary(); + StatGroupTitles = new Dictionary(); + StatGroupAirDate_Min = new Dictionary(); + StatGroupAirDate_Max = new Dictionary(); + StatGroupEndDate = new Dictionary(); + StatGroupSeriesCreatedDate = new Dictionary(); + StatGroupUserVoteOverall = new Dictionary(); + StatGroupUserVotePermanent = new Dictionary(); + StatGroupUserVoteTemporary = new Dictionary(); + StatGroupIsComplete = new Dictionary(); + StatGroupIsFinishedAiring = new Dictionary(); + StatGroupVideoQuality = new Dictionary(); + StatGroupVideoQualityEpisodes = new Dictionary(); + StatGroupAudioLanguages = new Dictionary(); + StatGroupSubtitleLanguages = new Dictionary(); + StatGroupHasTvDB = new Dictionary(); + StatGroupHasMovieDB = new Dictionary(); + StatGroupHasMovieDBOrTvDB = new Dictionary(); + StatGroupSeriesCount = new Dictionary(); + } + + public void UpdateUsingAniDBFile(string hash) + { + try + { + DateTime start = DateTime.Now; + AniDB_FileRepository repAniFile = new AniDB_FileRepository(); + AniDB_File anifile = repAniFile.GetByHash(hash); + if (anifile == null) return; + + UpdateUsingAnime(anifile.AnimeID); + + TimeSpan ts = DateTime.Now - start; + logger.Info("Updated cached stats file ({0}) in {1} ms", hash, ts.TotalMilliseconds); + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + } + + } + + public void UpdateUsingAnime(int animeID) + { + try + { + AniDB_AnimeRepository repAnime = new AniDB_AnimeRepository(); + AniDB_Anime anime = repAnime.GetByAnimeID(animeID); + if (anime == null) return; + + AnimeSeriesRepository repSeries = new AnimeSeriesRepository(); + AnimeSeries ser = repSeries.GetByAnimeID(animeID); + if (ser == null) return; + + UpdateUsingSeries(ser.AnimeSeriesID); + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + } + + } + + /// + /// Use whenever a series is added to or removed from a group + /// + /// + public void UpdateUsingSeries(int animeSeriesID) + { + try + { + + + AnimeSeriesRepository repSeries = new AnimeSeriesRepository(); + AnimeSeries ser = repSeries.GetByID(animeSeriesID); + if (ser == null) return; + + foreach (AnimeGroup grp in ser.AllGroupsAbove) + { + UpdateUsingGroup(grp.AnimeGroupID); + } + + + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + } + } + + public void UpdateUsingGroup(int animeGroupID) + { + try + { + DateTime start = DateTime.Now; + + AnimeGroupRepository repGroups = new AnimeGroupRepository(); + AnimeGroup thisgrp = repGroups.GetByID(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 allgroups = new List(); + allgroups.Add(thisgrp); + + int? groupID = thisgrp.AnimeGroupParentID; + while (groupID.HasValue) + { + AnimeGroup grpTemp = repGroups.GetByID(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; + + 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; + string videoQualityEpisodes = ""; + + List audioLanguages = new List(); + List subtitleLanguages = new List(); + + bool hasTvDB = true; + bool hasMovieDB = true; + bool hasMovieDBOrTvDB = true; + + int seriesCount = 0; + + foreach (AnimeSeries series in grp.AllSeries) + { + seriesCount++; + + // 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 vidQualEpCounts = new Dictionary(); // video quality, count of episodes + + foreach (AnimeEpisode ep in series.AnimeEpisodes) + { + if (ep.EpisodeTypeEnum != AniDBAPI.enEpisodeType.Episode) continue; + + List qualityAddedSoFar = new List(); // handle mutliple files of the same quality for one episode + foreach (VideoLocal vid in ep.VideoLocals) + { + AniDB_File anifile = vid.AniDBFile; + 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.Anime; + foreach (KeyValuePair 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 dicAudio = repAdHoc.GetAudioLanguageStatsByAnime(anime.AnimeID); + foreach (KeyValuePair 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 dicSubtitle = repAdHoc.GetSubtitleLanguageStatsByAnime(anime.AnimeID); + foreach (KeyValuePair 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; + + // 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 + if (series.CrossRefTvDB == null) hasTvDB = false; + if (series.CrossRefMovieDB == null) hasMovieDB = false; + + if (series.CrossRefTvDB == null && series.CrossRefMovieDB == null) hasMovieDBOrTvDB = false; + } + + + StatGroupIsComplete[grp.AnimeGroupID] = isComplete; + StatGroupIsFinishedAiring[grp.AnimeGroupID] = hasFinishedAiring; + StatGroupHasTvDB[grp.AnimeGroupID] = hasTvDB; + StatGroupHasMovieDB[grp.AnimeGroupID] = hasMovieDB; + StatGroupHasMovieDBOrTvDB[grp.AnimeGroupID] = hasMovieDBOrTvDB; + StatGroupSeriesCount[grp.AnimeGroupID] = seriesCount; + + 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; + + 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; + } + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + } + } + + public void InitStats() + { + try + { + + DateTime start = DateTime.Now; + + #region Get the data + AnimeGroupRepository repGroups = new AnimeGroupRepository(); + AniDB_AnimeRepository repAnime = new AniDB_AnimeRepository(); + AnimeSeriesRepository repSeries = new AnimeSeriesRepository(); + AniDB_CategoryRepository repCats = new AniDB_CategoryRepository(); + AniDB_Anime_CategoryRepository repAnimeCat = new AniDB_Anime_CategoryRepository(); + AniDB_Anime_TitleRepository repTitles = new AniDB_Anime_TitleRepository(); + + List allGrps = repGroups.GetAll(); + + Dictionary allGroupsDict = new Dictionary(); + foreach (AnimeGroup agrp in allGrps) + allGroupsDict[agrp.AnimeGroupID] = agrp; + TimeSpan ts = DateTime.Now - start; + logger.Info("Get All GROUPS (Database) in {0} ms", ts.TotalMilliseconds); + + + // anime + start = DateTime.Now; + List allAnime = repAnime.GetAll(); + Dictionary allAnimeDict = new Dictionary(); + foreach (AniDB_Anime anime in allAnime) + allAnimeDict[anime.AnimeID] = anime; + + ts = DateTime.Now - start; + logger.Info("Get All ANIME (Database) in {0} ms", ts.TotalMilliseconds); + + // categories + start = DateTime.Now; + List allCatgeories = repCats.GetAll(); + Dictionary allCatgeoriesDict = new Dictionary(); + foreach (AniDB_Category cat in allCatgeories) + allCatgeoriesDict[cat.CategoryID] = cat; + + + List allAnimeCatgeories = repAnimeCat.GetAll(); + Dictionary> allAnimeCatgeoriesDict = new Dictionary>(); // animeid / list of category id's + foreach (AniDB_Anime_Category aniCat in allAnimeCatgeories) + { + if (!allAnimeCatgeoriesDict.ContainsKey(aniCat.AnimeID)) + allAnimeCatgeoriesDict[aniCat.AnimeID] = new List(); + + allAnimeCatgeoriesDict[aniCat.AnimeID].Add(aniCat.CategoryID); + } + ts = DateTime.Now - start; + logger.Info("Get All CATEGORIES (Database) in {0} ms", ts.TotalMilliseconds); + + // titles + start = DateTime.Now; + List allTitles = repTitles.GetAll(); + Dictionary> allTitlesDict = new Dictionary>(); // animeid / list of titles + foreach (AniDB_Anime_Title aniTitle in allTitles) + { + if (!allTitlesDict.ContainsKey(aniTitle.AnimeID)) + allTitlesDict[aniTitle.AnimeID] = new List(); + + allTitlesDict[aniTitle.AnimeID].Add(aniTitle); + } + ts = DateTime.Now - start; + logger.Info("Get All TITLES (Database) in {0} ms", ts.TotalMilliseconds); + + // user votes + start = DateTime.Now; + AniDB_VoteRepository repVotes = new AniDB_VoteRepository(); + List allVotes = repVotes.GetAll(); + ts = DateTime.Now - start; + logger.Info("Get All VOTES (Database) in {0} ms", ts.TotalMilliseconds); + + // video quality + start = DateTime.Now; + AdhocRepository rep = new AdhocRepository(); + Dictionary allVidQuality = rep.GetAllVideoQualityByGroup(); + + ts = DateTime.Now - start; + logger.Info("Get VIDEO QUALITY STATS (Database) in {0} ms", ts.TotalMilliseconds); + + // video quality episode stats + start = DateTime.Now; + Dictionary dictStats = rep.GetEpisodeVideoQualityStatsByAnime(); + ts = DateTime.Now - start; + logger.Info("Get VIDEO QUALITY EPISODE STATS (Database) in {0} ms", ts.TotalMilliseconds); + + // audio and subtitle language stats + start = DateTime.Now; + Dictionary dictAudioStats = rep.GetAudioLanguageStatsForAnime(); + Dictionary dictSubtitleStats = rep.GetSubtitleLanguageStatsForAnime(); + ts = DateTime.Now - start; + logger.Info("Get LANGUAGE STATS (Database) in {0} ms", ts.TotalMilliseconds); + + start = DateTime.Now; + List allSeries = repSeries.GetAll(); + ts = DateTime.Now - start; + logger.Info("Get All Series (Database) in {0} ms", ts.TotalMilliseconds); + + // TvDB + start = DateTime.Now; + CrossRef_AniDB_TvDBRepository repCrossRef = new CrossRef_AniDB_TvDBRepository(); + List allCrossRefs = repCrossRef.GetAll(); + List animeWithTvDBCrossRef = new List(); + foreach (CrossRef_AniDB_TvDB xref in allCrossRefs) + { + if (!animeWithTvDBCrossRef.Contains(xref.AnimeID)) animeWithTvDBCrossRef.Add(xref.AnimeID); + } + ts = DateTime.Now - start; + logger.Info("Get All AniDB->TvDB Cross Refs (Database) in {0} ms", ts.TotalMilliseconds); + + // MovieDB + start = DateTime.Now; + CrossRef_AniDB_OtherRepository repOtherCrossRef = new CrossRef_AniDB_OtherRepository(); + List allOtherCrossRefs = repOtherCrossRef.GetAll(); + List animeWithMovieCrossRef = new List(); + foreach (CrossRef_AniDB_Other xref in allOtherCrossRefs) + { + if (!animeWithMovieCrossRef.Contains(xref.AnimeID) && xref.CrossRefType == (int)CrossRefType.MovieDB) + animeWithMovieCrossRef.Add(xref.AnimeID); + } + ts = DateTime.Now - start; + logger.Info("Get All AniDB->TvDB Cross Refs (Database) in {0} ms", ts.TotalMilliseconds); + + #endregion + + start = DateTime.Now; + + foreach (AnimeGroup ag in allGrps) + { + // get all the series for this group + List seriesForGroup = new List(); + GetAnimeSeriesRecursive(ag, ref seriesForGroup, allSeries, allGroupsDict); + + if (ag.AnimeGroupID == 166) + { + Console.Write(""); + } + + + DateTime? Stat_AirDate_Min = null; + DateTime? Stat_AirDate_Max = null; + DateTime? Stat_EndDate = new DateTime(1980, 1, 1); + DateTime? Stat_SeriesCreatedDate = null; + bool isComplete = false; + bool hasFinishedAiring = false; + + List categoryIDList = new List(); + List audioLanguageList = new List(); + List subtitleLanguageList = new List(); + string Stat_AllTitles = ""; + string Stat_AllCategories = ""; + string Stat_AllVideoQualityEpisodes = ""; + + + decimal totalVotesPerm = 0, totalVotesTemp = 0, totalVotes = 0; + int countVotesPerm = 0, countVotesTemp = 0, countVotes = 0; + + bool hasTvDB = true; + bool hasMovieDB = true; + bool hasMovieDBOrTvDB = true; + + int seriesCount = 0; + + foreach (AnimeSeries series in seriesForGroup) + { + seriesCount = 0; + if (allAnimeDict.ContainsKey(series.AniDB_ID)) + { + AniDB_Anime thisAnime = allAnimeDict[series.AniDB_ID]; + + // 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 + if (dictStats.ContainsKey(series.AniDB_ID)) + { + if (series.AniDB_ID == 7656) + { + Debug.Print(""); + } + + AnimeVideoQualityStat stat = dictStats[series.AniDB_ID]; + foreach (KeyValuePair kvp in stat.VideoQualityEpisodeCount) + { + if (kvp.Value >= thisAnime.EpisodeCountNormal) + { + if (Stat_AllVideoQualityEpisodes.Length > 0) Stat_AllVideoQualityEpisodes += ","; + Stat_AllVideoQualityEpisodes += kvp.Key; + } + } + } + + // Calculate Air Date + DateTime? thisDate = thisAnime.AirDate; + if (thisDate.HasValue) + { + if (Stat_AirDate_Min.HasValue) + { + if (thisDate.Value < Stat_AirDate_Min.Value) Stat_AirDate_Min = thisDate; + } + else + Stat_AirDate_Min = thisDate; + + if (Stat_AirDate_Max.HasValue) + { + if (thisDate.Value > Stat_AirDate_Max.Value) Stat_AirDate_Max = thisDate; + } + else + Stat_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 = thisAnime.EndDate; + if (thisDate.HasValue && Stat_EndDate.HasValue) + { + if (thisDate.Value > Stat_EndDate.Value) Stat_EndDate = thisDate; + } + else + Stat_EndDate = null; + + // Calculate Series Created Date + thisDate = series.DateTimeCreated; + if (thisDate.HasValue) + { + if (Stat_SeriesCreatedDate.HasValue) + { + if (thisDate.Value < Stat_SeriesCreatedDate.Value) Stat_SeriesCreatedDate = thisDate; + } + else + Stat_SeriesCreatedDate = thisDate; + } + + // Note - only one series has to be finished airing to qualify + if (thisAnime.EndDate.HasValue && thisAnime.EndDate.Value < DateTime.Now) + hasFinishedAiring = 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 (thisAnime.EndDate.HasValue) + { + if (thisAnime.EndDate.Value < DateTime.Now && series.MissingEpisodeCount == 0 && series.MissingEpisodeCountGroups == 0) + { + isComplete = true; + } + } + + // get categories + if (allAnimeCatgeoriesDict.ContainsKey(series.AniDB_ID)) + { + foreach (int catID in allAnimeCatgeoriesDict[series.AniDB_ID]) + { + if (!categoryIDList.Contains(catID)) categoryIDList.Add(catID); + } + } + + // get audio languages + if (dictAudioStats.ContainsKey(series.AniDB_ID)) + { + foreach (string lanName in dictAudioStats[series.AniDB_ID].LanguageNames) + { + if (!audioLanguageList.Contains(lanName)) audioLanguageList.Add(lanName); + } + } + + // get subtitle languages + if (dictSubtitleStats.ContainsKey(series.AniDB_ID)) + { + foreach (string lanName in dictSubtitleStats[series.AniDB_ID].LanguageNames) + { + if (!subtitleLanguageList.Contains(lanName)) subtitleLanguageList.Add(lanName); + } + } + + // get titles + if (allTitlesDict.ContainsKey(series.AniDB_ID)) + { + foreach (AniDB_Anime_Title title in allTitlesDict[series.AniDB_ID]) + { + if (Stat_AllTitles.Length > 0) Stat_AllTitles += ","; + Stat_AllTitles += title.Title; + } + } + + // get votes + foreach (AniDB_Vote vote in allVotes) + { + if (vote.EntityID == series.AniDB_ID && (vote.VoteType == (int)AniDBVoteType.Anime || vote.VoteType == (int)AniDBVoteType.AnimeTemp)) + { + countVotes++; + totalVotes += (decimal)vote.VoteValue; + + if (vote.VoteType == (int)AniDBVoteType.Anime) + { + countVotesPerm++; + totalVotesPerm += (decimal)vote.VoteValue; + } + if (vote.VoteType == (int)AniDBVoteType.AnimeTemp) + { + countVotesTemp++; + totalVotesTemp += (decimal)vote.VoteValue; + } + + break; + } + } + } + + // 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 + if (!animeWithTvDBCrossRef.Contains(series.AniDB_ID)) hasTvDB = false; + if (!animeWithMovieCrossRef.Contains(series.AniDB_ID)) hasMovieDB = false; + + if (!animeWithTvDBCrossRef.Contains(series.AniDB_ID) && !animeWithMovieCrossRef.Contains(series.AniDB_ID)) hasMovieDBOrTvDB = false; + } + + if (allVidQuality.ContainsKey(ag.AnimeGroupID)) + StatGroupVideoQuality[ag.AnimeGroupID] = allVidQuality[ag.AnimeGroupID]; + else + StatGroupVideoQuality[ag.AnimeGroupID] = ""; + + StatGroupVideoQualityEpisodes[ag.AnimeGroupID] = Stat_AllVideoQualityEpisodes; + + StatGroupIsComplete[ag.AnimeGroupID] = isComplete; + StatGroupIsFinishedAiring[ag.AnimeGroupID] = hasFinishedAiring; + + StatGroupSeriesCount[ag.AnimeGroupID] = seriesCount; + + StatGroupTitles[ag.AnimeGroupID] = Stat_AllTitles; + StatGroupAirDate_Max[ag.AnimeGroupID] = Stat_AirDate_Max; + StatGroupAirDate_Min[ag.AnimeGroupID] = Stat_AirDate_Min; + StatGroupEndDate[ag.AnimeGroupID] = Stat_EndDate; + StatGroupSeriesCreatedDate[ag.AnimeGroupID] = Stat_SeriesCreatedDate; + StatGroupHasTvDB[ag.AnimeGroupID] = hasTvDB; + StatGroupHasMovieDB[ag.AnimeGroupID] = hasMovieDB; + StatGroupHasMovieDBOrTvDB[ag.AnimeGroupID] = hasMovieDBOrTvDB; + + decimal? Stat_UserVoteOverall = null; + if (countVotes > 0) + Stat_UserVoteOverall = totalVotes / (decimal)countVotes / (decimal)100; + StatGroupUserVoteOverall[ag.AnimeGroupID] = Stat_UserVoteOverall; + + decimal? Stat_UserVotePermanent = null; + if (countVotesPerm > 0) + Stat_UserVotePermanent = totalVotesPerm / (decimal)countVotesPerm / (decimal)100; + StatGroupUserVotePermanent[ag.AnimeGroupID] = Stat_UserVotePermanent; + + decimal? Stat_UserVoteTemporary = null; + if (countVotesTemp > 0) + Stat_UserVoteTemporary = totalVotesTemp / (decimal)countVotesTemp / (decimal)100; + StatGroupUserVoteTemporary[ag.AnimeGroupID] = Stat_UserVoteTemporary; + + + Stat_AllCategories = ""; + + foreach (int catID in categoryIDList) + { + if (!allCatgeoriesDict.ContainsKey(catID)) continue; + + string catName = allCatgeoriesDict[catID].CategoryName; + if (Stat_AllCategories.Length > 0) + Stat_AllCategories += "|"; + + Stat_AllCategories += catName; + } + this.StatGroupCategories[ag.AnimeGroupID] = Stat_AllCategories; + + string Stat_AudioLanguages = ""; + foreach (string audioLan in audioLanguageList) + { + if (Stat_AudioLanguages.Length > 0) Stat_AudioLanguages += ","; + Stat_AudioLanguages += audioLan; + } + this.StatGroupAudioLanguages[ag.AnimeGroupID] = Stat_AudioLanguages; + + string Stat_SubtitleLanguages = ""; + foreach (string subLan in subtitleLanguageList) + { + if (Stat_SubtitleLanguages.Length > 0) Stat_SubtitleLanguages += ","; + Stat_SubtitleLanguages += subLan; + } + this.StatGroupSubtitleLanguages[ag.AnimeGroupID] = Stat_SubtitleLanguages; + + + } + + + ts = DateTime.Now - start; + logger.Info("GetAllGroups (Contracts) in {0} ms", ts.TotalMilliseconds); + + } + catch (Exception ex) + { + logger.ErrorException(ex.ToString(), ex); + } + } + + private static void GetAnimeSeriesRecursive(AnimeGroup grp, ref List seriesList, List allSeries, Dictionary allGroupsDict) + { + // get the series for this group + List thisSeries = new List(); + foreach (AnimeSeries ser in allSeries) + if (ser.AnimeGroupID == grp.AnimeGroupID) seriesList.Add(ser); + + + foreach (KeyValuePair kvp in allGroupsDict) + { + if (kvp.Value.AnimeGroupParentID.HasValue && kvp.Value.AnimeGroupParentID.Value == grp.AnimeGroupID) + { + GetAnimeSeriesRecursive(kvp.Value, ref seriesList, allSeries, allGroupsDict); + } + } + + /*foreach (AnimeGroup childGroup in grp.ChildGroups) + { + GetAnimeSeriesRecursive(childGroup, ref seriesList, allSeries, allGroupsDict); + }*/ + } + + public bool EvaluateGroupFilter(GroupFilter gf, AnimeGroup grp, JMMUser curUser, AnimeGroup_User userRec) + { + // sub groups don't count + if (grp.AnimeGroupParentID.HasValue) return false; + + // make sure the user has not filtered this out + if (!curUser.AllowedGroup(grp, userRec)) return false; + + // first check for anime groups which are included exluded every time + foreach (GroupFilterCondition gfc in gf.FilterConditions) + { + if (gfc.ConditionTypeEnum != GroupFilterConditionType.AnimeGroup) continue; + + int groupID = 0; + int.TryParse(gfc.ConditionParameter, out groupID); + if (groupID == 0) break; + + if (gfc.ConditionOperatorEnum == GroupFilterOperator.Equals) + if (groupID == grp.AnimeGroupID) return true; + + if (gfc.ConditionOperatorEnum == GroupFilterOperator.NotEquals) + if (groupID == grp.AnimeGroupID) return false; + } + + if (gf.BaseCondition == (int)GroupFilterBaseCondition.Exclude) return false; + + Contract_AnimeGroup contractGroup = grp.ToContract(userRec); + + // now check other conditions + foreach (GroupFilterCondition gfc in gf.FilterConditions) + { + switch (gfc.ConditionTypeEnum) + { + case GroupFilterConditionType.Favourite: + if (userRec == null) return false; + if (gfc.ConditionOperatorEnum == GroupFilterOperator.Include && userRec.IsFave == 0) return false; + if (gfc.ConditionOperatorEnum == GroupFilterOperator.Exclude && userRec.IsFave == 1) return false; + break; + + case GroupFilterConditionType.MissingEpisodes: + if (gfc.ConditionOperatorEnum == GroupFilterOperator.Include && grp.HasMissingEpisodesAny == false) return false; + if (gfc.ConditionOperatorEnum == GroupFilterOperator.Exclude && grp.HasMissingEpisodesAny == true) return false; + break; + + case GroupFilterConditionType.MissingEpisodesCollecting: + if (gfc.ConditionOperatorEnum == GroupFilterOperator.Include && grp.HasMissingEpisodesGroups == false) return false; + if (gfc.ConditionOperatorEnum == GroupFilterOperator.Exclude && grp.HasMissingEpisodesGroups == true) return false; + break; + + case GroupFilterConditionType.HasUnwatchedEpisodes: + if (userRec == null) return false; + if (gfc.ConditionOperatorEnum == GroupFilterOperator.Include && userRec.HasUnwatchedFiles == false) return false; + if (gfc.ConditionOperatorEnum == GroupFilterOperator.Exclude && userRec.HasUnwatchedFiles == true) return false; + break; + + case GroupFilterConditionType.AssignedTvDBInfo: + if (gfc.ConditionOperatorEnum == GroupFilterOperator.Include && contractGroup.Stat_HasTvDBLink == false) return false; + if (gfc.ConditionOperatorEnum == GroupFilterOperator.Exclude && contractGroup.Stat_HasTvDBLink == true) return false; + break; + + case GroupFilterConditionType.AssignedMovieDBInfo: + if (gfc.ConditionOperatorEnum == GroupFilterOperator.Include && contractGroup.Stat_HasMovieDBLink == false) return false; + if (gfc.ConditionOperatorEnum == GroupFilterOperator.Exclude && contractGroup.Stat_HasMovieDBLink == true) return false; + break; + + case GroupFilterConditionType.AssignedTvDBOrMovieDBInfo: + if (gfc.ConditionOperatorEnum == GroupFilterOperator.Include && contractGroup.Stat_HasMovieDBOrTvDBLink == false) return false; + if (gfc.ConditionOperatorEnum == GroupFilterOperator.Exclude && contractGroup.Stat_HasMovieDBOrTvDBLink == true) return false; + break; + + case GroupFilterConditionType.CompletedSeries: + + /*if (grp.IsComplete != grp.Stat_IsComplete) + { + Debug.Print("IsComplete DIFF {0}", grp.GroupName); + }*/ + + if (gfc.ConditionOperatorEnum == GroupFilterOperator.Include && contractGroup.Stat_IsComplete == false) return false; + if (gfc.ConditionOperatorEnum == GroupFilterOperator.Exclude && contractGroup.Stat_IsComplete == true) return false; + break; + + case GroupFilterConditionType.FinishedAiring: + if (gfc.ConditionOperatorEnum == GroupFilterOperator.Include && contractGroup.Stat_HasFinishedAiring == false) return false; + if (gfc.ConditionOperatorEnum == GroupFilterOperator.Exclude && contractGroup.Stat_HasFinishedAiring == true) return false; + break; + + case GroupFilterConditionType.UserVoted: + if (gfc.ConditionOperatorEnum == GroupFilterOperator.Include && contractGroup.Stat_UserVotePermanent.HasValue == false) return false; + if (gfc.ConditionOperatorEnum == GroupFilterOperator.Exclude && contractGroup.Stat_UserVotePermanent.HasValue == true) return false; + break; + + case GroupFilterConditionType.AirDate: + DateTime filterDate; + if (gfc.ConditionOperatorEnum == GroupFilterOperator.LastXDays) + { + int days = 0; + int.TryParse(gfc.ConditionParameter, out days); + filterDate = DateTime.Today.AddDays(0 - days); + } + else + filterDate = GetDateFromString(gfc.ConditionParameter); + + if (gfc.ConditionOperatorEnum == GroupFilterOperator.GreaterThan || gfc.ConditionOperatorEnum == GroupFilterOperator.LastXDays) + { + if (!contractGroup.Stat_AirDate_Min.HasValue || !contractGroup.Stat_AirDate_Max.HasValue) return false; + if (contractGroup.Stat_AirDate_Max.Value < filterDate) return false; + } + if (gfc.ConditionOperatorEnum == GroupFilterOperator.LessThan) + { + if (!contractGroup.Stat_AirDate_Min.HasValue || !contractGroup.Stat_AirDate_Max.HasValue) return false; + if (contractGroup.Stat_AirDate_Min.Value > filterDate) return false; + } + break; + + case GroupFilterConditionType.SeriesCreatedDate: + DateTime filterDateSeries; + if (gfc.ConditionOperatorEnum == GroupFilterOperator.LastXDays) + { + int days = 0; + int.TryParse(gfc.ConditionParameter, out days); + filterDateSeries = DateTime.Today.AddDays(0 - days); + } + else + filterDateSeries = GetDateFromString(gfc.ConditionParameter); + + if (gfc.ConditionOperatorEnum == GroupFilterOperator.GreaterThan || gfc.ConditionOperatorEnum == GroupFilterOperator.LastXDays) + { + if (!contractGroup.Stat_SeriesCreatedDate.HasValue) return false; + if (contractGroup.Stat_SeriesCreatedDate.Value < filterDateSeries) return false; + } + if (gfc.ConditionOperatorEnum == GroupFilterOperator.LessThan) + { + if (!contractGroup.Stat_SeriesCreatedDate.HasValue) return false; + if (contractGroup.Stat_SeriesCreatedDate.Value > filterDateSeries) return false; + } + break; + + case GroupFilterConditionType.EpisodeWatchedDate: + DateTime filterDateEpsiodeWatched; + if (gfc.ConditionOperatorEnum == GroupFilterOperator.LastXDays) + { + int days = 0; + int.TryParse(gfc.ConditionParameter, out days); + filterDateEpsiodeWatched = DateTime.Today.AddDays(0 - days); + } + else + filterDateEpsiodeWatched = GetDateFromString(gfc.ConditionParameter); + + if (gfc.ConditionOperatorEnum == GroupFilterOperator.GreaterThan || gfc.ConditionOperatorEnum == GroupFilterOperator.LastXDays) + { + if (userRec == null) return false; + if (!userRec.WatchedDate.HasValue) return false; + if (userRec.WatchedDate.Value < filterDateEpsiodeWatched) return false; + } + if (gfc.ConditionOperatorEnum == GroupFilterOperator.LessThan) + { + if (userRec == null) return false; + if (!userRec.WatchedDate.HasValue) return false; + if (userRec.WatchedDate.Value > filterDateEpsiodeWatched) return false; + } + break; + + case GroupFilterConditionType.EpisodeAddedDate: + DateTime filterDateEpisodeAdded; + if (gfc.ConditionOperatorEnum == GroupFilterOperator.LastXDays) + { + int days = 0; + int.TryParse(gfc.ConditionParameter, out days); + filterDateEpisodeAdded = DateTime.Today.AddDays(0 - days); + } + else + filterDateEpisodeAdded = GetDateFromString(gfc.ConditionParameter); + + if (gfc.ConditionOperatorEnum == GroupFilterOperator.GreaterThan || gfc.ConditionOperatorEnum == GroupFilterOperator.LastXDays) + { + if (!grp.EpisodeAddedDate.HasValue) return false; + if (grp.EpisodeAddedDate.Value < filterDateEpisodeAdded) return false; + } + if (gfc.ConditionOperatorEnum == GroupFilterOperator.LessThan) + { + if (!grp.EpisodeAddedDate.HasValue) return false; + if (grp.EpisodeAddedDate.Value > filterDateEpisodeAdded) return false; + } + break; + + case GroupFilterConditionType.AniDBRating: + + decimal dRating = -1; + decimal.TryParse(gfc.ConditionParameter, out dRating); + + if (gfc.ConditionOperatorEnum == GroupFilterOperator.GreaterThan && grp.AniDBRating < dRating) return false; + if (gfc.ConditionOperatorEnum == GroupFilterOperator.LessThan && grp.AniDBRating > dRating) return false; + break; + + case GroupFilterConditionType.UserRating: + + if (!contractGroup.Stat_UserVoteOverall.HasValue) return false; + + decimal dUserRating = -1; + decimal.TryParse(gfc.ConditionParameter, out dUserRating); + + if (gfc.ConditionOperatorEnum == GroupFilterOperator.GreaterThan && contractGroup.Stat_UserVoteOverall.Value < dUserRating) return false; + if (gfc.ConditionOperatorEnum == GroupFilterOperator.LessThan && contractGroup.Stat_UserVoteOverall.Value > dUserRating) return false; + break; + + case GroupFilterConditionType.Category: + + string filterParm = gfc.ConditionParameter.Trim(); + + string[] cats = filterParm.Split(','); + bool foundCat = false; + int index = 0; + foreach (string cat in cats) + { + if (cat.Trim().Length == 0) continue; + if (cat.Trim() == ",") continue; + + index = contractGroup.Stat_AllCategories.IndexOf(cat, 0, StringComparison.InvariantCultureIgnoreCase); + if (index > -1) + { + foundCat = true; + break; + } + } + + if (gfc.ConditionOperatorEnum == GroupFilterOperator.In) + if (!foundCat) return false; + + if (gfc.ConditionOperatorEnum == GroupFilterOperator.NotIn) + if (foundCat) return false; + break; + + case GroupFilterConditionType.AnimeType: + + filterParm = gfc.ConditionParameter.Trim(); + List grpTypeList = grp.AnimeTypesList; + + string[] atypes = filterParm.Split(','); + bool foundAnimeType = false; + index = 0; + foreach (string atype in atypes) + { + if (atype.Trim().Length == 0) continue; + if (atype.Trim() == ",") continue; + + foreach (string thisAType in grpTypeList) + { + if (string.Equals(thisAType, atype, StringComparison.InvariantCultureIgnoreCase)) + { + foundAnimeType = true; + break; + } + } + } + + if (gfc.ConditionOperatorEnum == GroupFilterOperator.In) + if (!foundAnimeType) return false; + + if (gfc.ConditionOperatorEnum == GroupFilterOperator.NotIn) + if (foundAnimeType) return false; + break; + + + + case GroupFilterConditionType.VideoQuality: + + filterParm = gfc.ConditionParameter.Trim(); + + string[] vidQuals = filterParm.Split(','); + bool foundVid = false; + bool foundVidAllEps = false; + index = 0; + foreach (string vidq in vidQuals) + { + if (vidq.Trim().Length == 0) continue; + if (vidq.Trim() == ",") continue; + + index = contractGroup.Stat_AllVideoQuality.IndexOf(vidq, 0, StringComparison.InvariantCultureIgnoreCase); + if (index > -1) foundVid = true; + + index = contractGroup.Stat_AllVideoQuality_Episodes.IndexOf(vidq, 0, StringComparison.InvariantCultureIgnoreCase); + if (index > -1) foundVidAllEps = true; + + } + + if (gfc.ConditionOperatorEnum == GroupFilterOperator.In) + if (!foundVid) return false; + + if (gfc.ConditionOperatorEnum == GroupFilterOperator.NotIn) + if (foundVid) return false; + + if (gfc.ConditionOperatorEnum == GroupFilterOperator.InAllEpisodes) + if (!foundVidAllEps) return false; + + if (gfc.ConditionOperatorEnum == GroupFilterOperator.NotInAllEpisodes) + if (foundVidAllEps) return false; + + break; + + case GroupFilterConditionType.AudioLanguage: + case GroupFilterConditionType.SubtitleLanguage: + + filterParm = gfc.ConditionParameter.Trim(); + + string[] languages = filterParm.Split(','); + bool foundLan = false; + index = 0; + foreach (string lanName in languages) + { + if (lanName.Trim().Length == 0) continue; + if (lanName.Trim() == ",") continue; + + if (gfc.ConditionTypeEnum == GroupFilterConditionType.AudioLanguage) + index = contractGroup.Stat_AudioLanguages.IndexOf(lanName, 0, StringComparison.InvariantCultureIgnoreCase); + + if (gfc.ConditionTypeEnum == GroupFilterConditionType.SubtitleLanguage) + index = contractGroup.Stat_SubtitleLanguages.IndexOf(lanName, 0, StringComparison.InvariantCultureIgnoreCase); + + if (index > -1) foundLan = true; + + } + + if (gfc.ConditionOperatorEnum == GroupFilterOperator.In) + if (!foundLan) return false; + + if (gfc.ConditionOperatorEnum == GroupFilterOperator.NotIn) + if (foundLan) return false; + + break; + } + } + + return true; + } + + public static DateTime GetDateFromString(string sDate) + { + try + { + int year = int.Parse(sDate.Substring(0, 4)); + int month = int.Parse(sDate.Substring(4, 2)); + int day = int.Parse(sDate.Substring(6, 2)); + + return new DateTime(year, month, day); + } + catch (Exception ex) + { + return DateTime.Today; + } + } + + /*private static void GetAnimeSeriesRecursive(int animeGroupID, ref List seriesList, List allSeries) + { + AnimeGroupRepository rep = new AnimeGroupRepository(); + AnimeGroup grp = rep.GetByID(animeGroupID); + if (grp == null) return; + + // get the series for this group + List thisSeries = new List(); + foreach (AnimeSeries ser in allSeries) + if (ser.AnimeGroupID == animeGroupID) seriesList.Add(ser); + + + foreach (AnimeGroup childGroup in grp.ChildGroups) + { + GetAnimeSeriesRecursive(childGroup.AnimeGroupID, ref seriesList, allSeries); + } + }*/ + } +} diff --git a/JMMServer/UI/HyperLinkStandard.xaml b/JMMServer/UI/HyperLinkStandard.xaml new file mode 100644 index 000000000..e7a669654 --- /dev/null +++ b/JMMServer/UI/HyperLinkStandard.xaml @@ -0,0 +1,18 @@ + + + + + + + + + + + + diff --git a/JMMServer/UI/HyperLinkStandard.xaml.cs b/JMMServer/UI/HyperLinkStandard.xaml.cs new file mode 100644 index 000000000..09c4586e3 --- /dev/null +++ b/JMMServer/UI/HyperLinkStandard.xaml.cs @@ -0,0 +1,67 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; +using System.Diagnostics; + +namespace JMMServer +{ + /// + /// Interaction logic for HyperLinkStandard.xaml + /// + public partial class HyperLinkStandard : UserControl + { + public static readonly DependencyProperty DisplayTextProperty = DependencyProperty.Register("DisplayText", + typeof(string), typeof(HyperLinkStandard), new UIPropertyMetadata("", displayTextChangedCallback)); + + public static readonly DependencyProperty URLProperty = DependencyProperty.Register("URL", + typeof(string), typeof(HyperLinkStandard), new UIPropertyMetadata("", urlChangedCallback)); + + public string DisplayText + { + get { return (string)GetValue(DisplayTextProperty); } + set { SetValue(DisplayTextProperty, value); } + } + + private static void displayTextChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + HyperLinkStandard input = (HyperLinkStandard)d; + input.txtLink.Text = e.NewValue as string; + } + + public string URL + { + get { return (string)GetValue(URLProperty); } + set { SetValue(URLProperty, value); } + } + + private static void urlChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + //HyperLinkStandard input = (HyperLinkStandard)d; + + } + + public HyperLinkStandard() + { + InitializeComponent(); + + hlURL.Click += new RoutedEventHandler(hlURL_Click); + } + + void hlURL_Click(object sender, RoutedEventArgs e) + { + Uri uri = new Uri(URL); + Process.Start(new ProcessStartInfo(uri.AbsoluteUri)); + e.Handled = true; + } + } +} diff --git a/JMMServer/UI/ImportFolderAdmin.xaml b/JMMServer/UI/ImportFolderAdmin.xaml new file mode 100644 index 000000000..1d95abea3 --- /dev/null +++ b/JMMServer/UI/ImportFolderAdmin.xaml @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/JMMServer/UI/ImportFolderAdmin.xaml.cs b/JMMServer/UI/ImportFolderAdmin.xaml.cs new file mode 100644 index 000000000..c6f464e6d --- /dev/null +++ b/JMMServer/UI/ImportFolderAdmin.xaml.cs @@ -0,0 +1,100 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; +using JMMServer.Entities; +using JMMServer.Repositories; + +namespace JMMServer +{ + /// + /// Interaction logic for ImportFolderAdmin.xaml + /// + public partial class ImportFolderAdmin : UserControl + { + public ImportFolderAdmin() + { + InitializeComponent(); + + btnAddImportFolder.Click += new RoutedEventHandler(btnAddImportFolder_Click); + btnDeleteImportFolder.Click += new RoutedEventHandler(btnDeleteImportFolder_Click); + lbImportFolders.MouseDoubleClick += new MouseButtonEventHandler(lbImportFolders_MouseDoubleClick); + } + + void lbImportFolders_MouseDoubleClick(object sender, MouseButtonEventArgs e) + { + object obj = lbImportFolders.SelectedItem; + if (obj == null) return; + + ImportFolder ns = (ImportFolder)obj; + ImportFolderForm frm = new ImportFolderForm(); + frm.Owner = GetTopParent(); + frm.Init(ns); + bool? result = frm.ShowDialog(); + } + + void btnDeleteImportFolder_Click(object sender, RoutedEventArgs e) + { + object obj = lbImportFolders.SelectedItem; + if (obj == null) return; + + try + { + if (obj.GetType() == typeof(ImportFolder)) + { + ImportFolder ns = (ImportFolder)obj; + + MessageBoxResult res = MessageBox.Show(string.Format("Are you sure you want to delete the Import Folder: {0}", ns.ImportFolderLocation), "Confirm", MessageBoxButton.YesNo, MessageBoxImage.Question); + if (res == MessageBoxResult.Yes) + { + ImportFolderRepository repFolders = new ImportFolderRepository(); + repFolders.Delete(ns.ImportFolderID); + ServerInfo.Instance.RefreshImportFolders(); + } + } + } + catch (Exception ex) + { + Utils.ShowErrorMessage(ex); + } + } + + void btnAddImportFolder_Click(object sender, RoutedEventArgs e) + { + try + { + ImportFolderForm frm = new ImportFolderForm(); + frm.Owner = GetTopParent(); + frm.Init(new ImportFolder()); + bool? result = frm.ShowDialog(); + + ServerInfo.Instance.RefreshImportFolders(); + } + catch (Exception ex) + { + Utils.ShowErrorMessage(ex); + } + } + + private Window GetTopParent() + { + DependencyObject dpParent = this.Parent; + do + { + dpParent = LogicalTreeHelper.GetParent(dpParent); + } + while (dpParent.GetType().BaseType != typeof(Window)); + + return dpParent as Window; + } + } +} diff --git a/JMMServer/UI/ImportFolderForm.xaml b/JMMServer/UI/ImportFolderForm.xaml new file mode 100644 index 000000000..3de7ea088 --- /dev/null +++ b/JMMServer/UI/ImportFolderForm.xaml @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/JMMServer/UI/ImportFolderForm.xaml.cs b/JMMServer/UI/ImportFolderForm.xaml.cs new file mode 100644 index 000000000..2c9fce50f --- /dev/null +++ b/JMMServer/UI/ImportFolderForm.xaml.cs @@ -0,0 +1,101 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Shapes; +using JMMServer.Entities; +using JMMServer; +using JMMServer.Repositories; + +namespace JMMServer +{ + /// + /// Interaction logic for ImportFolder.xaml + /// + public partial class ImportFolderForm : Window + { + private ImportFolder importFldr = null; + + public ImportFolderForm() + { + InitializeComponent(); + + btnCancel.Click += new RoutedEventHandler(btnCancel_Click); + btnSave.Click += new RoutedEventHandler(btnSave_Click); + } + + void btnSave_Click(object sender, RoutedEventArgs e) + { + try + { + // An import folder cannot be both the drop source and the drop destination + if (chkDropDestination.IsChecked.HasValue && chkDropSource.IsChecked.HasValue && chkDropDestination.IsChecked.Value && chkDropSource.IsChecked.Value) + { + MessageBox.Show("An import folder cannot be both the drop source and the drop destination", "Error", MessageBoxButton.OK, MessageBoxImage.Error); + return; + } + + // The import folder location cannot be blank. Enter a valid path on OMM Server + if (string.IsNullOrEmpty(txtImportFolderLocation.Text)) + { + MessageBox.Show("The import folder location cannot be blank. Enter a valid path on OMM Server", "Error", MessageBoxButton.OK, MessageBoxImage.Error); + txtImportFolderLocation.Focus(); + return; + } + + if (string.IsNullOrEmpty(txtImportFolderName.Text)) + importFldr.ImportFolderName = "NA"; + else + importFldr.ImportFolderName = txtImportFolderName.Text.Trim(); + + importFldr.ImportFolderLocation = txtImportFolderLocation.Text.Trim(); + importFldr.IsDropDestination = chkDropDestination.IsChecked.Value ? 1 : 0; + importFldr.IsDropSource = chkDropSource.IsChecked.Value ? 1 : 0; + + ImportFolderRepository repFolders = new ImportFolderRepository(); + repFolders.Save(importFldr); + + //JMMServerVM.Instance.RefreshImportFolders(); + } + catch (Exception ex) + { + Utils.ShowErrorMessage(ex); + } + + this.DialogResult = true; + this.Close(); + } + + void btnCancel_Click(object sender, RoutedEventArgs e) + { + this.DialogResult = false; + this.Close(); + } + + public void Init(ImportFolder ifldr) + { + try + { + importFldr = ifldr; + + txtImportFolderLocation.Text = importFldr.ImportFolderLocation; + txtImportFolderName.Text = importFldr.ImportFolderName; + chkDropDestination.IsChecked = importFldr.IsDropDestination == 1; + chkDropSource.IsChecked = importFldr.IsDropSource == 1; + + txtImportFolderName.Focus(); + } + catch (Exception ex) + { + Utils.ShowErrorMessage(ex); + } + } + } +} diff --git a/JMMServer/UI/ServerInfo.cs b/JMMServer/UI/ServerInfo.cs new file mode 100644 index 000000000..fe2b2fc08 --- /dev/null +++ b/JMMServer/UI/ServerInfo.cs @@ -0,0 +1,267 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.ComponentModel; +using System.Collections.ObjectModel; +using JMMServer.Entities; +using JMMServer.Repositories; + +namespace JMMServer +{ + public class ServerInfo : INotifyPropertyChanged + { + private static ServerInfo _instance; + public static ServerInfo Instance + { + get + { + if (_instance == null) + { + _instance = new ServerInfo(); + _instance.Init(); + } + return _instance; + } + } + + public event PropertyChangedEventHandler PropertyChanged; + protected virtual void OnPropertyChanged(PropertyChangedEventArgs e) + { + PropertyChangedEventHandler handler = PropertyChanged; + if (handler != null) + { + handler(this, e); + } + } + + private ServerInfo() + { + ImportFolders = new ObservableCollection(); + } + + private void Init() + { + //RefreshImportFolders(); + + JMMService.CmdProcessorGeneral.OnQueueCountChangedEvent += new Commands.CommandProcessorGeneral.QueueCountChangedHandler(CmdProcessorGeneral_OnQueueCountChangedEvent); + JMMService.CmdProcessorGeneral.OnQueueStateChangedEvent += new Commands.CommandProcessorGeneral.QueueStateChangedHandler(CmdProcessorGeneral_OnQueueStateChangedEvent); + + JMMService.CmdProcessorHasher.OnQueueCountChangedEvent += new Commands.CommandProcessorHasher.QueueCountChangedHandler(CmdProcessorHasher_OnQueueCountChangedEvent); + JMMService.CmdProcessorHasher.OnQueueStateChangedEvent += new Commands.CommandProcessorHasher.QueueStateChangedHandler(CmdProcessorHasher_OnQueueStateChangedEvent); + + JMMService.CmdProcessorImages.OnQueueCountChangedEvent += new Commands.CommandProcessorImages.QueueCountChangedHandler(CmdProcessorImages_OnQueueCountChangedEvent); + JMMService.CmdProcessorImages.OnQueueStateChangedEvent += new Commands.CommandProcessorImages.QueueStateChangedHandler(CmdProcessorImages_OnQueueStateChangedEvent); + } + + void CmdProcessorImages_OnQueueStateChangedEvent(Commands.QueueStateEventArgs ev) + { + ImagesQueueState = ev.QueueState; + } + + void CmdProcessorImages_OnQueueCountChangedEvent(Commands.QueueCountEventArgs ev) + { + ImagesQueueCount = ev.QueueCount; + } + + void CmdProcessorHasher_OnQueueStateChangedEvent(Commands.QueueStateEventArgs ev) + { + HasherQueueState = ev.QueueState; + } + + void CmdProcessorHasher_OnQueueCountChangedEvent(Commands.QueueCountEventArgs ev) + { + HasherQueueCount = ev.QueueCount; + } + + void CmdProcessorGeneral_OnQueueStateChangedEvent(Commands.QueueStateEventArgs ev) + { + GeneralQueueState = ev.QueueState; + } + + void CmdProcessorGeneral_OnQueueCountChangedEvent(Commands.QueueCountEventArgs ev) + { + GeneralQueueCount = ev.QueueCount; + } + + #region Observable Properties + + private int hasherQueueCount = 0; + public int HasherQueueCount + { + get { return hasherQueueCount; } + set + { + hasherQueueCount = value; + OnPropertyChanged(new PropertyChangedEventArgs("HasherQueueCount")); + } + } + + private string hasherQueueState = ""; + public string HasherQueueState + { + get { return hasherQueueState; } + set + { + hasherQueueState = value; + OnPropertyChanged(new PropertyChangedEventArgs("HasherQueueState")); + } + } + + private int imagesQueueCount = 0; + public int ImagesQueueCount + { + get { return imagesQueueCount; } + set + { + imagesQueueCount = value; + OnPropertyChanged(new PropertyChangedEventArgs("ImagesQueueCount")); + } + } + + private string imagesQueueState = ""; + public string ImagesQueueState + { + get { return imagesQueueState; } + set + { + imagesQueueState = value; + OnPropertyChanged(new PropertyChangedEventArgs("ImagesQueueState")); + } + } + + private int generalQueueCount = 0; + public int GeneralQueueCount + { + get { return generalQueueCount; } + set + { + generalQueueCount = value; + OnPropertyChanged(new PropertyChangedEventArgs("GeneralQueueCount")); + } + } + + private string generalQueueState = ""; + public string GeneralQueueState + { + get { return generalQueueState; } + set + { + generalQueueState = value; + OnPropertyChanged(new PropertyChangedEventArgs("GeneralQueueState")); + } + } + + private bool hasherQueuePaused = false; + public bool HasherQueuePaused + { + get { return hasherQueuePaused; } + set + { + hasherQueuePaused = value; + OnPropertyChanged(new PropertyChangedEventArgs("HasherQueuePaused")); + } + } + + private bool hasherQueueRunning = true; + public bool HasherQueueRunning + { + get { return hasherQueueRunning; } + set + { + hasherQueueRunning = value; + OnPropertyChanged(new PropertyChangedEventArgs("HasherQueueRunning")); + } + } + + private bool generalQueuePaused = false; + public bool GeneralQueuePaused + { + get { return generalQueuePaused; } + set + { + generalQueuePaused = value; + OnPropertyChanged(new PropertyChangedEventArgs("GeneralQueuePaused")); + } + } + + private bool generalQueueRunning = true; + public bool GeneralQueueRunning + { + get { return generalQueueRunning; } + set + { + generalQueueRunning = value; + OnPropertyChanged(new PropertyChangedEventArgs("GeneralQueueRunning")); + } + } + + private bool imagesQueuePaused = false; + public bool ImagesQueuePaused + { + get { return imagesQueuePaused; } + set + { + imagesQueuePaused = value; + OnPropertyChanged(new PropertyChangedEventArgs("ImagesQueuePaused")); + } + } + + private bool imagesQueueRunning = true; + public bool ImagesQueueRunning + { + get { return imagesQueueRunning; } + set + { + imagesQueueRunning = value; + OnPropertyChanged(new PropertyChangedEventArgs("ImagesQueueRunning")); + } + } + + private string banReason = ""; + public string BanReason + { + get { return banReason; } + set + { + banReason = value; + OnPropertyChanged(new PropertyChangedEventArgs("BanReason")); + } + } + + private bool isBanned = false; + public bool IsBanned + { + get { return isBanned; } + set + { + isBanned = value; + OnPropertyChanged(new PropertyChangedEventArgs("IsBanned")); + } + } + + public ObservableCollection ImportFolders { get; set; } + + public void RefreshImportFolders() + { + ImportFolders.Clear(); + + try + { + ImportFolderRepository repFolders = new ImportFolderRepository(); + List fldrs = repFolders.GetAll(); + + foreach (ImportFolder ifolder in fldrs) + ImportFolders.Add(ifolder); + + } + catch (Exception ex) + { + Utils.ShowErrorMessage(ex); + } + + } + + #endregion + } +} diff --git a/JMMServer/UI/UIStyles.xaml b/JMMServer/UI/UIStyles.xaml new file mode 100644 index 000000000..09a813bb7 --- /dev/null +++ b/JMMServer/UI/UIStyles.xaml @@ -0,0 +1,243 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/JMMServer/Utils.cs b/JMMServer/Utils.cs new file mode 100644 index 000000000..89d33a35f --- /dev/null +++ b/JMMServer/Utils.cs @@ -0,0 +1,608 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Runtime.InteropServices; +using System.Net; +using System.IO; +using System.Reflection; +using System.Diagnostics; +using System.Windows.Forms; +using NLog; +using System.Security.Cryptography; + +namespace JMMServer +{ + public class Utils + { + public const int LastYear = 2050; + + private static Logger logger = LogManager.GetCurrentClassLogger(); + + public static string CalculateSHA1(string text, Encoding enc) + { + byte[] buffer = enc.GetBytes(text); + SHA1CryptoServiceProvider cryptoTransformSHA1 = + new SHA1CryptoServiceProvider(); + string hash = BitConverter.ToString(cryptoTransformSHA1.ComputeHash(buffer)).Replace("-", ""); + + return hash; + } + + /// + /// Compute Levenshtein distance --- http://www.merriampark.com/ldcsharp.htm + /// + /// + /// + /// + public static int LevenshteinDistance(string s, string t) + { + int n = s.Length; //length of s + int m = t.Length; //length of t + + int[,] d = new int[n + 1, m + 1]; // matrix + + int cost; // cost + + // Step 1 + if (n == 0) return m; + if (m == 0) return n; + + // Step 2 + for (int i = 0; i <= n; d[i, 0] = i++) ; + for (int j = 0; j <= m; d[0, j] = j++) ; + + // Step 3 + for (int i = 1; i <= n; i++) + { + //Step 4 + for (int j = 1; j <= m; j++) + { + // Step 5 + cost = (t.Substring(j - 1, 1) == s.Substring(i - 1, 1) ? 0 : 1); + + // Step 6 + d[i, j] = System.Math.Min(System.Math.Min(d[i - 1, j] + 1, d[i, j - 1] + 1), + d[i - 1, j - 1] + cost); + } + } + + // Step 7 + return d[n, m]; + } + + // Function to display parent function + public static string GetParentMethodName() + { + StackTrace stackTrace = new StackTrace(); + StackFrame stackFrame = stackTrace.GetFrame(2); + MethodBase methodBase = stackFrame.GetMethod(); + return methodBase.Name; + } + + public static void ShowErrorMessage(Exception ex) + { + MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + logger.ErrorException(ex.ToString(), ex); + } + + public static void ShowErrorMessage(string msg) + { + MessageBox.Show(msg, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + logger.Error(msg); + } + + public static string GetApplicationVersion(Assembly a) + { + AssemblyName an = a.GetName(); + return an.Version.ToString(); + } + + + public static string DownloadWebPage(string url) + { + try + { + //BaseConfig.MyAnimeLog.Write("DownloadWebPage called by: {0} - {1}", GetParentMethodName(), url); + + HttpWebRequest webReq = (HttpWebRequest)WebRequest.Create(url); + webReq.Timeout = 30000; // 30 seconds + webReq.Proxy = null; + webReq.Headers.Add(HttpRequestHeader.AcceptEncoding, "gzip,deflate"); + webReq.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate; + + HttpWebResponse WebResponse = (HttpWebResponse)webReq.GetResponse(); + + Stream responseStream = WebResponse.GetResponseStream(); + String enco = WebResponse.CharacterSet; + Encoding encoding = null; + if (!String.IsNullOrEmpty(enco)) + encoding = Encoding.GetEncoding(WebResponse.CharacterSet); + if (encoding == null) + encoding = Encoding.Default; + StreamReader Reader = new StreamReader(responseStream, encoding); + + string output = Reader.ReadToEnd(); + + //BaseConfig.MyAnimeLog.Write("DownloadWebPage: {0}", output); + + WebResponse.Close(); + responseStream.Close(); + + return output; + } + catch (Exception ex) + { + string msg = "---------- ERROR IN DOWNLOAD WEB PAGE ---------" + Environment.NewLine + + url + Environment.NewLine + + ex.ToString() + Environment.NewLine + "------------------------------------"; + //BaseConfig.MyAnimeLog.Write(msg); + + // if the error is a 404 error it may mean that there is a bad series association + // so lets log it to the web cache so we can investigate + if (ex.ToString().Contains("(404) Not Found")) + { + } + + return ""; + } + } + + public static Stream DownloadWebBinary(string url) + { + try + { + HttpWebResponse response = null; + HttpWebRequest webReq = (HttpWebRequest)WebRequest.Create(url); + // Note: some network proxies require the useragent string to be set or they will deny the http request + // this is true for instance for EVERY thailand internet connection (also needs to be set for banners/episodethumbs and any other http request we send) + webReq.UserAgent = "Anime2MP"; + webReq.Timeout = 20000; // 20 seconds + response = (HttpWebResponse)webReq.GetResponse(); + + if (response != null) // Get the stream associated with the response. + return response.GetResponseStream(); + else + return null; + } + catch (Exception ex) + { + //BaseConfig.MyAnimeLog.Write(ex.ToString()); + return null; + } + } + + public static string GetAniDBDate(int secs) + { + if (secs == 0) return ""; + + DateTime thisDate = new DateTime(1970, 1, 1, 0, 0, 0); + thisDate = thisDate.AddSeconds(secs); + return thisDate.ToString("dd MMM yyyy", Globals.Culture); + } + + public static DateTime? GetAniDBDateAsDate(int secs) + { + if (secs == 0) return null; + + DateTime thisDate = new DateTime(1970, 1, 1, 0, 0, 0); + thisDate = thisDate.AddSeconds(secs); + return thisDate; + } + + public static int GetAniDBDateAsSeconds(string dateXML) + { + // eg "2008-12-31" or "2008-12" or "2008" + if (dateXML.Trim().Length < 4) return 0; + + string month = "1"; + string day = "1"; + + string year = dateXML.Trim().Substring(0, 4); + + if (dateXML.Trim().Length > 4) + month = dateXML.Trim().Substring(5, 2); + + if (dateXML.Trim().Length > 7) + day = dateXML.Trim().Substring(8, 2); + + //BaseConfig.MyAnimeLog.Write("Date = {0}/{1}/{2}", year, month, day); + + + DateTime actualDate = new DateTime(int.Parse(year), int.Parse(month), int.Parse(day), 0, 0, 0); + //startDate = startDate.AddDays(-1); + + return GetAniDBDateAsSeconds(actualDate); + } + + public static DateTime? GetAniDBDateAsDate(string dateInSeconds, int dateFlags) + { + // DateFlags + // 0 = normal start and end date (2010-01-31) + // 1 = start date is year-month (2010-01) + // 2 = start date is a year (2010) + // 4 = normal start date, year-month end date + // 8 = normal start date, year end date + // 10 = start date is a year (2010) + // 16 = normal start and end date (2010-01-31) + + double secs = 0; + double.TryParse(dateInSeconds, out secs); + if (secs == 0) return null; + + DateTime thisDate = new DateTime(1970, 1, 1, 0, 0, 0); + thisDate = thisDate.AddSeconds(secs); + + // reconstruct using date flags + int year = thisDate.Year; + int month = thisDate.Month; + int day = thisDate.Day; + + if (dateFlags == 2 || dateFlags == 10 || dateFlags == 1) + month = 1; + + if (dateFlags == 1) + day = 1; + + return new DateTime(year, month, day, 0, 0, 0); ; + } + + public static int GetAniDBDateAsSeconds(DateTime? dtDate) + { + if (!dtDate.HasValue) return 0; + + DateTime startDate = new DateTime(1970, 1, 1, 0, 0, 0); + TimeSpan ts = dtDate.Value - startDate; + + return (int)ts.TotalSeconds; + } + + public static string AniDBDate(DateTime date) + { + TimeSpan sp = date.Subtract(new DateTime(1970, 1, 1, 0, 0, 0)); + return ((long)sp.TotalSeconds).ToString(); + } + + private static string[] escapes = { "SOURCE", "TAKEN", "FROM", "HTTP", "ANN", "ANIMENFO", "ANIDB", "ANIMESUKI" }; + + public static string ReparseDescription(string description) + { + if (description == null || description.Length == 0) return ""; + + string val = description; + val = val.Replace("
", Environment.NewLine).Replace("
", Environment.NewLine).Replace("", ""). + Replace("", "").Replace("", "").Replace("", "").Replace("[i]", "").Replace("[/i]", ""). + Replace("[b]", "").Replace("[/b]", ""); + val = val.Replace("
", Environment.NewLine).Replace("
", Environment.NewLine).Replace("", "").Replace("", "").Replace("", "").Replace("", "").Replace("[I]", "").Replace("[/I]", ""). + Replace("[B]", "").Replace("[/B]", ""); + + string vup = val.ToUpper(); + while ((vup.Contains("[URL")) || (vup.Contains("[/URL]"))) + { + int a = vup.IndexOf("[URL"); + if (a >= 0) + { + int b = vup.IndexOf("]", a + 1); + if (b >= 0) + { + val = val.Substring(0, a) + val.Substring(b + 1); + vup = val.ToUpper(); + } + } + a = vup.IndexOf("[/URL]"); + if (a >= 0) + { + val = val.Substring(0, a) + val.Substring(a + 6); + vup = val.ToUpper(); + } + } + while (vup.Contains("HTTP:")) + { + int a = vup.IndexOf("HTTP:"); + if (a >= 0) + { + int b = vup.IndexOf(" ", a + 1); + if (b >= 0) + { + if (vup[b + 1] == '[') + { + int c = vup.IndexOf("]", b + 1); + val = val.Substring(0, a) + " " + val.Substring(b + 2, c - b - 2) + val.Substring(c + 1); + } + else + { + val = val.Substring(0, a) + val.Substring(b); + } + vup = val.ToUpper(); + } + else + { + break; + } + } + } + int d = -1; + do + { + if (d + 1 >= vup.Length) + break; + d = vup.IndexOf("[", d + 1); + if (d != -1) + { + int b = vup.IndexOf("]", d + 1); + if (b != -1) + { + string cont = vup.Substring(d, b - d); + bool dome = false; + foreach (string s in escapes) + { + if (cont.Contains(s)) + { + dome = true; + break; + } + } + if (dome) + { + val = val.Substring(0, d) + val.Substring(b + 1); + vup = val.ToUpper(); + } + } + } + } while (d != -1); + d = -1; + do + { + if (d + 1 >= vup.Length) + break; + + d = vup.IndexOf("(", d + 1); + if (d != -1) + { + int b = vup.IndexOf(")", d + 1); + if (b != -1) + { + string cont = vup.Substring(d, b - d); + bool dome = false; + foreach (string s in escapes) + { + if (cont.Contains(s)) + { + dome = true; + break; + } + } + if (dome) + { + val = val.Substring(0, d) + val.Substring(b + 1); + vup = val.ToUpper(); + } + } + } + } while (d != -1); + d = vup.IndexOf("SOURCE:"); + if (d == -1) + d = vup.IndexOf("SOURCE :"); + if (d > 0) + { + val = val.Substring(0, d); + } + return val.Trim(); + } + + public static string FormatSecondsToDisplayTime(int secs) + { + TimeSpan t = TimeSpan.FromSeconds(secs); + + if (t.Hours > 0) + return string.Format("{0}:{1}:{2}", t.Hours, t.Minutes.ToString().PadLeft(2, '0'), t.Seconds.ToString().PadLeft(2, '0')); + else + return string.Format("{0}:{1}", t.Minutes, t.Seconds.ToString().PadLeft(2, '0')); + } + + public static string FormatAniDBRating(double rat) + { + // the episode ratings from UDP are out of 1000, while the HTTP AP gives it out of 10 + rat /= 100; + + return String.Format("{0:0.00}", rat); + + } + + public static int? ProcessNullableInt(string sint) + { + if (string.IsNullOrEmpty(sint)) + return null; + else + return int.Parse(sint); + } + + public static string RemoveInvalidFolderNameCharacters(string folderName) + { + string ret = folderName.Replace(@"*", ""); + ret = ret.Replace(@"|", ""); + ret = ret.Replace(@"\", ""); + ret = ret.Replace(@"/", ""); + ret = ret.Replace(@":", ""); + ret = ret.Replace(((Char)34).ToString(), ""); // double quote + ret = ret.Replace(@">", ""); + ret = ret.Replace(@"<", ""); + ret = ret.Replace(@"?", ""); + + return ret; + } + + public static string GetSortName(string name) + { + string newName = name; + if (newName.ToLower().StartsWith("the ")) + newName.Remove(0, 4); + if (newName.ToLower().StartsWith("a ")) + newName.Remove(0, 2); + + return newName; + } + + public static string GetOSInfo() + { + //Get Operating system information. + OperatingSystem os = Environment.OSVersion; + //Get version information about the os. + Version vs = os.Version; + + //Variable to hold our return value + string operatingSystem = ""; + + if (os.Platform == PlatformID.Win32Windows) + { + //This is a pre-NT version of Windows + switch (vs.Minor) + { + case 0: + operatingSystem = "95"; + break; + case 10: + if (vs.Revision.ToString() == "2222A") + operatingSystem = "98SE"; + else + operatingSystem = "98"; + break; + case 90: + operatingSystem = "Me"; + break; + default: + break; + } + } + else if (os.Platform == PlatformID.Win32NT) + { + switch (vs.Major) + { + case 3: + operatingSystem = "NT 3.51"; + break; + case 4: + operatingSystem = "NT 4.0"; + break; + case 5: + if (vs.Minor == 0) + operatingSystem = "2000"; + else + operatingSystem = "XP"; + break; + case 6: + if (vs.Minor == 0) + operatingSystem = "Vista"; + else + operatingSystem = "7"; + break; + default: + break; + } + } + //Make sure we actually got something in our OS check + //We don't want to just return " Service Pack 2" or " 32-bit" + //That information is useless without the OS version. + if (operatingSystem != "") + { + //Got something. Let's prepend "Windows" and get more info. + operatingSystem = "Windows " + operatingSystem; + //See if there's a service pack installed. + if (os.ServicePack != "") + { + //Append it to the OS name. i.e. "Windows XP Service Pack 3" + operatingSystem += " " + os.ServicePack; + } + //Append the OS architecture. i.e. "Windows XP Service Pack 3 32-bit" + operatingSystem += " " + getOSArchitecture().ToString() + "-bit"; + } + //Return the information we've gathered. + return operatingSystem; + } + + public static int getOSArchitecture() + { + //easiest way: Just check the Size property of IntPtr. + return IntPtr.Size * 8; + } + + #region PrettyFilesize + [DllImport("Shlwapi.dll", CharSet = CharSet.Auto)] + static extern long StrFormatByteSize(long fileSize, + [MarshalAs(UnmanagedType.LPTStr)] StringBuilder buffer, int bufferSize); + + public static string FormatByteSize(long fileSize) + { + StringBuilder sbBuffer = new StringBuilder(20); + StrFormatByteSize(fileSize, sbBuffer, 20); + return sbBuffer.ToString(); + } + #endregion + + public static int GetVideoWidth(string videoResolution) + { + int videoWidth = 0; + if (videoResolution.Trim().Length > 0) + { + string[] dimensions = videoResolution.Split('x'); + if (dimensions.Length > 0) int.TryParse(dimensions[0], out videoWidth); + } + return videoWidth; + } + + public static int GetVideoHeight(string videoResolution) + { + int videoHeight = 0; + if (videoResolution.Trim().Length > 0) + { + string[] dimensions = videoResolution.Split('x'); + if (dimensions.Length > 1) int.TryParse(dimensions[1], out videoHeight); + } + return videoHeight; + } + + public static int GetVideoSourceRanking(string source) + { + if (source.ToUpper().Contains("BLU")) return 100; + if (source.ToUpper().Contains("DVD")) return 75; + if (source.ToUpper().Contains("HDTV")) return 50; + if (source.ToUpper().Contains("DTV")) return 40; + if (source.ToUpper().Trim() == "TV") return 30; + if (source.ToUpper().Contains("VHS")) return 20; + + return 0; + } + + public static int GetOverallVideoSourceRanking(string videoResolution, string source) + { + int vidWidth = GetVideoWidth(videoResolution); + int score = 0; + score += GetVideoSourceRanking(source); + + if (vidWidth > 1900) score += 100; + else if (vidWidth > 1300) score += 50; + else if (vidWidth > 1100) score += 25; + else if (vidWidth > 800) score += 10; + else if (vidWidth > 700) score += 8; + else if (vidWidth > 500) score += 7; + else if (vidWidth > 400) score += 6; + else if (vidWidth > 1300) score += 5; + else score += 2; + + return score; + } + + public static int GetScheduledHours(ScheduledUpdateFrequency freq) + { + switch (freq) + { + case ScheduledUpdateFrequency.Daily: return 24; + case ScheduledUpdateFrequency.HoursSix: return 6; + case ScheduledUpdateFrequency.HoursTwelve: return 12; + case ScheduledUpdateFrequency.Never: return int.MaxValue; + } + + return int.MaxValue; + } + } +} diff --git a/JMMServer/WatchedUnwatchedCount.cs b/JMMServer/WatchedUnwatchedCount.cs new file mode 100644 index 000000000..479bd521e --- /dev/null +++ b/JMMServer/WatchedUnwatchedCount.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace JMMServer +{ + public class WatchedUnwatchedCount + { + public int WatchedCount { get; set; } + public int UnwatchedCount { get; set; } + public int WatchedCountEpisodes { get; set; } + public int UnwatchedCountEpisodes { get; set; } + public int WatchedCountCredits { get; set; } + public int UnwatchedCountCredits { get; set; } + public int WatchedCountSpecials { get; set; } + public int UnwatchedCountSpecials { get; set; } + public int WatchedCountTrailer { get; set; } + public int UnwatchedCountTrailer { get; set; } + public int WatchedCountParody { get; set; } + public int UnwatchedCountParody { get; set; } + public int WatchedCountOther { get; set; } + public int UnwatchedCountOther { get; set; } + + public WatchedUnwatchedCount() + { + this.WatchedCount = 0; + this.UnwatchedCount = 0; + this.WatchedCountEpisodes = 0; + this.UnwatchedCountEpisodes = 0; + this.WatchedCountCredits = 0; + this.UnwatchedCountCredits = 0; + this.WatchedCountSpecials = 0; + this.UnwatchedCountSpecials = 0; + this.WatchedCountTrailer = 0; + this.UnwatchedCountTrailer = 0; + this.WatchedCountParody = 0; + this.UnwatchedCountParody = 0; + this.WatchedCountOther = 0; + this.UnwatchedCountOther = 0; + } + } +} diff --git a/JMMServer/WebCache/AddCrossRef_AniDB_OtherRequest.cs b/JMMServer/WebCache/AddCrossRef_AniDB_OtherRequest.cs new file mode 100644 index 000000000..18ee5864f --- /dev/null +++ b/JMMServer/WebCache/AddCrossRef_AniDB_OtherRequest.cs @@ -0,0 +1,63 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Xml.Serialization; +using JMMServer.Entities; +using AniDBAPI; +using JMMServer.Repositories; + +namespace JMMServer.WebCache +{ + [Serializable] + [XmlRoot("AddCrossRef_AniDB_Other_Request")] + public class AddCrossRef_AniDB_OtherRequest : XMLBase + { + protected string username = ""; + public string Username + { + get { return username; } + set { username = value; } + } + + protected int animeID = 0; + public int AnimeID + { + get { return animeID; } + set { animeID = value; } + } + + protected string crossRefID = ""; + public string CrossRefID + { + get { return crossRefID; } + set { crossRefID = value; } + } + + protected int crossRefType = 0; + public int CrossRefType + { + get { return crossRefType; } + set { crossRefType = value; } + } + + // default constructor + public AddCrossRef_AniDB_OtherRequest() + { + } + + // default constructor + public AddCrossRef_AniDB_OtherRequest(CrossRef_AniDB_Other data) + { + this.AnimeID = data.AnimeID; + this.CrossRefID = data.CrossRefID; + this.CrossRefType = data.CrossRefType; + + string username = ServerSettings.AniDB_Username; + if (ServerSettings.WebCache_Anonymous) + username = Constants.AnonWebCacheUsername; + + this.Username = username; + } + } +} diff --git a/JMMServer/WebCache/AddCrossRef_AniDB_TraktRequest.cs b/JMMServer/WebCache/AddCrossRef_AniDB_TraktRequest.cs new file mode 100644 index 000000000..7b3a02886 --- /dev/null +++ b/JMMServer/WebCache/AddCrossRef_AniDB_TraktRequest.cs @@ -0,0 +1,71 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Xml.Serialization; +using JMMServer.Entities; +using AniDBAPI; +using JMMServer.Repositories; + +namespace JMMServer.WebCache +{ + [Serializable] + [XmlRoot("AddCrossRef_AniDB_Trakt_Request")] + public class AddCrossRef_AniDB_TraktRequest : XMLBase + { + protected string username = ""; + public string Username + { + get { return username; } + set { username = value; } + } + + protected string showName = ""; + public string ShowName + { + get { return showName; } + set { showName = value; } + } + + protected int animeID = 0; + public int AnimeID + { + get { return animeID; } + set { animeID = value; } + } + + protected string traktID = ""; + public string TraktID + { + get { return traktID; } + set { traktID = value; } + } + + protected int season = 0; + public int Season + { + get { return season; } + set { season = value; } + } + + // default constructor + public AddCrossRef_AniDB_TraktRequest() + { + } + + // default constructor + public AddCrossRef_AniDB_TraktRequest(CrossRef_AniDB_Trakt data, string showName) + { + this.AnimeID = data.AnimeID; + this.TraktID = data.TraktID; + this.Season = data.TraktSeasonNumber; + + string username = ServerSettings.AniDB_Username; + if (ServerSettings.WebCache_Anonymous) + username = Constants.AnonWebCacheUsername; + + this.Username = username; + this.ShowName = showName; + } + } +} diff --git a/JMMServer/WebCache/AddCrossRef_AniDB_TvDBRequest.cs b/JMMServer/WebCache/AddCrossRef_AniDB_TvDBRequest.cs new file mode 100644 index 000000000..38e8d367b --- /dev/null +++ b/JMMServer/WebCache/AddCrossRef_AniDB_TvDBRequest.cs @@ -0,0 +1,71 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Xml.Serialization; +using JMMServer.Entities; +using AniDBAPI; +using JMMServer.Repositories; + +namespace JMMServer.WebCache +{ + [Serializable] + [XmlRoot("AddCrossRef_AniDB_TvDB_Request")] + public class AddCrossRef_AniDB_TvDBRequest : XMLBase + { + protected string username = ""; + public string Username + { + get { return username; } + set { username = value; } + } + + protected string seriesName = ""; + public string SeriesName + { + get { return seriesName; } + set { seriesName = value; } + } + + protected int animeID = 0; + public int AnimeID + { + get { return animeID; } + set { animeID = value; } + } + + protected int tvDBID = 0; + public int TvDBID + { + get { return tvDBID; } + set { tvDBID = value; } + } + + protected int tvDBSeason = 0; + public int TvDBSeason + { + get { return tvDBSeason; } + set { tvDBSeason = value; } + } + + // default constructor + public AddCrossRef_AniDB_TvDBRequest() + { + } + + // default constructor + public AddCrossRef_AniDB_TvDBRequest(CrossRef_AniDB_TvDB data, string seriesName) + { + this.AnimeID = data.AnimeID; + this.TvDBID = data.TvDBID; + this.TvDBSeason = data.TvDBSeasonNumber; + + string username = ServerSettings.AniDB_Username; + if (ServerSettings.WebCache_Anonymous) + username = Constants.AnonWebCacheUsername; + + this.Username = username; + this.SeriesName = seriesName; + } + } +} diff --git a/JMMServer/WebCache/AniDB_UpdatedRequest.cs b/JMMServer/WebCache/AniDB_UpdatedRequest.cs new file mode 100644 index 000000000..06c825931 --- /dev/null +++ b/JMMServer/WebCache/AniDB_UpdatedRequest.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Xml.Serialization; +using AniDBAPI; + +namespace JMMServer.WebCache +{ + [Serializable] + [XmlRoot("AniDB_Updated")] + public class AniDB_UpdatedRequest : XMLBase + { + public long UpdatedTime { get; set; } + public string Username { get; set; } + public string AnimeIDList { get; set; } + + // default constructor + public AniDB_UpdatedRequest() + { + } + + // default constructor + public AniDB_UpdatedRequest(string uptime, string aidlist) + { + this.UpdatedTime = long.Parse(uptime); + this.AnimeIDList = aidlist; + + string username = ServerSettings.AniDB_Username; + if (ServerSettings.WebCache_Anonymous) + username = Constants.AnonWebCacheUsername; + + this.Username = username; + } + } +} diff --git a/JMMServer/WebCache/CrossRef_AniDB_OtherResult.cs b/JMMServer/WebCache/CrossRef_AniDB_OtherResult.cs new file mode 100644 index 000000000..5b62df773 --- /dev/null +++ b/JMMServer/WebCache/CrossRef_AniDB_OtherResult.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMContracts; + +namespace JMMServer.WebCache +{ + public class CrossRef_AniDB_OtherResult + { + public int AnimeID { get; set; } + public string CrossRefID { get; set; } + + // default constructor + public CrossRef_AniDB_OtherResult() + { + } + + public Contract_CrossRef_AniDB_OtherResult ToContract() + { + Contract_CrossRef_AniDB_OtherResult contract = new Contract_CrossRef_AniDB_OtherResult(); + contract.AnimeID = this.AnimeID; + contract.CrossRefID = this.CrossRefID; + return contract; + } + } +} diff --git a/JMMServer/WebCache/CrossRef_AniDB_TraktResult.cs b/JMMServer/WebCache/CrossRef_AniDB_TraktResult.cs new file mode 100644 index 000000000..66061551d --- /dev/null +++ b/JMMServer/WebCache/CrossRef_AniDB_TraktResult.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMContracts; + +namespace JMMServer.WebCache +{ + public class CrossRef_AniDB_TraktResult + { + public int AnimeID { get; set; } + public string TraktID { get; set; } + public int TraktSeasonNumber { get; set; } + public int AdminApproved { get; set; } + public string ShowName { get; set; } + + // default constructor + public CrossRef_AniDB_TraktResult() + { + } + + public Contract_CrossRef_AniDB_TraktResult ToContract() + { + Contract_CrossRef_AniDB_TraktResult contract = new Contract_CrossRef_AniDB_TraktResult(); + + contract.AnimeID = AnimeID; + contract.TraktID = TraktID; + contract.TraktSeasonNumber = TraktSeasonNumber; + contract.AdminApproved = AdminApproved; + contract.ShowName = ShowName; + + return contract; + } + } +} diff --git a/JMMServer/WebCache/CrossRef_AniDB_TvDBResult.cs b/JMMServer/WebCache/CrossRef_AniDB_TvDBResult.cs new file mode 100644 index 000000000..a9ac4b0f4 --- /dev/null +++ b/JMMServer/WebCache/CrossRef_AniDB_TvDBResult.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JMMContracts; + +namespace JMMServer.WebCache +{ + public class CrossRef_AniDB_TvDBResult + { + public int AnimeID { get; set; } + public int TvDBID { get; set; } + public int TvDBSeasonNumber { get; set; } + public int AdminApproved { get; set; } + public string SeriesName { get; set; } + + // default constructor + public CrossRef_AniDB_TvDBResult() + { + } + + public Contract_CrossRef_AniDB_TvDBResult ToContract() + { + Contract_CrossRef_AniDB_TvDBResult contract = new Contract_CrossRef_AniDB_TvDBResult(); + contract.AnimeID = this.AnimeID; + contract.TvDBID = this.TvDBID; + contract.TvDBSeasonNumber = this.TvDBSeasonNumber; + contract.AdminApproved = this.AdminApproved; + contract.SeriesName = this.SeriesName; + return contract; + } + } +} diff --git a/JMMServer/WebCache/CrossRef_File_EpisodeRequest.cs b/JMMServer/WebCache/CrossRef_File_EpisodeRequest.cs new file mode 100644 index 000000000..88720d849 --- /dev/null +++ b/JMMServer/WebCache/CrossRef_File_EpisodeRequest.cs @@ -0,0 +1,79 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Xml.Serialization; +using AniDBAPI; +using JMMServer.Entities; + +namespace JMMServer.WebCache +{ + [Serializable] + [XmlRoot("CrossRef_File_EpisodeRequest")] + public class CrossRef_File_EpisodeRequest : XMLBase + { + protected string uname = ""; + public string Uname + { + get { return uname; } + set { uname = value; } + } + + protected string hash = ""; + public string Hash + { + get { return hash; } + set { hash = value; } + } + + protected int animeID = 0; + public int AnimeID + { + get { return animeID; } + set { animeID = value; } + } + + protected int episodeID = 0; + public int EpisodeID + { + get { return episodeID; } + set { episodeID = value; } + } + + protected int percentage = 0; + public int Percentage + { + get { return percentage; } + set { percentage = value; } + } + + protected int episodeOrder = 0; + public int EpisodeOrder + { + get { return episodeOrder; } + set { episodeOrder = value; } + } + + + // default constructor + public CrossRef_File_EpisodeRequest() + { + } + + // default constructor + public CrossRef_File_EpisodeRequest(CrossRef_File_Episode data) + { + this.AnimeID = data.AnimeID; + this.EpisodeID = data.EpisodeID; + this.Percentage = data.Percentage; + this.EpisodeOrder = data.EpisodeOrder; + this.hash = data.Hash; + + string username = ServerSettings.AniDB_Username; + if (ServerSettings.WebCache_Anonymous) + username = Constants.AnonWebCacheUsername; + + this.uname = username; + } + } +} diff --git a/JMMServer/WebCache/DeleteCrossRef_AniDBTvDBAll_Request.cs b/JMMServer/WebCache/DeleteCrossRef_AniDBTvDBAll_Request.cs new file mode 100644 index 000000000..d019ac09a --- /dev/null +++ b/JMMServer/WebCache/DeleteCrossRef_AniDBTvDBAll_Request.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Xml.Serialization; +using AniDBAPI; +using JMMServer.Entities; + +namespace JMMServer.WebCache +{ + [Serializable] + [XmlRoot("DeleteCrossRef_AniDBTvDBAll_Request")] + public class DeleteCrossRef_AniDBTvDBAll_Request : XMLBase + { + protected int seriesID = 0; + public int SeriesID + { + get { return seriesID; } + set { seriesID = value; } + } + + // default constructor + public DeleteCrossRef_AniDBTvDBAll_Request() + { + } + + // default constructor + public DeleteCrossRef_AniDBTvDBAll_Request(int tvDBID) + { + this.SeriesID = tvDBID; + } + } +} diff --git a/JMMServer/WebCache/DeleteCrossRef_AniDB_OtherRequest.cs b/JMMServer/WebCache/DeleteCrossRef_AniDB_OtherRequest.cs new file mode 100644 index 000000000..23d7dd06f --- /dev/null +++ b/JMMServer/WebCache/DeleteCrossRef_AniDB_OtherRequest.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Xml.Serialization; +using JMMServer.Entities; +using AniDBAPI; + +namespace JMMServer.WebCache +{ + [Serializable] + [XmlRoot("DeleteCrossRef_AniDB_OtherRequest")] + public class DeleteCrossRef_AniDB_OtherRequest : XMLBase + { + protected string username = ""; + public string Username + { + get { return username; } + set { username = value; } + } + + protected int animeID = 0; + public int AnimeID + { + get { return animeID; } + set { animeID = value; } + } + + protected int crossRefType = 0; + public int CrossRefType + { + get { return crossRefType; } + set { crossRefType = value; } + } + + // default constructor + public DeleteCrossRef_AniDB_OtherRequest() + { + } + + // default constructor + public DeleteCrossRef_AniDB_OtherRequest(int animeID, CrossRefType xrefType) + { + this.AnimeID = animeID; + this.CrossRefType = (int)xrefType; + + string username = ServerSettings.AniDB_Username; + if (ServerSettings.WebCache_Anonymous) + username = Constants.AnonWebCacheUsername; + + this.Username = username; + } + } +} diff --git a/JMMServer/WebCache/DeleteCrossRef_AniDB_TraktRequest.cs b/JMMServer/WebCache/DeleteCrossRef_AniDB_TraktRequest.cs new file mode 100644 index 000000000..c8fdbace7 --- /dev/null +++ b/JMMServer/WebCache/DeleteCrossRef_AniDB_TraktRequest.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Xml.Serialization; +using JMMServer.Entities; +using AniDBAPI; + +namespace JMMServer.WebCache +{ + [Serializable] + [XmlRoot("DeleteCrossRef_AniDB_TraktRequest")] + public class DeleteCrossRef_AniDB_TraktRequest : XMLBase + { + protected string username = ""; + public string Username + { + get { return username; } + set { username = value; } + } + + protected int animeID = 0; + public int AnimeID + { + get { return animeID; } + set { animeID = value; } + } + + // default constructor + public DeleteCrossRef_AniDB_TraktRequest() + { + } + + // default constructor + public DeleteCrossRef_AniDB_TraktRequest(int animeID) + { + this.AnimeID = animeID; + + string username = ServerSettings.AniDB_Username; + if (ServerSettings.WebCache_Anonymous) + username = Constants.AnonWebCacheUsername; + + this.Username = username; + } + } +} diff --git a/JMMServer/WebCache/DeleteCrossRef_AniDB_TvDBRequest.cs b/JMMServer/WebCache/DeleteCrossRef_AniDB_TvDBRequest.cs new file mode 100644 index 000000000..f4596623c --- /dev/null +++ b/JMMServer/WebCache/DeleteCrossRef_AniDB_TvDBRequest.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Xml.Serialization; +using JMMServer.Entities; +using AniDBAPI; + +namespace JMMServer.WebCache +{ + [Serializable] + [XmlRoot("DeleteCrossRef_AniDB_TvDBRequest")] + public class DeleteCrossRef_AniDB_TvDBRequest : XMLBase + { + protected string username = ""; + public string Username + { + get { return username; } + set { username = value; } + } + + protected int animeID = 0; + public int AnimeID + { + get { return animeID; } + set { animeID = value; } + } + + // default constructor + public DeleteCrossRef_AniDB_TvDBRequest() + { + } + + // default constructor + public DeleteCrossRef_AniDB_TvDBRequest(int animeID) + { + this.AnimeID = animeID; + + string username = ServerSettings.AniDB_Username; + if (ServerSettings.WebCache_Anonymous) + username = Constants.AnonWebCacheUsername; + + this.Username = username; + } + } +} diff --git a/JMMServer/WebCache/DeleteCrossRef_File_EpisodeRequest.cs b/JMMServer/WebCache/DeleteCrossRef_File_EpisodeRequest.cs new file mode 100644 index 000000000..498ba05aa --- /dev/null +++ b/JMMServer/WebCache/DeleteCrossRef_File_EpisodeRequest.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Xml.Serialization; +using AniDBAPI; +using JMMServer.Entities; + +namespace JMMServer.WebCache +{ + [Serializable] + [XmlRoot("DeleteCrossRef_File_EpisodeRequest")] + public class DeleteCrossRef_File_EpisodeRequest : XMLBase + { + protected string uname = ""; + public string Uname + { + get { return uname; } + set { uname = value; } + } + + protected string hash = ""; + public string Hash + { + get { return hash; } + set { hash = value; } + } + + protected int episodeID = 0; + public int EpisodeID + { + get { return episodeID; } + set { episodeID = value; } + } + + // default constructor + public DeleteCrossRef_File_EpisodeRequest() + { + } + + // default constructor + public DeleteCrossRef_File_EpisodeRequest(string hash, int aniDBEpisodeID) + { + this.EpisodeID = aniDBEpisodeID; + this.hash = hash; + + string username = ServerSettings.AniDB_Username; + if (ServerSettings.WebCache_Anonymous) + username = Constants.AnonWebCacheUsername; + + this.uname = username; + } + } +} diff --git a/JMMServer/WebCache/FileHashRequest.cs b/JMMServer/WebCache/FileHashRequest.cs new file mode 100644 index 000000000..cd7a208ad --- /dev/null +++ b/JMMServer/WebCache/FileHashRequest.cs @@ -0,0 +1,64 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Xml.Serialization; +using JMMServer.Entities; +using AniDBAPI; +using System.IO; + +namespace JMMServer.WebCache +{ + [Serializable] + [XmlRoot("FileHashRequest")] + public class FileHashRequest : XMLBase + { + + protected string fname = ""; + public string Fname + { + get { return fname; } + set { fname = value; } + } + + protected long fsize = 0; + public long Fsize + { + get { return fsize; } + set { fsize = value; } + } + + protected string uname = ""; + public string Uname + { + get { return uname; } + set { uname = value; } + } + + protected string hash = ""; + public string Hash + { + get { return hash; } + set { hash = value; } + } + + // default constructor + public FileHashRequest() + { + } + + // default constructor + public FileHashRequest(VideoLocal data) + { + this.fsize = data.FileSize; + this.hash = data.ED2KHash; + this.fname = Path.GetFileName(data.FilePath); + + string username = ServerSettings.AniDB_Username; + if (ServerSettings.WebCache_Anonymous) + username = Constants.AnonWebCacheUsername; + + this.uname = username; + } + } +} diff --git a/JMMServer/WebCache/XMLService.cs b/JMMServer/WebCache/XMLService.cs new file mode 100644 index 000000000..cf7090855 --- /dev/null +++ b/JMMServer/WebCache/XMLService.cs @@ -0,0 +1,529 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Xml; +using NLog; +using System.IO; +using System.Net; +using JMMServer.Entities; +using System.Xml.Serialization; +using AniDBAPI; +using JMMServer.AniDB_API; +using JMMServer.Repositories; + +namespace JMMServer.WebCache +{ + public class XMLService + { + private static Logger logger = LogManager.GetCurrentClassLogger(); + + #region File Hash + + public static string Get_FileHash(string filename, long filesize) + { + if (!ServerSettings.WebCache_FileHashes_Get) return ""; + + try + { + string fileName = Path.GetFileName(filename); + + fileName = fileName.Replace("+", "%252b"); + fileName = fileName.Replace("&", "%26"); + fileName = fileName.Replace("[", "%5b"); + fileName = fileName.Replace("]", "%5d"); + + string username = ServerSettings.AniDB_Username; + if (ServerSettings.WebCache_Anonymous) + username = Constants.AnonWebCacheUsername; + + string uri = string.Format("http://{0}/GetFileNameHash.aspx?uname={1}&fname={2}&fsize={3}", + ServerSettings.WebCache_Address, username, fileName, filesize); + string xml = GetData(uri); + + if (xml.Trim().Length == 0) return ""; + + XmlDocument docFile = new XmlDocument(); + docFile.LoadXml(xml); + + string hash = TryGetProperty(docFile, "FileHashResult", "Hash").ToUpper(); + + return hash; + } + catch (Exception ex) + { + logger.ErrorException("Error in XMLService.Get_FileHash:: {0}", ex); + return ""; + } + } + + public static void Send_FileHash(VideoLocal data) + { + if (!ServerSettings.WebCache_FileHashes_Send) return; + + + string uri = string.Format("http://{0}/AddFileNameHash.aspx", ServerSettings.WebCache_Address); + FileHashRequest fhr = new FileHashRequest(data); + string xml = fhr.ToXML(); + + SendData(uri, xml); + } + + #endregion + + #region CrossRef File Episode + + /// + /// Current only handling one file containing file + /// + /// + /// + public static List Get_CrossRef_File_Episode(VideoLocal vid) + { + List crossRefs = new List(); + + if (!ServerSettings.WebCache_XRefFileEpisode_Get) return null; + + try + { + string username = ServerSettings.AniDB_Username; + if (ServerSettings.WebCache_Anonymous) + username = Constants.AnonWebCacheUsername; + + string uri = string.Format("http://{0}/GetCrossRef_File_Episode.aspx?uname={1}&hash={2}", + ServerSettings.WebCache_Address, username, vid.Hash); + string xml = GetData(uri); + + if (xml.Trim().Length == 0) return null; + + XmlDocument docFile = new XmlDocument(); + docFile.LoadXml(xml); + + string sAnimeID = TryGetProperty(docFile, "CrossRef_File_EpisodeResultCollection", "AnimeID").ToUpper(); + string sEpisodeID = TryGetProperty(docFile, "CrossRef_File_EpisodeResultCollection", "EpisodeIDs").ToUpper(); + string sEpisodeOrder = TryGetProperty(docFile, "CrossRef_File_EpisodeResultCollection", "EpisodeOrders").ToUpper(); + string sPercentages = TryGetProperty(docFile, "CrossRef_File_EpisodeResultCollection", "EpisodePercentages").ToUpper(); + + int animeID = 0; + int.TryParse(sAnimeID, out animeID); + + if (animeID <= 0) return null; + + string[] epids = sEpisodeID.Split('|'); + string[] eporders = sEpisodeOrder.Split('|'); + string[] eppcts = sPercentages.Split('|'); + + for (int i=0;i < epids.Length; i++) + { + int episodeID = 0, percentage = 0, episodeOrder = 0; + + int.TryParse(epids[i], out episodeID); + int.TryParse(eporders[i], out episodeOrder); + int.TryParse(eppcts[i], out percentage); + + CrossRef_File_Episode xref = new CrossRef_File_Episode(); + xref.Hash = vid.ED2KHash; + xref.FileName = Path.GetFileName(vid.FullServerPath); + xref.FileSize = vid.FileSize; + xref.CrossRefSource = (int)JMMServer.CrossRefSource.WebCache; + xref.AnimeID = animeID; + xref.EpisodeID = episodeID; + xref.Percentage = percentage; + xref.EpisodeOrder = episodeOrder; + + crossRefs.Add(xref); + } + + + + return crossRefs; + } + catch (Exception ex) + { + logger.ErrorException("Error in XMLService.Get_FileHash:: {0}", ex); + return null; + } + } + + public static void Send_CrossRef_File_Episode(CrossRef_File_Episode data) + { + if (!ServerSettings.WebCache_XRefFileEpisode_Send) return; + + + string uri = string.Format("http://{0}/AddCrossRef_File_Episode.aspx", ServerSettings.WebCache_Address); + CrossRef_File_EpisodeRequest fhr = new CrossRef_File_EpisodeRequest(data); + string xml = fhr.ToXML(); + + SendData(uri, xml); + } + + public static void Delete_CrossRef_File_Episode(string hash, int aniDBEpisodeID) + { + if (!ServerSettings.WebCache_XRefFileEpisode_Send && !ServerSettings.WebCache_XRefFileEpisode_Get) return; + + string uri = string.Format("http://{0}/DeleteCrossRef_File_Episode.aspx", ServerSettings.WebCache_Address); + DeleteCrossRef_File_EpisodeRequest fhr = new DeleteCrossRef_File_EpisodeRequest(hash, aniDBEpisodeID); + string xml = fhr.ToXML(); + + SendData(uri, xml); + } + + #endregion + + #region CrossRef AniDB to TvDB + + public static void Send_CrossRef_AniDB_TvDB(CrossRef_AniDB_TvDB data, string seriesName) + { + if (!ServerSettings.WebCache_XRefFileEpisode_Send) return; + + + string uri = string.Format("http://{0}/AddCrossRef_AniDB_TvDB.aspx", ServerSettings.WebCache_Address); + AddCrossRef_AniDB_TvDBRequest fhr = new AddCrossRef_AniDB_TvDBRequest(data, seriesName); + string xml = fhr.ToXML(); + + SendData(uri, xml); + } + + public static void Delete_CrossRef_AniDB_TvDB(int animeID) + { + if (!ServerSettings.WebCache_XRefFileEpisode_Send) return; + if (ServerSettings.WebCache_Anonymous) return; + + string uri = string.Format("http://{0}/DeleteCrossRef_AniDB_TvDB.aspx", ServerSettings.WebCache_Address); + DeleteCrossRef_AniDB_TvDBRequest req = new DeleteCrossRef_AniDB_TvDBRequest(animeID); + string xml = req.ToXML(); + + SendData(uri, xml); + } + + + public static void Delete_CrossRef_AniDB_TvDB_All(int tvDBID) + { + if (!ServerSettings.WebCache_XRefFileEpisode_Send) return; + if (ServerSettings.WebCache_Anonymous) return; + + string uri = string.Format("http://{0}/DeleteCrossRef_AniDBTvDBAll.aspx", ServerSettings.WebCache_Address); + DeleteCrossRef_AniDBTvDBAll_Request req = new DeleteCrossRef_AniDBTvDBAll_Request(tvDBID); + string xml = req.ToXML(); + + SendData(uri, xml); + } + + public static CrossRef_AniDB_TvDBResult Get_CrossRef_AniDB_TvDB(int animeID) + { + if (!ServerSettings.WebCache_XRefFileEpisode_Get) return null; + + try + { + string username = ServerSettings.AniDB_Username; + if (ServerSettings.WebCache_Anonymous) + username = Constants.AnonWebCacheUsername; + + string uri = string.Format("http://{0}/GetCrossRef_AniDB_TvDB.aspx?uname={1}&AnimeID={2}", + ServerSettings.WebCache_Address, username, animeID); + string xml = GetData(uri); + + if (xml.Trim().Length == 0) return null; + + XmlDocument docFile = new XmlDocument(); + docFile.LoadXml(xml); + + string sTvDBID = TryGetProperty(docFile, "CrossRef_AniDB_TvDBResult", "TvDBID"); + string sTvDBSeasonNumber = TryGetProperty(docFile, "CrossRef_AniDB_TvDBResult", "TvDBSeasonNumber"); + string sAdminApproved = TryGetProperty(docFile, "CrossRef_AniDB_TvDBResult", "AdminApproved"); + string seriesName = TryGetProperty(docFile, "CrossRef_AniDB_TvDBResult", "SeriesName"); + + + int TvDBID = 0; + int.TryParse(sTvDBID, out TvDBID); + + int TvDBSeasonNumber = 0; + int.TryParse(sTvDBSeasonNumber, out TvDBSeasonNumber); + + int AdminApproved = 0; + int.TryParse(sAdminApproved, out AdminApproved); + + if (TvDBID <= 0) return null; + + CrossRef_AniDB_TvDBResult result = new CrossRef_AniDB_TvDBResult(); + result.AnimeID = animeID; + result.TvDBID = TvDBID; + result.TvDBSeasonNumber = TvDBSeasonNumber; + result.SeriesName = seriesName; + + return result; + } + catch (Exception ex) + { + logger.ErrorException("Error in XMLService.Get_FileHash:: {0}", ex); + return null; + } + } + + #endregion + + #region CrossRef AniDB to Other + + public static void Send_CrossRef_AniDB_Other(CrossRef_AniDB_Other data) + { + if (!ServerSettings.WebCache_XRefFileEpisode_Send) return; + + + string uri = string.Format("http://{0}/AddCrossRef_AniDB_Other.aspx", ServerSettings.WebCache_Address); + AddCrossRef_AniDB_OtherRequest fhr = new AddCrossRef_AniDB_OtherRequest(data); + string xml = fhr.ToXML(); + + SendData(uri, xml); + } + + public static void Delete_CrossRef_AniDB_Other(int animeID, CrossRefType xrefType) + { + if (!ServerSettings.WebCache_XRefFileEpisode_Send) return; + if (ServerSettings.WebCache_Anonymous) return; + + string uri = string.Format("http://{0}/DeleteCrossRef_AniDB_Other.aspx", ServerSettings.WebCache_Address); + DeleteCrossRef_AniDB_OtherRequest req = new DeleteCrossRef_AniDB_OtherRequest(animeID, xrefType); + string xml = req.ToXML(); + + SendData(uri, xml); + } + + public static CrossRef_AniDB_OtherResult Get_CrossRef_AniDB_Other(int animeID, CrossRefType xrefType) + { + if (!ServerSettings.WebCache_XRefFileEpisode_Get) return null; + + try + { + string username = ServerSettings.AniDB_Username; + if (ServerSettings.WebCache_Anonymous) + username = Constants.AnonWebCacheUsername; + + string uri = string.Format("http://{0}/GetCrossRef_AniDB_Other.aspx?uname={1}&AnimeID={2}&CrossRefType={3}", + ServerSettings.WebCache_Address, username, animeID, (int)xrefType); + string xml = GetData(uri); + + if (xml.Trim().Length == 0) return null; + + XmlDocument docFile = new XmlDocument(); + docFile.LoadXml(xml); + + string sOtherDBID = TryGetProperty(docFile, "CrossRef_AniDB_OtherResult", "CrossRefID"); + + if (string.IsNullOrEmpty(sOtherDBID)) return null; + + CrossRef_AniDB_OtherResult result = new CrossRef_AniDB_OtherResult(); + result.AnimeID = animeID; + result.CrossRefID = sOtherDBID; + + return result; + } + catch (Exception ex) + { + logger.ErrorException("Error in XMLService.Get_FileHash:: {0}", ex); + return null; + } + } + + #endregion + + #region CrossRef AniDB to Trakt + + public static void Send_CrossRef_AniDB_Trakt(CrossRef_AniDB_Trakt data, string showName) + { + if (!ServerSettings.WebCache_XRefFileEpisode_Send) return; + + + string uri = string.Format("http://{0}/AddCrossRef_AniDB_Trakt.aspx", ServerSettings.WebCache_Address); + AddCrossRef_AniDB_TraktRequest fhr = new AddCrossRef_AniDB_TraktRequest(data, showName); + string xml = fhr.ToXML(); + + SendData(uri, xml); + } + + public static void Delete_CrossRef_AniDB_Trakt(int animeID) + { + if (!ServerSettings.WebCache_XRefFileEpisode_Send) return; + if (ServerSettings.WebCache_Anonymous) return; + + string uri = string.Format("http://{0}/DeleteCrossRef_AniDB_Trakt.aspx", ServerSettings.WebCache_Address); + DeleteCrossRef_AniDB_TraktRequest req = new DeleteCrossRef_AniDB_TraktRequest(animeID); + string xml = req.ToXML(); + + SendData(uri, xml); + } + + public static CrossRef_AniDB_TraktResult Get_CrossRef_AniDB_Trakt(int animeID) + { + if (!ServerSettings.WebCache_XRefFileEpisode_Get) return null; + + try + { + string username = ServerSettings.AniDB_Username; + if (ServerSettings.WebCache_Anonymous) + username = Constants.AnonWebCacheUsername; + + string uri = string.Format("http://{0}/GetCrossRef_AniDB_Trakt.aspx?uname={1}&AnimeID={2}", + ServerSettings.WebCache_Address, username, animeID); + string xml = GetData(uri); + + if (xml.Trim().Length == 0) return null; + + XmlDocument docFile = new XmlDocument(); + docFile.LoadXml(xml); + + string sTraktID = TryGetProperty(docFile, "CrossRef_AniDB_TraktResult", "TraktID"); + string sTraktSeasonNumber = TryGetProperty(docFile, "CrossRef_AniDB_TraktResult", "TraktSeasonNumber"); + string sAdminApproved = TryGetProperty(docFile, "CrossRef_AniDB_TraktResult", "AdminApproved"); + string showName = TryGetProperty(docFile, "CrossRef_AniDB_TraktResult", "ShowName"); + + + int SeasonNumber = 0; + int.TryParse(sTraktSeasonNumber, out SeasonNumber); + + int AdminApproved = 0; + int.TryParse(sAdminApproved, out AdminApproved); + + CrossRef_AniDB_TraktResult result = new CrossRef_AniDB_TraktResult(); + result.AnimeID = animeID; + result.TraktID = sTraktID; + result.TraktSeasonNumber = SeasonNumber; + result.ShowName = showName; + + return result; + } + catch (Exception ex) + { + logger.ErrorException("Error in XMLService.Get_CrossRef_AniDB_Trakt:: {0}", ex); + return null; + } + } + + #endregion + + public static UpdatesCollection Get_AniDBUpdates(long utcUpdateTime) + { + try + { + + string uri = string.Format("http://{0}/GetUpdates.aspx?updatetime={1}", ServerSettings.WebCache_Address, utcUpdateTime); + string xml = GetData(uri); + + if (xml.Trim().Length == 0) return null; + + UpdatesCollection updateCol = new UpdatesCollection(); + + XmlDocument docUpdates = new XmlDocument(); + docUpdates.LoadXml(xml); + + // populate the fields + updateCol.RawAnimeIDs = TryGetProperty(docUpdates, "UpdatesCollection", "AnimeIDs"); + updateCol.UpdateCount = long.Parse(TryGetProperty(docUpdates, "UpdatesCollection", "UpdateCount")); + + logger.Info("Get_AniDBUpdates:: {0} - {1}", updateCol.UpdateCount, updateCol.RawAnimeIDs); + + return updateCol; + } + catch (Exception ex) + { + logger.ErrorException("Error in XMLService.Get_AniDBUpdates:: {0}" + ex.ToString(), ex); + return null; + } + } + + public static void Send_AniDBUpdates(string updatedTime, string animeIDList) + { + string uri = string.Format("http://{0}/AddUpdatedList.aspx", ServerSettings.WebCache_Address); + AniDB_UpdatedRequest data = new AniDB_UpdatedRequest(updatedTime, animeIDList); + string xml = data.ToXML(); + + SendData(uri, xml); + } + + private static string TryGetProperty(XmlDocument doc, string keyName, string propertyName) + { + try + { + string prop = doc[keyName][propertyName].InnerText.Trim(); + return prop; + } + catch (Exception ex) + { + logger.Info("---------------------------------------------------------------"); + logger.Info("Error in XMLService.TryGetProperty: {0}-{1}", Utils.GetParentMethodName(), ex.ToString()); + logger.Info("keyName: {0}, propertyName: {1}", keyName, propertyName); + logger.Info("---------------------------------------------------------------"); + } + + return ""; + } + + private static string GetData(string uri) + { + try + { + DateTime start = DateTime.Now; + + logger.Trace("GetData for: {0}", uri.ToString()); + string xml = Utils.DownloadWebPage(uri); + TimeSpan ts = DateTime.Now - start; + logger.Trace("GetData returned in {0}: {1} (in {2} ms)", Utils.GetParentMethodName(), xml, ts.TotalMilliseconds); + if (xml.Contains(Constants.WebCacheError)) return ""; + + return xml; + } + catch (WebException webEx) + { + logger.Error("Error(1) in XMLService.GetData: {0}", webEx); + } + catch (Exception ex) + { + logger.ErrorException("Error(2) in XMLService.GetData: {0}", ex); + } + + return ""; + } + + private static void SendData(string uri, string xml) + { + + WebRequest req = null; + WebResponse rsp = null; + try + { + DateTime start = DateTime.Now; + + + req = WebRequest.Create(uri); + req.Method = "POST"; // Post method + req.ContentType = "text/xml"; // content type + req.Proxy = null; + + // Wrap the request stream with a text-based writer + StreamWriter writer = new StreamWriter(req.GetRequestStream()); + // Write the XML text into the stream + writer.WriteLine(xml); + writer.Close(); + // Send the data to the webserver + rsp = req.GetResponse(); + + TimeSpan ts = DateTime.Now - start; + logger.Trace("Sent Web Cache Update in {0} ms: {1} --- {2}", ts.TotalMilliseconds, uri, xml); + + } + catch (WebException webEx) + { + logger.Error("Error(1) in XMLServiceQueue.SendData: {0}", webEx); + } + catch (Exception ex) + { + logger.ErrorException("Error(2) in XMLServiceQueue.SendData: {0}", ex); + } + finally + { + if (req != null) req.GetRequestStream().Close(); + if (rsp != null) rsp.GetResponseStream().Close(); + } + } + } + +} diff --git a/JMMServer/app.manifest b/JMMServer/app.manifest new file mode 100644 index 000000000..93ead012e --- /dev/null +++ b/JMMServer/app.manifest @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/JMMServer/db.ico b/JMMServer/db.ico new file mode 100644 index 000000000..ed0a90d0f Binary files /dev/null and b/JMMServer/db.ico differ diff --git a/hasher/Hasher.sln b/hasher/Hasher.sln new file mode 100644 index 000000000..3d9fc1c85 --- /dev/null +++ b/hasher/Hasher.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual C++ Express 2008 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "hasher", "hasher.vcproj", "{4AB1249D-D635-48A3-8F82-FAB34B69AE4C}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {4AB1249D-D635-48A3-8F82-FAB34B69AE4C}.Debug|Win32.ActiveCfg = Debug|Win32 + {4AB1249D-D635-48A3-8F82-FAB34B69AE4C}.Debug|Win32.Build.0 = Debug|Win32 + {4AB1249D-D635-48A3-8F82-FAB34B69AE4C}.Release|Win32.ActiveCfg = Release|Win32 + {4AB1249D-D635-48A3-8F82-FAB34B69AE4C}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/hasher/Hasher.suo b/hasher/Hasher.suo new file mode 100644 index 000000000..4314621cf Binary files /dev/null and b/hasher/Hasher.suo differ diff --git a/hasher/Hasher.vcproj b/hasher/Hasher.vcproj new file mode 100644 index 000000000..7e8245219 --- /dev/null +++ b/hasher/Hasher.vcproj @@ -0,0 +1,337 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/hasher/Hasher.vcxproj b/hasher/Hasher.vcxproj new file mode 100644 index 000000000..fa878592b --- /dev/null +++ b/hasher/Hasher.vcxproj @@ -0,0 +1,188 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {4AB1249D-D635-48A3-8F82-FAB34B69AE4C} + hasher + + + + DynamicLibrary + false + MultiByte + + + DynamicLibrary + false + MultiByte + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30128.1 + .\Debug\ + .\Debug\ + true + ..\Release\ + .\Release\ + false + AllRules.ruleset + + + AllRules.ruleset + + + + + + _DEBUG;%(PreprocessorDefinitions) + true + true + Win32 + .\Debug/hasher.tlb + + + + + Disabled + WIN32;_DEBUG;_WINDOWS;_USRDLL;HASHER_EXPORTS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + Use + stdafx.h + .\Debug/hasher.pch + .\Debug/ + .\Debug/ + .\Debug/ + Level3 + true + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0813 + + + build assembly + ml.exe md4_asm.asm /c /coff + + + MD4_asm.obj;%(AdditionalDependencies) + Debug\hasher.dll + true + true + .\Debug/hasher.pdb + false + + + .\Debug/hasher.lib + MachineX86 + + + true + .\Debug/hasher.bsc + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + Win32 + .\Release/hasher.tlb + + + + + MaxSpeed + OnlyExplicitInline + WIN32;NDEBUG;_WINDOWS;_USRDLL;HASHER_EXPORTS;%(PreprocessorDefinitions) + true + MultiThreaded + true + Use + stdafx.h + .\Release/hasher.pch + .\Release/ + .\Release/ + .\Release/ + Level3 + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x0813 + + + build assembly + ml.exe md4_asm.asm /c /coff + + + MD4_asm.obj;%(AdditionalDependencies) + .\Release/hasher.dll + true + .\Release/hasher.pdb + false + + + .\Release/hasher.lib + MachineX86 + + + true + .\Release/hasher.bsc + + + + + + + + + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + %(PreprocessorDefinitions) + Create + %(PreprocessorDefinitions) + Create + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/hasher/Hasher.vcxproj.filters b/hasher/Hasher.vcxproj.filters new file mode 100644 index 000000000..e020a5ee5 --- /dev/null +++ b/hasher/Hasher.vcxproj.filters @@ -0,0 +1,72 @@ + + + + + {643064fb-b43c-4e13-ab66-fa006d95e3d7} + cpp;c;cxx;rc;def;r;odl;idl;hpj;bat + + + {0c572f2d-f686-47b0-8ad0-62b4e0c6c1d3} + h;hpp;hxx;hm;inl + + + {1c729e05-58c4-4acb-aa48-e837e5aa513a} + ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/hasher/Hasher.vcxproj.user b/hasher/Hasher.vcxproj.user new file mode 100644 index 000000000..695b5c78b --- /dev/null +++ b/hasher/Hasher.vcxproj.user @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/hasher/MD4.cpp b/hasher/MD4.cpp new file mode 100644 index 000000000..4fdd3ab14 --- /dev/null +++ b/hasher/MD4.cpp @@ -0,0 +1,138 @@ +// +// Free implementation of the MD4 hash algorithm +// MD4C.C - RSA Data Security, Inc., MD4 message-digest algorithm +// + +/* + Copyright (C) 1990-2, RSA Data Security, Inc. All rights reserved. + + License to copy and use this software is granted provided that it + is identified as the "RSA Data Security, Inc. MD4 Message-Digest + Algorithm" in all material mentioning or referencing this software + or this function. + + License is also granted to make and use derivative works provided + that such works are identified as "derived from the RSA Data + Security, Inc. MD4 Message-Digest Algorithm" in all material + mentioning or referencing the derived work. + + RSA Data Security, Inc. makes no representations concerning either + the merchantability of this software or the suitability of this + software for any particular purpose. It is provided "as is" + without express or implied warranty of any kind. + + These notices must be retained in any copies of any part of this + documentation and/or software. +*/ +#include "StdAfx.h" +#include "MD4.h" + +#include +#include + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + + +/////////////////////////////////////////////////////////////////////////////// +// Sanity checks for external assembler implemention +// +extern "C" DWORD MD4_asm_m_nCount0; +extern "C" DWORD MD4_asm_m_nCount1; +extern "C" DWORD MD4_asm_m_nState0; +extern "C" DWORD MD4_asm_m_nState1; +extern "C" DWORD MD4_asm_m_nState2; +extern "C" DWORD MD4_asm_m_nState3; +extern "C" DWORD MD4_asm_m_nBuffer; + +bool CMD4::VerifyImplementation() +{ + if (MD4_asm_m_nCount0 != offsetof(CMD4, m_nCount[0]) || + MD4_asm_m_nCount1 != offsetof(CMD4, m_nCount[1]) ){ + _ASSERT(0); + return false; + } + + if (MD4_asm_m_nState0 != offsetof(CMD4, m_nState[0]) || + MD4_asm_m_nState1 != offsetof(CMD4, m_nState[1]) || + MD4_asm_m_nState2 != offsetof(CMD4, m_nState[2]) || + MD4_asm_m_nState3 != offsetof(CMD4, m_nState[3]) ){ + _ASSERT(0); + return false; + } + + if (MD4_asm_m_nBuffer != offsetof(CMD4, m_nBuffer)){ + _ASSERT(0); + return false; + } + + return true; +} + + +/////////////////////////////////////////////////////////////////////////////// +// CMD4 +// + +CMD4::CMD4() +{ + Reset(); +} + +CMD4::~CMD4() +{ +} + +static unsigned char MD4_PADDING[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +extern "C" void MD4_Add_p5(CMD4*, LPCVOID pData, DWORD nLength); + +// MD4 initialization. Begins an MD4 operation, writing a new context + +void CMD4::Reset() +{ + // Clear counts + m_nCount[0] = m_nCount[1] = 0; + // Load magic initialization constants + m_nState[0] = 0x67452301; + m_nState[1] = 0xefcdab89; + m_nState[2] = 0x98badcfe; + m_nState[3] = 0x10325476; +} + +// Fetch hash +void CMD4::GetHash(MD4* pHash) +{ + memcpy(pHash->b, m_nState, 16); +} + +// MD4 block update operation. Continues an MD4 message-digest +// operation, processing another message block, and updating the +// context +void CMD4::Add(LPCVOID pData, DWORD nLength) +{ + MD4_Add_p5(this, pData, nLength); +} + +// MD4 finalization. Ends an MD4 message-digest operation, writing the +// the message digest and zeroizing the context. + +void CMD4::Finish() +{ + unsigned int bits[2], index = 0; + // Save number of bits + bits[1] = ( m_nCount[1] << 3 ) + ( m_nCount[0] >> 29); + bits[0] = m_nCount[0] << 3; + // Pad out to 56 mod 64. + index = (unsigned int)(m_nCount[0] & 0x3f); + MD4_Add_p5(this, MD4_PADDING, (index < 56) ? (56 - index) : (120 - index) ); + // Append length (before padding) + MD4_Add_p5(this, bits, 8 ); +} diff --git a/hasher/MD4.h b/hasher/MD4.h new file mode 100644 index 000000000..ebbedb6c9 --- /dev/null +++ b/hasher/MD4.h @@ -0,0 +1,63 @@ +// +// MD4.h +// +// Copyright (c) Shareaza Development Team, 2002-2004. +// This file is part of SHAREAZA (www.shareaza.com) +// +// Shareaza is free software; you can redistribute it +// and/or modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 of +// the License, or (at your option) any later version. +// +// Shareaza is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Shareaza; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +#pragma once + +typedef union +{ + BYTE n[16]; + BYTE b[16]; + DWORD w[4]; +} MD4, MD5; + +class CMD4 +{ +// Construction +public: + CMD4(); + virtual ~CMD4(); + + static bool VerifyImplementation(); + +// Attributes +protected: + // NOTE: if you change this, modify the offsets in MD4_ASM.ASM accordingly + DWORD m_nState[4]; + DWORD m_nCount[2]; + BYTE m_nBuffer[64]; + +// Operations +public: + void Reset(); + void Add(LPCVOID pData, DWORD nLength); + void Finish(); + void GetHash(MD4* pHash); + const BYTE* GetHash() const { return (const BYTE*)m_nState; } +}; + +inline bool operator==(const MD4& md4a, const MD4& md4b) +{ + return memcmp( &md4a, &md4b, 16 ) == 0; +} + +inline bool operator!=(const MD4& md4a, const MD4& md4b) +{ + return memcmp( &md4a, &md4b, 16 ) != 0; +} diff --git a/hasher/MD4_asm.asm b/hasher/MD4_asm.asm new file mode 100644 index 000000000..ad7cb5823 --- /dev/null +++ b/hasher/MD4_asm.asm @@ -0,0 +1,297 @@ +; ##################################################################################################################### +; +; MD4_asm.asm +; +; Copyright (c) Shareaza Development Team, 2002-2004. +; This file is part of SHAREAZA (www.shareaza.com) +; +; Shareaza is free software; you can redistribute it +; and/or modify it under the terms of the GNU General Public License +; as published by the Free Software Foundation; either version 2 of +; the License, or (at your option) any later version. +; +; Shareaza is distributed in the hope that it will be useful, +; but WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +; GNU General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with Shareaza; if not, write to the Free Software +; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +; +; ##################################################################################################################### +; +; MD4_asm - Implementation of MD4 for x86 - use together with MD4.cpp and MD4.h +; +; created 7.7.2004 by Camper +; +; last modified 20.7.2004 by Camper +; +; The integration into other projects than Shareaza is expressivly encouraged. Feel free to contact me about it. +; +; ##################################################################################################################### + + .586p + .model flat, C + option casemap:none ; case sensitive + option prologue:none ; we generate our own entry/exit code + option epilogue:none + +; ##################################################################################################################### + +CMD4_MemberStart EQU 4 ; skip vtbl + +m_nState0 EQU CMD4_MemberStart+0 ; offsets as found in MD4.h +m_nState1 EQU CMD4_MemberStart+4 +m_nState2 EQU CMD4_MemberStart+8 +m_nState3 EQU CMD4_MemberStart+12 + +m_nCount0 EQU CMD4_MemberStart+16 +m_nCount1 EQU CMD4_MemberStart+20 + +m_nBuffer EQU CMD4_MemberStart+24 + + + .data +MD4_asm_m_nState0 DD m_nState0 +MD4_asm_m_nState1 DD m_nState1 +MD4_asm_m_nState2 DD m_nState2 +MD4_asm_m_nState3 DD m_nState3 +MD4_asm_m_nCount0 DD m_nCount0 +MD4_asm_m_nCount1 DD m_nCount1 +MD4_asm_m_nBuffer DD m_nBuffer + + PUBLIC MD4_asm_m_nState0 + PUBLIC MD4_asm_m_nState1 + PUBLIC MD4_asm_m_nState2 + PUBLIC MD4_asm_m_nState3 + PUBLIC MD4_asm_m_nCount0 + PUBLIC MD4_asm_m_nCount1 + PUBLIC MD4_asm_m_nBuffer + + +; Some magic numbers for Transform... +MD4_S11 EQU 3 +MD4_S12 EQU 7 +MD4_S13 EQU 11 +MD4_S14 EQU 19 +MD4_S21 EQU 3 +MD4_S22 EQU 5 +MD4_S23 EQU 9 +MD4_S24 EQU 13 +MD4_S31 EQU 3 +MD4_S32 EQU 9 +MD4_S33 EQU 11 +MD4_S34 EQU 15 + +MD4FF MACRO a:REQ,b:REQ,c:REQ,d:REQ,count:REQ,s:REQ +; a = (a+x[count]+((b&c)|(~b&d))) rol s + mov reg_temp1, b + mov reg_temp2, b + add a, [reg_base+count*4] +reg_t textequ reg_temp1 +reg_temp1 textequ b ; an attempt to improve instruction pairing +b textequ reg_t + not reg_temp1 + and reg_temp2, c + and reg_temp1, d + or reg_temp1, reg_temp2 + add a, reg_temp1 + rol a, s + ENDM + +MD4GG MACRO a:REQ,b:REQ,c:REQ,d:REQ,count:REQ,s:REQ +; a = (a+x[count]+((b&c)|(b&d)|(c&d))+5A827999H) rol s + mov reg_temp1, b + mov reg_temp2, b + add a, [reg_base+count*4] +reg_t textequ reg_temp1 +reg_temp1 textequ b ; an attempt to improve instruction pairing +b textequ reg_t + and reg_temp1, c + and reg_temp2, d + add a, 5A827999H + or reg_temp1, reg_temp2 + mov reg_temp2, c + and reg_temp2, d + or reg_temp1, reg_temp2 + add a, reg_temp1 + rol a, s + ENDM + +MD4HH MACRO a:REQ,b:REQ,c:REQ,d:REQ,count:REQ,s:REQ +; a = (a+x[count]+(b^c^d)+6ED9EBA1H) rol s + mov reg_temp1, b + add a, [reg_base+count*4] +reg_t textequ reg_temp1 +reg_temp1 textequ b ; an attempt to improve instruction pairing +b textequ reg_t + xor reg_temp1, c + add a, 6ED9EBA1H + xor reg_temp1, d + add a, reg_temp1 + rol a, s + ENDM + + .code + +MD4_Transform_p5 PROC ; we expect ebp to point to the Data stream + ; all other registers (eax,ebx,ecx,edx,esi,edi) will be destroyed +__this textequ <[esp+32+2*4]> ; 1*pusha+2*call + +; set alias for registers +reg_a textequ +reg_b textequ +reg_c textequ +reg_d textequ +reg_temp1 textequ +reg_temp2 textequ +reg_base textequ + + mov reg_temp1, __this + mov reg_a, [reg_temp1+m_nState0] + mov reg_b, [reg_temp1+m_nState1] + mov reg_c, [reg_temp1+m_nState2] + mov reg_d, [reg_temp1+m_nState3] + +; round 1 + MD4FF reg_a, reg_b, reg_c, reg_d, 0, MD4_S11 + MD4FF reg_d, reg_a, reg_b, reg_c, 1, MD4_S12 + MD4FF reg_c, reg_d, reg_a, reg_b, 2, MD4_S13 + MD4FF reg_b, reg_c, reg_d, reg_a, 3, MD4_S14 + + MD4FF reg_a, reg_b, reg_c, reg_d, 4, MD4_S11 + MD4FF reg_d, reg_a, reg_b, reg_c, 5, MD4_S12 + MD4FF reg_c, reg_d, reg_a, reg_b, 6, MD4_S13 + MD4FF reg_b, reg_c, reg_d, reg_a, 7, MD4_S14 + + MD4FF reg_a, reg_b, reg_c, reg_d, 8, MD4_S11 + MD4FF reg_d, reg_a, reg_b, reg_c, 9, MD4_S12 + MD4FF reg_c, reg_d, reg_a, reg_b, 10, MD4_S13 + MD4FF reg_b, reg_c, reg_d, reg_a, 11, MD4_S14 + + MD4FF reg_a, reg_b, reg_c, reg_d, 12, MD4_S11 + MD4FF reg_d, reg_a, reg_b, reg_c, 13, MD4_S12 + MD4FF reg_c, reg_d, reg_a, reg_b, 14, MD4_S13 + MD4FF reg_b, reg_c, reg_d, reg_a, 15, MD4_S14 + +; round 2 + + MD4GG reg_a, reg_b, reg_c, reg_d, 0, MD4_S21 + MD4GG reg_d, reg_a, reg_b, reg_c, 4, MD4_S22 + MD4GG reg_c, reg_d, reg_a, reg_b, 8, MD4_S23 + MD4GG reg_b, reg_c, reg_d, reg_a, 12, MD4_S24 + + MD4GG reg_a, reg_b, reg_c, reg_d, 1, MD4_S21 + MD4GG reg_d, reg_a, reg_b, reg_c, 5, MD4_S22 + MD4GG reg_c, reg_d, reg_a, reg_b, 9, MD4_S23 + MD4GG reg_b, reg_c, reg_d, reg_a, 13, MD4_S24 + + MD4GG reg_a, reg_b, reg_c, reg_d, 2, MD4_S21 + MD4GG reg_d, reg_a, reg_b, reg_c, 6, MD4_S22 + MD4GG reg_c, reg_d, reg_a, reg_b, 10, MD4_S23 + MD4GG reg_b, reg_c, reg_d, reg_a, 14, MD4_S24 + + MD4GG reg_a, reg_b, reg_c, reg_d, 3, MD4_S21 + MD4GG reg_d, reg_a, reg_b, reg_c, 7, MD4_S22 + MD4GG reg_c, reg_d, reg_a, reg_b, 11, MD4_S23 + MD4GG reg_b, reg_c, reg_d, reg_a, 15, MD4_S24 + +; round 3 + + MD4HH reg_a, reg_b, reg_c, reg_d, 0, MD4_S31 + MD4HH reg_d, reg_a, reg_b, reg_c, 8, MD4_S32 + MD4HH reg_c, reg_d, reg_a, reg_b, 4, MD4_S33 + MD4HH reg_b, reg_c, reg_d, reg_a, 12, MD4_S34 + + MD4HH reg_a, reg_b, reg_c, reg_d, 2, MD4_S31 + MD4HH reg_d, reg_a, reg_b, reg_c, 10, MD4_S32 + MD4HH reg_c, reg_d, reg_a, reg_b, 6, MD4_S33 + MD4HH reg_b, reg_c, reg_d, reg_a, 14, MD4_S34 + + MD4HH reg_a, reg_b, reg_c, reg_d, 1, MD4_S31 + MD4HH reg_d, reg_a, reg_b, reg_c, 9, MD4_S32 + MD4HH reg_c, reg_d, reg_a, reg_b, 5, MD4_S33 + MD4HH reg_b, reg_c, reg_d, reg_a, 13, MD4_S34 + + MD4HH reg_a, reg_b, reg_c, reg_d, 3, MD4_S31 + MD4HH reg_d, reg_a, reg_b, reg_c, 11, MD4_S32 + MD4HH reg_c, reg_d, reg_a, reg_b, 7, MD4_S33 + MD4HH reg_b, reg_c, reg_d, reg_a, 15, MD4_S34 + + mov reg_temp1, __this + add [reg_temp1+m_nState0], reg_a + add [reg_temp1+m_nState1], reg_b + add [reg_temp1+m_nState2], reg_c + add [reg_temp1+m_nState3], reg_d + + ret + +MD4_Transform_p5 ENDP + +MD4_Add_p5 PROC PUBLIC, _this:DWORD, _Data:DWORD, _nLength:DWORD + + pusha +__this textequ <[esp+36]> ; different offset due to pusha +__Data textequ <[esp+40]> +__nLength textequ <[esp+44]> + + mov ecx, __nLength + and ecx, ecx + jz get_out + xor edx, edx + mov ebp, __Data + mov edi, __this + mov ebx, [edi+m_nCount0] + mov eax, ebx + add ebx, ecx + mov [edi+m_nCount0], ebx + adc [edi+m_nCount1], edx + + and eax, 63 + jnz partial_buffer +full_blocks: mov ecx, __nLength + and ecx, ecx + jz get_out + sub ecx, 64 + jb end_of_stream + mov __nLength, ecx + call MD4_Transform_p5 + add ebp, 64 + jmp full_blocks + +end_of_stream: mov edi, __this + mov esi, ebp + lea edi, [edi+m_nBuffer] + add ecx, 64 + rep movsb + jmp get_out + +partial_buffer: add ecx, eax ; eax = offset in buffer, ecx = _nLength + cmp ecx, 64 + jb short_stream ; we can't fill the buffer + mov ecx, -64 + add ecx, eax + add __nLength, ecx ; _nlength += (offset-64) +@@: mov bl, [ebp] + inc ebp + mov byte ptr [edi+m_nBuffer+64+ecx], bl + inc ecx + jnz @B ; offset = 64 + mov __Data, ebp + lea ebp, [edi+m_nBuffer] + call MD4_Transform_p5 + mov ebp, __Data + jmp full_blocks + +short_stream: sub ecx, eax ; --> ecx=_nLength + mov esi, ebp + lea edi, [edi+m_nBuffer+eax] + rep movsb + +get_out: popa + ret + +MD4_Add_p5 ENDP + + end diff --git a/hasher/SHA.cpp b/hasher/SHA.cpp new file mode 100644 index 000000000..b5d947bfa --- /dev/null +++ b/hasher/SHA.cpp @@ -0,0 +1,251 @@ +// +// This file is part of the aMule Project. +// +// Copyright (c) 2003-2006 Angel Vidal (Kry) ( kry@amule.org ) +// Copyright (c) 2003-2006 aMule Team ( admin@amule.org / http://www.amule.org ) +// +// Any parts of this program derived from the xMule, lMule or eMule project, +// or contributed by third-party developers are copyrighted by their +// respective authors. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA +// +// Kry - Modified version of the original SHA.cpp to work on linux and +// use wxWidgets. Original license follows. +// + +/* + --------------------------------------------------------------------------- + Copyright (c) 2002, Dr Brian Gladman , Worcester, UK. + All rights reserved. + + LICENSE TERMS + + The free distribution and use of this software in both source and binary + form is allowed (with or without changes) provided that: + + 1. distributions of this source code include the above copyright + notice, this list of conditions and the following disclaimer; + + 2. distributions in binary form include the above copyright + notice, this list of conditions and the following disclaimer + in the documentation and/or other associated materials; + + 3. the copyright holder's name is not used to endorse products + built using this software without specific written permission. + + ALTERNATIVELY, provided that this notice is retained in full, this product + may be distributed under the terms of the GNU General Public License (GPL), + in which case the provisions of the GPL apply INSTEAD OF those given above. + + DISCLAIMER + + This software is provided 'as is' with no explicit or implied warranties + in respect of its properties, including, but not limited to, correctness + and/or fitness for purpose. + --------------------------------------------------------------------------- + Issue Date: 30/11/2002 + + This is a byte oriented version of SHA1 that operates on arrays of bytes + stored in memory. It runs at 22 cycles per byte on a Pentium P4 processor +*/ +#include "stdafx.h" +#include "SHA.h" + + +CSHA::CSHA() +{ + Reset(); +} +/* + To obtain the highest speed on processors with 32-bit words, this code + needs to determine the order in which bytes are packed into such words. + The following block of code is an attempt to capture the most obvious + ways in which various environemnts specify their endian definitions. + It may well fail, in which case the definitions will need to be set by + editing at the points marked **** EDIT HERE IF NECESSARY **** below. +*/ +#define SHA_LITTLE_ENDIAN 1234 /* byte 0 is least significant (i386) */ +#define SHA_BIG_ENDIAN 4321 /* byte 0 is most significant (mc68k) */ + +// Kry - Use wxWidgets byte order definitions +#if wxBYTE_ORDER == wxLITTLE_ENDIAN + #define PLATFORM_BYTE_ORDER SHA_LITTLE_ENDIAN +#else + #define PLATFORM_BYTE_ORDER SHA_BIG_ENDIAN +#endif + +#define rotl32(x,n) (((x) << n) | ((x) >> (32 - n))) + +#if (PLATFORM_BYTE_ORDER == SHA_BIG_ENDIAN) +#define swap_b32(x) (x) +#elif defined(bswap_32) +#define swap_b32(x) bswap_32(x) +#else +#define swap_b32(x) ((rotl32((x), 8) & 0x00ff00ff) | (rotl32((x), 24) & 0xff00ff00)) +#endif + +#define SHA1_MASK (SHA1_BLOCK_SIZE - 1) + +/* reverse byte order in 32-bit words */ + +#define ch(x,y,z) (((x) & (y)) ^ (~(x) & (z))) +#define parity(x,y,z) ((x) ^ (y) ^ (z)) +#define maj(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) + +/* A normal version as set out in the FIPS. This version uses */ +/* partial loop unrolling and is optimised for the Pentium 4 */ + +#define rnd(f,k) t = a; a = rotl32(a,5) + f(b,c,d) + e + k + w[i]; e = d; d = c; c = rotl32(b, 30); b = t + +void CSHA::Compile() +{ + uint32 w[80], i, a, b, c, d, e, t; + + /* note that words are compiled from the buffer into 32-bit */ + /* words in big-endian order so an order reversal is needed */ + /* here on little endian machines */ + for(i = 0; i < SHA1_BLOCK_SIZE / 4; ++i) + w[i] = swap_b32(m_nBuffer[i]); + + for(i = SHA1_BLOCK_SIZE / 4; i < 80; ++i) + w[i] = rotl32(w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16], 1); + + a = m_nHash[0]; + b = m_nHash[1]; + c = m_nHash[2]; + d = m_nHash[3]; + e = m_nHash[4]; + + for(i = 0; i < 20; ++i) + { + rnd(ch, 0x5a827999); + } + + for(i = 20; i < 40; ++i) + { + rnd(parity, 0x6ed9eba1); + } + + for(i = 40; i < 60; ++i) + { + rnd(maj, 0x8f1bbcdc); + } + + for(i = 60; i < 80; ++i) + { + rnd(parity, 0xca62c1d6); + } + + m_nHash[0] += a; + m_nHash[1] += b; + m_nHash[2] += c; + m_nHash[3] += d; + m_nHash[4] += e; +} + +void CSHA::Reset() +{ + m_nCount[0] = m_nCount[1] = 0; + m_nHash[0] = 0x67452301; + m_nHash[1] = 0xefcdab89; + m_nHash[2] = 0x98badcfe; + m_nHash[3] = 0x10325476; + m_nHash[4] = 0xc3d2e1f0; +} + +void CSHA::GetHash(CAICHHash& Hash) +{ + /* extract the hash value as bytes in case the hash buffer is */ + /* misaligned for 32-bit words*/ + + //wxASSERT( Hash.GetHashSize() == 20 ); + for(int i = 0; i < SHA1_DIGEST_SIZE; ++i) + Hash.GetRawHash()[i] = (unsigned char)(m_nHash[i >> 2] >> 8 * (~i & 3)); +} + +/* SHA1 hash data in an array of bytes into hash buffer and call the */ +/* hash_compile function as required. */ + +void CSHA::Add(const void* pData, uint32 nLength) +{ + const unsigned char* data = (const unsigned char*)pData; + + uint32 pos = (uint32)(m_nCount[0] & SHA1_MASK), + space = SHA1_BLOCK_SIZE - pos; + const unsigned char *sp = data; + + if((m_nCount[0] += nLength) < nLength) + ++(m_nCount[1]); + + while(nLength >= space) /* tranfer whole blocks while possible */ + { + memcpy(((unsigned char*)m_nBuffer) + pos, sp, space); + sp += space; nLength -= space; space = SHA1_BLOCK_SIZE; pos = 0; + Compile(); + } + + memcpy(((unsigned char*)m_nBuffer) + pos, sp, nLength); +} + +/* SHA1 final padding and digest calculation */ + +#if (PLATFORM_BYTE_ORDER == SHA_LITTLE_ENDIAN) +static uint32 mask[4] = + { 0x00000000, 0x000000ff, 0x0000ffff, 0x00ffffff }; +static uint32 bits[4] = + { 0x00000080, 0x00008000, 0x00800000, 0x80000000 }; +#else +static uint32 mask[4] = + { 0x00000000, 0xff000000, 0xffff0000, 0xffffff00 }; +static uint32 bits[4] = + { 0x80000000, 0x00800000, 0x00008000, 0x00000080 }; +#endif + +void CSHA::Finish(CAICHHash& Hash) +{ + uint32 i = (uint32)(m_nCount[0] & SHA1_MASK); + + /* mask out the rest of any partial 32-bit word and then set */ + /* the next byte to 0x80. On big-endian machines any bytes in */ + /* the buffer will be at the top end of 32 bit words, on little */ + /* endian machines they will be at the bottom. Hence the AND */ + /* and OR masks above are reversed for little endian systems */ + /* Note that we can always add the first padding byte at this */ + /* because the buffer always contains at least one empty slot */ + m_nBuffer[i >> 2] = (m_nBuffer[i >> 2] & mask[i & 3]) | bits[i & 3]; + + /* we need 9 or more empty positions, one for the padding byte */ + /* (above) and eight for the length count. If there is not */ + /* enough space pad and empty the buffer */ + if(i > SHA1_BLOCK_SIZE - 9) + { + if(i < 60) m_nBuffer[15] = 0; + Compile(); + i = 0; + } + else /* compute a word index for the empty buffer positions */ + i = (i >> 2) + 1; + + while(i < 14) /* and zero pad all but last two positions */ + m_nBuffer[i++] = 0; + + /* assemble the eight byte counter in in big-endian format */ + m_nBuffer[14] = swap_b32((m_nCount[1] << 3) | (m_nCount[0] >> 29)); + m_nBuffer[15] = swap_b32(m_nCount[0] << 3); + + Compile(); + GetHash(Hash); +} diff --git a/hasher/SHA.h b/hasher/SHA.h new file mode 100644 index 000000000..f9175732c --- /dev/null +++ b/hasher/SHA.h @@ -0,0 +1,93 @@ +// +// This file is part of the aMule Project. +// +// Copyright (c) 2003-2006 Angel Vidal (Kry) ( kry@amule.org ) +// Copyright (c) 2003-2006 aMule Team ( admin@amule.org / http://www.amule.org ) +// +// Any parts of this program derived from the xMule, lMule or eMule project, +// or contributed by third-party developers are copyrighted by their +// respective authors. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA +// +// Kry - Modified version of the original SHA.cpp to work on linux and +// use wxWidgets. Original license follows. +// + +/* + --------------------------------------------------------------------------- + Copyright (c) 2002, Dr Brian Gladman , Worcester, UK. + All rights reserved. + + LICENSE TERMS + + The free distribution and use of this software in both source and binary + form is allowed (with or without changes) provided that: + + 1. distributions of this source code include the above copyright + notice, this list of conditions and the following disclaimer; + + 2. distributions in binary form include the above copyright + notice, this list of conditions and the following disclaimer + in the documentation and/or other associated materials; + + 3. the copyright holder's name is not used to endorse products + built using this software without specific written permission. + + ALTERNATIVELY, provided that this notice is retained in full, this product + may be distributed under the terms of the GNU General Public License (GPL), + in which case the provisions of the GPL apply INSTEAD OF those given above. + + DISCLAIMER + + This software is provided 'as is' with no explicit or implied warranties + in respect of its properties, including, but not limited to, correctness + and/or fitness for purpose. + --------------------------------------------------------------------------- + Issue Date: 30/11/2002 + + This is a byte oriented version of SHA1 that operates on arrays of bytes + stored in memory. It runs at 22 cycles per byte on a Pentium P4 processor +*/ + +#ifndef __SHA_H__ +#define __SHA_H__ + +#include "ShaHashSet.h" + +class CSHA : public CAICHHashAlgo +{ +// Construction +public: + CSHA(); + virtual ~CSHA() {}; +// Operations +public: + virtual void Reset(); + virtual void Add(const void* pData, uint32 nLength); + virtual void Finish(CAICHHash& Hash); + virtual void GetHash(CAICHHash& Hash); +protected: + void Compile(); +private: + uint32 m_nCount[2]; + uint32 m_nHash[5]; + uint32 m_nBuffer[16]; +}; + +#define SHA1_BLOCK_SIZE 64 +#define SHA1_DIGEST_SIZE 20 + +#endif // __SHA_H__ diff --git a/hasher/SHAHashSet.cpp b/hasher/SHAHashSet.cpp new file mode 100644 index 000000000..86cbcf572 --- /dev/null +++ b/hasher/SHAHashSet.cpp @@ -0,0 +1,957 @@ +// +// This file is part of the aMule Project. +// +// Copyright (c) 2003-2006 Angel Vidal (Kry) ( kry@amule.org ) +// Copyright (c) 2003-2006 aMule Team ( admin@amule.org / http://www.amule.org ) +// Copyright (c) 2002 Merkur ( devs@emule-project.net / http://www.emule-project.net ) +// +// Any parts of this program derived from the xMule, lMule or eMule project, +// or contributed by third-party developers are copyrighted by their +// respective authors. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA +// +#include "StdAfx.h" +#include "SHAHashSet.h" +//#include "Types.h" +//#include "OPCodes.h" +//#include "amule.h" +//#include "MemFile.h" +//#include "KnownFile.h" +//#include "Preferences.h" +#include "SHA.h" +//#include "updownclient.h" +//#include "DownloadQueue.h" +//#include "PartFile.h" +//#include "Logger.h" +//#include + +#define ASSERT(b){if(!(b))printf("ASSERT!\n");} +#define VERIFY(b){if(!(b))printf("VERIFY!\n");} +void out(const char * str){ + printf("OUT: %s\n",str); +} + +//#include + +//using namespace std; + +/*#ifdef _DEBUG +#undef THIS_FILE +static char THIS_FILE[]=__FILE__; +#define new DEBUG_NEW +#endif*/ + +// for this version the limits are set very high, they might be lowered later +// to make a hash trustworthy, at least 10 unique Ips (255.255.128.0) must have send it +// and if we have received more than one hash for the file, one hash has to be send by more than 95% of all unique IPs +//#define MINUNIQUEIPS_TOTRUST 10 // how many unique IPs most have send us a hash to make it trustworthy +//#define MINPERCENTAGE_TOTRUST 92 // how many percentage of clients most have sent the same hash to make it trustworthy + +//CAICHRequestedDataList CAICHHashSet::m_liRequestedData; + +///////////////////////////////////////////////////////////////////////////////////////// +///CAICHHash +/*wxString CAICHHash::GetString() const{ + return EncodeBase32(m_abyBuffer, HASHSIZE); +}*/ + + +/*void CAICHHash::Read(CFileDataIO* file) { + file->Read(m_abyBuffer,HASHSIZE); +} + + +void CAICHHash::Write(CFileDataIO* file) const{ + file->Write(m_abyBuffer,HASHSIZE); +}*/ + +/*unsigned int CAICHHash::DecodeBase32(const wxString &base32) +{ + return ::DecodeBase32(base32, HASHSIZE, m_abyBuffer); +} */ + + +///////////////////////////////////////////////////////////////////////////////////////// +///CAICHHashTree + +CAICHHashTree::CAICHHashTree(uint64 nDataSize, bool bLeftBranch, uint64 nBaseSize){ + m_nDataSize = nDataSize; + m_nBaseSize = nBaseSize; + m_bIsLeftBranch = bLeftBranch; + m_pLeftTree = NULL; + m_pRightTree = NULL; + m_bHashValid = false; +} + +CAICHHashTree::~CAICHHashTree(){ + if (m_pLeftTree) + delete m_pLeftTree; + if (m_pRightTree) + delete m_pRightTree; +} + +// recursive +CAICHHashTree* CAICHHashTree::FindHash(uint64 nStartPos, uint64 nSize, uint8* nLevel){ + (*nLevel)++; + if (*nLevel > 22){ // sanity + ASSERT ( false ); + return false; + } + if (nStartPos + nSize > m_nDataSize){ // sanity + ASSERT ( false ); + return NULL; + } + if (nSize > m_nDataSize){ // sanity + ASSERT ( false ); + return NULL; + } + + if (nStartPos == 0 && nSize == m_nDataSize){ + // this is the searched hash + return this; + } + else if (m_nDataSize <= m_nBaseSize){ // sanity + // this is already the last level, cant go deeper + ASSERT( false ); + return NULL; + } + else{ + uint64 nBlocks = m_nDataSize / m_nBaseSize + ((m_nDataSize % m_nBaseSize != 0 )? 1:0); + uint64 nLeft = ( ((m_bIsLeftBranch) ? nBlocks+1:nBlocks) / 2)* m_nBaseSize; + uint64 nRight = m_nDataSize - nLeft; + if (nStartPos < nLeft){ + if (nStartPos + nSize > nLeft){ // sanity + ASSERT ( false ); + return NULL; + } + if (m_pLeftTree == NULL) + m_pLeftTree = new CAICHHashTree(nLeft, true, (nLeft <= PARTSIZE) ? EMBLOCKSIZE : PARTSIZE); + else{ + ASSERT( m_pLeftTree->m_nDataSize == nLeft ); + } + return m_pLeftTree->FindHash(nStartPos, nSize, nLevel); + } + else{ + nStartPos -= nLeft; + if (nStartPos + nSize > nRight){ // sanity + ASSERT ( false ); + return NULL; + } + if (m_pRightTree == NULL) + m_pRightTree = new CAICHHashTree(nRight, false, (nRight <= PARTSIZE) ? EMBLOCKSIZE : PARTSIZE); + else{ + ASSERT( m_pRightTree->m_nDataSize == nRight ); + } + return m_pRightTree->FindHash(nStartPos, nSize, nLevel); + } + } +} + +// recursive +// calculates missing hash fromt he existing ones +// overwrites existing hashs +// fails if no hash is found for any branch +bool CAICHHashTree::ReCalculateHash(CAICHHashAlgo* hashalg, bool bDontReplace){ + ASSERT ( !( (m_pLeftTree != NULL) ^ (m_pRightTree != NULL)) ); + if (m_pLeftTree && m_pRightTree){ + if ( !m_pLeftTree->ReCalculateHash(hashalg, bDontReplace) || !m_pRightTree->ReCalculateHash(hashalg, bDontReplace) ) + return false; + if (bDontReplace && m_bHashValid) + return true; + if (m_pRightTree->m_bHashValid && m_pLeftTree->m_bHashValid){ + hashalg->Reset(); + hashalg->Add(m_pLeftTree->m_Hash.GetRawHash(), HASHSIZE); + hashalg->Add(m_pRightTree->m_Hash.GetRawHash(), HASHSIZE); + hashalg->Finish(m_Hash); + m_bHashValid = true; + return true; + } + else + return m_bHashValid; + } + else + return true; +} + +bool CAICHHashTree::VerifyHashTree(CAICHHashAlgo* hashalg, bool bDeleteBadTrees){ + if (!m_bHashValid){ + ASSERT ( false ); + if (bDeleteBadTrees){ + if (m_pLeftTree){ + delete m_pLeftTree; + m_pLeftTree = NULL; + } + if (m_pRightTree){ + delete m_pRightTree; + m_pRightTree = NULL; + } + } + //AddDebugLogLineM( false, logSHAHashSet, wxT("VerifyHashTree - No masterhash available")); + printf("VerifyHashTree - No masterhash available\n"); + return false; + } + + // calculated missing hashs without overwriting anything + if (m_pLeftTree && !m_pLeftTree->m_bHashValid) + m_pLeftTree->ReCalculateHash(hashalg, true); + if (m_pRightTree && !m_pRightTree->m_bHashValid) + m_pRightTree->ReCalculateHash(hashalg, true); + + if ((m_pRightTree && m_pRightTree->m_bHashValid) ^ (m_pLeftTree && m_pLeftTree->m_bHashValid)){ + // one branch can never be verified + if (bDeleteBadTrees){ + if (m_pLeftTree){ + delete m_pLeftTree; + m_pLeftTree = NULL; + } + if (m_pRightTree){ + delete m_pRightTree; + m_pRightTree = NULL; + } + } + //AddDebugLogLineM( false, logSHAHashSet, wxT("VerifyHashSet failed - Hashtree incomplete")); + printf("VerifyHashSet failed - Hashtree incomplete\n"); + return false; + } + if ((m_pRightTree && m_pRightTree->m_bHashValid) && (m_pLeftTree && m_pLeftTree->m_bHashValid)){ + // check verify the hashs of both child nodes against my hash + + CAICHHash CmpHash; + hashalg->Reset(); + hashalg->Add(m_pLeftTree->m_Hash.GetRawHash(), HASHSIZE); + hashalg->Add(m_pRightTree->m_Hash.GetRawHash(), HASHSIZE); + hashalg->Finish(CmpHash); + + if (m_Hash != CmpHash){ + if (bDeleteBadTrees){ + if (m_pLeftTree){ + delete m_pLeftTree; + m_pLeftTree = NULL; + } + if (m_pRightTree){ + delete m_pRightTree; + m_pRightTree = NULL; + } + } + return false; + } + return m_pLeftTree->VerifyHashTree(hashalg, bDeleteBadTrees) && m_pRightTree->VerifyHashTree(hashalg, bDeleteBadTrees); + } + else + // last hash in branch - nothing below to verify + return true; + +} + +void CAICHHashTree::SetBlockHash(uint64 nSize, uint64 nStartPos, CAICHHashAlgo* pHashAlg){ + ASSERT ( nSize <= EMBLOCKSIZE ); + CAICHHashTree* pToInsert = FindHash(nStartPos, nSize); + if (pToInsert == NULL){ // sanity + ASSERT ( false ); + //AddDebugLogLineM( false, logSHAHashSet, wxT("Critical Error: Failed to Insert SHA-HashBlock, FindHash() failed!")); + out("Critical Error: Failed to Insert SHA-HashBlock, FindHash() failed!"); + return; + } + + //sanity + if (pToInsert->m_nBaseSize != EMBLOCKSIZE || pToInsert->m_nDataSize != nSize){ + ASSERT ( false ); + //AddDebugLogLineM( false, logSHAHashSet, wxT("Critical Error: Logical error on values in SetBlockHashFromData")); + out("Critical Error: Logical error on values in SetBlockHashFromData"); + return; + } + + pHashAlg->Finish(pToInsert->m_Hash); + pToInsert->m_bHashValid = true; +} +/* +bool CAICHHashTree::CreatePartRecoveryData(uint32 nStartPos, uint32 nSize, CFileDataIO* fileDataOut, uint16 wHashIdent){ + if (nStartPos + nSize > m_nDataSize){ // sanity + ASSERT ( false ); + return false; + } + if (nSize > m_nDataSize){ // sanity + ASSERT ( false ); + return false; + } + + if (nStartPos == 0 && nSize == m_nDataSize){ + // this is the searched part, now write all blocks of this part + // hashident for this level will be adjsuted by WriteLowestLevelHash + return WriteLowestLevelHashs(fileDataOut, wHashIdent); + } + else if (m_nDataSize <= m_nBaseSize){ // sanity + // this is already the last level, cant go deeper + ASSERT( false ); + return false; + } + else{ + wHashIdent <<= 1; + wHashIdent |= (m_bIsLeftBranch) ? 1: 0; + + uint32 nBlocks = m_nDataSize / m_nBaseSize + ((m_nDataSize % m_nBaseSize != 0 )? 1:0); + uint32 nLeft = ( ((m_bIsLeftBranch) ? nBlocks+1:nBlocks) / 2)* m_nBaseSize; + uint32 nRight = m_nDataSize - nLeft; + if (m_pLeftTree == NULL || m_pRightTree == NULL){ + ASSERT( false ); + return false; + } + if (nStartPos < nLeft){ + if (nStartPos + nSize > nLeft || !m_pRightTree->m_bHashValid){ // sanity + ASSERT ( false ); + return false; + } + m_pRightTree->WriteHash(fileDataOut, wHashIdent); + return m_pLeftTree->CreatePartRecoveryData(nStartPos, nSize, fileDataOut, wHashIdent); + } + else{ + nStartPos -= nLeft; + if (nStartPos + nSize > nRight || !m_pLeftTree->m_bHashValid){ // sanity + ASSERT ( false ); + return false; + } + m_pLeftTree->WriteHash(fileDataOut, wHashIdent); + return m_pRightTree->CreatePartRecoveryData(nStartPos, nSize, fileDataOut, wHashIdent); + + } + } +} + +void CAICHHashTree::WriteHash(CFileDataIO* fileDataOut, uint16 wHashIdent) const{ + ASSERT( m_bHashValid ); + wHashIdent <<= 1; + wHashIdent |= (m_bIsLeftBranch) ? 1: 0; + fileDataOut->WriteUInt16(wHashIdent); + m_Hash.Write(fileDataOut); +} + +// write lowest level hashs into file, ordered from left to right optional without identifier +bool CAICHHashTree::WriteLowestLevelHashs(CFileDataIO* fileDataOut, uint16 wHashIdent, bool bNoIdent) const{ + wHashIdent <<= 1; + wHashIdent |= (m_bIsLeftBranch) ? 1: 0; + if (m_pLeftTree == NULL && m_pRightTree == NULL){ + if (m_nDataSize <= m_nBaseSize && m_bHashValid ){ + if (!bNoIdent) + fileDataOut->WriteUInt16(wHashIdent); + m_Hash.Write(fileDataOut); + return true; + } + else{ + ASSERT( false ); + return false; + } + } + else if (m_pLeftTree == NULL || m_pRightTree == NULL){ + ASSERT( false ); + return false; + } + else{ + return m_pLeftTree->WriteLowestLevelHashs(fileDataOut, wHashIdent, bNoIdent) + && m_pRightTree->WriteLowestLevelHashs(fileDataOut, wHashIdent, bNoIdent); + } +} + +// recover all low level hashs from given data. hashs are assumed to be ordered in left to right - no identifier used +bool CAICHHashTree::LoadLowestLevelHashs(CFileDataIO* fileInput){ + if (m_nDataSize <= m_nBaseSize){ // sanity + // lowest level, read hash + m_Hash.Read(fileInput); + m_bHashValid = true; + return true; + } + else{ + uint32 nBlocks = m_nDataSize / m_nBaseSize + ((m_nDataSize % m_nBaseSize != 0 )? 1:0); + uint32 nLeft = ( ((m_bIsLeftBranch) ? nBlocks+1:nBlocks) / 2)* m_nBaseSize; + uint32 nRight = m_nDataSize - nLeft; + if (m_pLeftTree == NULL) + m_pLeftTree = new CAICHHashTree(nLeft, true, (nLeft <= PARTSIZE) ? EMBLOCKSIZE : PARTSIZE); + else{ + ASSERT( m_pLeftTree->m_nDataSize == nLeft ); + } + if (m_pRightTree == NULL) + m_pRightTree = new CAICHHashTree(nRight, false, (nRight <= PARTSIZE) ? EMBLOCKSIZE : PARTSIZE); + else{ + ASSERT( m_pRightTree->m_nDataSize == nRight ); + } + return m_pLeftTree->LoadLowestLevelHashs(fileInput) + && m_pRightTree->LoadLowestLevelHashs(fileInput); + } +} + + +// write the hash, specified by wHashIdent, with Data from fileInput. +bool CAICHHashTree::SetHash(CFileDataIO* fileInput, uint16 wHashIdent, sint8 nLevel, bool bAllowOverwrite){ + if (nLevel == (-1)){ + // first call, check how many level we need to go + uint8 i; + for (i = 0; i != 16 && (wHashIdent & 0x8000) == 0; ++i){ + wHashIdent <<= 1; + } + if (i > 15){ + AddDebugLogLineM( false, logSHAHashSet, wxT("CAICHHashTree::SetHash - found invalid HashIdent (0)")); + return false; + } + else{ + nLevel = 15 - i; + } + } + if (nLevel == 0){ + // this is the searched hash + if (m_bHashValid && !bAllowOverwrite){ + // not allowed to overwrite this hash, however move the filepointer by reading a hash + CAICHHash(file); + return true; + } + m_Hash.Read(fileInput); + m_bHashValid = true; + return true; + } + else if (m_nDataSize <= m_nBaseSize){ // sanity + // this is already the last level, cant go deeper + ASSERT( false ); + return false; + } + else{ + // adjust ident to point the path to the next node + wHashIdent <<= 1; + nLevel--; + uint32 nBlocks = m_nDataSize / m_nBaseSize + ((m_nDataSize % m_nBaseSize != 0 )? 1:0); + uint32 nLeft = ( ((m_bIsLeftBranch) ? nBlocks+1:nBlocks) / 2)* m_nBaseSize; + uint32 nRight = m_nDataSize - nLeft; + if ((wHashIdent & 0x8000) > 0){ + if (m_pLeftTree == NULL) + m_pLeftTree = new CAICHHashTree(nLeft, true, (nLeft <= PARTSIZE) ? EMBLOCKSIZE : PARTSIZE); + else{ + ASSERT( m_pLeftTree->m_nDataSize == nLeft ); + } + return m_pLeftTree->SetHash(fileInput, wHashIdent, nLevel); + } + else{ + if (m_pRightTree == NULL) + m_pRightTree = new CAICHHashTree(nRight, false, (nRight <= PARTSIZE) ? EMBLOCKSIZE : PARTSIZE); + else{ + ASSERT( m_pRightTree->m_nDataSize == nRight ); + } + return m_pRightTree->SetHash(fileInput, wHashIdent, nLevel); + } + } +}*/ + + +///////////////////////////////////////////////////////////////////////////////////////// +///CAICHUntrustedHash +/*bool CAICHUntrustedHash::AddSigningIP(uint32 dwIP){ + dwIP &= 0x00F0FFFF; // we use only the 20 most significant bytes for unique IPs + return m_adwIpsSigning.insert(dwIP).second; +}*/ + + + +///////////////////////////////////////////////////////////////////////////////////////// +///CAICHHashSet + +CAICHHashSet::CAICHHashSet()//CKnownFile* pOwner) + : m_pHashTree(0, true, PARTSIZE) +{ + m_eStatus = AICH_EMPTY; + //m_pOwner = pOwner; +} + +CAICHHashSet::~CAICHHashSet(void) +{ + FreeHashSet(); +} +/* +bool CAICHHashSet::CreatePartRecoveryData(uint32 nPartStartPos, CFileDataIO* fileDataOut, bool bDbgDontLoad){ + ASSERT( m_pOwner ); + if (m_pOwner->IsPartFile() || m_eStatus != AICH_HASHSETCOMPLETE){ + ASSERT( false ); + return false; + } + if (m_pHashTree.m_nDataSize <= EMBLOCKSIZE){ + ASSERT( false ); + return false; + } + if (!bDbgDontLoad){ + if (!LoadHashSet()){ + AddDebugLogLineM( false, logSHAHashSet, wxT("Created RecoveryData error: failed to load hashset. File:") + m_pOwner->GetFileName() ); + SetStatus(AICH_ERROR); + return false; + } + } + bool bResult; + uint8 nLevel = 0; + uint32 nPartSize = min(PARTSIZE, m_pOwner->GetFileSize()-nPartStartPos); + m_pHashTree.FindHash(nPartStartPos, nPartSize,&nLevel); + uint16 nHashsToWrite = (nLevel-1) + nPartSize/EMBLOCKSIZE + ((nPartSize % EMBLOCKSIZE != 0 )? 1:0); + fileDataOut->WriteUInt16(nHashsToWrite); + uint32 nCheckFilePos = fileDataOut->GetPosition(); + if (m_pHashTree.CreatePartRecoveryData(nPartStartPos, nPartSize, fileDataOut, 0)){ + if (nHashsToWrite*(HASHSIZE+2u) != fileDataOut->GetPosition() - nCheckFilePos){ + ASSERT( false ); + AddDebugLogLineM( false, logSHAHashSet, wxT("Created RecoveryData has wrong length. File: ") + m_pOwner->GetFileName() ); + bResult = false; + SetStatus(AICH_ERROR); + } + else + bResult = true; + } else { + AddDebugLogLineM( false, logSHAHashSet, wxT("Failed to create RecoveryData for ") + m_pOwner->GetFileName() ); + bResult = false; + SetStatus(AICH_ERROR); + } + if (!bDbgDontLoad){ + FreeHashSet(); + } + return bResult; +} + +bool CAICHHashSet::ReadRecoveryData(uint32 nPartStartPos, CMemFile* fileDataIn) +{ + if (!(m_eStatus == AICH_VERIFIED || m_eStatus == AICH_TRUSTED) ){ + ASSERT( false ); + return false; + } + // at this time we check the recoverydata for the correct ammounts of hashs only + // all hash are then taken into the tree, depending on there hashidentifier (except the masterhash) + + uint8 nLevel = 0; + uint32 nPartSize = min(PARTSIZE, m_pOwner->GetFileSize()-nPartStartPos); + m_pHashTree.FindHash(nPartStartPos, nPartSize,&nLevel); + uint16 nHashsToRead = (nLevel-1) + nPartSize/EMBLOCKSIZE + ((nPartSize % EMBLOCKSIZE != 0 )? 1:0); + uint16 nHashsAvailable = fileDataIn->ReadUInt16(); + if (fileDataIn->GetLength()-fileDataIn->GetPosition() < nHashsToRead*(HASHSIZE+2u) || nHashsToRead != nHashsAvailable){ + // this check is redunant, CSafememfile would catch such an error too + AddDebugLogLineM( false, logSHAHashSet, wxT("Failed to read RecoveryData for ") + m_pOwner->GetFileName() + wxT("%s - Received datasize/amounts of hashs was invalid")); + return false; + } + for (uint32 i = 0; i != nHashsToRead; ++i){ + uint16 wHashIdent = fileDataIn->ReadUInt16(); + if (wHashIdent == 1 //never allow masterhash to be overwritten + || !m_pHashTree.SetHash(fileDataIn, wHashIdent,(-1), false)) + { + AddDebugLogLineM( false, logSHAHashSet, wxT("Failed to read RecoveryData for ") + m_pOwner->GetFileName() + wxT(" - Error when trying to read hash into tree")); + VerifyHashTree(true); // remove invalid hashs which we have already written + return false; + } + } + if (VerifyHashTree(true)){ + // some final check if all hashs we wanted are there + for (uint32 nPartPos = 0; nPartPos < nPartSize; nPartPos += EMBLOCKSIZE){ + CAICHHashTree* phtToCheck = m_pHashTree.FindHash(nPartStartPos+nPartPos, min(EMBLOCKSIZE, nPartSize-nPartPos)); + if (phtToCheck == NULL || !phtToCheck->m_bHashValid){ + AddDebugLogLineM( false, logSHAHashSet, wxT("Failed to read RecoveryData for ") + m_pOwner->GetFileName() + wxT(" - Error while verifying presence of all lowest level hashs")); + return false; + } + } + // all done + return true; + } + else{ + AddDebugLogLineM( false, logSHAHashSet, wxT("Failed to read RecoveryData for ") + m_pOwner->GetFileName() + wxT(" - Verifying received hashtree failed")); + return false; + } +} + +// this function is only allowed to be called right after successfully calculating the hashset (!) +// will delete the hashset, after saving to free the memory +bool CAICHHashSet::SaveHashSet(){ + if (m_eStatus != AICH_HASHSETCOMPLETE){ + ASSERT( false ); + return false; + } + if ( !m_pHashTree.m_bHashValid || m_pHashTree.m_nDataSize != m_pOwner->GetFileSize()){ + ASSERT( false ); + return false; + } + wxString fullpath = theApp.ConfigDir + KNOWN2_MET_FILENAME; + CFile file; + if (wxFileExists(fullpath)) { + if (!file.Open(fullpath, CFile::read_write)) { + // Add logline about unable to open file + return false; + } + } else { + if (!file.Create(fullpath)) { + // Add logline about unable to create file + return false; + } + } + + try { + // first we check if the hashset we want to write is already stored + CAICHHash CurrentHash; + uint32 nExistingSize = file.GetLength(); + while (file.GetPosition() < nExistingSize){ + CurrentHash.Read(&file); + if (m_pHashTree.m_Hash == CurrentHash){ + // this hashset if already available, no need to save it again + return true; + } + uint16 nHashCount = file.ReadUInt16(); + if (file.GetPosition() + nHashCount*HASHSIZE > nExistingSize){ + throw fullpath; + } + // skip the rest of this hashset + file.Seek(nHashCount*HASHSIZE, wxFromCurrent); + } + // write hashset + m_pHashTree.m_Hash.Write(&file); + uint16 nHashCount = (PARTSIZE/EMBLOCKSIZE + ((PARTSIZE % EMBLOCKSIZE != 0)? 1 : 0)) * (m_pHashTree.m_nDataSize/PARTSIZE); + if (m_pHashTree.m_nDataSize % PARTSIZE != 0) + nHashCount += (m_pHashTree.m_nDataSize % PARTSIZE)/EMBLOCKSIZE + (((m_pHashTree.m_nDataSize % PARTSIZE) % EMBLOCKSIZE != 0)? 1 : 0); + file.WriteUInt16(nHashCount); + if (!m_pHashTree.WriteLowestLevelHashs(&file, 0, true)){ + // thats bad... really + file.SetLength(nExistingSize); + AddDebugLogLineM( true, logSHAHashSet, wxT("Failed to save HashSet: WriteLowestLevelHashs() failed!")); + return false; + } + if (file.GetLength() != nExistingSize + (nHashCount+1)*HASHSIZE + 2){ + // thats even worse + file.SetLength(nExistingSize); + AddDebugLogLineM( true, logSHAHashSet, wxT("Failed to save HashSet: Calculated and real size of hashset differ!")); + return false; + } + AddDebugLogLineM( false, logSHAHashSet, wxString::Format(wxT("Sucessfully saved eMuleAC Hashset, %u Hashs + 1 Masterhash written"), nHashCount)); + } catch (const wxString& error){ + AddDebugLogLineM(true, logSHAHashSet, wxT("Error: ") + error); + return false; + } catch (const CSafeIOException& e) { + AddDebugLogLineM(true, logSHAHashSet, wxT("IO error while saving AICH HashSet: ") + e.what()); + return false; + } + + FreeHashSet(); + return true; +} + + +bool CAICHHashSet::LoadHashSet() +{ + if (m_eStatus != AICH_HASHSETCOMPLETE){ + ASSERT( false ); + return false; + } + if ( !m_pHashTree.m_bHashValid || m_pHashTree.m_nDataSize != m_pOwner->GetFileSize() || m_pHashTree.m_nDataSize == 0){ + ASSERT( false ); + return false; + } + wxString fullpath = theApp.ConfigDir + KNOWN2_MET_FILENAME; + CFile file(fullpath, CFile::read_write); + if (!file.IsOpened()){ + if (wxFileExists(fullpath)) { + wxString strError(wxT("Failed to load ") KNOWN2_MET_FILENAME wxT(" file")); + AddDebugLogLineM( true, logSHAHashSet, strError); + } + return false; + } + + try { + //setvbuf(file.m_pStream, NULL, _IOFBF, 16384); + CAICHHash CurrentHash; + uint32 nExistingSize = file.GetLength(); + uint16 nHashCount; + while (file.GetPosition() < nExistingSize){ + CurrentHash.Read(&file); + if (m_pHashTree.m_Hash == CurrentHash){ + // found Hashset + uint32 nExpectedCount = (PARTSIZE/EMBLOCKSIZE + ((PARTSIZE % EMBLOCKSIZE != 0)? 1 : 0)) * (m_pHashTree.m_nDataSize/PARTSIZE); + if (m_pHashTree.m_nDataSize % PARTSIZE != 0) + nExpectedCount += (m_pHashTree.m_nDataSize % PARTSIZE)/EMBLOCKSIZE + (((m_pHashTree.m_nDataSize % PARTSIZE) % EMBLOCKSIZE != 0)? 1 : 0); + nHashCount = file.ReadUInt16(); + if (nHashCount != nExpectedCount){ + AddDebugLogLineM( true, logSHAHashSet, wxT("Failed to load HashSet: Available Hashs and expected hashcount differ!")); + return false; + } + if (!m_pHashTree.LoadLowestLevelHashs(&file)){ + AddDebugLogLineM( true, logSHAHashSet, wxT("Failed to load HashSet: LoadLowestLevelHashs failed!")); + return false; + } + if (!ReCalculateHash(false)){ + AddDebugLogLineM( true, logSHAHashSet, wxT("Failed to load HashSet: Calculating loaded hashs failed!")); + return false; + } + if (CurrentHash != m_pHashTree.m_Hash){ + AddDebugLogLineM( true, logSHAHashSet, wxT("Failed to load HashSet: Calculated Masterhash differs from given Masterhash - hashset corrupt!")); + return false; + } + return true; + } + nHashCount = file.ReadUInt16(); + if (file.GetPosition() + nHashCount*HASHSIZE > nExistingSize){ + throw fullpath; + } + // skip the rest of this hashset + file.Seek(nHashCount*HASHSIZE, wxFromCurrent); + } + AddDebugLogLineM( true, logSHAHashSet, wxT("Failed to load HashSet: HashSet not found!")); + } catch (const wxString& error) { + AddDebugLogLineM(true, logSHAHashSet, wxT("Error: ") + error); + return false; + } catch (const CSafeIOException& e) { + AddDebugLogLineM(true, logSHAHashSet, wxT("IO error while loading AICH HashSet: ") + e.what()); + return false; + } + + + return false; +}*/ + +// delete the hashset except the masterhash (we dont keep aich hashsets in memory to save ressources) +void CAICHHashSet::FreeHashSet(){ + if (m_pHashTree.m_pLeftTree){ + delete m_pHashTree.m_pLeftTree; + m_pHashTree.m_pLeftTree = NULL; + } + if (m_pHashTree.m_pRightTree){ + delete m_pHashTree.m_pRightTree; + m_pHashTree.m_pRightTree = NULL; + } +} + +/*void CAICHHashSet::SetMasterHash(const CAICHHash& Hash, EAICHStatus eNewStatus){ + m_pHashTree.m_Hash = Hash; + m_pHashTree.m_bHashValid = true; + SetStatus(eNewStatus); +}*/ + +CAICHHashAlgo* CAICHHashSet::GetNewHashAlgo(){ + return new CSHA(); +} + +bool CAICHHashSet::ReCalculateHash(bool bDontReplace){ + CAICHHashAlgo* hashalg = GetNewHashAlgo(); + bool bResult = m_pHashTree.ReCalculateHash(hashalg, bDontReplace); + delete hashalg; + return bResult; +} + +bool CAICHHashSet::VerifyHashTree(bool bDeleteBadTrees){ + CAICHHashAlgo* hashalg = GetNewHashAlgo(); + bool bResult = m_pHashTree.VerifyHashTree(hashalg, bDeleteBadTrees); + delete hashalg; + return bResult; +} + +void CAICHHashSet::SetFileSize(EMFileSize nSize){ + m_pHashTree.m_nDataSize = nSize; + m_pHashTree.m_nBaseSize = (nSize <= (uint64)PARTSIZE) ? EMBLOCKSIZE : PARTSIZE; +} +/* +void CAICHHashSet::UntrustedHashReceived(const CAICHHash& Hash, uint32 dwFromIP){ + switch(GetStatus()){ + case AICH_EMPTY: + case AICH_UNTRUSTED: + case AICH_TRUSTED: + break; + default: + return; + } + bool bFound = false; + bool bAdded = false; + for (uint32 i = 0; i < m_aUntrustedHashs.size(); ++i){ + if (m_aUntrustedHashs[i].m_Hash == Hash){ + bAdded = m_aUntrustedHashs[i].AddSigningIP(dwFromIP); + bFound = true; + break; + } + } + if (!bFound){ + bAdded = true; + CAICHUntrustedHash uhToAdd; + uhToAdd.m_Hash = Hash; + uhToAdd.AddSigningIP(dwFromIP); + m_aUntrustedHashs.push_back(uhToAdd); + } + + uint32 nSigningIPsTotal = 0; // unique clients who send us a hash + sint32 nMostTrustedPos = (-1); // the hash which most clients send us + uint32 nMostTrustedIPs = 0; + for (uint32 i = 0; i < (uint32)m_aUntrustedHashs.size(); ++i){ + nSigningIPsTotal += m_aUntrustedHashs[i].m_adwIpsSigning.size(); + if ((uint32)m_aUntrustedHashs[i].m_adwIpsSigning.size() > nMostTrustedIPs){ + nMostTrustedIPs = m_aUntrustedHashs[i].m_adwIpsSigning.size(); + nMostTrustedPos = i; + } + } + if (nMostTrustedPos == (-1) || nSigningIPsTotal == 0){ + ASSERT( false ); + return; + } + // the check if we trust any hash + if ( thePrefs::IsTrustingEveryHash() || + (nMostTrustedIPs >= MINUNIQUEIPS_TOTRUST && (100 * nMostTrustedIPs)/nSigningIPsTotal >= MINPERCENTAGE_TOTRUST)){ + //trusted + AddDebugLogLineM(false, logSHAHashSet, + CFormat(wxT("IACH Hash recieved (%sadded), We have now %u hash(es) from %u unique IP(s). ") + wxT("We trust the Hash %s from %u client(s) (%u%%). File: %s")) + % (bAdded ? wxT("") : wxT("not ")) + % m_aUntrustedHashs.size() + % nSigningIPsTotal + % m_aUntrustedHashs[nMostTrustedPos].m_Hash.GetString() + % nMostTrustedIPs + % ((100 * nMostTrustedIPs) / nSigningIPsTotal) + % m_pOwner->GetFileName()); + + SetStatus(AICH_TRUSTED); + if (!HasValidMasterHash() || GetMasterHash() != m_aUntrustedHashs[nMostTrustedPos].m_Hash){ + SetMasterHash(m_aUntrustedHashs[nMostTrustedPos].m_Hash, AICH_TRUSTED); + FreeHashSet(); + } + } else { + // untrusted + AddDebugLogLineM(false, logSHAHashSet, + CFormat(wxT("IACH Hash recieved (%sadded), We have now %u hash(es) from %u unique IP(s). ") + wxT("Best Hash %s from %u clients (%u%%) - but we dont trust it yet. File: %s")) + % (bAdded ? wxT(""): wxT("not ")) + % m_aUntrustedHashs.size() + % nSigningIPsTotal + % m_aUntrustedHashs[nMostTrustedPos].m_Hash.GetString() + % nMostTrustedIPs + % ((100 * nMostTrustedIPs) / nSigningIPsTotal) + % m_pOwner->GetFileName()); + + SetStatus(AICH_UNTRUSTED); + if (!HasValidMasterHash() || GetMasterHash() != m_aUntrustedHashs[nMostTrustedPos].m_Hash){ + SetMasterHash(m_aUntrustedHashs[nMostTrustedPos].m_Hash, AICH_UNTRUSTED); + FreeHashSet(); + } + } +} + +#ifndef CLIENT_GUI + +void CAICHHashSet::ClientAICHRequestFailed(CUpDownClient* pClient){ + pClient->SetReqFileAICHHash(NULL); + CAICHRequestedData data = GetAICHReqDetails(pClient); + RemoveClientAICHRequest(pClient); + if (data.m_pClient != pClient) + return; + if( theApp.downloadqueue->IsPartFile(data.m_pPartFile)){ + AddDebugLogLineM( false, logSHAHashSet, wxT("IACH Request failed, Trying to ask another client (file ") + data.m_pPartFile->GetFileName() + wxString::Format(wxT(", Part: %u, Client"),data.m_nPart) + pClient->GetClientFullInfo()); + data.m_pPartFile->RequestAICHRecovery(data.m_nPart); + } +} + +#endif + +void CAICHHashSet::RemoveClientAICHRequest(const CUpDownClient* pClient) { + + for (CAICHRequestedDataList::iterator it = m_liRequestedData.begin();it != m_liRequestedData.end(); ++it) { + if ((*(it)).m_pClient == pClient){ + m_liRequestedData.erase(it); + return; + } + } + ASSERT( false ); +} + +bool CAICHHashSet::IsClientRequestPending(const CPartFile* pForFile, uint16 nPart){ + for (CAICHRequestedDataList::iterator it = m_liRequestedData.begin();it != m_liRequestedData.end(); ++it) { + if ((*(it)).m_pPartFile == pForFile && (*(it)).m_nPart == nPart){ + return true; + } + } + return false; +} + +CAICHRequestedData CAICHHashSet::GetAICHReqDetails(const CUpDownClient* pClient){ + for (CAICHRequestedDataList::iterator it = m_liRequestedData.begin();it != m_liRequestedData.end(); ++it) { + if ((*(it)).m_pClient == pClient){ + return *(it); + } + } + ASSERT( false ); + CAICHRequestedData empty; + return empty; +} + +bool CAICHHashSet::IsPartDataAvailable(uint32 nPartStartPos){ + if (!(m_eStatus == AICH_VERIFIED || m_eStatus == AICH_TRUSTED || m_eStatus == AICH_HASHSETCOMPLETE) ){ + ASSERT( false ); + return false; + } + uint32 nPartSize = min(PARTSIZE, m_pOwner->GetFileSize()-nPartStartPos); + for (uint32 nPartPos = 0; nPartPos < nPartSize; nPartPos += EMBLOCKSIZE){ + CAICHHashTree* phtToCheck = m_pHashTree.FindHash(nPartStartPos+nPartPos, min(EMBLOCKSIZE, nPartSize-nPartPos)); + if (phtToCheck == NULL || !phtToCheck->m_bHashValid){ + return false; + } + } + return true; +} + +// VC++ defines Assert as ASSERT. VC++ also defines VERIFY MACRO, which is the equivalent of ASSERT but also works in Released builds. + +#define VERIFY(x) ASSERT(x) + +void CAICHHashSet::DbgTest(){ + + //define TESTSIZE 4294567295 + uint8 maxLevel = 0; + uint32 cHash = 1; + uint8 curLevel = 0; + maxLevel = 0; + +#define TESTSIZE m_pHashTree.m_nDataSize + if (m_pHashTree.m_nDataSize <= EMBLOCKSIZE) + return; + CAICHHashSet TestHashSet(m_pOwner); + TestHashSet.SetFileSize(m_pOwner->GetFileSize()); + TestHashSet.SetMasterHash(GetMasterHash(), AICH_VERIFIED); + CMemFile file; + uint64 i = 0; + for (i = 0; i+9728000 < TESTSIZE; i += 9728000){ + VERIFY( CreatePartRecoveryData(i, &file) ); + + file.Seek(0,wxFromStart); + VERIFY( TestHashSet.ReadRecoveryData(i, &file) ); + file.Seek(0,wxFromStart); + TestHashSet.FreeHashSet(); + uint32 j = 0; + for (j = 0; j+EMBLOCKSIZE < 9728000; j += EMBLOCKSIZE){ + VERIFY( m_pHashTree.FindHash(i+j, EMBLOCKSIZE, &curLevel) ); + //TRACE(wxT("%u - %s\r\n"), cHash, m_pHashTree.FindHash(i+j, EMBLOCKSIZE, &curLevel)->m_Hash.GetString()); + maxLevel = max(curLevel, maxLevel); + curLevel = 0; + cHash++; + } + VERIFY( m_pHashTree.FindHash(i+j, 9728000-j, &curLevel) ); + //TRACE(wxT("%u - %s\r\n"), cHash, m_pHashTree.FindHash(i+j, 9728000-j, &curLevel)->m_Hash.GetString()); + maxLevel = max(curLevel, maxLevel); + curLevel = 0; + cHash++; + + } + VERIFY( CreatePartRecoveryData(i, &file) ); + file.Seek(0,wxFromStart); + VERIFY( TestHashSet.ReadRecoveryData(i, &file) ); + file.Seek(0,wxFromStart); + TestHashSet.FreeHashSet(); + uint64 j = 0; + for (j = 0; j+EMBLOCKSIZE < TESTSIZE-i; j += EMBLOCKSIZE){ + VERIFY( m_pHashTree.FindHash(i+j, EMBLOCKSIZE, &curLevel) ); + //TRACE(wxT("%u - %s\r\n"), cHash,m_pHashTree.FindHash(i+j, EMBLOCKSIZE, &curLevel)->m_Hash.GetString()); + maxLevel = max(curLevel, maxLevel); + curLevel = 0; + cHash++; + } + //VERIFY( m_pHashTree.FindHash(i+j, (TESTSIZE-i)-j, &curLevel) ); +// TRACE(wxT("%u - %s\r\n"), cHash,m_pHashTree.FindHash(i+j, (TESTSIZE-i)-j, &curLevel)->m_Hash.GetString()); + maxLevel = max(curLevel, maxLevel); + +}*/ diff --git a/hasher/SHAHashSet.h b/hasher/SHAHashSet.h new file mode 100644 index 000000000..76fe51149 --- /dev/null +++ b/hasher/SHAHashSet.h @@ -0,0 +1,257 @@ +// +// This file is part of the aMule Project. +// +// Copyright (c) 2003-2006 Angel Vidal (Kry) ( kry@amule.org ) +// Copyright (c) 2003-2006 aMule Team ( admin@amule.org / http://www.amule.org ) +// Copyright (c) 2002 Merkur ( devs@emule-project.net / http://www.emule-project.net ) +// +// Any parts of this program derived from the xMule, lMule or eMule project, +// or contributed by third-party developers are copyrighted by their +// respective authors. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA +// + +/* + SHA haset basically exists of 1 Tree for all Parts (9.28MB) + n Trees + for all blocks (180KB) while n is the number of Parts. + This means it is NOT a complete hashtree, since the 9.28MB is a given level, in order + to be able to create a hashset format similar to the MD4 one. + + If the number of elements for the next level are odd (for example 21 blocks to spread into 2 hashs) + the majority of elements will go into the left branch if the parent node was a left branch + and into the right branch if the parent node was a right branch. The first node is always + taken as a left branch. + +Example tree: + FileSize: 19506000 Bytes = 18,6 MB + + X (18,6) MasterHash + / \ + X (18,55) \ + / \ \ + X(9,28) x(9,28) X (0,05MB) PartHashs + / \ / \ \ + X(4,75) X(4,57) X(4,57) X(4,75) \ + + [...............] +X(180KB) X(180KB) [...] X(140KB) | X(180KB) X(180KB [...] BlockHashs + v + Border between first and second Part (9.28MB) + +HashsIdentifier: +When sending hashs, they are send with a 16bit identifier which specifies its postion in the +tree (so StartPosition + HashDataSize would lead to the same hash) +The identifier basically describes the way from the top of the tree to the hash. a set bit (1) +means follow the left branch, a 0 means follow the right. The highest bit which is set is seen as the start- +postion (since the first node is always seend as left). + +Example + + x 0000000000000001 + / \ + x \ 0000000000000011 + / \ \ + x _X_ x 0000000000000110 + + +*/ + +#ifndef __SHAHAHSET_H__ +#define __SHAHAHSET_H__ + +/*#include +#include +#include */ + +#include "Types.h" +#define PARTSIZE 9728000 +#define EMBLOCKSIZE 184320 +//typedef unsigned char uint8; +//typedef unsigned char uchar; + +#include "stdinc.h" + + +//typedef unsigned int uint32; +//typedef unsigned __int64 uint64; +#define HASHSIZE 20 +//#define KNOWN2_MET_FILENAME wxT("known2.met") + +enum EAICHStatus { + AICH_ERROR = 0, + AICH_EMPTY, + AICH_UNTRUSTED, + AICH_TRUSTED, + AICH_VERIFIED, + AICH_HASHSETCOMPLETE +}; + +/*class CFileDataIO; +class CKnownFile; +class CMemFile; +class CPartFile; +class CUpDownClient;*/ + +//using namespace std; + +///////////////////////////////////////////////////////////////////////////////////////// +///CAICHHash +typedef unsigned char byte; + +class CAICHHash +{ +public: + ~CAICHHash() {;} + CAICHHash() { memset(m_abyBuffer, 0, HASHSIZE); } + //CAICHHash(CFileDataIO* file) { Read(file); } + CAICHHash(byte* data) { Read(data); } + CAICHHash(const CAICHHash& k1) { *this = k1; } + CAICHHash& operator=(const CAICHHash& k1) { memcpy(m_abyBuffer, k1.m_abyBuffer, HASHSIZE); return *this; } + friend bool operator==(const CAICHHash& k1,const CAICHHash& k2) { return memcmp(k1.m_abyBuffer, k2.m_abyBuffer, HASHSIZE) == 0;} + friend bool operator!=(const CAICHHash& k1,const CAICHHash& k2) { return !(k1 == k2); } + //void Read(CFileDataIO* file); + //void Write(CFileDataIO* file) const; + void Read(byte* data) { memcpy(m_abyBuffer, data, HASHSIZE); } +// wxString GetString() const; + byte* GetRawHash() { return m_abyBuffer; } + + static unsigned int GetHashSize() { return HASHSIZE;} + + //unsigned int DecodeBase32(const wxString &base32); + +private: + byte m_abyBuffer[HASHSIZE]; +}; + +///////////////////////////////////////////////////////////////////////////////////////// +///CAICHHashAlgo +class CAICHHashAlgo +{ +public: + virtual ~CAICHHashAlgo() {}; + virtual void Reset() = 0; + virtual void Add(const void* pData, uint32 nLength) = 0; + virtual void Finish(CAICHHash& Hash) = 0; + virtual void GetHash(CAICHHash& Hash) = 0; +}; + +///////////////////////////////////////////////////////////////////////////////////////// +///CAICHHashTree +class CAICHHashTree +{ + // Madness from eMule, and gcc don't like being friend with itself... + // That probably means gcc is not friend of gcc. So gcc hates itself. + // friend class CAICHHashTree; + friend class CAICHHashSet; +public: + CAICHHashTree(uint64 nDataSize, bool bLeftBranch, uint64 nBaseSize); + ~CAICHHashTree(); + void SetBlockHash(uint64 nSize, uint64 nStartPos, CAICHHashAlgo* pHashAlg); + bool ReCalculateHash(CAICHHashAlgo* hashalg, bool bDontReplace ); + bool VerifyHashTree(CAICHHashAlgo* hashalg, bool bDeleteBadTrees); + CAICHHashTree* FindHash(uint64 nStartPos, uint64 nSize) {uint8 buffer = 0; return FindHash(nStartPos, nSize, &buffer);} + +protected: + CAICHHashTree* FindHash(uint64 nStartPos, uint64 nSize, uint8* nLevel); +// bool CreatePartRecoveryData(uint32 nStartPos, uint32 nSize, CFileDataIO* fileDataOut, uint16 wHashIdent); +// void WriteHash(CFileDataIO* fileDataOut, uint16 wHashIdent) const; +// bool WriteLowestLevelHashs(CFileDataIO* fileDataOut, uint16 wHashIdent, bool bNoIdent = false) const; +// bool LoadLowestLevelHashs(CFileDataIO* fileInput); +// bool SetHash(CFileDataIO* fileInput, uint16 wHashIdent, sint8 nLevel = (-1), bool bAllowOverwrite = true); + CAICHHashTree* m_pLeftTree; + CAICHHashTree* m_pRightTree; + +public: + CAICHHash m_Hash; + uint64 m_nDataSize; // size of data which is covered by this hash + uint64 m_nBaseSize; // blocksize on which the lowest hash is based on + bool m_bIsLeftBranch; // left or right branch of the tree + bool m_bHashValid; // the hash is valid and not empty +}; + +///////////////////////////////////////////////////////////////////////////////////////// +///CAICHUntrustedHashs +/*class CAICHUntrustedHash { +public: + CAICHUntrustedHash& operator=(const CAICHUntrustedHash& k1) { m_adwIpsSigning = k1.m_adwIpsSigning; m_Hash = k1.m_Hash ; return *this; } + bool AddSigningIP(uint32 dwIP); + + CAICHHash m_Hash; + set m_adwIpsSigning; +};*/ + +///////////////////////////////////////////////////////////////////////////////////////// +///CAICHUntrustedHashs +/*class CAICHRequestedData { +public: + CAICHRequestedData() {m_nPart = 0; m_pPartFile = NULL; m_pClient= NULL;} + CAICHRequestedData& operator=(const CAICHRequestedData& k1) { m_nPart = k1.m_nPart; m_pPartFile = k1.m_pPartFile; m_pClient = k1.m_pClient; return *this; } + uint16 m_nPart; + CPartFile* m_pPartFile; + CUpDownClient* m_pClient; +}; + + +using namespace std; + +typedef std::list CAICHRequestedDataList; +*/ +///////////////////////////////////////////////////////////////////////////////////////// +///CAICHHashSet +class CAICHHashSet +{ +public: + CAICHHashSet();//CKnownFile* pOwner); + ~CAICHHashSet(void); +// bool CreatePartRecoveryData(uint32 nPartStartPos, CFileDataIO* fileDataOut, bool bDbgDontLoad = false); +// bool ReadRecoveryData(uint32 nPartStartPos, CMemFile* fileDataIn); + bool ReCalculateHash(bool bDontReplace = false); + bool VerifyHashTree(bool bDeleteBadTrees); +// void UntrustedHashReceived(const CAICHHash& Hash, uint32 dwFromIP); +// bool IsPartDataAvailable(uint32 nPartStartPos); + void SetStatus(EAICHStatus bNewValue) {m_eStatus = bNewValue;} + EAICHStatus GetStatus() const {return m_eStatus;} +// + void FreeHashSet(); + void SetFileSize(uint64 nSize); +// + CAICHHash& GetMasterHash() {return m_pHashTree.m_Hash;} +// void SetMasterHash(const CAICHHash& Hash, EAICHStatus eNewStatus); + bool HasValidMasterHash() {return m_pHashTree.m_bHashValid;} + +// bool SaveHashSet(); +// bool LoadHashSet(); // only call directly when debugging + + CAICHHashAlgo* GetNewHashAlgo(); +// static void ClientAICHRequestFailed(CUpDownClient* pClient); +// static void RemoveClientAICHRequest(const CUpDownClient* pClient); +// static bool IsClientRequestPending(const CPartFile* pForFile, uint16 nPart); +// static CAICHRequestedData GetAICHReqDetails(const CUpDownClient* pClient); +// void DbgTest(); + +// void SetOwner(CKnownFile* owner) { m_pOwner = owner;} + + CAICHHashTree m_pHashTree; + + //static CAICHRequestedDataList m_liRequestedData; + +private: + //CKnownFile* m_pOwner; + EAICHStatus m_eStatus; + //deque m_aUntrustedHashs; +}; + +#endif //__SHAHAHSET_H__ diff --git a/hasher/StdAfx.cpp b/hasher/StdAfx.cpp new file mode 100644 index 000000000..b69eaeadc --- /dev/null +++ b/hasher/StdAfx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : source file that includes just the standard includes +// ed2k.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + +// TODO: reference any additional headers you need in STDAFX.H +// and not in this file diff --git a/hasher/StdAfx.h b/hasher/StdAfx.h new file mode 100644 index 000000000..af43e51f2 --- /dev/null +++ b/hasher/StdAfx.h @@ -0,0 +1,27 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#if !defined(AFX_STDAFX_H__FE1C0E5C_BC20_4818_BC9B_601686BB10FA__INCLUDED_) +#define AFX_STDAFX_H__FE1C0E5C_BC20_4818_BC9B_601686BB10FA__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + + +// Insert your headers here +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers + +#define UNICODE +#define _UNICODE + +#include + +// TODO: reference additional headers your program requires here + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_STDAFX_H__FE1C0E5C_BC20_4818_BC9B_601686BB10FA__INCLUDED_) diff --git a/hasher/Types.h b/hasher/Types.h new file mode 100644 index 000000000..c6a90c469 --- /dev/null +++ b/hasher/Types.h @@ -0,0 +1,21 @@ +#pragma once + +typedef unsigned char uchar; +typedef unsigned char uint8; +typedef signed char sint8; + +typedef unsigned short uint16; +typedef signed short sint16; + +typedef unsigned int uint32; +typedef signed int sint32; + +typedef unsigned __int64 uint64; +typedef signed __int64 sint64; + +//#ifdef _DEBUG +//#include "Debug_FileSize.h" +//typedef CEMFileSize EMFileSize; +//#else +typedef unsigned __int64 EMFileSize; +//#endif \ No newline at end of file diff --git a/hasher/config.h b/hasher/config.h new file mode 100644 index 000000000..9d46a7f03 --- /dev/null +++ b/hasher/config.h @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2001-2005 Jacek Sieka, arnetheduck on gmail point com + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#if !defined(CONFIG_H) +#define CONFIG_H + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#ifdef HAVE_CONFIG_H +#include "autoconf.h" +#endif + +// Changing this number will change the maximum number of simultaneous users +// we can handle (when using select)... +#define FD_SETSIZE 4096 + +// Remove this line if hashes are not available in your stl +#define HAVE_HASH 1 + +// This enables stlport's debug mode (and slows it down to a crawl...) +//# define _STLP_DEBUG 1 + +// --- Shouldn't have to change anything under here... + +#ifndef _REENTRANT +# define _REENTRANT 1 +#endif + +#ifdef HAVE_STLPORT +# define _STLP_DONT_USE_SHORT_STRING_OPTIM 1 // Lots of memory issues with this undefined...wonder what's up with that.. +# define _STLP_USE_PTR_SPECIALIZATIONS 1 +# define _STLP_USE_TEMPLATE_EXPRESSION 1 +# define _STLP_NO_ANACHRONISMS 1 +# define _STLP_NO_CUSTOM_IO 1 +# define _STLP_NO_IOSTREAMS 1 +# ifndef _DEBUG +# define _STLP_DONT_USE_EXCEPTIONS 1 +# endif +#endif + +#ifdef _MSC_VER +# pragma warning(disable: 4711) // function 'xxx' selected for automatic inline expansion +# pragma warning(disable: 4786) // identifier was truncated to '255' characters in the debug information +# pragma warning(disable: 4290) // C++ Exception Specification ignored +# pragma warning(disable: 4127) // constant expression +# pragma warning(disable: 4710) // function not inlined +# pragma warning(disable: 4503) // decorated name length exceeded, name was truncated +//# if _MSC_VER == 1200 || _MSC_VER == 1300 || _MSC_VER == 1310 + +typedef signed char int8_t; +typedef signed short int16_t; +typedef signed long int32_t; +typedef signed __int64 int64_t; + +typedef unsigned char u_int8_t; +typedef unsigned short u_int16_t; +typedef unsigned long u_int32_t; +typedef unsigned __int64 u_int64_t; + +//# endif + +#endif + +#if defined(_MSC_VER) +#define _LL(x) x##ll +#define _ULL(x) x##ull +#define I64_FMT "%I64d" +#elif defined(SIZEOF_LONG) && SIZEOF_LONG == 8 +#define _LL(x) x##l +#define _ULL(x) x##ul +#define I64_FMT "%ld" +#else +#define _LL(x) x##ll +#define _ULL(x) x##ull +#define I64_FMT "%lld" +#endif + +#ifdef _WIN32 + +# define PATH_SEPARATOR '\\' +# define PATH_SEPARATOR_STR "\\" + +#else + +# define PATH_SEPARATOR '/' +# define PATH_SEPARATOR_STR "/" + +#endif + +#ifdef _MSC_VER + +# ifndef CDECL +# define CDECL _cdecl +# endif + +#else // _MSC_VER + +# ifndef CDECL +# define CDECL +# endif + +#endif // _MSC_VER + +#define BZ_NO_STDIO + + + +#endif // !defined(CONFIG_H) + +/** + * @file + * $Id: config.h,v 1.35 2005/12/03 20:36:50 arnetheduck Exp $ + */ diff --git a/hasher/hash_crc.cpp b/hasher/hash_crc.cpp new file mode 100644 index 000000000..aeb27b4c6 --- /dev/null +++ b/hasher/hash_crc.cpp @@ -0,0 +1,88 @@ +// Copyright (C) 2006 epoximator +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + +#include "stdafx.h" +#include "hash_wrapper.h" +#include +#include + +/* Table of CRCs of all 8-bit messages. */ +unsigned long crc_table[256]; + +/* Flag: has the table been computed? Initially false. */ +int crc_table_computed = 0; + +/* Make the table for a fast CRC. */ +void make_crc_table(void){ + unsigned long c; + int n, k; + + for (n = 0; n < 256; n++) { + c = (unsigned long) n; + for (k = 0; k < 8; k++) { + if (c & 1) + c = 0xedb88320L ^ (c >> 1); + else + c = c >> 1; + } + crc_table[n] = c; + } + crc_table_computed = 1; +} + +/* Update a running CRC with the bytes buf[0..len-1]--the CRC + should be initialized to all 1's, and the transmitted value + is the 1's complement of the final running CRC (see the + crc() routine below)). */ + +unsigned long update_crc(unsigned long crc, unsigned char *buf, int len) +{ + unsigned long c = crc; + int n; + + + for (n = 0; n < len; n++) { + c = crc_table[(c ^ buf[n]) & 0xff] ^ (c >> 8); + } + return c; +} + +/* Return the CRC of the bytes buf[0..len-1]. */ +unsigned long crc(unsigned char *buf, int len) +{ + return update_crc(0xffffffffL, buf, len) ^ 0xffffffffL; +} + +DigestCRC::DigestCRC(){ + if (!crc_table_computed) + make_crc_table(); + crc_value = 0xffffffffL; +} +void DigestCRC::clean(){ + +} +void DigestCRC::update(char* s, int len){ + crc_value = update_crc(crc_value, (unsigned char *)s, len); +} +int DigestCRC::digest(char* sum, int len){ + int val=crc_value^0xffffffffL; + sum[0]=(val>>24); + sum[1]=(val>>16)&0xFF; + sum[2]=(val>>8)&0xFF; + sum[3]=val&0xFF; + return 4; +} diff --git a/hasher/hash_md5.cpp b/hasher/hash_md5.cpp new file mode 100644 index 000000000..5b72ba534 --- /dev/null +++ b/hasher/hash_md5.cpp @@ -0,0 +1,234 @@ +// Copyright (C) 2006 epoximator +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +//#include + +#include "stdafx.h" +#include "stdinc.h" +#include "hash_wrapper.h" + + +// Code by: B-Con (http://b-con.us) +// Released under the GNU GPL +// MD5 Hash Digest implementation (little endian byte order) + + +// Bah, signed variables are for wimps +#define uchar unsigned char +#define uint unsigned int + +// DBL_INT_ADD treats two unsigned ints a and b as one 64-bit integer and adds c to it +#define DBL_INT_ADD(a,b,c) if (a > 0xffffffff - c) ++b; a += c; +#define ROTLEFT(a,b) ((a << b) | (a >> (32-b))) + +#define F(x,y,z) ((x & y) | (~x & z)) +#define G(x,y,z) ((x & z) | (y & ~z)) +#define H(x,y,z) (x ^ y ^ z) +#define I(x,y,z) (y ^ (x | ~z)) + +#define FF(a,b,c,d,m,s,t) { a += F(b,c,d) + m + t; \ + a = b + ROTLEFT(a,s); } +#define GG(a,b,c,d,m,s,t) { a += G(b,c,d) + m + t; \ + a = b + ROTLEFT(a,s); } +#define HH(a,b,c,d,m,s,t) { a += H(b,c,d) + m + t; \ + a = b + ROTLEFT(a,s); } +#define II(a,b,c,d,m,s,t) { a += I(b,c,d) + m + t; \ + a = b + ROTLEFT(a,s); } + + +typedef struct { + uchar data[64]; + uint datalen; + uint bitlen[2]; + uint state[4]; +} MD5_CTX; + + +void md5_transform(MD5_CTX *ctx, uchar data[]) +{ + uint a,b,c,d,m[16],i,j; + + // MD5 specifies big endian byte order, but this implementation assumes a little + // endian byte order CPU. Reverse all the bytes upon input, and re-reverse them + // on output (in md5_final()). + for (i=0,j=0; i < 16; ++i, j += 4) + m[i] = (data[j]) + (data[j+1] << 8) + (data[j+2] << 16) + (data[j+3] << 24); + + a = ctx->state[0]; + b = ctx->state[1]; + c = ctx->state[2]; + d = ctx->state[3]; + + FF(a,b,c,d,m[0], 7,0xd76aa478); + FF(d,a,b,c,m[1], 12,0xe8c7b756); + FF(c,d,a,b,m[2], 17,0x242070db); + FF(b,c,d,a,m[3], 22,0xc1bdceee); + FF(a,b,c,d,m[4], 7,0xf57c0faf); + FF(d,a,b,c,m[5], 12,0x4787c62a); + FF(c,d,a,b,m[6], 17,0xa8304613); + FF(b,c,d,a,m[7], 22,0xfd469501); + FF(a,b,c,d,m[8], 7,0x698098d8); + FF(d,a,b,c,m[9], 12,0x8b44f7af); + FF(c,d,a,b,m[10],17,0xffff5bb1); + FF(b,c,d,a,m[11],22,0x895cd7be); + FF(a,b,c,d,m[12], 7,0x6b901122); + FF(d,a,b,c,m[13],12,0xfd987193); + FF(c,d,a,b,m[14],17,0xa679438e); + FF(b,c,d,a,m[15],22,0x49b40821); + + GG(a,b,c,d,m[1], 5,0xf61e2562); + GG(d,a,b,c,m[6], 9,0xc040b340); + GG(c,d,a,b,m[11],14,0x265e5a51); + GG(b,c,d,a,m[0], 20,0xe9b6c7aa); + GG(a,b,c,d,m[5], 5,0xd62f105d); + GG(d,a,b,c,m[10], 9,0x02441453); + GG(c,d,a,b,m[15],14,0xd8a1e681); + GG(b,c,d,a,m[4], 20,0xe7d3fbc8); + GG(a,b,c,d,m[9], 5,0x21e1cde6); + GG(d,a,b,c,m[14], 9,0xc33707d6); + GG(c,d,a,b,m[3], 14,0xf4d50d87); + GG(b,c,d,a,m[8], 20,0x455a14ed); + GG(a,b,c,d,m[13], 5,0xa9e3e905); + GG(d,a,b,c,m[2], 9,0xfcefa3f8); + GG(c,d,a,b,m[7], 14,0x676f02d9); + GG(b,c,d,a,m[12],20,0x8d2a4c8a); + + HH(a,b,c,d,m[5], 4,0xfffa3942); + HH(d,a,b,c,m[8], 11,0x8771f681); + HH(c,d,a,b,m[11],16,0x6d9d6122); + HH(b,c,d,a,m[14],23,0xfde5380c); + HH(a,b,c,d,m[1], 4,0xa4beea44); + HH(d,a,b,c,m[4], 11,0x4bdecfa9); + HH(c,d,a,b,m[7], 16,0xf6bb4b60); + HH(b,c,d,a,m[10],23,0xbebfbc70); + HH(a,b,c,d,m[13], 4,0x289b7ec6); + HH(d,a,b,c,m[0], 11,0xeaa127fa); + HH(c,d,a,b,m[3], 16,0xd4ef3085); + HH(b,c,d,a,m[6], 23,0x04881d05); + HH(a,b,c,d,m[9], 4,0xd9d4d039); + HH(d,a,b,c,m[12],11,0xe6db99e5); + HH(c,d,a,b,m[15],16,0x1fa27cf8); + HH(b,c,d,a,m[2], 23,0xc4ac5665); + + II(a,b,c,d,m[0], 6,0xf4292244); + II(d,a,b,c,m[7], 10,0x432aff97); + II(c,d,a,b,m[14],15,0xab9423a7); + II(b,c,d,a,m[5], 21,0xfc93a039); + II(a,b,c,d,m[12], 6,0x655b59c3); + II(d,a,b,c,m[3], 10,0x8f0ccc92); + II(c,d,a,b,m[10],15,0xffeff47d); + II(b,c,d,a,m[1], 21,0x85845dd1); + II(a,b,c,d,m[8], 6,0x6fa87e4f); + II(d,a,b,c,m[15],10,0xfe2ce6e0); + II(c,d,a,b,m[6], 15,0xa3014314); + II(b,c,d,a,m[13],21,0x4e0811a1); + II(a,b,c,d,m[4], 6,0xf7537e82); + II(d,a,b,c,m[11],10,0xbd3af235); + II(c,d,a,b,m[2], 15,0x2ad7d2bb); + II(b,c,d,a,m[9], 21,0xeb86d391); + + ctx->state[0] += a; + ctx->state[1] += b; + ctx->state[2] += c; + ctx->state[3] += d; +} + +void md5_init(MD5_CTX *ctx) +{ + ctx->datalen = 0; + ctx->bitlen[0] = 0; + ctx->bitlen[1] = 0; + ctx->state[0] = 0x67452301; + ctx->state[1] = 0xEFCDAB89; + ctx->state[2] = 0x98BADCFE; + ctx->state[3] = 0x10325476; +} + +void md5_update(MD5_CTX *ctx, uchar *data, uint len) +{ + uint i; + + for (i=0; i < len; ++i) { + ctx->data[ctx->datalen] = data[i]; + ctx->datalen++; + if (ctx->datalen == 64) { + md5_transform(ctx,ctx->data); + DBL_INT_ADD(ctx->bitlen[0],ctx->bitlen[1],512); + ctx->datalen = 0; + } + } +} + +void md5_final(MD5_CTX *ctx, uchar hash[]) +{ + uint i; + + i = ctx->datalen; + + // Pad whatever data is left in the buffer. + if (ctx->datalen < 56) { + ctx->data[i++] = 0x80; + while (i < 56) + ctx->data[i++] = 0x00; + } + else if (ctx->datalen >= 56) { + ctx->data[i++] = 0x80; + while (i < 64) + ctx->data[i++] = 0x00; + md5_transform(ctx,ctx->data); + memset(ctx->data,0,56); + } + + // Append to the padding the total message's length in bits and transform. + DBL_INT_ADD(ctx->bitlen[0],ctx->bitlen[1],8 * ctx->datalen); + ctx->data[56] = ctx->bitlen[0]; + ctx->data[57] = ctx->bitlen[0] >> 8; + ctx->data[58] = ctx->bitlen[0] >> 16; + ctx->data[59] = ctx->bitlen[0] >> 24; + ctx->data[60] = ctx->bitlen[1]; + ctx->data[61] = ctx->bitlen[1] >> 8; + ctx->data[62] = ctx->bitlen[1] >> 16; + ctx->data[63] = ctx->bitlen[1] >> 24; + md5_transform(ctx,ctx->data); + + // Since this implementation uses little endian byte ordering and MD uses big endian, + // reverse all the bytes when copying the final state to the output hash. + for (i=0; i < 4; ++i) { + hash[i] = (ctx->state[0] >> (i*8)) & 0x000000ff; + hash[i+4] = (ctx->state[1] >> (i*8)) & 0x000000ff; + hash[i+8] = (ctx->state[2] >> (i*8)) & 0x000000ff; + hash[i+12] = (ctx->state[3] >> (i*8)) & 0x000000ff; + } +} + +DigestMD5::DigestMD5(){ + MD5_CTX* my = new MD5_CTX; + md5_init(my); + addr = (void*)my; +} +void DigestMD5::clean(){ + delete (MD5_CTX*)addr; + //free((MD5_CTX*)addr); +} +void DigestMD5::update(char* s, int len){ + md5_update((MD5_CTX*)addr,(uchar*)s,len); +} +int DigestMD5::digest(char* sum, int len){ + uchar hash[16]; + md5_final((MD5_CTX*)addr,hash); + memcpy(sum,hash,16); + return 16; +} \ No newline at end of file diff --git a/hasher/hash_sha.cpp b/hasher/hash_sha.cpp new file mode 100644 index 000000000..be2c8b186 --- /dev/null +++ b/hasher/hash_sha.cpp @@ -0,0 +1,40 @@ +// Copyright (C) 2006 epoximator +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +#include "stdafx.h" +#include "hash_wrapper.h" + +#include "SHA.h" + + +DigestSHA::DigestSHA(){ + addr = (void*)new CSHA(); +} +void DigestSHA::clean(){ + CSHA* sha = (CSHA*)addr; + delete sha; +} +void DigestSHA::update(char* buf, int len){ + CSHA* sha = (CSHA*)addr; + sha->Add(buf, len); +} +int DigestSHA::digest(char* sum, int len){ + CSHA* sha = (CSHA*)addr; + CAICHHash hash; + sha->Finish(hash); + memcpy(sum,hash.GetRawHash(), hash.GetHashSize()); + return hash.GetHashSize(); +} diff --git a/hasher/hash_wrapper.h b/hasher/hash_wrapper.h new file mode 100644 index 000000000..f0aeea855 --- /dev/null +++ b/hasher/hash_wrapper.h @@ -0,0 +1,53 @@ +// Copyright (C) 2006 epoximator +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +#pragma once + +class Digest{ +protected: +void* addr; +public: +virtual void update(char* buf, int len)=0; +virtual int digest(char* sum, int len)=0; +virtual void clean()=0; +}; + +class DigestCRC : public Digest{ +private: +unsigned long crc_value; +public: +DigestCRC(); +void update(char* buf, int len); +int digest(char* sum, int len); +void clean(); +}; + + +class DigestSHA : public Digest{ +public: +DigestSHA(); +void update(char* buf, int len); +int digest(char* sum, int len); +void clean(); +}; + +class DigestMD5 : public Digest{ +public: +DigestMD5(); +void update(char* buf, int len); +int digest(char* sum, int len); +void clean(); +}; diff --git a/hasher/hasher.cpp b/hasher/hasher.cpp new file mode 100644 index 000000000..38cdf5608 --- /dev/null +++ b/hasher/hasher.cpp @@ -0,0 +1,342 @@ +// ed2k.cpp : Defines the entry point for the DLL application. +// + +#include "stdafx.h" +#include "hasher.h" +#include "md4.h" +#include "hash_wrapper.h" +#include +#include +#include +#include + +///////////////////////////////////////////////////////////////////////////////// +#define ED2K_CHUNK_SIZE 9728000 +#define SIZE_HASH_BUFFER 16384 + +extern "C" __declspec(dllexport) int __cdecl CalculateHashes_SyncIO(const TCHAR * pszFile, unsigned char * pResult, HASHCALLBACK pHashProgress, bool getCRC32, bool getMD5, bool getSHA1) +{ + struct _stat64 statFile; + if (_tstat64(pszFile, &statFile) != 0) + return 1; + if (statFile.st_size <= 0) + return 6; + + //hash file in chunks of 9728000 bytes + UINT uChunkSize = 9728000; + UINT nChunks = (UINT)(statFile.st_size / uChunkSize); + UINT64 uChunkSizeLast = statFile.st_size % uChunkSize; + if (uChunkSizeLast > 0) + nChunks++; + else + uChunkSizeLast = uChunkSize; + + HANDLE hFile = CreateFile(pszFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL); + if (hFile == INVALID_HANDLE_VALUE) + return 2; + + CMD4 MD4Engine; + + unsigned char pBuf[SIZE_HASH_BUFFER]; + DWORD dwRead = 0; + unsigned char * pTemp = new unsigned char[nChunks*16]; + UINT64 uReadTotal = 0; + + int nStatus = 0; + UINT nChunk = 0; + MD4 md4; + DigestSHA sha1; + DigestCRC crc32; + DigestMD5 md5; + + while (nChunk < nChunks) + { + UINT64 uCurrentChunkSize = (nChunk == nChunks - 1)?uChunkSizeLast:uChunkSize; + + //calculate MD4 of chunk + MD4Engine.Reset(); + + unsigned long dwReadChunk = 0; + unsigned long dwReadToRead = 0; + while (dwReadChunk < uCurrentChunkSize) + { + if (uCurrentChunkSize - dwReadChunk > SIZE_HASH_BUFFER) + dwReadToRead = SIZE_HASH_BUFFER; + else + dwReadToRead = (DWORD)(uCurrentChunkSize - dwReadChunk); + if (!ReadFile(hFile, pBuf, dwReadToRead, &dwRead, NULL)) + { + nStatus = 3; + break; + } + dwReadChunk += dwRead; + uReadTotal += dwRead; + + MD4Engine.Add(pBuf, dwRead); + if (getSHA1) sha1.update((char *)pBuf,dwRead); + if (getCRC32) crc32.update((char *)pBuf,dwRead); + if (getMD5) md5.update((char *)pBuf,dwRead); + } + + MD4Engine.Finish(); + MD4Engine.GetHash(&md4); + BYTE * pData = (BYTE*)&md4; + for (int n=0; n<16; n++) + pTemp[nChunk*16+n] = pData[n]; + + nChunk++; + + //report progress + if (pHashProgress) + { + int nResult = (*pHashProgress)(pszFile, (int)((float)uReadTotal / statFile.st_size * 100)); + if (nResult == 0) + { + nStatus = 4; + break; + } + } + } + + CloseHandle(hFile); + hFile = NULL; + + //create final hash + if (nStatus == 0 && nChunk != nChunks) + nStatus = 5; + + if (nStatus == 0) + { + //First ED2K + if (nChunks > 1) + { + MD4Engine.Reset(); + MD4Engine.Add(pTemp, nChunks*16); + MD4Engine.Finish(); + MD4Engine.GetHash(&md4); + BYTE * pData = (BYTE*)&md4; + for (int n=0; n<16; n++) + pResult[n] = pData[n]; + } + else + { + memcpy(pResult, pTemp, 16); + } + if (getCRC32) crc32.digest((char *)(pResult+16),4); + if (getMD5) md5.digest((char *)(pResult+20),16); + if (getSHA1) sha1.digest((char *)(pResult+36),20); + } + + + delete pTemp; + pTemp = NULL; + + return nStatus; +} + + +static const unsigned int NumBlocksPow = 3; +static const unsigned int NumBlocks = 1 << NumBlocksPow; +static const unsigned int NumBlocksMask = NumBlocks - 1; +static const unsigned int BlockSize = 1024 * 1024; +static const unsigned int uChunkSize = 9728000; + +#define LODWORD(l) ((DWORD)((DWORDLONG)(l))) +#define HIDWORD(l) ((DWORD)(((DWORDLONG)(l)>>32)&0xFFFFFFFF)) +#define MAKEDWORDLONG(a,b) ((DWORDLONG)(((DWORD)(a))|(((DWORDLONG)((DWORD)(b)))<<32))) + +extern "C" __declspec(dllexport) int __cdecl CalculateHashes_AsyncIO(const TCHAR * pszFile, unsigned char * pResult, HASHCALLBACK pHashProgress, bool getCRC32, bool getMD5, bool getSHA1) +{ + //get file size + struct _stat64 statFile; + if (_tstat64(pszFile, &statFile) != 0) + return 1; + if (statFile.st_size <= 0) + return 6; + unsigned __int64 FileSize = statFile.st_size; + + //hash file in chunks of 9728000 bytes + UINT nChunks = (UINT)(statFile.st_size / uChunkSize); + if (statFile.st_size % uChunkSize > 0) + nChunks++; + + //open file + HANDLE hFile = CreateFile(pszFile, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, + FILE_FLAG_NO_BUFFERING | FILE_FLAG_OVERLAPPED | FILE_FLAG_SEQUENTIAL_SCAN, 0); + if (hFile == INVALID_HANDLE_VALUE) + return 2; + + //allocate data + char * blocks[NumBlocks] = {0}; + OVERLAPPED overlapped[NumBlocks] = {0}; + + for (int i = 0; i < NumBlocks; i++) + { + // VirtualAlloc() creates storage that is page aligned and so is disk sector aligned + blocks[i] = static_cast(VirtualAlloc(0, BlockSize, MEM_COMMIT, PAGE_READWRITE)); + + ZeroMemory(&overlapped[i], sizeof(OVERLAPPED)); + overlapped[i].hEvent = CreateEvent(0, FALSE, FALSE, 0); + } + + CMD4 MD4Engine; + + unsigned int iWriterPos = 0; + unsigned int iReaderPos = 0; + unsigned __int64 iIOPos = 0; + unsigned __int64 iPos = 0; + + unsigned int nLastProgress = -1; + unsigned char * pTemp = new unsigned char[nChunks*16]; + UINT nChunk = 0; + unsigned __int64 uChunkEnd = min(uChunkSize, FileSize); + MD4 md4; + DigestSHA sha1; + DigestCRC crc32; + DigestMD5 md5; + + + TCHAR szMsg[255] = {0}; + int nStatus = 0; + do + { + //read blocks, keep 8 I/O requests active + while (iWriterPos - iReaderPos != NumBlocks && iIOPos < FileSize) + { + overlapped[iWriterPos & NumBlocksMask].Offset = LODWORD(iIOPos); + overlapped[iWriterPos & NumBlocksMask].OffsetHigh = HIDWORD(iIOPos); + + const int iMaskedWriterPos = iWriterPos & NumBlocksMask; + //note: we set 'number of bytes to read' to BlockSize, which may be too much (end of file) + // this doesn't matter though, because ReadFile automatically stops at the end of the file + if (!ReadFile(hFile, blocks[iMaskedWriterPos], BlockSize, NULL, &overlapped[iMaskedWriterPos]) && GetLastError() != ERROR_IO_PENDING) + { + nStatus = 3; + break; + } + + iWriterPos++; + iIOPos += BlockSize; + } + + if (nStatus != 0) + { + CancelIo(hFile); + break; + } + + //wait until next block is ready + DWORD dwBytesRead = 0; + const int iMaskedReaderPos = iReaderPos & NumBlocksMask; + if (iPos < FileSize && !GetOverlappedResult(hFile, &overlapped[iMaskedReaderPos], &dwBytesRead, TRUE)) + { + nStatus = 4; + CancelIo(hFile); + break; + } + + //calculate MD4 of chunk + if (iPos + dwBytesRead < uChunkEnd) + { + //update MD4 of current chunk + MD4Engine.Add(blocks[iMaskedReaderPos], dwBytesRead); + if (getSHA1) sha1.update(blocks[iMaskedReaderPos], dwBytesRead); + if (getCRC32) crc32.update(blocks[iMaskedReaderPos], dwBytesRead); + if (getMD5) md5.update(blocks[iMaskedReaderPos], dwBytesRead); + + } + else + { + //update MD4 of current chunk + DWORD dwBytesChunkLeft = (DWORD)(uChunkEnd - iPos); + MD4Engine.Add(blocks[iMaskedReaderPos], dwBytesChunkLeft); + if (getSHA1) sha1.update(blocks[iMaskedReaderPos], dwBytesChunkLeft); + if (getCRC32) crc32.update(blocks[iMaskedReaderPos], dwBytesChunkLeft); + if (getMD5) md5.update(blocks[iMaskedReaderPos], dwBytesChunkLeft); + //calculate MD4 of chunk + MD4Engine.Finish(); + MD4Engine.GetHash(&md4); + BYTE * pData = (BYTE*)&md4; + for (int n=0; n<16; n++) + pTemp[nChunk*16+n] = pData[n]; + MD4Engine.Reset(); + + //prepare for next chunk + nChunk++; + uChunkEnd += uChunkSize; + if (FileSize < uChunkEnd) + uChunkEnd = FileSize; + + //update MD4 of next chunk if data was left on the block + DWORD dwBytesChunkNext = dwBytesRead - dwBytesChunkLeft; + if (dwBytesChunkNext > 0) + MD4Engine.Add(blocks[iMaskedReaderPos] + dwBytesChunkLeft, dwBytesChunkNext); + } + + //prepare for next block + iReaderPos++; + iPos += dwBytesRead; + + //report progress + int nProgress = (int)((float)iPos / statFile.st_size * 100); + if (pHashProgress && nLastProgress != nProgress) + { + int nResult = (*pHashProgress)(pszFile, nProgress); + if (nResult == 0) + { + nStatus = 5; + break; + } + nLastProgress = nProgress; + } + } + while (nChunk < nChunks); + + //clean up + CloseHandle(hFile); + + for (int i = 0; i < NumBlocks; i++) + { + VirtualFree(blocks[i], 0, MEM_RELEASE); + CloseHandle(overlapped[i].hEvent); + } + + //create final hash + if (nStatus == 0 && nChunk != nChunks) + nStatus = 6; + + if (nStatus == 0) + { + if (nChunks > 1) + { + MD4Engine.Reset(); + MD4Engine.Add(pTemp, nChunks*16); + MD4Engine.Finish(); + MD4Engine.GetHash(&md4); + BYTE * pData = (BYTE*)&md4; + for (int n=0; n<16; n++) + pResult[n] = pData[n]; + } + else + { + memcpy(pResult, pTemp, 16); + } + if (getCRC32) crc32.digest((char *)(pResult+16),4); + if (getSHA1) md5.digest((char *)(pResult+20),16); + if (getMD5) sha1.digest((char *)(pResult+36),20); + } + + delete pTemp; + pTemp = NULL; + + //report final progress + if (pHashProgress && nLastProgress < 100) + (*pHashProgress)(pszFile, 100); + + return nStatus; +} + +extern "C" __declspec(dllexport) int __cdecl CalculateHashes(const TCHAR * pszFile, unsigned char * pResult, HASHCALLBACK pHashProgress, bool getCRC32, bool getMD5, bool getSHA1) +{ + return (0 == CalculateHashes_AsyncIO(pszFile, pResult, pHashProgress, getCRC32, getMD5, getSHA1)) ? TRUE : FALSE; +} diff --git a/hasher/hasher.h b/hasher/hasher.h new file mode 100644 index 000000000..70b48b2d0 --- /dev/null +++ b/hasher/hasher.h @@ -0,0 +1,7 @@ +#pragma once + +typedef int (__stdcall *HASHCALLBACK)(const TCHAR * pszFile, int nProgress); + +extern "C" __declspec(dllexport) int __cdecl CalculateHashes_SsyncIO(const TCHAR * pszFile, unsigned char * pResult, HASHCALLBACK pHashProgress, bool getCRC32, bool getMD5, bool getSHA1); +extern "C" __declspec(dllexport) int __cdecl CalculateHashes_AsyncIO(const TCHAR * pszFile, unsigned char * pResult, HASHCALLBACK pHashProgress, bool getCRC32, bool getMD5, bool getSHA1); +extern "C" __declspec(dllexport) int __cdecl CalculateHashes(const TCHAR * pszFile, unsigned char * pResult, HASHCALLBACK pHashProgress, bool getCRC32, bool getMD5, bool getSHA1); diff --git a/hasher/hasher.vcproj.PROJECTGOTH.lwerndly.user b/hasher/hasher.vcproj.PROJECTGOTH.lwerndly.user new file mode 100644 index 000000000..2cb3066b4 --- /dev/null +++ b/hasher/hasher.vcproj.PROJECTGOTH.lwerndly.user @@ -0,0 +1,65 @@ + + + + + + + + + + + diff --git a/hasher/md4_asm.obj b/hasher/md4_asm.obj new file mode 100644 index 000000000..fa071a27b Binary files /dev/null and b/hasher/md4_asm.obj differ diff --git a/hasher/stdinc.h b/hasher/stdinc.h new file mode 100644 index 000000000..687d3d39b --- /dev/null +++ b/hasher/stdinc.h @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2001-2005 Jacek Sieka, arnetheduck on gmail point com + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#if !defined(STDINC_H) +#define STDINC_H + +#include "config.h" + +#ifdef _WIN32 + + +#define WIN32_LEAN_AND_MEAN +#define _WTL_NO_CSTRING +#define _ATL_NO_OPENGL +#define _ATL_NO_MSIMG +#define _ATL_NO_COM +#define _ATL_NO_HOSTING +#define _ATL_NO_OLD_NAMES + +#include + +#include +#include +#include + +#else +#include +#endif + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Use maps if hash_maps aren't available +#ifdef HAVE_HASH +# ifdef HAVE_STLPORT +# define HASH_MAP_X(key, type, hfunc, eq, order) hash_map +# define HASH_MULTIMAP_X(key, type, hfunc, eq, order) hash_multimap +# elif defined(__GLIBCPP__) || defined(__GLIBCXX__) // Using GNU C++ library? +# define HASH_MAP_X(key, type, hfunc, eq, order) hash_map +# define HASH_MULTIMAP_X(key, type, hfunc, eq, order) hash_multimap +# elif defined(_MSC_VER) // Assume the msvc 7.x stl +# define HASH_MAP_X(key, type, hfunc, eq, order) hash_map +# define HASH_MULTIMAP_X(key, type, hfunc, eq, order) hash_multimap +# else +# error Unknown STL, hashes need to be configured +# endif + +# define HASH_SET hash_set +# define HASH_MAP hash_map +# define HASH_MULTIMAP hash_multimap + +#else // HAVE_HASH + +# define HASH_SET set +# define HASH_MAP map +# define HASH_MAP_X(key, type, hfunc, eq, order) map +# define HASH_MULTIMAP multimap +# define HASH_MULTIMAP_X(key, type, hfunc, eq, order) multimap + +#endif // HAVE_HASH + + +#ifdef HAVE_STLPORT +using namespace _STL; +#include +#include + +#elif defined(__GLIBCPP__) || defined(__GLIBCXX__) // Using GNU C++ library? +#include +#include +#include +using namespace std; +using namespace __gnu_cxx; + +// GNU C++ library doesn't have hash(std::string) or hash(long long int) +namespace __gnu_cxx { + template<> struct hash { + size_t operator()(const std::string& x) const + { return hash()(x.c_str()); } + }; + template<> struct hash { + size_t operator()(long long int x) const { return x; } + }; +} +#else // __GLIBCPP__ + +#include +#include + +using namespace std; +using namespace stdext; + +#endif // __GLIBCPP__ + +#endif // !defined(STDINC_H) + +/** + * @file + * $Id: stdinc.h,v 1.20 2005/12/16 01:00:46 arnetheduck Exp $ + */