construct subsonic models elsewhere
This commit is contained in:
@@ -13,9 +13,9 @@ import "time"
|
||||
type Album struct {
|
||||
IDBase
|
||||
CrudBase
|
||||
AlbumArtist AlbumArtist
|
||||
AlbumArtistID int `gorm:"index" sql:"default: null; type:int REFERENCES album_artists(id) ON DELETE CASCADE"`
|
||||
Title string `gorm:"not null; index"`
|
||||
Artist Artist
|
||||
ArtistID int `gorm:"index" sql:"default: null; type:int REFERENCES artists(id) ON DELETE CASCADE"`
|
||||
Title string `gorm:"not null; index"`
|
||||
// an Album having a `Path` is a little weird when browsing by tags
|
||||
// (for the most part - the library's folder structure is treated as
|
||||
// if it were flat), but this solves the "American Football problem"
|
||||
@@ -28,8 +28,8 @@ type Album struct {
|
||||
IsNew bool `gorm:"-"`
|
||||
}
|
||||
|
||||
// AlbumArtist represents the AlbumArtists table
|
||||
type AlbumArtist struct {
|
||||
// Artist represents the Artists table
|
||||
type Artist struct {
|
||||
IDBase
|
||||
CrudBase
|
||||
Name string `gorm:"not null; unique_index"`
|
||||
@@ -40,26 +40,26 @@ type AlbumArtist struct {
|
||||
type Track struct {
|
||||
IDBase
|
||||
CrudBase
|
||||
Album Album
|
||||
AlbumID int `gorm:"index" sql:"default: null; type:int REFERENCES albums(id) ON DELETE CASCADE"`
|
||||
AlbumArtist AlbumArtist
|
||||
AlbumArtistID int `gorm:"index" sql:"default: null; type:int REFERENCES album_artists(id) ON DELETE CASCADE"`
|
||||
Artist string
|
||||
Bitrate int
|
||||
Codec string
|
||||
DiscNumber int
|
||||
Duration int
|
||||
Title string
|
||||
TotalDiscs int
|
||||
TotalTracks int
|
||||
TrackNumber int
|
||||
Year int
|
||||
Suffix string
|
||||
ContentType string
|
||||
Size int
|
||||
Folder Folder
|
||||
FolderID int `gorm:"not null; index" sql:"default: null; type:int REFERENCES folders(id) ON DELETE CASCADE"`
|
||||
Path string `gorm:"not null; unique_index"`
|
||||
Album Album
|
||||
AlbumID int `gorm:"index" sql:"default: null; type:int REFERENCES albums(id) ON DELETE CASCADE"`
|
||||
Artist Artist
|
||||
ArtistID int `gorm:"index" sql:"default: null; type:int REFERENCES artists(id) ON DELETE CASCADE"`
|
||||
TrackArtist string
|
||||
Bitrate int
|
||||
Codec string
|
||||
DiscNumber int
|
||||
Duration int
|
||||
Title string
|
||||
TotalDiscs int
|
||||
TotalTracks int
|
||||
TrackNumber int
|
||||
Year int
|
||||
Suffix string
|
||||
ContentType string
|
||||
Size int
|
||||
Folder Folder
|
||||
FolderID int `gorm:"not null; index" sql:"default: null; type:int REFERENCES folders(id) ON DELETE CASCADE"`
|
||||
Path string `gorm:"not null; unique_index"`
|
||||
}
|
||||
|
||||
// Cover represents the covers table
|
||||
|
||||
@@ -31,7 +31,7 @@ type Scanner struct {
|
||||
curTracks []model.Track
|
||||
curCover model.Cover
|
||||
curAlbum model.Album
|
||||
curAArtist model.AlbumArtist
|
||||
curAArtist model.Artist
|
||||
}
|
||||
|
||||
func New(db *gorm.DB, musicPath string) *Scanner {
|
||||
@@ -43,7 +43,7 @@ func New(db *gorm.DB, musicPath string) *Scanner {
|
||||
curTracks: make([]model.Track, 0),
|
||||
curCover: model.Cover{},
|
||||
curAlbum: model.Album{},
|
||||
curAArtist: model.AlbumArtist{},
|
||||
curAArtist: model.Artist{},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,7 +105,7 @@ func (s *Scanner) MigrateDB() error {
|
||||
defer s.tx.Commit()
|
||||
s.tx.AutoMigrate(
|
||||
model.Album{},
|
||||
model.AlbumArtist{},
|
||||
model.Artist{},
|
||||
model.Track{},
|
||||
model.Cover{},
|
||||
model.User{},
|
||||
|
||||
@@ -81,7 +81,7 @@ func (s *Scanner) callbackPost(path string, info *godirwalk.Dirent) error {
|
||||
s.curTracks = make([]model.Track, 0)
|
||||
s.curCover = model.Cover{}
|
||||
s.curAlbum = model.Album{}
|
||||
s.curAArtist = model.AlbumArtist{}
|
||||
s.curAArtist = model.Artist{}
|
||||
//
|
||||
log.Printf("processed folder `%s`\n", path)
|
||||
return nil
|
||||
@@ -156,7 +156,7 @@ func (s *Scanner) handleTrack(it *item) error {
|
||||
track.ContentType = it.track.mime
|
||||
track.Size = int(it.stat.Size())
|
||||
track.Title = tags.Title()
|
||||
track.Artist = tags.Artist()
|
||||
track.TrackArtist = tags.Artist()
|
||||
track.Year = tags.Year()
|
||||
track.FolderID = s.curFolders.PeekID()
|
||||
//
|
||||
@@ -168,7 +168,7 @@ func (s *Scanner) handleTrack(it *item) error {
|
||||
s.curAArtist.Name = tags.AlbumArtist()
|
||||
s.tx.Save(&s.curAArtist)
|
||||
}
|
||||
track.AlbumArtistID = s.curAArtist.ID
|
||||
track.ArtistID = s.curAArtist.ID
|
||||
//
|
||||
// set album if this is the first track in the folder
|
||||
if len(s.curTracks) > 0 {
|
||||
@@ -189,7 +189,7 @@ func (s *Scanner) handleTrack(it *item) error {
|
||||
s.curAlbum.Path = directory
|
||||
s.curAlbum.Title = tags.Album()
|
||||
s.curAlbum.Year = tags.Year()
|
||||
s.curAlbum.AlbumArtistID = s.curAArtist.ID
|
||||
s.curAlbum.ArtistID = s.curAArtist.ID
|
||||
s.curAlbum.IsNew = true
|
||||
return nil
|
||||
}
|
||||
|
||||
54
server/handler/construct_sub_by_folder.go
Normal file
54
server/handler/construct_sub_by_folder.go
Normal file
@@ -0,0 +1,54 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"github.com/sentriz/gonic/model"
|
||||
"github.com/sentriz/gonic/server/subsonic"
|
||||
)
|
||||
|
||||
func makeChildFromFolder(f *model.Folder, parent *model.Folder) *subsonic.Child {
|
||||
return &subsonic.Child{
|
||||
ID: f.ID,
|
||||
Title: f.Name,
|
||||
CoverID: f.CoverID,
|
||||
ParentID: parent.ID,
|
||||
IsDir: true,
|
||||
}
|
||||
}
|
||||
|
||||
func makeChildFromTrack(t *model.Track, parent *model.Folder) *subsonic.Child {
|
||||
return &subsonic.Child{
|
||||
ID: t.ID,
|
||||
Album: t.Album.Title,
|
||||
Artist: t.TrackArtist,
|
||||
ContentType: t.ContentType,
|
||||
Path: t.Path,
|
||||
Size: t.Size,
|
||||
Suffix: t.Suffix,
|
||||
Title: t.Title,
|
||||
Track: t.TrackNumber,
|
||||
ParentID: parent.ID,
|
||||
CoverID: parent.CoverID,
|
||||
Duration: 0,
|
||||
IsDir: false,
|
||||
Type: "music",
|
||||
}
|
||||
}
|
||||
|
||||
func makeAlbumFromFolder(f *model.Folder) *subsonic.Album {
|
||||
return &subsonic.Album{
|
||||
ID: f.ID,
|
||||
Title: f.Name,
|
||||
Album: f.Name,
|
||||
CoverID: f.CoverID,
|
||||
ParentID: f.ParentID,
|
||||
Artist: f.Parent.Name,
|
||||
IsDir: true,
|
||||
}
|
||||
}
|
||||
|
||||
func makeArtistFromFolder(f *model.Folder) *subsonic.Artist {
|
||||
return &subsonic.Artist{
|
||||
ID: f.ID,
|
||||
Name: f.Name,
|
||||
}
|
||||
}
|
||||
43
server/handler/construct_sub_by_tags.go
Normal file
43
server/handler/construct_sub_by_tags.go
Normal file
@@ -0,0 +1,43 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"github.com/sentriz/gonic/model"
|
||||
"github.com/sentriz/gonic/server/subsonic"
|
||||
)
|
||||
|
||||
func makeAlbumFromAlbum(a *model.Album, artist *model.Artist) *subsonic.Album {
|
||||
return &subsonic.Album{
|
||||
ID: a.ID,
|
||||
Name: a.Title,
|
||||
Created: a.CreatedAt,
|
||||
CoverID: a.CoverID,
|
||||
Artist: artist.Name,
|
||||
ArtistID: artist.ID,
|
||||
}
|
||||
}
|
||||
|
||||
func makeTrackFromTrack(t *model.Track, album *model.Album) *subsonic.Track {
|
||||
return &subsonic.Track{
|
||||
ID: t.ID,
|
||||
Title: t.Title,
|
||||
Artist: t.TrackArtist,
|
||||
TrackNumber: t.TrackNumber,
|
||||
ContentType: t.ContentType,
|
||||
Path: t.Path,
|
||||
Suffix: t.Suffix,
|
||||
CreatedAt: t.CreatedAt,
|
||||
Size: t.Size,
|
||||
Album: album.Title,
|
||||
AlbumID: album.ID,
|
||||
ArtistID: album.Artist.ID,
|
||||
CoverID: album.CoverID,
|
||||
Type: "music",
|
||||
}
|
||||
}
|
||||
|
||||
func makeArtistFromArtist(a *model.Artist) *subsonic.Artist {
|
||||
return &subsonic.Artist{
|
||||
ID: a.ID,
|
||||
Name: a.Name,
|
||||
}
|
||||
}
|
||||
@@ -49,7 +49,7 @@ func (c *Controller) ServeLogout(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
func (c *Controller) ServeHome(w http.ResponseWriter, r *http.Request) {
|
||||
var data templateData
|
||||
c.DB.Table("album_artists").Count(&data.ArtistCount)
|
||||
c.DB.Table("artists").Count(&data.ArtistCount)
|
||||
c.DB.Table("albums").Count(&data.AlbumCount)
|
||||
c.DB.Table("tracks").Count(&data.TrackCount)
|
||||
c.DB.Find(&data.AllUsers)
|
||||
|
||||
@@ -13,7 +13,7 @@ import (
|
||||
func (c *Controller) GetIndexes(w http.ResponseWriter, r *http.Request) {
|
||||
// we are browsing by folder, but the subsonic docs show sub <artist> elements
|
||||
// for this, so we're going to return root directories as "artists"
|
||||
var folders []*model.Folder
|
||||
var folders []model.Folder
|
||||
c.DB.Where("parent_id = ?", 1).Find(&folders)
|
||||
var indexMap = make(map[rune]*subsonic.Index)
|
||||
var indexes []*subsonic.Index
|
||||
@@ -28,10 +28,8 @@ func (c *Controller) GetIndexes(w http.ResponseWriter, r *http.Request) {
|
||||
indexMap[i] = index
|
||||
indexes = append(indexes, index)
|
||||
}
|
||||
index.Artists = append(index.Artists, &subsonic.Artist{
|
||||
ID: folder.ID,
|
||||
Name: folder.Name,
|
||||
})
|
||||
index.Artists = append(index.Artists,
|
||||
makeArtistFromFolder(&folder))
|
||||
}
|
||||
sub := subsonic.NewResponse()
|
||||
sub.Indexes = &subsonic.Indexes{
|
||||
@@ -48,61 +46,42 @@ func (c *Controller) GetMusicDirectory(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
childrenObj := []*subsonic.Child{}
|
||||
var cFolder model.Folder
|
||||
c.DB.First(&cFolder, id)
|
||||
var folder model.Folder
|
||||
c.DB.First(&folder, id)
|
||||
//
|
||||
// start looking for child folders in the current dir
|
||||
var folders []*model.Folder
|
||||
// start looking for child childFolders in the current dir
|
||||
var childFolders []model.Folder
|
||||
c.DB.
|
||||
Where("parent_id = ?", id).
|
||||
Find(&folders)
|
||||
for _, folder := range folders {
|
||||
childrenObj = append(childrenObj, &subsonic.Child{
|
||||
Parent: cFolder.ID,
|
||||
ID: folder.ID,
|
||||
Title: folder.Name,
|
||||
IsDir: true,
|
||||
CoverID: folder.CoverID,
|
||||
})
|
||||
Find(&childFolders)
|
||||
for _, c := range childFolders {
|
||||
childrenObj = append(childrenObj,
|
||||
makeChildFromFolder(&c, &folder))
|
||||
}
|
||||
//
|
||||
// start looking for child tracks in the current dir
|
||||
var tracks []*model.Track
|
||||
// start looking for child childTracks in the current dir
|
||||
var childTracks []model.Track
|
||||
c.DB.
|
||||
Where("folder_id = ?", id).
|
||||
Preload("Album").
|
||||
Order("title").
|
||||
Find(&tracks)
|
||||
for _, track := range tracks {
|
||||
Find(&childTracks)
|
||||
for _, c := range childTracks {
|
||||
if getStrParam(r, "c") == "Jamstash" {
|
||||
// jamstash thinks it can't play flacs
|
||||
track.ContentType = "audio/mpeg"
|
||||
track.Suffix = "mp3"
|
||||
c.ContentType = "audio/mpeg"
|
||||
c.Suffix = "mp3"
|
||||
}
|
||||
childrenObj = append(childrenObj, &subsonic.Child{
|
||||
ID: track.ID,
|
||||
Album: track.Album.Title,
|
||||
Artist: track.Artist,
|
||||
ContentType: track.ContentType,
|
||||
CoverID: cFolder.CoverID,
|
||||
Duration: 0,
|
||||
IsDir: false,
|
||||
Parent: cFolder.ID,
|
||||
Path: track.Path,
|
||||
Size: track.Size,
|
||||
Suffix: track.Suffix,
|
||||
Title: track.Title,
|
||||
Track: track.TrackNumber,
|
||||
Type: "music",
|
||||
})
|
||||
childrenObj = append(childrenObj,
|
||||
makeChildFromTrack(&c, &folder))
|
||||
}
|
||||
//
|
||||
// respond section
|
||||
sub := subsonic.NewResponse()
|
||||
sub.Directory = &subsonic.Directory{
|
||||
ID: cFolder.ID,
|
||||
Parent: cFolder.ParentID,
|
||||
Name: cFolder.Name,
|
||||
ID: folder.ID,
|
||||
Parent: folder.ParentID,
|
||||
Name: folder.Name,
|
||||
Children: childrenObj,
|
||||
}
|
||||
respond(w, r, sub)
|
||||
@@ -152,28 +131,18 @@ func (c *Controller) GetAlbumList(w http.ResponseWriter, r *http.Request) {
|
||||
))
|
||||
return
|
||||
}
|
||||
var folders []*model.Folder
|
||||
var folders []model.Folder
|
||||
q.
|
||||
Where("folders.has_tracks = 1").
|
||||
Offset(getIntParamOr(r, "offset", 0)).
|
||||
Limit(getIntParamOr(r, "size", 10)).
|
||||
Preload("Parent").
|
||||
Find(&folders)
|
||||
listObj := []*subsonic.Album{}
|
||||
for _, folder := range folders {
|
||||
listObj = append(listObj, &subsonic.Album{
|
||||
ID: folder.ID,
|
||||
Title: folder.Name,
|
||||
Album: folder.Name,
|
||||
CoverID: folder.CoverID,
|
||||
ParentID: folder.ParentID,
|
||||
IsDir: true,
|
||||
Artist: folder.Parent.Name,
|
||||
})
|
||||
}
|
||||
sub := subsonic.NewResponse()
|
||||
sub.Albums = &subsonic.Albums{
|
||||
List: listObj,
|
||||
sub.Albums = &subsonic.Albums{}
|
||||
for _, folder := range folders {
|
||||
sub.Albums.List = append(sub.Albums.List,
|
||||
makeAlbumFromFolder(&folder))
|
||||
}
|
||||
respond(w, r, sub)
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
)
|
||||
|
||||
func (c *Controller) GetArtists(w http.ResponseWriter, r *http.Request) {
|
||||
var artists []*model.AlbumArtist
|
||||
var artists []model.Artist
|
||||
c.DB.Find(&artists)
|
||||
var indexMap = make(map[rune]*subsonic.Index)
|
||||
var indexes subsonic.Artists
|
||||
@@ -26,10 +26,8 @@ func (c *Controller) GetArtists(w http.ResponseWriter, r *http.Request) {
|
||||
indexMap[i] = index
|
||||
indexes.List = append(indexes.List, index)
|
||||
}
|
||||
index.Artists = append(index.Artists, &subsonic.Artist{
|
||||
ID: artist.ID,
|
||||
Name: artist.Name,
|
||||
})
|
||||
index.Artists = append(index.Artists,
|
||||
makeArtistFromArtist(&artist))
|
||||
}
|
||||
sub := subsonic.NewResponse()
|
||||
sub.Artists = &indexes
|
||||
@@ -42,26 +40,15 @@ func (c *Controller) GetArtist(w http.ResponseWriter, r *http.Request) {
|
||||
respondError(w, r, 10, "please provide an `id` parameter")
|
||||
return
|
||||
}
|
||||
var artist model.AlbumArtist
|
||||
var artist model.Artist
|
||||
c.DB.
|
||||
Preload("Albums").
|
||||
First(&artist, id)
|
||||
albumsObj := []*subsonic.Album{}
|
||||
for _, album := range artist.Albums {
|
||||
albumsObj = append(albumsObj, &subsonic.Album{
|
||||
ID: album.ID,
|
||||
Name: album.Title,
|
||||
Created: album.CreatedAt,
|
||||
Artist: artist.Name,
|
||||
ArtistID: artist.ID,
|
||||
CoverID: album.CoverID,
|
||||
})
|
||||
}
|
||||
sub := subsonic.NewResponse()
|
||||
sub.Artist = &subsonic.Artist{
|
||||
ID: artist.ID,
|
||||
Name: artist.Name,
|
||||
Albums: albumsObj,
|
||||
sub.Artist = makeArtistFromArtist(&artist)
|
||||
for _, album := range artist.Albums {
|
||||
sub.Artist.Albums = append(sub.Artist.Albums,
|
||||
makeAlbumFromAlbum(&album, &artist))
|
||||
}
|
||||
respond(w, r, sub)
|
||||
}
|
||||
@@ -73,39 +60,22 @@ func (c *Controller) GetAlbum(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
var album model.Album
|
||||
c.DB.
|
||||
Preload("AlbumArtist").
|
||||
err = c.DB.
|
||||
Preload("Artist").
|
||||
Preload("Tracks", func(db *gorm.DB) *gorm.DB {
|
||||
return db.Order("tracks.track_number")
|
||||
}).
|
||||
First(&album, id)
|
||||
tracksObj := []*subsonic.Track{}
|
||||
for _, track := range album.Tracks {
|
||||
tracksObj = append(tracksObj, &subsonic.Track{
|
||||
ID: track.ID,
|
||||
Title: track.Title,
|
||||
Artist: track.Artist, // track artist
|
||||
TrackNo: track.TrackNumber,
|
||||
ContentType: track.ContentType,
|
||||
Path: track.Path,
|
||||
Suffix: track.Suffix,
|
||||
Created: track.CreatedAt,
|
||||
Size: track.Size,
|
||||
Album: album.Title,
|
||||
AlbumID: album.ID,
|
||||
ArtistID: album.AlbumArtist.ID, // album artist
|
||||
CoverID: album.CoverID,
|
||||
Type: "music",
|
||||
})
|
||||
return db.Order("tracks.track_number")
|
||||
}).
|
||||
First(&album, id).
|
||||
Error
|
||||
if gorm.IsRecordNotFoundError(err) {
|
||||
respondError(w, r, 10, "couldn't find an album with that id")
|
||||
return
|
||||
}
|
||||
sub := subsonic.NewResponse()
|
||||
sub.Album = &subsonic.Album{
|
||||
ID: album.ID,
|
||||
Name: album.Title,
|
||||
CoverID: album.CoverID,
|
||||
Created: album.CreatedAt,
|
||||
Artist: album.AlbumArtist.Name,
|
||||
Tracks: tracksObj,
|
||||
sub.Album = makeAlbumFromAlbum(&album, &album.Artist)
|
||||
for _, track := range album.Tracks {
|
||||
sub.Album.Tracks = append(sub.Album.Tracks,
|
||||
makeTrackFromTrack(&track, &album))
|
||||
}
|
||||
respond(w, r, sub)
|
||||
}
|
||||
@@ -122,9 +92,9 @@ func (c *Controller) GetAlbumListTwo(w http.ResponseWriter, r *http.Request) {
|
||||
switch listType {
|
||||
case "alphabeticalByArtist":
|
||||
q = q.Joins(`
|
||||
JOIN album_artists
|
||||
ON albums.album_artist_id = album_artists.id`)
|
||||
q = q.Order("album_artists.name")
|
||||
JOIN artists
|
||||
ON albums.artist_id = artists.id`)
|
||||
q = q.Order("artists.name")
|
||||
case "alphabeticalByName":
|
||||
q = q.Order("title")
|
||||
case "byYear":
|
||||
@@ -157,26 +127,17 @@ func (c *Controller) GetAlbumListTwo(w http.ResponseWriter, r *http.Request) {
|
||||
))
|
||||
return
|
||||
}
|
||||
var albums []*model.Album
|
||||
var albums []model.Album
|
||||
q.
|
||||
Offset(getIntParamOr(r, "offset", 0)).
|
||||
Limit(getIntParamOr(r, "size", 10)).
|
||||
Preload("AlbumArtist").
|
||||
Preload("Artist").
|
||||
Find(&albums)
|
||||
listObj := []*subsonic.Album{}
|
||||
for _, album := range albums {
|
||||
listObj = append(listObj, &subsonic.Album{
|
||||
ID: album.ID,
|
||||
Name: album.Title,
|
||||
Created: album.CreatedAt,
|
||||
CoverID: album.CoverID,
|
||||
Artist: album.AlbumArtist.Name,
|
||||
ArtistID: album.AlbumArtist.ID,
|
||||
})
|
||||
}
|
||||
sub := subsonic.NewResponse()
|
||||
sub.AlbumsTwo = &subsonic.Albums{
|
||||
List: listObj,
|
||||
sub.AlbumsTwo = &subsonic.Albums{}
|
||||
for _, album := range albums {
|
||||
sub.AlbumsTwo.List = append(sub.AlbumsTwo.List,
|
||||
makeAlbumFromAlbum(&album, &album.Artist))
|
||||
}
|
||||
respond(w, r, sub)
|
||||
}
|
||||
|
||||
@@ -96,14 +96,14 @@ func (c *Controller) Scrobble(w http.ResponseWriter, r *http.Request) {
|
||||
// fetch user to get lastfm session
|
||||
user := r.Context().Value(contextUserKey).(*model.User)
|
||||
if user.LastFMSession == "" {
|
||||
respondError(w, r, 0, fmt.Sprintf("no last.fm session for this user: %v", err))
|
||||
respondError(w, r, 0, "you don't have a last.fm session")
|
||||
return
|
||||
}
|
||||
// fetch track for getting info to send to last.fm function
|
||||
var track model.Track
|
||||
c.DB.
|
||||
Preload("Album").
|
||||
Preload("AlbumArtist").
|
||||
Preload("Artist").
|
||||
First(&track, id)
|
||||
// scrobble with above info
|
||||
err = lastfm.Scrobble(
|
||||
|
||||
@@ -33,12 +33,12 @@ func checkCredentialsToken(password, token, salt string) bool {
|
||||
return token == expToken
|
||||
}
|
||||
|
||||
func checkCredentialsBasic(password, givenPassword string) bool {
|
||||
if givenPassword[:4] == "enc:" {
|
||||
bytes, _ := hex.DecodeString(givenPassword[4:])
|
||||
givenPassword = string(bytes)
|
||||
func checkCredentialsBasic(password, given string) bool {
|
||||
if given[:4] == "enc:" {
|
||||
bytes, _ := hex.DecodeString(given[4:])
|
||||
given = string(bytes)
|
||||
}
|
||||
return password == givenPassword
|
||||
return password == given
|
||||
}
|
||||
|
||||
func (c *Controller) WithValidSubsonicArgs(next http.HandlerFunc) http.HandlerFunc {
|
||||
@@ -62,7 +62,6 @@ func (c *Controller) WithValidSubsonicArgs(next http.HandlerFunc) http.HandlerFu
|
||||
}
|
||||
user := c.GetUserFromName(username)
|
||||
if user == nil {
|
||||
// the user does not exist
|
||||
respondError(w, r, 40, "invalid username")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -48,10 +48,10 @@ func Scrobble(apiKey, secret, session string, track *model.Track,
|
||||
}
|
||||
params.Add("api_key", apiKey)
|
||||
params.Add("sk", session)
|
||||
params.Add("artist", track.Artist)
|
||||
params.Add("artist", track.TrackArtist)
|
||||
params.Add("track", track.Title)
|
||||
params.Add("album", track.Album.Title)
|
||||
params.Add("albumArtist", track.AlbumArtist.Name)
|
||||
params.Add("albumArtist", track.Artist.Name)
|
||||
params.Add("trackNumber", strconv.Itoa(track.TrackNumber))
|
||||
params.Add("api_sig", getParamSignature(params, secret))
|
||||
_, err := makeRequest("POST", params)
|
||||
|
||||
23
server/lastfm/lastfm_test.go
Normal file
23
server/lastfm/lastfm_test.go
Normal file
@@ -0,0 +1,23 @@
|
||||
package lastfm
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestGetParamSignature(t *testing.T) {
|
||||
params := url.Values{}
|
||||
params.Add("ccc", "CCC")
|
||||
params.Add("bbb", "BBB")
|
||||
params.Add("aaa", "AAA")
|
||||
params.Add("ddd", "DDD")
|
||||
actual := getParamSignature(params, "secret")
|
||||
expected := fmt.Sprintf("%x", md5.Sum([]byte(
|
||||
"aaaAAAbbbBBBcccCCCdddDDDsecret",
|
||||
)))
|
||||
if actual != expected {
|
||||
t.Errorf("expected %x, got %s", expected, actual)
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
package subsonic
|
||||
|
||||
import "time"
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
type Albums struct {
|
||||
List []*Album `xml:"album" json:"album,omitempty"`
|
||||
@@ -30,26 +32,26 @@ type RandomTracks struct {
|
||||
}
|
||||
|
||||
type Track struct {
|
||||
ID int `xml:"id,attr,omitempty" json:"id"`
|
||||
Parent int `xml:"parent,attr,omitempty" json:"parent"`
|
||||
Title string `xml:"title,attr,omitempty" json:"title"`
|
||||
Album string `xml:"album,attr,omitempty" json:"album"`
|
||||
Artist string `xml:"artist,attr,omitempty" json:"artist"`
|
||||
IsDir bool `xml:"isDir,attr,omitempty" json:"isDir"`
|
||||
CoverID int `xml:"coverArt,attr,omitempty" json:"coverArt"`
|
||||
Created time.Time `xml:"created,attr,omitempty" json:"created"`
|
||||
Duration int `xml:"duration,attr,omitempty" json:"duration"`
|
||||
Genre string `xml:"genre,attr,omitempty" json:"genre"`
|
||||
Bitrate int `xml:"bitRate,attr,omitempty" json:"bitRate"`
|
||||
Size int `xml:"size,attr,omitempty" json:"size"`
|
||||
Suffix string `xml:"suffix,attr,omitempty" json:"suffix"`
|
||||
ContentType string `xml:"contentType,attr,omitempty" json:"contentType"`
|
||||
IsVideo bool `xml:"isVideo,attr,omitempty" json:"isVideo"`
|
||||
Path string `xml:"path,attr,omitempty" json:"path"`
|
||||
AlbumID int `xml:"albumId,attr,omitempty" json:"albumId"`
|
||||
ArtistID int `xml:"artistId,attr,omitempty" json:"artistId"`
|
||||
TrackNo int `xml:"track,attr,omitempty" json:"track"`
|
||||
Type string `xml:"type,attr,omitempty" json:"type"`
|
||||
ID int `xml:"id,attr,omitempty" json:"id"`
|
||||
Parent int `xml:"parent,attr,omitempty" json:"parent"`
|
||||
Title string `xml:"title,attr,omitempty" json:"title"`
|
||||
Album string `xml:"album,attr,omitempty" json:"album"`
|
||||
Artist string `xml:"artist,attr,omitempty" json:"artist"`
|
||||
IsDir bool `xml:"isDir,attr,omitempty" json:"isDir"`
|
||||
CoverID int `xml:"coverArt,attr,omitempty" json:"coverArt"`
|
||||
CreatedAt time.Time `xml:"created,attr,omitempty" json:"created"`
|
||||
Duration int `xml:"duration,attr,omitempty" json:"duration"`
|
||||
Genre string `xml:"genre,attr,omitempty" json:"genre"`
|
||||
Bitrate int `xml:"bitRate,attr,omitempty" json:"bitRate"`
|
||||
Size int `xml:"size,attr,omitempty" json:"size"`
|
||||
Suffix string `xml:"suffix,attr,omitempty" json:"suffix"`
|
||||
ContentType string `xml:"contentType,attr,omitempty" json:"contentType"`
|
||||
IsVideo bool `xml:"isVideo,attr,omitempty" json:"isVideo"`
|
||||
Path string `xml:"path,attr,omitempty" json:"path"`
|
||||
AlbumID int `xml:"albumId,attr,omitempty" json:"albumId"`
|
||||
ArtistID int `xml:"artistId,attr,omitempty" json:"artistId"`
|
||||
TrackNumber int `xml:"track,attr,omitempty" json:"track"`
|
||||
Type string `xml:"type,attr,omitempty" json:"type"`
|
||||
}
|
||||
|
||||
type Artists struct {
|
||||
@@ -84,7 +86,7 @@ type Directory struct {
|
||||
|
||||
type Child struct {
|
||||
ID int `xml:"id,attr,omitempty" json:"id,omitempty"`
|
||||
Parent int `xml:"parent,attr,omitempty" json:"parent,omitempty"`
|
||||
ParentID int `xml:"parent,attr,omitempty" json:"parent,omitempty"`
|
||||
Title string `xml:"title,attr,omitempty" json:"title,omitempty"`
|
||||
IsDir bool `xml:"isDir,attr,omitempty" json:"isDir,omitempty"`
|
||||
Album string `xml:"album,attr,omitempty" json:"album,omitempty"`
|
||||
|
||||
Reference in New Issue
Block a user