home to your local SPACEGIRL 💫 arimelody.space
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

whoever was responsible for that indentation blunder, you're fired

Signed-off-by: ari melody <ari@arimelody.me>

+937 -934
+592 -592
api/v1/music/music.go
··· 1 1 package music 2 2 3 3 import ( 4 - "fmt" 5 - "time" 4 + "fmt" 5 + "time" 6 6 ) 7 7 8 8 var ari = Artist{ 9 - Id: "arimelody", 10 - Name: "ari melody", 11 - Website: "https://arimelody.me", 9 + Id: "arimelody", 10 + Name: "ari melody", 11 + Website: "https://arimelody.me", 12 12 } 13 13 var mellodoot = Artist{ 14 - Id: "mellodoot", 15 - Name: "mellodoot", 16 - Website: "https://mellodoot.com", 14 + Id: "mellodoot", 15 + Name: "mellodoot", 16 + Website: "https://mellodoot.com", 17 17 } 18 18 var zaire = Artist{ 19 - Id: "zaire", 20 - Name: "zaire", 21 - Website: "https://supitszaire.com", 19 + Id: "zaire", 20 + Name: "zaire", 21 + Website: "https://supitszaire.com", 22 22 } 23 23 var mae = Artist{ 24 - Id: "maetaylor", 25 - Name: "mae taylor", 26 - Website: "https://mae.wtf", 24 + Id: "maetaylor", 25 + Name: "mae taylor", 26 + Website: "https://mae.wtf", 27 27 } 28 28 var loudar = Artist{ 29 - Id: "loudar", 30 - Name: "Loudar", 31 - Website: "https://alex.targoninc.com", 29 + Id: "loudar", 30 + Name: "Loudar", 31 + Website: "https://alex.targoninc.com", 32 32 } 33 33 var red = Artist { 34 - Id: "smoljorb", 35 - Name: "smoljorb", 34 + Id: "smoljorb", 35 + Name: "smoljorb", 36 36 } 37 37 38 38 func make_date_work(date string) time.Time { 39 - res, err := time.Parse("2-Jan-2006", date) 40 - if err != nil { 41 - fmt.Printf("somehow we failed to parse %s! falling back to epoch :]\n", date) 42 - return time.Unix(0, 0) 43 - } 44 - return res 39 + res, err := time.Parse("2-Jan-2006", date) 40 + if err != nil { 41 + fmt.Printf("somehow we failed to parse %s! falling back to epoch :]\n", date) 42 + return time.Unix(0, 0) 43 + } 44 + return res 45 45 } 46 46 47 47 var placeholders = []MusicRelease{ 48 - { 49 - Id: "test", 50 - Title: "test album", 51 - // Type: "album", 52 - ReleaseDate: make_date_work("18-Mar-2024"), 53 - Buyname: "go get it!!", 54 - Buylink: "https://arimelody.me/", 55 - Links: []MusicLink{ 56 - { 57 - Name: "youtube", 58 - Url: "https://youtu.be/dQw4w9WgXcQ", 59 - }, 60 - }, 61 - Description: 62 - `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.`, 63 - Credits: []MusicCredit{ 64 - { 65 - Artist: &ari, 66 - Role: "having the swag", 67 - }, 68 - { 69 - Artist: &zaire, 70 - Role: "having the swag", 71 - }, 72 - { 73 - Artist: &mae, 74 - Role: "having the swag", 75 - }, 76 - { 77 - Artist: &loudar, 78 - Role: "having the swag", 79 - }, 80 - }, 81 - Lyrics: 82 - `(call me when you fall asleep) 83 - (all in, let me ride the wave) 48 + { 49 + Id: "test", 50 + Title: "test album", 51 + // Type: "album", 52 + ReleaseDate: make_date_work("18-Mar-2024"), 53 + Buyname: "go get it!!", 54 + Buylink: "https://arimelody.me/", 55 + Links: []MusicLink{ 56 + { 57 + Name: "youtube", 58 + Url: "https://youtu.be/dQw4w9WgXcQ", 59 + }, 60 + }, 61 + Description: 62 + `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.`, 63 + Credits: []MusicCredit{ 64 + { 65 + Artist: &ari, 66 + Role: "having the swag", 67 + }, 68 + { 69 + Artist: &zaire, 70 + Role: "having the swag", 71 + }, 72 + { 73 + Artist: &mae, 74 + Role: "having the swag", 75 + }, 76 + { 77 + Artist: &loudar, 78 + Role: "having the swag", 79 + }, 80 + }, 81 + Lyrics: 82 + `(call me when you fall asleep) 83 + (all in, let me ride the wave) 84 84 85 - (okay!) 85 + (okay!) 86 86 87 - call me 88 - when you fall asleep 89 - (fall asleep, call on me) 90 - (oh babe, why don'cha) 91 - yeah, it's how you feel 92 - when the stars come out 93 - (you're never gonna get it) 94 - (while you've lost yourself in a rut) 95 - all in 96 - let me ride the wave 97 - (i'm so stressed) 98 - (i need to fly out of this place) 99 - yeah, 'cause we can drift 100 - 'til the break of dawn 101 - (i think i'll be okay) 102 - (if i can sleep today) 87 + call me 88 + when you fall asleep 89 + (fall asleep, call on me) 90 + (oh babe, why don'cha) 91 + yeah, it's how you feel 92 + when the stars come out 93 + (you're never gonna get it) 94 + (while you've lost yourself in a rut) 95 + all in 96 + let me ride the wave 97 + (i'm so stressed) 98 + (i need to fly out of this place) 99 + yeah, 'cause we can drift 100 + 'til the break of dawn 101 + (i think i'll be okay) 102 + (if i can sleep today) 103 103 104 - (switch it up!) 104 + (switch it up!) 105 105 106 - slumber party at 2AM 107 - could think of nothing more perfect 108 - than a moonlight jam 106 + slumber party at 2AM 107 + could think of nothing more perfect 108 + than a moonlight jam 109 109 110 - yeah, i've got no sleep 111 - but I'm free today 112 - yeah you could even say 113 - that i'm free2play 110 + yeah, i've got no sleep 111 + but I'm free today 112 + yeah you could even say 113 + that i'm free2play 114 114 115 - you ain't here by my side 116 - and i try to get by 117 - with my head out the window 118 - get a listen of this 115 + you ain't here by my side 116 + and i try to get by 117 + with my head out the window 118 + get a listen of this 119 119 120 - the whispers of the trees 121 - the crickets do be chirpin' 122 - i guess that's how it goes 120 + the whispers of the trees 121 + the crickets do be chirpin' 122 + i guess that's how it goes 123 123 124 - (call me when you fall asleep) 125 - (all in, let me ride the wave) 124 + (call me when you fall asleep) 125 + (all in, let me ride the wave) 126 126 127 - (let's go!) 127 + (let's go!) 128 128 129 - call me 130 - when you fall asleep 131 - (fall asleep, call on me) 132 - (oh babe, why don'cha) 133 - yeah, it's how you feel 134 - when the stars come out 135 - (you're never gonna get it) 136 - (while you've lost yourself in a rut) 137 - all in 138 - let me ride the wave 139 - (i'm so stressed) 140 - (i need to fly out of this place) 141 - yeah, 'cause we can drift 142 - 'til the break of dawn 143 - (i think i'll be okay) 144 - (if i can sleep today) 129 + call me 130 + when you fall asleep 131 + (fall asleep, call on me) 132 + (oh babe, why don'cha) 133 + yeah, it's how you feel 134 + when the stars come out 135 + (you're never gonna get it) 136 + (while you've lost yourself in a rut) 137 + all in 138 + let me ride the wave 139 + (i'm so stressed) 140 + (i need to fly out of this place) 141 + yeah, 'cause we can drift 142 + 'til the break of dawn 143 + (i think i'll be okay) 144 + (if i can sleep today) 145 145 146 - yeah... woo! 147 - (BASS) 148 - oh man... 149 - i'm just sitting here 150 - feeling the breeze 151 - hanging out 152 - listening to the crickets 153 - and the trees in the breeze 154 - living my best life`, 155 - }, 156 - // { 157 - // Id: "free2play", 158 - // Title: "free2play", 159 - // Type: "upcoming", 160 - // ReleaseDate: make_date_work("17-Mar-2024"), 161 - // Buyname: "pre-order", 162 - // Buylink: "https://arimelody.me/", 163 - // Description: "hello from your local SPACEGIRL! 💫", 164 - // Credits: []AlbumCredit{ 165 - // AlbumCredit{ 166 - // Artist: &ari, 167 - // Role: "vocals", 168 - // }, 169 - // AlbumCredit{ 170 - // Artist: &ari, 171 - // Role: "production", 172 - // }, 173 - // AlbumCredit{ 174 - // Artist: &ari, 175 - // Role: "artwork", 176 - // }, 177 - // }, 178 - // }, 179 - { 180 - Id: "dream", 181 - Title: "Dream", 182 - Type: "single", 183 - ReleaseDate: make_date_work("11-Nov-2022"), 184 - Artwork: "https://mellodoot.com/img/music_artwork/mellodoot_-_Dream.webp", 185 - Buylink: "https://arimelody.bandcamp.com/track/dream", 186 - Links: []MusicLink{ 187 - { 188 - Name: "spotify", 189 - Url: "https://open.spotify.com/album/5talRpqzjExP1w6j5LFIAh", 190 - }, 191 - { 192 - Name: "apple music", 193 - Url: "https://music.apple.com/ie/album/dream-single/1650037132", 194 - }, 195 - { 196 - Name: "soundcloud", 197 - Url: "https://soundcloud.com/arimelody/dream2022", 198 - }, 199 - { 200 - Name: "youtube", 201 - Url: "https://www.youtube.com/watch?v=nfFgtMuYAx8", 202 - }, 203 - }, 204 - Description: "living the dream 🌌 ✨", 205 - Credits: []MusicCredit{ 206 - { 207 - Artist: &mellodoot, 208 - Role: "vocals", 209 - }, 210 - { 211 - Artist: &mellodoot, 212 - Role: "production", 213 - }, 214 - { 215 - Artist: &mellodoot, 216 - Role: "artwork", 217 - }, 218 - }, 219 - Lyrics: 220 - `the truth is what you make of it 221 - in the end, what you spend, is the end of it 222 - when you're lost in the life 223 - the life that you created on your own 224 - i'm becoming one 225 - with the soul that i see in the mirror 226 - blending one and whole 227 - this time, i'm real 146 + yeah... woo! 147 + (BASS) 148 + oh man... 149 + i'm just sitting here 150 + feeling the breeze 151 + hanging out 152 + listening to the crickets 153 + and the trees in the breeze 154 + living my best life`, 155 + }, 156 + // { 157 + // Id: "free2play", 158 + // Title: "free2play", 159 + // Type: "upcoming", 160 + // ReleaseDate: make_date_work("17-Mar-2024"), 161 + // Buyname: "pre-order", 162 + // Buylink: "https://arimelody.me/", 163 + // Description: "hello from your local SPACEGIRL! 💫", 164 + // Credits: []AlbumCredit{ 165 + // AlbumCredit{ 166 + // Artist: &ari, 167 + // Role: "vocals", 168 + // }, 169 + // AlbumCredit{ 170 + // Artist: &ari, 171 + // Role: "production", 172 + // }, 173 + // AlbumCredit{ 174 + // Artist: &ari, 175 + // Role: "artwork", 176 + // }, 177 + // }, 178 + // }, 179 + { 180 + Id: "dream", 181 + Title: "Dream", 182 + Type: "single", 183 + ReleaseDate: make_date_work("11-Nov-2022"), 184 + Artwork: "https://mellodoot.com/img/music_artwork/mellodoot_-_Dream.webp", 185 + Buylink: "https://arimelody.bandcamp.com/track/dream", 186 + Links: []MusicLink{ 187 + { 188 + Name: "spotify", 189 + Url: "https://open.spotify.com/album/5talRpqzjExP1w6j5LFIAh", 190 + }, 191 + { 192 + Name: "apple music", 193 + Url: "https://music.apple.com/ie/album/dream-single/1650037132", 194 + }, 195 + { 196 + Name: "soundcloud", 197 + Url: "https://soundcloud.com/arimelody/dream2022", 198 + }, 199 + { 200 + Name: "youtube", 201 + Url: "https://www.youtube.com/watch?v=nfFgtMuYAx8", 202 + }, 203 + }, 204 + Description: "living the dream 🌌 ✨", 205 + Credits: []MusicCredit{ 206 + { 207 + Artist: &mellodoot, 208 + Role: "vocals", 209 + }, 210 + { 211 + Artist: &mellodoot, 212 + Role: "production", 213 + }, 214 + { 215 + Artist: &mellodoot, 216 + Role: "artwork", 217 + }, 218 + }, 219 + Lyrics: 220 + `the truth is what you make of it 221 + in the end, what you spend, is the end of it 222 + when you're lost in the life 223 + the life that you created on your own 224 + i'm becoming one 225 + with the soul that i see in the mirror 226 + blending one and whole 227 + this time, i'm real 228 228 229 - i'm living the dream 230 - i'm living my best life 231 - running out of time 232 - i gotta make this right 233 - whenever you rise 234 - whenever you come down 235 - fall away from the light 236 - and then fall into our arms 229 + i'm living the dream 230 + i'm living my best life 231 + running out of time 232 + i gotta make this right 233 + whenever you rise 234 + whenever you come down 235 + fall away from the light 236 + and then fall into our arms 237 237 238 - the truth is what you make of it 239 - in the end, what you spend, is the end of it 240 - when you're lost in the life 241 - the life that you created on your own 242 - i'm becoming one 243 - with the soul that i see in the mirror 244 - blending one and whole 245 - this time, i'm real`, 246 - }, 247 - { 248 - Id: "gomyway", 249 - Title: "Go My Way", 250 - Type: "single", 251 - ReleaseDate: make_date_work("24-Jan-2021"), 252 - Artwork: "https://mellodoot.com/img/music_artwork/mellodoot_-_Go_My_Way.webp", 253 - Buylink: "https://arimelody.bandcamp.com/track/go-my-way", 254 - Links: []MusicLink{ 255 - { 256 - Name: "spotify", 257 - Url: "https://open.spotify.com/album/35WNtxK12IDHCUoXHDePGE", 258 - }, 259 - { 260 - Name: "apple music", 261 - Url: "https://music.apple.com/ie/album/go-my-way-single/1547145699", 262 - }, 263 - { 264 - Name: "soundcloud", 265 - Url: "https://soundcloud.com/arimelody/go-my-way", 266 - }, 267 - { 268 - Name: "youtube", 269 - Url: "https://www.youtube.com/watch?v=CNptNQdLkl0", 270 - }, 271 - }, 272 - Description: "hey! go my way! 💥 ✨", 273 - Credits: []MusicCredit{ 274 - { 275 - Artist: &mellodoot, 276 - Role: "vocals", 277 - }, 278 - { 279 - Artist: &mellodoot, 280 - Role: "production", 281 - }, 282 - { 283 - Artist: &mellodoot, 284 - Role: "artwork", 285 - }, 286 - }, 287 - }, 288 - { 289 - Id: "rowboat", 290 - Title: "Rowboat", 291 - Type: "single", 292 - ReleaseDate: make_date_work("12-Mar-2020"), 293 - Artwork: "https://mellodoot.com/img/music_artwork/mellodoot_-_Rowboat.webp", 294 - Buylink: "https://arimelody.bandcamp.com/track/rowboat", 295 - Links: []MusicLink{ 296 - { 297 - Name: "spotify", 298 - Url: "https://open.spotify.com/album/7jyqJFVKaENCPm58v5O44Y", 299 - }, 300 - { 301 - Name: "apple music", 302 - Url: "https://music.apple.com/ie/album/rowboat-single/1502608714", 303 - }, 304 - { 305 - Name: "soundcloud", 306 - Url: "https://soundcloud.com/arimelody/rowboat", 307 - }, 308 - { 309 - Name: "youtube", 310 - Url: "https://www.youtube.com/watch?v=uOQyILDTzME", 311 - }, 312 - }, 313 - Description: "let's take a trip. i've got a goddamn boat ⛵️", 314 - Credits: []MusicCredit{ 315 - { 316 - Artist: &mellodoot, 317 - Role: "vocals", 318 - }, 319 - { 320 - Artist: &mellodoot, 321 - Role: "production", 322 - }, 323 - { 324 - Artist: &mellodoot, 325 - Role: "artwork", 326 - }, 327 - }, 328 - }, 329 - { 330 - Id: "helloworld", 331 - Title: "Hello World", 332 - Type: "single", 333 - ReleaseDate: make_date_work("25-Dec-2019"), 334 - Artwork: "https://mellodoot.com/img/music_artwork/mellodoot_-_Hello_World.webp", 335 - Buylink: "https://arimelody.bandcamp.com/track/hello-world", 336 - Links: []MusicLink{ 337 - { 338 - Name: "spotify", 339 - Url: "https://open.spotify.com/album/3LbElPXD4dsDumttGBuYxx", 340 - }, 341 - { 342 - Name: "apple music", 343 - Url: "https://music.apple.com/ie/album/hello-world-single/1491880155", 344 - }, 345 - { 346 - Name: "soundcloud", 347 - Url: "https://soundcloud.com/arimelody/helloworld", 348 - }, 349 - { 350 - Name: "youtube", 351 - Url: "https://www.youtube.com/watch?v=CQhlRsl0Mjk", 352 - }, 353 - }, 354 - Description: "we'll dawn a new frontier! 👾", 355 - Credits: []MusicCredit{ 356 - { 357 - Artist: &mellodoot, 358 - Role: "vocals", 359 - }, 360 - { 361 - Artist: &mellodoot, 362 - Role: "production", 363 - }, 364 - { 365 - Artist: &mellodoot, 366 - Role: "artwork", 367 - }, 368 - }, 369 - }, 370 - { 371 - Id: "sine", 372 - Title: "Sine", 373 - Type: "single", 374 - ReleaseDate: make_date_work("07-Dec-2019"), 375 - Artwork: "https://mellodoot.com/img/music_artwork/zaire_-_Sine_ft._mellodoot.webp", 376 - Links: []MusicLink{ 377 - { 378 - Name: "spotify", 379 - Url: "https://open.spotify.com/album/4WPuaJtTV7z86KubD9Rnmk", 380 - }, 381 - { 382 - Name: "apple music", 383 - Url: "https://music.apple.com/us/album/sine-feat-mellodoot/1489163020", 384 - }, 385 - { 386 - Name: "youtube", 387 - Url: "https://www.youtube.com/watch?v=z1H1s6VRnyY", 388 - }, 389 - }, 390 - Credits: []MusicCredit{ 391 - { 392 - Artist: &zaire, 393 - Role: "production", 394 - }, 395 - { 396 - Artist: &mellodoot, 397 - Role: "production", 398 - }, 399 - }, 400 - }, 401 - { 402 - Id: "10", 403 - Title: "10", 404 - Type: "single", 405 - ReleaseDate: make_date_work("29-Sep-2019"), 406 - Artwork: "https://mellodoot.com/img/music_artwork/mellodoot_-_10.webp", 407 - Buylink: "https://arimelody.bandcamp.com/track/10", 408 - Links: []MusicLink{ 409 - { 410 - Name: "spotify", 411 - Url: "https://open.spotify.com/album/2x4gbACfDm99unaXpLXyj0", 412 - }, 413 - { 414 - Name: "apple music", 415 - Url: "https://music.apple.com/ie/album/ten-single/1483193041", 416 - }, 417 - { 418 - Name: "soundcloud", 419 - Url: "https://soundcloud.com/arimelody/ten", 420 - }, 421 - { 422 - Name: "youtube", 423 - Url: "https://www.youtube.com/watch?v=C7WP5L2BK4U", 424 - }, 425 - }, 426 - Credits: []MusicCredit{ 427 - { 428 - Artist: &mellodoot, 429 - Role: "production", 430 - }, 431 - { 432 - Artist: &mellodoot, 433 - Role: "artwork", 434 - }, 435 - }, 436 - }, 437 - { 438 - Id: "mad", 439 - Title: "MAD", 440 - Type: "single", 441 - ReleaseDate: make_date_work("03-Nov-2018"), 442 - Artwork: "https://mellodoot.com/img/music_artwork/mellodoot_-_MAD.webp", 443 - Buylink: "https://arimelody.bandcamp.com/track/mad", 444 - Links: []MusicLink{ 445 - { 446 - Name: "spotify", 447 - Url: "https://open.spotify.com/album/59nFXw1WNoRhXou7lXqBZd", 448 - }, 449 - { 450 - Name: "apple music", 451 - Url: "https://music.apple.com/ie/album/mad/1441233120", 452 - }, 453 - { 454 - Name: "soundcloud", 455 - Url: "https://soundcloud.com/arimelody/mad", 456 - }, 457 - { 458 - Name: "youtube", 459 - Url: "https://www.youtube.com/watch?v=OB-Pk6p6mfQ", 460 - }, 461 - }, 462 - Credits: []MusicCredit{ 463 - { 464 - Artist: &mellodoot, 465 - Role: "vocals", 466 - }, 467 - { 468 - Artist: &mellodoot, 469 - Role: "production", 470 - }, 471 - { 472 - Artist: &mellodoot, 473 - Role: "artwork", 474 - }, 475 - }, 476 - }, 477 - { 478 - Id: "welcomingparty", 479 - Title: "Welcoming Party", 480 - Type: "album", 481 - ReleaseDate: make_date_work("01-Nov-2018"), 482 - Artwork: "https://mellodoot.com/img/music_artwork/mellodoot_-_Welcoming_Party.webp", 483 - Buylink: "https://arimelody.bandcamp.com/album/welcoming-party", 484 - Links: []MusicLink{ 485 - { 486 - Name: "spotify", 487 - Url: "https://open.spotify.com/album/3EPa4HZpkISQVRAks64LfR", 488 - }, 489 - { 490 - Name: "apple music", 491 - Url: "https://music.apple.com/ie/album/welcoming-party-ep/1441161424", 492 - }, 493 - { 494 - Name: "soundcloud", 495 - Url: "https://soundcloud.com/arimelody/sets/welcoming-party", 496 - }, 497 - { 498 - Name: "youtube", 499 - Url: "https://www.youtube.com/playlist?list=PLBG_QJeOHrB5EeniiXBIlHpoQbD6CUJca", 500 - }, 501 - }, 502 - Credits: []MusicCredit{ 503 - { 504 - Artist: &mellodoot, 505 - Role: "production", 506 - }, 507 - { 508 - Artist: &mellodoot, 509 - Role: "artwork", 510 - }, 511 - }, 512 - // "tracks": [ 513 - // { 514 - // "title": "Paradigm" 515 - // }, 516 - // { 517 - // "title": "Mitrio" 518 - // }, 519 - // { 520 - // "title": "Level One" 521 - // }, 522 - // { 523 - // "title": "Cubes" 524 - // }, 525 - // { 526 - // "title": "Aria" 527 - // } 528 - // ] 529 - }, 530 - { 531 - Id: "howtheyknow2018", 532 - Title: "How They Know (2018)", 533 - Type: "single", 534 - ReleaseDate: make_date_work("27-Feb-2018"), 535 - Artwork: "https://mellodoot.com/img/music_artwork/mellodoot_-_How_They_Know_2018.webp", 536 - Buyname: "free download", 537 - Buylink: "https://arimelody.bandcamp.com/track/how-they-know-2018-remastered", 538 - Links: []MusicLink{ 539 - { 540 - Name: "soundcloud", 541 - Url: "https://soundcloud.com/arimelody/how-they-know-2018", 542 - }, 543 - { 544 - Name: "youtube", 545 - Url: "https://www.youtube.com/watch?v=mbAgSwCzyMw", 546 - }, 547 - }, 548 - Credits: []MusicCredit{ 549 - { 550 - Artist: &mellodoot, 551 - Role: "production", 552 - }, 553 - { 554 - Artist: &red, 555 - Role: "artwork", 556 - Meta: true, 557 - }, 558 - }, 559 - }, 560 - { 561 - Id: "howtheyknow", 562 - Title: "How They Know", 563 - Type: "single", 564 - ReleaseDate: make_date_work("29-Nov-2017"), 565 - Artwork: "https://mellodoot.com/img/music_artwork/mellodoot_-_How_They_Know.webp", 566 - Buyname: "free download", 567 - Buylink: "https://arimelody.bandcamp.com/track/how-they-know", 568 - Links: []MusicLink{ 569 - { 570 - Name: "soundcloud", 571 - Url: "https://soundcloud.com/arimelody/how-they-know", 572 - }, 573 - { 574 - Name: "youtube", 575 - Url: "https://www.youtube.com/watch?v=q6lzKuG1Emo", 576 - }, 577 - }, 578 - Credits: []MusicCredit{ 579 - { 580 - Artist: &mellodoot, 581 - Role: "production", 582 - }, 583 - { 584 - Artist: &red, 585 - Role: "artwork", 586 - Meta: true, 587 - }, 588 - }, 589 - }, 590 - { 591 - Id: "traveller", 592 - Title: "Traveller", 593 - Type: "single", 594 - ReleaseDate: make_date_work("24-Sep-2017"), 595 - Artwork: "https://mellodoot.com/img/music_artwork/mellodoot_-_Traveller.webp", 596 - Buyname: "free download", 597 - Buylink: "https://arimelody.bandcamp.com/track/traveller", 598 - Links: []MusicLink{ 599 - { 600 - Name: "soundcloud", 601 - Url: "https://soundcloud.com/arimelody/traveller", 602 - }, 603 - { 604 - Name: "youtube", 605 - Url: "https://www.youtube.com/watch?v=ZTO7IQZ-yXA", 606 - }, 607 - }, 608 - Description: "an 8-bit expedition! ⚔️🛡️", 609 - Credits: []MusicCredit{ 610 - { 611 - Artist: &mellodoot, 612 - Role: "production", 613 - }, 614 - { 615 - Artist: &mellodoot, 616 - Role: "artwork", 617 - }, 618 - }, 619 - }, 238 + the truth is what you make of it 239 + in the end, what you spend, is the end of it 240 + when you're lost in the life 241 + the life that you created on your own 242 + i'm becoming one 243 + with the soul that i see in the mirror 244 + blending one and whole 245 + this time, i'm real`, 246 + }, 247 + { 248 + Id: "gomyway", 249 + Title: "Go My Way", 250 + Type: "single", 251 + ReleaseDate: make_date_work("24-Jan-2021"), 252 + Artwork: "https://mellodoot.com/img/music_artwork/mellodoot_-_Go_My_Way.webp", 253 + Buylink: "https://arimelody.bandcamp.com/track/go-my-way", 254 + Links: []MusicLink{ 255 + { 256 + Name: "spotify", 257 + Url: "https://open.spotify.com/album/35WNtxK12IDHCUoXHDePGE", 258 + }, 259 + { 260 + Name: "apple music", 261 + Url: "https://music.apple.com/ie/album/go-my-way-single/1547145699", 262 + }, 263 + { 264 + Name: "soundcloud", 265 + Url: "https://soundcloud.com/arimelody/go-my-way", 266 + }, 267 + { 268 + Name: "youtube", 269 + Url: "https://www.youtube.com/watch?v=CNptNQdLkl0", 270 + }, 271 + }, 272 + Description: "hey! go my way! 💥 ✨", 273 + Credits: []MusicCredit{ 274 + { 275 + Artist: &mellodoot, 276 + Role: "vocals", 277 + }, 278 + { 279 + Artist: &mellodoot, 280 + Role: "production", 281 + }, 282 + { 283 + Artist: &mellodoot, 284 + Role: "artwork", 285 + }, 286 + }, 287 + }, 288 + { 289 + Id: "rowboat", 290 + Title: "Rowboat", 291 + Type: "single", 292 + ReleaseDate: make_date_work("12-Mar-2020"), 293 + Artwork: "https://mellodoot.com/img/music_artwork/mellodoot_-_Rowboat.webp", 294 + Buylink: "https://arimelody.bandcamp.com/track/rowboat", 295 + Links: []MusicLink{ 296 + { 297 + Name: "spotify", 298 + Url: "https://open.spotify.com/album/7jyqJFVKaENCPm58v5O44Y", 299 + }, 300 + { 301 + Name: "apple music", 302 + Url: "https://music.apple.com/ie/album/rowboat-single/1502608714", 303 + }, 304 + { 305 + Name: "soundcloud", 306 + Url: "https://soundcloud.com/arimelody/rowboat", 307 + }, 308 + { 309 + Name: "youtube", 310 + Url: "https://www.youtube.com/watch?v=uOQyILDTzME", 311 + }, 312 + }, 313 + Description: "let's take a trip. i've got a goddamn boat ⛵️", 314 + Credits: []MusicCredit{ 315 + { 316 + Artist: &mellodoot, 317 + Role: "vocals", 318 + }, 319 + { 320 + Artist: &mellodoot, 321 + Role: "production", 322 + }, 323 + { 324 + Artist: &mellodoot, 325 + Role: "artwork", 326 + }, 327 + }, 328 + }, 329 + { 330 + Id: "helloworld", 331 + Title: "Hello World", 332 + Type: "single", 333 + ReleaseDate: make_date_work("25-Dec-2019"), 334 + Artwork: "https://mellodoot.com/img/music_artwork/mellodoot_-_Hello_World.webp", 335 + Buylink: "https://arimelody.bandcamp.com/track/hello-world", 336 + Links: []MusicLink{ 337 + { 338 + Name: "spotify", 339 + Url: "https://open.spotify.com/album/3LbElPXD4dsDumttGBuYxx", 340 + }, 341 + { 342 + Name: "apple music", 343 + Url: "https://music.apple.com/ie/album/hello-world-single/1491880155", 344 + }, 345 + { 346 + Name: "soundcloud", 347 + Url: "https://soundcloud.com/arimelody/helloworld", 348 + }, 349 + { 350 + Name: "youtube", 351 + Url: "https://www.youtube.com/watch?v=CQhlRsl0Mjk", 352 + }, 353 + }, 354 + Description: "we'll dawn a new frontier! 👾", 355 + Credits: []MusicCredit{ 356 + { 357 + Artist: &mellodoot, 358 + Role: "vocals", 359 + }, 360 + { 361 + Artist: &mellodoot, 362 + Role: "production", 363 + }, 364 + { 365 + Artist: &mellodoot, 366 + Role: "artwork", 367 + }, 368 + }, 369 + }, 370 + { 371 + Id: "sine", 372 + Title: "Sine", 373 + Type: "single", 374 + ReleaseDate: make_date_work("07-Dec-2019"), 375 + Artwork: "https://mellodoot.com/img/music_artwork/zaire_-_Sine_ft._mellodoot.webp", 376 + Links: []MusicLink{ 377 + { 378 + Name: "spotify", 379 + Url: "https://open.spotify.com/album/4WPuaJtTV7z86KubD9Rnmk", 380 + }, 381 + { 382 + Name: "apple music", 383 + Url: "https://music.apple.com/us/album/sine-feat-mellodoot/1489163020", 384 + }, 385 + { 386 + Name: "youtube", 387 + Url: "https://www.youtube.com/watch?v=z1H1s6VRnyY", 388 + }, 389 + }, 390 + Credits: []MusicCredit{ 391 + { 392 + Artist: &zaire, 393 + Role: "production", 394 + }, 395 + { 396 + Artist: &mellodoot, 397 + Role: "production", 398 + }, 399 + }, 400 + }, 401 + { 402 + Id: "10", 403 + Title: "10", 404 + Type: "single", 405 + ReleaseDate: make_date_work("29-Sep-2019"), 406 + Artwork: "https://mellodoot.com/img/music_artwork/mellodoot_-_10.webp", 407 + Buylink: "https://arimelody.bandcamp.com/track/10", 408 + Links: []MusicLink{ 409 + { 410 + Name: "spotify", 411 + Url: "https://open.spotify.com/album/2x4gbACfDm99unaXpLXyj0", 412 + }, 413 + { 414 + Name: "apple music", 415 + Url: "https://music.apple.com/ie/album/ten-single/1483193041", 416 + }, 417 + { 418 + Name: "soundcloud", 419 + Url: "https://soundcloud.com/arimelody/ten", 420 + }, 421 + { 422 + Name: "youtube", 423 + Url: "https://www.youtube.com/watch?v=C7WP5L2BK4U", 424 + }, 425 + }, 426 + Credits: []MusicCredit{ 427 + { 428 + Artist: &mellodoot, 429 + Role: "production", 430 + }, 431 + { 432 + Artist: &mellodoot, 433 + Role: "artwork", 434 + }, 435 + }, 436 + }, 437 + { 438 + Id: "mad", 439 + Title: "MAD", 440 + Type: "single", 441 + ReleaseDate: make_date_work("03-Nov-2018"), 442 + Artwork: "https://mellodoot.com/img/music_artwork/mellodoot_-_MAD.webp", 443 + Buylink: "https://arimelody.bandcamp.com/track/mad", 444 + Links: []MusicLink{ 445 + { 446 + Name: "spotify", 447 + Url: "https://open.spotify.com/album/59nFXw1WNoRhXou7lXqBZd", 448 + }, 449 + { 450 + Name: "apple music", 451 + Url: "https://music.apple.com/ie/album/mad/1441233120", 452 + }, 453 + { 454 + Name: "soundcloud", 455 + Url: "https://soundcloud.com/arimelody/mad", 456 + }, 457 + { 458 + Name: "youtube", 459 + Url: "https://www.youtube.com/watch?v=OB-Pk6p6mfQ", 460 + }, 461 + }, 462 + Credits: []MusicCredit{ 463 + { 464 + Artist: &mellodoot, 465 + Role: "vocals", 466 + }, 467 + { 468 + Artist: &mellodoot, 469 + Role: "production", 470 + }, 471 + { 472 + Artist: &mellodoot, 473 + Role: "artwork", 474 + }, 475 + }, 476 + }, 477 + { 478 + Id: "welcomingparty", 479 + Title: "Welcoming Party", 480 + Type: "album", 481 + ReleaseDate: make_date_work("01-Nov-2018"), 482 + Artwork: "https://mellodoot.com/img/music_artwork/mellodoot_-_Welcoming_Party.webp", 483 + Buylink: "https://arimelody.bandcamp.com/album/welcoming-party", 484 + Links: []MusicLink{ 485 + { 486 + Name: "spotify", 487 + Url: "https://open.spotify.com/album/3EPa4HZpkISQVRAks64LfR", 488 + }, 489 + { 490 + Name: "apple music", 491 + Url: "https://music.apple.com/ie/album/welcoming-party-ep/1441161424", 492 + }, 493 + { 494 + Name: "soundcloud", 495 + Url: "https://soundcloud.com/arimelody/sets/welcoming-party", 496 + }, 497 + { 498 + Name: "youtube", 499 + Url: "https://www.youtube.com/playlist?list=PLBG_QJeOHrB5EeniiXBIlHpoQbD6CUJca", 500 + }, 501 + }, 502 + Credits: []MusicCredit{ 503 + { 504 + Artist: &mellodoot, 505 + Role: "production", 506 + }, 507 + { 508 + Artist: &mellodoot, 509 + Role: "artwork", 510 + }, 511 + }, 512 + // "tracks": [ 513 + // { 514 + // "title": "Paradigm" 515 + // }, 516 + // { 517 + // "title": "Mitrio" 518 + // }, 519 + // { 520 + // "title": "Level One" 521 + // }, 522 + // { 523 + // "title": "Cubes" 524 + // }, 525 + // { 526 + // "title": "Aria" 527 + // } 528 + // ] 529 + }, 530 + { 531 + Id: "howtheyknow2018", 532 + Title: "How They Know (2018)", 533 + Type: "single", 534 + ReleaseDate: make_date_work("27-Feb-2018"), 535 + Artwork: "https://mellodoot.com/img/music_artwork/mellodoot_-_How_They_Know_2018.webp", 536 + Buyname: "free download", 537 + Buylink: "https://arimelody.bandcamp.com/track/how-they-know-2018-remastered", 538 + Links: []MusicLink{ 539 + { 540 + Name: "soundcloud", 541 + Url: "https://soundcloud.com/arimelody/how-they-know-2018", 542 + }, 543 + { 544 + Name: "youtube", 545 + Url: "https://www.youtube.com/watch?v=mbAgSwCzyMw", 546 + }, 547 + }, 548 + Credits: []MusicCredit{ 549 + { 550 + Artist: &mellodoot, 551 + Role: "production", 552 + }, 553 + { 554 + Artist: &red, 555 + Role: "artwork", 556 + Meta: true, 557 + }, 558 + }, 559 + }, 560 + { 561 + Id: "howtheyknow", 562 + Title: "How They Know", 563 + Type: "single", 564 + ReleaseDate: make_date_work("29-Nov-2017"), 565 + Artwork: "https://mellodoot.com/img/music_artwork/mellodoot_-_How_They_Know.webp", 566 + Buyname: "free download", 567 + Buylink: "https://arimelody.bandcamp.com/track/how-they-know", 568 + Links: []MusicLink{ 569 + { 570 + Name: "soundcloud", 571 + Url: "https://soundcloud.com/arimelody/how-they-know", 572 + }, 573 + { 574 + Name: "youtube", 575 + Url: "https://www.youtube.com/watch?v=q6lzKuG1Emo", 576 + }, 577 + }, 578 + Credits: []MusicCredit{ 579 + { 580 + Artist: &mellodoot, 581 + Role: "production", 582 + }, 583 + { 584 + Artist: &red, 585 + Role: "artwork", 586 + Meta: true, 587 + }, 588 + }, 589 + }, 590 + { 591 + Id: "traveller", 592 + Title: "Traveller", 593 + Type: "single", 594 + ReleaseDate: make_date_work("24-Sep-2017"), 595 + Artwork: "https://mellodoot.com/img/music_artwork/mellodoot_-_Traveller.webp", 596 + Buyname: "free download", 597 + Buylink: "https://arimelody.bandcamp.com/track/traveller", 598 + Links: []MusicLink{ 599 + { 600 + Name: "soundcloud", 601 + Url: "https://soundcloud.com/arimelody/traveller", 602 + }, 603 + { 604 + Name: "youtube", 605 + Url: "https://www.youtube.com/watch?v=ZTO7IQZ-yXA", 606 + }, 607 + }, 608 + Description: "an 8-bit expedition! ⚔️🛡️", 609 + Credits: []MusicCredit{ 610 + { 611 + Artist: &mellodoot, 612 + Role: "production", 613 + }, 614 + { 615 + Artist: &mellodoot, 616 + Role: "artwork", 617 + }, 618 + }, 619 + }, 620 620 } 621 621 622 622 func GetRelease(id string) (MusicRelease, bool) { 623 - for _, album := range placeholders { 624 - if album.Id == id { 625 - return album, true 626 - } 627 - } 628 - return MusicRelease{}, false 623 + for _, album := range placeholders { 624 + if album.Id == id { 625 + return album, true 626 + } 627 + } 628 + return MusicRelease{}, false 629 629 } 630 630 631 631 func QueryAllMusic() ([]MusicRelease) { 632 - return placeholders 632 + return placeholders 633 633 } 634 634 635 635 func QueryAllArtists() ([]Artist) { 636 - return []Artist{ ari, mellodoot, zaire, mae, loudar, red } 636 + return []Artist{ ari, mellodoot, zaire, mae, loudar, red } 637 637 } 638 638
+119 -119
api/v1/music/music_types.go
··· 1 1 package music 2 2 3 3 import ( 4 - "regexp" 5 - "strings" 6 - "time" 4 + "regexp" 5 + "strings" 6 + "time" 7 7 ) 8 8 9 9 type ( 10 - Artist struct { 11 - Id string 12 - Name string 13 - Website string 14 - } 10 + Artist struct { 11 + Id string 12 + Name string 13 + Website string 14 + } 15 15 16 - MusicRelease struct { 17 - Id string 18 - Title string 19 - Type string 20 - ReleaseDate time.Time 21 - Artwork string 22 - Buyname string 23 - Buylink string 24 - Links []MusicLink 25 - Description string 26 - Credits []MusicCredit 27 - Lyrics string 28 - } 16 + MusicRelease struct { 17 + Id string 18 + Title string 19 + Type string 20 + ReleaseDate time.Time 21 + Artwork string 22 + Buyname string 23 + Buylink string 24 + Links []MusicLink 25 + Description string 26 + Credits []MusicCredit 27 + Lyrics string 28 + } 29 29 30 - MusicLink struct { 31 - Name string 32 - Url string 33 - } 30 + MusicLink struct { 31 + Name string 32 + Url string 33 + } 34 34 35 - MusicCredit struct { 36 - Artist *Artist 37 - Role string 38 - Meta bool // for "meta" contributors (i.e. not credited for the musical work, but other related assets) 39 - } 40 - ) 35 + MusicCredit struct { 36 + Artist *Artist 37 + Role string 38 + Meta bool // for "meta" contributors (i.e. not credited for the musical work, but other related assets) 39 + } 40 + ) 41 41 42 42 func (album MusicRelease) GetUniqueArtists() []Artist { 43 - if len(album.Credits) == 1 { 44 - return []Artist{*album.Credits[0].Artist} 45 - } 43 + if len(album.Credits) == 1 { 44 + return []Artist{*album.Credits[0].Artist} 45 + } 46 46 47 - // create a map of artists to prevent duplicates 48 - res := []Artist{} 49 - for _, credit := range album.Credits { 50 - artist := *credit.Artist 51 - exists := false 52 - for _, c := range res { 53 - if c == *credit.Artist { 54 - exists = true 55 - break 56 - } 57 - } 58 - if exists { 59 - continue 60 - } 61 - res = append(res, artist) 62 - } 47 + // create a map of artists to prevent duplicates 48 + res := []Artist{} 49 + for _, credit := range album.Credits { 50 + artist := *credit.Artist 51 + exists := false 52 + for _, c := range res { 53 + if c == *credit.Artist { 54 + exists = true 55 + break 56 + } 57 + } 58 + if exists { 59 + continue 60 + } 61 + res = append(res, artist) 62 + } 63 63 64 - // now create the actual array to send 65 - return res 64 + // now create the actual array to send 65 + return res 66 66 } 67 67 68 68 func (album MusicRelease) GetUniqueNonMetaArtists() []Artist { 69 - if len(album.Credits) == 1 { 70 - return []Artist{*album.Credits[0].Artist} 71 - } 69 + if len(album.Credits) == 1 { 70 + return []Artist{*album.Credits[0].Artist} 71 + } 72 72 73 - // create a map of artists to prevent duplicates 74 - res := []Artist{} 75 - for _, credit := range album.Credits { 76 - if credit.Meta { 77 - continue 78 - } 79 - artist := *credit.Artist 80 - exists := false 81 - for _, c := range res { 82 - if c == *credit.Artist { 83 - exists = true 84 - break 85 - } 86 - } 87 - if exists { 88 - continue 89 - } 90 - res = append(res, artist) 91 - } 73 + // create a map of artists to prevent duplicates 74 + res := []Artist{} 75 + for _, credit := range album.Credits { 76 + if credit.Meta { 77 + continue 78 + } 79 + artist := *credit.Artist 80 + exists := false 81 + for _, c := range res { 82 + if c == *credit.Artist { 83 + exists = true 84 + break 85 + } 86 + } 87 + if exists { 88 + continue 89 + } 90 + res = append(res, artist) 91 + } 92 92 93 - // now create the actual array to send 94 - return res 93 + // now create the actual array to send 94 + return res 95 95 } 96 96 97 97 func (album MusicRelease) GetUniqueArtistNames() []string { 98 - if len(album.Credits) == 1 { 99 - return []string{album.Credits[0].Artist.Name} 100 - } 98 + if len(album.Credits) == 1 { 99 + return []string{album.Credits[0].Artist.Name} 100 + } 101 101 102 - artists := album.GetUniqueArtists() 103 - names := []string{} 104 - for _, artist := range artists { 105 - names = append(names, artist.Name) 106 - } 102 + artists := album.GetUniqueArtists() 103 + names := []string{} 104 + for _, artist := range artists { 105 + names = append(names, artist.Name) 106 + } 107 107 108 - return names 108 + return names 109 109 } 110 110 111 111 func (album MusicRelease) GetUniqueNonMetaArtistNames() []string { 112 - if len(album.Credits) == 1 { 113 - return []string{album.Credits[0].Artist.Name} 114 - } 112 + if len(album.Credits) == 1 { 113 + return []string{album.Credits[0].Artist.Name} 114 + } 115 115 116 - artists := album.GetUniqueNonMetaArtists() 117 - names := []string{} 118 - for _, artist := range artists { 119 - names = append(names, artist.Name) 120 - } 116 + artists := album.GetUniqueNonMetaArtists() 117 + names := []string{} 118 + for _, artist := range artists { 119 + names = append(names, artist.Name) 120 + } 121 121 122 - return names 122 + return names 123 123 } 124 124 125 125 func (album MusicRelease) PrintPrimaryArtists() string { 126 - names := album.GetUniqueNonMetaArtistNames() 127 - if len(names) == 1 { 128 - return names[0] 129 - } 130 - res := strings.Join(names[:len(names)-1], ", ") 131 - res += " & " + names[len(names)-1] 132 - return res 126 + names := album.GetUniqueNonMetaArtistNames() 127 + if len(names) == 1 { 128 + return names[0] 129 + } 130 + res := strings.Join(names[:len(names)-1], ", ") 131 + res += " & " + names[len(names)-1] 132 + return res 133 133 } 134 134 135 135 func (album MusicRelease) PrintCommaPrimaryArtists() string { 136 - names := album.GetUniqueNonMetaArtistNames() 137 - if len(names) == 1 { 138 - return names[0] 139 - } 140 - return strings.Join(names[:], ", ") 136 + names := album.GetUniqueNonMetaArtistNames() 137 + if len(names) == 1 { 138 + return names[0] 139 + } 140 + return strings.Join(names[:], ", ") 141 141 } 142 142 143 143 func (album MusicRelease) ResolveType() string { 144 - if album.Type != "" { 145 - return album.Type 146 - } 147 - return "unknown" 144 + if album.Type != "" { 145 + return album.Type 146 + } 147 + return "unknown" 148 148 } 149 149 150 150 func (album MusicRelease) ResolveArtwork() string { 151 - if album.Artwork != "" { 152 - return album.Artwork 153 - } 154 - return "/img/music-artwork/default.png" 151 + if album.Artwork != "" { 152 + return album.Artwork 153 + } 154 + return "/img/music-artwork/default.png" 155 155 } 156 156 157 157 func (album MusicRelease) PrintReleaseDate() string { 158 - return album.ReleaseDate.Format("02 January 2006") 158 + return album.ReleaseDate.Format("02 January 2006") 159 159 } 160 160 161 161 func (album MusicRelease) GetReleaseYear() int { 162 - return album.ReleaseDate.Year() 162 + return album.ReleaseDate.Year() 163 163 } 164 164 165 165 func (link MusicLink) NormaliseName() string { 166 - re := regexp.MustCompile(`[^a-z0-9]`) 167 - return strings.ToLower(re.ReplaceAllString(link.Name, "")) 166 + re := regexp.MustCompile(`[^a-z0-9]`) 167 + return strings.ToLower(re.ReplaceAllString(link.Name, "")) 168 168 } 169 169 170 170 func (credit MusicCredit) ResolveArtist() Artist { 171 - return *credit.Artist 171 + return *credit.Artist 172 172 }
+62 -62
db.go
··· 1 1 package main 2 2 3 3 import ( 4 - "arimelody.me/arimelody.me/api/v1/music" 4 + "arimelody.me/arimelody.me/api/v1/music" 5 5 6 - "fmt" 7 - "os" 8 - "time" 6 + "fmt" 7 + "os" 8 + "time" 9 9 10 - _ "github.com/lib/pq" 11 - "github.com/jmoiron/sqlx" 10 + _ "github.com/lib/pq" 11 + "github.com/jmoiron/sqlx" 12 12 ) 13 13 14 14 var schema = 15 15 `CREATE TABLE IF NOT EXISTS artists ( 16 - id TEXT PRIMARY KEY, 17 - name TEXT, 18 - website TEXT 16 + id TEXT PRIMARY KEY, 17 + name TEXT, 18 + website TEXT 19 19 ); 20 20 21 21 CREATE TABLE IF NOT EXISTS musicreleases ( 22 - id VARCHAR(64) PRIMARY KEY, 23 - title TEXT NOT NULL, 24 - type TEXT, 25 - release_date DATE NOT NULL, 26 - artwork TEXT, 27 - buyname TEXT, 28 - buylink TEXT, 29 - description TEXT, 30 - lyrics TEXT 22 + id VARCHAR(64) PRIMARY KEY, 23 + title TEXT NOT NULL, 24 + type TEXT, 25 + release_date DATE NOT NULL, 26 + artwork TEXT, 27 + buyname TEXT, 28 + buylink TEXT, 29 + description TEXT, 30 + lyrics TEXT 31 31 ); 32 32 33 33 CREATE TABLE IF NOT EXISTS musiclinks ( 34 - album VARCHAR(64) REFERENCES musicreleases(id) ON DELETE CASCADE ON UPDATE CASCADE, 35 - name TEXT, 36 - url TEXT, 37 - CONSTRAINT musiclinks_pk PRIMARY KEY (album, name) 34 + album VARCHAR(64) REFERENCES musicreleases(id) ON DELETE CASCADE ON UPDATE CASCADE, 35 + name TEXT, 36 + url TEXT, 37 + CONSTRAINT musiclinks_pk PRIMARY KEY (album, name) 38 38 ); 39 39 40 40 CREATE TABLE IF NOT EXISTS musiccredits ( 41 - album VARCHAR(64) REFERENCES musicreleases(ID) ON DELETE CASCADE, 42 - artist TEXT REFERENCES artists(id) ON DELETE CASCADE, 43 - role TEXT, 44 - meta BOOLEAN, 45 - constraint musiccredits_pk PRIMARY KEY (album, artist, role) 41 + album VARCHAR(64) REFERENCES musicreleases(ID) ON DELETE CASCADE, 42 + artist TEXT REFERENCES artists(id) ON DELETE CASCADE, 43 + role TEXT, 44 + meta BOOLEAN, 45 + constraint musiccredits_pk PRIMARY KEY (album, artist, role) 46 46 );` 47 47 48 48 func PushArtist(db *sqlx.DB, artist music.Artist) { 49 - fmt.Printf("syncing artist [%s] to database...", artist.Name) 49 + fmt.Printf("syncing artist [%s] to database...", artist.Name) 50 50 51 - db.MustExec("INSERT INTO artists (id, name, website) VALUES ($1, $2, $3) ON CONFLICT (id) DO UPDATE SET name=$2, website=$3", 52 - &artist.Id, 53 - &artist.Name, 54 - &artist.Website, 55 - ) 56 - 57 - fmt.Printf("done!\n") 51 + db.MustExec("INSERT INTO artists (id, name, website) VALUES ($1, $2, $3) ON CONFLICT (id) DO UPDATE SET name=$2, website=$3", 52 + &artist.Id, 53 + &artist.Name, 54 + &artist.Website, 55 + ) 56 + 57 + fmt.Printf("done!\n") 58 58 } 59 59 60 60 func PushRelease(db *sqlx.DB, release music.MusicRelease) { 61 - fmt.Printf("syncing release [%s] to database...", release.Id) 61 + fmt.Printf("syncing release [%s] to database...", release.Id) 62 62 63 - tx := db.MustBegin() 64 - tx.MustExec("INSERT INTO musicreleases (id, title, release_date, artwork, buyname, buylink, description, lyrics) VALUES ($1, $2, $3, $4, $5, $6, $7, $8) "+ 65 - "ON CONFLICT (id) DO UPDATE SET title=$2, release_date=$3, artwork=$4, buyname=$5, buylink=$6, description=$7, lyrics=$8", 66 - &release.Id, &release.Title, release.ReleaseDate.Format("2-Jan-2006"), &release.Artwork, &release.Buyname, &release.Buylink, &release.Description, &release.Lyrics) 63 + tx := db.MustBegin() 64 + tx.MustExec("INSERT INTO musicreleases (id, title, release_date, artwork, buyname, buylink, description, lyrics) VALUES ($1, $2, $3, $4, $5, $6, $7, $8) "+ 65 + "ON CONFLICT (id) DO UPDATE SET title=$2, release_date=$3, artwork=$4, buyname=$5, buylink=$6, description=$7, lyrics=$8", 66 + &release.Id, &release.Title, release.ReleaseDate.Format("2-Jan-2006"), &release.Artwork, &release.Buyname, &release.Buylink, &release.Description, &release.Lyrics) 67 67 68 - for _, link := range release.Links { 69 - tx.MustExec("INSERT INTO musiclinks (album, name, url) VALUES ($1, $2, $3) ON CONFLICT (album, name) DO UPDATE SET url=$3", 70 - &release.Id, &link.Name, &link.Url) 71 - } 72 - for _, credit := range release.Credits { 73 - tx.MustExec("INSERT INTO musiccredits (album, artist, role, meta) VALUES ($1, $2, $3, $4) ON CONFLICT DO NOTHING", 74 - &release.Id, &credit.Artist.Id, &credit.Role, &credit.Meta) 75 - } 68 + for _, link := range release.Links { 69 + tx.MustExec("INSERT INTO musiclinks (album, name, url) VALUES ($1, $2, $3) ON CONFLICT (album, name) DO UPDATE SET url=$3", 70 + &release.Id, &link.Name, &link.Url) 71 + } 72 + for _, credit := range release.Credits { 73 + tx.MustExec("INSERT INTO musiccredits (album, artist, role, meta) VALUES ($1, $2, $3, $4) ON CONFLICT DO NOTHING", 74 + &release.Id, &credit.Artist.Id, &credit.Role, &credit.Meta) 75 + } 76 76 77 - tx.Commit() 77 + tx.Commit() 78 78 79 - fmt.Printf("done!\n") 79 + fmt.Printf("done!\n") 80 80 } 81 81 82 82 func InitDatabase() *sqlx.DB { 83 - db, err := sqlx.Connect("postgres", "user=arimelody dbname=arimelody password=fuckingpassword sslmode=disable") 84 - if err != nil { 85 - fmt.Fprintf(os.Stderr, "unable to create database connection pool: %v\n", err) 86 - os.Exit(1) 87 - } 88 - 89 - db.SetConnMaxLifetime(time.Minute * 3) 90 - db.SetMaxOpenConns(10) 91 - db.SetMaxIdleConns(10) 83 + db, err := sqlx.Connect("postgres", "user=arimelody dbname=arimelody password=fuckingpassword sslmode=disable") 84 + if err != nil { 85 + fmt.Fprintf(os.Stderr, "unable to create database connection pool: %v\n", err) 86 + os.Exit(1) 87 + } 88 + 89 + db.SetConnMaxLifetime(time.Minute * 3) 90 + db.SetMaxOpenConns(10) 91 + db.SetMaxIdleConns(10) 92 92 93 - db.MustExec(schema) 94 - fmt.Printf("database schema synchronised.\n") 93 + db.MustExec(schema) 94 + fmt.Printf("database schema synchronised.\n") 95 95 96 - return db 96 + return db 97 97 }
+7 -4
go.mod
··· 1 1 module arimelody.me/arimelody.me 2 2 3 - go 1.22.1 3 + go 1.22 4 + 5 + require ( 6 + github.com/gomarkdown/markdown v0.0.0-20231222211730-1d6d20845b47 7 + github.com/jmoiron/sqlx v1.3.5 8 + github.com/lib/pq v1.10.9 9 + ) 4 10 5 11 require ( 6 - github.com/gomarkdown/markdown v0.0.0-20231222211730-1d6d20845b47 // indirect 7 12 github.com/jackc/pgpassfile v1.0.0 // indirect 8 13 github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect 9 14 github.com/jackc/pgx/v5 v5.5.5 // indirect 10 15 github.com/jackc/puddle/v2 v2.2.1 // indirect 11 - github.com/jmoiron/sqlx v1.3.5 // indirect 12 - github.com/lib/pq v1.10.9 // indirect 13 16 golang.org/x/crypto v0.17.0 // indirect 14 17 golang.org/x/sync v0.1.0 // indirect 15 18 golang.org/x/text v0.14.0 // indirect
+157 -157
main.go
··· 1 1 package main 2 2 3 3 import ( 4 - "fmt" 5 - "html/template" 6 - "log" 7 - "net/http" 8 - "os" 9 - "regexp" 10 - "strconv" 11 - "strings" 12 - "time" 4 + "fmt" 5 + "html/template" 6 + "log" 7 + "net/http" 8 + "os" 9 + "regexp" 10 + "strconv" 11 + "strings" 12 + "time" 13 13 14 - "arimelody.me/arimelody.me/api/v1/music" 14 + "arimelody.me/arimelody.me/api/v1/music" 15 15 16 - "github.com/gomarkdown/markdown" 17 - "github.com/gomarkdown/markdown/html" 18 - "github.com/gomarkdown/markdown/parser" 16 + "github.com/gomarkdown/markdown" 17 + "github.com/gomarkdown/markdown/html" 18 + "github.com/gomarkdown/markdown/parser" 19 19 ) 20 20 21 21 const PORT int = 8080 22 22 23 23 var mime_types = map[string]string{ 24 - "css": "text/css; charset=utf-8", 25 - "png": "image/png", 26 - "jpg": "image/jpg", 27 - "webp": "image/webp", 28 - "html": "text/html", 29 - "asc": "text/plain", 30 - "pub": "text/plain", 31 - "js": "application/javascript", 24 + "css": "text/css; charset=utf-8", 25 + "png": "image/png", 26 + "jpg": "image/jpg", 27 + "webp": "image/webp", 28 + "html": "text/html", 29 + "asc": "text/plain", 30 + "pub": "text/plain", 31 + "js": "application/javascript", 32 32 } 33 33 34 34 var base_template = template.Must(template.ParseFiles( 35 - "views/base.html", 36 - "views/header.html", 37 - "views/footer.html", 38 - "views/prideflag.html", 35 + "views/base.html", 36 + "views/header.html", 37 + "views/footer.html", 38 + "views/prideflag.html", 39 39 )) 40 40 var htmx_template = template.Must(template.New("root").Parse(`<head>{{block "head" .}}{{end}}</head>{{block "content" .}}{{end}}`)) 41 41 42 42 func log_request(req *http.Request, code int, start_time time.Time) { 43 - now := time.Now() 44 - difference := (now.Nanosecond() - start_time.Nanosecond()) / 1_000_000 45 - elapsed := "<1" 46 - if difference >= 1 { 47 - elapsed = strconv.Itoa(difference) 48 - } 43 + now := time.Now() 44 + difference := (now.Nanosecond() - start_time.Nanosecond()) / 1_000_000 45 + elapsed := "<1" 46 + if difference >= 1 { 47 + elapsed = strconv.Itoa(difference) 48 + } 49 49 50 - fmt.Printf("[%s] %s %s - %d (%sms) (%s)\n", 51 - now.Format(time.UnixDate), 52 - req.Method, 53 - req.URL.Path, 54 - code, 55 - elapsed, 56 - req.Header["User-Agent"][0], 57 - ) 50 + fmt.Printf("[%s] %s %s - %d (%sms) (%s)\n", 51 + now.Format(time.UnixDate), 52 + req.Method, 53 + req.URL.Path, 54 + code, 55 + elapsed, 56 + req.Header["User-Agent"][0], 57 + ) 58 58 } 59 59 60 60 func handle_request(writer http.ResponseWriter, req *http.Request) { 61 - uri := req.URL.Path 62 - start_time := time.Now() 61 + uri := req.URL.Path 62 + start_time := time.Now() 63 63 64 - hx_request := len(req.Header["Hx-Request"]) > 0 && req.Header["Hx-Request"][0] == "true" 64 + hx_request := len(req.Header["Hx-Request"]) > 0 && req.Header["Hx-Request"][0] == "true" 65 65 66 - // don't bother fulfilling requests to a page that's already loaded on the client! 67 - if hx_request && len(req.Header["Referer"]) > 0 && len(req.Header["Hx-Current-Url"]) > 0 { 68 - regex := regexp.MustCompile(`https?:\/\/[^\/]+`) 69 - current_location := regex.ReplaceAllString(req.Header["Hx-Current-Url"][0], "") 70 - if current_location == req.URL.Path { 71 - writer.WriteHeader(204); 72 - return 73 - } 74 - } 66 + // don't bother fulfilling requests to a page that's already loaded on the client! 67 + if hx_request && len(req.Header["Referer"]) > 0 && len(req.Header["Hx-Current-Url"]) > 0 { 68 + regex := regexp.MustCompile(`https?:\/\/[^\/]+`) 69 + current_location := regex.ReplaceAllString(req.Header["Hx-Current-Url"][0], "") 70 + if current_location == req.URL.Path { 71 + writer.WriteHeader(204); 72 + return 73 + } 74 + } 75 75 76 - code := func(writer http.ResponseWriter, req *http.Request) int { 77 - var root *template.Template 78 - if hx_request { 79 - root = template.Must(htmx_template.Clone()) 80 - } else { 81 - root = template.Must(base_template.Clone()) 82 - } 76 + code := func(writer http.ResponseWriter, req *http.Request) int { 77 + var root *template.Template 78 + if hx_request { 79 + root = template.Must(htmx_template.Clone()) 80 + } else { 81 + root = template.Must(base_template.Clone()) 82 + } 83 83 84 - if req.URL.Path == "/" { 85 - return index_handler(writer, root) 86 - } 84 + if req.URL.Path == "/" { 85 + return index_handler(writer, root) 86 + } 87 87 88 - if uri == "/music" || uri == "/music/" { 89 - return music_directory_handler(writer, root) 90 - } 88 + if uri == "/music" || uri == "/music/" { 89 + return music_directory_handler(writer, root) 90 + } 91 91 92 - if strings.HasPrefix(uri, "/music/") { 93 - return music_gateway_handler(writer, req, root) 94 - } 92 + if strings.HasPrefix(uri, "/music/") { 93 + return music_gateway_handler(writer, req, root) 94 + } 95 95 96 - return static_handler(writer, req) 97 - }(writer, req) 96 + return static_handler(writer, req) 97 + }(writer, req) 98 98 99 - log_request(req, code, start_time) 99 + log_request(req, code, start_time) 100 100 } 101 101 102 102 func index_handler(writer http.ResponseWriter, root *template.Template) int { 103 - index_template := template.Must(root.ParseFiles("views/index.html")) 104 - err := index_template.Execute(writer, nil) 105 - if err != nil { 106 - http.Error(writer, err.Error(), http.StatusInternalServerError) 107 - return 500 108 - } 109 - return 200 103 + index_template := template.Must(root.ParseFiles("views/index.html")) 104 + err := index_template.Execute(writer, nil) 105 + if err != nil { 106 + http.Error(writer, err.Error(), http.StatusInternalServerError) 107 + return 500 108 + } 109 + return 200 110 110 } 111 111 112 112 func music_directory_handler(writer http.ResponseWriter, root *template.Template) int { 113 - music_template := template.Must(root.ParseFiles("views/music.html")) 114 - music := music.QueryAllMusic() 115 - err := music_template.Execute(writer, music) 116 - if err != nil { 117 - http.Error(writer, err.Error(), http.StatusInternalServerError) 118 - return 500 119 - } 120 - return 200 113 + music_template := template.Must(root.ParseFiles("views/music.html")) 114 + music := music.QueryAllMusic() 115 + err := music_template.Execute(writer, music) 116 + if err != nil { 117 + http.Error(writer, err.Error(), http.StatusInternalServerError) 118 + return 500 119 + } 120 + return 200 121 121 } 122 122 123 123 func music_gateway_handler(writer http.ResponseWriter, req *http.Request, root *template.Template) int { 124 - id := req.URL.Path[len("/music/"):] 125 - // http.Redirect(writer, req, "https://mellodoot.com/music/"+title, 302) 126 - // return 127 - release, ok := music.GetRelease(id) 128 - if !ok { 129 - http.Error(writer, "404 not found", http.StatusNotFound) 130 - return 404 131 - } 132 - gateway_template := template.Must(root.ParseFiles("views/music-gateway.html")) 133 - err := gateway_template.Execute(writer, release) 134 - if err != nil { 135 - http.Error(writer, err.Error(), http.StatusInternalServerError) 136 - return 500 137 - } 138 - return 200 124 + id := req.URL.Path[len("/music/"):] 125 + // http.Redirect(writer, req, "https://mellodoot.com/music/"+title, 302) 126 + // return 127 + release, ok := music.GetRelease(id) 128 + if !ok { 129 + http.Error(writer, "404 not found", http.StatusNotFound) 130 + return 404 131 + } 132 + gateway_template := template.Must(root.ParseFiles("views/music-gateway.html")) 133 + err := gateway_template.Execute(writer, release) 134 + if err != nil { 135 + http.Error(writer, err.Error(), http.StatusInternalServerError) 136 + return 500 137 + } 138 + return 200 139 139 } 140 140 141 141 func static_handler(writer http.ResponseWriter, req *http.Request) int { 142 - filename := "public/" + req.URL.Path[1:] 142 + filename := "public/" + req.URL.Path[1:] 143 143 144 - // check the file's metadata 145 - info, err := os.Stat(filename) 146 - if err != nil { 147 - http.Error(writer, "404 not found", http.StatusNotFound) 148 - return 404 149 - } 144 + // check the file's metadata 145 + info, err := os.Stat(filename) 146 + if err != nil { 147 + http.Error(writer, "404 not found", http.StatusNotFound) 148 + return 404 149 + } 150 150 151 - if len(req.Header["If-Modified-Since"]) > 0 && req.Header["If-Modified-Since"][0] != "" { 152 - if_modified_since_time, err := time.Parse(http.TimeFormat, req.Header["If-Modified-Since"][0]) 153 - if err != nil { 154 - http.Error(writer, "400 bad request", http.StatusBadRequest) 155 - return 400 156 - } 157 - if req.Header["If-Modified-Since"][0] == info.ModTime().Format(http.TimeFormat) || if_modified_since_time.After(info.ModTime()) { 158 - writer.WriteHeader(304) // not modified 159 - return 304 160 - } 161 - } 151 + if len(req.Header["If-Modified-Since"]) > 0 && req.Header["If-Modified-Since"][0] != "" { 152 + if_modified_since_time, err := time.Parse(http.TimeFormat, req.Header["If-Modified-Since"][0]) 153 + if err != nil { 154 + http.Error(writer, "400 bad request", http.StatusBadRequest) 155 + return 400 156 + } 157 + if req.Header["If-Modified-Since"][0] == info.ModTime().Format(http.TimeFormat) || if_modified_since_time.After(info.ModTime()) { 158 + writer.WriteHeader(304) // not modified 159 + return 304 160 + } 161 + } 162 162 163 - // set other nice headers 164 - writer.Header().Set("Cache-Control", "max-age=86400") 165 - writer.Header().Set("Last-Modified", info.ModTime().Format(http.TimeFormat)) 166 - // Last-Modified: <day-name>, <day> <month> <year> <hour>:<minute>:<second> GMT 167 - // Last-Modified: Wed, 21 Oct 2015 07:28:00 GMT 163 + // set other nice headers 164 + writer.Header().Set("Cache-Control", "max-age=86400") 165 + writer.Header().Set("Last-Modified", info.ModTime().Format(http.TimeFormat)) 166 + // Last-Modified: <day-name>, <day> <month> <year> <hour>:<minute>:<second> GMT 167 + // Last-Modified: Wed, 21 Oct 2015 07:28:00 GMT 168 168 169 - // read the file 170 - body, err := os.ReadFile(filename) 171 - if err != nil { 172 - http.Error(writer, err.Error(), http.StatusInternalServerError) 173 - return 500 174 - } 169 + // read the file 170 + body, err := os.ReadFile(filename) 171 + if err != nil { 172 + http.Error(writer, err.Error(), http.StatusInternalServerError) 173 + return 500 174 + } 175 175 176 - // setting MIME types 177 - filetype := filename[strings.LastIndex(filename, ".")+1:] 178 - if mime_type, ok := mime_types[filetype]; ok { 179 - writer.Header().Set("Content-Type", mime_type) 180 - } else { 181 - writer.Header().Set("Content-Type", "text/plain; charset=utf-8") 182 - } 176 + // setting MIME types 177 + filetype := filename[strings.LastIndex(filename, ".")+1:] 178 + if mime_type, ok := mime_types[filetype]; ok { 179 + writer.Header().Set("Content-Type", mime_type) 180 + } else { 181 + writer.Header().Set("Content-Type", "text/plain; charset=utf-8") 182 + } 183 183 184 - writer.Write([]byte(body)) 185 - return 200 184 + writer.Write([]byte(body)) 185 + return 200 186 186 } 187 187 188 188 func parse_markdown(md []byte) []byte { 189 - extensions := parser.CommonExtensions | parser.AutoHeadingIDs | parser.NoEmptyLineBeforeBlock 190 - p := parser.NewWithExtensions(extensions) 191 - doc := p.Parse(md) 189 + extensions := parser.CommonExtensions | parser.AutoHeadingIDs | parser.NoEmptyLineBeforeBlock 190 + p := parser.NewWithExtensions(extensions) 191 + doc := p.Parse(md) 192 192 193 - htmlFlags := html.CommonFlags 194 - opts := html.RendererOptions{Flags: htmlFlags} 195 - renderer := html.NewRenderer(opts) 193 + htmlFlags := html.CommonFlags 194 + opts := html.RendererOptions{Flags: htmlFlags} 195 + renderer := html.NewRenderer(opts) 196 196 197 - return markdown.Render(doc, renderer) 197 + return markdown.Render(doc, renderer) 198 198 } 199 199 200 200 func push_to_db_this_is_a_testing_thing_and_will_be_superfluous_later() { 201 - db := InitDatabase() 202 - defer db.Close() 201 + db := InitDatabase() 202 + defer db.Close() 203 203 204 - for _, artist := range music.QueryAllArtists() { 205 - PushArtist(db, artist) 206 - } 204 + for _, artist := range music.QueryAllArtists() { 205 + PushArtist(db, artist) 206 + } 207 207 208 - for _, album := range music.QueryAllMusic() { 209 - PushRelease(db, album) 210 - } 208 + for _, album := range music.QueryAllMusic() { 209 + PushRelease(db, album) 210 + } 211 211 } 212 212 213 213 func main() { 214 - push_to_db_this_is_a_testing_thing_and_will_be_superfluous_later() 214 + push_to_db_this_is_a_testing_thing_and_will_be_superfluous_later() 215 215 216 - http.HandleFunc("/", handle_request) 216 + http.HandleFunc("/", handle_request) 217 217 218 - fmt.Printf("now serving at http://127.0.0.1:%d\n", PORT) 219 - log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", PORT), nil)) 218 + fmt.Printf("now serving at http://127.0.0.1:%d\n", PORT) 219 + log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", PORT), nil)) 220 220 }