Ejemplo n.º 1
0
        private void ResetButtonPressed()
        {
            _maxResultsShownStagingValue = PluginConfig.MaxSearchResults;
            _stripSymbolsStagingValue    = PluginConfig.StripSymbols;
            _splitQueryStagingValue      = PluginConfig.SplitQueryByWords;
            _songFieldsStagingValue      = PluginConfig.SongFieldsToSearch;
            _compactModeStagingValue     = PluginConfig.CompactSearchMode;

            RefreshUI();

            _resetButton.interactable = false;
            _applyButton.interactable = false;
        }
        private IEnumerator _SearchSongs(string searchQuery)
        {
            int index = 0;

            string[]             queryWords;
            bool                 stripSymbols = PluginConfig.StripSymbols;
            bool                 splitWords   = PluginConfig.SplitQueryByWords;
            SearchableSongFields songFields   = PluginConfig.SongFieldsToSearch;

            if (stripSymbols)
            {
                searchQuery = RemoveSymbolsRegex.Replace(searchQuery.ToLower(), string.Empty);
            }
            else
            {
                searchQuery = searchQuery.ToLower();
            }

            if (splitWords)
            {
                queryWords = searchQuery.Split(SplitCharacters, StringSplitOptions.RemoveEmptyEntries);
            }
            else
            {
                queryWords = new string[] { searchQuery }
            };

            while (index < _searchSpace.Count)
            {
                // limit the number of songs to evaluate so users with large song libraries don't pause on every key press
                for (int count = 0; count < MaxSearchInOneFrame && index < _searchSpace.Count; ++count)
                {
                    if (!CheckSong(_searchSpace[index], stripSymbols, splitWords, songFields, queryWords))
                    {
                        _searchSpace.RemoveAt(index);
                    }
                    else
                    {
                        ++index;
                    }
                }
                yield return(null);
            }

            _searchCompletedAction?.Invoke(_searchSpace.ToArray());
            _searchCoroutine = null;
        }
        /// <summary>
        /// Search through all the songs provided and return a result immediately, rather than using a coroutine and a callback.
        /// This may cause the game to freeze momentarily for large song libraries.
        /// </summary>
        /// <param name="searchSpace">A list of songs to search through.</param>
        /// <param name="searchQuery">The search term that all returned songs should contain.</param>
        /// <param name="overrideStripSymbols">Strip symbols from the query and search space fields. Set as null to use config settings.</param>
        /// <param name="overrideSplitWords">Split a query into separate words. Set as null to use config settings.</param>
        /// <param name="overrideSongFields">Fields of a beatmap to search for the query. Set as null to use config settings.</param>
        /// <returns>A list of songs that contain the provided search term.</returns>
        public List <IPreviewBeatmapLevel> StartInstantSearch(IEnumerable <IPreviewBeatmapLevel> searchSpace, string searchQuery, bool?overrideStripSymbols = null, bool?overrideSplitWords = null, SearchableSongFields?overrideSongFields = null)
        {
            if (searchSpace == null || string.IsNullOrEmpty(searchQuery))
            {
                return(searchSpace?.ToList() ?? new List <IPreviewBeatmapLevel>(0));
            }

            string[]             queryWords;
            bool                 stripSymbols = overrideStripSymbols.HasValue ? overrideStripSymbols.Value : PluginConfig.StripSymbols;
            bool                 splitWords   = overrideSplitWords.HasValue ? overrideSplitWords.Value : PluginConfig.SplitQueryByWords;
            SearchableSongFields songFields   = overrideSongFields.HasValue ? overrideSongFields.Value : PluginConfig.SongFieldsToSearch;

            if (stripSymbols)
            {
                searchQuery = RemoveSymbolsRegex.Replace(searchQuery.ToLower(), string.Empty);
            }
            else
            {
                searchQuery = searchQuery.ToLower();
            }

            if (splitWords)
            {
                queryWords = searchQuery.Split(SplitCharacters, StringSplitOptions.RemoveEmptyEntries);
            }
            else
            {
                queryWords = new string[] { searchQuery }
            };

            return(searchSpace
                   .AsParallel()
                   .Where(level => CheckSong(level, stripSymbols, splitWords, songFields, queryWords))
                   .AsSequential()
                   .ToList());
        }
