mirror of
https://github.com/navidrome/navidrome.git
synced 2025-05-17 02:26:35 +03:00
Formatting
This commit is contained in:
parent
8e9a4c9e45
commit
473d96edda
@ -163,7 +163,7 @@ func handleArtist(matchResults map[string]string, ret []interface{}, cds *conten
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
return ret,nil
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func handleAlbum(matchResults map[string]string, ret []interface{}, cds *contentDirectoryService, o object, host string) ([]interface{}, error) {
|
||||
@ -195,9 +195,9 @@ func handleGenre(matchResults map[string]string, ret []interface{}, cds *content
|
||||
//This is never hit as the URL is direct to the streamPath
|
||||
} else if matchResults["GenreArtist"] != "" {
|
||||
tracks, err := cds.ds.MediaFile(cds.ctx).GetAll(model.QueryOptions{Filters: squirrel.And{
|
||||
squirrel.Eq{"genre.id": matchResults["Genre"]},
|
||||
squirrel.Eq{"artist_id": matchResults["GenreArtist"]},
|
||||
},
|
||||
squirrel.Eq{"genre.id": matchResults["Genre"]},
|
||||
squirrel.Eq{"artist_id": matchResults["GenreArtist"]},
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
fmt.Printf("Error retrieving tracks for artist and genre: %+v", err)
|
||||
|
@ -32,13 +32,13 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
serverField = "Linux/3.4 DLNADOC/1.50 UPnP/1.0 DMS/1.0"
|
||||
rootDescPath = "/rootDesc.xml"
|
||||
resourcePath = "/r/"
|
||||
resourceFilePath = "f"
|
||||
serverField = "Linux/3.4 DLNADOC/1.50 UPnP/1.0 DMS/1.0"
|
||||
rootDescPath = "/rootDesc.xml"
|
||||
resourcePath = "/r/"
|
||||
resourceFilePath = "f"
|
||||
resourceStreamPath = "s"
|
||||
resourceArtPath = "a"
|
||||
serviceControlURL = "/ctl"
|
||||
resourceArtPath = "a"
|
||||
serviceControlURL = "/ctl"
|
||||
)
|
||||
|
||||
//go:embed static/*
|
||||
@ -49,8 +49,8 @@ type DLNAServer struct {
|
||||
broker events.Broker
|
||||
ssdp SSDPServer
|
||||
ctx context.Context
|
||||
ms core.MediaStreamer
|
||||
art artwork.Artwork
|
||||
ms core.MediaStreamer
|
||||
art artwork.Artwork
|
||||
}
|
||||
|
||||
type SSDPServer struct {
|
||||
@ -74,8 +74,8 @@ type SSDPServer struct {
|
||||
// Time interval between SSPD announces
|
||||
AnnounceInterval time.Duration
|
||||
|
||||
ms core.MediaStreamer
|
||||
art artwork.Artwork
|
||||
ms core.MediaStreamer
|
||||
art artwork.Artwork
|
||||
}
|
||||
|
||||
func New(ds model.DataStore, broker events.Broker, mediastreamer core.MediaStreamer, artwork artwork.Artwork) *DLNAServer {
|
||||
@ -89,10 +89,10 @@ func New(ds model.DataStore, broker events.Broker, mediastreamer core.MediaStrea
|
||||
ModelNumber: consts.Version,
|
||||
RootDeviceUUID: makeDeviceUUID("Navidrome"),
|
||||
waitChan: make(chan struct{}),
|
||||
ms: mediastreamer,
|
||||
art: artwork,
|
||||
ms: mediastreamer,
|
||||
art: artwork,
|
||||
},
|
||||
ms: mediastreamer,
|
||||
ms: mediastreamer,
|
||||
art: artwork,
|
||||
}
|
||||
|
||||
@ -293,73 +293,73 @@ func (s *SSDPServer) resourceHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
components := strings.Split(remotePath, "/")
|
||||
switch components[0] {
|
||||
case resourceFilePath:
|
||||
localFile, _ := strings.CutPrefix(remotePath, path.Join(resourceFilePath,"Music/Files"))
|
||||
localFilePath := path.Join(conf.Server.MusicFolder, localFile)
|
||||
case resourceFilePath:
|
||||
localFile, _ := strings.CutPrefix(remotePath, path.Join(resourceFilePath, "Music/Files"))
|
||||
localFilePath := path.Join(conf.Server.MusicFolder, localFile)
|
||||
|
||||
log.Info(fmt.Sprintf("resource handler Executed with remote path: %s, localpath: %s", remotePath, localFilePath))
|
||||
log.Info(fmt.Sprintf("resource handler Executed with remote path: %s, localpath: %s", remotePath, localFilePath))
|
||||
|
||||
fileStats, err := os.Stat(localFilePath)
|
||||
if err != nil {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Length", strconv.FormatInt(fileStats.Size(), 10))
|
||||
fileStats, err := os.Stat(localFilePath)
|
||||
if err != nil {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Length", strconv.FormatInt(fileStats.Size(), 10))
|
||||
|
||||
// add some DLNA specific headers
|
||||
if r.Header.Get("getContentFeatures.dlna.org") != "" {
|
||||
w.Header().Set("contentFeatures.dlna.org", dms_dlna.ContentFeatures{
|
||||
SupportRange: true,
|
||||
}.String())
|
||||
}
|
||||
w.Header().Set("transferMode.dlna.org", "Streaming")
|
||||
// add some DLNA specific headers
|
||||
if r.Header.Get("getContentFeatures.dlna.org") != "" {
|
||||
w.Header().Set("contentFeatures.dlna.org", dms_dlna.ContentFeatures{
|
||||
SupportRange: true,
|
||||
}.String())
|
||||
}
|
||||
w.Header().Set("transferMode.dlna.org", "Streaming")
|
||||
|
||||
fileHandle, err := os.Open(localFilePath)
|
||||
if err != nil {
|
||||
fmt.Printf("file streaming error: %+v\n", err)
|
||||
return
|
||||
}
|
||||
defer fileHandle.Close()
|
||||
fileHandle, err := os.Open(localFilePath)
|
||||
if err != nil {
|
||||
fmt.Printf("file streaming error: %+v\n", err)
|
||||
return
|
||||
}
|
||||
defer fileHandle.Close()
|
||||
|
||||
http.ServeContent(w, r, remotePath, time.Now(), fileHandle)
|
||||
case resourceStreamPath: //TODO refactor this with stream.go:52?
|
||||
http.ServeContent(w, r, remotePath, time.Now(), fileHandle)
|
||||
case resourceStreamPath: //TODO refactor this with stream.go:52?
|
||||
|
||||
fileId := components[1]
|
||||
fileId := components[1]
|
||||
|
||||
//TODO figure out format, bitrate
|
||||
stream, err := s.ms.NewStream(r.Context(), fileId, "mp3", 0, 0)
|
||||
if err != nil {
|
||||
log.Error("Error streaming file", "id", fileId, err)
|
||||
return
|
||||
}
|
||||
defer func() {
|
||||
if err := stream.Close(); err != nil && log.IsGreaterOrEqualTo(log.LevelDebug) {
|
||||
log.Error("Error closing stream", "id", fileId, "file", stream.Name(), err)
|
||||
}
|
||||
}()
|
||||
w.Header().Set("X-Content-Type-Options", "nosniff")
|
||||
w.Header().Set("X-Content-Duration", strconv.FormatFloat(float64(stream.Duration()), 'G', -1, 32))
|
||||
http.ServeContent(w, r, stream.Name(), stream.ModTime(), stream)
|
||||
case resourceArtPath: //TODO refactor this with handle_images.go:39?
|
||||
artId, err := model.ParseArtworkID(components[1])
|
||||
if err != nil {
|
||||
log.Error("Failure to parse ArtworkId", "inputString", components[1], err)
|
||||
return
|
||||
}
|
||||
//TODO size (250)
|
||||
imgReader, lastUpdate, err := s.art.Get(r.Context(), artId, 250, true)
|
||||
if err != nil {
|
||||
log.Error("Failure to retrieve artwork", "artid", artId, err)
|
||||
return
|
||||
}
|
||||
defer imgReader.Close()
|
||||
w.Header().Set("Cache-Control", "public, max-age=315360000")
|
||||
w.Header().Set("Last-Modified", lastUpdate.Format(time.RFC1123))
|
||||
_, err = io.Copy(w, imgReader)
|
||||
if err != nil {
|
||||
log.Error("Error writing Artwork Response stream", err)
|
||||
return
|
||||
//TODO figure out format, bitrate
|
||||
stream, err := s.ms.NewStream(r.Context(), fileId, "mp3", 0, 0)
|
||||
if err != nil {
|
||||
log.Error("Error streaming file", "id", fileId, err)
|
||||
return
|
||||
}
|
||||
defer func() {
|
||||
if err := stream.Close(); err != nil && log.IsGreaterOrEqualTo(log.LevelDebug) {
|
||||
log.Error("Error closing stream", "id", fileId, "file", stream.Name(), err)
|
||||
}
|
||||
}()
|
||||
w.Header().Set("X-Content-Type-Options", "nosniff")
|
||||
w.Header().Set("X-Content-Duration", strconv.FormatFloat(float64(stream.Duration()), 'G', -1, 32))
|
||||
http.ServeContent(w, r, stream.Name(), stream.ModTime(), stream)
|
||||
case resourceArtPath: //TODO refactor this with handle_images.go:39?
|
||||
artId, err := model.ParseArtworkID(components[1])
|
||||
if err != nil {
|
||||
log.Error("Failure to parse ArtworkId", "inputString", components[1], err)
|
||||
return
|
||||
}
|
||||
//TODO size (250)
|
||||
imgReader, lastUpdate, err := s.art.Get(r.Context(), artId, 250, true)
|
||||
if err != nil {
|
||||
log.Error("Failure to retrieve artwork", "artid", artId, err)
|
||||
return
|
||||
}
|
||||
defer imgReader.Close()
|
||||
w.Header().Set("Cache-Control", "public, max-age=315360000")
|
||||
w.Header().Set("Last-Modified", lastUpdate.Format(time.RFC1123))
|
||||
_, err = io.Copy(w, imgReader)
|
||||
if err != nil {
|
||||
log.Error("Error writing Artwork Response stream", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -423,7 +423,7 @@ func (s *SSDPServer) soapActionResponse(sa upnp.SoapAction, actionRequestXML []b
|
||||
|
||||
func (s *SSDPServer) serveHTTP() error {
|
||||
srv := &http.Server{
|
||||
Handler: s.handler,
|
||||
Handler: s.handler,
|
||||
ReadHeaderTimeout: 10 * time.Second,
|
||||
}
|
||||
err := srv.Serve(s.HTTPConn)
|
||||
|
@ -39,20 +39,21 @@ type Item struct {
|
||||
|
||||
// Object description
|
||||
type Object struct {
|
||||
ID string `xml:"id,attr"`
|
||||
ParentID string `xml:"parentID,attr"`
|
||||
Restricted int `xml:"restricted,attr"` // indicates whether the object is modifiable
|
||||
Class string `xml:"upnp:class"`
|
||||
Icon string `xml:"upnp:icon,omitempty"`
|
||||
Title string `xml:"dc:title"`
|
||||
Date Timestamp `xml:"dc:date"`
|
||||
Artist string `xml:"upnp:artist,omitempty"`
|
||||
Album string `xml:"upnp:album,omitempty"`
|
||||
Genre string `xml:"upnp:genre,omitempty"`
|
||||
AlbumArtURI string `xml:"upnp:albumArtURI,omitempty"`
|
||||
OriginalTrackNumber int `xml:"upnp:originalTrackNumber,omitempty"`
|
||||
Searchable int `xml:"searchable,attr"`
|
||||
ID string `xml:"id,attr"`
|
||||
ParentID string `xml:"parentID,attr"`
|
||||
Restricted int `xml:"restricted,attr"` // indicates whether the object is modifiable
|
||||
Class string `xml:"upnp:class"`
|
||||
Icon string `xml:"upnp:icon,omitempty"`
|
||||
Title string `xml:"dc:title"`
|
||||
Date Timestamp `xml:"dc:date"`
|
||||
Artist string `xml:"upnp:artist,omitempty"`
|
||||
Album string `xml:"upnp:album,omitempty"`
|
||||
Genre string `xml:"upnp:genre,omitempty"`
|
||||
AlbumArtURI string `xml:"upnp:albumArtURI,omitempty"`
|
||||
OriginalTrackNumber int `xml:"upnp:originalTrackNumber,omitempty"`
|
||||
Searchable int `xml:"searchable,attr"`
|
||||
}
|
||||
|
||||
// Timestamp wraps time.Time for formatting purposes
|
||||
type Timestamp struct {
|
||||
time.Time
|
||||
|
4
go.mod
4
go.mod
@ -8,6 +8,7 @@ replace github.com/dhowden/tag v0.0.0-20240417053706-3d75831295e8 => github.com/
|
||||
require (
|
||||
github.com/Masterminds/squirrel v1.5.4
|
||||
github.com/RaveNoX/go-jsoncommentstrip v1.0.0
|
||||
github.com/anacrolix/dms v1.7.1
|
||||
github.com/andybalholm/cascadia v1.3.3
|
||||
github.com/bmatcuk/doublestar/v4 v4.8.1
|
||||
github.com/bradleyjkemp/cupaloy/v2 v2.8.0
|
||||
@ -41,6 +42,7 @@ require (
|
||||
github.com/mileusna/useragent v1.3.5
|
||||
github.com/onsi/ginkgo/v2 v2.22.2
|
||||
github.com/onsi/gomega v1.36.2
|
||||
github.com/oriser/regroup v0.0.0-20240925165441-f6bb0e08289e
|
||||
github.com/pelletier/go-toml/v2 v2.2.3
|
||||
github.com/pocketbase/dbx v1.11.0
|
||||
github.com/pressly/goose/v3 v3.24.1
|
||||
@ -66,7 +68,6 @@ require (
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/anacrolix/dms v1.7.1 // indirect
|
||||
github.com/anacrolix/generics v0.0.1 // indirect
|
||||
github.com/anacrolix/log v0.15.2 // indirect
|
||||
github.com/aymerick/douceur v0.2.0 // indirect
|
||||
@ -97,7 +98,6 @@ require (
|
||||
github.com/mfridman/interpolate v0.0.2 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/oriser/regroup v0.0.0-20240925165441-f6bb0e08289e // indirect
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||
github.com/prometheus/client_model v0.6.1 // indirect
|
||||
github.com/prometheus/common v0.62.0 // indirect
|
||||
|
3
go.sum
3
go.sum
@ -83,7 +83,6 @@ github.com/google/go-pipeline v0.0.0-20230411140531-6cbedfc1d3fc h1:hd+uUVsB1vdx
|
||||
github.com/google/go-pipeline v0.0.0-20230411140531-6cbedfc1d3fc/go.mod h1:SL66SJVysrh7YbDCP9tH30b8a9o/N2HeiQNUm85EKhc=
|
||||
github.com/google/pprof v0.0.0-20250208200701-d0013a598941 h1:43XjGa6toxLpeksjcxs1jIoIyr+vUfOqY2c6HB4bpoc=
|
||||
github.com/google/pprof v0.0.0-20250208200701-d0013a598941/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
|
||||
github.com/google/subcommands v1.2.0 h1:vWQspBTo2nEqTUFita5/KeEWlUL8kQObDFbub/EN9oE=
|
||||
github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
@ -261,8 +260,6 @@ golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4=
|
||||
golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
|
Loading…
x
Reference in New Issue
Block a user