private static List <SearchResult> SearchTagsEquals(string query, int limit, SVR_JMMUser user, ParallelQuery <AniDB_Tag> allTags) { List <SearchResult> series = new List <SearchResult>(); IEnumerable <CustomTag> customTags = RepoFactory.CustomTag.GetAll(); series.AddRange(customTags.Where(a => a.TagName.Equals(query, StringComparison.InvariantCultureIgnoreCase)).SelectMany(tag => { return(RepoFactory.CrossRef_CustomTag.GetByCustomTagID(tag.CustomTagID) .Select(xref => { if (xref.CrossRefType != (int)CustomTagCrossRefType.Anime) { return null; } var anime = RepoFactory.AnimeSeries.GetByAnimeID(xref.CrossRefID); // Because we are searching tags, then getting series from it, we need to make sure it's allowed // for example, p**n could have the drugs tag, even though it's not a "p**n tag" if (anime?.GetAnime()?.GetAllTags().FindInEnumerable(user.GetHideCategories()) ?? true) { return null; } return new SearchResult { Distance = 0, Index = 0, Match = tag.TagName, Result = anime, ExactMatch = true }; }).Where(a => a != null).OrderBy(a => a.Distance).ThenBy(a => a.Result.GetSeriesName())); }).Take(limit)); limit -= series.Count; series.AddRange(allTags.Where(a => a.TagName.Equals(query, StringComparison.InvariantCultureIgnoreCase)).SelectMany(tag => { return(RepoFactory.AniDB_Anime_Tag.GetByTagID(tag.TagID) .Select(xref => { var anime = RepoFactory.AnimeSeries.GetByAnimeID(xref.AnimeID); // Because we are searching tags, then getting series from it, we need to make sure it's allowed // for example, p**n could have the drugs tag, even though it's not a "p**n tag" if (anime?.GetAnime()?.GetAllTags().FindInEnumerable(user.GetHideCategories()) ?? true) { return null; } return new SearchResult { Distance = (600 - xref.Weight) / 600D, Index = 0, Match = tag.TagName, Result = anime, ExactMatch = true }; }).Where(a => a != null).OrderBy(a => a.Distance).ThenBy(a => a.Result.GetSeriesName())); }).Take(limit)); return(series); }
public User(SVR_JMMUser user) { ID = user.JMMUserID; Username = user.Username; IsAdmin = user.IsAdmin == 1; CommunitySites = new List <CommunitySites>(); if (user.IsAniDBUser == 1) { CommunitySites.Add(global::Shoko.Models.Enums.CommunitySites.AniDB); } if (user.IsTraktUser == 1) { CommunitySites.Add(global::Shoko.Models.Enums.CommunitySites.Trakt); } if (!string.IsNullOrEmpty(user.PlexToken)) { CommunitySites.Add(global::Shoko.Models.Enums.CommunitySites.Plex); } TagBlacklist = user.GetHideCategories().ToList(); }
private static List <SearchResult> SearchTagsFuzzy(string query, int limit, SVR_JMMUser user, ParallelQuery <AniDB_Tag> allTags) { List <SearchResult> series = new List <SearchResult>(); IEnumerable <Misc.SearchInfo <CustomTag> > customTags = RepoFactory.CustomTag.GetAll().Select(a => { if (user.GetHideCategories().Contains(a.TagName)) { return(null); } Misc.SearchInfo <CustomTag> tag = Misc.DiceFuzzySearch(a.TagName, query, 0, a); if (tag.Index == -1 || tag.Result == null) { return(null); } return(tag); }).Where(a => a != null).OrderBy(a => a.Distance); series.AddRange(customTags.SelectMany(tag => { return(RepoFactory.CrossRef_CustomTag.GetByCustomTagID(tag.Result.CustomTagID) .Select(xref => { if (xref.CrossRefType != (int)CustomTagCrossRefType.Anime) { return null; } SVR_AnimeSeries anime = RepoFactory.AnimeSeries.GetByAnimeID(xref.CrossRefID); // Because we are searching tags, then getting series from it, we need to make sure it's allowed // for example, p**n could have the drugs tag, even though it's not a "p**n tag" if (anime?.GetAnime()?.GetAllTags().FindInEnumerable(user.GetHideCategories()) ?? true) { return null; } return new SearchResult { Distance = tag.Distance, Index = tag.Index, Match = tag.Result.TagName, Result = anime, ExactMatch = tag.ExactMatch }; }).Where(b => b != null).OrderBy(b => b.Distance).ThenBy(b => b.Result.GetSeriesName()).ToList()); }).Take(limit)); limit -= series.Count; var tags = allTags.Select(tag => { var result = Misc.DiceFuzzySearch(tag.TagName, query, 0, tag); if (result.Index == -1 || result.Result == null) { return(null); } return(result); }).Where(a => a != null).OrderBy(a => a.Distance); series.AddRange(tags.SelectMany(tag => { return(RepoFactory.AniDB_Anime_Tag.GetByTagID(tag.Result.TagID) .Select(xref => { var anime = RepoFactory.AnimeSeries.GetByAnimeID(xref.AnimeID); // Because we are searching tags, then getting series from it, we need to make sure it's allowed // for example, p**n could have the drugs tag, even though it's not a "p**n tag" if (anime?.GetAnime()?.GetAllTags().FindInEnumerable(user.GetHideCategories()) ?? true) { return null; } return new SearchResult { Distance = (600D - xref.Weight) / 600, Index = tag.Index, Match = tag.Result.TagName, Result = anime, ExactMatch = tag.ExactMatch }; }).Where(a => a != null).OrderBy(a => a.Distance).ThenBy(a => a.Result.GetSeriesName()).ToList()); }).Take(limit)); return(series); }
/// <summary> /// Search for series with given query in name or tag /// </summary> /// <param name="query">target string</param> /// <param name="userID">user id</param> /// <param name="limit">The number of results to return</param> /// <param name="flags">The SearchFlags to determine the type of search</param> /// <returns> /// <see cref="List{SearchResult}" /> /// </returns> public static List <SearchResult> Search(int userID, string query, int limit, SearchFlags flags, TagFilter.Filter tagFilter = TagFilter.Filter.None) { query = query.ToLowerInvariant(); SVR_JMMUser user = RepoFactory.JMMUser.GetByID(userID); if (user == null) { throw new Exception("User not found"); } ParallelQuery <SVR_AnimeSeries> allSeries = RepoFactory.AnimeSeries.GetAll().AsParallel().Where(a => a?.GetAnime() != null && (a.GetAnime().GetAllTags().Count == 0 || !a.GetAnime().GetAllTags().FindInEnumerable(user.GetHideCategories()))); ParallelQuery <AniDB_Tag> allTags = RepoFactory.AniDB_Tag.GetAll().AsParallel() .Where(a => { List <string> _ = new List <string>(); return(!user.GetHideCategories().Contains(a.TagName) && !TagFilter.IsTagBlackListed(a.TagName, tagFilter, ref _)); }); //search by anime id if (int.TryParse(query, out int aid)) { var aidResults = SearchTitlesByAnimeID(aid, allSeries); if (aidResults.Count > 0) { return(aidResults); } } #region Search_TitlesOnly switch (flags) { case SearchFlags.Titles: return(SearchTitlesIndexOf(query, limit, allSeries)); case SearchFlags.Fuzzy | SearchFlags.Titles: return(SearchTitlesFuzzy(query, limit, allSeries)); case SearchFlags.Tags: return(SearchTagsEquals(query, limit, user, allTags)); case SearchFlags.Fuzzy | SearchFlags.Tags: return(SearchTagsFuzzy(query, limit, user, allTags)); case SearchFlags.Tags | SearchFlags.Titles: List <SearchResult> titleResult = SearchTitlesIndexOf(query, limit, allSeries); int tagLimit = limit - titleResult.Count; if (tagLimit <= 0) { return(titleResult); } titleResult.AddRange(SearchTagsEquals(query, tagLimit, user, allTags)); return(titleResult); case SearchFlags.Fuzzy | SearchFlags.Tags | SearchFlags.Titles: List <SearchResult> titles = SearchTitlesFuzzy(query, limit, allSeries); int tagLimit2 = limit - titles.Count; if (tagLimit2 <= 0) { return(titles); } titles.AddRange(SearchTagsFuzzy(query, tagLimit2, user, allTags)); return(titles); } #endregion return(new List <SearchResult>()); }
public object GetStats() { SVR_JMMUser user = HttpContext.User.Identity as SVR_JMMUser; int series_count; int file_count; string size; int watched_files = 0; int watched_series = 0; long hours = 0; List <string> tags; if (user != null) { var series = Repo.Instance.AnimeSeries.GetAll().Where(a => !a.GetAnime()?.GetAllTags().FindInEnumerable(user.GetHideCategories()) ?? false).ToList(); series_count = series.Count; var files = series.SelectMany(a => a.GetAnimeEpisodes()).SelectMany(a => a.GetVideoLocals()) .DistinctBy(a => a.VideoLocalID).ToList(); file_count = files.Count; size = SizeSuffix(files.Sum(a => a.FileSize)); var watched = Repo.Instance.VideoLocal_User.GetByUserID(user.JMMUserID) .Where(a => a.WatchedDate != null).ToList(); watched_files = watched.Count; watched_series = Repo.Instance.AnimeSeries.GetAll().Count(a => { var contract = a.GetUserContract(user.JMMUserID); if (contract?.MissingEpisodeCount > 0) { return(false); } return(contract?.UnwatchedEpisodeCount == 0); }); hours = watched.Select(a => Repo.Instance.VideoLocal.GetByID(a.VideoLocalID)).Where(a => a != null) .Sum(a => a.Duration) / 3600000; // 1000ms * 60s * 60m = ?h tags = Repo.Instance.AniDB_Anime_Tag.GetAllForLocalSeries().GroupBy(a => a.TagID) .ToDictionary(a => a.Key, a => a.Count()).OrderByDescending(a => a.Value) .Select(a => Repo.Instance.AniDB_Tag.GetByID(a.Key)?.TagName) .Where(a => a != null && !user.GetHideCategories().Contains(a)).ToList(); var tagfilter = TagFilter.Filter.AnidbInternal | TagFilter.Filter.Misc | TagFilter.Filter.Source; tags = TagFilter.ProcessTags(tagfilter, tags).Take(10).ToList(); } else { var series = Repo.Instance.AnimeSeries.GetAll(); series_count = series.Count; var files = series.SelectMany(a => a.GetAnimeEpisodes()).SelectMany(a => a.GetVideoLocals()) .DistinctBy(a => a.VideoLocalID).ToList(); file_count = files.Count; size = SizeSuffix(files.Sum(a => a.FileSize)); tags = Repo.Instance.AniDB_Anime_Tag.GetAllForLocalSeries().GroupBy(a => a.TagID) .ToDictionary(a => a.Key, a => a.Count()).OrderByDescending(a => a.Value) .Select(a => Repo.Instance.AniDB_Tag.GetByID(a.Key)?.TagName) .Where(a => a != null).ToList(); var tagfilter = TagFilter.Filter.AnidbInternal | TagFilter.Filter.Misc | TagFilter.Filter.Source; tags = TagFilter.ProcessTags(tagfilter, tags).Take(10).ToList(); } return(new Dictionary <string, object> { { "queue", Repo.Instance.CommandRequest.GetByClasses().ToDictionary(a => FromLastPoint(a.Key), a => a.Value) }, { "file_count", file_count }, { "series_count", series_count }, { "collection_size", size }, { "watched_files", watched_files }, { "watched_series", watched_series }, { "hours_watched", hours }, { "tags", tags } }); }