private void DropAndCreateAllTagFilters(ISessionWrapper session)
        {
            var             locked    = GetAll(session);
            SVR_GroupFilter tagsdirec = locked.FirstOrDefault(
                a => a.FilterType == (int)(GroupFilterType.Directory | GroupFilterType.Tag));
            var tagFilters = locked.Where(a => a.FilterType == (int)GroupFilterType.Tag).ToList();

            using (ITransaction trans = session.BeginTransaction())
            {
                BatchDelete(session, tagFilters);
                trans.Commit();
            }

            if (tagsdirec != null)
            {
                HashSet <string> alltags = new HashSet <string>(
                    RepoFactory.AniDB_Tag.GetAllForLocalSeries().Select(a => a.TagName.Replace('`', '\'')),
                    StringComparer.InvariantCultureIgnoreCase);
                List <SVR_GroupFilter> toAdd = new List <SVR_GroupFilter>(alltags.Count);

                //AniDB Tags are in english so we use en-us culture
                TextInfo tinfo = new CultureInfo("en-US", false).TextInfo;
                foreach (string s in alltags)
                {
                    SVR_GroupFilter yf = new SVR_GroupFilter
                    {
                        ParentGroupFilterID = tagsdirec.GroupFilterID,
                        InvisibleInClients  = 0,
                        ApplyToSeries       = 1,
                        GroupFilterName     = tinfo.ToTitleCase(s),
                        BaseCondition       = 1,
                        Locked          = 1,
                        SortingCriteria = "5;1",
                        FilterType      = (int)GroupFilterType.Tag
                    };
                    GroupFilterCondition gfc = new GroupFilterCondition
                    {
                        ConditionType      = (int)GroupFilterConditionType.Tag,
                        ConditionOperator  = (int)GroupFilterOperator.In,
                        ConditionParameter = s,
                        GroupFilterID      = yf.GroupFilterID
                    };
                    yf.Conditions.Add(gfc);
                    toAdd.Add(yf);
                }

                using (ITransaction trans = session.BeginTransaction())
                {
                    BatchInsert(session, toAdd);
                    trans.Commit();
                }
            }
        }
Пример #2
0
        /// <summary>
        /// Creates a single <see cref="SVR_AnimeGroup"/> for each <see cref="SVR_AnimeSeries"/> in <paramref name="seriesList"/>.
        /// </summary>
        /// <remarks>
        /// This method assumes that there are no active transactions on the specified <paramref name="session"/>.
        /// </remarks>
        /// <param name="session">The NHibernate session.</param>
        /// <param name="seriesList">The list of <see cref="SVR_AnimeSeries"/> to create groups for.</param>
        /// <returns>A sequence of the created <see cref="SVR_AnimeGroup"/>s.</returns>
        private IEnumerable <SVR_AnimeGroup> CreateGroupPerSeries(ISessionWrapper session,
                                                                  IReadOnlyList <SVR_AnimeSeries> seriesList)
        {
            _log.Info("Generating AnimeGroups for {0} AnimeSeries", seriesList.Count);

            DateTime now = DateTime.Now;
            var      newGroupsToSeries = new Tuple <SVR_AnimeGroup, SVR_AnimeSeries> [seriesList.Count];

            // Create one group per series
            for (int grp = 0; grp < seriesList.Count; grp++)
            {
                SVR_AnimeGroup  group  = new SVR_AnimeGroup();
                SVR_AnimeSeries series = seriesList[grp];

                @group.Populate(series, now);
                newGroupsToSeries[grp] = new Tuple <SVR_AnimeGroup, SVR_AnimeSeries>(group, series);
            }

            using (ITransaction trans = session.BeginTransaction())
            {
                _animeGroupRepo.InsertBatch(session, newGroupsToSeries.Select(gts => gts.Item1).AsReadOnlyCollection());
                trans.Commit();
            }

            // Anime groups should have IDs now they've been inserted. Now assign the group ID's to their respective series
            // (The caller of this method will be responsible for saving the AnimeSeries)
            foreach (Tuple <SVR_AnimeGroup, SVR_AnimeSeries> groupAndSeries in newGroupsToSeries)
            {
                groupAndSeries.Item2.AnimeGroupID = groupAndSeries.Item1.AnimeGroupID;
            }

            _log.Info("Generated {0} AnimeGroups", newGroupsToSeries.Length);

            return(newGroupsToSeries.Select(gts => gts.Item1));
        }
