Beispiel #1
0
        /// <summary>
        /// Calculates what groups should belong to tag related group filters.
        /// </summary>
        /// <param name="session">The NHibernate session.</param>
        /// <returns>A <see cref="ILookup{TKey,TElement}"/> that maps group filter ID to anime group IDs.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="session"/> is <c>null</c>.</exception>
        public ILookup <int, int> CalculateAnimeSeriesPerTagGroupFilter(ISessionWrapper session)
        {
            if (session == null)
            {
                throw new ArgumentNullException(nameof(session));
            }

            lock (globalDBLock)
            {
                var groupsByFilter = session.CreateSQLQuery(@"
                SELECT DISTINCT grpFilter.GroupFilterID, series.AnimeSeriesID
                    FROM AnimeSeries series
                        INNER JOIN AniDB_Anime_Tag anidbTag
                            ON anidbTag.AnimeID = series.AniDB_ID
                        INNER JOIN AniDB_Tag tag
                            ON tag.TagID = anidbTag.TagID
                        INNER JOIN GroupFilter grpFilter
                            ON grpFilter.GroupFilterName = tag.TagName
                                AND grpFilter.FilterType = :tagType
                    ORDER BY grpFilter.GroupFilterID, series.AnimeSeriesID")
                                     .AddScalar("GroupFilterID", NHibernateUtil.Int32)
                                     .AddScalar("AnimeSeriesID", NHibernateUtil.Int32)
                                     .SetInt32("tagType", (int)GroupFilterType.Tag)
                                     .List <object[]>()
                                     .ToLookup(r => (int)r[0], r => (int)r[1]);

                return(groupsByFilter);
            }
        }
        public ILookup <int, MovieDB_Fanart> GetByAnimeIDs(ISessionWrapper session, int[] animeIds)
        {
            if (session == null)
            {
                throw new ArgumentNullException(nameof(session));
            }
            if (animeIds == null)
            {
                throw new ArgumentNullException(nameof(animeIds));
            }

            if (animeIds.Length == 0)
            {
                return(EmptyLookup <int, MovieDB_Fanart> .Instance);
            }

            var fanartByAnime = session.CreateSQLQuery(@"
                SELECT DISTINCT adbOther.AnimeID, {mdbFanart.*}
                    FROM CrossRef_AniDB_Other AS adbOther
                        INNER JOIN MovieDB_Fanart AS mdbFanart
                            ON mdbFanart.MovieId = adbOther.CrossRefID
                    WHERE adbOther.CrossRefType = :crossRefType AND adbOther.AnimeID IN (:animeIds)")
                                .AddScalar("AnimeID", NHibernateUtil.Int32)
                                .AddEntity("mdbFanart", typeof(MovieDB_Fanart))
                                .SetInt32("crossRefType", (int)CrossRefType.MovieDB)
                                .SetParameterList("animeIds", animeIds)
                                .List <object[]>()
                                .ToLookup(r => (int)r[0], r => (MovieDB_Fanart)r[1]);

            return(fanartByAnime);
        }
        public ILookup <int, TvDB_ImageFanart> GetByAnimeIDs(ISessionWrapper session, int[] animeIds)
        {
            if (session == null)
            {
                throw new ArgumentNullException(nameof(session));
            }
            if (animeIds == null)
            {
                throw new ArgumentNullException(nameof(animeIds));
            }

            if (animeIds.Length == 0)
            {
                return(EmptyLookup <int, TvDB_ImageFanart> .Instance);
            }

            lock (globalDBLock)
            {
                var fanartByAnime = session.CreateSQLQuery(@"
                SELECT DISTINCT crAdbTvTb.AniDBID, {tvdbFanart.*}
                   FROM CrossRef_AniDB_TvDB AS crAdbTvTb
                      INNER JOIN TvDB_ImageFanart AS tvdbFanart
                         ON tvdbFanart.SeriesID = crAdbTvTb.TvDBID
                   WHERE crAdbTvTb.AniDBID IN (:animeIds)")
                                    .AddScalar("AniDBID", NHibernateUtil.Int32)
                                    .AddEntity("tvdbFanart", typeof(TvDB_ImageFanart))
                                    .SetParameterList("animeIds", animeIds)
                                    .List <object[]>()
                                    .ToLookup(r => (int)r[0], r => (TvDB_ImageFanart)r[1]);

                return(fanartByAnime);
            }
        }
        private Dictionary <int, LanguageStat> GetAudioLanguageStatsByAnimeResults(ISessionWrapper session,
                                                                                   string animeIdPredicate)
        {
            Dictionary <int, LanguageStat> dictStats = new Dictionary <int, LanguageStat>();
            string query = GetAudioLanguageStatsByAnimeSQL(animeIdPredicate);

            var rows = session.CreateSQLQuery(query)
                       .AddScalar("AnimeID", NHibernateUtil.Int32)
                       .AddScalar("MainTitle", NHibernateUtil.String)
                       .AddScalar("LanguageName", NHibernateUtil.String)
                       .List <object[]>();

            foreach (object[] cols in rows)
            {
                int    animeID   = Convert.ToInt32(cols[0]);
                string mainTitle = cols[1].ToString().Trim();
                string lanName   = cols[2].ToString().Trim();

                if (!dictStats.TryGetValue(animeID, out LanguageStat stat))
                {
                    stat = new LanguageStat
                    {
                        AnimeID       = animeID,
                        MainTitle     = mainTitle,
                        LanguageNames = new List <string>()
                    };
                    dictStats.Add(animeID, stat);
                }

                stat.LanguageNames.Add(lanName);
            }

            return(dictStats);
        }
        public ILookup <int, Tuple <CrossRef_AniDB_TvDBV2, TvDB_Series> > GetByAnimeIDsV2(ISessionWrapper session,
                                                                                          int[] animeIds)
        {
            if (session == null)
            {
                throw new ArgumentNullException(nameof(session));
            }
            if (animeIds == null)
            {
                throw new ArgumentNullException(nameof(animeIds));
            }

            if (animeIds.Length == 0)
            {
                return(EmptyLookup <int, Tuple <CrossRef_AniDB_TvDBV2, TvDB_Series> > .Instance);
            }

            var tvDbSeriesByAnime = session.CreateSQLQuery(@"
                SELECT {cr.*}, {series.*}
                    FROM CrossRef_AniDB_TvDBV2 cr
                        INNER JOIN TvDB_Series series
                            ON series.SeriesID = cr.TvDBID
                    WHERE cr.AnimeID IN (:animeIds)")
                                    .AddEntity("cr", typeof(CrossRef_AniDB_TvDBV2))
                                    .AddEntity("series", typeof(TvDB_Series))
                                    .SetParameterList("animeIds", animeIds)
                                    .List <object[]>()
                                    .ToLookup(r => ((CrossRef_AniDB_TvDBV2)r[0]).AnimeID,
                                              r => new Tuple <CrossRef_AniDB_TvDBV2, TvDB_Series>((CrossRef_AniDB_TvDBV2)r[0],
                                                                                                  (TvDB_Series)r[1]));

            return(tvDbSeriesByAnime);
        }
        public Dictionary <int, Tuple <CrossRef_AniDB_Other, MovieDB_Movie> > GetByAnimeIDs(ISessionWrapper session,
                                                                                            int[] animeIds)
        {
            if (session == null)
            {
                throw new ArgumentNullException(nameof(session));
            }
            if (animeIds == null)
            {
                throw new ArgumentNullException(nameof(animeIds));
            }

            if (animeIds.Length == 0)
            {
                return(new Dictionary <int, Tuple <CrossRef_AniDB_Other, MovieDB_Movie> >());
            }

            var movieByAnime = session.CreateSQLQuery(@"
                SELECT {cr.*}, {movie.*}
                    FROM CrossRef_AniDB_Other cr
                        INNER JOIN MovieDB_Movie movie
                            ON cr.CrossRefType = :crossRefType
                                AND movie.MovieId = cr.CrossRefID
                    WHERE cr.AnimeID IN (:animeIds)")
                               .AddEntity("cr", typeof(CrossRef_AniDB_Other))
                               .AddEntity("movie", typeof(MovieDB_Movie))
                               .SetInt32("crossRefType", (int)CrossRefType.MovieDB)
                               .SetParameterList("animeIds", animeIds)
                               .List <object[]>()
                               .ToDictionary(r => ((CrossRef_AniDB_Other)r[0]).AnimeID,
                                             r => new Tuple <CrossRef_AniDB_Other, MovieDB_Movie>((CrossRef_AniDB_Other)r[0],
                                                                                                  (MovieDB_Movie)r[1]));

            return(movieByAnime);
        }
        public ILookup <int, AnimeCharacterAndSeiyuu> GetCharacterAndSeiyuuByAnime(ISessionWrapper session,
                                                                                   int[] animeIds)
        {
            if (session == null)
            {
                throw new ArgumentNullException(nameof(session));
            }
            if (animeIds == null)
            {
                throw new ArgumentNullException(nameof(animeIds));
            }

            if (animeIds.Length == 0)
            {
                return(EmptyLookup <int, AnimeCharacterAndSeiyuu> .Instance);
            }

            // The below query makes sure that only one seiyuu is returned for each anime/character combiniation
            var animeChars = session.CreateSQLQuery(@"
                SELECT animeChr.AnimeID, {chr.*}, {seiyuu.*}, animeChr.CharType
                    FROM AniDB_Anime_Character AS animeChr
                        INNER JOIN AniDB_Character AS chr
                            ON chr.CharID = animeChr.CharID
                        LEFT OUTER JOIN (
                            SELECT ac.AnimeID, ac.CharID, MIN(cs.SeiyuuID) AS SeiyuuID
                                FROM AniDB_Anime_Character ac
                                    INNER JOIN AniDB_Character_Seiyuu cs
                                        ON cs.CharID = ac.CharID
                                GROUP BY ac.AnimeID, ac.CharID
                            ) AS chrSeiyuu
                            ON chrSeiyuu.CharID = chr.CharID
                                AND chrSeiyuu.AnimeID = animeChr.AnimeID
                        LEFT OUTER JOIN AniDB_Seiyuu AS seiyuu
                            ON seiyuu.SeiyuuID = chrSeiyuu.SeiyuuID
                    WHERE animeChr.AnimeID IN (:animeIds)")
                             .AddScalar("AnimeID", NHibernateUtil.Int32)
                             .AddEntity("chr", typeof(AniDB_Character))
                             .AddEntity("seiyuu", typeof(AniDB_Seiyuu))
                             .AddScalar("CharType", NHibernateUtil.String)
                             .SetParameterList("animeIds", animeIds)
                             .List <object[]>()
                             .Select(r => new AnimeCharacterAndSeiyuu((int)r[0], (AniDB_Character)r[1], (AniDB_Seiyuu)r[2],
                                                                      (string)r[3]))
                             .ToLookup(ac => ac.AnimeID);

            return(animeChars);
        }
Beispiel #8
0
        /// <summary>
        /// Deletes the anime groups and user mappings as well as resetting group filters and moves all anime series into the specified group.
        /// </summary>
        /// <param name="session">The NHibernate session.</param>
        /// <param name="tempGroupId">The ID of the temporary anime group to use for migration.</param>
        private void ClearGroupsAndDependencies(ISessionWrapper session, int tempGroupId)
        {
            _log.Info("Removing existing AnimeGroups and resetting GroupFilters");

            _animeGroupUserRepo.DeleteAll(session);
            _animeGroupRepo.DeleteAll(session, tempGroupId);
            session.CreateSQLQuery(@"
                UPDATE AnimeSeries SET AnimeGroupID = :tempGroupId;
                UPDATE GroupFilter SET GroupsIdsString = '{}';")
            .SetInt32("tempGroupId", tempGroupId)
            .ExecuteUpdate();

            // We've deleted/modified all AnimeSeries/GroupFilter records, so update caches to reflect that
            _animeSeriesRepo.ClearCache();
            _groupFilterRepo.ClearCache();
            _log.Info("AnimeGroups have been removed and GroupFilters have been reset");
        }
Beispiel #9
0
        private Dictionary <int, LanguageStat> GetSubtitleLanguageStatsByAnimeResults(ISessionWrapper session,
                                                                                      string animeIdPredicate)
        {
            Dictionary <int, LanguageStat> dictStats = new Dictionary <int, LanguageStat>();
            string query = "SELECT DISTINCT anime.AnimeID, anime.MainTitle, lan.LanguageName "
                           + "FROM AnimeSeries ser  "
                           + "INNER JOIN AniDB_Anime anime on anime.AnimeID = ser.AniDB_ID "
                           + "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 "
                           + "INNER JOIN CrossRef_Subtitles_AniDB_File subt on subt.FileID = anifile.FileID "
                           + "INNER JOIN Language lan on subt.LanguageID = lan.LanguageID "
                           + "WHERE anime.AnimeID " + animeIdPredicate;

            var rows = session.CreateSQLQuery(query)
                       .AddScalar("AnimeID", NHibernateUtil.Int32)
                       .AddScalar("MainTitle", NHibernateUtil.String)
                       .AddScalar("LanguageName", NHibernateUtil.String)
                       .List <object[]>();

            foreach (object[] cols in rows)
            {
                int          animeID   = Convert.ToInt32(cols[0]);
                string       mainTitle = cols[1].ToString().Trim();
                string       lanName   = cols[2].ToString().Trim();
                LanguageStat stat      = null;

                if (!dictStats.TryGetValue(animeID, out stat))
                {
                    stat = new LanguageStat
                    {
                        AnimeID       = animeID,
                        MainTitle     = mainTitle,
                        LanguageNames = new List <string>()
                    };
                    dictStats.Add(animeID, stat);
                }

                stat.LanguageNames.Add(lanName);
            }

            return(dictStats);
        }
Beispiel #10
0
        /// <summary>
        /// Gets All video quality by group.
        /// </summary>
        /// <param name="session">The NHibernate session.</param>
        /// <param name="animeGroupIds">The optional list of group IDs to limit the results to.
        /// If <c>null</c> is specified, then results for ALL groups will be returned.</param>
        /// <returns>A <see cref="ILookup{TKey,TElement}"/> containing all video quality grouped by anime group ID.</returns>
        public ILookup <int, string> GetAllVideoQualityByGroup(ISessionWrapper session,
                                                               IReadOnlyCollection <int> animeGroupIds = null)
        {
            if (session == null)
            {
                throw new ArgumentNullException(nameof(session));
            }

            if (animeGroupIds != null && animeGroupIds.Count == 0)
            {
                return(EmptyLookup <int, string> .Instance);
            }

            string query = @"
                SELECT DISTINCT ag.AnimeGroupID, anifile.File_Source
                    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
                        INNER JOIN CrossRef_Subtitles_AniDB_File subt
                            ON subt.FileID = anifile.FileID";

            if (animeGroupIds != null)
            {
                query += @"
                    WHERE ag.AnimeGroupID IN (" + String.Join(",", animeGroupIds) + ")";
            }

            var results = session.CreateSQLQuery(query)
                          .AddScalar("AnimeGroupID", NHibernateUtil.Int32)
                          .AddScalar("File_Source", NHibernateUtil.String)
                          .List <object[]>()
                          .ToLookup(r => (int)r[0], r => (string)r[1]);

            return(results);
        }
Beispiel #11
0
        /// <summary>
        /// Creates a new <see cref="AutoAnimeGroupCalculator"/> using relationships stored in the database.
        /// </summary>
        /// <param name="session">The NHibernate session.</param>
        /// <param name="exclusions">The relation/anime types to ignore when building relation graphs.</param>
        /// <param name="relationsToFuzzyTitleTest">The relationships for which we'll perform title similarity checks for
        /// (If the titles aren't similar enough then the anime will end up in different groups).</param>
        /// <param name="mainAnimeSelectionStrategy">The strategy to use for selecting the "main" anime that will be used
        /// for representing the group.</param>
        /// <returns>The created <see cref="AutoAnimeGroupCalculator"/>.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="session"/> is <c>null</c>.</exception>
        public static AutoAnimeGroupCalculator Create(ISessionWrapper session,
                                                      AutoGroupExclude exclusions = AutoGroupExclude.SameSetting | AutoGroupExclude.Character,
                                                      AnimeRelationType relationsToFuzzyTitleTest           = AnimeRelationType.SecondaryRelations,
                                                      MainAnimeSelectionStrategy mainAnimeSelectionStrategy = MainAnimeSelectionStrategy.MinAirDate)
        {
            if (session == null)
            {
                throw new ArgumentNullException(nameof(session));
            }

            var relationshipMap = session.CreateSQLQuery(@"
                SELECT    fromAnime.AnimeID AS fromAnimeId
                        , toAnime.AnimeID AS toAnimeId
                        , fromAnime.AnimeType AS fromAnimeType
                        , toAnime.AnimeType AS toAnimeType
                        , fromAnime.MainTitle AS fromMainTitle
                        , toAnime.MainTitle AS toMainTitle
                        , fromAnime.AirDate AS fromAirDate
                        , toAnime.AirDate AS toAirDate
                        , rel.RelationType AS relationType
                    FROM AniDB_Anime_Relation rel
                        INNER JOIN AniDB_Anime fromAnime
                            ON fromAnime.AnimeID = rel.AnimeID
                        INNER JOIN AniDB_Anime toAnime
                            ON toAnime.AnimeID = rel.RelatedAnimeID")
                                  .AddScalar("fromAnimeId", NHibernateUtil.Int32)
                                  .AddScalar("toAnimeId", NHibernateUtil.Int32)
                                  .AddScalar("fromAnimeType", NHibernateUtil.Int32)
                                  .AddScalar("toAnimeType", NHibernateUtil.Int32)
                                  .AddScalar("fromMainTitle", NHibernateUtil.String)
                                  .AddScalar("toMainTitle", NHibernateUtil.String)
                                  .AddScalar("fromAirDate", NHibernateUtil.DateTime)
                                  .AddScalar("toAirDate", NHibernateUtil.DateTime)
                                  .AddScalar("relationType", NHibernateUtil.String)
                                  .List <object[]>()
                                  .Select(r =>
            {
                var relation = new AnimeRelation
                {
                    FromId        = (int)r[0],
                    ToId          = (int)r[1],
                    FromType      = (AnimeType)r[2],
                    ToType        = (AnimeType)r[3],
                    FromMainTitle = (string)r[4],
                    ToMainTitle   = (string)r[5],
                    FromAirDate   = (DateTime?)r[6],
                    ToAirDate     = (DateTime?)r[7]
                };

                switch (((string)r[8]).ToLowerInvariant())
                {
                case "full story":
                    relation.RelationType = AnimeRelationType.FullStory;
                    break;

                case "summary":
                    relation.RelationType = AnimeRelationType.Summary;
                    break;

                case "parent story":
                    relation.RelationType = AnimeRelationType.ParentStory;
                    break;

                case "side story":
                    relation.RelationType = AnimeRelationType.SideStory;
                    break;

                case "prequel":
                    relation.RelationType = AnimeRelationType.Prequel;
                    break;

                case "sequel":
                    relation.RelationType = AnimeRelationType.Sequel;
                    break;

                case "alternative setting":
                    relation.RelationType = AnimeRelationType.AlternateSetting;
                    break;

                case "alternative version":
                    relation.RelationType = AnimeRelationType.AlternateVersion;
                    break;

                case "same setting":
                    relation.RelationType = AnimeRelationType.SameSetting;
                    break;

                case "character":
                    relation.RelationType = AnimeRelationType.Character;
                    break;

                default:
                    relation.RelationType = AnimeRelationType.Other;
                    break;
                }

                return(relation);
            })
                                  .ToLookup(k => k.FromId);

            return(new AutoAnimeGroupCalculator(relationshipMap, exclusions, relationsToFuzzyTitleTest,
                                                mainAnimeSelectionStrategy));
        }
Beispiel #12
0
        public Dictionary <int, DefaultAnimeImages> GetDefaultImagesByAnime(ISessionWrapper session, int[] animeIds)
        {
            if (session == null)
            {
                throw new ArgumentNullException("session");
            }
            if (animeIds == null)
            {
                throw new ArgumentNullException("animeIds");
            }

            var defImagesByAnime = new Dictionary <int, DefaultAnimeImages>();

            if (animeIds.Length == 0)
            {
                return(defImagesByAnime);
            }

            lock (globalDBLock)
            {
                // TODO: Determine if joining on the correct columns
                var results = session.CreateSQLQuery(@"
                SELECT {defImg.*}, {tvWide.*}, {tvPoster.*}, {tvFanart.*}, {movPoster.*}, {movFanart.*}
                    FROM AniDB_Anime_DefaultImage defImg
                        LEFT OUTER JOIN TvDB_ImageWideBanner AS tvWide
                            ON tvWide.TvDB_ImageWideBannerID = defImg.ImageParentID AND defImg.ImageParentType = :tvdbBannerType
                        LEFT OUTER JOIN TvDB_ImagePoster AS tvPoster
                            ON tvPoster.TvDB_ImagePosterID = defImg.ImageParentID AND defImg.ImageParentType = :tvdbCoverType
                        LEFT OUTER JOIN TvDB_ImageFanart AS tvFanart
                            ON tvFanart.TvDB_ImageFanartID = defImg.ImageParentID AND defImg.ImageParentType = :tvdbFanartType
                        LEFT OUTER JOIN MovieDB_Poster AS movPoster
                            ON movPoster.MovieDB_PosterID = defImg.ImageParentID AND defImg.ImageParentType = :movdbPosterType
                        LEFT OUTER JOIN MovieDB_Fanart AS movFanart
                            ON movFanart.MovieDB_FanartID = defImg.ImageParentID AND defImg.ImageParentType = :movdbFanartType
                    WHERE defImg.AnimeID IN (:animeIds) AND defImg.ImageParentType IN (:tvdbBannerType, :tvdbCoverType, :tvdbFanartType, :movdbPosterType, :movdbFanartType)")
                              .AddEntity("defImg", typeof(AniDB_Anime_DefaultImage))
                              .AddEntity("tvWide", typeof(TvDB_ImageWideBanner))
                              .AddEntity("tvPoster", typeof(TvDB_ImagePoster))
                              .AddEntity("tvFanart", typeof(TvDB_ImageFanart))
                              .AddEntity("movPoster", typeof(MovieDB_Poster))
                              .AddEntity("movFanart", typeof(MovieDB_Fanart))
                              .SetParameterList("animeIds", animeIds)
                              .SetInt32("tvdbBannerType", (int)ImageEntityType.TvDB_Banner)
                              .SetInt32("tvdbCoverType", (int)ImageEntityType.TvDB_Cover)
                              .SetInt32("tvdbFanartType", (int)ImageEntityType.TvDB_FanArt)
                              .SetInt32("movdbPosterType", (int)ImageEntityType.MovieDB_Poster)
                              .SetInt32("movdbFanartType", (int)ImageEntityType.MovieDB_FanArt)
                              .List <object[]>();

                foreach (object[] result in results)
                {
                    var          aniDbDefImage = (AniDB_Anime_DefaultImage)result[0];
                    IImageEntity parentImage   = null;

                    switch ((ImageEntityType)aniDbDefImage.ImageParentType)
                    {
                    case ImageEntityType.TvDB_Banner:
                        parentImage = (IImageEntity)result[1];
                        break;

                    case ImageEntityType.TvDB_Cover:
                        parentImage = (IImageEntity)result[2];
                        break;

                    case ImageEntityType.TvDB_FanArt:
                        parentImage = (IImageEntity)result[3];
                        break;

                    case ImageEntityType.MovieDB_Poster:
                        parentImage = (IImageEntity)result[4];
                        break;

                    case ImageEntityType.MovieDB_FanArt:
                        parentImage = (IImageEntity)result[5];
                        break;
                    }

                    if (parentImage == null)
                    {
                        continue;
                    }

                    DefaultAnimeImage defImage = new DefaultAnimeImage(aniDbDefImage, parentImage);

                    if (!defImagesByAnime.TryGetValue(aniDbDefImage.AnimeID, out DefaultAnimeImages defImages))
                    {
                        defImages = new DefaultAnimeImages {
                            AnimeID = aniDbDefImage.AnimeID
                        };
                        defImagesByAnime.Add(defImages.AnimeID, defImages);
                    }

                    switch (defImage.AniDBImageSizeType)
                    {
                    case ImageSizeType.Poster:
                        defImages.Poster = defImage;
                        break;

                    case ImageSizeType.WideBanner:
                        defImages.WideBanner = defImage;
                        break;

                    case ImageSizeType.Fanart:
                        defImages.Fanart = defImage;
                        break;
                    }
                }
            }

            return(defImagesByAnime);
        }
        private Dictionary<int, LanguageStat> GetSubtitleLanguageStatsByAnimeResults(ISessionWrapper session, string animeIdPredicate)
        {
            Dictionary<int, LanguageStat> dictStats = new Dictionary<int, LanguageStat>();
            string query = "SELECT DISTINCT anime.AnimeID, anime.MainTitle, lan.LanguageName "
                + "FROM AnimeSeries ser  "
                + "INNER JOIN AniDB_Anime anime on anime.AnimeID = ser.AniDB_ID "
                + "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 "
                + "INNER JOIN CrossRef_Subtitles_AniDB_File subt on subt.FileID = anifile.FileID "
                + "INNER JOIN Language lan on subt.LanguageID = lan.LanguageID "
                + "WHERE anime.AnimeID " + animeIdPredicate;

            var rows = session.CreateSQLQuery(query)
                .AddScalar("AnimeID", NHibernateUtil.Int32)
                .AddScalar("MainTitle", NHibernateUtil.String)
                .AddScalar("LanguageName", NHibernateUtil.String)
                .List<object[]>();

            foreach (object[] cols in rows)
            {
                int animeID = Convert.ToInt32(cols[0]);
                string mainTitle = cols[1].ToString().Trim();
                string lanName = cols[2].ToString().Trim();
                LanguageStat stat = null;

                if (!dictStats.TryGetValue(animeID, out stat))
                {
                    stat = new LanguageStat
                    {
                        AnimeID = animeID,
                        MainTitle = mainTitle,
                        LanguageNames = new List<string>()
                    };
                    dictStats.Add(animeID, stat);
                }

                stat.LanguageNames.Add(lanName);
            }

            return dictStats;
        }
        private Dictionary<int, LanguageStat> GetAudioLanguageStatsByAnimeResults(ISessionWrapper session, string animeIdPredicate)
        {
            Dictionary<int, LanguageStat> dictStats = new Dictionary<int, LanguageStat>();
            string query = GetAudioLanguageStatsByAnimeSQL(animeIdPredicate);

            var rows = session.CreateSQLQuery(query)
                .AddScalar("AnimeID", NHibernateUtil.Int32)
                .AddScalar("MainTitle", NHibernateUtil.String)
                .AddScalar("LanguageName", NHibernateUtil.String)
                .List<object[]>();

            foreach (object[] cols in rows)
            {
                int animeID = Convert.ToInt32(cols[0]);
                string mainTitle = cols[1].ToString().Trim();
                string lanName = cols[2].ToString().Trim();
                LanguageStat stat = null;

                if (!dictStats.TryGetValue(animeID, out stat))
                {
                    stat = new LanguageStat
                    {
                        AnimeID = animeID,
                        MainTitle = mainTitle,
                        LanguageNames = new List<string>()
                    };
                    dictStats.Add(animeID, stat);
                }

                stat.LanguageNames.Add(lanName);
            }

            return dictStats;
        }
        /// <summary>
        /// Gets All video quality by group.
        /// </summary>
        /// <param name="session">The NHibernate session.</param>
        /// <param name="animeGroupIds">The optional list of group IDs to limit the results to.
        /// If <c>null</c> is specified, then results for ALL groups will be returned.</param>
        /// <returns>A <see cref="ILookup{TKey,TElement}"/> containing all video quality grouped by anime group ID.</returns>
        public ILookup<int, string> GetAllVideoQualityByGroup(ISessionWrapper session, IReadOnlyCollection<int> animeGroupIds = null)
        {
            if (session == null)
                throw new ArgumentNullException(nameof(session));

            if (animeGroupIds != null && animeGroupIds.Count == 0)
            {
                return EmptyLookup<int, string>.Instance;
            }

            string query = @"
                SELECT DISTINCT ag.AnimeGroupID, anifile.File_Source
                    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
                        INNER JOIN CrossRef_Subtitles_AniDB_File subt
                            ON subt.FileID = anifile.FileID";

            if (animeGroupIds != null)
            {
                query += @"
                    WHERE ag.AnimeGroupID IN (" + String.Join(",", animeGroupIds) + ")";
            }

            var results = session.CreateSQLQuery(query)
                .AddScalar("AnimeGroupID", NHibernateUtil.Int32)
                .AddScalar("File_Source", NHibernateUtil.String)
                .List<object[]>()
                .ToLookup(r => (int)r[0], r => (string)r[1]);

            return results;
        }
        /// <summary>
        /// Deletes the anime groups and user mappings as well as resetting group filters and moves all anime series into the specified group.
        /// </summary>
        /// <param name="session">The NHibernate session.</param>
        /// <param name="tempGroupId">The ID of the temporary anime group to use for migration.</param>
        private void ClearGroupsAndDependencies(ISessionWrapper session, int tempGroupId)
        {
            _log.Info("Removing existing AnimeGroups and resetting GroupFilters");

            _animeGroupUserRepo.DeleteAll(session);
            _animeGroupRepo.DeleteAll(session, tempGroupId);
            session.CreateSQLQuery(@"
                UPDATE AnimeSeries SET AnimeGroupID = :tempGroupId;
                UPDATE GroupFilter SET GroupsIdsString = '{}';")
                .SetInt32("tempGroupId", tempGroupId)
                .ExecuteUpdate();

            // We've deleted/modified all AnimeSeries/GroupFilter records, so update caches to reflect that
            _animeSeriesRepo.ClearCache();
            _groupFilterRepo.ClearCache();
            _log.Info("AnimeGroups have been removed and GroupFilters have been reset");
        }