private SearchTextQuery ProcessAdvancedSearch(SearchTextQuery textQuery, SongQueryParams queryParams) { if (textQuery.IsEmpty || textQuery.MatchMode == NameMatchMode.Exact || textQuery.MatchMode == NameMatchMode.StartsWith || !textQuery.OriginalQuery.StartsWith("!")) { return(textQuery); } var parsed = SearchParser.ParseQuery(textQuery.OriginalQuery.Substring(1)); var artistNames = parsed.GetValues("artist").ToArray(); if (artistNames.Any()) { queryParams.ArtistNames = artistNames; } var words = parsed.GetValues("").ToArray(); if (words.Any()) { queryParams.Common.TextQuery = new SearchTextQuery(textQuery.Query, NameMatchMode.Words, textQuery.OriginalQuery, words); return(queryParams.Common.TextQuery); } else { return(textQuery); } }
private IQueryable <Song> CreateQuery( SongQueryParams queryParams, ParsedSongQuery parsedQuery, NameMatchMode?nameMatchMode = null) { var query = Query <Song>() .Where(s => !s.Deleted) .WhereHasName(parsedQuery.Name, nameMatchMode ?? queryParams.Common.NameMatchMode) .WhereHasArtistParticipationStatus(queryParams.ArtistId, queryParams.ArtistParticipationStatus, queryParams.ChildVoicebanks, id => querySource.Load <Artist>(id)) .WhereDraftsOnly(queryParams.Common.DraftOnly) .WhereStatusIs(queryParams.Common.EntryStatus) .WhereHasType(queryParams.SongTypes) .WhereHasTag(!string.IsNullOrEmpty(queryParams.Tag) ? queryParams.Tag : parsedQuery.TagName) .WhereArtistHasTag(parsedQuery.ArtistTag) .WhereArtistHasType(parsedQuery.ArtistType) .WhereHasNicoId(parsedQuery.NicoId) .WhereIdNotIn(queryParams.IgnoredIds) .WhereInUserCollection(queryParams.UserCollectionId) .WhereHasLyrics(queryParams.LyricsLanguages); query = AddScoreFilter(query, queryParams.MinScore); query = AddTimeFilter(query, queryParams.TimeFilter); query = AddPVFilter(query, queryParams.OnlyWithPVs); return(query); }
/// <summary> /// Get songs, searching by exact matches FIRST. /// This mode does not support paging. /// </summary> private PartialFindResult <Song> GetSongsMoveExactToTop(SongQueryParams queryParams, ParsedSongQuery parsedQuery) { var sortRule = queryParams.SortRule; var maxResults = queryParams.Paging.MaxEntries; var getCount = queryParams.Paging.GetTotalCount; // Exact query contains the "exact" matches. // Note: the matched name does not have to be in user's display language, it can be any name. // The songs are sorted by user's display language though var exactQ = CreateQuery(queryParams, parsedQuery, NameMatchMode.StartsWith); int count; int[] ids; var exactResults = exactQ .OrderBy(sortRule, LanguagePreference) .Select(s => s.Id) .Take(maxResults) .ToArray(); if (exactResults.Length >= maxResults) { ids = exactResults; count = getCount ? CreateQuery(queryParams, parsedQuery).Count() : 0; } else { var directQ = CreateQuery(queryParams, parsedQuery); var direct = directQ .OrderBy(sortRule, LanguagePreference) .Select(s => s.Id) .Take(maxResults) .ToArray(); ids = exactResults .Concat(direct) .Distinct() .Take(maxResults) .ToArray(); count = getCount ? directQ.Count() : 0; } var songs = SortByIds( querySource .Query <Song>() .Where(s => ids.Contains(s.Id)) .ToArray(), ids); return(new PartialFindResult <Song>(songs, count, queryParams.Common.Query, true)); }
private EntryTypeAndTagCollection <SongType> ProcessUnifiedTypesAndTags(SongQueryParams queryParams) { EntryTypeAndTagCollection <SongType> typesAndTags = null; if (queryParams.UnifyEntryTypesAndTags) { typesAndTags = EntryTypeAndTagCollection <SongType> .Create(EntryType.Song, queryParams.SongTypes, queryParams.TagIds, _querySource); queryParams.TagIds = queryParams.TagIds.Except(typesAndTags.TagIds).ToArray(); queryParams.SongTypes = queryParams.SongTypes.Except(typesAndTags.SubTypes).ToArray(); } return(typesAndTags); }
private IQueryable <Song> CreateQuery( SongQueryParams queryParams, ParsedSongQuery parsedQuery, NameMatchMode?nameMatchMode = null) { var textQuery = !SearchTextQuery.IsNullOrEmpty(parsedQuery.Name) ? new SearchTextQuery(parsedQuery.Name.Query, nameMatchMode ?? parsedQuery.Name.MatchMode, parsedQuery.Name.OriginalQuery) : SearchTextQuery.Empty; textQuery = ProcessAdvancedSearch(textQuery, queryParams); var typesAndTags = ProcessUnifiedTypesAndTags(queryParams); var query = Query <Song>() .WhereNotDeleted() .WhereHasName(textQuery) .WhereHasArtistParticipationStatus(queryParams.ArtistParticipation, _querySource.OfType <Artist>()) .WhereHasArtists <Song, ArtistForSong>(queryParams.ArtistNames) .WhereStatusIs(queryParams.Common.EntryStatus) .WhereHasType(queryParams.SongTypes) .WhereHasTags(queryParams.TagIds, queryParams.ChildTags) .WhereHasTags(queryParams.Tags) .WhereHasTag(parsedQuery.TagName) .WhereHasTypeOrTag(typesAndTags) .WhereArtistHasTag(parsedQuery.ArtistTag) .WhereArtistHasType(parsedQuery.ArtistType) .WhereHasNicoId(parsedQuery.NicoId) .WhereHasPV(parsedQuery.PV) .WhereHasPVService(queryParams.PVServices) .WhereIdIs(parsedQuery.Id) .WhereIdNotIn(queryParams.IgnoredIds) .WhereInUserCollection(queryParams.UserCollectionId) .WhereHasParentSong(queryParams.ParentSongId) .WhereArtistIsFollowedByUser(queryParams.FollowedByUserId) .WhereReleaseEventIs(queryParams.ReleaseEventId) .WherePublishDateIsBetween(parsedQuery.PublishedAfter, parsedQuery.PublishedBefore) .WherePublishDateIsBetween(queryParams.AfterDate, queryParams.BeforeDate) .WhereHasScore(queryParams.MinScore) .WhereCreateDateIsWithin(queryParams.TimeFilter) .WhereHasPV(queryParams.OnlyWithPVs) .WhereMatchFilters(queryParams.AdvancedFilters) .WhereMilliBpmIsBetween(queryParams.MinMilliBpm, queryParams.MaxMilliBpm) .WhereLengthIsBetween(queryParams.MinLength, queryParams.MaxLength); return(query); }
public ActionResult ByName(string query, ContentLanguagePreference? lang, int? start, int? maxResults, NameMatchMode? nameMatchMode, string callback, DataFormat format = DataFormat.Auto) { var param = new SongQueryParams(query, new SongType[] {}, 0, defaultMax, false, true, NameMatchMode.Exact, SongSortRule.Name, true, false, new int[] {}); if (start.HasValue) param.Paging.Start = start.Value; if (maxResults.HasValue) param.Paging.MaxEntries = Math.Min(maxResults.Value, defaultMax); if (nameMatchMode.HasValue) param.Common.NameMatchMode = nameMatchMode.Value; var songs = Service.Find(s => new SongForApiContract(s, lang ?? ContentLanguagePreference.Default), param); return Object(songs, format, callback); }
private PartialFindResult <Song> GetSongs(SongQueryParams queryParams, ParsedSongQuery parsedQuery) { var query = CreateQuery(queryParams, parsedQuery); var ids = query .AddOrder(queryParams.SortRule, LanguagePreference) .Select(s => s.Id) .Paged(queryParams.Paging) .ToArray(); var songs = SortByIds(querySource .Query <Song>() .Where(s => ids.Contains(s.Id)) .ToArray(), ids); var count = (queryParams.Paging.GetTotalCount ? query.Count() : 0); return(new PartialFindResult <Song>(songs, count, queryParams.Common.Query, false)); }
/// <summary> /// Finds songs based on criteria. /// </summary> /// <param name="queryParams">Query parameters. Cannot be null.</param> /// <returns>List of song search results. Cannot be null.</returns> public PartialFindResult <Song> Find(SongQueryParams queryParams) { ParamIs.NotNull(() => queryParams); var parsedQuery = ParseTextQuery(queryParams.Common.TextQuery); var isMoveToTopQuery = (queryParams.Common.MoveExactToTop && queryParams.Common.NameMatchMode != NameMatchMode.StartsWith && queryParams.Common.NameMatchMode != NameMatchMode.Exact && !queryParams.ArtistParticipation.ArtistIds.HasAny && queryParams.Paging.Start == 0 && parsedQuery.HasNameQuery); if (isMoveToTopQuery) { return(GetSongsMoveExactToTop(queryParams, parsedQuery)); } return(GetSongs(queryParams, parsedQuery)); }
private IQueryable <Song> CreateQuery( SongQueryParams queryParams, ParsedSongQuery parsedQuery, NameMatchMode?nameMatchMode = null) { var textQuery = !SearchTextQuery.IsNullOrEmpty(parsedQuery.Name) ? new SearchTextQuery(parsedQuery.Name.Query, nameMatchMode ?? parsedQuery.Name.MatchMode, parsedQuery.Name.OriginalQuery) : SearchTextQuery.Empty; textQuery = ProcessAdvancedSearch(textQuery, queryParams); var query = Query <Song>() .Where(s => !s.Deleted) .WhereHasName(textQuery) .WhereHasArtistParticipationStatus(queryParams.ArtistParticipation, id => querySource.Load <Artist>(id)) .WhereHasArtists <Song, ArtistForSong>(queryParams.ArtistNames) .WhereStatusIs(queryParams.Common.EntryStatus) .WhereHasType(queryParams.SongTypes) .WhereHasTags(queryParams.TagIds, queryParams.ChildTags) .WhereHasTags(queryParams.Tags) .WhereHasTag(parsedQuery.TagName) .WhereArtistHasTag(parsedQuery.ArtistTag) .WhereArtistHasType(parsedQuery.ArtistType) .WhereHasNicoId(parsedQuery.NicoId) .WhereHasPV(parsedQuery.PV) .WhereHasPVService(queryParams.PVServices) .WhereIdIs(parsedQuery.Id) .WhereIdNotIn(queryParams.IgnoredIds) .WhereInUserCollection(queryParams.UserCollectionId) .WherePublishDateIsBetween(parsedQuery.PublishedAfter, parsedQuery.PublishedBefore) .WhereHasScore(queryParams.MinScore) .WhereCreateDateIsWithin(queryParams.TimeFilter) .WhereHasPV(queryParams.OnlyWithPVs) .WhereMatchFilters(queryParams.AdvancedFilters); return(query); }
public PartialFindResult<SongForApiContract> GetList( string query = "", SongType songTypes = SongType.Unspecified, string tag = null, int? artistId = null, ArtistAlbumParticipationStatus artistParticipationStatus = ArtistAlbumParticipationStatus.Everything, bool childVoicebanks = false, bool onlyWithPvs = false, int? since = null, [FromUri] ContentLanguageSelections? lyrics = null, int? userCollectionId = null, EntryStatus? status = null, int start = 0, int maxResults = defaultMax, bool getTotalCount = false, SongSortRule sort = SongSortRule.Name, NameMatchMode nameMatchMode = NameMatchMode.Exact, SongOptionalFields fields = SongOptionalFields.None, ContentLanguagePreference lang = ContentLanguagePreference.Default) { query = FindHelpers.GetMatchModeAndQueryForSearch(query, ref nameMatchMode); var types = songTypes != SongType.Unspecified ? new[] { songTypes } : new SongType[0]; var param = new SongQueryParams(query, types, start, Math.Min(maxResults, absoluteMax), false, getTotalCount, nameMatchMode, sort, false, false, null) { Tag = tag, OnlyWithPVs = onlyWithPvs, ArtistId = artistId ?? 0, ArtistParticipationStatus = artistParticipationStatus, ChildVoicebanks = childVoicebanks, TimeFilter = since.HasValue ? TimeSpan.FromHours(since.Value) : TimeSpan.Zero, LyricsLanguages = lyrics != null ? lyrics.Value.ToIndividualSelections().ToArray() : null, UserCollectionId = userCollectionId ?? 0 }; param.Common.EntryStatus = status; var artists = service.Find(s => new SongForApiContract(s, null, lang, fields), param); return artists; }
public void SetUp() { queryParams = new SongQueryParams { SortRule = SongSortRule.Name }; context = new DatabaseTestContext<IQuerySource>(); }
public PartialViewResult SongsPaged(int id = invalidId, int? page = null) { var pageIndex = (page - 1) ?? 0; var queryParams = new SongQueryParams { Paging = PagingProperties.CreateFromPage(pageIndex, entriesPerPage, true), SortRule = SongSortRule.Name, ArtistId = id }; var result = Services.Songs.Find(queryParams); var data = new PagingData<SongContract>(result.Items.ToPagedList(pageIndex, entriesPerPage, result.TotalCount), id, "SongsPaged", "ui-tabs-4"); return PartialView("PagedSongs", data); }
public void SetUp() { querySource = new QuerySourceList(); artist = new Artist(TranslatedString.Create("Junk")) { Id = 257 }; song = new Song(new LocalizedString("Nebula", ContentLanguageSelection.English)) { Id = 121, SongType = SongType.Original, PVServices = PVServices.Youtube, CreateDate = new DateTime(2012, 6, 1) }; AddSong(song); songWithArtist = new Song(new LocalizedString("Crystal Tears", ContentLanguageSelection.English)) { Id = 7787, FavoritedTimes = 39, CreateDate = new DateTime(2012, 1, 1) }; songWithArtist.AddArtist(artist); AddSong(songWithArtist); queryParams = new SongQueryParams(); search = new Model.Service.Search.SongSearch.SongSearch(querySource, ContentLanguagePreference.Default); }
public ActionResult Index(IndexRouteParams indexParams) { WebHelper.VerifyUserAgent(Request); var pageSize = (indexParams.pageSize.HasValue ? Math.Min(indexParams.pageSize.Value, 30) : 30); var page = indexParams.page ?? 1; var sortRule = indexParams.sort ?? SongSortRule.Name; var timeFilter = DateTimeUtils.ParseFromSimpleString(indexParams.since); var filter = indexParams.filter; var songType = indexParams.songType ?? SongType.Unspecified; var draftsOnly = indexParams.draftsOnly ?? false; var matchMode = indexParams.matchMode ?? NameMatchMode.Auto; var onlyWithPVs = indexParams.onlyWithPVs ?? false; var view = indexParams.view ?? SongViewMode.Details; if (matchMode == NameMatchMode.Auto && filter != null && filter.Length <= 2) matchMode = NameMatchMode.StartsWith; var queryParams = new SongQueryParams(filter, songType != SongType.Unspecified ? new[] { songType } : new SongType[] { }, (page - 1) * pageSize, pageSize, draftsOnly, true, matchMode, sortRule, false, false, null) { TimeFilter = timeFilter, OnlyWithPVs = onlyWithPVs, ArtistId = indexParams.artistId ?? 0 }; var result = Service.FindWithAlbum(queryParams, view == SongViewMode.Preview); if (page == 1 && result.TotalCount == 1 && result.Items.Length == 1) { return RedirectToAction("Details", new { id = result.Items[0].Id }); } SetSearchEntryType(EntryType.Song); var model = new Index(result, filter, matchMode, songType, indexParams.since, onlyWithPVs, sortRule, view, draftsOnly, page, pageSize, indexParams); return View(model); }
public FeedResult Feed(IndexRouteParams indexParams) { WebHelper.VerifyUserAgent(Request); var pageSize = (indexParams.pageSize.HasValue ? Math.Min(indexParams.pageSize.Value, 30) : 30); var sortRule = indexParams.sort ?? SongSortRule.Name; var timeFilter = DateTimeUtils.ParseFromSimpleString(indexParams.since); var filter = indexParams.filter; var songType = indexParams.songType ?? SongType.Unspecified; var draftsOnly = indexParams.draftsOnly ?? false; var matchMode = indexParams.matchMode ?? NameMatchMode.Auto; var onlyWithPVs = indexParams.onlyWithPVs ?? false; var queryParams = new SongQueryParams(filter, songType != SongType.Unspecified ? new[] { songType } : new SongType[] { }, 0, pageSize, draftsOnly, false, matchMode, sortRule, false, false, null) { TimeFilter = timeFilter, OnlyWithPVs = onlyWithPVs, ArtistId = indexParams.artistId ?? 0, }; var result = Service.FindWithThumbPreferNotNico(queryParams); var fac = new SongFeedFactory(); var feed = fac.Create(result.Items, VocaUriBuilder.CreateAbsolute(Url.Action("Index", indexParams)), song => RenderPartialViewToString("SongItem", song), song => Url.Action("Details", new { id = song.Id })); return new FeedResult(new Atom10FeedFormatter(feed)); }
/// <summary> /// Finds songs based on criteria. /// </summary> /// <param name="queryParams">Query parameters. Cannot be null.</param> /// <returns>List song search results. Cannot be null.</returns> public PartialFindResult <Song> Find(SongQueryParams queryParams) { ParamIs.NotNull(() => queryParams); var draftsOnly = queryParams.Common.DraftOnly; var getTotalCount = queryParams.Paging.GetTotalCount; var ignoreIds = queryParams.IgnoredIds; var moveExactToTop = queryParams.Common.MoveExactToTop; var nameMatchMode = queryParams.Common.NameMatchMode; var onlyByName = queryParams.Common.OnlyByName; var query = queryParams.Common.Query; var songTypes = queryParams.SongTypes; var sortRule = queryParams.SortRule; var start = queryParams.Paging.Start; var maxResults = queryParams.Paging.MaxEntries; bool filterByType = songTypes.Any(); Song[] songs; bool foundExactMatch = false; if (queryParams.ArtistId == 0 && string.IsNullOrWhiteSpace(query)) { var q = Query <Song>() .Where(s => !s.Deleted && !ignoreIds.Contains(s.Id)); if (draftsOnly) { q = q.Where(a => a.Status == EntryStatus.Draft); } if (filterByType) { q = q.Where(s => songTypes.Contains(s.SongType)); } q = AddTimeFilter(q, queryParams.TimeFilter); q = AddPVFilter(q, queryParams.OnlyWithPVs); q = q.AddOrder(sortRule, LanguagePreference); songs = q .Skip(start) .Take(maxResults) .ToArray(); } else if (queryParams.ArtistId != 0) { int artistId = queryParams.ArtistId; var q = Query <ArtistForSong>() .Where(m => !m.Song.Deleted && m.Artist.Id == artistId); if (draftsOnly) { q = q.Where(a => a.Song.Status == EntryStatus.Draft); } if (filterByType) { q = q.Where(s => songTypes.Contains(s.Song.SongType)); } q = AddTimeFilter(q, queryParams.TimeFilter); q = AddPVFilter(q, queryParams.OnlyWithPVs); songs = q .Select(m => m.Song) .AddOrder(sortRule, LanguagePreference) .Skip(start) .Take(maxResults) .ToArray(); } else { query = query.Trim(); // Searching by SortNames can be disabled in the future because all names should be included in the Names list anyway. var directQ = Query <Song>() .Where(s => !s.Deleted); if (draftsOnly) { directQ = directQ.Where(a => a.Status == EntryStatus.Draft); } if (filterByType) { directQ = directQ.Where(s => songTypes.Contains(s.SongType)); } directQ = AddTimeFilter(directQ, queryParams.TimeFilter); directQ = AddPVFilter(directQ, queryParams.OnlyWithPVs); directQ = AddNameFilter(directQ, query, nameMatchMode, onlyByName); directQ = directQ.AddOrder(sortRule, LanguagePreference); var direct = directQ.ToArray(); var additionalNamesQ = Query <SongName>() .Where(m => !m.Song.Deleted); if (draftsOnly) { additionalNamesQ = additionalNamesQ.Where(a => a.Song.Status == EntryStatus.Draft); } additionalNamesQ = AddTimeFilter(additionalNamesQ, queryParams.TimeFilter); additionalNamesQ = AddPVFilter(additionalNamesQ, queryParams.OnlyWithPVs); additionalNamesQ = FindHelpers.AddEntryNameFilter(additionalNamesQ, query, nameMatchMode); if (filterByType) { additionalNamesQ = additionalNamesQ.Where(m => songTypes.Contains(m.Song.SongType)); } var additionalNames = additionalNamesQ .Select(m => m.Song) .AddOrder(sortRule, LanguagePreference) .Distinct() .ToArray() .Where(a => !direct.Contains(a)); var entries = direct.Concat(additionalNames) .Where(e => !ignoreIds.Contains(e.Id)) .Skip(start) .Take(maxResults) .ToArray(); if (moveExactToTop) { var exactMatch = entries .Where(e => e.Names.Any(n => n.Value.StartsWith(query, StringComparison.InvariantCultureIgnoreCase))) .ToArray(); if (exactMatch.Any()) { entries = CollectionHelper.MoveToTop(entries, exactMatch).ToArray(); foundExactMatch = true; } } songs = entries; } int count = (getTotalCount ? GetSongCount(query, songTypes, onlyByName, draftsOnly, nameMatchMode, queryParams.TimeFilter, queryParams.OnlyWithPVs, queryParams) : 0); return(new PartialFindResult <Song>(songs, count, queryParams.Common.Query, foundExactMatch)); }
public int GetSongCount(string query, SongType[] songTypes, bool onlyByName, bool draftsOnly, NameMatchMode nameMatchMode, TimeSpan timeFilter, bool onlyWithPVs, SongQueryParams queryParams) { bool filterByType = songTypes.Any(); if (queryParams.ArtistId == 0 && string.IsNullOrWhiteSpace(query)) { var q = Query <Song>() .Where(s => !s.Deleted); if (draftsOnly) { q = q.Where(a => a.Status == EntryStatus.Draft); } if (filterByType) { q = q.Where(s => songTypes.Contains(s.SongType)); } q = AddTimeFilter(q, timeFilter); q = AddPVFilter(q, onlyWithPVs); return(q.Count()); } else if (queryParams.ArtistId != 0) { int artistId = queryParams.ArtistId; var q = Query <ArtistForSong>() .Where(m => !m.Song.Deleted && m.Artist.Id == artistId); if (draftsOnly) { q = q.Where(a => a.Song.Status == EntryStatus.Draft); } if (filterByType) { q = q.Where(s => songTypes.Contains(s.Song.SongType)); } q = AddTimeFilter(q, timeFilter); q = AddPVFilter(q, onlyWithPVs); return(q.Count()); } else { var directQ = Query <Song>() .Where(s => !s.Deleted); if (draftsOnly) { directQ = directQ.Where(a => a.Status == EntryStatus.Draft); } if (filterByType) { directQ = directQ.Where(s => songTypes.Contains(s.SongType)); } directQ = AddTimeFilter(directQ, timeFilter); directQ = AddPVFilter(directQ, onlyWithPVs); directQ = AddNameFilter(directQ, query, nameMatchMode, onlyByName); var direct = directQ.ToArray(); var additionalNamesQ = Query <SongName>() .Where(m => !m.Song.Deleted); if (draftsOnly) { additionalNamesQ = additionalNamesQ.Where(a => a.Song.Status == EntryStatus.Draft); } if (filterByType) { additionalNamesQ = additionalNamesQ.Where(s => songTypes.Contains(s.Song.SongType)); } additionalNamesQ = AddTimeFilter(additionalNamesQ, timeFilter); additionalNamesQ = AddPVFilter(additionalNamesQ, onlyWithPVs); additionalNamesQ = FindHelpers.AddEntryNameFilter(additionalNamesQ, query, nameMatchMode); var additionalNames = additionalNamesQ .Select(m => m.Song) .Distinct() .ToArray() .Where(a => !direct.Contains(a)) .ToArray(); return(direct.Count() + additionalNames.Count()); } }