Skip to content
This repository was archived by the owner on Jan 29, 2025. It is now read-only.

Commit de89a2b

Browse files
committed
feat: add missing fields for catalog item
1 parent 862e117 commit de89a2b

10 files changed

+204
-162
lines changed

Diff for: README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ Run a simple cli based on this project by downloading a [release](https://github
2727
Afterwards usage is as simple as this:
2828

2929
```bash
30-
$ ./monstercat releases --search="mix contest"
30+
$ ./monstercat catalog --search="mix contest"
3131
+------------+-------------------------------------------------+------------+---------+--------------+
3232
| CATALOG ID | TITLE | ARTIST | TYPE | RELEASE DATE |
3333
+------------+-------------------------------------------------+------------+---------+--------------+
@@ -65,7 +65,7 @@ import (
6565

6666
func main() {
6767
client := monstercat.NewClient()
68-
catalog, err := client.GetCatalog("mix contest", "podcast", 5, 0)
68+
catalog, err := client.Catalog("mix contest", "podcast", 5, 0)
6969
if err != nil {
7070
fmt.Printf("error: %s", err)
7171
os.Exit(1)

Diff for: cmd/catalog.go

+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package cmd
2+
3+
import (
4+
"fmt"
5+
"os"
6+
7+
"github.com/menzerath/monstercat-api/monstercat"
8+
"github.com/olekukonko/tablewriter"
9+
"github.com/spf13/cobra"
10+
)
11+
12+
var (
13+
catalogSearch string
14+
catalogType string
15+
catalogLimit int
16+
catalogOffset int
17+
)
18+
19+
func init() {
20+
catalogCmd.Flags().StringVarP(&catalogSearch, "search", "s", "", "search query")
21+
catalogCmd.Flags().StringVarP(&catalogType, "type", "t", "", "type of release")
22+
catalogCmd.Flags().IntVar(&catalogLimit, "limit", 10, "limit number of catalog")
23+
catalogCmd.Flags().IntVar(&catalogOffset, "offset", 0, "offset number of catalog")
24+
25+
rootCmd.AddCommand(catalogCmd)
26+
}
27+
28+
var catalogCmd = &cobra.Command{
29+
Use: "catalog",
30+
Short: "catalog returns a set of the most recent Monstercat catalog items",
31+
Run: func(cmd *cobra.Command, args []string) {
32+
catalog, err := monstercat.NewClient().Catalog(catalogSearch, catalogType, catalogLimit, catalogOffset)
33+
if err != nil {
34+
fmt.Printf("error fetching catalog: %s", err)
35+
os.Exit(1)
36+
}
37+
38+
table := tablewriter.NewWriter(os.Stdout)
39+
table.SetAutoWrapText(false)
40+
table.SetHeader([]string{"Title", "Artist", "Album", "Catalog ID", "Type", "Release Date"})
41+
table.SetCaption(true, fmt.Sprintf("%d of %d results", len(catalog.Data), catalog.Total))
42+
43+
for _, item := range catalog.Data {
44+
title := item.Title
45+
if item.Version != "" {
46+
title = fmt.Sprintf("%s (%s)", item.Title, item.Version)
47+
}
48+
49+
table.Append([]string{title, item.ArtistsTitle, item.Release.Title, item.Release.CatalogID, string(item.Release.Type), item.DebutDate.Format("2006-01-02")})
50+
}
51+
table.Render()
52+
},
53+
}

Diff for: cmd/releases.go

-48
This file was deleted.

Diff for: monstercat/catalog.go

+8-4
Original file line numberDiff line numberDiff line change
@@ -8,22 +8,26 @@ import (
88
"net/url"
99
)
1010

11-
// Catalog represents a list of releases from Monstercat API
11+
// Catalog represents a list of catalog items from Monstercat API
1212
type Catalog struct {
1313
Data []CatalogItem `json:"Data"`
1414
Total int `json:"Total"`
1515
Limit int `json:"Limit"`
1616
Offset int `json:"Offset"`
1717
}
1818

19-
// GetCatalog returns a set of releases containing the given search query, matching the given release type and being within the given range.
19+
// Catalog returns a set of catalog items containing the given search query, matching the given release type and being within the given range.
2020
// While limit and offset are required, you may leave search and releaseType empty to ignore those filters.
21-
func (client Client) GetCatalog(search string, releaseType string, limit int, offset int) (Catalog, error) {
21+
// TODO: add brands[], tags[] and genres[]
22+
func (client Client) Catalog(search string, releaseType string, limit int, offset int) (Catalog, error) {
2223
catalog := Catalog{}
2324

2425
urlParameters := url.Values{}
2526
urlParameters.Add("search", search)
2627
urlParameters.Add("types[]", releaseType)
28+
urlParameters.Add("sort", "-date") // TODO: make configurable + add values
29+
urlParameters.Add("nogold", "false") // TODO: make configurable
30+
urlParameters.Add("onlyReleased", "false") // TODO: make configurable
2731
urlParameters.Add("limit", fmt.Sprintf("%d", limit))
2832
urlParameters.Add("offset", fmt.Sprintf("%d", offset))
2933

@@ -58,7 +62,7 @@ func (client Client) GetCatalog(search string, releaseType string, limit int, of
5862
return catalog, nil
5963
}
6064

61-
// HasNextPage returns true if the release list contains more pages, false otherwise.
65+
// HasNextPage returns true if the catalog list contains more pages, false otherwise.
6266
func (catalog Catalog) HasNextPage() bool {
6367
return (catalog.Offset + catalog.Limit) < catalog.Total
6468
}

Diff for: monstercat/catalog_item.go

+66
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package monstercat
2+
3+
import (
4+
"time"
5+
)
6+
7+
// CatalogItem represents a single release from Monstercat API
8+
type CatalogItem struct {
9+
ID string `json:"Id"`
10+
ISRC string `json:"ISRC"`
11+
Title string `json:"Title"`
12+
Artists []Artist `json:"Artists"`
13+
ArtistsTitle string `json:"ArtistsTitle"`
14+
DebutDate time.Time `json:"DebutDate"`
15+
Release Release `json:"Release"`
16+
Tags []string `json:"Tags"`
17+
Version string `json:"Version"`
18+
19+
Brand string `json:"Brand"`
20+
BrandID int `json:"BrandId"`
21+
22+
BPM float32 `json:"BPM"`
23+
Duration int `json:"Duration"`
24+
Explicit bool `json:"Explicit"`
25+
GenrePrimary string `json:"GenrePrimary"`
26+
GenreSecondary string `json:"GenreSecondary"`
27+
28+
CreatorFriendly bool `json:"CreatorFriendly"`
29+
Downloadable bool `json:"Downloadable"`
30+
InEarlyAccess bool `json:"InEarlyAccess"`
31+
Streamable bool `json:"Streamable"`
32+
}
33+
34+
// Artist describes a single artist of a CatalogItem
35+
type Artist struct {
36+
ID string `json:"Id"`
37+
Name string `json:"Name"`
38+
Role string `json:"Role"`
39+
URI string `json:"URI"`
40+
}
41+
42+
// Release describes which release a CatalogItem belongs to
43+
type Release struct {
44+
ArtistsTitle string `json:"ArtistsTitle"`
45+
CatalogID string `json:"CatalogId"`
46+
Description string `json:"Description"`
47+
ID string `json:"Id"`
48+
ReleaseDate time.Time `json:"ReleaseDate"`
49+
Title string `json:"Title"`
50+
Type ReleaseType `json:"Type"`
51+
UPC string `json:"UPC"`
52+
Version string `json:"Version"`
53+
}
54+
55+
// ReleaseType describes what kind of release we are looking at
56+
type ReleaseType string
57+
58+
// define all known release types
59+
const (
60+
ReleaseTypeAlbum ReleaseType = "Album"
61+
ReleaseTypeCompilation ReleaseType = "Compilation"
62+
ReleaseTypeEP ReleaseType = "EP"
63+
ReleaseTypeMixes ReleaseType = "Mixes"
64+
ReleaseTypePodcast ReleaseType = "Podcast"
65+
ReleaseTypeSingle ReleaseType = "Single"
66+
)

Diff for: monstercat/catalog_test.go

+8-8
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import (
99
func TestCatalog(t *testing.T) {
1010
client := NewClient()
1111

12-
catalog, err := client.GetCatalog("", "", 10, 0)
12+
catalog, err := client.Catalog("", "", 10, 0)
1313
assert.NoError(t, err)
1414
assert.NotEmpty(t, catalog.Data)
1515
assert.NotEqual(t, 0, catalog.Total)
@@ -19,7 +19,7 @@ func TestCatalog(t *testing.T) {
1919
func TestCatalog_Search(t *testing.T) {
2020
client := NewClient()
2121

22-
catalog, err := client.GetCatalog("mix", "", 10, 0)
22+
catalog, err := client.Catalog("mix", "", 10, 0)
2323
assert.NoError(t, err)
2424
assert.NotEmpty(t, catalog.Data)
2525
assert.NotEqual(t, 0, catalog.Total)
@@ -29,7 +29,7 @@ func TestCatalog_Search(t *testing.T) {
2929
func TestCatalog_Search_NoResults(t *testing.T) {
3030
client := NewClient()
3131

32-
catalog, err := client.GetCatalog("xxx not found xxx", "", 10, 0)
32+
catalog, err := client.Catalog("xxx not found xxx", "", 10, 0)
3333
assert.NoError(t, err)
3434
assert.Empty(t, catalog.Data)
3535
assert.Equal(t, 0, catalog.Total)
@@ -39,7 +39,7 @@ func TestCatalog_Search_NoResults(t *testing.T) {
3939
func TestCatalog_Type(t *testing.T) {
4040
client := NewClient()
4141

42-
catalog, err := client.GetCatalog("", string(ReleaseTypeSingle), 10, 0)
42+
catalog, err := client.Catalog("", string(ReleaseTypeSingle), 10, 0)
4343
assert.NoError(t, err)
4444
assert.NotEmpty(t, catalog.Data)
4545
assert.NotEqual(t, 0, catalog.Total)
@@ -49,7 +49,7 @@ func TestCatalog_Type(t *testing.T) {
4949
func TestCatalog_Type_NoResults(t *testing.T) {
5050
client := NewClient()
5151

52-
catalog, err := client.GetCatalog("", "xxx not found", 10, 0)
52+
catalog, err := client.Catalog("", "xxx not found", 10, 0)
5353
assert.NoError(t, err)
5454
assert.Empty(t, catalog.Data)
5555
assert.Equal(t, 0, catalog.Total)
@@ -59,7 +59,7 @@ func TestCatalog_Type_NoResults(t *testing.T) {
5959
func TestCatalog_Search_Type(t *testing.T) {
6060
client := NewClient()
6161

62-
catalog, err := client.GetCatalog("mix", string(ReleaseTypeCompilation), 5, 0)
62+
catalog, err := client.Catalog("mix", string(ReleaseTypeCompilation), 5, 0)
6363
assert.NoError(t, err)
6464
assert.NotEmpty(t, catalog.Data)
6565
assert.NotEqual(t, 0, catalog.Total)
@@ -69,11 +69,11 @@ func TestCatalog_Search_Type(t *testing.T) {
6969
func TestCatalogUntilEnd(t *testing.T) {
7070
client := NewClient()
7171

72-
catalog, err := client.GetCatalog("", "", 100, 0)
72+
catalog, err := client.Catalog("", "", 100, 0)
7373
assert.NoError(t, err)
7474

7575
for catalog.HasNextPage() {
76-
catalog, err = client.GetCatalog("", "", catalog.Limit, catalog.Offset+catalog.Limit)
76+
catalog, err = client.Catalog("", "", catalog.Limit, catalog.Offset+catalog.Limit)
7777
assert.NoError(t, err)
7878
}
7979
}

Diff for: monstercat/download.go

+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package monstercat
2+
3+
import (
4+
"fmt"
5+
"io"
6+
"net/http"
7+
"os"
8+
)
9+
10+
// DownloadFormat describes in what kind of formats we can download a release
11+
type DownloadFormat string
12+
13+
// define all known download formats
14+
const (
15+
DownloadReleaseFormatFlac = "flac"
16+
DownloadReleaseFormatMP3 = "mp3_320"
17+
DownloadReleaseFormatWAV = "wav"
18+
)
19+
20+
// DownloadRelease downloads the given release as ZIP file in the requested format and stores it at the given path
21+
func (client Client) DownloadRelease(release Release, downloadFormat DownloadFormat, downloadPath string) error {
22+
if !client.IsLoggedIn() {
23+
return ErrorClientNotLoggedIn
24+
}
25+
26+
request, err := http.NewRequest("GET", fmt.Sprintf(endpointDownloadRelease, release.ID, downloadFormat), http.NoBody)
27+
if err != nil {
28+
return err
29+
}
30+
if client.IsLoggedIn() {
31+
request.Header.Set("Cookie", fmt.Sprintf("%s=%s", authenticationCookieName, client.authenticationCookie))
32+
}
33+
34+
httpClient := &http.Client{}
35+
response, err := httpClient.Do(request)
36+
if err != nil {
37+
return err
38+
}
39+
defer response.Body.Close()
40+
41+
if response.StatusCode != http.StatusOK {
42+
message, err := io.ReadAll(response.Body)
43+
if err != nil {
44+
return fmt.Errorf("http error %d", response.StatusCode)
45+
}
46+
return fmt.Errorf("http error %d: %s", response.StatusCode, message)
47+
}
48+
49+
// create and save file
50+
targetFile, err := os.Create(downloadPath)
51+
if err != nil {
52+
return err
53+
}
54+
_, err = io.Copy(targetFile, response.Body)
55+
if err != nil {
56+
return err
57+
}
58+
59+
return nil
60+
}
61+
62+
// TODO: add download function for a single catalog item

Diff for: monstercat/release_test.go renamed to monstercat/download_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import (
99
func Test_DownloadRelease(t *testing.T) {
1010
client := NewClient()
1111

12-
err := client.DownloadRelease(CatalogItem{}, ReleaseDownloadFormatMP3, "./file.mp3")
12+
err := client.DownloadRelease(Release{}, DownloadReleaseFormatMP3, "./file.zip")
1313
assert.Error(t, err)
1414
assert.Equal(t, ErrorClientNotLoggedIn, err)
1515
}

Diff for: monstercat/monstercat.go

+4-3
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@ package monstercat
33
import "fmt"
44

55
const (
6-
endpointLogin = "https://www.monstercat.com/api/sign-in"
7-
endpointCatalog = "https://www.monstercat.com/api/catalog/browse"
8-
endpointReleaseDownload = "https://www.monstercat.com/api/release/%s/download?format=%s"
6+
endpointLogin = "https://www.monstercat.com/api/sign-in"
7+
endpointCatalog = "https://www.monstercat.com/api/catalog/browse"
8+
9+
endpointDownloadRelease = "https://www.monstercat.com/api/release/%s/download?format=%s"
910

1011
authenticationCookieName = "cid"
1112
)

0 commit comments

Comments
 (0)