diff --git a/api/tracks.go b/api/tracks.go index f47af77..60a3dc2 100644 --- a/api/tracks.go +++ b/api/tracks.go @@ -3,6 +3,9 @@ package api import ( "fmt" "net/http" + "os" + "path" + "strings" "github.com/gin-gonic/gin" @@ -21,7 +24,43 @@ func declareTracksRoutes(cfg *config.Config, router *gin.RouterGroup) { c.JSON(http.StatusOK, tracks) }) router.POST("/tracks", func(c *gin.Context) { - c.AbortWithStatusJSON(http.StatusNotImplemented, gin.H{"errmsg": "TODO"}) + ftrack, err := c.FormFile("trackfile") + if err != nil { + c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": "No track found"}) + return + } + + // Check file extension + if path.Ext(ftrack.Filename) != ".mp3" && path.Ext(ftrack.Filename) != ".flac" { + c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": "Bad file type. You should only upload .mp3 or .flac files."}) + return + } + + if strings.Contains(ftrack.Filename, "/") { + c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": "Bad file name."}) + return + } + + dst := path.Join(cfg.TracksDir, ftrack.Filename) + err = c.SaveUploadedFile(ftrack, dst) + if err != nil { + c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": fmt.Sprintf("Something goes wrong when saving the track: %s", err.Error())}) + return + } + + d, err := os.Stat(dst) + if err != nil { + c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": fmt.Sprintf("Something goes wrong when saving the track: %s", err.Error())}) + return + } + + track, err := reveil.LoadTrack(dst, d) + if err != nil { + c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": fmt.Sprintf("Unable to load track: %s", err.Error())}) + return + } + + c.JSON(http.StatusOK, track) }) tracksRoutes := router.Group("/tracks/:tid") diff --git a/model/track.go b/model/track.go index 5aadc86..6565142 100644 --- a/model/track.go +++ b/model/track.go @@ -18,6 +18,16 @@ type Track struct { Enabled bool `json:"enabled"` } +func LoadTrack(path string, d fs.FileInfo) (track *Track, err error) { + hash := sha512.Sum512([]byte(path)) + return &Track{ + Id: hash[:], + Name: strings.TrimSuffix(d.Name(), filepath.Ext(d.Name())), + Path: path, + Enabled: len(strings.Split(path, "/")) == 2, + }, nil +} + func LoadTracks(cfg *config.Config) (tracks []*Track, err error) { err = filepath.Walk(cfg.TracksDir, func(path string, d fs.FileInfo, err error) error { if d.Mode().IsRegular() { diff --git a/ui/src/lib/track.js b/ui/src/lib/track.js index a056409..559dc2f 100644 --- a/ui/src/lib/track.js +++ b/ui/src/lib/track.js @@ -46,6 +46,25 @@ export class Track { } } +export async function uploadTrack(files, meta) { + for (const file of files) { + const formData = new FormData(); + formData.append("trackfile", file); + formData.append("meta", JSON.stringify(meta)); + + const res = await fetch('/api/tracks', { + method: 'POST', + body: formData, + }); + if (res.ok) { + const data = await res.json(); + return new Track(data) + } else { + throw new Error((await res.json()).errmsg); + } + } +} + export async function getTracks() { const res = await fetch(`api/tracks`, {headers: {'Accept': 'application/json'}}) if (res.status == 200) { diff --git a/ui/src/routes/musiks/tracks/new/+page.svelte b/ui/src/routes/musiks/tracks/new/+page.svelte index ff4047f..98b302c 100644 --- a/ui/src/routes/musiks/tracks/new/+page.svelte +++ b/ui/src/routes/musiks/tracks/new/+page.svelte @@ -1,3 +1,45 @@ -