Пример #3
0
        /// <summary>
        /// Updates all Group Filters. This should be done as the last step.
        /// </summary>
        /// <remarks>
        /// Assumes that all caches are up to date.
        /// </remarks>
        private void UpdateGroupFilters(ISessionWrapper session)
        {
            _log.Info("Updating Group Filters");
            _log.Info("Calculating Tag Filters");
            ServerState.Instance.DatabaseBlocked = new ServerState.DatabaseBlockedInfo {
                Blocked = true, Status = "Calculating Tag Filters"
            };
            _groupFilterRepo.CalculateAnimeSeriesPerTagGroupFilter(session);
            _log.Info("Calculating All Other Filters");
            ServerState.Instance.DatabaseBlocked = new ServerState.DatabaseBlockedInfo {
                Blocked = true, Status = "Calculating Non-Tag Filters"
            };
            IEnumerable <SVR_GroupFilter> grpFilters = _groupFilterRepo.GetAll(session).Where(a =>
                                                                                              a.FilterType != (int)GroupFilterType.Tag &&
                                                                                              ((GroupFilterType)a.FilterType & GroupFilterType.Directory) == 0).ToList();

            // The main reason for doing this in parallel is because UpdateEntityReferenceStrings does JSON encoding
            // and is enough work that it can benefit from running in parallel
            Parallel.ForEach(
                grpFilters, filter =>
            {
                filter.SeriesIds.Clear();
                filter.CalculateGroupsAndSeries();
                filter.UpdateEntityReferenceStrings();
            });

            using (ITransaction trans = session.BeginTransaction())
            {
                _groupFilterRepo.BatchUpdate(session, grpFilters);
                trans.Commit();
            }

            _log.Info("Group Filters updated");
        }
Пример #4
0
        /// <summary>
        /// Creates <see cref="SVR_AnimeGroup"/> that contain <see cref="SVR_AnimeSeries"/> that appear to be related.
        /// </summary>
        /// <remarks>
        /// This method assumes that there are no active transactions on the specified <paramref name="session"/>.
        /// </remarks>
        /// <param name="session">The NHibernate session.</param>
        /// <param name="seriesList">The list of <see cref="SVR_AnimeSeries"/> to create groups for.</param>
        /// <returns>A sequence of the created <see cref="SVR_AnimeGroup"/>s.</returns>
        private IEnumerable <SVR_AnimeGroup> AutoCreateGroupsWithRelatedSeries(ISessionWrapper session,
                                                                               IReadOnlyCollection <SVR_AnimeSeries> seriesList)
        {
            ServerState.Instance.DatabaseBlocked = new ServerState.DatabaseBlockedInfo {
                Blocked = true, Status = "Auto-generating Groups based on Relation Trees"
            };
            _log.Info("Auto-generating AnimeGroups for {0} AnimeSeries based on aniDB relationships", seriesList.Count);

            DateTime now           = DateTime.Now;
            var      grpCalculator = AutoAnimeGroupCalculator.CreateFromServerSettings(session);

            _log.Info(
                "The following exclusions will be applied when generating the groups: " + grpCalculator.Exclusions);

            // Group all of the specified series into their respective groups (keyed by the groups main anime ID)
            var seriesByGroup     = seriesList.ToLookup(s => grpCalculator.GetGroupAnimeId(s.AniDB_ID));
            var newGroupsToSeries =
                new List <Tuple <SVR_AnimeGroup, IReadOnlyCollection <SVR_AnimeSeries> > >(seriesList.Count);

            foreach (var groupAndSeries in seriesByGroup)
            {
                int             mainAnimeId = groupAndSeries.Key;
                SVR_AnimeSeries mainSeries  = groupAndSeries.FirstOrDefault(series => series.AniDB_ID == mainAnimeId);
                SVR_AnimeGroup  animeGroup  = CreateAnimeGroup(mainSeries, mainAnimeId, now);

                newGroupsToSeries.Add(
                    new Tuple <SVR_AnimeGroup, IReadOnlyCollection <SVR_AnimeSeries> >(animeGroup,
                                                                                       groupAndSeries.AsReadOnlyCollection()));
            }

            using (ITransaction trans = session.BeginTransaction())
            {
                _animeGroupRepo.InsertBatch(session, newGroupsToSeries.Select(gts => gts.Item1).AsReadOnlyCollection());
                trans.Commit();
            }

            // Anime groups should have IDs now they've been inserted. Now assign the group ID's to their respective series
            // (The caller of this method will be responsible for saving the AnimeSeries)
            foreach (var groupAndSeries in newGroupsToSeries)
            {
                foreach (SVR_AnimeSeries series in groupAndSeries.Item2)
                {
                    series.AnimeGroupID = groupAndSeries.Item1.AnimeGroupID;
                }
            }

            _log.Info("Generated {0} AnimeGroups", newGroupsToSeries.Count);

            return(newGroupsToSeries.Select(gts => gts.Item1));
        }
        private void DropAllTagFilters(ISessionWrapper session)
        {
            lock (globalDBLock)
            {
                lock (Cache)
                {
                    ClearCache();
                }

                using (ITransaction trans = session.BeginTransaction())
                {
                    session.CreateQuery("DELETE FROM " + nameof(SVR_GroupFilter) + " WHERE FilterType = " +
                                        (int)GroupFilterType.Tag + ";")
                    .ExecuteUpdate();
                    trans.Commit();
                }
            }
        }
