Rename MediaFolder to Library
This commit is contained in:
+1
-1
@@ -20,10 +20,10 @@ type ResourceRepository interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type DataStore interface {
|
type DataStore interface {
|
||||||
|
Library(ctx context.Context) LibraryRepository
|
||||||
Album(ctx context.Context) AlbumRepository
|
Album(ctx context.Context) AlbumRepository
|
||||||
Artist(ctx context.Context) ArtistRepository
|
Artist(ctx context.Context) ArtistRepository
|
||||||
MediaFile(ctx context.Context) MediaFileRepository
|
MediaFile(ctx context.Context) MediaFileRepository
|
||||||
MediaFolder(ctx context.Context) MediaFolderRepository
|
|
||||||
Genre(ctx context.Context) GenreRepository
|
Genre(ctx context.Context) GenreRepository
|
||||||
Playlist(ctx context.Context) PlaylistRepository
|
Playlist(ctx context.Context) PlaylistRepository
|
||||||
PlayQueue(ctx context.Context) PlayQueueRepository
|
PlayQueue(ctx context.Context) PlayQueueRepository
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package model
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io/fs"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Library struct {
|
||||||
|
ID int32
|
||||||
|
Name string
|
||||||
|
Path string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f Library) FS() fs.FS {
|
||||||
|
return os.DirFS(f.Path)
|
||||||
|
}
|
||||||
|
|
||||||
|
type Libraries []Library
|
||||||
|
|
||||||
|
type LibraryRepository interface {
|
||||||
|
Get(id int32) (*Library, error)
|
||||||
|
GetAll() (Libraries, error)
|
||||||
|
}
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
package model
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io/fs"
|
|
||||||
"os"
|
|
||||||
)
|
|
||||||
|
|
||||||
type MediaFolder struct {
|
|
||||||
ID int32
|
|
||||||
Name string
|
|
||||||
Path string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f MediaFolder) FS() fs.FS {
|
|
||||||
return os.DirFS(f.Path)
|
|
||||||
}
|
|
||||||
|
|
||||||
type MediaFolders []MediaFolder
|
|
||||||
|
|
||||||
type MediaFolderRepository interface {
|
|
||||||
Get(id int32) (*MediaFolder, error)
|
|
||||||
GetAll() (MediaFolders, error)
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
package persistence
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/navidrome/navidrome/conf"
|
||||||
|
"github.com/navidrome/navidrome/model"
|
||||||
|
"github.com/pocketbase/dbx"
|
||||||
|
)
|
||||||
|
|
||||||
|
type libraryRepository struct {
|
||||||
|
ctx context.Context
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewLibraryRepository(ctx context.Context, _ dbx.Builder) model.LibraryRepository {
|
||||||
|
return &libraryRepository{ctx}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *libraryRepository) Get(int32) (*model.Library, error) {
|
||||||
|
library := hardCoded()
|
||||||
|
return &library, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*libraryRepository) GetAll() (model.Libraries, error) {
|
||||||
|
return model.Libraries{hardCoded()}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func hardCoded() model.Library {
|
||||||
|
library := model.Library{ID: 0, Path: conf.Server.MusicFolder}
|
||||||
|
library.Name = "Music Library"
|
||||||
|
return library
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ model.LibraryRepository = (*libraryRepository)(nil)
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
package persistence
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/navidrome/navidrome/conf"
|
|
||||||
"github.com/navidrome/navidrome/model"
|
|
||||||
"github.com/pocketbase/dbx"
|
|
||||||
)
|
|
||||||
|
|
||||||
type mediaFolderRepository struct {
|
|
||||||
ctx context.Context
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewMediaFolderRepository(ctx context.Context, _ dbx.Builder) model.MediaFolderRepository {
|
|
||||||
return &mediaFolderRepository{ctx}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *mediaFolderRepository) Get(id int32) (*model.MediaFolder, error) {
|
|
||||||
mediaFolder := hardCoded()
|
|
||||||
return &mediaFolder, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*mediaFolderRepository) GetAll() (model.MediaFolders, error) {
|
|
||||||
mediaFolder := hardCoded()
|
|
||||||
result := make(model.MediaFolders, 1)
|
|
||||||
result[0] = mediaFolder
|
|
||||||
return result, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func hardCoded() model.MediaFolder {
|
|
||||||
mediaFolder := model.MediaFolder{ID: 0, Path: conf.Server.MusicFolder}
|
|
||||||
mediaFolder.Name = "Music Library"
|
|
||||||
return mediaFolder
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ model.MediaFolderRepository = (*mediaFolderRepository)(nil)
|
|
||||||
@@ -31,8 +31,8 @@ func (s *SQLStore) MediaFile(ctx context.Context) model.MediaFileRepository {
|
|||||||
return NewMediaFileRepository(ctx, s.getDBXBuilder())
|
return NewMediaFileRepository(ctx, s.getDBXBuilder())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SQLStore) MediaFolder(ctx context.Context) model.MediaFolderRepository {
|
func (s *SQLStore) Library(ctx context.Context) model.LibraryRepository {
|
||||||
return NewMediaFolderRepository(ctx, s.getDBXBuilder())
|
return NewLibraryRepository(ctx, s.getDBXBuilder())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SQLStore) Genre(ctx context.Context) model.GenreRepository {
|
func (s *SQLStore) Genre(ctx context.Context) model.GenreRepository {
|
||||||
|
|||||||
+23
-22
@@ -18,11 +18,11 @@ import (
|
|||||||
|
|
||||||
type Scanner interface {
|
type Scanner interface {
|
||||||
RescanAll(ctx context.Context, fullRescan bool) error
|
RescanAll(ctx context.Context, fullRescan bool) error
|
||||||
Status(mediaFolder string) (*StatusInfo, error)
|
Status(library string) (*StatusInfo, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type StatusInfo struct {
|
type StatusInfo struct {
|
||||||
MediaFolder string
|
Library string
|
||||||
Scanning bool
|
Scanning bool
|
||||||
LastScan time.Time
|
LastScan time.Time
|
||||||
Count uint32
|
Count uint32
|
||||||
@@ -74,47 +74,47 @@ func GetInstance(ds model.DataStore, playlists core.Playlists, cacheWarmer artwo
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *scanner) rescan(ctx context.Context, mediaFolder string, fullRescan bool) error {
|
func (s *scanner) rescan(ctx context.Context, library string, fullRescan bool) error {
|
||||||
folderScanner := s.folders[mediaFolder]
|
folderScanner := s.folders[library]
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
|
|
||||||
s.setStatusStart(mediaFolder)
|
s.setStatusStart(library)
|
||||||
defer s.setStatusEnd(mediaFolder, start)
|
defer s.setStatusEnd(library, start)
|
||||||
|
|
||||||
lastModifiedSince := time.Time{}
|
lastModifiedSince := time.Time{}
|
||||||
if !fullRescan {
|
if !fullRescan {
|
||||||
lastModifiedSince = s.getLastModifiedSince(ctx, mediaFolder)
|
lastModifiedSince = s.getLastModifiedSince(ctx, library)
|
||||||
log.Debug("Scanning folder", "folder", mediaFolder, "lastModifiedSince", lastModifiedSince)
|
log.Debug("Scanning folder", "folder", library, "lastModifiedSince", lastModifiedSince)
|
||||||
} else {
|
} else {
|
||||||
log.Debug("Scanning folder (full scan)", "folder", mediaFolder)
|
log.Debug("Scanning folder (full scan)", "folder", library)
|
||||||
}
|
}
|
||||||
|
|
||||||
progress, cancel := s.startProgressTracker(mediaFolder)
|
progress, cancel := s.startProgressTracker(library)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
changeCount, err := folderScanner.Scan(ctx, lastModifiedSince, progress)
|
changeCount, err := folderScanner.Scan(ctx, lastModifiedSince, progress)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Error importing MediaFolder", "folder", mediaFolder, err)
|
log.Error("Error scanning Library", "folder", library, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if changeCount > 0 {
|
if changeCount > 0 {
|
||||||
log.Debug(ctx, "Detected changes in the music folder. Sending refresh event",
|
log.Debug(ctx, "Detected changes in the music folder. Sending refresh event",
|
||||||
"folder", mediaFolder, "changeCount", changeCount)
|
"folder", library, "changeCount", changeCount)
|
||||||
// Don't use real context, forcing a refresh in all open windows, including the one that triggered the scan
|
// Don't use real context, forcing a refresh in all open windows, including the one that triggered the scan
|
||||||
s.broker.SendMessage(context.Background(), &events.RefreshResource{})
|
s.broker.SendMessage(context.Background(), &events.RefreshResource{})
|
||||||
}
|
}
|
||||||
|
|
||||||
s.updateLastModifiedSince(mediaFolder, start)
|
s.updateLastModifiedSince(library, start)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *scanner) startProgressTracker(mediaFolder string) (chan uint32, context.CancelFunc) {
|
func (s *scanner) startProgressTracker(library string) (chan uint32, context.CancelFunc) {
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
progress := make(chan uint32, 100)
|
progress := make(chan uint32, 100)
|
||||||
go func() {
|
go func() {
|
||||||
s.broker.SendMessage(ctx, &events.ScanStatus{Scanning: true, Count: 0, FolderCount: 0})
|
s.broker.SendMessage(ctx, &events.ScanStatus{Scanning: true, Count: 0, FolderCount: 0})
|
||||||
defer func() {
|
defer func() {
|
||||||
if status, ok := s.getStatus(mediaFolder); ok {
|
if status, ok := s.getStatus(library); ok {
|
||||||
s.broker.SendMessage(ctx, &events.ScanStatus{
|
s.broker.SendMessage(ctx, &events.ScanStatus{
|
||||||
Scanning: false,
|
Scanning: false,
|
||||||
Count: int64(status.fileCount),
|
Count: int64(status.fileCount),
|
||||||
@@ -130,7 +130,7 @@ func (s *scanner) startProgressTracker(mediaFolder string) (chan uint32, context
|
|||||||
if count == 0 {
|
if count == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
totalFolders, totalFiles := s.incStatusCounter(mediaFolder, count)
|
totalFolders, totalFiles := s.incStatusCounter(library, count)
|
||||||
s.broker.SendMessage(ctx, &events.ScanStatus{
|
s.broker.SendMessage(ctx, &events.ScanStatus{
|
||||||
Scanning: true,
|
Scanning: true,
|
||||||
Count: int64(totalFiles),
|
Count: int64(totalFiles),
|
||||||
@@ -201,13 +201,14 @@ func (s *scanner) RescanAll(ctx context.Context, fullRescan bool) error {
|
|||||||
core.WriteAfterScanMetrics(ctx, s.ds, true)
|
core.WriteAfterScanMetrics(ctx, s.ds, true)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
func (s *scanner) Status(mediaFolder string) (*StatusInfo, error) {
|
|
||||||
status, ok := s.getStatus(mediaFolder)
|
func (s *scanner) Status(library string) (*StatusInfo, error) {
|
||||||
|
status, ok := s.getStatus(library)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, errors.New("mediaFolder not found")
|
return nil, errors.New("library not found")
|
||||||
}
|
}
|
||||||
return &StatusInfo{
|
return &StatusInfo{
|
||||||
MediaFolder: mediaFolder,
|
Library: library,
|
||||||
Scanning: status.active,
|
Scanning: status.active,
|
||||||
LastScan: status.lastUpdate,
|
LastScan: status.lastUpdate,
|
||||||
Count: status.fileCount,
|
Count: status.fileCount,
|
||||||
@@ -236,7 +237,7 @@ func (s *scanner) updateLastModifiedSince(folder string, t time.Time) {
|
|||||||
|
|
||||||
func (s *scanner) loadFolders() {
|
func (s *scanner) loadFolders() {
|
||||||
ctx := context.TODO()
|
ctx := context.TODO()
|
||||||
fs, _ := s.ds.MediaFolder(ctx).GetAll()
|
fs, _ := s.ds.Library(ctx).GetAll()
|
||||||
for _, f := range fs {
|
for _, f := range fs {
|
||||||
log.Info("Configuring Media Folder", "name", f.Name, "path", f.Path)
|
log.Info("Configuring Media Folder", "name", f.Name, "path", f.Path)
|
||||||
s.folders[f.Path] = s.newScanner(f)
|
s.folders[f.Path] = s.newScanner(f)
|
||||||
@@ -249,6 +250,6 @@ func (s *scanner) loadFolders() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *scanner) newScanner(f model.MediaFolder) FolderScanner {
|
func (s *scanner) newScanner(f model.Library) FolderScanner {
|
||||||
return NewTagScanner(f.Path, s.ds, s.pls, s.cacheWarmer)
|
return NewTagScanner(f.Path, s.ds, s.pls, s.cacheWarmer)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,9 +17,9 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (api *Router) GetMusicFolders(r *http.Request) (*responses.Subsonic, error) {
|
func (api *Router) GetMusicFolders(r *http.Request) (*responses.Subsonic, error) {
|
||||||
mediaFolderList, _ := api.ds.MediaFolder(r.Context()).GetAll()
|
libraries, _ := api.ds.Library(r.Context()).GetAll()
|
||||||
folders := make([]responses.MusicFolder, len(mediaFolderList))
|
folders := make([]responses.MusicFolder, len(libraries))
|
||||||
for i, f := range mediaFolderList {
|
for i, f := range libraries {
|
||||||
folders[i].Id = f.ID
|
folders[i].Id = f.ID
|
||||||
folders[i].Name = f.Name
|
folders[i].Name = f.Name
|
||||||
}
|
}
|
||||||
@@ -28,11 +28,11 @@ func (api *Router) GetMusicFolders(r *http.Request) (*responses.Subsonic, error)
|
|||||||
return response, nil
|
return response, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api *Router) getArtistIndex(r *http.Request, mediaFolderId int, ifModifiedSince time.Time) (*responses.Indexes, error) {
|
func (api *Router) getArtistIndex(r *http.Request, libId int, ifModifiedSince time.Time) (*responses.Indexes, error) {
|
||||||
ctx := r.Context()
|
ctx := r.Context()
|
||||||
folder, err := api.ds.MediaFolder(ctx).Get(int32(mediaFolderId))
|
folder, err := api.ds.Library(ctx).Get(int32(libId))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(ctx, "Error retrieving MediaFolder", "id", mediaFolderId, err)
|
log.Error(ctx, "Error retrieving Library", "id", libId, err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (api *Router) GetScanStatus(r *http.Request) (*responses.Subsonic, error) {
|
func (api *Router) GetScanStatus(r *http.Request) (*responses.Subsonic, error) {
|
||||||
// TODO handle multiple mediafolders
|
// TODO handle multiple libraries
|
||||||
ctx := r.Context()
|
ctx := r.Context()
|
||||||
mediaFolder := conf.Server.MusicFolder
|
mediaFolder := conf.Server.MusicFolder
|
||||||
status, err := api.scanner.Status(mediaFolder)
|
status, err := api.scanner.Status(mediaFolder)
|
||||||
|
|||||||
@@ -43,8 +43,8 @@ func (db *MockDataStore) MediaFile(context.Context) model.MediaFileRepository {
|
|||||||
return db.MockedMediaFile
|
return db.MockedMediaFile
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *MockDataStore) MediaFolder(context.Context) model.MediaFolderRepository {
|
func (db *MockDataStore) Library(context.Context) model.LibraryRepository {
|
||||||
return struct{ model.MediaFolderRepository }{}
|
return struct{ model.LibraryRepository }{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *MockDataStore) Genre(context.Context) model.GenreRepository {
|
func (db *MockDataStore) Genre(context.Context) model.GenreRepository {
|
||||||
|
|||||||
Reference in New Issue
Block a user