No description provided.
{{else}}
diff --git a/admin/views/index.html b/admin/views/index.html
index 8847492..36dff67 100644
--- a/admin/views/index.html
+++ b/admin/views/index.html
@@ -9,7 +9,7 @@
{{range $Release := .Releases}}
@@ -93,5 +93,6 @@
-
+
+
{{end}}
diff --git a/api/release.go b/api/release.go
index 6d02733..2064fb0 100644
--- a/api/release.go
+++ b/api/release.go
@@ -1,9 +1,14 @@
package api
import (
+ "bufio"
+ "encoding/base64"
"encoding/json"
"fmt"
+ "io/fs"
"net/http"
+ "os"
+ "path/filepath"
"strings"
"time"
@@ -85,40 +90,53 @@ func CreateRelease() http.Handler {
http.Error(w, "Release ID cannot be empty\n", http.StatusBadRequest)
return
}
- if *data.Title == "" {
- http.Error(w, "Release title cannot be empty\n", http.StatusBadRequest)
- return
+
+ title := data.ID
+ if data.Title != nil && *data.Title != "" {
+ title = *data.Title
}
- if data.Buyname == nil || *data.Buyname == "" { *data.Buyname = "buy" }
- if data.Buylink == nil || *data.Buylink == "" { *data.Buylink = "https://arimelody.me" }
+
+ description := ""
+ if data.Description != nil && *data.Description != "" { description = *data.Description }
+
+ releaseType := model.Single
+ if data.ReleaseType != nil && *data.ReleaseType != "" { releaseType = *data.ReleaseType }
+
+ releaseDate := time.Time{}
+ if data.ReleaseDate != nil && *data.ReleaseDate != "" {
+ releaseDate, err = time.Parse("2006-01-02T15:04", *data.ReleaseDate)
+ if err != nil {
+ http.Error(w, "Invalid release date", http.StatusBadRequest)
+ return
+ }
+ } else {
+ releaseDate = time.Date(time.Now().Year(), time.Now().Month(), time.Now().Day(), 0, 0, 0, 0, time.UTC)
+ }
+
+ artwork := "/img/default-cover-art.png"
+ if data.Artwork != nil && *data.Artwork != "" { artwork = *data.Artwork }
+
+ buyname := ""
+ if data.Buyname != nil && *data.Buyname != "" { buyname = *data.Buyname }
+
+ buylink := ""
+ if data.Buylink != nil && *data.Buylink != "" { buylink = *data.Buylink }
if global.GetRelease(data.ID) != nil {
http.Error(w, fmt.Sprintf("Release %s already exists\n", data.ID), http.StatusBadRequest)
return
}
- releaseDate := time.Time{}
- if *data.ReleaseDate == "" {
- http.Error(w, "Release date cannot be empty\n", http.StatusBadRequest)
- return
- } else if data.ReleaseDate != nil {
- releaseDate, err = time.Parse("2006-01-02T15:04", *data.ReleaseDate)
- if err != nil {
- http.Error(w, "Invalid release date", http.StatusBadRequest)
- return
- }
- }
-
var release = model.Release{
ID: data.ID,
- Visible: *data.Visible,
- Title: *data.Title,
- Description: *data.Description,
- ReleaseType: *data.ReleaseType,
+ Visible: false,
+ Title: title,
+ Description: description,
+ ReleaseType: releaseType,
ReleaseDate: releaseDate,
- Artwork: *data.Artwork,
- Buyname: *data.Buyname,
- Buylink: *data.Buylink,
+ Artwork: artwork,
+ Buyname: buyname,
+ Buylink: buylink,
Links: []*model.Link{},
Credits: []*model.Credit{},
Tracks: []*model.Track{},
@@ -181,7 +199,69 @@ func UpdateRelease() http.Handler {
}
update.ReleaseDate = newDate
}
- if data.Artwork != nil { update.Artwork = *data.Artwork }
+ if data.Artwork != nil {
+ if strings.Contains(*data.Artwork, ";base64,") {
+ split := strings.Split(*data.Artwork, ";base64,")
+ header := split[0]
+ imageData, err := base64.StdEncoding.DecodeString(split[1])
+ ext, _ := strings.CutPrefix(header, "data:image/")
+
+ switch ext {
+ case "png":
+ case "jpg":
+ case "jpeg":
+ default:
+ http.Error(w, "Invalid image type. Allowed: .png, .jpg, .jpeg", http.StatusBadRequest)
+ return
+ }
+
+ artworkDirectory := filepath.Join("uploads", "musicart")
+ // ensure directory exists
+ os.MkdirAll(artworkDirectory, os.ModePerm)
+
+ imagePath := filepath.Join(artworkDirectory, fmt.Sprintf("%s.%s", update.ID, ext))
+ file, err := os.Create(imagePath)
+ if err != nil {
+ fmt.Printf("FATAL: Failed to create file %s: %s\n", imagePath, err)
+ http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
+ return
+ }
+
+ defer file.Close()
+
+ buffer := bufio.NewWriter(file)
+ _, err = buffer.Write(imageData)
+ if err != nil {
+ fmt.Printf("FATAL: Failed to write to file %s: %s\n", imagePath, err)
+ http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
+ return
+ }
+
+ if err := buffer.Flush(); err != nil {
+ fmt.Printf("FATAL: Failed to flush data to file %s: %s\n", imagePath, err)
+ http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
+ return
+ }
+
+ // clean up files with this ID and different extensions
+ err = filepath.Walk(artworkDirectory, func(path string, info fs.FileInfo, err error) error {
+ if path == imagePath { return nil }
+
+ withoutExt := strings.TrimSuffix(path, filepath.Ext(path))
+ if withoutExt != filepath.Join(artworkDirectory, update.ID) { return nil }
+
+ return os.Remove(path)
+ })
+ if err != nil {
+ fmt.Printf("WARN: Error while cleaning up artwork files: %s\n", err)
+ }
+
+ fmt.Printf("Artwork for %s updated.\n", update.ID)
+ update.Artwork = fmt.Sprintf("/uploads/musicart/%s.%s", update.ID, ext)
+ } else {
+ update.Artwork = *data.Artwork
+ }
+ }
if data.Buyname != nil {
if *data.Buyname == "" {
http.Error(w, "Release buy name cannot be empty", http.StatusBadRequest)
diff --git a/music/controller/release.go b/music/controller/release.go
index 9e70aa7..167f4b6 100644
--- a/music/controller/release.go
+++ b/music/controller/release.go
@@ -47,7 +47,7 @@ func PullReleaseTracksDB(db *sqlx.DB, release *model.Release) ([]*model.Track, e
err := db.Select(&track_rows,
"SELECT track FROM musicreleasetrack "+
"WHERE release=$1 "+
- "ORDER BY number DESC",
+ "ORDER BY number ASC",
release.ID,
)
if err != nil {
diff --git a/music/view/release.go b/music/view/release.go
index 634c481..6b9b181 100644
--- a/music/view/release.go
+++ b/music/view/release.go
@@ -86,11 +86,11 @@ func ServeGateway() http.Handler {
tracks := []gatewayTrack{}
for i, track := range release.Tracks {
- tracks = append([]gatewayTrack{{
+ tracks = append(tracks, gatewayTrack{
Track: track,
Lyrics: template.HTML(strings.Replace(track.Lyrics, "\n", "
", -1)),
- Number: len(release.Tracks) - i,
- }}, tracks...)
+ Number: i + 1,
+ })
}
lrw := global.LoggingResponseWriter{ResponseWriter: w, Code: http.StatusOK}
diff --git a/public/img/list-grabber.svg b/public/img/list-grabber.svg
new file mode 100644
index 0000000..58eb280
--- /dev/null
+++ b/public/img/list-grabber.svg
@@ -0,0 +1,6 @@
+
+
+
diff --git a/res/list-grabber.afdesign b/res/list-grabber.afdesign
new file mode 100644
index 0000000..9184153
Binary files /dev/null and b/res/list-grabber.afdesign differ
diff --git a/res/list-grabber.afdesign~lock~ b/res/list-grabber.afdesign~lock~
new file mode 100644
index 0000000..663b6ef
Binary files /dev/null and b/res/list-grabber.afdesign~lock~ differ
diff --git a/views/music-gateway.html b/views/music-gateway.html
index 57e2434..0eb4081 100644
--- a/views/music-gateway.html
+++ b/views/music-gateway.html
@@ -64,6 +64,7 @@
Releases: {{.PrintReleaseDate}}
{{end}}
+ {{if .IsReleased}}
{{if .Buylink}}
-
@@ -77,6 +78,7 @@
{{end}}
+ {{end}}
{{if .Description}}
diff --git a/views/music.html b/views/music.html
index 225a9a9..8e59903 100644
--- a/views/music.html
+++ b/views/music.html
@@ -38,6 +38,7 @@
{{$Release.PrintArtists true true}}
{{$Release.ReleaseType}}
+ {{if $Release.IsReleased}}
{{range $Link := $Release.Links}}
-
@@ -45,6 +46,7 @@
{{end}}
+ {{end}}