Пример #6
0
        /// <summary>
        /// Re-creates all AnimeGroups based on the existing AnimeSeries.
        /// </summary>
        /// <param name="session">The NHibernate session.</param>
        /// <exception cref="ArgumentNullException"><paramref name="session"/> is <c>null</c>.</exception>
        public void RecreateAllGroups(ISessionWrapper session)
        {
            if (session == null)
            {
                throw new ArgumentNullException(nameof(session));
            }

            bool cmdProcGeneralPaused = ShokoService.CmdProcessorGeneral.Paused;
            bool cmdProcHasherPaused  = ShokoService.CmdProcessorHasher.Paused;
            bool cmdProcImagesPaused  = ShokoService.CmdProcessorImages.Paused;

            try
            {
                // Pause queues
                ShokoService.CmdProcessorGeneral.Paused = true;
                ShokoService.CmdProcessorHasher.Paused  = true;
                ShokoService.CmdProcessorImages.Paused  = true;

                _log.Info("Beginning re-creation of all groups");

                IReadOnlyList <SVR_AnimeSeries>      animeSeries   = RepoFactory.AnimeSeries.GetAll();
                IReadOnlyCollection <SVR_AnimeGroup> createdGroups = null;
                SVR_AnimeGroup tempGroup = null;

                using (ITransaction trans = session.BeginTransaction())
                {
                    tempGroup = CreateTempAnimeGroup(session);
                    ClearGroupsAndDependencies(session, tempGroup.AnimeGroupID);
                    trans.Commit();
                }

                if (_autoGroupSeries)
                {
                    createdGroups = AutoCreateGroupsWithRelatedSeries(session, animeSeries)
                                    .AsReadOnlyCollection();
                }
                else // Standard group re-create
                {
                    createdGroups = CreateGroupPerSeries(session, animeSeries)
                                    .AsReadOnlyCollection();
                }

                using (ITransaction trans = session.BeginTransaction())
                {
                    UpdateAnimeSeriesContractsAndSave(session, animeSeries);
                    session.Delete(tempGroup); // We should no longer need the temporary group we created earlier
                    trans.Commit();
                }

                // We need groups and series cached for updating of AnimeGroup contracts to work
                _animeGroupRepo.Populate(session, displayname: false);
                _animeSeriesRepo.Populate(session, displayname: false);

                using (ITransaction trans = session.BeginTransaction())
                {
                    UpdateAnimeGroupsAndTheirContracts(session, createdGroups);
                    trans.Commit();
                }

                // We need to update the AnimeGroups cache again now that the contracts have been saved
                // (Otherwise updating Group Filters won't get the correct results)
                _animeGroupRepo.Populate(session, displayname: false);
                _animeGroupUserRepo.Populate(session, displayname: false);
                _groupFilterRepo.Populate(session, displayname: false);

                using (ITransaction trans = session.BeginTransaction())
                {
                    UpdateGroupFilters(session);
                    trans.Commit();
                }

                _log.Info("Successfuly completed re-creating all groups");
            }
            catch (Exception e)
            {
                _log.Error(e, "An error occurred while re-creating all groups");

                try
                {
                    // If an error occurs then chances are the caches are in an inconsistent state. So re-populate them
                    _animeSeriesRepo.Populate();
                    _animeGroupRepo.Populate();
                    _groupFilterRepo.Populate();
                    _animeGroupUserRepo.Populate();
                }
                catch (Exception ie)
                {
                    _log.Warn(ie, "Failed to re-populate caches");
                }

                throw;
            }
            finally
            {
                // Un-pause queues (if they were previously running)
                ShokoService.CmdProcessorGeneral.Paused = cmdProcGeneralPaused;
                ShokoService.CmdProcessorHasher.Paused  = cmdProcHasherPaused;
                ShokoService.CmdProcessorImages.Paused  = cmdProcImagesPaused;
            }
        }
        private void CreateAllTagFilters(ISessionWrapper session, SVR_GroupFilter tagsdirec, Dictionary <int, ILookup <string, int> > lookup)
        {
            if (tagsdirec == null)
            {
                return;
            }

            HashSet <string> alltags = new HashSet <string>(
                RepoFactory.AniDB_Tag.GetAllForLocalSeries().Select(a => a.TagName.Replace('`', '\'')),
                StringComparer.InvariantCultureIgnoreCase);
            List <SVR_GroupFilter> toAdd = new List <SVR_GroupFilter>(alltags.Count);

            var users = RepoFactory.JMMUser.GetAll().ToList();

            //AniDB Tags are in english so we use en-us culture
            TextInfo tinfo = new CultureInfo("en-US", false).TextInfo;

            foreach (string s in alltags)
            {
                SVR_GroupFilter yf = new SVR_GroupFilter
                {
                    ParentGroupFilterID = tagsdirec.GroupFilterID,
                    InvisibleInClients  = 0,
                    ApplyToSeries       = 1,
                    GroupFilterName     = tinfo.ToTitleCase(s),
                    BaseCondition       = 1,
                    Locked          = 1,
                    SortingCriteria = "5;1",
                    FilterType      = (int)GroupFilterType.Tag,
                };
                yf.SeriesIds[0] = lookup[0][s.ToLowerInvariant()].ToHashSet();
                yf.GroupsIds[0] = yf.SeriesIds[0]
                                  .Select(id => RepoFactory.AnimeSeries.GetByID(id).TopLevelAnimeGroup?.AnimeGroupID ?? -1)
                                  .Where(id => id != -1).ToHashSet();
                foreach (var user in users)
                {
                    yf.SeriesIds[user.JMMUserID] = lookup[user.JMMUserID][s.ToLowerInvariant()].ToHashSet();
                    yf.GroupsIds[user.JMMUserID] = yf.SeriesIds[user.JMMUserID]
                                                   .Select(id => RepoFactory.AnimeSeries.GetByID(id).TopLevelAnimeGroup?.AnimeGroupID ?? -1)
                                                   .Where(id => id != -1).ToHashSet();
                }

                using (var trans = session.BeginTransaction())
                {
                    // get an ID
                    session.Insert(yf);
                    trans.Commit();
                }

                GroupFilterCondition gfc = new GroupFilterCondition
                {
                    ConditionType      = (int)GroupFilterConditionType.Tag,
                    ConditionOperator  = (int)GroupFilterOperator.In,
                    ConditionParameter = s,
                    GroupFilterID      = yf.GroupFilterID
                };
                yf.Conditions.Add(gfc);
                yf.UpdateEntityReferenceStrings();
                yf.GroupConditions        = Newtonsoft.Json.JsonConvert.SerializeObject(yf._conditions);
                yf.GroupConditionsVersion = SVR_GroupFilter.GROUPCONDITIONS_VERSION;
                toAdd.Add(yf);
            }

            lock (Cache)
            {
                Populate(session, false);
                lock (globalDBLock)
                {
                    foreach (var filters in toAdd.Batch(50))
                    {
                        using (ITransaction trans = session.BeginTransaction())
                        {
                            BatchUpdate(session, filters);
                            trans.Commit();
                        }
                    }
                }
            }
        }
        /// <summary>
        /// Creates a single <see cref="AnimeGroup"/> for each <see cref="AnimeSeries"/> in <paramref name="seriesList"/>.
        /// </summary>
        /// <remarks>
        /// This method assumes that there are no active transactions on the specified <paramref name="session"/>.
        /// </remarks>
        /// <param name="session">The NHibernate session.</param>
        /// <param name="seriesList">The list of <see cref="AnimeSeries"/> to create groups for.</param>
        /// <returns>A sequence of the created <see cref="AnimeGroup"/>s.</returns>
        private IEnumerable<AnimeGroup> CreateGroupPerSeries(ISessionWrapper session, IReadOnlyList<AnimeSeries> seriesList)
        {
            _log.Info("Generating AnimeGroups for {0} AnimeSeries", seriesList.Count);

            DateTime now = DateTime.Now;
            var newGroupsToSeries = new Tuple<AnimeGroup, AnimeSeries>[seriesList.Count];

            // Create one group per series
            for (int grp = 0; grp < seriesList.Count; grp++)
            {
                AnimeGroup group = new AnimeGroup();
                AnimeSeries series = seriesList[grp];

                group.Populate(series, now);
                newGroupsToSeries[grp] = new Tuple<AnimeGroup, AnimeSeries>(group, series);
            }

            using (ITransaction trans = session.BeginTransaction())
            {
                _animeGroupRepo.InsertBatch(session, newGroupsToSeries.Select(gts => gts.Item1).AsReadOnlyCollection());
                trans.Commit();
            }

            // Anime groups should have IDs now they've been inserted. Now assign the group ID's to their respective series
            // (The caller of this method will be responsible for saving the AnimeSeries)
            foreach (Tuple<AnimeGroup, AnimeSeries> groupAndSeries in newGroupsToSeries)
            {
                groupAndSeries.Item2.AnimeGroupID = groupAndSeries.Item1.AnimeGroupID;
            }

            _log.Info("Generated {0} AnimeGroups", newGroupsToSeries.Length);

            return newGroupsToSeries.Select(gts => gts.Item1);
        }
        /// <summary>
        /// Creates <see cref="AnimeGroup"/> that contain <see cref="AnimeSeries"/> that appear to be related.
        /// </summary>
        /// <remarks>
        /// This method assumes that there are no active transactions on the specified <paramref name="session"/>.
        /// </remarks>
        /// <param name="session">The NHibernate session.</param>
        /// <param name="seriesList">The list of <see cref="AnimeSeries"/> to create groups for.</param>
        /// <returns>A sequence of the created <see cref="AnimeGroup"/>s.</returns>
        private IEnumerable<AnimeGroup> AutoCreateGroupsWithRelatedSeries(ISessionWrapper session, IReadOnlyCollection<AnimeSeries> seriesList)
        {
            _log.Info("Auto-generating AnimeGroups for {0} AnimeSeries based on aniDB relationships", seriesList.Count);

            DateTime now = DateTime.Now;
            var grpCalculator = AutoAnimeGroupCalculator.CreateFromServerSettings(session);

            _log.Info("The following exclusions will be applied when generating the groups: " + grpCalculator.Exclusions);

            // Group all of the specified series into their respective groups (keyed by the groups main anime ID)
            var seriesByGroup = seriesList.ToLookup(s => grpCalculator.GetGroupAnimeId(s.AniDB_ID));
            var newGroupsToSeries = new List<Tuple<AnimeGroup, IReadOnlyCollection<AnimeSeries>>>(seriesList.Count);

            foreach (var groupAndSeries in seriesByGroup)
            {
                int mainAnimeId = groupAndSeries.Key;
                AnimeSeries mainSeries = groupAndSeries.FirstOrDefault(series => series.AniDB_ID == mainAnimeId);
                AnimeGroup animeGroup = CreateAnimeGroup(session, mainSeries, mainAnimeId, now);

                newGroupsToSeries.Add(new Tuple<AnimeGroup, IReadOnlyCollection<AnimeSeries>>(animeGroup, groupAndSeries.AsReadOnlyCollection()));
            }

            using (ITransaction trans = session.BeginTransaction())
            {
                _animeGroupRepo.InsertBatch(session, newGroupsToSeries.Select(gts => gts.Item1).AsReadOnlyCollection());
                trans.Commit();
            }

            // Anime groups should have IDs now they've been inserted. Now assign the group ID's to their respective series
            // (The caller of this method will be responsible for saving the AnimeSeries)
            foreach (var groupAndSeries in newGroupsToSeries)
            {
                foreach (AnimeSeries series in groupAndSeries.Item2)
                {
                    series.AnimeGroupID = groupAndSeries.Item1.AnimeGroupID;
                }
            }

            _log.Info("Generated {0} AnimeGroups", newGroupsToSeries.Count);

            return newGroupsToSeries.Select(gts => gts.Item1);
        }
