Commit Graph

50 Commits

Author SHA1 Message Date
Deluan Quintão
54de0dbc52 feat(server): implement FTS5-based full-text search (#5079)
* build: add sqlite_fts5 build tag to enable FTS5 support

* feat: add SearchBackend config option (default: fts)

* feat: add buildFTS5Query for safe FTS5 query preprocessing

* feat: add FTS5 search backend with config toggle, refactor legacy search

- Add searchExprFunc type and getSearchExpr() for backend selection
- Rename fullTextExpr to legacySearchExpr
- Add ftsSearchExpr using FTS5 MATCH subquery
- Update fullTextFilter in sql_restful.go to use configured backend

* feat: add FTS5 migration with virtual tables, triggers, and search_participants

Creates FTS5 virtual tables for media_file, album, and artist with
unicode61 tokenizer and diacritic folding. Adds search_participants
column, populates from JSON, and sets up INSERT/UPDATE/DELETE triggers.

* feat: populate search_participants in PostMapArgs for FTS5 indexing

* test: add FTS5 search integration tests

* fix: exclude FTS5 virtual tables from e2e DB restore

The restoreDB function iterates all tables in sqlite_master and
runs DELETE + INSERT to reset state. FTS5 contentless virtual tables
cannot be directly deleted from. Since triggers handle FTS5 sync
automatically, simply skip tables matching *_fts and *_fts_* patterns.

* build: add compile-time guard for sqlite_fts5 build tag

Same pattern as netgo: compilation fails with a clear error if
the sqlite_fts5 build tag is missing.

* build: add sqlite_fts5 tag to reflex dev server config

* build: extract GO_BUILD_TAGS variable in Makefile to avoid duplication

* fix: strip leading * from FTS5 queries to prevent "unknown special query" error

* feat: auto-append prefix wildcard to FTS5 search tokens for broader matching

Every plain search token now gets a trailing * appended (e.g., "love" becomes
"love*"), so searching for "love" also matches "lovelace", "lovely", etc.
Quoted phrases are preserved as exact matches without wildcards. Results are
ordered alphabetically by name/title, so shorter exact matches naturally
appear first.

* fix: clarify comments about FTS5 operator neutralization

The comments said "strip" but the code lowercases operators to
neutralize them (FTS5 operators are case-sensitive). Updated comments
to accurately describe the behavior.

* fix: use fmt.Sprintf for FTS5 phrase placeholders

The previous encoding used rune('0'+index) which silently breaks with
10+ quoted phrases. Use fmt.Sprintf for arbitrary index support.

* fix: validate and normalize SearchBackend config option

Normalize the value to lowercase and fall back to "fts" with a log
warning for unrecognized values. This prevents silent misconfiguration
from typos like "FTS", "Legacy", or "fts5".

* refactor: improve documentation for build tags and FTS5 requirements

Signed-off-by: Deluan <deluan@navidrome.org>

* refactor: convert FTS5 query and search backend normalization tests to DescribeTable format

Signed-off-by: Deluan <deluan@navidrome.org>

* fix: add sqlite_fts5 build tag to golangci configuration

Signed-off-by: Deluan <deluan@navidrome.org>

* feat: add UISearchDebounceMs configuration option and update related components

Signed-off-by: Deluan <deluan@navidrome.org>

* fix: fall back to legacy search when SearchFullString is enabled

FTS5 is token-based and cannot match substrings within words, so
getSearchExpr now returns legacySearchExpr when SearchFullString
is true, regardless of SearchBackend setting.

* fix: add sqlite_fts5 build tag to CI pipeline and Dockerfile

* fix: add WHEN clauses to FTS5 AFTER UPDATE triggers

Added WHEN clauses to the media_file_fts_au, album_fts_au, and
artist_fts_au triggers so they only fire when FTS-indexed columns
actually change. Previously, every row update (e.g., play count, rating,
starred status) triggered an unnecessary delete+insert cycle in the FTS
shadow tables. The WHEN clauses use IS NOT for NULL-safe comparison of
each indexed column, avoiding FTS index churn for non-indexed updates.

* feat: add SearchBackend configuration option to data and insights components

Signed-off-by: Deluan <deluan@navidrome.org>

* fix: enhance input sanitization for FTS5 by stripping additional punctuation and special characters

Signed-off-by: Deluan <deluan@navidrome.org>

* feat: add search_normalized column for punctuated name search (R.E.M., AC/DC)

Add index-time normalization and query-time single-letter collapsing to
fix FTS5 search for punctuated names. A new search_normalized column
stores concatenated forms of punctuated words (e.g., "R.E.M." → "REM",
"AC/DC" → "ACDC") and is indexed in FTS5 tables. At query time, runs of
consecutive single letters (from dot-stripping) are collapsed into OR
expressions like ("R E M" OR REM*) to match both the original tokens and
the normalized form. This enables searching by "R.E.M.", "REM", "AC/DC",
"ACDC", "A-ha", or "Aha" and finding the correct results.

* refactor: simplify isSingleUnicodeLetter to avoid []rune allocation

Use utf8.DecodeRuneInString to check for a single Unicode letter
instead of converting the entire string to a []rune slice.

* feat: define ftsSearchColumns for flexible FTS5 search column inclusion

Signed-off-by: Deluan <deluan@navidrome.org>

* feat: update collapseSingleLetterRuns to return quoted phrases for abbreviations

Signed-off-by: Deluan <deluan@navidrome.org>

* feat: implement extractPunctuatedWords to handle artist/album names with embedded punctuation

Signed-off-by: Deluan <deluan@navidrome.org>

* feat: implement extractPunctuatedWords to handle artist/album names with embedded punctuation

Signed-off-by: Deluan <deluan@navidrome.org>

* refactor: punctuated word handling to improve processing of artist/album names

Signed-off-by: Deluan <deluan@navidrome.org>

* feat: add CJK support for search queries with LIKE filters

Signed-off-by: Deluan <deluan@navidrome.org>

* feat: enhance FTS5 search by adding album version support and CJK handling

Signed-off-by: Deluan <deluan@navidrome.org>

* refactor: search configuration to use structured options

Signed-off-by: Deluan <deluan@navidrome.org>

* feat: enhance search functionality to support punctuation-only queries and update related tests

Signed-off-by: Deluan <deluan@navidrome.org>

---------

Signed-off-by: Deluan <deluan@navidrome.org>
2026-02-21 17:52:42 -05:00
Deluan Quintão
69e2a6d620 build(netgo): make sure the project is always compiled with netgo build tag (#3428)
* build(netgo): make sure the project is always compiled with `netgo` build tag

* docs(netgo): better comments
2024-10-26 13:28:23 -04:00
Deluan
c380139606 Fix lint 2023-03-15 13:10:14 -04:00
Deluan
63fbccf5a9 Enable memory profiling 2023-03-15 12:43:25 -04:00
Deluan
10cd3152ba Remove misplaced import 2022-11-27 22:01:07 -05:00
Deluan
950b5dc1ce Remove math/rand and only use crypto/rand 2022-11-27 21:53:13 -05:00
Deluan
3972616585 New Criteria API 2021-10-23 20:25:28 -04:00
Yash Jipkate
af210c8903 Add Native Sharing REST API (#1150)
* Initial draft - UNTESTED

* changes to Save() and Update()

* apply col filter and limit nanoid

* remove columns to not update
2021-06-08 15:44:30 -04:00
Deluan
6ee45a9ccc Move project to Navidrome GitHub organization 2021-02-06 21:46:35 -05:00
Deluan
58a52c31c2 Turn off memory profiling, saving a couple of megabytes 2021-02-01 16:30:06 -05:00
Deluan
5021c0fd0c Replace multiconfig with cobra+viper 2020-07-02 17:53:51 -04:00
Deluan
75cd21da1f Add BaseURL configuration (fixes #103) 2020-04-03 19:05:38 -04:00
Deluan
15606770ca chore: removed non-working config flag 2020-03-22 01:13:55 -04:00
Deluan
a6b0c57ce0 feat: add a proper caching system to the transcoding functionality 2020-02-20 19:25:39 -05:00
Deluan
d1f8d39866 refactor: move banner to consts, closer to version 2020-02-04 10:14:53 -05:00
Deluan
7e65bb8f20 refactor: better integration between db and persistence packages
Will address support for different DBs in the future (+1 squashed commit)
Squashed commits:
[a014757] refactor: better integration between `db` and `persistence` packages
2020-02-01 17:23:03 -05:00
Deluan
71c1844bca refactor: new persistence, more SQL, less ORM 2020-02-01 17:23:03 -05:00
Deluan
828dc8f0f4 feat: add -help, simplified config loading 2020-01-26 16:21:07 -05:00
Deluan
8756f55650 Add git info to version 2020-01-25 11:06:04 -05:00
Deluan
5b84188f58 Add banner.txt as a static file 2020-01-24 23:45:31 -05:00
Deluan
bff6f3a4bd Rename env vars prefix to ND_ 2020-01-24 01:29:31 -05:00
Deluan
bee55c04c8 Rename project to Navidrome 2020-01-23 19:44:08 -05:00
Deluan
28cd3ec3e4 Fix startup order, setting LogLevel 2020-01-20 17:35:04 -05:00
Deluan
3a03284c59 Add routing for basic web ui 2020-01-19 19:35:03 -05:00
Deluan
c995766c45 Add startup banner 2020-01-13 18:24:54 -05:00
Deluan
536244bc44 Removed LedisDB persistence layer. May reimplement in the future (not likely thou) 2020-01-13 16:37:24 -05:00
Deluan
4b1c909a4d Make persistence provider pluggable at runtime 2020-01-11 15:27:32 -05:00
Deluan
48b465f2fb Simplify API routes mounting 2020-01-11 15:27:32 -05:00
Deluan
408030eb6c Refactor App to use DI 2020-01-11 15:27:32 -05:00
Deluan
30ebbc1fa1 Move API dependency injection to main package, opening the possibility to switch persistence without code changes 2020-01-11 15:27:32 -05:00
Deluan
23e38ec82f Removed (almost) all remaining init() 2020-01-09 22:44:45 -05:00
Deluan
5d2a7b1db1 Removed MainController 2020-01-09 22:44:45 -05:00
Deluan
e8a8313b43 Removed inject lib, only use wire for DI 2020-01-09 22:44:45 -05:00
Deluan
3af9972b41 Remove Beego tasks, make Importer available through DI 2020-01-09 22:44:45 -05:00
Deluan
79701caca3 Removed Beego routing/controllers, converted to Chi.
Also introduced Wire for dependency injection
2020-01-09 22:44:45 -05:00
Deluan
c417a00e62 Renamed project to CloudSonic 2017-04-01 09:47:14 -04:00
Deluan
09f98508a4 Removed duplicated import 2016-11-09 09:49:06 -05:00
Deluan
c2b1f9782b New configuration system 2016-03-30 00:05:57 -04:00
Deluan
9049d97820 Moving code away from conf package.
This is necessary, as the conf package will hold only configuration, and cannot have dependencies on other packages
2016-03-29 18:27:14 -04:00
Deluan
cad65f517c Polishing 2016-03-15 13:17:51 -04:00
Deluan
4b09eeccc2 Configuring "prod" 2016-03-11 21:14:32 -05:00
Deluan
12b0350d3e Task for continuously check for iTunes Library updates 2016-03-11 18:37:37 -05:00
Deluan
46e7627fd3 Optimized import, only updating changed data and purging old data 2016-03-08 14:19:07 -05:00
Deluan
4843ccb46c go fmt 2016-03-02 13:18:39 -05:00
Deluan
02a5fec6b6 Show Query params for invalid URL's 2016-03-01 20:42:20 -05:00
Deluan
4efb8ab031 Moved router to conf package 2016-03-01 09:23:40 -05:00
Deluan
375fd30045 Fixed AlbumId generation. Some code cleanup 2016-03-01 09:17:28 -05:00
Deluan
a25c09111b Removed doc code. For the API documentation see Subsonic site 2016-02-24 19:22:01 -05:00
Deluan
9a55fa1c64 Experiments with bleve, repositories and parsing itunes 2016-02-24 15:30:28 -05:00
Deluan
5d6fd4ee6b Initial project skeleton 2016-02-23 18:41:35 -05:00