musiciwant 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.d.ts +27 -0
- package/index.js +54 -0
- package/package.json +1 -1
package/index.d.ts
CHANGED
|
@@ -73,12 +73,39 @@ export interface StatsResponse {
|
|
|
73
73
|
most_intense_genres: GenreStat[];
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
+
export interface FilterOptions {
|
|
77
|
+
minBpm?: number; maxBpm?: number; minIntensity?: number; maxIntensity?: number;
|
|
78
|
+
maxDynamicRange?: number; sensoryLevel?: 'safe' | 'moderate' | 'intense';
|
|
79
|
+
suddenChanges?: string | string[]; vocalStyle?: string; mood?: string;
|
|
80
|
+
misoSafe?: boolean; limit?: number; offset?: number;
|
|
81
|
+
}
|
|
82
|
+
export interface FilterResponse { count: number; results: Song[]; }
|
|
83
|
+
export type SongRef = { title: string; artist?: string } | { slug: string };
|
|
84
|
+
export interface BatchResponse { count: number; results: { query: SongRef; found: boolean; song: Song | null }[]; }
|
|
85
|
+
export interface PlaylistTrack { query: SongRef; matched: boolean; title?: string; artist?: string; slug?: string; intensity?: number; sensory_level?: string; }
|
|
86
|
+
export interface PlaylistResponse {
|
|
87
|
+
tracks: PlaylistTrack[];
|
|
88
|
+
stats: { avg: number; max_jump: number; ambushes: number[]; peak_index: number; calm_index: number } | null;
|
|
89
|
+
unmatched: number;
|
|
90
|
+
}
|
|
91
|
+
export interface FingerprintResponse {
|
|
92
|
+
found: boolean;
|
|
93
|
+
song?: { title: string; artist: string; slug: string };
|
|
94
|
+
vector?: Record<string, number>;
|
|
95
|
+
vector_array?: number[];
|
|
96
|
+
dims?: string[];
|
|
97
|
+
}
|
|
98
|
+
|
|
76
99
|
export class MusicIWant {
|
|
77
100
|
constructor(opts?: ClientOptions);
|
|
78
101
|
song(params: { title: string; artist?: string } | { slug: string }): Promise<SongResponse>;
|
|
79
102
|
search(q: string): Promise<SearchResponse>;
|
|
80
103
|
gentler(params: { title: string; artist?: string } | { slug: string }): Promise<GentlerResponse>;
|
|
81
104
|
stats(): Promise<StatsResponse>;
|
|
105
|
+
filter(opts?: FilterOptions): Promise<FilterResponse>;
|
|
106
|
+
batch(songs: SongRef[]): Promise<BatchResponse>;
|
|
107
|
+
playlist(songs: SongRef[]): Promise<PlaylistResponse>;
|
|
108
|
+
fingerprint(params: { title: string; artist?: string } | { slug: string }): Promise<FingerprintResponse>;
|
|
82
109
|
usage(): Promise<UsageResponse>;
|
|
83
110
|
static getKey(email: string, opts?: ClientOptions): Promise<KeyResponse>;
|
|
84
111
|
}
|
package/index.js
CHANGED
|
@@ -74,6 +74,60 @@ class MusicIWant {
|
|
|
74
74
|
return this._get('/api/v1/stats', {});
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
+
/**
|
|
78
|
+
* Query the catalog by feel. All options optional: { minBpm, maxBpm,
|
|
79
|
+
* minIntensity, maxIntensity, maxDynamicRange, sensoryLevel, suddenChanges
|
|
80
|
+
* (string or array), vocalStyle, mood, misoSafe (bool), limit, offset }.
|
|
81
|
+
* @returns {Promise<object>} { count, results }
|
|
82
|
+
*/
|
|
83
|
+
filter(opts = {}) {
|
|
84
|
+
const sc = Array.isArray(opts.suddenChanges) ? opts.suddenChanges.join(',') : opts.suddenChanges;
|
|
85
|
+
return this._get('/api/v1/filter', {
|
|
86
|
+
min_bpm: opts.minBpm, max_bpm: opts.maxBpm,
|
|
87
|
+
min_intensity: opts.minIntensity, max_intensity: opts.maxIntensity,
|
|
88
|
+
max_dynamic_range: opts.maxDynamicRange, sensory_level: opts.sensoryLevel,
|
|
89
|
+
sudden_changes: sc, vocal_style: opts.vocalStyle, mood: opts.mood,
|
|
90
|
+
miso_safe: opts.misoSafe ? 'true' : undefined,
|
|
91
|
+
limit: opts.limit, offset: opts.offset
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Batch lookup (up to 100). songs: array of { title, artist } or { slug }.
|
|
97
|
+
* @returns {Promise<object>} { count, results: [{ query, found, song }] }
|
|
98
|
+
*/
|
|
99
|
+
batch(songs) {
|
|
100
|
+
if (!Array.isArray(songs) || !songs.length) throw new Error('batch(songs) needs a non-empty array');
|
|
101
|
+
return this._post('/api/v1/songs', { songs });
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Sensory shape of an ordered playlist (up to 60). songs: array of
|
|
106
|
+
* { title, artist } or { slug }. @returns {Promise<object>} { tracks, stats, unmatched }
|
|
107
|
+
*/
|
|
108
|
+
playlist(songs) {
|
|
109
|
+
if (!Array.isArray(songs) || !songs.length) throw new Error('playlist(songs) needs a non-empty array');
|
|
110
|
+
return this._post('/api/v1/playlist', { songs });
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Normalized 0–1 feature vector (the Spotify audio-features replacement).
|
|
115
|
+
* Provide {title, artist} or {slug}. @returns {Promise<object>} { found, song, vector, vector_array, dims }
|
|
116
|
+
*/
|
|
117
|
+
fingerprint({ title, artist, slug } = {}) {
|
|
118
|
+
if (!title && !slug) throw new Error('fingerprint() needs { title, artist } or { slug }');
|
|
119
|
+
return this._get('/api/v1/fingerprint', { title, artist, slug });
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
async _post(path, body) {
|
|
123
|
+
const headers = { 'Accept': 'application/json', 'Content-Type': 'application/json' };
|
|
124
|
+
if (this.apiKey) headers['X-API-Key'] = this.apiKey;
|
|
125
|
+
const res = await this._fetch(this.baseUrl + path, { method: 'POST', headers, body: JSON.stringify(body) });
|
|
126
|
+
const out = await res.json().catch(() => ({}));
|
|
127
|
+
if (!res.ok) throw new MusicIWantError((out && out.error) || ('HTTP ' + res.status), res.status, out);
|
|
128
|
+
return out;
|
|
129
|
+
}
|
|
130
|
+
|
|
77
131
|
/** Current key's tier + remaining quota. Requires an apiKey. */
|
|
78
132
|
usage() {
|
|
79
133
|
if (!this.apiKey) throw new Error('usage() requires an apiKey');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "musiciwant",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Independent music analysis API client — BPM, dynamic range, sensory intensity, moods, misophonia flags. A Spotify Audio Features alternative.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|