Beispiel #1
0
        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);
            }
        }
Beispiel #2
0
        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);
        }
Beispiel #3
0
        /// <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));
        }
Beispiel #4
0
        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);
        }
Beispiel #5
0
        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);
        }
Beispiel #7
0
        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));
        }
Beispiel #8
0
        /// <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));
        }
Beispiel #9
0
        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>();

		}
Beispiel #12
0
        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);
        }
Beispiel #13
0
        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);
        }
Beispiel #14
0
        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);
        }
Beispiel #15
0
        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));
        }
Beispiel #16
0
        /// <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));
        }
Beispiel #17
0
        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());
            }
        }