package music import ( "errors" "fmt" "strings" "time" "github.com/jmoiron/sqlx" ) type ReleaseType string const ( Single ReleaseType = "Single" Album ReleaseType = "Album" EP ReleaseType = "EP" Compilation ReleaseType = "Compilation" ) type Release struct { id string title string releaseType ReleaseType releaseDate time.Time artwork string buyname string buylink string links []Link description string credits []Credit tracks []Track } var Releases []Release; // GETTERS func (release Release) GetID() string { return release.id } func (release Release) GetTitle() string { return release.title } func (release Release) GetType() ReleaseType { return release.releaseType } func (release Release) GetReleaseDate() time.Time { return release.releaseDate } func (release Release) GetArtwork() string { if release.artwork == "" { return "/img/music-artwork/default.png" } return release.artwork } func (release Release) GetBuyName() string { return release.buyname } func (release Release) GetBuyLink() string { return release.buylink } func (release Release) GetLinks() []Link { return release.links } func (release Release) GetDescription() string { return release.description } func (release Release) GetCredits() []Credit { return release.credits } func (release Release) GetTracks() []Track { return release.tracks } // SETTERS func (release Release) SetID(id string) error { // TODO: update DB release.id = id return nil } func (release Release) SetTitle(title string) error { // TODO: update DB release.title = title return nil } func (release Release) SetType(releaseType ReleaseType) error { // TODO: update DB release.releaseType = releaseType return nil } func (release Release) SetReleaseDate(releaseDate time.Time) error { // TODO: update DB release.releaseDate = releaseDate return nil } func (release Release) SetArtwork(artwork string) error { // TODO: update DB release.artwork = artwork return nil } func (release Release) SetBuyName(buyname string) error { // TODO: update DB release.buyname = buyname return nil } func (release Release) SetBuyLink(buylink string) error { // TODO: update DB release.buylink = buylink return nil } func (release Release) SetLinks(links []Link) error { // TODO: update DB release.links = links return nil } func (release Release) SetDescription(description string) error { // TODO: update DB release.description = description return nil } func (release Release) SetCredits(credits []Credit) error { // TODO: update DB release.credits = credits return nil } func (release Release) SetTracks(tracks []Track) error { // TODO: update DB release.tracks = tracks return nil } // MISC func GetRelease(id string) *Release { for _, release := range Releases { if release.GetID() == id { return &release } } return nil } func (release Release) PrintReleaseDate() string { return release.releaseDate.Format("02 January 2006") } func (release Release) GetReleaseYear() int { return release.releaseDate.Year() } func (release Release) IsSingle() bool { return len(release.tracks) == 1; } func (release Release) IsReleased() bool { return release.releaseDate.Before(time.Now()) } func (release Release) GetUniqueArtists(only_primary bool) []Artist { var artists = []Artist{} for _, credit := range release.credits { if only_primary && !credit.primary { continue } exists := false for _, a := range artists { if a.id == credit.artist.id { exists = true break } } if exists { continue } artists = append(artists, *credit.artist) } return artists } func (release Release) GetUniqueArtistNames(only_primary bool) []string { var names = []string{} for _, artist := range release.GetUniqueArtists(only_primary) { names = append(names, artist.GetName()) } return names } func (release Release) PrintArtists(only_primary bool, ampersand bool) string { names := release.GetUniqueArtistNames(only_primary) if len(names) == 0 { return "Unknown Artist" } else if len(names) == 1 { return names[0] } if ampersand { res := strings.Join(names[:len(names)-1], ", ") res += " & " + names[len(names)-1] return res } else { return strings.Join(names[:], ", ") } } // DATABASE func (release Release) PushToDB(db *sqlx.DB) error { // fmt.Printf("Pushing release [%s] to database...", release.id) tx, err := db.Begin() if err != nil { return errors.New(fmt.Sprintf("Failed to initiate transaction: %s", err)) } _, err = tx.Exec("INSERT INTO musicreleases (id, title, type, release_date, artwork, buyname, buylink) VALUES ($1, $2, $3, $4, $5, $6, $7) "+ "ON CONFLICT (id) DO UPDATE SET title=$2, type=$3, release_date=$4, artwork=$5, buyname=$6, buylink=$7", release.id, release.title, release.releaseType, release.releaseDate.Format("2-Jan-2006"), release.artwork, release.buyname, release.buylink) for _, link := range release.links { _, err = tx.Exec( "INSERT INTO musiclinks (release, name, url) "+ "VALUES ($1, $2, $3) "+ "ON CONFLICT (release, name) "+ "DO UPDATE SET url=$3 ", release.id, link.name, link.url, ) if err != nil { return errors.New(fmt.Sprintf("Failed to add music link to transaction: %s", err)) } } for _, credit := range release.credits { _, err = tx.Exec( "INSERT INTO musiccredits (release, artist, role, is_primary) "+ "VALUES ($1, $2, $3, $4) "+ "ON CONFLICT (release, artist) "+ "DO UPDATE SET role=$3, is_primary=$4", release.id, credit.artist.id, credit.role, credit.primary, ) if err != nil { return errors.New(fmt.Sprintf("Failed to add music credit to transaction: %s", err)) } } for _, track := range release.tracks { _, err = tx.Exec( "INSERT INTO musictracks (release, number, title, description, lyrics, preview_url) "+ "VALUES ($1, $2, $3, $4, $5, $6) "+ "ON CONFLICT (release, number) "+ "DO UPDATE SET title=$3, description=$4, lyrics=$5, preview_url=$6", release.id, track.number, track.title, track.description, track.lyrics, track.previewURL, ) if err != nil { return errors.New(fmt.Sprintf("Failed to add music track to transaction: %s", err)) } } err = tx.Commit() if err != nil { return errors.New(fmt.Sprintf("Failed to commit transaction: %s", err)) } // fmt.Printf("done!\n") return nil } func (release Release) DeleteFromDB(db *sqlx.DB) error { // this probably doesn't need to be a transaction; // i just felt like making it one tx, err := db.Begin() if err != nil { return errors.New(fmt.Sprintf("Failed to initiate transaction: %s", err)) } _, err = tx.Exec("DELETE FROM musicreleases WHERE id=$1", release.id) err = tx.Commit() if err != nil { return errors.New(fmt.Sprintf("Failed to commit transaction: %s", err)) } return nil } func PullAllReleases(db *sqlx.DB) ([]Release, error) { releases := []Release{} rows, err := db.Query("SELECT id, title, description, type, release_date, artwork, buyname, buylink FROM musicreleases") if err != nil { return nil, err } for rows.Next() { var release = Release{} err = rows.Scan( &release.id, &release.title, &release.description, &release.releaseType, &release.releaseDate, &release.artwork, &release.buyname, &release.buylink, ) if err != nil { fmt.Printf("Error while pulling a release: %s\n", err) continue } release.credits, err = PullReleaseCredits(db, release.id) if err != nil { fmt.Printf("Failed to pull credits for %s: %v\n", release.id, err) } release.links, err = PullReleaseLinks(db, release.id) if err != nil { fmt.Printf("Failed to pull links for %s: %v\n", release.id, err) } release.tracks, err = PullReleaseTracks(db, release.id) if err != nil { return nil, errors.New(fmt.Sprintf("error pulling tracks for %s: %v\n", release.id, err)) } releases = append(releases, release) } return releases, nil }