@@ -9,6 +9,7 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
|
"path/filepath"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@@ -20,6 +21,7 @@ import (
|
|||||||
|
|
||||||
"go.senan.xyz/gonic"
|
"go.senan.xyz/gonic"
|
||||||
"go.senan.xyz/gonic/db"
|
"go.senan.xyz/gonic/db"
|
||||||
|
"go.senan.xyz/gonic/paths"
|
||||||
"go.senan.xyz/gonic/server"
|
"go.senan.xyz/gonic/server"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -48,7 +50,7 @@ func main() {
|
|||||||
confHTTPLog := set.Bool("http-log", true, "http request logging (optional)")
|
confHTTPLog := set.Bool("http-log", true, "http request logging (optional)")
|
||||||
confShowVersion := set.Bool("version", false, "show gonic version")
|
confShowVersion := set.Bool("version", false, "show gonic version")
|
||||||
|
|
||||||
var confMusicPaths musicPaths
|
var confMusicPaths paths.MusicPaths
|
||||||
set.Var(&confMusicPaths, "music-path", "path to music")
|
set.Var(&confMusicPaths, "music-path", "path to music")
|
||||||
|
|
||||||
_ = set.String("config-path", "", "path to config (optional)")
|
_ = set.String("config-path", "", "path to config (optional)")
|
||||||
@@ -77,8 +79,8 @@ func main() {
|
|||||||
log.Fatalf("please provide a music directory")
|
log.Fatalf("please provide a music directory")
|
||||||
}
|
}
|
||||||
for _, confMusicPath := range confMusicPaths {
|
for _, confMusicPath := range confMusicPaths {
|
||||||
if _, err := os.Stat(confMusicPath); os.IsNotExist(err) {
|
if _, err := os.Stat(confMusicPath.Path); os.IsNotExist(err) {
|
||||||
log.Fatalf("music directory %q not found", confMusicPath)
|
log.Fatalf("music directory %q not found", confMusicPath.Path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if _, err := os.Stat(*confPodcastPath); os.IsNotExist(err) {
|
if _, err := os.Stat(*confPodcastPath); os.IsNotExist(err) {
|
||||||
@@ -109,7 +111,7 @@ func main() {
|
|||||||
defer dbc.Close()
|
defer dbc.Close()
|
||||||
|
|
||||||
err = dbc.Migrate(db.MigrationContext{
|
err = dbc.Migrate(db.MigrationContext{
|
||||||
OriginalMusicPath: confMusicPaths[0],
|
OriginalMusicPath: confMusicPaths[0].Path,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Panicf("error migrating database: %v\n", err)
|
log.Panicf("error migrating database: %v\n", err)
|
||||||
@@ -120,11 +122,11 @@ func main() {
|
|||||||
server, err := server.New(server.Options{
|
server, err := server.New(server.Options{
|
||||||
DB: dbc,
|
DB: dbc,
|
||||||
MusicPaths: confMusicPaths,
|
MusicPaths: confMusicPaths,
|
||||||
CachePath: cacheDirAudio,
|
CachePath: filepath.Clean(cacheDirAudio),
|
||||||
CoverCachePath: cacheDirCovers,
|
CoverCachePath: cacheDirCovers,
|
||||||
ProxyPrefix: *confProxyPrefix,
|
ProxyPrefix: *confProxyPrefix,
|
||||||
GenreSplit: *confGenreSplit,
|
GenreSplit: *confGenreSplit,
|
||||||
PodcastPath: *confPodcastPath,
|
PodcastPath: filepath.Clean(*confPodcastPath),
|
||||||
HTTPLog: *confHTTPLog,
|
HTTPLog: *confHTTPLog,
|
||||||
JukeboxEnabled: *confJukeboxEnabled,
|
JukeboxEnabled: *confJukeboxEnabled,
|
||||||
})
|
})
|
||||||
@@ -158,14 +160,3 @@ func main() {
|
|||||||
log.Panicf("error in job: %v", err)
|
log.Panicf("error in job: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type musicPaths []string
|
|
||||||
|
|
||||||
func (m musicPaths) String() string {
|
|
||||||
return strings.Join(m, ", ")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *musicPaths) Set(value string) error {
|
|
||||||
*m = append(*m, value)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|||||||
61
paths/paths.go
Normal file
61
paths/paths.go
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
package paths
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
const sep = "->"
|
||||||
|
|
||||||
|
type MusicPaths []MusicPath
|
||||||
|
|
||||||
|
func (mps MusicPaths) String() string {
|
||||||
|
var strs []string
|
||||||
|
for _, path := range mps {
|
||||||
|
strs = append(strs, path.String())
|
||||||
|
}
|
||||||
|
return strings.Join(strs, ", ")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mps *MusicPaths) Set(value string) error {
|
||||||
|
alias, path, ok := strings.Cut(value, sep)
|
||||||
|
if !ok {
|
||||||
|
*mps = append(*mps, MusicPath{
|
||||||
|
Path: filepath.Clean(strings.TrimSpace(value)),
|
||||||
|
})
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
*mps = append(*mps, MusicPath{
|
||||||
|
Alias: strings.TrimSpace(alias),
|
||||||
|
Path: filepath.Clean(strings.TrimSpace(path)),
|
||||||
|
})
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mps MusicPaths) Paths() []string {
|
||||||
|
var paths []string
|
||||||
|
for _, mp := range mps {
|
||||||
|
paths = append(paths, mp.Path)
|
||||||
|
}
|
||||||
|
return paths
|
||||||
|
}
|
||||||
|
|
||||||
|
type MusicPath struct {
|
||||||
|
Alias string
|
||||||
|
Path string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mp MusicPath) String() string {
|
||||||
|
if mp.Alias == "" {
|
||||||
|
return mp.Path
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%s %s %s", mp.Alias, sep, mp.Path)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mp MusicPath) DisplayAlias() string {
|
||||||
|
if mp.Alias == "" {
|
||||||
|
return filepath.Base(mp.Path)
|
||||||
|
}
|
||||||
|
return mp.Alias
|
||||||
|
}
|
||||||
@@ -10,6 +10,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"go.senan.xyz/gonic/jukebox"
|
"go.senan.xyz/gonic/jukebox"
|
||||||
|
"go.senan.xyz/gonic/paths"
|
||||||
"go.senan.xyz/gonic/podcasts"
|
"go.senan.xyz/gonic/podcasts"
|
||||||
"go.senan.xyz/gonic/scrobble"
|
"go.senan.xyz/gonic/scrobble"
|
||||||
"go.senan.xyz/gonic/server/ctrlbase"
|
"go.senan.xyz/gonic/server/ctrlbase"
|
||||||
@@ -31,7 +32,7 @@ type Controller struct {
|
|||||||
CachePath string
|
CachePath string
|
||||||
CoverCachePath string
|
CoverCachePath string
|
||||||
PodcastsPath string
|
PodcastsPath string
|
||||||
MusicPaths []string
|
MusicPaths paths.MusicPaths
|
||||||
Jukebox *jukebox.Jukebox
|
Jukebox *jukebox.Jukebox
|
||||||
Scrobblers []scrobble.Scrobbler
|
Scrobblers []scrobble.Scrobbler
|
||||||
Podcasts *podcasts.Podcasts
|
Podcasts *podcasts.Podcasts
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import (
|
|||||||
|
|
||||||
"go.senan.xyz/gonic/db"
|
"go.senan.xyz/gonic/db"
|
||||||
"go.senan.xyz/gonic/mockfs"
|
"go.senan.xyz/gonic/mockfs"
|
||||||
|
"go.senan.xyz/gonic/paths"
|
||||||
"go.senan.xyz/gonic/server/ctrlbase"
|
"go.senan.xyz/gonic/server/ctrlbase"
|
||||||
"go.senan.xyz/gonic/server/ctrlsubsonic/params"
|
"go.senan.xyz/gonic/server/ctrlsubsonic/params"
|
||||||
"go.senan.xyz/gonic/transcode"
|
"go.senan.xyz/gonic/transcode"
|
||||||
@@ -158,9 +159,9 @@ func makec(t *testing.T, roots []string, audio bool) *Controller {
|
|||||||
m.ScanAndClean()
|
m.ScanAndClean()
|
||||||
m.ResetDates()
|
m.ResetDates()
|
||||||
|
|
||||||
var absRoots []string
|
var absRoots paths.MusicPaths
|
||||||
for _, root := range roots {
|
for _, root := range roots {
|
||||||
absRoots = append(absRoots, filepath.Join(m.TmpDir(), root))
|
absRoots = append(absRoots, paths.MusicPath{Alias: "", Path: filepath.Join(m.TmpDir(), root)})
|
||||||
}
|
}
|
||||||
|
|
||||||
base := &ctrlbase.Controller{DB: m.DB()}
|
base := &ctrlbase.Controller{DB: m.DB()}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import (
|
|||||||
|
|
||||||
"go.senan.xyz/gonic/db"
|
"go.senan.xyz/gonic/db"
|
||||||
"go.senan.xyz/gonic/multierr"
|
"go.senan.xyz/gonic/multierr"
|
||||||
|
"go.senan.xyz/gonic/paths"
|
||||||
"go.senan.xyz/gonic/scanner"
|
"go.senan.xyz/gonic/scanner"
|
||||||
"go.senan.xyz/gonic/server/ctrlsubsonic/params"
|
"go.senan.xyz/gonic/server/ctrlsubsonic/params"
|
||||||
"go.senan.xyz/gonic/server/ctrlsubsonic/spec"
|
"go.senan.xyz/gonic/server/ctrlsubsonic/spec"
|
||||||
@@ -29,7 +30,7 @@ func lowerUDecOrHash(in string) string {
|
|||||||
return string(lower)
|
return string(lower)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getMusicFolder(musicPaths []string, p params.Params) string {
|
func getMusicFolder(musicPaths paths.MusicPaths, p params.Params) string {
|
||||||
idx, err := p.GetInt("musicFolderId")
|
idx, err := p.GetInt("musicFolderId")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ""
|
return ""
|
||||||
@@ -37,7 +38,7 @@ func getMusicFolder(musicPaths []string, p params.Params) string {
|
|||||||
if idx < 0 || idx > len(musicPaths) {
|
if idx < 0 || idx > len(musicPaths) {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
return musicPaths[idx]
|
return musicPaths[idx].Path
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Controller) ServeGetLicence(r *http.Request) *spec.Response {
|
func (c *Controller) ServeGetLicence(r *http.Request) *spec.Response {
|
||||||
@@ -91,7 +92,7 @@ func (c *Controller) ServeGetMusicFolders(r *http.Request) *spec.Response {
|
|||||||
sub.MusicFolders = &spec.MusicFolders{}
|
sub.MusicFolders = &spec.MusicFolders{}
|
||||||
sub.MusicFolders.List = make([]*spec.MusicFolder, len(c.MusicPaths))
|
sub.MusicFolders.List = make([]*spec.MusicFolder, len(c.MusicPaths))
|
||||||
for i, path := range c.MusicPaths {
|
for i, path := range c.MusicPaths {
|
||||||
sub.MusicFolders.List[i] = &spec.MusicFolder{ID: i, Name: filepath.Base(path)}
|
sub.MusicFolders.List[i] = &spec.MusicFolder{ID: i, Name: path.DisplayAlias()}
|
||||||
}
|
}
|
||||||
return sub
|
return sub
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
@@ -14,6 +13,7 @@ import (
|
|||||||
|
|
||||||
"go.senan.xyz/gonic/db"
|
"go.senan.xyz/gonic/db"
|
||||||
"go.senan.xyz/gonic/jukebox"
|
"go.senan.xyz/gonic/jukebox"
|
||||||
|
"go.senan.xyz/gonic/paths"
|
||||||
"go.senan.xyz/gonic/podcasts"
|
"go.senan.xyz/gonic/podcasts"
|
||||||
"go.senan.xyz/gonic/scanner"
|
"go.senan.xyz/gonic/scanner"
|
||||||
"go.senan.xyz/gonic/scanner/tags"
|
"go.senan.xyz/gonic/scanner/tags"
|
||||||
@@ -29,7 +29,7 @@ import (
|
|||||||
|
|
||||||
type Options struct {
|
type Options struct {
|
||||||
DB *db.DB
|
DB *db.DB
|
||||||
MusicPaths []string
|
MusicPaths paths.MusicPaths
|
||||||
PodcastPath string
|
PodcastPath string
|
||||||
CachePath string
|
CachePath string
|
||||||
CoverCachePath string
|
CoverCachePath string
|
||||||
@@ -48,15 +48,9 @@ type Server struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func New(opts Options) (*Server, error) {
|
func New(opts Options) (*Server, error) {
|
||||||
for i, musicPath := range opts.MusicPaths {
|
|
||||||
opts.MusicPaths[i] = filepath.Clean(musicPath)
|
|
||||||
}
|
|
||||||
opts.CachePath = filepath.Clean(opts.CachePath)
|
|
||||||
opts.PodcastPath = filepath.Clean(opts.PodcastPath)
|
|
||||||
|
|
||||||
tagger := &tags.TagReader{}
|
tagger := &tags.TagReader{}
|
||||||
|
|
||||||
scanner := scanner.New(opts.MusicPaths, opts.DB, opts.GenreSplit, tagger)
|
scanner := scanner.New(opts.MusicPaths.Paths(), opts.DB, opts.GenreSplit, tagger)
|
||||||
base := &ctrlbase.Controller{
|
base := &ctrlbase.Controller{
|
||||||
DB: opts.DB,
|
DB: opts.DB,
|
||||||
ProxyPrefix: opts.ProxyPrefix,
|
ProxyPrefix: opts.ProxyPrefix,
|
||||||
|
|||||||
Reference in New Issue
Block a user