Пример #10
0
        /// <summary>
        /// Re-creates all AnimeGroups based on the existing AnimeSeries.
        /// </summary>
        /// <param name="session">The NHibernate session.</param>
        /// <exception cref="ArgumentNullException"><paramref name="session"/> is <c>null</c>.</exception>
        public void RecreateAllGroups(ISessionWrapper session)
        {
            if (session == null)
                throw new ArgumentNullException(nameof(session));

            bool cmdProcGeneralPaused = JMMService.CmdProcessorGeneral.Paused;
            bool cmdProcHasherPaused = JMMService.CmdProcessorHasher.Paused;
            bool cmdProcImagesPaused = JMMService.CmdProcessorImages.Paused;

            try
            {
                // Pause queues
                JMMService.CmdProcessorGeneral.Paused = true;
                JMMService.CmdProcessorHasher.Paused = true;
                JMMService.CmdProcessorImages.Paused = true;

                _log.Info("Beginning re-creation of all groups");

                IReadOnlyList<AnimeSeries> animeSeries = RepoFactory.AnimeSeries.GetAll();
                IReadOnlyCollection<AnimeGroup> createdGroups = null;
                AnimeGroup tempGroup = null;

                using (ITransaction trans = session.BeginTransaction())
                {
                    tempGroup = CreateTempAnimeGroup(session);
                    ClearGroupsAndDependencies(session, tempGroup.AnimeGroupID);
                    trans.Commit();
                }

                if (_autoGroupSeries)
                {
                    createdGroups = AutoCreateGroupsWithRelatedSeries(session, animeSeries)
                        .AsReadOnlyCollection();
                }
                else // Standard group re-create
                {
                    createdGroups = CreateGroupPerSeries(session, animeSeries)
                        .AsReadOnlyCollection();
                }

                using (ITransaction trans = session.BeginTransaction())
                {
                    UpdateAnimeSeriesContractsAndSave(session, animeSeries);
                    session.Delete(tempGroup); // We should no longer need the temporary group we created earlier
                    trans.Commit();
                }

                // We need groups and series cached for updating of AnimeGroup contracts to work
                _animeGroupRepo.Populate(session, displayname: false);
                _animeSeriesRepo.Populate(session, displayname: false);

                using (ITransaction trans = session.BeginTransaction())
                {
                    UpdateAnimeGroupsAndTheirContracts(session, createdGroups);
                    trans.Commit();
                }

                // We need to update the AnimeGroups cache again now that the contracts have been saved
                // (Otherwise updating Group Filters won't get the correct results)
                _animeGroupRepo.Populate(session, displayname: false);
                _animeGroupUserRepo.Populate(session, displayname: false);
                _groupFilterRepo.Populate(session, displayname: false);

                using (ITransaction trans = session.BeginTransaction())
                {
                    UpdateGroupFilters(session);
                    trans.Commit();
                }

                _log.Info("Successfuly completed re-creating all groups");
            }
            catch (Exception e)
            {
                _log.Error(e, "An error occurred while re-creating all groups");

                try
                {
                    // If an error occurs then chances are the caches are in an inconsistent state. So re-populate them
                    _animeSeriesRepo.Populate();
                    _animeGroupRepo.Populate();
                    _groupFilterRepo.Populate();
                    _animeGroupUserRepo.Populate();
                }
                catch (Exception ie)
                {
                    _log.Warn(ie, "Failed to re-populate caches");
                }

                throw;
            }
            finally
            {
                // Un-pause queues (if they were previously running)
                JMMService.CmdProcessorGeneral.Paused = cmdProcGeneralPaused;
                JMMService.CmdProcessorHasher.Paused = cmdProcHasherPaused;
                JMMService.CmdProcessorImages.Paused = cmdProcImagesPaused;
            }
        }