diff --git a/api/v1/music/music.go b/api/v1/music/music.go index ec4bd1e..06f7380 100644 --- a/api/v1/music/music.go +++ b/api/v1/music/music.go @@ -6,21 +6,34 @@ import ( ) var ari = Artist{ + Id: "arimelody", Name: "ari melody", Website: "https://arimelody.me", } +var mellodoot = Artist{ + Id: "mellodoot", + Name: "mellodoot", + Website: "https://mellodoot.com", +} var zaire = Artist{ + Id: "zaire", Name: "zaire", Website: "https://supitszaire.com", } var mae = Artist{ + Id: "maetaylor", Name: "mae taylor", Website: "https://mae.wtf", } var loudar = Artist{ + Id: "loudar", Name: "Loudar", Website: "https://alex.targoninc.com", } +var red = Artist { + Id: "smoljorb", + Name: "smoljorb", +} func make_date_work(date string) time.Time { res, err := time.Parse("2-Jan-2006", date) @@ -35,7 +48,7 @@ var placeholders = []Album{ { Id: "test", Title: "test album", - Type: "album", + // Type: "album", ReleaseDate: make_date_work("18-Mar-2024"), Buyname: "go get it!!", Buylink: "https://arimelody.me/", @@ -45,7 +58,8 @@ var placeholders = []Album{ Url: "https://youtu.be/dQw4w9WgXcQ", }, }, - Description: "she sample on my text 'til i 🚫🚫🚫", + Description: + `Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas viverra ligula interdum, tempor metus venenatis, tempus est. Praesent semper vulputate nulla, a venenatis libero elementum id. Proin maximus aliquet accumsan. Integer eu orci congue, ultrices leo sed, maximus risus. Integer laoreet non urna non accumsan. Cras ut sollicitudin justo. Vivamus eu orci tempus, aliquet est rhoncus, tempus neque. Aliquam tempor sit amet nibh sed tempus. Nulla vitae bibendum purus. Sed in mi enim. Nam pharetra enim lorem, vel tristique diam malesuada a. Duis dignissim nunc mi, id semper ex tincidunt a. Sed laoreet consequat lacus a consectetur. Nulla est diam, tempus eget lacus ullamcorper, tincidunt faucibus ex. Duis consectetur felis sit amet ante fermentum interdum. Sed pulvinar laoreet tellus.`, Credits: []AlbumCredit{ AlbumCredit{ Artist: &ari, @@ -190,15 +204,15 @@ var placeholders = []Album{ Description: "living the dream 🌌 ✨", Credits: []AlbumCredit{ AlbumCredit{ - Artist: &ari, + Artist: &mellodoot, Role: "vocals", }, AlbumCredit{ - Artist: &ari, + Artist: &mellodoot, Role: "production", }, AlbumCredit{ - Artist: &ari, + Artist: &mellodoot, Role: "artwork", }, }, @@ -258,15 +272,15 @@ var placeholders = []Album{ Description: "hey! go my way! 💥 ✨", Credits: []AlbumCredit{ AlbumCredit{ - Artist: &ari, + Artist: &mellodoot, Role: "vocals", }, AlbumCredit{ - Artist: &ari, + Artist: &mellodoot, Role: "production", }, AlbumCredit{ - Artist: &ari, + Artist: &mellodoot, Role: "artwork", }, }, @@ -299,15 +313,15 @@ var placeholders = []Album{ Description: "let's take a trip. i've got a goddamn boat ⛵️", Credits: []AlbumCredit{ AlbumCredit{ - Artist: &ari, + Artist: &mellodoot, Role: "vocals", }, AlbumCredit{ - Artist: &ari, + Artist: &mellodoot, Role: "production", }, AlbumCredit{ - Artist: &ari, + Artist: &mellodoot, Role: "artwork", }, }, @@ -340,15 +354,15 @@ var placeholders = []Album{ Description: "we'll dawn a new frontier! 👾", Credits: []AlbumCredit{ AlbumCredit{ - Artist: &ari, + Artist: &mellodoot, Role: "vocals", }, AlbumCredit{ - Artist: &ari, + Artist: &mellodoot, Role: "production", }, AlbumCredit{ - Artist: &ari, + Artist: &mellodoot, Role: "artwork", }, }, @@ -379,7 +393,7 @@ var placeholders = []Album{ Role: "production", }, AlbumCredit{ - Artist: &ari, + Artist: &mellodoot, Role: "production", }, }, @@ -411,11 +425,11 @@ var placeholders = []Album{ }, Credits: []AlbumCredit{ AlbumCredit{ - Artist: &ari, + Artist: &mellodoot, Role: "production", }, AlbumCredit{ - Artist: &ari, + Artist: &mellodoot, Role: "artwork", }, }, @@ -447,15 +461,15 @@ var placeholders = []Album{ }, Credits: []AlbumCredit{ AlbumCredit{ - Artist: &ari, + Artist: &mellodoot, Role: "vocals", }, AlbumCredit{ - Artist: &ari, + Artist: &mellodoot, Role: "production", }, AlbumCredit{ - Artist: &ari, + Artist: &mellodoot, Role: "artwork", }, }, @@ -487,11 +501,11 @@ var placeholders = []Album{ }, Credits: []AlbumCredit{ AlbumCredit{ - Artist: &ari, + Artist: &mellodoot, Role: "production", }, AlbumCredit{ - Artist: &ari, + Artist: &mellodoot, Role: "artwork", }, }, @@ -533,9 +547,14 @@ var placeholders = []Album{ }, Credits: []AlbumCredit{ AlbumCredit{ - Artist: &ari, + Artist: &mellodoot, Role: "production", }, + AlbumCredit{ + Artist: &red, + Role: "artwork", + Meta: true, + }, }, }, { @@ -558,9 +577,14 @@ var placeholders = []Album{ }, Credits: []AlbumCredit{ AlbumCredit{ - Artist: &ari, + Artist: &mellodoot, Role: "production", }, + AlbumCredit{ + Artist: &red, + Role: "artwork", + Meta: true, + }, }, }, { @@ -584,11 +608,11 @@ var placeholders = []Album{ Description: "an 8-bit expedition! ⚔️🛡️", Credits: []AlbumCredit{ AlbumCredit{ - Artist: &ari, + Artist: &mellodoot, Role: "production", }, AlbumCredit{ - Artist: &ari, + Artist: &mellodoot, Role: "artwork", }, }, @@ -609,6 +633,6 @@ func QueryAllAlbums() ([]Album) { } func QueryAllArtists() ([]Artist) { - return []Artist{ ari, zaire, mae, loudar } + return []Artist{ ari, mellodoot, zaire, mae, loudar, red } } diff --git a/api/v1/music/music_types.go b/api/v1/music/music_types.go index d5ce05d..f6eb250 100644 --- a/api/v1/music/music_types.go +++ b/api/v1/music/music_types.go @@ -8,6 +8,7 @@ import ( type ( Artist struct { + Id string; Name string; Website string; } @@ -34,6 +35,7 @@ type ( AlbumCredit struct { Artist *Artist; Role string; + Meta bool; // for "meta" contributors (i.e. not credited for the musical work, but other related assets) } ) @@ -63,36 +65,88 @@ func (album Album) GetUniqueArtists() []Artist { return res } -func (album Album) PrintArtists() string { - artists := album.GetUniqueArtists() - if len(artists) == 1 { - return artists[0].Name +func (album Album) GetUniqueNonMetaArtists() []Artist { + if len(album.Credits) == 1 { + return []Artist{ *album.Credits[0].Artist } } + // create a map of artists to prevent duplicates + res := []Artist{} + for _, credit := range album.Credits { + if credit.Meta { + continue + } + artist := *credit.Artist + exists := false + for _, c := range res { + if c == *credit.Artist { + exists = true + break + } + } + if exists { + continue + } + res = append(res, artist) + } + + // now create the actual array to send + return res +} + +func (album Album) GetUniqueArtistNames() []string { + if len(album.Credits) == 1 { + return []string{ album.Credits[0].Artist.Name } + } + + artists := album.GetUniqueArtists() names := []string{} for _, artist := range artists { names = append(names, artist.Name) } + return names; +} + +func (album Album) GetUniqueNonMetaArtistNames() []string { + if len(album.Credits) == 1 { + return []string{ album.Credits[0].Artist.Name } + } + + artists := album.GetUniqueNonMetaArtists() + names := []string{} + for _, artist := range artists { + names = append(names, artist.Name) + } + + return names; +} + +func (album Album) PrintPrimaryArtists() string { + names := album.GetUniqueNonMetaArtistNames(); + if len(names) == 1 { + return names[0] + } res := strings.Join(names[:len(names) - 1], ", ") res += " & " + names[len(names) - 1] return res } -func (album Album) PrintCommaArtists() string { - if len(album.Credits) == 1 { - return album.Credits[0].Artist.Name +func (album Album) PrintCommaPrimaryArtists() string { + names := album.GetUniqueNonMetaArtistNames(); + if len(names) == 1 { + return names[0] } - - artists := album.GetUniqueArtists() - names := []string{} - for _, artist := range artists { - names = append(names, artist.Name) - } - return strings.Join(names[:len(names)], ", ") } +func (album Album) ResolveType() string { + if album.Type != "" { + return album.Type + } + return "unknown" +} + func (album Album) ResolveArtwork() string { if album.Artwork != "" { return album.Artwork diff --git a/db.go b/db.go index 951298c..2a609df 100644 --- a/db.go +++ b/db.go @@ -13,126 +13,67 @@ import ( var schema = `CREATE TABLE IF NOT EXISTS Artists ( - id SERIAL primary key, - name text, - website text + id TEXT PRIMARY KEY, + name TEXT, + website TEXT ); CREATE TABLE IF NOT EXISTS Albums ( - id varchar(64) primary key, - title text not null, - release_date date not null, - artwork text, - buyname text, - buylink text, - description text, - lyrics text + id VARCHAR(64) PRIMARY KEY, + title TEXT NOT NULL, + type TEXT, + release_date DATE NOT NULL, + artwork TEXT, + buyname TEXT, + buylink TEXT, + description TEXT, + lyrics TEXT ); CREATE TABLE IF NOT EXISTS AlbumLinks ( - album varchar(64) references Albums(id) on delete cascade, - name text, - url text, - constraint albumlinks_pk primary key (album, name) + album VARCHAR(64) REFERENCES Albums(id) ON DELETE CASCADE ON UPDATE CASCADE, + name TEXT, + url TEXT, + CONSTRAINT albumlinks_pk PRIMARY KEY (album, name) ); CREATE TABLE IF NOT EXISTS AlbumCredits ( - album varchar(64) references Albums(id) on delete cascade, - artist int references Artists(id) on delete cascade, - role text - constraint albumcredits_pk primary key (album, artist, role) + album VARCHAR(64) REFERENCES Albums(ID) ON DELETE CASCADE, + artist TEXT REFERENCES Artists(id) ON DELETE CASCADE, + role TEXT, + meta BOOLEAN, + constraint albumcredits_pk PRIMARY KEY (album, artist, role) );` func PushArtist(db *sqlx.DB, artist music.Artist) { - query := "SELECT count(*) FROM Artists WHERE name=$1" - var count int - err := db.Get(&count, query, artist.Name) - if err != nil { - fmt.Printf("error while pushing artist [%s] to the database: %v\n", artist.Name, err) - } + fmt.Printf("syncing artist [%s] to database...", artist.Name) - query = "INSERT INTO artists (name, website) VALUES ($1, $2)" - if count != 0 { - query = "UPDATE artists SET website=$2 WHERE name=$1" - } - - fmt.Printf("saving artist [%s] to the database...", artist.Name) - _, err = db.Exec(query, + db.MustExec("INSERT INTO artists (id, name, website) VALUES ($1, $2, $3) ON CONFLICT (id) DO UPDATE SET name=$2, website=$3", + &artist.Id, &artist.Name, &artist.Website, ) - if err != nil { - fmt.Printf("error while pushing artist [%s] to the database: %v\n", artist.Name, err) - } + fmt.Printf("done!\n") - - // defer db.Close() } func PushAlbum(db *sqlx.DB, album music.Album) { - var count int - err := db.Get(&count, "SELECT count(*) FROM Albums WHERE id=$1", album.Id) - if err != nil { - fmt.Printf("error while pushing album [%s] to the database: %v\n", album.Id, err) - } - - artist_ids := map[string]int{}; - for _, credit := range album.Credits { - if _, ok := artist_ids[credit.Artist.Name]; ok { - continue; - } - var id int - err := db.Get(&id, "SELECT id FROM Artists WHERE name=$1", credit.Artist.Name) - if err != nil { - continue; - } - artist_ids[credit.Artist.Name] = id - } - - if count == 0 { - fmt.Printf("creating album [%s]...", album.Id) - - tx := db.MustBegin() - tx.MustExec("INSERT INTO Albums VALUES ($1, $2, $3, $4, $5, $6, $7, $8)", &album.Id, &album.Title, album.ReleaseDate.Format("2-Jan-2006"), &album.Artwork, &album.Buyname, &album.Buylink, &album.Description, &album.Lyrics) - for _, link := range album.Links { - tx.MustExec("INSERT INTO AlbumLinks (album, name, url) VALUES ($1, $2, $3)", &album.Id, &link.Name, &link.Url) - } - for _, credit := range album.Credits { - artist_id := artist_ids[credit.Artist.Name] - tx.MustExec("INSERT INTO AlbumCredits (album, artist, role) VALUES ($1, $2, $3)", &album.Id, &artist_id, &credit.Role) - } - tx.Commit() - - fmt.Printf("done!\n") - return; - - } - - fmt.Printf("updating album [%s]...", album.Id) + fmt.Printf("syncing album [%s] to database...", album.Id) tx := db.MustBegin() - tx.MustExec("UPDATE Albums SET title=$2, release_date=$3, artwork=$4, buyname=$5, buylink=$6, description=$7, lyrics=$8 WHERE id=$1", - &album.Id, - &album.Title, - album.ReleaseDate.Format("2-Jan-2006"), - &album.Artwork, - &album.Buyname, - &album.Buylink, - &album.Description, - &album.Lyrics, - ) - // we're just gonna completely fresh them because - // like hell am i actually gonna comb through every - // single one of these - tx.MustExec("DELETE FROM AlbumLinks WHERE album=$1", &album.Id) - tx.MustExec("DELETE FROM AlbumCredits WHERE album=$1", &album.Id) + tx.MustExec("INSERT INTO albums (id, title, release_date, artwork, buyname, buylink, description, lyrics) VALUES ($1, $2, $3, $4, $5, $6, $7, $8) "+ + "ON CONFLICT (id) DO UPDATE SET title=$2, release_date=$3, artwork=$4, buyname=$5, buylink=$6, description=$7, lyrics=$8", + &album.Id, &album.Title, album.ReleaseDate.Format("2-Jan-2006"), &album.Artwork, &album.Buyname, &album.Buylink, &album.Description, &album.Lyrics) + for _, link := range album.Links { - tx.MustExec("INSERT INTO AlbumLinks (album, name, url) VALUES ($1, $2, $3)", &album.Id, &link.Name, &link.Url) + tx.MustExec("INSERT INTO albumlinks (album, name, url) VALUES ($1, $2, $3) ON CONFLICT (album, name) DO UPDATE SET url=$3", + &album.Id, &link.Name, &link.Url) } for _, credit := range album.Credits { - artist_id := artist_ids[credit.Artist.Name] - tx.MustExec("INSERT INTO AlbumCredits (album, artist, role) VALUES ($1, $2, $3)", &album.Id, &artist_id, &credit.Role) + tx.MustExec("INSERT INTO albumcredits (album, artist, role, meta) VALUES ($1, $2, $3, $4) ON CONFLICT DO NOTHING", + &album.Id, &credit.Artist.Id, &credit.Role, &credit.Meta) } + tx.Commit() fmt.Printf("done!\n") @@ -149,7 +90,8 @@ func InitDatabase() *sqlx.DB { db.SetMaxOpenConns(10) db.SetMaxIdleConns(10) - // db.MustExec(schema) + db.MustExec(schema) + fmt.Printf("database schema synchronised.\n") return db } diff --git a/main.go b/main.go index 9cc5438..f9bcbec 100644 --- a/main.go +++ b/main.go @@ -17,7 +17,7 @@ import ( "github.com/gomarkdown/markdown/parser" ) -const PORT int = 8080 +const PORT int = 8081 var mime_types = map[string]string{ "css": "text/css; charset=utf-8", diff --git a/public/script/main.js b/public/script/main.js index ed57fff..18be1ad 100644 --- a/public/script/main.js +++ b/public/script/main.js @@ -1,4 +1,5 @@ import "./header.js"; +import "./accessibility.js"; function type_out(e) { const text = e.innerText; diff --git a/public/script/music-gateway.js b/public/script/music-gateway.js index ceda265..301a461 100644 --- a/public/script/music-gateway.js +++ b/public/script/music-gateway.js @@ -28,6 +28,16 @@ function apply_funny_bob_to_upcoming_tags() { } } +document.querySelectorAll("div#extras ul li a[href]").forEach(link => { + link.addEventListener("click", event => { + event.preventDefault(); + location.replace(link.href); + }); +}); + +/* + * handling track previews (currently not implemented) + const previews = document.querySelectorAll("[id^=preview-]"); for (const preview of previews) { preview.addEventListener("click", (e) => { @@ -67,3 +77,5 @@ function stopPreview(preview) { } stopPreviews(); + +*/ diff --git a/public/style/music-gateway.css b/public/style/music-gateway.css index 866af9a..37f06f3 100644 --- a/public/style/music-gateway.css +++ b/public/style/music-gateway.css @@ -332,28 +332,43 @@ div#info { font-size: 1.2em; } -ul#extras { - list-style: none; +div#extras ul { + height: 100%; + margin: 0; display: flex; padding: 0; gap: .6em; + list-style: none; + flex-direction: column; + justify-content: space-evenly; } -ul#extras li a { +div#extras ul li a { color: #888; text-decoration: none; font-style: italic; + writing-mode: vertical-rl; + transition: color .1s linear; +} + +div#extras ul li a:hover { + color: #eee; } div#info > div { max-height: 360px; min-height: 360px; overflow-y: scroll; - padding: 2rem 4rem; - margin: -2rem -4rem; + padding: 2rem 1rem 2rem 4rem; + margin: -2rem -3.5rem -2rem -4rem; mask-image: linear-gradient(to bottom, transparent 0%, black 10%, black 90%, transparent 100%); } +div#info p { + max-width: 500px; + white-space: pre-line; +} + a.scrollback { color: #888; font-style: italic; @@ -367,11 +382,6 @@ a.scrollback { margin-bottom: 1rem; } -#lyrics p { - max-width: 500px; - white-space: pre-line; -} - #share { margin: 0; display: inline-block; @@ -481,12 +491,28 @@ footer a:hover { } @media only screen and (min-width: 800px) { - div#info:has(> #credits:target) { - transform: translateY(calc(-360px + -6rem)); + div#music-container:has(:not(> div#info #credits:target):not(> div#info #credits:target)) { + div#extras ul li:first-of-type a { + color: #eee; + } } - div#info:has(> #lyrics:target) { - transform: translateY(calc((-360px + -6rem) * 2)); + div#music-container:has(> div#info #credits:target) { + div#info { + transform: translateY(calc(-360px + -6rem)); + } + div#extras ul li a[href="#credits"] { + color: #eee; + } + } + + div#music-container:has(> div#info #lyrics:target) { + div#info { + transform: translateY(calc((-360px + -6rem) * 2)); + } + div#extras ul li a[href="#lyrics"] { + color: #eee; + } } } @@ -532,7 +558,7 @@ footer a:hover { mask-image: none; } - a.scrollback { + div#extras { display: none; } diff --git a/views/index.html b/views/index.html index ec4b541..410c2a5 100644 --- a/views/index.html +++ b/views/index.html @@ -21,7 +21,6 @@ -
diff --git a/views/music-gateway.html b/views/music-gateway.html index dd582a8..239482f 100644 --- a/views/music-gateway.html +++ b/views/music-gateway.html @@ -6,19 +6,19 @@ -{{.PrintArtists}}
-{{.Type}}
- - {{if .Description}} -- {{.Description}} -
- {{end}} +{{.PrintPrimaryArtists}}
+{{.ResolveType}}
+ {{.Description}} +
{{end}} @@ -107,12 +91,15 @@ {{if .Credits}}