Files
gonic/server/ctrlsubsonic/handlers_common.go
2019-11-24 23:09:48 +00:00

231 lines
5.8 KiB
Go

package ctrlsubsonic
import (
"log"
"net/http"
"strconv"
"time"
"unicode"
"github.com/jinzhu/gorm"
"senan.xyz/g/gonic/model"
"senan.xyz/g/gonic/scanner"
"senan.xyz/g/gonic/server/ctrlsubsonic/spec"
"senan.xyz/g/gonic/server/key"
"senan.xyz/g/gonic/server/lastfm"
"senan.xyz/g/gonic/server/parsing"
)
func lowerUDecOrHash(in string) string {
lower := unicode.ToLower(rune(in[0]))
if !unicode.IsLetter(lower) {
return "#"
}
return string(lower)
}
func (c *Controller) ServeGetLicence(r *http.Request) *spec.Response {
sub := spec.NewResponse()
sub.Licence = &spec.Licence{
Valid: true,
}
return sub
}
func (c *Controller) ServePing(r *http.Request) *spec.Response {
return spec.NewResponse()
}
func (c *Controller) ServeScrobble(r *http.Request) *spec.Response {
id, err := parsing.GetIntParam(r, "id")
if err != nil {
return spec.NewError(10, "please provide an `id` parameter")
}
// fetch user to get lastfm session
user := r.Context().Value(key.User).(*model.User)
if user.LastFMSession == "" {
return spec.NewError(0, "you don't have a last.fm session")
}
// fetch track for getting info to send to last.fm function
track := &model.Track{}
c.DB.
Preload("Album").
Preload("Artist").
First(track, id)
// scrobble with above info
err = lastfm.Scrobble(
c.DB.GetSetting("lastfm_api_key"),
c.DB.GetSetting("lastfm_secret"),
user.LastFMSession,
track,
// clients will provide time in miliseconds, so use that or
// instead convert UnixNano to miliseconds
parsing.GetIntParamOr(r, "time", int(time.Now().UnixNano()/1e6)),
parsing.GetStrParamOr(r, "submission", "true") != "false",
)
if err != nil {
return spec.NewError(0, "error when submitting: %v", err)
}
return spec.NewResponse()
}
func (c *Controller) ServeGetMusicFolders(r *http.Request) *spec.Response {
folders := &spec.MusicFolders{}
folders.List = []*spec.MusicFolder{
{ID: 1, Name: "music"},
}
sub := spec.NewResponse()
sub.MusicFolders = folders
return sub
}
func (c *Controller) ServeStartScan(r *http.Request) *spec.Response {
go func() {
if err := c.Scanner.Start(); err != nil {
log.Printf("error while scanning: %v\n", err)
}
}()
return c.ServeGetScanStatus(r)
}
func (c *Controller) ServeGetScanStatus(r *http.Request) *spec.Response {
var trackCount int
c.DB.
Model(model.Track{}).
Count(&trackCount)
sub := spec.NewResponse()
sub.ScanStatus = &spec.ScanStatus{
Scanning: scanner.IsScanning(),
Count: trackCount,
}
return sub
}
func (c *Controller) ServeGetUser(r *http.Request) *spec.Response {
user := r.Context().Value(key.User).(*model.User)
sub := spec.NewResponse()
sub.User = &spec.User{
Username: user.Name,
AdminRole: user.IsAdmin,
ScrobblingEnabled: user.LastFMSession != "",
Folder: []int{1},
}
return sub
}
func (c *Controller) ServeNotFound(r *http.Request) *spec.Response {
return spec.NewError(70, "view not found")
}
func (c *Controller) ServeGetPlaylists(r *http.Request) *spec.Response {
user := r.Context().Value(key.User).(*model.User)
var playlists []*model.Playlist
c.DB.
Where("user_id = ?", user.ID).
Find(&playlists)
sub := spec.NewResponse()
sub.Playlists = &spec.Playlists{
List: make([]*spec.Playlist, len(playlists)),
}
for i, playlist := range playlists {
sub.Playlists.List[i] = spec.NewPlaylist(playlist)
sub.Playlists.List[i].Owner = user.Name
}
return sub
}
func (c *Controller) ServeGetPlaylist(r *http.Request) *spec.Response {
playlistID, err := parsing.GetIntParam(r, "id")
if err != nil {
return spec.NewError(10, "please provide an `id` parameter")
}
playlist := model.Playlist{}
err = c.DB.
Where("id = ?", playlistID).
Find(&playlist).
Error
if gorm.IsRecordNotFoundError(err) {
return spec.NewError(70, "playlist with id `%d` not found", playlistID)
}
var tracks []*model.Track
c.DB.
Joins(`
JOIN playlist_items
ON playlist_items.track_id = tracks.id
`).
Where("playlist_items.playlist_id = ?", playlistID).
Group("tracks.id").
Order("playlist_items.created_at").
Preload("Album").
Find(&tracks)
user := r.Context().Value(key.User).(*model.User)
sub := spec.NewResponse()
sub.Playlist = spec.NewPlaylist(&playlist)
sub.Playlist.Owner = user.Name
sub.Playlist.List = make([]*spec.TrackChild, len(tracks))
for i, track := range tracks {
sub.Playlist.List[i] = spec.NewTCTrackByFolder(track, track.Album)
}
return sub
}
func (c *Controller) ServeUpdatePlaylist(r *http.Request) *spec.Response {
playlistID, _ := parsing.GetFirstIntParamOf(r, "id", "playlistId")
//
// begin updating meta
playlist := &model.Playlist{}
c.DB.
Where("id = ?", playlistID).
First(playlist)
user := r.Context().Value(key.User).(*model.User)
playlist.UserID = user.ID
if name := parsing.GetStrParam(r, "name"); name != "" {
playlist.Name = name
}
if comment := parsing.GetStrParam(r, "comment"); comment != "" {
playlist.Comment = comment
}
c.DB.Save(playlist)
//
// begin delete tracks
if indexes, ok := r.URL.Query()["songIndexToRemove"]; ok {
trackIDs := []int{}
c.DB.
Order("created_at").
Model(&model.PlaylistItem{}).
Where("playlist_id = ?", playlistID).
Pluck("track_id", &trackIDs)
for _, indexStr := range indexes {
i, err := strconv.Atoi(indexStr)
if err != nil {
continue
}
c.DB.Delete(&model.PlaylistItem{},
"track_id = ?", trackIDs[i])
}
}
//
// begin add tracks
if toAdd := parsing.GetFirstParamOf(r, "songId", "songIdToAdd"); toAdd != nil {
for _, trackIDStr := range toAdd {
trackID, err := strconv.Atoi(trackIDStr)
if err != nil {
continue
}
c.DB.Save(&model.PlaylistItem{
PlaylistID: playlist.ID,
TrackID: trackID,
})
}
}
return spec.NewResponse()
}
func (c *Controller) ServeDeletePlaylist(r *http.Request) *spec.Response {
c.DB.
Where("id = ?", parsing.GetIntParamOr(r, "id", 0)).
Delete(&model.Playlist{})
return spec.NewResponse()
}