Ejemplo n.º 4
0
        protected override void DidActivate(bool firstActivation, ActivationType activationType)
        {
            _maxResultsShownStagingValue = PluginConfig.MaxSearchResults;
            _stripSymbolsStagingValue    = PluginConfig.StripSymbols;
            _splitQueryStagingValue      = PluginConfig.SplitQueryByWords;
            _songFieldsStagingValue      = PluginConfig.SongFieldsToSearch;
            _compactModeStagingValue     = PluginConfig.CompactSearchMode;

            if (firstActivation)
            {
                var headerRectTransform = Instantiate(Resources.FindObjectsOfTypeAll <RectTransform>()
                                                      .First(x => x.name == "HeaderPanel" && x.parent.name == "PlayerSettingsViewController"), this.rectTransform);
                headerRectTransform.gameObject.SetActive(true);
                TextMeshProUGUI titleText = headerRectTransform.GetComponentInChildren <TextMeshProUGUI>();
                titleText.text = "Options";

                _submenu = new SubMenu(this.transform);

                // have to use the ListViewController because IntViewController doesn't seem to work outside of the settings menu
                float[] maxResultsShownValues =
                    Enumerable.Range(PluginConfig.MaxSearchResultsMinValue, PluginConfig.MaxSearchResultsMaxValue + 1)
                    .Select((x) => (float)x).ToArray();
                _maxResultsShownSetting = _submenu.AddList("Maximum # of Results Shown", maxResultsShownValues,
                                                           "The maximum number of songs found before a search result is shown.\n" +
                                                           "<color=#11FF11>A lower number is less distracting and only displays results when most irrelevant songs are removed.</color>\n" +
                                                           "<color=#FFFF11>You can force a search result to be shown using the button on the center screen.</color>");
                _maxResultsShownSetting.GetTextForValue += x => ((int)x).ToString();
                _maxResultsShownSetting.GetValue        += () => _maxResultsShownStagingValue;
                _maxResultsShownSetting.SetValue        += delegate(float value)
                {
                    _maxResultsShownStagingValue = (int)value;
                    _resetButton.interactable    = true;
                    _applyButton.interactable    = true;
                };
                SetSettingElementPosition(_maxResultsShownSetting.transform as RectTransform);
                _maxResultsShownSetting.Init();
                _maxResultsShownSetting.applyImmediately = true;        // applyImmediately is after Init(), otherwise it calls SetValue once

                _splitQuerySetting = _submenu.AddBool("Search Each Word Individually",
                                                      "Split up the search query into words and searches the song details for those words individually. " +
                                                      "A song will only appear in the results if it contains all the words typed.\n" +
                                                      "<color=#11FF11>'ON' - For when you know some words or names in the song details, but not the specific order.</color>\n" +
                                                      "<color=#11FF11>'OFF' - Useful if you want to search for a particular phrase.</color>");
                _splitQuerySetting.GetValue += () => _splitQueryStagingValue;
                _splitQuerySetting.SetValue += delegate(bool value)
                {
                    _splitQueryStagingValue   = value;
                    _resetButton.interactable = true;
                    _applyButton.interactable = true;
                };
                SetSettingElementPosition(_splitQuerySetting.transform as RectTransform);
                _splitQuerySetting.Init();
                _splitQuerySetting.applyImmediately = true;

                float[] songFieldsValues = new float[3]
                {
                    (float)SearchableSongFields.All, (float)SearchableSongFields.TitleAndAuthor, (float)SearchableSongFields.TitleOnly
                };
                _songFieldsSetting = _submenu.AddList("Song Fields to Search", songFieldsValues,
                                                      "A query will only search in these particular details of a song.\n" +
                                                      "<color=#11FF11>Can get relevant results quicker if you never search for song artist or beatmap creator.</color>\n" +
                                                      "Options - 'All', 'Title and Author', 'Title Only'");
                _songFieldsSetting.GetTextForValue += delegate(float value)
                {
                    switch (value)
                    {
                    case (float)SearchableSongFields.All:
                        return("All");

                    case (float)SearchableSongFields.TitleAndAuthor:
                        return("<size=80%>Title and Author</size>");

                    //case (float)SearchableSongFields.TitleOnly:
                    default:
                        return("Title Only");
                    }
                };
                _songFieldsSetting.GetValue += () => (float)_songFieldsStagingValue;
                _songFieldsSetting.SetValue += delegate(float value)
                {
                    _songFieldsStagingValue   = (SearchableSongFields)value;
                    _resetButton.interactable = true;
                    _applyButton.interactable = true;
                };
                SetSettingElementPosition(_songFieldsSetting.transform as RectTransform);
                _songFieldsSetting.Init();
                _songFieldsSetting.applyImmediately = true;

                _stripSymbolsSetting = _submenu.AddBool("Strip Symbols from Song Details",
                                                        "Removes symbols from song title, subtitle, artist, etc. fields when performing search.\n" +
                                                        "<color=#11FF11>Can be useful when searching for song remixes and titles with apostrophes, quotations, or hyphens.</color>");
                _stripSymbolsSetting.GetValue += () => _stripSymbolsStagingValue;
                _stripSymbolsSetting.SetValue += delegate(bool value)
                {
                    _stripSymbolsStagingValue = value;
                    _resetButton.interactable = true;
                    _applyButton.interactable = true;
                };
                SetSettingElementPosition(_stripSymbolsSetting.transform as RectTransform);
                _stripSymbolsSetting.Init();
                _stripSymbolsSetting.applyImmediately = true;

                _compactModeSetting = _submenu.AddBool("Use Compact Mode",
                                                       "Removes the keyboard on the right screen, replacing it with a smaller keyboard on the center screen.");
                _compactModeSetting.GetValue += () => _compactModeStagingValue;
                _compactModeSetting.SetValue += delegate(bool value)
                {
                    _compactModeStagingValue  = value;
                    _resetButton.interactable = true;
                    _applyButton.interactable = true;
                };
                SetSettingElementPosition(_compactModeSetting.transform as RectTransform);
                _compactModeSetting.Init();
                _compactModeSetting.applyImmediately = true;

                _defaultButton = BeatSaberUI.CreateUIButton(this.rectTransform, "CancelButton",
                                                            new Vector2(-37f, -32f), new Vector2(36f, 10f),
                                                            DefaultButtonPressed, "Use Defaults");
                _defaultButton.ToggleWordWrapping(false);
                _resetButton = BeatSaberUI.CreateUIButton(this.rectTransform, "CancelButton",
                                                          new Vector2(16f, -32f), new Vector2(24f, 9f),
                                                          ResetButtonPressed, "Reset");
                _resetButton.ToggleWordWrapping(false);
                _applyButton = BeatSaberUI.CreateUIButton(this.rectTransform, "CancelButton",
                                                          new Vector2(43f, -32f), new Vector2(24f, 9f),
                                                          ApplyButtonPressed, "Apply");
                _applyButton.ToggleWordWrapping(false);
            }
            else
            {
                // force show current value in config
                RefreshUI();
            }

            _resetButton.interactable = false;
            _applyButton.interactable = false;
        }
        /// <summary>
        /// Check whether a song contains the all the words in the query.
        /// </summary>
        /// <param name="level">Song to check.</param>
        /// <param name="stripSymbols">Whether to strip the symbols of each word before checking.</param>
        /// <param name="combineSingleLetterSequences">Whether to combine single letter 'word' sequences.</param>
        /// <param name="songFields">Song fields to check.</param>
        /// <param name="queryWords">List of words (or a phrase) to query for.</param>
        /// <returns>True if the song contains all the words in the query, otherwise false.</returns>
        private bool CheckSong(IPreviewBeatmapLevel level, bool stripSymbols, bool combineSingleLetterSequences, SearchableSongFields songFields, IEnumerable <string> queryWords)
        {
            string songName;

            if (combineSingleLetterSequences)
            {
                // combine contiguous single letter 'word' sequences in the title each into one word
                // should only done when Split Words option is enabled
                StringBuilder songNameSB        = new StringBuilder(level.songName.Length);
                StringBuilder constructedWordSB = new StringBuilder(level.songName.Length);

                foreach (string word in level.songName.Split(SplitCharacters, StringSplitOptions.RemoveEmptyEntries))
                {
                    if (word.Length > 1 || !char.IsLetterOrDigit(word[0]))
                    {
                        // multi-letter word or special character
                        if (constructedWordSB.Length > 0)
                        {
                            if (songNameSB.Length > 0)
                            {
                                songNameSB.Append(' ');
                            }

                            songNameSB.Append(constructedWordSB.ToString());
                            constructedWordSB.Clear();
                        }

                        if (songNameSB.Length > 0)
                        {
                            songNameSB.Append(' ');
                        }

                        songNameSB.Append(word);
                    }
                    else
                    {
                        // single letter 'word'
                        constructedWordSB.Append(word);
                    }
                }

                // add last constructed word if it exists
                if (constructedWordSB.Length > 0)
                {
                    if (songNameSB.Length > 0)
                    {
                        songNameSB.Append(' ');
                    }

                    songNameSB.Append(constructedWordSB.ToString());
                }

                songName = songNameSB.ToString();
            }
            else
            {
                songName = level.songName;
            }

            string fields;

            if (songFields == SearchableSongFields.All)
            {
                fields = $"{songName} {level.songSubName} {level.levelAuthorName} {level.songAuthorName}".ToLower();
            }
            else if (songFields == SearchableSongFields.TitleOnly)
            {
                fields = $"{songName} {level.songSubName}".ToLower();
            }
            //else if (songFields == SearchableSongFields.TitleAndAuthor)
            else
            {
                fields = $"{songName} {level.songSubName} {level.songAuthorName}".ToLower();
            }

            if (stripSymbols)
            {
                fields = RemoveSymbolsRegex.Replace(fields, string.Empty);
            }

            foreach (var word in queryWords)
            {
                if (!fields.Contains(word))
                {
                    return(false);
                }
            }

            return(true);
        }
        private IEnumerator _SearchSongs(string searchQuery)
        {
            int index = 0;

            string[]             queryWords;
            bool                 stripSymbols = PluginConfig.StripSymbols;
            bool                 splitWords   = PluginConfig.SplitQueryByWords;
            SearchableSongFields songFields   = PluginConfig.SongFieldsToSearch;

            if (stripSymbols)
            {
                searchQuery = RemoveSymbolsRegex.Replace(searchQuery.ToLower(), string.Empty);
            }
            else
            {
                searchQuery = searchQuery.ToLower();
            }

            if (splitWords)
            {
                queryWords = searchQuery.Split(SplitCharacters, StringSplitOptions.RemoveEmptyEntries);
            }
            else
            {
                queryWords = new string[] { searchQuery }
            };

            while (index < _searchSpace.Count)
            {
                // limit the number of songs to evaluate so users with large song libraries don't pause on every key press
                for (int count = 0; count < MaxSearchInOneFrame && index < _searchSpace.Count; ++count)
                {
                    IPreviewBeatmapLevel level = _searchSpace[index];
                    string songName;

                    if (splitWords)
                    {
                        // combine contiguous single letter 'word' sequences in the title each into one word
                        // only done when Split Words option is enabled
                        StringBuilder songNameSB        = new StringBuilder(level.songName.Length);
                        StringBuilder constructedWordSB = new StringBuilder(level.songName.Length);

                        foreach (string word in level.songName.Split(SplitCharacters, StringSplitOptions.RemoveEmptyEntries))
                        {
                            if (word.Length > 1 || !char.IsLetterOrDigit(word[0]))
                            {
                                // multi-letter word or special character
                                if (constructedWordSB.Length > 0)
                                {
                                    if (songNameSB.Length > 0)
                                    {
                                        songNameSB.Append(' ');
                                    }

                                    songNameSB.Append(constructedWordSB.ToString());
                                    constructedWordSB.Clear();
                                }

                                if (songNameSB.Length > 0)
                                {
                                    songNameSB.Append(' ');
                                }

                                songNameSB.Append(word);
                            }
                            else
                            {
                                // single letter 'word'
                                constructedWordSB.Append(word);
                            }
                        }

                        // add last constructed word if it exists
                        if (constructedWordSB.Length > 0)
                        {
                            if (songNameSB.Length > 0)
                            {
                                songNameSB.Append(' ');
                            }

                            songNameSB.Append(constructedWordSB.ToString());
                        }

                        songName = songNameSB.ToString();
                    }
                    else
                    {
                        songName = level.songName;
                    }

                    string fields;
                    if (songFields == SearchableSongFields.All)
                    {
                        fields = $"{songName} {level.songSubName} {level.levelAuthorName} {level.songAuthorName}".ToLower();
                    }
                    else if (songFields == SearchableSongFields.TitleOnly)
                    {
                        fields = $"{songName} {level.songSubName}".ToLower();
                    }
                    //else if (songFields == SearchableSongFields.TitleAndAuthor)
                    else
                    {
                        fields = $"{songName} {level.songSubName} {level.songAuthorName}".ToLower();
                    }

                    if (stripSymbols)
                    {
                        fields = RemoveSymbolsRegex.Replace(fields, string.Empty);
                    }

                    bool remove = false;
                    foreach (var word in queryWords)
                    {
                        if (!fields.Contains(word))
                        {
                            remove = true;
                            break;
                        }
                    }
                    if (remove)
                    {
                        _searchSpace.RemoveAt(index);
                    }
                    else
                    {
                        ++index;
                    }
                }
                yield return(null);
            }

            _searchCompletedAction?.Invoke(_searchSpace.ToArray());
            _searchCoroutine = null;
        }
    }
