Compare commits

..

4 commits

22 changed files with 214 additions and 223 deletions

View file

@ -3,10 +3,11 @@
.air.toml/
.gitattributes
.gitignore
uploads/*
uploads/
test/
tmp/
db/
res/
docker-compose.yml
docker-compose-test.yml
Dockerfile

2
.gitignore vendored
View file

@ -3,5 +3,5 @@
db/
tmp/
test/
uploads/*
uploads/
docker-compose-test.yml

View file

@ -6,15 +6,15 @@ import (
"strings"
"arimelody-web/global"
"arimelody-web/music/model"
"arimelody-web/music/controller"
"arimelody-web/model"
"arimelody-web/controller"
)
func serveArtist() http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
slices := strings.Split(r.URL.Path[1:], "/")
id := slices[0]
artist, err := music.GetArtist(global.DB, id)
artist, err := controller.GetArtist(global.DB, id)
if err != nil {
if artist == nil {
http.NotFound(w, r)
@ -25,7 +25,7 @@ func serveArtist() http.Handler {
return
}
credits, err := music.GetArtistCredits(global.DB, artist.ID, true)
credits, err := controller.GetArtistCredits(global.DB, artist.ID, true)
if err != nil {
fmt.Printf("Error rendering admin track page for %s: %s\n", id, err)
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)

View file

@ -11,8 +11,8 @@ import (
"arimelody-web/discord"
"arimelody-web/global"
musicDB "arimelody-web/music/controller"
musicModel "arimelody-web/music/model"
"arimelody-web/controller"
"arimelody-web/model"
)
type loginData struct {
@ -41,21 +41,21 @@ func Handler() http.Handler {
return
}
releases, err := musicDB.GetAllReleases(global.DB, false, 0, true)
releases, err := controller.GetAllReleases(global.DB, false, 0, true)
if err != nil {
fmt.Printf("FATAL: Failed to pull releases: %s\n", err)
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
artists, err := musicDB.GetAllArtists(global.DB)
artists, err := controller.GetAllArtists(global.DB)
if err != nil {
fmt.Printf("FATAL: Failed to pull artists: %s\n", err)
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
tracks, err := musicDB.GetOrphanTracks(global.DB)
tracks, err := controller.GetOrphanTracks(global.DB)
if err != nil {
fmt.Printf("FATAL: Failed to pull orphan tracks: %s\n", err)
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
@ -63,9 +63,9 @@ func Handler() http.Handler {
}
type IndexData struct {
Releases []*musicModel.Release
Artists []*musicModel.Artist
Tracks []*musicModel.Track
Releases []*model.Release
Artists []*model.Artist
Tracks []*model.Track
}
err = pages["index"].Execute(w, IndexData{

View file

@ -6,8 +6,8 @@ import (
"strings"
"arimelody-web/global"
db "arimelody-web/music/controller"
"arimelody-web/music/model"
"arimelody-web/controller"
"arimelody-web/model"
)
func serveRelease() http.Handler {
@ -15,7 +15,7 @@ func serveRelease() http.Handler {
slices := strings.Split(r.URL.Path[1:], "/")
releaseID := slices[0]
release, err := db.GetRelease(global.DB, releaseID, true)
release, err := controller.GetRelease(global.DB, releaseID, true)
if err != nil {
if strings.Contains(err.Error(), "no rows") {
http.NotFound(w, r)
@ -81,7 +81,7 @@ func serveEditCredits(release *model.Release) http.Handler {
func serveAddCredit(release *model.Release) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
artists, err := db.GetArtistsNotOnRelease(global.DB, release.ID)
artists, err := controller.GetArtistsNotOnRelease(global.DB, release.ID)
if err != nil {
fmt.Printf("FATAL: Failed to pull artists not on %s: %s\n", release.ID, err)
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
@ -108,7 +108,7 @@ func serveAddCredit(release *model.Release) http.Handler {
func serveNewCredit() http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
artistID := strings.Split(r.URL.Path, "/")[3]
artist, err := db.GetArtist(global.DB, artistID)
artist, err := controller.GetArtist(global.DB, artistID)
if err != nil {
fmt.Printf("FATAL: Failed to pull artists %s: %s\n", artistID, err)
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
@ -152,7 +152,7 @@ func serveEditTracks(release *model.Release) http.Handler {
func serveAddTrack(release *model.Release) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
tracks, err := db.GetTracksNotOnRelease(global.DB, release.ID)
tracks, err := controller.GetTracksNotOnRelease(global.DB, release.ID)
if err != nil {
fmt.Printf("FATAL: Failed to pull tracks not on %s: %s\n", release.ID, err)
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
@ -180,7 +180,7 @@ func serveAddTrack(release *model.Release) http.Handler {
func serveNewTrack() http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
trackID := strings.Split(r.URL.Path, "/")[3]
track, err := db.GetTrack(global.DB, trackID)
track, err := controller.GetTrack(global.DB, trackID)
if err != nil {
fmt.Printf("Error rendering new track component for %s: %s\n", trackID, err)
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)

View file

@ -6,15 +6,15 @@ import (
"strings"
"arimelody-web/global"
"arimelody-web/music/model"
"arimelody-web/music/controller"
"arimelody-web/model"
"arimelody-web/controller"
)
func serveTrack() http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
slices := strings.Split(r.URL.Path[1:], "/")
id := slices[0]
track, err := music.GetTrack(global.DB, id)
track, err := controller.GetTrack(global.DB, id)
if err != nil {
fmt.Printf("Error rendering admin track page for %s: %s\n", id, err)
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
@ -25,7 +25,7 @@ func serveTrack() http.Handler {
return
}
releases, err := music.GetTrackReleases(global.DB, track.ID, true)
releases, err := controller.GetTrackReleases(global.DB, track.ID, true)
if err != nil {
fmt.Printf("FATAL: Failed to pull releases for %s: %s\n", id, err)
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)

View file

@ -7,8 +7,7 @@ import (
"arimelody-web/admin"
"arimelody-web/global"
music "arimelody-web/music/controller"
musicView "arimelody-web/music/view"
"arimelody-web/controller"
)
func Handler() http.Handler {
@ -24,7 +23,7 @@ func Handler() http.Handler {
mux.Handle("/v1/artist/", http.StripPrefix("/v1/artist", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
var artistID = strings.Split(r.URL.Path[1:], "/")[0]
artist, err := music.GetArtist(global.DB, artistID)
artist, err := controller.GetArtist(global.DB, artistID)
if err != nil {
if strings.Contains(err.Error(), "no rows") {
http.NotFound(w, r)
@ -66,7 +65,7 @@ func Handler() http.Handler {
mux.Handle("/v1/music/", http.StripPrefix("/v1/music", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
var releaseID = strings.Split(r.URL.Path[1:], "/")[0]
release, err := music.GetRelease(global.DB, releaseID, true)
release, err := controller.GetRelease(global.DB, releaseID, true)
if err != nil {
if strings.Contains(err.Error(), "no rows") {
http.NotFound(w, r)
@ -80,7 +79,7 @@ func Handler() http.Handler {
switch r.Method {
case http.MethodGet:
// GET /api/v1/music/{id}
musicView.ServeRelease(release).ServeHTTP(w, r)
ServeRelease(release).ServeHTTP(w, r)
case http.MethodPut:
// PUT /api/v1/music/{id} (admin)
admin.MustAuthorise(UpdateRelease(release)).ServeHTTP(w, r)
@ -108,7 +107,7 @@ func Handler() http.Handler {
mux.Handle("/v1/track/", http.StripPrefix("/v1/track", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
var trackID = strings.Split(r.URL.Path[1:], "/")[0]
track, err := music.GetTrack(global.DB, trackID)
track, err := controller.GetTrack(global.DB, trackID)
if err != nil {
if strings.Contains(err.Error(), "no rows") {
http.NotFound(w, r)

View file

@ -8,18 +8,18 @@ import (
"os"
"path/filepath"
"strings"
"time"
"arimelody-web/admin"
"arimelody-web/global"
db "arimelody-web/music/controller"
music "arimelody-web/music/controller"
"arimelody-web/music/model"
"arimelody-web/controller"
"arimelody-web/model"
)
func ServeAllArtists() http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
var artists = []*model.Artist{}
artists, err := db.GetAllArtists(global.DB)
artists, err := controller.GetAllArtists(global.DB)
if err != nil {
fmt.Printf("FATAL: Failed to serve all artists: %s\n", err)
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
@ -38,8 +38,12 @@ func ServeArtist(artist *model.Artist) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
type (
creditJSON struct {
Role string `json:"role"`
Primary bool `json:"primary"`
ID string `json:"id"`
Title string `json:"title"`
ReleaseDate time.Time `json:"releaseDate" db:"release_date"`
Artwork string `json:"artwork"`
Role string `json:"role"`
Primary bool `json:"primary"`
}
artistJSON struct {
*model.Artist
@ -50,7 +54,7 @@ func ServeArtist(artist *model.Artist) http.Handler {
show_hidden_releases := admin.GetSession(r) != nil
var dbCredits []*model.Credit
dbCredits, err := db.GetArtistCredits(global.DB, artist.ID, show_hidden_releases)
dbCredits, err := controller.GetArtistCredits(global.DB, artist.ID, show_hidden_releases)
if err != nil {
fmt.Printf("FATAL: Failed to retrieve artist credits for %s: %s\n", artist.ID, err)
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
@ -60,6 +64,10 @@ func ServeArtist(artist *model.Artist) http.Handler {
var credits = map[string]creditJSON{}
for _, credit := range dbCredits {
credits[credit.Release.ID] = creditJSON{
ID: credit.Release.ID,
Title: credit.Release.Title,
ReleaseDate: credit.Release.ReleaseDate,
Artwork: credit.Release.Artwork,
Role: credit.Role,
Primary: credit.Primary,
}
@ -91,7 +99,7 @@ func CreateArtist() http.Handler {
}
if artist.Name == "" { artist.Name = artist.ID }
err = music.CreateArtist(global.DB, &artist)
err = controller.CreateArtist(global.DB, &artist)
if err != nil {
if strings.Contains(err.Error(), "duplicate key") {
http.Error(w, fmt.Sprintf("Artist %s already exists\n", artist.ID), http.StatusBadRequest)
@ -139,7 +147,7 @@ func UpdateArtist(artist *model.Artist) http.Handler {
}
}
err = music.UpdateArtist(global.DB, artist)
err = controller.UpdateArtist(global.DB, artist)
if err != nil {
if strings.Contains(err.Error(), "no rows") {
http.NotFound(w, r)
@ -153,7 +161,7 @@ func UpdateArtist(artist *model.Artist) http.Handler {
func DeleteArtist(artist *model.Artist) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
err := music.DeleteArtist(global.DB, artist.ID)
err := controller.DeleteArtist(global.DB, artist.ID)
if err != nil {
if strings.Contains(err.Error(), "no rows") {
http.NotFound(w, r)

View file

@ -12,13 +12,109 @@ import (
"arimelody-web/admin"
"arimelody-web/global"
music "arimelody-web/music/controller"
"arimelody-web/music/model"
"arimelody-web/controller"
"arimelody-web/model"
)
func ServeRelease(release *model.Release) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// only allow authorised users to view hidden releases
authorised := admin.GetSession(r) != nil
if !authorised && !release.Visible {
http.NotFound(w, r)
return
}
type (
Track struct {
Title string `json:"title"`
Description string `json:"description"`
Lyrics string `json:"lyrics"`
}
Credit struct {
*model.Artist
Role string `json:"role"`
Primary bool `json:"primary"`
}
Release struct {
*model.Release
Tracks []Track `json:"tracks"`
Credits []Credit `json:"credits"`
Links map[string]string `json:"links"`
}
)
response := Release{
Release: release,
Tracks: []Track{},
Credits: []Credit{},
Links: make(map[string]string),
}
if authorised || release.IsReleased() {
// get credits
credits, err := controller.GetReleaseCredits(global.DB, release.ID)
if err != nil {
fmt.Printf("FATAL: Failed to serve release %s: Credits: %s\n", release.ID, err)
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
for _, credit := range credits {
artist, err := controller.GetArtist(global.DB, credit.Artist.ID)
if err != nil {
fmt.Printf("FATAL: Failed to serve release %s: Artists: %s\n", release.ID, err)
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
response.Credits = append(response.Credits, Credit{
Artist: artist,
Role: credit.Role,
Primary: credit.Primary,
})
}
// get tracks
tracks, err := controller.GetReleaseTracks(global.DB, release.ID)
if err != nil {
fmt.Printf("FATAL: Failed to serve release %s: Tracks: %s\n", release.ID, err)
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
for _, track := range tracks {
response.Tracks = append(response.Tracks, Track{
Title: track.Title,
Description: track.Description,
Lyrics: track.Lyrics,
})
}
// get links
links, err := controller.GetReleaseLinks(global.DB, release.ID)
if err != nil {
fmt.Printf("FATAL: Failed to serve release %s: Links: %s\n", release.ID, err)
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
for _, link := range links {
response.Links[link.Name] = link.URL
}
}
w.Header().Add("Content-Type", "application/json")
err := json.NewEncoder(w).Encode(response)
if err != nil {
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
})
}
func ServeCatalog() http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
releases, err := music.GetAllReleases(global.DB, false, 0, true)
releases, err := controller.GetAllReleases(global.DB, false, 0, true)
if err != nil {
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
@ -95,7 +191,7 @@ func CreateRelease() http.Handler {
if release.Artwork == "" { release.Artwork = "/img/default-cover-art.png" }
err = music.CreateRelease(global.DB, &release)
err = controller.CreateRelease(global.DB, &release)
if err != nil {
if strings.Contains(err.Error(), "duplicate key") {
http.Error(w, fmt.Sprintf("Release %s already exists\n", release.ID), http.StatusBadRequest)
@ -173,7 +269,7 @@ func UpdateRelease(release *model.Release) http.Handler {
}
}
err = music.UpdateRelease(global.DB, release)
err = controller.UpdateRelease(global.DB, release)
if err != nil {
if strings.Contains(err.Error(), "no rows") {
http.NotFound(w, r)
@ -194,7 +290,7 @@ func UpdateReleaseTracks(release *model.Release) http.Handler {
return
}
err = music.UpdateReleaseTracks(global.DB, release.ID, trackIDs)
err = controller.UpdateReleaseTracks(global.DB, release.ID, trackIDs)
if err != nil {
if strings.Contains(err.Error(), "no rows") {
http.NotFound(w, r)
@ -231,7 +327,7 @@ func UpdateReleaseCredits(release *model.Release) http.Handler {
})
}
err = music.UpdateReleaseCredits(global.DB, release.ID, credits)
err = controller.UpdateReleaseCredits(global.DB, release.ID, credits)
if err != nil {
if strings.Contains(err.Error(), "duplicate key") {
http.Error(w, "Artists may only be credited once\n", http.StatusBadRequest)
@ -261,7 +357,7 @@ func UpdateReleaseLinks(release *model.Release) http.Handler {
return
}
err = music.UpdateReleaseLinks(global.DB, release.ID, links)
err = controller.UpdateReleaseLinks(global.DB, release.ID, links)
if err != nil {
if strings.Contains(err.Error(), "no rows") {
http.NotFound(w, r)
@ -275,7 +371,7 @@ func UpdateReleaseLinks(release *model.Release) http.Handler {
func DeleteRelease(release *model.Release) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
err := music.DeleteRelease(global.DB, release.ID)
err := controller.DeleteRelease(global.DB, release.ID)
if err != nil {
if strings.Contains(err.Error(), "no rows") {
http.NotFound(w, r)

View file

@ -6,8 +6,8 @@ import (
"net/http"
"arimelody-web/global"
music "arimelody-web/music/controller"
"arimelody-web/music/model"
"arimelody-web/controller"
"arimelody-web/model"
)
type (
@ -26,7 +26,7 @@ func ServeAllTracks() http.Handler {
var tracks = []Track{}
var dbTracks = []*model.Track{}
dbTracks, err := music.GetAllTracks(global.DB)
dbTracks, err := controller.GetAllTracks(global.DB)
if err != nil {
fmt.Printf("FATAL: Failed to pull tracks from DB: %s\n", err)
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
@ -50,7 +50,7 @@ func ServeAllTracks() http.Handler {
func ServeTrack(track *model.Track) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
dbReleases, err := music.GetTrackReleases(global.DB, track.ID, false)
dbReleases, err := controller.GetTrackReleases(global.DB, track.ID, false)
if err != nil {
fmt.Printf("FATAL: Failed to pull track releases for %s from DB: %s\n", track.ID, err)
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
@ -89,7 +89,7 @@ func CreateTrack() http.Handler {
return
}
id, err := music.CreateTrack(global.DB, &track)
id, err := controller.CreateTrack(global.DB, &track)
if err != nil {
fmt.Printf("FATAL: Failed to create track: %s\n", err)
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
@ -120,7 +120,7 @@ func UpdateTrack(track *model.Track) http.Handler {
return
}
err = music.UpdateTrack(global.DB, track)
err = controller.UpdateTrack(global.DB, track)
if err != nil {
fmt.Printf("Failed to update track %s: %s\n", track.ID, err)
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
@ -143,7 +143,7 @@ func DeleteTrack(track *model.Track) http.Handler {
}
var trackID = r.URL.Path[1:]
err := music.DeleteTrack(global.DB, trackID)
err := controller.DeleteTrack(global.DB, trackID)
if err != nil {
fmt.Printf("Failed to delete track %s: %s\n", trackID, err)
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)

View file

@ -1,7 +1,7 @@
package music
package controller
import (
"arimelody-web/music/model"
"arimelody-web/model"
"github.com/jmoiron/sqlx"
)
@ -45,7 +45,7 @@ func GetArtistsNotOnRelease(db *sqlx.DB, releaseID string) ([]*model.Artist, err
}
func GetArtistCredits(db *sqlx.DB, artistID string, show_hidden bool) ([]*model.Credit, error) {
var query string = "SELECT release.id,release.title,release.artwork,artist.id,artist.name,artist.website,artist.avatar,role,is_primary "+
var query string = "SELECT release.id,title,artwork,release_date,artist.id,name,website,avatar,role,is_primary "+
"FROM musiccredit "+
"JOIN musicrelease AS release ON release=release.id "+
"JOIN artist ON artist=artist.id "+
@ -69,6 +69,7 @@ func GetArtistCredits(db *sqlx.DB, artistID string, show_hidden bool) ([]*model.
&credit.Release.ID,
&credit.Release.Title,
&credit.Release.Artwork,
&credit.Release.ReleaseDate,
&credit.Artist.ID,
&credit.Artist.Name,
&credit.Artist.Website,

View file

@ -1,10 +1,10 @@
package music
package controller
import (
"errors"
"fmt"
"arimelody-web/music/model"
"arimelody-web/model"
"github.com/jmoiron/sqlx"
)

View file

@ -1,7 +1,7 @@
package music
package controller
import (
"arimelody-web/music/model"
"arimelody-web/model"
"github.com/jmoiron/sqlx"
)

View file

@ -13,7 +13,7 @@ import (
"arimelody-web/admin"
"arimelody-web/api"
"arimelody-web/global"
musicView "arimelody-web/music/view"
"arimelody-web/view"
"arimelody-web/templates"
"github.com/jmoiron/sqlx"
@ -210,7 +210,7 @@ func createServeMux() *http.ServeMux {
mux.Handle("/admin/", http.StripPrefix("/admin", admin.Handler()))
mux.Handle("/api/", http.StripPrefix("/api", api.Handler()))
mux.Handle("/music/", http.StripPrefix("/music", musicView.Handler()))
mux.Handle("/music/", http.StripPrefix("/music", view.MusicHandler()))
mux.Handle("/uploads/", http.StripPrefix("/uploads", staticHandler("uploads")))
mux.Handle("/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path == "/" || r.URL.Path == "/index.html" {

View file

@ -1,136 +0,0 @@
package view
import (
"encoding/json"
"fmt"
"net/http"
"arimelody-web/admin"
"arimelody-web/global"
"arimelody-web/music/model"
db "arimelody-web/music/controller"
"arimelody-web/templates"
)
type (
Track struct {
Title string `json:"title"`
Description string `json:"description"`
Lyrics string `json:"lyrics"`
}
Credit struct {
*model.Artist
Role string `json:"role"`
Primary bool `json:"primary"`
}
Release struct {
*model.Release
Tracks []Track `json:"tracks"`
Credits []Credit `json:"credits"`
Links map[string]string `json:"links"`
}
)
func ServeRelease(release *model.Release) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// only allow authorised users to view hidden releases
authorised := admin.GetSession(r) != nil
if !authorised && !release.Visible {
http.NotFound(w, r)
return
}
response := Release{
Release: release,
Tracks: []Track{},
Credits: []Credit{},
Links: make(map[string]string),
}
if authorised || release.IsReleased() {
// get credits
credits, err := db.GetReleaseCredits(global.DB, release.ID)
if err != nil {
fmt.Printf("FATAL: Failed to serve release %s: Credits: %s\n", release.ID, err)
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
for _, credit := range credits {
artist, err := db.GetArtist(global.DB, credit.Artist.ID)
if err != nil {
fmt.Printf("FATAL: Failed to serve release %s: Artists: %s\n", release.ID, err)
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
response.Credits = append(response.Credits, Credit{
Artist: artist,
Role: credit.Role,
Primary: credit.Primary,
})
}
// get tracks
tracks, err := db.GetReleaseTracks(global.DB, release.ID)
if err != nil {
fmt.Printf("FATAL: Failed to serve release %s: Tracks: %s\n", release.ID, err)
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
for _, track := range tracks {
response.Tracks = append(response.Tracks, Track{
Title: track.Title,
Description: track.Description,
Lyrics: track.Lyrics,
})
}
// get links
links, err := db.GetReleaseLinks(global.DB, release.ID)
if err != nil {
fmt.Printf("FATAL: Failed to serve release %s: Links: %s\n", release.ID, err)
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
for _, link := range links {
response.Links[link.Name] = link.URL
}
}
w.Header().Add("Content-Type", "application/json")
err := json.NewEncoder(w).Encode(response)
if err != nil {
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
})
}
func ServeGateway(release *model.Release) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// only allow authorised users to view hidden releases
authorised := admin.GetSession(r) != nil
if !authorised && !release.Visible {
http.NotFound(w, r)
return
}
response := *release
if authorised || release.IsReleased() {
response.Tracks = release.Tracks
response.Credits = release.Credits
response.Links = release.Links
}
err := templates.Pages["music-gateway"].Execute(w, response)
if err != nil {
fmt.Printf("Error rendering music gateway for %s: %s\n", release.ID, err)
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
})
}

View file

@ -4,15 +4,16 @@ import (
"fmt"
"net/http"
"arimelody-web/admin"
"arimelody-web/controller"
"arimelody-web/global"
music "arimelody-web/music/controller"
"arimelody-web/music/model"
"arimelody-web/model"
"arimelody-web/templates"
)
// HTTP HANDLER METHODS
func Handler() http.Handler {
func MusicHandler() http.Handler {
mux := http.NewServeMux()
mux.Handle("/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
@ -21,7 +22,7 @@ func Handler() http.Handler {
return
}
release, err := music.GetRelease(global.DB, r.URL.Path[1:], true)
release, err := controller.GetRelease(global.DB, r.URL.Path[1:], true)
if err != nil {
http.NotFound(w, r)
return
@ -35,7 +36,7 @@ func Handler() http.Handler {
func ServeCatalog() http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
releases, err := music.GetAllReleases(global.DB, true, 0, true)
releases, err := controller.GetAllReleases(global.DB, true, 0, true)
if err != nil {
fmt.Printf("FATAL: Failed to pull releases for catalog: %s\n", err)
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
@ -54,3 +55,30 @@ func ServeCatalog() http.Handler {
}
})
}
func ServeGateway(release *model.Release) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// only allow authorised users to view hidden releases
authorised := admin.GetSession(r) != nil
if !authorised && !release.Visible {
http.NotFound(w, r)
return
}
response := *release
if authorised || release.IsReleased() {
response.Tracks = release.Tracks
response.Credits = release.Credits
response.Links = release.Links
}
err := templates.Pages["music-gateway"].Execute(w, response)
if err != nil {
fmt.Printf("Error rendering music gateway for %s: %s\n", release.ID, err)
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
})
}

View file

@ -59,11 +59,11 @@
</h2>
<div class="answer">
<p>
<strong class="big">yes!</strong> well, in most cases...
<strong class="big">yes!*</strong> <em>in most cases...</em>
</p>
<p>
from <a href="/music/dream">Dream (2022)</a> onward, all of my <em>self-released</em> songs are
licensed under <a href="https://creativecommons.org/licenses/by-sa/4.0/" target="_blank">Creative Commons Attribution-ShareAlike 4.0</a>.
all of my <em>self-released</em> songs are licensed under
<a href="https://creativecommons.org/licenses/by-sa/4.0/" target="_blank">Creative Commons Attribution-ShareAlike 4.0</a>.
anyone may use and remix these songs freely, so long as they provide credit back to me and link back to this license!
please note that all derivative works must inherit this license.
</p>
@ -71,23 +71,17 @@
a great example of some credit text would be as follows:
</p>
<blockquote>
music used: mellodoot - Dream<br>
<a href="/music/dream">https://arimelody.me/music/dream</a><br>
licensed under <a href="https://creativecommons.org/licenses/by-sa/4.0/">CC BY-SA 4.0</a>.
music used: ari melody - free2play<br>
<a href="/music/free2play">https://arimelody.me/music/free2play</a><br>
licensed under <a href="https://creativecommons.org/licenses/by-sa/4.0/" target="_blank">CC BY-SA 4.0</a>.
</blockquote>
<p>
for any songs prior to this, they were all either released by me (in which case, i honestly
don't mind), or in collaboration with chill people who i don't see having an issue with it.
do be sure to ask them about it, though!
if the song you want to use is <em>not</em> released by me (i.e. under a record label), their usage rights
will likely trump whatever i'd otherwise have in mind. i'll try to negotiate some nice terms, though!
</p>
<p>
in the event the song you want to use is released under some other label, their usage rights
will more than likely trump whatever i'd otherwise have in mind. i'll try to negotiate some
nice terms, though! ;3
</p>
<p>
i love the idea of other creators using my songs in their work, so if you do happen to use
my stuff in a work you're particularly proud of, feel free to send it my way!
i believe that encouraging creative use of artistic works is better than stifling any use at all.
if you do happen to use my work in something you're particularly proud of, feel free to send it my way!
</p>
<p>
&gt; <a href="mailto:ari@arimelody.me">ari@arimelody.me</a>