mirror of
https://github.com/navidrome/navidrome.git
synced 2025-05-09 14:51:06 +03:00
* add dockerfile
* set default value for 'ReportRealPath' to True * move deleteSong logic from subsonic apis to native-apis
This commit is contained in:
parent
d8fa4629da
commit
c94e894beb
@ -45,6 +45,7 @@ func (p *players) Register(ctx context.Context, id, client, userAgent, ip string
|
|||||||
UserId: user.ID,
|
UserId: user.ID,
|
||||||
Client: client,
|
Client: client,
|
||||||
ScrobbleEnabled: true,
|
ScrobbleEnabled: true,
|
||||||
|
ReportRealPath: true,
|
||||||
}
|
}
|
||||||
log.Info(ctx, "Registering new player", "id", plr.ID, "client", client, "username", userName(ctx), "type", userAgent)
|
log.Info(ctx, "Registering new player", "id", plr.ID, "client", client, "username", userName(ctx), "type", userAgent)
|
||||||
}
|
}
|
||||||
|
18
docker-compose.yml
Normal file
18
docker-compose.yml
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
version: '3.4'
|
||||||
|
services:
|
||||||
|
navidrome:
|
||||||
|
image: navidrome:latest
|
||||||
|
restart: unless-stopped
|
||||||
|
container_name: "${NAME}"
|
||||||
|
user: "501:20"
|
||||||
|
ports:
|
||||||
|
- "${PORT}:4533"
|
||||||
|
environment:
|
||||||
|
ND_SCANSCHEDULE: 0
|
||||||
|
ND_LOGLEVEL: debug
|
||||||
|
ND_SESSIONTIMEOUT: 24h
|
||||||
|
# must add this so navidrome can respond to the path navidrome is to be accessed on via traefik
|
||||||
|
#ND_BASEURL: /navidrome
|
||||||
|
volumes:
|
||||||
|
- "/Users/lukepurnell/subbox/${USER}/navidrome/data:/data"
|
||||||
|
- "/Users/lukepurnell/subbox/${USER}/nav_music:/music:ro"
|
@ -53,6 +53,7 @@ func (n *Router) routes() http.Handler {
|
|||||||
|
|
||||||
n.addPlaylistRoute(r)
|
n.addPlaylistRoute(r)
|
||||||
n.addPlaylistTrackRoute(r)
|
n.addPlaylistTrackRoute(r)
|
||||||
|
n.addDeleteSongRoute(r)
|
||||||
|
|
||||||
// Keepalive endpoint to be used to keep the session valid (ex: while playing songs)
|
// Keepalive endpoint to be used to keep the session valid (ex: while playing songs)
|
||||||
r.Get("/keepalive/*", func(w http.ResponseWriter, r *http.Request) {
|
r.Get("/keepalive/*", func(w http.ResponseWriter, r *http.Request) {
|
||||||
@ -145,3 +146,14 @@ func (n *Router) addPlaylistTrackRoute(r chi.Router) {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (n *Router) addDeleteSongRoute(r chi.Router) {
|
||||||
|
r.Route("/song", func(r chi.Router) {
|
||||||
|
r.Route("/{id}", func(r chi.Router) {
|
||||||
|
r.Use(server.URLParamsMiddleware)
|
||||||
|
r.Delete("/", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
deleteSong(n.ds)(w, r)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
177
server/nativeapi/song.go
Normal file
177
server/nativeapi/song.go
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
package nativeapi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/navidrome/navidrome/log"
|
||||||
|
"github.com/navidrome/navidrome/model"
|
||||||
|
"github.com/navidrome/navidrome/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
type BeetsItem struct {
|
||||||
|
Results []struct {
|
||||||
|
Artpath string `json:"artpath"`
|
||||||
|
Year int `json:"year"`
|
||||||
|
Albumtype string `json:"albumtype"`
|
||||||
|
R128TrackGain any `json:"r128_track_gain"`
|
||||||
|
Day int `json:"day"`
|
||||||
|
Disc int `json:"disc"`
|
||||||
|
Albumartist string `json:"albumartist"`
|
||||||
|
MbReleasegroupid string `json:"mb_releasegroupid"`
|
||||||
|
InitialKey any `json:"initial_key"`
|
||||||
|
AcoustidID string `json:"acoustid_id"`
|
||||||
|
MbAlbumid string `json:"mb_albumid"`
|
||||||
|
Month int `json:"month"`
|
||||||
|
Track int `json:"track"`
|
||||||
|
Style string `json:"style"`
|
||||||
|
RgAlbumGain any `json:"rg_album_gain"`
|
||||||
|
Album string `json:"album"`
|
||||||
|
DiscogsArtistid int `json:"discogs_artistid"`
|
||||||
|
Tracktotal int `json:"tracktotal"`
|
||||||
|
MbAlbumartistid string `json:"mb_albumartistid"`
|
||||||
|
Country string `json:"country"`
|
||||||
|
Channels int `json:"channels"`
|
||||||
|
Arranger string `json:"arranger"`
|
||||||
|
Comp int `json:"comp"`
|
||||||
|
Bitrate int `json:"bitrate"`
|
||||||
|
Length float64 `json:"length"`
|
||||||
|
Lyricist string `json:"lyricist"`
|
||||||
|
RgAlbumPeak any `json:"rg_album_peak"`
|
||||||
|
MbArtistid string `json:"mb_artistid"`
|
||||||
|
Trackdisambig string `json:"trackdisambig"`
|
||||||
|
OriginalMonth int `json:"original_month"`
|
||||||
|
AcoustidFingerprint string `json:"acoustid_fingerprint"`
|
||||||
|
OriginalDay int `json:"original_day"`
|
||||||
|
ComposerSort string `json:"composer_sort"`
|
||||||
|
AlbumartistCredit string `json:"albumartist_credit"`
|
||||||
|
MbWorkid string `json:"mb_workid"`
|
||||||
|
MbReleasetrackid string `json:"mb_releasetrackid"`
|
||||||
|
Mtime float64 `json:"mtime"`
|
||||||
|
Work string `json:"work"`
|
||||||
|
AlbumartistSort string `json:"albumartist_sort"`
|
||||||
|
DiscogsLabelid int `json:"discogs_labelid"`
|
||||||
|
Bpm int `json:"bpm"`
|
||||||
|
Language string `json:"language"`
|
||||||
|
DataSource string `json:"data_source"`
|
||||||
|
ArtistCredit string `json:"artist_credit"`
|
||||||
|
Format string `json:"format"`
|
||||||
|
Composer string `json:"composer"`
|
||||||
|
Disctotal int `json:"disctotal"`
|
||||||
|
Title string `json:"title"`
|
||||||
|
Grouping string `json:"grouping"`
|
||||||
|
Added float64 `json:"added"`
|
||||||
|
Media string `json:"media"`
|
||||||
|
Artist string `json:"artist"`
|
||||||
|
Albumdisambig string `json:"albumdisambig"`
|
||||||
|
Isrc string `json:"isrc"`
|
||||||
|
DiscogsAlbumid int `json:"discogs_albumid"`
|
||||||
|
Disctitle string `json:"disctitle"`
|
||||||
|
Lyrics string `json:"lyrics"`
|
||||||
|
Albumstatus string `json:"albumstatus"`
|
||||||
|
Albumtypes string `json:"albumtypes"`
|
||||||
|
Releasegroupdisambig string `json:"releasegroupdisambig"`
|
||||||
|
Comments string `json:"comments"`
|
||||||
|
Encoder string `json:"encoder"`
|
||||||
|
Catalognum string `json:"catalognum"`
|
||||||
|
R128AlbumGain any `json:"r128_album_gain"`
|
||||||
|
Label string `json:"label"`
|
||||||
|
Bitdepth int `json:"bitdepth"`
|
||||||
|
RgTrackGain any `json:"rg_track_gain"`
|
||||||
|
ID int `json:"id"`
|
||||||
|
Script string `json:"script"`
|
||||||
|
ArtistSort string `json:"artist_sort"`
|
||||||
|
TrackAlt string `json:"track_alt"`
|
||||||
|
Genre string `json:"genre"`
|
||||||
|
OriginalYear int `json:"original_year"`
|
||||||
|
WorkDisambig string `json:"work_disambig"`
|
||||||
|
AlbumID int `json:"album_id"`
|
||||||
|
MbTrackid string `json:"mb_trackid"`
|
||||||
|
Asin string `json:"asin"`
|
||||||
|
RgTrackPeak any `json:"rg_track_peak"`
|
||||||
|
Samplerate int `json:"samplerate"`
|
||||||
|
Size int `json:"size"`
|
||||||
|
} `json:"results"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func deleteSong(ds model.DataStore) http.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// todo: tests, use proper url parsing lib
|
||||||
|
id := utils.ParamString(r, ":id")
|
||||||
|
ctx := r.Context()
|
||||||
|
ids := strings.Split(id, ",")
|
||||||
|
for _, id := range ids {
|
||||||
|
println(id)
|
||||||
|
mf, err := ds.MediaFile(ctx).Get(id)
|
||||||
|
if err != nil {
|
||||||
|
log.Error(err)
|
||||||
|
}
|
||||||
|
println(mf.Artist)
|
||||||
|
println(mf.Title)
|
||||||
|
// todo set this base from env variable
|
||||||
|
//baseUrl := "http://127.0.0.1:8337"
|
||||||
|
baseUrl := "http://host.docker.internal:8337"
|
||||||
|
queryEndPoint := "/item/query/"
|
||||||
|
queryStr := fmt.Sprintf("artist:%s/title:%s/album:%s", mf.Artist, mf.Title, mf.Album)
|
||||||
|
url := baseUrl + queryEndPoint + queryStr
|
||||||
|
fmt.Printf("query url: %s\n", url)
|
||||||
|
resp, err := http.Get(url) // nolint
|
||||||
|
if err != nil {
|
||||||
|
log.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
body, err := io.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
log.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
sb := string(body)
|
||||||
|
var beetsItem BeetsItem
|
||||||
|
err = json.Unmarshal([]byte(sb), &beetsItem)
|
||||||
|
if err != nil {
|
||||||
|
log.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
length := len(beetsItem.Results)
|
||||||
|
if length != 1 {
|
||||||
|
log.Error("following query string matched n entries", "n", length, "queryStr", queryStr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
item := beetsItem.Results[0]
|
||||||
|
log.Info("deleting: ", item.Artist, " : ", item.Title, " id: ", item.ID)
|
||||||
|
|
||||||
|
deleteStr := fmt.Sprintf("/item/%d", item.ID)
|
||||||
|
|
||||||
|
del_url := baseUrl + deleteStr
|
||||||
|
// Create request
|
||||||
|
req, err := http.NewRequest(http.MethodDelete, del_url, nil)
|
||||||
|
log.Info("delete request: ", req)
|
||||||
|
if err != nil {
|
||||||
|
log.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Fetch Request
|
||||||
|
client := &http.Client{}
|
||||||
|
del_resp, del_err := client.Do(req)
|
||||||
|
if del_err != nil {
|
||||||
|
log.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer del_resp.Body.Close()
|
||||||
|
|
||||||
|
// read the response body
|
||||||
|
del_body, err := io.ReadAll(del_resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
log.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// print the response body
|
||||||
|
fmt.Println(string(del_body))
|
||||||
|
log.Info("del body: ", del_body)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -2,7 +2,6 @@ package subsonic
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
@ -18,91 +17,6 @@ import (
|
|||||||
"github.com/navidrome/navidrome/utils/req"
|
"github.com/navidrome/navidrome/utils/req"
|
||||||
)
|
)
|
||||||
|
|
||||||
type BeetsItem struct {
|
|
||||||
Results []struct {
|
|
||||||
Artpath string `json:"artpath"`
|
|
||||||
Year int `json:"year"`
|
|
||||||
Albumtype string `json:"albumtype"`
|
|
||||||
R128TrackGain any `json:"r128_track_gain"`
|
|
||||||
Day int `json:"day"`
|
|
||||||
Disc int `json:"disc"`
|
|
||||||
Albumartist string `json:"albumartist"`
|
|
||||||
MbReleasegroupid string `json:"mb_releasegroupid"`
|
|
||||||
InitialKey any `json:"initial_key"`
|
|
||||||
AcoustidID string `json:"acoustid_id"`
|
|
||||||
MbAlbumid string `json:"mb_albumid"`
|
|
||||||
Month int `json:"month"`
|
|
||||||
Track int `json:"track"`
|
|
||||||
Style string `json:"style"`
|
|
||||||
RgAlbumGain any `json:"rg_album_gain"`
|
|
||||||
Album string `json:"album"`
|
|
||||||
DiscogsArtistid int `json:"discogs_artistid"`
|
|
||||||
Tracktotal int `json:"tracktotal"`
|
|
||||||
MbAlbumartistid string `json:"mb_albumartistid"`
|
|
||||||
Country string `json:"country"`
|
|
||||||
Channels int `json:"channels"`
|
|
||||||
Arranger string `json:"arranger"`
|
|
||||||
Comp int `json:"comp"`
|
|
||||||
Bitrate int `json:"bitrate"`
|
|
||||||
Length float64 `json:"length"`
|
|
||||||
Lyricist string `json:"lyricist"`
|
|
||||||
RgAlbumPeak any `json:"rg_album_peak"`
|
|
||||||
MbArtistid string `json:"mb_artistid"`
|
|
||||||
Trackdisambig string `json:"trackdisambig"`
|
|
||||||
OriginalMonth int `json:"original_month"`
|
|
||||||
AcoustidFingerprint string `json:"acoustid_fingerprint"`
|
|
||||||
OriginalDay int `json:"original_day"`
|
|
||||||
ComposerSort string `json:"composer_sort"`
|
|
||||||
AlbumartistCredit string `json:"albumartist_credit"`
|
|
||||||
MbWorkid string `json:"mb_workid"`
|
|
||||||
MbReleasetrackid string `json:"mb_releasetrackid"`
|
|
||||||
Mtime float64 `json:"mtime"`
|
|
||||||
Work string `json:"work"`
|
|
||||||
AlbumartistSort string `json:"albumartist_sort"`
|
|
||||||
DiscogsLabelid int `json:"discogs_labelid"`
|
|
||||||
Bpm int `json:"bpm"`
|
|
||||||
Language string `json:"language"`
|
|
||||||
DataSource string `json:"data_source"`
|
|
||||||
ArtistCredit string `json:"artist_credit"`
|
|
||||||
Format string `json:"format"`
|
|
||||||
Composer string `json:"composer"`
|
|
||||||
Disctotal int `json:"disctotal"`
|
|
||||||
Title string `json:"title"`
|
|
||||||
Grouping string `json:"grouping"`
|
|
||||||
Added float64 `json:"added"`
|
|
||||||
Media string `json:"media"`
|
|
||||||
Artist string `json:"artist"`
|
|
||||||
Albumdisambig string `json:"albumdisambig"`
|
|
||||||
Isrc string `json:"isrc"`
|
|
||||||
DiscogsAlbumid int `json:"discogs_albumid"`
|
|
||||||
Disctitle string `json:"disctitle"`
|
|
||||||
Lyrics string `json:"lyrics"`
|
|
||||||
Albumstatus string `json:"albumstatus"`
|
|
||||||
Albumtypes string `json:"albumtypes"`
|
|
||||||
Releasegroupdisambig string `json:"releasegroupdisambig"`
|
|
||||||
Comments string `json:"comments"`
|
|
||||||
Encoder string `json:"encoder"`
|
|
||||||
Catalognum string `json:"catalognum"`
|
|
||||||
R128AlbumGain any `json:"r128_album_gain"`
|
|
||||||
Label string `json:"label"`
|
|
||||||
Bitdepth int `json:"bitdepth"`
|
|
||||||
RgTrackGain any `json:"rg_track_gain"`
|
|
||||||
ID int `json:"id"`
|
|
||||||
Script string `json:"script"`
|
|
||||||
ArtistSort string `json:"artist_sort"`
|
|
||||||
TrackAlt string `json:"track_alt"`
|
|
||||||
Genre string `json:"genre"`
|
|
||||||
OriginalYear int `json:"original_year"`
|
|
||||||
WorkDisambig string `json:"work_disambig"`
|
|
||||||
AlbumID int `json:"album_id"`
|
|
||||||
MbTrackid string `json:"mb_trackid"`
|
|
||||||
Asin string `json:"asin"`
|
|
||||||
RgTrackPeak any `json:"rg_track_peak"`
|
|
||||||
Samplerate int `json:"samplerate"`
|
|
||||||
Size int `json:"size"`
|
|
||||||
} `json:"results"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (api *Router) serveStream(ctx context.Context, w http.ResponseWriter, r *http.Request, stream *core.Stream, id string) {
|
func (api *Router) serveStream(ctx context.Context, w http.ResponseWriter, r *http.Request, stream *core.Stream, id string) {
|
||||||
if stream.Seekable() {
|
if stream.Seekable() {
|
||||||
http.ServeContent(w, r, stream.Name(), stream.ModTime(), stream)
|
http.ServeContent(w, r, stream.Name(), stream.ModTime(), stream)
|
||||||
@ -166,85 +80,6 @@ func (api *Router) Stream(w http.ResponseWriter, r *http.Request) (*responses.Su
|
|||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api *Router) Delete(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) {
|
|
||||||
// todo: tests, use proper url parsing lib
|
|
||||||
println("hello from go. Deleting...")
|
|
||||||
id, err := requiredParamString(r, "id")
|
|
||||||
ctx := r.Context()
|
|
||||||
ids := strings.Split(id, ",")
|
|
||||||
for _, id := range ids {
|
|
||||||
println(id)
|
|
||||||
mf, err := api.ds.MediaFile(ctx).Get(id)
|
|
||||||
if err != nil {
|
|
||||||
log.Error(err)
|
|
||||||
}
|
|
||||||
println(mf.Artist)
|
|
||||||
println(mf.Title)
|
|
||||||
// todo set this base from env variable
|
|
||||||
//baseUrl := "http://127.0.0.1:8337"
|
|
||||||
baseUrl := "http://host.docker.internal:8337"
|
|
||||||
queryEndPoint := "/item/query/"
|
|
||||||
queryStr := fmt.Sprintf("artist:%s/title:%s/album:%s", mf.Artist, mf.Title, mf.Album)
|
|
||||||
url := baseUrl + queryEndPoint + queryStr
|
|
||||||
fmt.Printf("query url: %s\n", url)
|
|
||||||
resp, err := http.Get(url) // nolint
|
|
||||||
if err != nil {
|
|
||||||
log.Error(err)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
body, err := io.ReadAll(resp.Body)
|
|
||||||
if err != nil {
|
|
||||||
log.Error(err)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
sb := string(body)
|
|
||||||
var beetsItem BeetsItem
|
|
||||||
err = json.Unmarshal([]byte(sb), &beetsItem)
|
|
||||||
if err != nil {
|
|
||||||
log.Error(err)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
length := len(beetsItem.Results)
|
|
||||||
if length != 1 {
|
|
||||||
log.Error("following query string matched n entries", "n", length, "queryStr", queryStr)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
item := beetsItem.Results[0]
|
|
||||||
log.Info("deleting: ", item.Artist, " : ", item.Title, " id: ", item.ID)
|
|
||||||
|
|
||||||
deleteStr := fmt.Sprintf("/item/%d", item.ID)
|
|
||||||
|
|
||||||
del_url := baseUrl + deleteStr
|
|
||||||
// Create request
|
|
||||||
req, err := http.NewRequest(http.MethodDelete, del_url, nil)
|
|
||||||
log.Info("delete request: ", req)
|
|
||||||
if err != nil {
|
|
||||||
log.Error(err)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
// Fetch Request
|
|
||||||
client := &http.Client{}
|
|
||||||
del_resp, del_err := client.Do(req)
|
|
||||||
if del_err != nil {
|
|
||||||
log.Error(err)
|
|
||||||
return nil, del_err
|
|
||||||
}
|
|
||||||
defer del_resp.Body.Close()
|
|
||||||
|
|
||||||
// read the response body
|
|
||||||
del_body, err := io.ReadAll(del_resp.Body)
|
|
||||||
if err != nil {
|
|
||||||
log.Error(err)
|
|
||||||
return nil, del_err
|
|
||||||
}
|
|
||||||
|
|
||||||
// print the response body
|
|
||||||
fmt.Println(string(del_body))
|
|
||||||
log.Info("del body: ", del_body)
|
|
||||||
}
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (api *Router) Download(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) {
|
func (api *Router) Download(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) {
|
||||||
ctx := r.Context()
|
ctx := r.Context()
|
||||||
username, _ := request.UsernameFrom(ctx)
|
username, _ := request.UsernameFrom(ctx)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user