diff --git a/src/modules/album/album.go b/src/modules/album/album.go new file mode 100644 index 0000000..abb7704 --- /dev/null +++ b/src/modules/album/album.go @@ -0,0 +1,60 @@ +package album + +import ( + "acide/src/modules/song" + "acide/src/utils" + "net/http" + "sync" + + "github.com/labstack/echo" + "github.com/labstack/gommon/log" +) + +func Setup(g *echo.Group) { + log.Print("Setting up the album module") + g.Use(utils.Authed) + + g.GET("/:id", albumPage) +} + +func albumPage(c echo.Context) error { + token, server := utils.Credentials(c) + albumId := c.Param("id") + + // load album info and song list on the background + var wg sync.WaitGroup + + var album *utils.Album + var songs []utils.Song + var routineErr error = nil + + wg.Add(2) + go func() { + defer wg.Done() + + res, err := loadAlbum(token, server, albumId) + if err != nil { + routineErr = err + return + } + + album = res + }() + go func() { + defer wg.Done() + + res, err := song.LoadSongs(token, server, albumId) + if err != nil { + routineErr = err + return + } + songs = res + }() + wg.Wait() + + if routineErr != nil { + return routineErr + } + + return utils.RenderTempl(c, http.StatusOK, albumTempl(albumId, album, songs)) +} diff --git a/src/modules/album/album.service.go b/src/modules/album/album.service.go new file mode 100644 index 0000000..c4a260c --- /dev/null +++ b/src/modules/album/album.service.go @@ -0,0 +1,31 @@ +package album + +import ( + "acide/src/utils" + "errors" + "fmt" + + "github.com/go-resty/resty/v2" +) + +func loadAlbum(token, server, albumId string) (*utils.Album, error) { + var album utils.Album + var error utils.NavError + + client := resty.New() + response, err := client.R(). + SetHeader("x-nd-authorization", fmt.Sprintf("Bearer %s", token)). + SetResult(&album). + SetError(&error). + Get(fmt.Sprintf("%s/api/album/%s", server, albumId)) + + if err != nil { + return nil, err + } + + if !response.IsSuccess() { + return nil, errors.New(error.Error) + } + + return &album, nil +} diff --git a/src/modules/album/album.templ b/src/modules/album/album.templ new file mode 100644 index 0000000..257c561 --- /dev/null +++ b/src/modules/album/album.templ @@ -0,0 +1,27 @@ +package album + +import ( + "acide/src/utils" + "fmt" +) + +templ albumTempl(albumId string, album *utils.Album, songs []utils.Song) { + @utils.SkeletonTempl() { +
+ +

+ { album.Name } +

+

+ { album.Artist } +

+
+ for _, song := range songs { +

+ { song.Title } +

+ } +
+
+ } +} diff --git a/src/modules/album/album_templ.go b/src/modules/album/album_templ.go new file mode 100644 index 0000000..06721f9 --- /dev/null +++ b/src/modules/album/album_templ.go @@ -0,0 +1,125 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.2.778 +package album + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import templruntime "github.com/a-h/templ/runtime" + +import ( + "acide/src/utils" + "fmt" +) + +func albumTempl(albumId string, album *utils.Album, songs []utils.Song) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Var2 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var4 string + templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(album.Name) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `src/modules/album/album.templ`, Line: 13, Col: 16} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var5 string + templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(album.Artist) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `src/modules/album/album.templ`, Line: 16, Col: 18} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + for _, song := range songs { + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var6 string + templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(song.Title) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `src/modules/album/album.templ`, Line: 21, Col: 18} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return templ_7745c5c3_Err + }) + templ_7745c5c3_Err = utils.SkeletonTempl().Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return templ_7745c5c3_Err + }) +} + +var _ = templruntime.GeneratedTemplate diff --git a/src/modules/index/index.templ b/src/modules/index/index.templ index 709fcf6..7f12b52 100644 --- a/src/modules/index/index.templ +++ b/src/modules/index/index.templ @@ -11,6 +11,9 @@ templ IndexTempl(albums []utils.Album) { +

+ Random Albums +

for _, album := range albums { @albumCard(album) @@ -24,9 +27,12 @@ templ albumCard(album utils.Album) {
- +
{ album.Artist }
diff --git a/src/modules/index/index_templ.go b/src/modules/index/index_templ.go index fbf98e5..3f6d00e 100644 --- a/src/modules/index/index_templ.go +++ b/src/modules/index/index_templ.go @@ -46,7 +46,7 @@ func IndexTempl(albums []utils.Album) templ.Component { }() } ctx = templ.InitializeContext(ctx) - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("

Random Albums

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -98,38 +98,47 @@ func albumCard(album utils.Album) templ.Component { var templ_7745c5c3_Var4 string templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("/covers/%s", album.ID)) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `src/modules/index/index.templ`, Line: 26, Col: 49} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `src/modules/index/index.templ`, Line: 29, Col: 49} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">
") + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err diff --git a/src/modules/song/song.service.go b/src/modules/song/song.service.go new file mode 100644 index 0000000..051d47b --- /dev/null +++ b/src/modules/song/song.service.go @@ -0,0 +1,31 @@ +package song + +import ( + "acide/src/utils" + "errors" + "fmt" + + "github.com/go-resty/resty/v2" +) + +func LoadSongs(token, server, albumId string) ([]utils.Song, error) { + var songs []utils.Song + var error utils.NavError + + client := resty.New() + response, err := client.R(). + SetHeader("x-nd-authorization", fmt.Sprintf("Bearer %s", token)). + SetResult(&songs). + SetError(&error). + Get(fmt.Sprintf("%s/api/song?_end=0&_order=ASC&_sort=album&_start=0&album_id=%s", server, albumId)) + + if err != nil { + return nil, err + } + + if !response.IsSuccess() { + return nil, errors.New(error.Error) + } + + return songs, nil +} diff --git a/src/routes.go b/src/routes.go index 50b3bab..ac12db8 100644 --- a/src/routes.go +++ b/src/routes.go @@ -1,6 +1,7 @@ package src import ( + "acide/src/modules/album" "acide/src/modules/auth" "acide/src/modules/covers" "acide/src/modules/index" @@ -29,6 +30,7 @@ func (s *Server) RegisterRoutes() http.Handler { index.SetupRoutes(e.Group("")) auth.SetupRoutes(e.Group("/auth")) covers.Setup(e.Group("/covers")) + album.Setup(e.Group("/album")) return e } diff --git a/src/utils/types.go b/src/utils/types.go index f0bafc8..c58b4c2 100644 --- a/src/utils/types.go +++ b/src/utils/types.go @@ -56,3 +56,51 @@ type Album struct { type NavError struct { Error string `json:"error"` } + +type Song struct { + PlayCount int `json:"playCount"` + PlayDate time.Time `json:"playDate"` + Rating int `json:"rating"` + Starred bool `json:"starred"` + StarredAt interface{} `json:"starredAt"` + BookmarkPosition int `json:"bookmarkPosition"` + ID string `json:"id"` + LibraryID int `json:"libraryId"` + Path string `json:"path"` + Title string `json:"title"` + Album string `json:"album"` + ArtistID string `json:"artistId"` + Artist string `json:"artist"` + AlbumArtistID string `json:"albumArtistId"` + AlbumArtist string `json:"albumArtist"` + AlbumID string `json:"albumId"` + HasCoverArt bool `json:"hasCoverArt"` + TrackNumber int `json:"trackNumber"` + DiscNumber int `json:"discNumber"` + Year int `json:"year"` + OriginalYear int `json:"originalYear"` + ReleaseYear int `json:"releaseYear"` + Size int `json:"size"` + Suffix string `json:"suffix"` + Duration float64 `json:"duration"` + BitRate int `json:"bitRate"` + SampleRate int `json:"sampleRate"` + Channels int `json:"channels"` + Genre string `json:"genre"` + Genres []struct { + ID string `json:"id"` + Name string `json:"name"` + } `json:"genres"` + OrderTitle string `json:"orderTitle"` + OrderAlbumName string `json:"orderAlbumName"` + OrderArtistName string `json:"orderArtistName"` + OrderAlbumArtistName string `json:"orderAlbumArtistName"` + Compilation bool `json:"compilation"` + Lyrics string `json:"lyrics"` + RgAlbumGain int `json:"rgAlbumGain"` + RgAlbumPeak int `json:"rgAlbumPeak"` + RgTrackGain int `json:"rgTrackGain"` + RgTrackPeak int `json:"rgTrackPeak"` + CreatedAt time.Time `json:"createdAt"` + UpdatedAt time.Time `json:"updatedAt"` +}