Ejemplo n.º 7
0
        private IEnumerator _SearchSongs(string searchQuery)
        {
            int index = 0;

            string[]             queryWords;
            bool                 stripSymbols = PluginConfig.StripSymbols;
            bool                 splitWords   = PluginConfig.SplitQueryByWords;
            SearchableSongFields songFields   = PluginConfig.SongFieldsToSearch;

            if (stripSymbols)
            {
                searchQuery = RemoveSymbolsRegex.Replace(searchQuery.ToLower(), string.Empty);
            }
            else
            {
                searchQuery = searchQuery.ToLower();
            }

            if (splitWords)
            {
                queryWords = searchQuery.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
            }
            else
            {
                queryWords = new string[] { searchQuery }
            };

            while (index < _searchSpace.Count)
            {
                // limit the number of songs to evaluate so users with large song libraries don't pause on every key press
                for (int count = 0; count < MaxSearchInOneFrame && index < _searchSpace.Count; ++count)
                {
                    IPreviewBeatmapLevel level = _searchSpace[index];
                    string fields;

                    if (songFields == SearchableSongFields.All)
                    {
                        fields = $"{level.songName} {level.songSubName} {level.levelAuthorName} {level.songAuthorName}".ToLower();
                    }
                    else if (songFields == SearchableSongFields.TitleOnly)
                    {
                        fields = $"{level.songName} {level.songSubName}".ToLower();
                    }
                    //else if (songFields == SearchableSongFields.TitleAndAuthor)
                    else
                    {
                        fields = $"{level.songName} {level.songSubName} {level.songAuthorName}".ToLower();
                    }

                    if (stripSymbols)
                    {
                        fields = RemoveSymbolsRegex.Replace(fields, string.Empty);
                    }

                    bool remove = false;
                    foreach (var word in queryWords)
                    {
                        if (!fields.Contains(word))
                        {
                            remove = true;
                            break;
                        }
                    }
                    if (remove)
                    {
                        _searchSpace.RemoveAt(index);
                    }
                    else
                    {
                        ++index;
                    }
                }
                yield return(null);
            }

            _searchCompletedAction?.Invoke(_searchSpace.ToArray());
            _searchCoroutine = null;
        }
    }