early database work
Signed-off-by: ari melody <ari@arimelody.me>
This commit is contained in:
parent
6efd47c6c6
commit
5eecef1d78
|
@ -1,19 +1,47 @@
|
|||
package music
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
var ari = Artist{
|
||||
Name: "ari melody",
|
||||
Website: "https://arimelody.me",
|
||||
}
|
||||
var zaire = Artist{
|
||||
Name: "zaire",
|
||||
Website: "https://supitszaire.com",
|
||||
}
|
||||
var mae = Artist{
|
||||
Name: "mae taylor",
|
||||
Website: "https://mae.wtf",
|
||||
}
|
||||
var loudar = Artist{
|
||||
Name: "Loudar",
|
||||
Website: "https://alex.targoninc.com",
|
||||
}
|
||||
var red = Artist{
|
||||
Name: "smoljorb",
|
||||
}
|
||||
|
||||
func make_date_work(date string) time.Time {
|
||||
res, err := time.Parse("2-Jan-2006", date)
|
||||
if err != nil {
|
||||
fmt.Printf("somehow we failed to parse %s! falling back to epoch :]\n", date)
|
||||
return time.Unix(0, 0)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
var placeholders = []Album{
|
||||
{
|
||||
Id: "test",
|
||||
Title: "test album",
|
||||
Type: "album",
|
||||
Year: 2024,
|
||||
ReleaseDate: make_date_work("18-Mar-2024"),
|
||||
Buyname: "go get it!!",
|
||||
Buylink: "https://arimelody.me/",
|
||||
Artists: []string{
|
||||
"ari melody",
|
||||
"zaire",
|
||||
"mae taylor",
|
||||
"Loudar",
|
||||
},
|
||||
Links: []AlbumLink{
|
||||
AlbumLink{
|
||||
Name: "youtube",
|
||||
|
@ -23,23 +51,19 @@ var placeholders = []Album{
|
|||
Description: "she sample on my text 'til i 🚫🚫🚫",
|
||||
Credits: []AlbumCredit{
|
||||
AlbumCredit{
|
||||
Name: "ari melody",
|
||||
Url: "https://arimelody.me",
|
||||
Artist: &ari,
|
||||
Role: "having the swag",
|
||||
},
|
||||
AlbumCredit{
|
||||
Name: "zaire",
|
||||
Url: "https://supitszaire.com",
|
||||
Artist: &zaire,
|
||||
Role: "having the swag",
|
||||
},
|
||||
AlbumCredit{
|
||||
Name: "mae taylor",
|
||||
Url: "https://mae.wtf",
|
||||
Artist: &mae,
|
||||
Role: "having the swag",
|
||||
},
|
||||
AlbumCredit{
|
||||
Name: "Loudar",
|
||||
Url: "https://alex.targoninc.com",
|
||||
Artist: &loudar,
|
||||
Role: "having the swag",
|
||||
},
|
||||
},
|
||||
|
@ -122,21 +146,32 @@ var placeholders = []Album{
|
|||
Id: "free2play",
|
||||
Title: "free2play",
|
||||
Type: "upcoming",
|
||||
Year: 2024,
|
||||
ReleaseDate: make_date_work("17-Mar-2024"),
|
||||
Buyname: "pre-order",
|
||||
Buylink: "https://arimelody.me/",
|
||||
Artists: []string{ "ari melody" },
|
||||
Description: "hello from your local SPACEGIRL! 💫",
|
||||
Credits: []AlbumCredit{
|
||||
AlbumCredit{
|
||||
Artist: &ari,
|
||||
Role: "vocals",
|
||||
},
|
||||
AlbumCredit{
|
||||
Artist: &ari,
|
||||
Role: "production",
|
||||
},
|
||||
AlbumCredit{
|
||||
Artist: &ari,
|
||||
Role: "artwork",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Id: "dream",
|
||||
Title: "Dream",
|
||||
Type: "single",
|
||||
Year: 2022,
|
||||
Artists: []string{ "mellodoot" },
|
||||
ReleaseDate: make_date_work("11-Nov-2024"),
|
||||
Artwork: "https://mellodoot.com/img/music_artwork/mellodoot_-_Dream.webp",
|
||||
Buylink: "https://arimelody.bandcamp.com/track/dream",
|
||||
Free: false,
|
||||
Links: []AlbumLink{
|
||||
AlbumLink{
|
||||
Name: "spotify",
|
||||
|
@ -158,18 +193,15 @@ var placeholders = []Album{
|
|||
Description: "living the dream 🌌 ✨",
|
||||
Credits: []AlbumCredit{
|
||||
AlbumCredit{
|
||||
Name: "ari melody",
|
||||
Url: "https://arimelody.me",
|
||||
Artist: &ari,
|
||||
Role: "vocals",
|
||||
},
|
||||
AlbumCredit{
|
||||
Name: "ari melody",
|
||||
Url: "https://arimelody.me",
|
||||
Artist: &ari,
|
||||
Role: "production",
|
||||
},
|
||||
AlbumCredit{
|
||||
Name: "ari melody",
|
||||
Url: "https://arimelody.me",
|
||||
Artist: &ari,
|
||||
Role: "artwork",
|
||||
},
|
||||
},
|
||||
|
@ -205,8 +237,7 @@ var placeholders = []Album{
|
|||
Id: "gomyway",
|
||||
Title: "Go My Way",
|
||||
Type: "single",
|
||||
Year: 2021,
|
||||
Artists: []string{ "mellodoot" },
|
||||
ReleaseDate: make_date_work("24-Jan-2021"),
|
||||
Artwork: "https://mellodoot.com/img/music_artwork/mellodoot_-_Go_My_Way.webp",
|
||||
Buylink: "https://arimelody.bandcamp.com/track/go-my-way",
|
||||
Links: []AlbumLink{
|
||||
|
@ -228,13 +259,26 @@ var placeholders = []Album{
|
|||
},
|
||||
},
|
||||
Description: "hey! go my way! 💥 ✨",
|
||||
Credits: []AlbumCredit{
|
||||
AlbumCredit{
|
||||
Artist: &ari,
|
||||
Role: "vocals",
|
||||
},
|
||||
AlbumCredit{
|
||||
Artist: &ari,
|
||||
Role: "production",
|
||||
},
|
||||
AlbumCredit{
|
||||
Artist: &ari,
|
||||
Role: "artwork",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Id: "rowboat",
|
||||
Title: "Rowboat",
|
||||
Type: "single",
|
||||
Year: 2020,
|
||||
Artists: []string{ "mellodoot" },
|
||||
ReleaseDate: make_date_work("12-Mar-2020"),
|
||||
Artwork: "https://mellodoot.com/img/music_artwork/mellodoot_-_Rowboat.webp",
|
||||
Buylink: "https://arimelody.bandcamp.com/track/rowboat",
|
||||
Links: []AlbumLink{
|
||||
|
@ -256,13 +300,26 @@ var placeholders = []Album{
|
|||
},
|
||||
},
|
||||
Description: "let's take a trip. i've got a goddamn boat ⛵️",
|
||||
Credits: []AlbumCredit{
|
||||
AlbumCredit{
|
||||
Artist: &ari,
|
||||
Role: "vocals",
|
||||
},
|
||||
AlbumCredit{
|
||||
Artist: &ari,
|
||||
Role: "production",
|
||||
},
|
||||
AlbumCredit{
|
||||
Artist: &ari,
|
||||
Role: "artwork",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Id: "helloworld",
|
||||
Title: "Hello World",
|
||||
Type: "single",
|
||||
Year: 2019,
|
||||
Artists: []string{ "mellodoot" },
|
||||
ReleaseDate: make_date_work("25-Dec-2019"),
|
||||
Artwork: "https://mellodoot.com/img/music_artwork/mellodoot_-_Hello_World.webp",
|
||||
Buylink: "https://arimelody.bandcamp.com/track/hello-world",
|
||||
Links: []AlbumLink{
|
||||
|
@ -284,13 +341,26 @@ var placeholders = []Album{
|
|||
},
|
||||
},
|
||||
Description: "we'll dawn a new frontier! 👾",
|
||||
Credits: []AlbumCredit{
|
||||
AlbumCredit{
|
||||
Artist: &ari,
|
||||
Role: "vocals",
|
||||
},
|
||||
AlbumCredit{
|
||||
Artist: &ari,
|
||||
Role: "production",
|
||||
},
|
||||
AlbumCredit{
|
||||
Artist: &ari,
|
||||
Role: "artwork",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Id: "sine",
|
||||
Title: "Sine",
|
||||
Type: "single",
|
||||
Artists: []string{ "zaire", "mellodoot" },
|
||||
Year: 2019,
|
||||
ReleaseDate: make_date_work("07-Dec-2019"),
|
||||
Artwork: "https://mellodoot.com/img/music_artwork/zaire_-_Sine_ft._mellodoot.webp",
|
||||
Links: []AlbumLink{
|
||||
{
|
||||
|
@ -306,13 +376,22 @@ var placeholders = []Album{
|
|||
Url: "https://www.youtube.com/watch?v=z1H1s6VRnyY",
|
||||
},
|
||||
},
|
||||
Credits: []AlbumCredit{
|
||||
AlbumCredit{
|
||||
Artist: &zaire,
|
||||
Role: "production",
|
||||
},
|
||||
AlbumCredit{
|
||||
Artist: &ari,
|
||||
Role: "production",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Id: "10",
|
||||
Title: "10",
|
||||
Type: "single",
|
||||
Year: 2019,
|
||||
Artists: []string{ "mellodoot" },
|
||||
ReleaseDate: make_date_work("29-Sep-2019"),
|
||||
Artwork: "https://mellodoot.com/img/music_artwork/mellodoot_-_10.webp",
|
||||
Buylink: "https://arimelody.bandcamp.com/track/10",
|
||||
Links: []AlbumLink{
|
||||
|
@ -333,13 +412,22 @@ var placeholders = []Album{
|
|||
Url: "https://www.youtube.com/watch?v=C7WP5L2BK4U",
|
||||
},
|
||||
},
|
||||
Credits: []AlbumCredit{
|
||||
AlbumCredit{
|
||||
Artist: &ari,
|
||||
Role: "production",
|
||||
},
|
||||
AlbumCredit{
|
||||
Artist: &ari,
|
||||
Role: "artwork",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Id: "mad",
|
||||
Title: "MAD",
|
||||
Type: "single",
|
||||
Year: 2018,
|
||||
Artists: []string{ "mellodoot" },
|
||||
ReleaseDate: make_date_work("03-Nov-2018"),
|
||||
Artwork: "https://mellodoot.com/img/music_artwork/mellodoot_-_MAD.webp",
|
||||
Buylink: "https://arimelody.bandcamp.com/track/mad",
|
||||
Links: []AlbumLink{
|
||||
|
@ -360,13 +448,26 @@ var placeholders = []Album{
|
|||
Url: "https://www.youtube.com/watch?v=OB-Pk6p6mfQ",
|
||||
},
|
||||
},
|
||||
Credits: []AlbumCredit{
|
||||
AlbumCredit{
|
||||
Artist: &ari,
|
||||
Role: "vocals",
|
||||
},
|
||||
AlbumCredit{
|
||||
Artist: &ari,
|
||||
Role: "production",
|
||||
},
|
||||
AlbumCredit{
|
||||
Artist: &ari,
|
||||
Role: "artwork",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Id: "welcomingparty",
|
||||
Title: "Welcoming Party",
|
||||
Type: "album",
|
||||
Year: 2018,
|
||||
Artists: []string{ "mellodoot" },
|
||||
ReleaseDate: make_date_work("01-Nov-2018"),
|
||||
Artwork: "https://mellodoot.com/img/music_artwork/mellodoot_-_Welcoming_Party.webp",
|
||||
Buylink: "https://arimelody.bandcamp.com/album/welcoming-party",
|
||||
Links: []AlbumLink{
|
||||
|
@ -387,6 +488,16 @@ var placeholders = []Album{
|
|||
Url: "https://www.youtube.com/playlist?list=PLBG_QJeOHrB5EeniiXBIlHpoQbD6CUJca",
|
||||
},
|
||||
},
|
||||
Credits: []AlbumCredit{
|
||||
AlbumCredit{
|
||||
Artist: &ari,
|
||||
Role: "production",
|
||||
},
|
||||
AlbumCredit{
|
||||
Artist: &ari,
|
||||
Role: "artwork",
|
||||
},
|
||||
},
|
||||
// "tracks": [
|
||||
// {
|
||||
// "title": "Paradigm"
|
||||
|
@ -409,11 +520,10 @@ var placeholders = []Album{
|
|||
Id: "howtheyknow2018",
|
||||
Title: "How They Know (2018)",
|
||||
Type: "single",
|
||||
Year: 2018,
|
||||
Artists: []string{ "mellodoot" },
|
||||
ReleaseDate: make_date_work("27-Feb-2018"),
|
||||
Artwork: "https://mellodoot.com/img/music_artwork/mellodoot_-_How_They_Know_2018.webp",
|
||||
Buyname: "free download",
|
||||
Buylink: "https://arimelody.bandcamp.com/track/how-they-know-2018-remastered",
|
||||
Free: true,
|
||||
Links: []AlbumLink{
|
||||
{
|
||||
Name: "soundcloud",
|
||||
|
@ -424,16 +534,25 @@ var placeholders = []Album{
|
|||
Url: "https://www.youtube.com/watch?v=mbAgSwCzyMw",
|
||||
},
|
||||
},
|
||||
Credits: []AlbumCredit{
|
||||
AlbumCredit{
|
||||
Artist: &ari,
|
||||
Role: "production",
|
||||
},
|
||||
AlbumCredit{
|
||||
Artist: &red,
|
||||
Role: "artwork",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Id: "howtheyknow",
|
||||
Title: "How They Know",
|
||||
Type: "single",
|
||||
Year: 2017,
|
||||
Artists: []string{ "mellodoot" },
|
||||
ReleaseDate: make_date_work("29-Nov-2017"),
|
||||
Artwork: "https://mellodoot.com/img/music_artwork/mellodoot_-_How_They_Know.webp",
|
||||
Buyname: "free download",
|
||||
Buylink: "https://arimelody.bandcamp.com/track/how-they-know",
|
||||
Free: true,
|
||||
Links: []AlbumLink{
|
||||
{
|
||||
Name: "soundcloud",
|
||||
|
@ -444,16 +563,25 @@ var placeholders = []Album{
|
|||
Url: "https://www.youtube.com/watch?v=q6lzKuG1Emo",
|
||||
},
|
||||
},
|
||||
Credits: []AlbumCredit{
|
||||
AlbumCredit{
|
||||
Artist: &ari,
|
||||
Role: "production",
|
||||
},
|
||||
AlbumCredit{
|
||||
Artist: &red,
|
||||
Role: "artwork",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Id: "traveller",
|
||||
Title: "Traveller",
|
||||
Type: "single",
|
||||
Year: 2017,
|
||||
Artists: []string{ "mellodoot" },
|
||||
ReleaseDate: make_date_work("24-Sep-2017"),
|
||||
Artwork: "https://mellodoot.com/img/music_artwork/mellodoot_-_Traveller.webp",
|
||||
Buyname: "free download",
|
||||
Buylink: "https://arimelody.bandcamp.com/track/traveller",
|
||||
Free: true,
|
||||
Links: []AlbumLink{
|
||||
{
|
||||
Name: "soundcloud",
|
||||
|
@ -465,6 +593,16 @@ var placeholders = []Album{
|
|||
},
|
||||
},
|
||||
Description: "an 8-bit expedition! ⚔️🛡️",
|
||||
Credits: []AlbumCredit{
|
||||
AlbumCredit{
|
||||
Artist: &ari,
|
||||
Role: "production",
|
||||
},
|
||||
AlbumCredit{
|
||||
Artist: &ari,
|
||||
Role: "artwork",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -477,7 +615,11 @@ func GetAlbum(id string) (Album, bool) {
|
|||
return Album{}, false
|
||||
}
|
||||
|
||||
func QueryAll() ([]Album) {
|
||||
func QueryAllAlbums() ([]Album) {
|
||||
return placeholders
|
||||
}
|
||||
|
||||
func QueryAllArtists() ([]Artist) {
|
||||
return []Artist{ ari, zaire, mae, loudar, red }
|
||||
}
|
||||
|
||||
|
|
|
@ -3,19 +3,23 @@ package music
|
|||
import (
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type (
|
||||
Artist struct {
|
||||
Name string;
|
||||
Website string;
|
||||
}
|
||||
|
||||
Album struct {
|
||||
Id string;
|
||||
Title string;
|
||||
Type string;
|
||||
Year int;
|
||||
Artists []string;
|
||||
ReleaseDate time.Time;
|
||||
Artwork string;
|
||||
Buyname string;
|
||||
Buylink string;
|
||||
Free bool;
|
||||
Links []AlbumLink;
|
||||
Description string;
|
||||
Credits []AlbumCredit;
|
||||
|
@ -28,26 +32,59 @@ type (
|
|||
}
|
||||
|
||||
AlbumCredit struct {
|
||||
Artist *Artist;
|
||||
Role string;
|
||||
Name string;
|
||||
Url string;
|
||||
}
|
||||
)
|
||||
|
||||
func (album Album) PrintArtists() string {
|
||||
if len(album.Artists) == 1 {
|
||||
return album.Artists[0]
|
||||
func (album Album) GetUniqueArtists() []Artist {
|
||||
if len(album.Credits) == 1 {
|
||||
return []Artist{ *album.Credits[0].Artist }
|
||||
}
|
||||
res := strings.Join(album.Artists[:len(album.Artists) - 1], ", ")
|
||||
res += " & " + album.Artists[len(album.Artists) - 1]
|
||||
|
||||
// create a map of artists to prevent duplicates
|
||||
m := map[string]Artist{}
|
||||
for _, credit := range album.Credits {
|
||||
artist := *credit.Artist
|
||||
m[artist.Name] = artist
|
||||
}
|
||||
|
||||
// now create the actual array to send
|
||||
res := []Artist{}
|
||||
for _, artist := range m {
|
||||
res = append(res, artist)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func (album Album) PrintArtists() string {
|
||||
if len(album.Credits) == 1 {
|
||||
return album.Credits[0].Artist.Name
|
||||
}
|
||||
|
||||
artists := album.GetUniqueArtists()
|
||||
names := []string{}
|
||||
for _, artist := range artists {
|
||||
names = append(names, artist.Name)
|
||||
}
|
||||
|
||||
res := strings.Join(names[:len(names) - 1], ", ")
|
||||
res += " & " + names[len(names) - 1]
|
||||
return res
|
||||
}
|
||||
|
||||
func (album Album) PrintCommaArtists() string {
|
||||
if len(album.Artists) == 1 {
|
||||
return album.Artists[0]
|
||||
if len(album.Credits) == 1 {
|
||||
return album.Credits[0].Artist.Name
|
||||
}
|
||||
return strings.Join(album.Artists[:len(album.Artists)], ", ")
|
||||
|
||||
artists := album.GetUniqueArtists()
|
||||
names := []string{}
|
||||
for _, artist := range artists {
|
||||
names = append(names, artist.Name)
|
||||
}
|
||||
|
||||
return strings.Join(names[:len(names)], ", ")
|
||||
}
|
||||
|
||||
func (album Album) ResolveArtwork() string {
|
||||
|
@ -57,7 +94,15 @@ func (album Album) ResolveArtwork() string {
|
|||
return "/img/music-artwork/default.png"
|
||||
}
|
||||
|
||||
func (album Album) GetReleaseYear() int {
|
||||
return album.ReleaseDate.Year()
|
||||
}
|
||||
|
||||
func (link AlbumLink) NormaliseName() string {
|
||||
re := regexp.MustCompile(`[^a-z0-9]`)
|
||||
return strings.ToLower(re.ReplaceAllString(link.Name, ""))
|
||||
}
|
||||
|
||||
func (credit AlbumCredit) ResolveArtist() Artist {
|
||||
return *credit.Artist
|
||||
}
|
||||
|
|
118
db.go
Normal file
118
db.go
Normal file
|
@ -0,0 +1,118 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"arimelody.me/arimelody.me/api/v1/music"
|
||||
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
_ "github.com/lib/pq"
|
||||
"github.com/jmoiron/sqlx"
|
||||
)
|
||||
|
||||
var schema =
|
||||
`CREATE TABLE IF NOT EXISTS Artists (
|
||||
id SERIAL 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
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS AlbumLinks (
|
||||
id SERIAL primary key,
|
||||
album varchar(64) references Albums(id),
|
||||
name text,
|
||||
url text
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS AlbumCredits (
|
||||
id SERIAL primary key,
|
||||
album varchar(64) references Albums(id),
|
||||
artist int references Artists(id),
|
||||
role text
|
||||
);`
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
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,
|
||||
&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) {
|
||||
query := "SELECT count(*) FROM Albums WHERE id=$1"
|
||||
var count int
|
||||
err := db.Get(&count, query, album.Id)
|
||||
if err != nil {
|
||||
fmt.Printf("error while pushing album [%s] to the database: %v\n", album.Id, err)
|
||||
}
|
||||
|
||||
query = "INSERT INTO Albums (id, title, release_date, artwork, buyname, buylink, description, lyrics) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)"
|
||||
if count != 0 {
|
||||
query = "UPDATE Albums SET title=$2, release_date=$3, artwork=$4, buyname=$5, buylink=$6, description=$7, lyrics=$8 WHERE id=$1"
|
||||
}
|
||||
|
||||
fmt.Printf("saving album [%s] to the database...", album.Id)
|
||||
_, err = db.Exec(query,
|
||||
&album.Id,
|
||||
&album.Title,
|
||||
album.ReleaseDate.Format("2-Jan-2006"),
|
||||
&album.Artwork,
|
||||
&album.Buyname,
|
||||
&album.Buylink,
|
||||
&album.Description,
|
||||
&album.Lyrics,
|
||||
)
|
||||
if err != nil {
|
||||
fmt.Printf("error while pushing album [%s] to the database: %v\n", album.Id, err)
|
||||
}
|
||||
fmt.Printf("done!\n")
|
||||
|
||||
// defer db.Close()
|
||||
}
|
||||
|
||||
func InitDatabase() *sqlx.DB {
|
||||
db, err := sqlx.Connect("postgres", "user=arimimi dbname=arimelody password=fuckingpassword sslmode=disable")
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "unable to create database connection pool: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
db.SetConnMaxLifetime(time.Minute * 3)
|
||||
db.SetMaxOpenConns(10)
|
||||
db.SetMaxIdleConns(10)
|
||||
|
||||
db.MustExec(schema)
|
||||
|
||||
return db
|
||||
}
|
13
go.mod
13
go.mod
|
@ -2,4 +2,15 @@ module arimelody.me/arimelody.me
|
|||
|
||||
go 1.22.1
|
||||
|
||||
require github.com/gomarkdown/markdown v0.0.0-20231222211730-1d6d20845b47 // indirect
|
||||
require (
|
||||
github.com/gomarkdown/markdown v0.0.0-20231222211730-1d6d20845b47 // indirect
|
||||
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
|
||||
github.com/jackc/pgx/v5 v5.5.5 // indirect
|
||||
github.com/jackc/puddle/v2 v2.2.1 // indirect
|
||||
github.com/jmoiron/sqlx v1.3.5 // indirect
|
||||
github.com/lib/pq v1.10.9 // indirect
|
||||
golang.org/x/crypto v0.17.0 // indirect
|
||||
golang.org/x/sync v0.1.0 // indirect
|
||||
golang.org/x/text v0.14.0 // indirect
|
||||
)
|
||||
|
|
28
go.sum
28
go.sum
|
@ -1,2 +1,30 @@
|
|||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
github.com/gomarkdown/markdown v0.0.0-20231222211730-1d6d20845b47 h1:k4Tw0nt6lwro3Uin8eqoET7MDA4JnT8YgbCjc/g5E3k=
|
||||
github.com/gomarkdown/markdown v0.0.0-20231222211730-1d6d20845b47/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA=
|
||||
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
|
||||
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
||||
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk=
|
||||
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
|
||||
github.com/jackc/pgx/v5 v5.5.5 h1:amBjrZVmksIdNjxGW/IiIMzxMKZFelXbUoPNb+8sjQw=
|
||||
github.com/jackc/pgx/v5 v5.5.5/go.mod h1:ez9gk+OAat140fv9ErkZDYFWmXLfV+++K0uAOiwgm1A=
|
||||
github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk=
|
||||
github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
|
||||
github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g=
|
||||
github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ=
|
||||
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
|
||||
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k=
|
||||
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
|
||||
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
|
104
main.go
104
main.go
|
@ -10,6 +10,7 @@ import (
|
|||
"log"
|
||||
"strings"
|
||||
"time"
|
||||
"strconv"
|
||||
|
||||
"github.com/gomarkdown/markdown"
|
||||
"github.com/gomarkdown/markdown/html"
|
||||
|
@ -35,49 +36,69 @@ var templates = template.Must(template.ParseFiles(
|
|||
"views/music-gateway.html",
|
||||
))
|
||||
|
||||
func web_handler(writer http.ResponseWriter, req *http.Request) {
|
||||
uri := req.URL.Path
|
||||
func log_request(req *http.Request, code int, start_time time.Time) {
|
||||
now := time.Now()
|
||||
difference := (now.Nanosecond() - start_time.Nanosecond()) / 1_000_000
|
||||
elapsed := "<1"
|
||||
if difference >= 1 {
|
||||
elapsed = strconv.Itoa(difference)
|
||||
}
|
||||
|
||||
fmt.Printf("[%s] %s %s (%s)\n",
|
||||
time.Now().Format(time.UnixDate),
|
||||
fmt.Printf("[%s] %s %s - %d (%sms) (%s)\n",
|
||||
now.Format(time.UnixDate),
|
||||
req.Method,
|
||||
req.URL.Path,
|
||||
code,
|
||||
elapsed,
|
||||
req.Header["User-Agent"][0],
|
||||
)
|
||||
}
|
||||
|
||||
func web_handler(writer http.ResponseWriter, req *http.Request) {
|
||||
uri := req.URL.Path
|
||||
start_time := time.Now()
|
||||
|
||||
if req.URL.Path == "/" {
|
||||
index_handler(writer, req)
|
||||
code := index_handler(writer, req)
|
||||
log_request(req, code, start_time)
|
||||
return
|
||||
}
|
||||
if uri == "/music" {
|
||||
music_handler(writer, req)
|
||||
code := music_handler(writer, req)
|
||||
log_request(req, code, start_time)
|
||||
return
|
||||
}
|
||||
if strings.HasPrefix(uri, "/music/") {
|
||||
music_gateway_handler(writer, req)
|
||||
code := music_gateway_handler(writer, req)
|
||||
log_request(req, code, start_time)
|
||||
return
|
||||
}
|
||||
static_handler(writer, req)
|
||||
code := static_handler(writer, req)
|
||||
log_request(req, code, start_time)
|
||||
}
|
||||
|
||||
func index_handler(writer http.ResponseWriter, req *http.Request) {
|
||||
func index_handler(writer http.ResponseWriter, req *http.Request) int {
|
||||
err := templates.ExecuteTemplate(writer, "index.html", nil)
|
||||
if err != nil {
|
||||
http.Error(writer, err.Error(), http.StatusInternalServerError)
|
||||
return 500
|
||||
}
|
||||
return 200
|
||||
}
|
||||
|
||||
func music_handler(writer http.ResponseWriter, req *http.Request) {
|
||||
err := templates.ExecuteTemplate(writer, "music.html", music.QueryAll())
|
||||
func music_handler(writer http.ResponseWriter, req *http.Request) int {
|
||||
err := templates.ExecuteTemplate(writer, "music.html", music.QueryAllAlbums())
|
||||
if err != nil {
|
||||
http.Error(writer, err.Error(), http.StatusInternalServerError)
|
||||
return 500
|
||||
}
|
||||
return 200
|
||||
}
|
||||
|
||||
func music_gateway_handler(writer http.ResponseWriter, req *http.Request) {
|
||||
func music_gateway_handler(writer http.ResponseWriter, req *http.Request) int {
|
||||
if len(req.URL.Path) <= len("/music/") {
|
||||
http.Error(writer, "400 bad request", http.StatusBadRequest)
|
||||
return
|
||||
return 400
|
||||
}
|
||||
|
||||
id := req.URL.Path[len("/music/"):]
|
||||
|
@ -86,28 +107,61 @@ func music_gateway_handler(writer http.ResponseWriter, req *http.Request) {
|
|||
album, ok := music.GetAlbum(id)
|
||||
if !ok {
|
||||
http.Error(writer, "404 not found", http.StatusNotFound)
|
||||
return
|
||||
return 404
|
||||
}
|
||||
err := templates.ExecuteTemplate(writer, "music-gateway.html", album)
|
||||
if err != nil {
|
||||
http.Error(writer, err.Error(), http.StatusInternalServerError)
|
||||
return 500
|
||||
}
|
||||
return 200
|
||||
}
|
||||
|
||||
func static_handler(writer http.ResponseWriter, req *http.Request) {
|
||||
func static_handler(writer http.ResponseWriter, req *http.Request) int {
|
||||
filename := "public/" + req.URL.Path[1:]
|
||||
body, err := os.ReadFile(filename)
|
||||
|
||||
// check the file's metadata
|
||||
info, err := os.Stat(filename)
|
||||
if err != nil {
|
||||
http.Error(writer, "404 not found", http.StatusNotFound)
|
||||
return
|
||||
return 404
|
||||
}
|
||||
|
||||
if len(req.Header["If-Modified-Since"]) > 0 && req.Header["If-Modified-Since"][0] != "" {
|
||||
if_modified_since_time, err := time.Parse(http.TimeFormat, req.Header["If-Modified-Since"][0])
|
||||
if err != nil {
|
||||
http.Error(writer, "400 bad request", http.StatusBadRequest)
|
||||
return 400
|
||||
}
|
||||
if req.Header["If-Modified-Since"][0] == info.ModTime().Format(http.TimeFormat) || if_modified_since_time.After(info.ModTime()) {
|
||||
writer.WriteHeader(304) // not modified
|
||||
return 304
|
||||
}
|
||||
}
|
||||
|
||||
// set other nice headers
|
||||
writer.Header().Set("Cache-Control", "max-age=86400")
|
||||
writer.Header().Set("Last-Modified", info.ModTime().Format(http.TimeFormat))
|
||||
// Last-Modified: <day-name>, <day> <month> <year> <hour>:<minute>:<second> GMT
|
||||
// Last-Modified: Wed, 21 Oct 2015 07:28:00 GMT
|
||||
|
||||
// read the file
|
||||
body, err := os.ReadFile(filename)
|
||||
if err != nil {
|
||||
http.Error(writer, err.Error(), http.StatusInternalServerError)
|
||||
return 500
|
||||
}
|
||||
|
||||
// setting MIME types
|
||||
filetype := filename[strings.LastIndex(filename, ".") + 1:]
|
||||
if mime_type, ok := mime_types[filetype]; ok {
|
||||
writer.Header().Set("Content-Type", mime_type)
|
||||
} else {
|
||||
writer.Header().Set("Content-Type", "text/plain; charset=utf-8")
|
||||
}
|
||||
|
||||
writer.Write([]byte(body))
|
||||
return 200
|
||||
}
|
||||
|
||||
func parse_markdown(md []byte) []byte {
|
||||
|
@ -122,7 +176,23 @@ func parse_markdown(md []byte) []byte {
|
|||
return markdown.Render(doc, renderer)
|
||||
}
|
||||
|
||||
func push_to_db_this_is_a_testing_thing_and_will_be_superfluous_later() {
|
||||
db := InitDatabase()
|
||||
|
||||
for _, album := range music.QueryAllAlbums() {
|
||||
PushAlbum(db, album)
|
||||
}
|
||||
|
||||
for _, artist := range music.QueryAllArtists() {
|
||||
PushArtist(db, artist)
|
||||
}
|
||||
|
||||
defer db.Close()
|
||||
}
|
||||
|
||||
func main() {
|
||||
// push_to_db_this_is_a_testing_thing_and_will_be_superfluous_later()
|
||||
|
||||
http.HandleFunc("/", web_handler)
|
||||
log.Fatal(http.ListenAndServe(":8080", nil))
|
||||
}
|
||||
|
|
|
@ -216,7 +216,7 @@ div#info {
|
|||
|
||||
#title-container {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
align-items: last baseline;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
<meta name="description" content="Stream "{{.Title}}" by {{.PrintArtists}} on all platforms!">
|
||||
<meta name="author" content="{{.PrintArtists}}">
|
||||
<meta name="keywords" content="{{.PrintCommaArtists}}, music, {{.Title}}, {{.Id}}, {{.Year}}">
|
||||
<meta name="keywords" content="{{.PrintCommaArtists}}, music, {{.Title}}, {{.Id}}, {{.GetReleaseYear}}">
|
||||
|
||||
<meta property="og:url" content="https://arimelody.me/music/{{.Id}}">
|
||||
<meta property="og:type" content="website">
|
||||
|
@ -61,23 +61,26 @@
|
|||
<div id="main">
|
||||
<div id="title-container">
|
||||
<h1 id="title">{{.Title}}</h1>
|
||||
<span id="year">{{.Year}}</span>
|
||||
<span id="year">{{.GetReleaseYear}}</span>
|
||||
</div>
|
||||
<p id="artist">{{.PrintArtists}}</p>
|
||||
<p id="type" class="{{.Type}}">{{.Type}}</p>
|
||||
|
||||
{{if .Description}}
|
||||
<p id="description">
|
||||
{{.Description}}
|
||||
</p>
|
||||
{{end}}
|
||||
|
||||
<div id="links">
|
||||
{{if .Buylink}}
|
||||
<a href="{{.Buylink}}" target="_blank" class="buy">
|
||||
{{if .Buyname}}
|
||||
{{.Buyname}}
|
||||
{{.Buyname}}
|
||||
{{else}}
|
||||
{{if .Free}}
|
||||
download
|
||||
{{else}}
|
||||
buy
|
||||
buy
|
||||
{{end}}
|
||||
{{end}}</a>
|
||||
</a>
|
||||
{{end}}
|
||||
|
||||
{{range .Links}}
|
||||
|
@ -87,10 +90,7 @@
|
|||
{{end}}
|
||||
</div>
|
||||
|
||||
<p id="description">
|
||||
{{.Description}}
|
||||
</p>
|
||||
|
||||
{{if or .Credits .Lyrics}}
|
||||
<ul id="extras">
|
||||
{{if .Credits}}
|
||||
<li><a href="#credits">credits</a></li>
|
||||
|
@ -100,6 +100,7 @@
|
|||
<li><a href="#lyrics">lyrics</a></li>
|
||||
{{end}}
|
||||
</ul>
|
||||
{{end}}
|
||||
|
||||
<p id="share">share</p>
|
||||
</div>
|
||||
|
@ -110,7 +111,8 @@
|
|||
<h2>credits:</h2>
|
||||
<ul>
|
||||
{{range .Credits}}
|
||||
<li><strong><a href="{{.Url}}">{{.Name}}</a></strong>: {{.Role}}</li>
|
||||
{{$Artist := .ResolveArtist}}
|
||||
<li><strong><a href="{{$Artist.Website}}">{{$Artist.Name}}</a></strong>: {{.Role}}</li>
|
||||
{{end}}
|
||||
</ul>
|
||||
</div>
|
||||
|
|
Loading…
Reference in a new issue