From 473d96edda6d69ff734ea03df04b03f2f6b0cd85 Mon Sep 17 00:00:00 2001 From: Rob Emery Date: Sat, 8 Feb 2025 19:14:59 +0000 Subject: [PATCH] Formatting --- dlna/contenddirectoryservice.go | 8 +- dlna/dlnaserver.go | 146 ++++++++++++++++---------------- dlna/upnpav/upnpav.go | 27 +++--- go.mod | 4 +- go.sum | 3 - 5 files changed, 93 insertions(+), 95 deletions(-) diff --git a/dlna/contenddirectoryservice.go b/dlna/contenddirectoryservice.go index d3865d649..7057f9a6b 100644 --- a/dlna/contenddirectoryservice.go +++ b/dlna/contenddirectoryservice.go @@ -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) diff --git a/dlna/dlnaserver.go b/dlna/dlnaserver.go index abfc6376e..73a270719 100644 --- a/dlna/dlnaserver.go +++ b/dlna/dlnaserver.go @@ -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) diff --git a/dlna/upnpav/upnpav.go b/dlna/upnpav/upnpav.go index a3f5c15e4..3a9616fad 100644 --- a/dlna/upnpav/upnpav.go +++ b/dlna/upnpav/upnpav.go @@ -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 diff --git a/go.mod b/go.mod index 9a848b742..0b6398126 100644 --- a/go.mod +++ b/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 diff --git a/go.sum b/go.sum index 7af6924bb..5ba66f1d9 100644 --- a/go.sum +++ b/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=