music page functional, just nto all covers yet
crispy-caesus 114518720+crispy-caesus@users.noreply.github.com
Fri, 02 May 2025 13:29:09 +0200
5 files changed,
178 insertions(+),
13 deletions(-)
M
music.go
→
music.go
@@ -5,11 +5,19 @@ "net/http"
"text/template" ) +type musicData struct { + Releases []musicItem + Spending float32 +} + func musicHandler(w http.ResponseWriter, r *http.Request) { results := loadMusic() + spending := getSpending() tmpl := template.Must(template.ParseFiles("templates/music.html")) - err := tmpl.Execute(w, results) + data := musicData{Releases: results, Spending: spending} + + err := tmpl.Execute(w, data) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) }
M
sql.go
→
sql.go
@@ -8,14 +8,14 @@ _ "github.com/mattn/go-sqlite3"
) type musicItem struct { - id int - external_ids sql.NullString - Name string - Artist string - price float64 - seller sql.NullString - note sql.NullString - purchase_date sql.NullString + id int + external_ids sql.NullString + Name string + Artist string + price float64 + seller sql.NullString + Note string + purchase_date sql.NullString } func openDB(DBName string) (*sql.DB, error) {@@ -52,14 +52,31 @@ &result.Name,
&result.Artist, &result.price, &result.seller, - &result.note, + &result.Note, &result.purchase_date) if err != nil { log.Print(err) } - results = append(results, result) } return results } +func getSpending() (value float32) { + db, err := openDB("walletdrain") + if err != nil { + panic("couldn't open db") + } + defer db.Close() + + query := "SELECT SUM(price) FROM music" + + err = db.QueryRow(query).Scan(&value) + if err == sql.ErrNoRows { + log.Println("No rows found") + } else if err != nil { + log.Fatal(err) + } + + return value +}
M
templates/music.html
→
templates/music.html
@@ -10,9 +10,13 @@ </head>
<body> <h1>My bought music</h1> + <p>Spending so far: {{.Spending}}€</p> <ul> - {{range .}} - <li>{{.Name}} - {{.Artist}}</li> + {{range .Releases}} + <li> + <img src="{{.Note}}" alt="Album Cover" /> <br> + {{.Name}} - {{.Artist}} + </li> {{end}} </ul> </body>
A
test.go.test
@@ -0,0 +1,135 @@
+package main + +import ( + "database/sql" + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + "net/url" + "time" + + _ "github.com/mattn/go-sqlite3" +) + +type musicItem struct { + id int + external_ids sql.NullString + Name string + Artist string + price float64 + seller sql.NullString + Note sql.NullString + purchase_date sql.NullString +} + +func main() { + // Connect to the SQLite database + db, err := sql.Open("sqlite3", "walletdrain.db") + if err != nil { + fmt.Printf("Error connecting to database: %v\n", err) + return + } + defer db.Close() + + // Query to get the first 10 music items + rows, err := db.Query("SELECT id, external_ids, Name, Artist, price, seller, Note, purchase_date FROM music WHERE artist='Zephyrianna '") + if err != nil { + fmt.Printf("Error querying database: %v\n", err) + return + } + defer rows.Close() + + // Create HTTP client and set user agent + client := &http.Client{} + ua := "MusicCoverArtFetcher/1.0 (your-email@example.com)" + + fmt.Println("ID\tARTIST\tRELEASE\tCOVER ART URL (250px)") + fmt.Println("-----------------------------------------------") + + // Process each row from the database + for rows.Next() { + var item musicItem + + if err := rows.Scan(&item.id, &item.external_ids, &item.Name, &item.Artist, + &item.price, &item.seller, &item.Note, &item.purchase_date); err != nil { + fmt.Printf("Error scanning row: %v\n", err) + continue + } + + // Search MusicBrainz for the release + query := url.QueryEscape(fmt.Sprintf("artist:\"%s\" AND release:\"%s\"", item.Artist, item.Name)) + req, _ := http.NewRequest("GET", "https://musicbrainz.org/ws/2/release?query="+query+"&fmt=json", nil) + req.Header.Set("User-Agent", ua) + + resp, err := client.Do(req) + if err != nil || resp.StatusCode != http.StatusOK { + fmt.Printf("%d\t%s\t%s\tError searching MusicBrainz\n", item.id, item.Artist, item.Name) + continue + } + + var mbResp struct { + Releases []struct { + ID string `json:"id"` + } `json:"releases"` + } + + body, _ := ioutil.ReadAll(resp.Body) + resp.Body.Close() + + if err := json.Unmarshal(body, &mbResp); err != nil || len(mbResp.Releases) == 0 { + fmt.Printf("%d\t%s\t%s\tNo match found\n", item.id, item.Artist, item.Name) + continue + } + + // Get cover art using the MusicBrainz ID + req, _ = http.NewRequest("GET", "https://coverartarchive.org/release/"+mbResp.Releases[0].ID, nil) + req.Header.Set("User-Agent", ua) + + resp, err = client.Do(req) + if err != nil || resp.StatusCode != http.StatusOK { + fmt.Printf("%d\t%s\t%s\tNo cover art available\n", item.id, item.Artist, item.Name) + continue + } + + var caResp struct { + Images []struct { + Thumbnails struct { + Img250 string `json:"250"` + } `json:"thumbnails"` + Front bool `json:"front"` + } `json:"images"` + } + + body, _ = ioutil.ReadAll(resp.Body) + resp.Body.Close() + + if err := json.Unmarshal(body, &caResp); err != nil { + fmt.Printf("%d\t%s\t%s\tError parsing cover art data\n", item.id, item.Artist, item.Name) + continue + } + + // Find and display the front cover URL + coverURL := "" + for _, img := range caResp.Images { + if img.Front { + coverURL = img.Thumbnails.Img250 + break + } + } + + if coverURL == "" { + fmt.Printf("%d\t%s\t%s\tNo front cover found\n", item.id, item.Artist, item.Name) + } else { + fmt.Printf("%d\t%s\t%s\t%s\n", item.id, item.Artist, item.Name, coverURL) + } + + // Respect API rate limits + time.Sleep(1 * time.Second) + } + + // Check for errors from iterating over rows + if err = rows.Err(); err != nil { + fmt.Printf("Error iterating over rows: %v\n", err) + } +}