mirror of
https://git.sr.ht/~joren/streamrip-go
synced 2026-07-27 23:42:28 +02:00
feat: add beatport provider
This commit is contained in:
@@ -0,0 +1,212 @@
|
||||
package beatport
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"streamrip-go/internal/config"
|
||||
)
|
||||
|
||||
func newTestClient(t *testing.T, handler http.Handler) (*Client, func()) {
|
||||
t.Helper()
|
||||
ts := httptest.NewServer(handler)
|
||||
cfg := &config.Config{Session: config.DefaultConfigData(), File: config.DefaultConfigData()}
|
||||
cfg.Session.Beatport.Username = "user"
|
||||
cfg.Session.Beatport.Password = "pass"
|
||||
cfg.Session.Beatport.AccessToken = "token"
|
||||
cfg.Session.Beatport.TokenExpiry = time.Now().Add(time.Hour).Unix()
|
||||
c := New(cfg)
|
||||
c.baseURL = ts.URL
|
||||
c.http = ts.Client()
|
||||
c.loggedIn = true
|
||||
return c, ts.Close
|
||||
}
|
||||
|
||||
func writeJSON(t *testing.T, w http.ResponseWriter, v any) {
|
||||
t.Helper()
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
if err := json.NewEncoder(w).Encode(v); err != nil {
|
||||
t.Fatalf("encode json: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetDownloadableMapsQuality(t *testing.T) {
|
||||
c, closeServer := newTestClient(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.URL.Path != "/catalog/tracks/42/download/" {
|
||||
t.Fatalf("path = %q", r.URL.Path)
|
||||
}
|
||||
if got := r.URL.Query().Get("quality"); got != "high" {
|
||||
t.Fatalf("quality = %q, want high", got)
|
||||
}
|
||||
writeJSON(t, w, map[string]any{"location": "https://cdn.example/42.m4a", "stream_quality": ".256k.aac.mp4"})
|
||||
}))
|
||||
defer closeServer()
|
||||
|
||||
d, err := c.GetDownloadable(context.Background(), "42", 2)
|
||||
if err != nil {
|
||||
t.Fatalf("GetDownloadable() error = %v", err)
|
||||
}
|
||||
if d.URL != "https://cdn.example/42.m4a" || d.Extension != "m4a" || d.Audio.BitrateKbps != 256 || d.Audio.Quality != "HIGH" {
|
||||
t.Fatalf("unexpected downloadable: %+v", d)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAlbumMetadataNormalizesReleaseTracks(t *testing.T) {
|
||||
c, closeServer := newTestClient(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
switch r.URL.Path {
|
||||
case "/catalog/releases/7/":
|
||||
writeJSON(t, w, map[string]any{
|
||||
"id": 7,
|
||||
"name": "Release Name",
|
||||
"new_release_date": "2024-01-02",
|
||||
"track_count": 1,
|
||||
"artists": []any{map[string]any{"id": 10, "name": "Album Artist"}},
|
||||
"image": map[string]any{"dynamic_uri": "https://img.example/{w}x{h}.jpg"},
|
||||
})
|
||||
case "/catalog/releases/7/tracks/":
|
||||
writeJSON(t, w, map[string]any{
|
||||
"next": nil,
|
||||
"results": []any{map[string]any{
|
||||
"id": 42,
|
||||
"name": "Track Name",
|
||||
"mix_name": "Original Mix",
|
||||
"number": 1,
|
||||
"artists": []any{map[string]any{"id": 11, "name": "Track Artist"}},
|
||||
"genre": map[string]any{"name": "House"},
|
||||
"isrc": "USABC1234567",
|
||||
}},
|
||||
})
|
||||
default:
|
||||
t.Fatalf("unexpected path %q", r.URL.Path)
|
||||
}
|
||||
}))
|
||||
defer closeServer()
|
||||
|
||||
meta, err := c.GetMetadata(context.Background(), "7", "album")
|
||||
if err != nil {
|
||||
t.Fatalf("GetMetadata() error = %v", err)
|
||||
}
|
||||
if meta["title"] != "Release Name" || meta["release_date_original"] != "2024-01-02" {
|
||||
t.Fatalf("unexpected album meta: %+v", meta)
|
||||
}
|
||||
tracks := meta["tracks"].(map[string]any)["items"].([]any)
|
||||
if len(tracks) != 1 {
|
||||
t.Fatalf("tracks len = %d", len(tracks))
|
||||
}
|
||||
track := tracks[0].(map[string]any)
|
||||
if track["id"] != "42" || track["title"] != "Track Name" || track["version"] != "Original Mix" {
|
||||
t.Fatalf("unexpected track meta: %+v", track)
|
||||
}
|
||||
album := track["album"].(map[string]any)
|
||||
if album["title"] != "Release Name" {
|
||||
t.Fatalf("unexpected track album: %+v", album)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAlbumMetadataCollapsesManyReleaseArtists(t *testing.T) {
|
||||
c, closeServer := newTestClient(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
switch r.URL.Path {
|
||||
case "/catalog/releases/7/":
|
||||
writeJSON(t, w, map[string]any{
|
||||
"id": 7,
|
||||
"name": "Compilation",
|
||||
"track_count": 1,
|
||||
"artists": []any{
|
||||
map[string]any{"id": 1, "name": "A"},
|
||||
map[string]any{"id": 2, "name": "B"},
|
||||
map[string]any{"id": 3, "name": "C"},
|
||||
map[string]any{"id": 4, "name": "D"},
|
||||
},
|
||||
})
|
||||
case "/catalog/releases/7/tracks/":
|
||||
writeJSON(t, w, map[string]any{
|
||||
"next": nil,
|
||||
"results": []any{map[string]any{
|
||||
"id": 42,
|
||||
"name": "Track Name",
|
||||
"number": 1,
|
||||
"artists": []any{map[string]any{"id": 1, "name": "A"}},
|
||||
}},
|
||||
})
|
||||
default:
|
||||
t.Fatalf("unexpected path %q", r.URL.Path)
|
||||
}
|
||||
}))
|
||||
defer closeServer()
|
||||
|
||||
meta, err := c.GetMetadata(context.Background(), "7", "album")
|
||||
if err != nil {
|
||||
t.Fatalf("GetMetadata() error = %v", err)
|
||||
}
|
||||
artist := meta["artist"].(map[string]any)
|
||||
if artist["name"] != "Various Artists" {
|
||||
t.Fatalf("album artist = %q, want Various Artists", artist["name"])
|
||||
}
|
||||
track := meta["tracks"].(map[string]any)["items"].([]any)[0].(map[string]any)
|
||||
album := track["album"].(map[string]any)
|
||||
albumArtist := album["artist"].(map[string]any)
|
||||
if albumArtist["name"] != "Various Artists" {
|
||||
t.Fatalf("track album artist = %q, want Various Artists", albumArtist["name"])
|
||||
}
|
||||
}
|
||||
|
||||
func TestReleaseArtistCollapseCanBeDisabled(t *testing.T) {
|
||||
cfg := &config.Config{Session: config.DefaultConfigData(), File: config.DefaultConfigData()}
|
||||
cfg.Session.Beatport.VariousArtistsThreshold = -1
|
||||
c := New(cfg)
|
||||
got := c.releaseArtistName([]any{
|
||||
map[string]any{"name": "A"},
|
||||
map[string]any{"name": "B"},
|
||||
map[string]any{"name": "C"},
|
||||
map[string]any{"name": "D"},
|
||||
})
|
||||
if got != "A, B, C, D" {
|
||||
t.Fatalf("releaseArtistName() = %q", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestArtistMetadataUsesReleases(t *testing.T) {
|
||||
c, closeServer := newTestClient(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
switch r.URL.Path {
|
||||
case "/catalog/artists/908468/":
|
||||
writeJSON(t, w, map[string]any{"id": 908468, "name": "D'ort"})
|
||||
case "/catalog/releases/":
|
||||
if got := r.URL.Query().Get("artist_id"); got != "908468" {
|
||||
t.Fatalf("artist_id = %q", got)
|
||||
}
|
||||
writeJSON(t, w, map[string]any{
|
||||
"next": nil,
|
||||
"results": []any{map[string]any{
|
||||
"id": 123,
|
||||
"name": "An Artisan's Exhibition",
|
||||
"new_release_date": "2026-01-01",
|
||||
"track_count": 10,
|
||||
"artists": []any{map[string]any{"id": 908468, "name": "D'ort"}},
|
||||
}},
|
||||
})
|
||||
default:
|
||||
t.Fatalf("unexpected path %q", r.URL.Path)
|
||||
}
|
||||
}))
|
||||
defer closeServer()
|
||||
|
||||
meta, err := c.GetMetadata(context.Background(), "908468", "artist")
|
||||
if err != nil {
|
||||
t.Fatalf("GetMetadata() error = %v", err)
|
||||
}
|
||||
if meta["name"] != "D'ort" {
|
||||
t.Fatalf("artist name = %q", meta["name"])
|
||||
}
|
||||
albums := meta["albums"].(map[string]any)["items"].([]any)
|
||||
if len(albums) != 1 {
|
||||
t.Fatalf("albums len = %d", len(albums))
|
||||
}
|
||||
album := albums[0].(map[string]any)
|
||||
if album["id"] != "123" || album["title"] != "An Artisan's Exhibition" || album["tracks_count"] != 10 {
|
||||
t.Fatalf("unexpected album: %+v", album)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user