update
Some checks failed
Pipeline: Test, Lint, Build / Get version info (push) Has been cancelled
Pipeline: Test, Lint, Build / Lint Go code (push) Has been cancelled
Pipeline: Test, Lint, Build / Test Go code (push) Has been cancelled
Pipeline: Test, Lint, Build / Test JS code (push) Has been cancelled
Pipeline: Test, Lint, Build / Lint i18n files (push) Has been cancelled
Pipeline: Test, Lint, Build / Check Docker configuration (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (darwin/amd64) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (darwin/arm64) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/386) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/amd64) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/arm/v5) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/arm/v6) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/arm/v7) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/arm64) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (windows/386) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (windows/amd64) (push) Has been cancelled
Pipeline: Test, Lint, Build / Push to GHCR (push) Has been cancelled
Pipeline: Test, Lint, Build / Push to Docker Hub (push) Has been cancelled
Pipeline: Test, Lint, Build / Cleanup digest artifacts (push) Has been cancelled
Pipeline: Test, Lint, Build / Build Windows installers (push) Has been cancelled
Pipeline: Test, Lint, Build / Package/Release (push) Has been cancelled
Pipeline: Test, Lint, Build / Upload Linux PKG (push) Has been cancelled
Close stale issues and PRs / stale (push) Has been cancelled
POEditor import / update-translations (push) Has been cancelled

This commit is contained in:
2025-12-08 16:16:23 +01:00
commit c251f174ed
1349 changed files with 194301 additions and 0 deletions

191
persistence/meilisearch.go Normal file
View File

@@ -0,0 +1,191 @@
package persistence
import (
"encoding/json"
"fmt"
"github.com/meilisearch/meilisearch-go"
"github.com/navidrome/navidrome/conf"
"github.com/navidrome/navidrome/log"
"github.com/navidrome/navidrome/model"
)
type MeilisearchService struct {
client meilisearch.ServiceManager
}
func NewMeilisearchService() *MeilisearchService {
if !conf.Server.Meilisearch.Enabled {
return nil
}
client := meilisearch.New(conf.Server.Meilisearch.Host, meilisearch.WithAPIKey(conf.Server.Meilisearch.ApiKey))
return &MeilisearchService{client: client}
}
func (s *MeilisearchService) IndexMediaFile(mf *model.MediaFile) {
if s == nil {
return
}
s.IndexMediaFiles([]model.MediaFile{*mf})
}
func (s *MeilisearchService) IndexMediaFiles(mfs []model.MediaFile) {
if s == nil || len(mfs) == 0 {
return
}
docs := make([]map[string]interface{}, len(mfs))
for i, mf := range mfs {
docs[i] = map[string]interface{}{
"id": mf.ID,
"title": mf.Title,
"artist": mf.Artist,
"album": mf.Album,
"albumArtist": mf.AlbumArtist,
"path": mf.Path,
"year": mf.Year,
"genre": mf.Genre,
}
}
_, err := s.client.Index("mediafiles").AddDocuments(docs, nil)
if err != nil {
log.Error("Error indexing mediafiles", "count", len(mfs), err)
}
}
func (s *MeilisearchService) DeleteMediaFile(id string) {
if s == nil {
return
}
_, err := s.client.Index("mediafiles").DeleteDocument(id)
if err != nil {
log.Error("Error deleting mediafile from index", "id", id, err)
}
}
func (s *MeilisearchService) DeleteMediaFiles(ids []string) {
if s == nil {
return
}
_, err := s.client.Index("mediafiles").DeleteDocuments(ids)
if err != nil {
log.Error("Error deleting mediafiles from index", "ids", ids, err)
}
}
func (s *MeilisearchService) IndexAlbum(album *model.Album) {
if s == nil {
return
}
s.IndexAlbums([]model.Album{*album})
}
func (s *MeilisearchService) IndexAlbums(albums []model.Album) {
if s == nil || len(albums) == 0 {
return
}
docs := make([]map[string]interface{}, len(albums))
for i, album := range albums {
docs[i] = map[string]interface{}{
"id": album.ID,
"name": album.Name,
"artist": album.AlbumArtist,
"albumArtist": album.AlbumArtist,
"year": album.MinYear,
"genre": album.Genre,
}
}
_, err := s.client.Index("albums").AddDocuments(docs, nil)
if err != nil {
log.Error("Error indexing albums", "count", len(albums), err)
}
}
func (s *MeilisearchService) DeleteAlbum(id string) {
if s == nil {
return
}
_, err := s.client.Index("albums").DeleteDocument(id)
if err != nil {
log.Error("Error deleting album from index", "id", id, err)
}
}
func (s *MeilisearchService) DeleteAlbums(ids []string) {
if s == nil {
return
}
_, err := s.client.Index("albums").DeleteDocuments(ids)
if err != nil {
log.Error("Error deleting albums from index", "ids", ids, err)
}
}
func (s *MeilisearchService) IndexArtist(artist *model.Artist) {
if s == nil {
return
}
s.IndexArtists([]model.Artist{*artist})
}
func (s *MeilisearchService) IndexArtists(artists []model.Artist) {
if s == nil || len(artists) == 0 {
return
}
docs := make([]map[string]interface{}, len(artists))
for i, artist := range artists {
docs[i] = map[string]interface{}{
"id": artist.ID,
"name": artist.Name,
}
}
_, err := s.client.Index("artists").AddDocuments(docs, nil)
if err != nil {
log.Error("Error indexing artists", "count", len(artists), err)
}
}
func (s *MeilisearchService) DeleteArtist(id string) {
if s == nil {
return
}
_, err := s.client.Index("artists").DeleteDocument(id)
if err != nil {
log.Error("Error deleting artist from index", "id", id, err)
}
}
func (s *MeilisearchService) DeleteArtists(ids []string) {
if s == nil {
return
}
_, err := s.client.Index("artists").DeleteDocuments(ids)
if err != nil {
log.Error("Error deleting artists from index", "ids", ids, err)
}
}
func (s *MeilisearchService) Search(indexName string, query string, offset, limit int) ([]string, error) {
if s == nil {
return nil, fmt.Errorf("meilisearch is not enabled")
}
searchRes, err := s.client.Index(indexName).Search(query, &meilisearch.SearchRequest{
Offset: int64(offset),
Limit: int64(limit),
})
if err != nil {
return nil, err
}
var ids []string
for _, hit := range searchRes.Hits {
if id, ok := hit["id"]; ok {
var idStr string
if err := json.Unmarshal(id, &idStr); err == nil {
ids = append(ids, idStr)
}
}
}
// Handle case where id might be non-string if necessary, though simpler is better for now.
// Meilisearch returns map[string]interface{}
return ids, nil
}