@sriinnu/harmon-apple 0.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/.chitragupta-ecosystem/.profile.json +109 -0
- package/LICENSE +661 -0
- package/README.md +65 -0
- package/SKILL.md +45 -0
- package/dist/auth-cli.d.ts +5 -0
- package/dist/auth-cli.d.ts.map +1 -0
- package/dist/auth-cli.js +328 -0
- package/dist/auth-cli.js.map +1 -0
- package/dist/index.d.ts +123 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +298 -0
- package/dist/index.js.map +1 -0
- package/logo.svg +17 -0
- package/package.json +52 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Harmon Apple - Apple Music API client
|
|
3
|
+
*/
|
|
4
|
+
const APPLE_MUSIC_API_BASE = 'https://api.music.apple.com/v1';
|
|
5
|
+
class AppleMusicClientImpl {
|
|
6
|
+
developerToken;
|
|
7
|
+
userToken;
|
|
8
|
+
storefront;
|
|
9
|
+
constructor(config) {
|
|
10
|
+
if (!config.developerToken) {
|
|
11
|
+
throw new Error('Missing Apple Music developer token');
|
|
12
|
+
}
|
|
13
|
+
this.developerToken = config.developerToken;
|
|
14
|
+
this.userToken = config.userToken;
|
|
15
|
+
this.storefront = config.storefront || 'us';
|
|
16
|
+
}
|
|
17
|
+
async search(term, types, options = {}) {
|
|
18
|
+
const data = await this.request(`/catalog/${this.storefront}/search`, {
|
|
19
|
+
term,
|
|
20
|
+
types: types.join(','),
|
|
21
|
+
...listQuery(options),
|
|
22
|
+
});
|
|
23
|
+
return {
|
|
24
|
+
songs: (data.results?.songs?.data || []).map(mapSong),
|
|
25
|
+
albums: (data.results?.albums?.data || []).map(mapAlbum),
|
|
26
|
+
artists: (data.results?.artists?.data || []).map(mapArtist),
|
|
27
|
+
playlists: (data.results?.playlists?.data || []).map(mapPlaylist),
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
async getSong(id) {
|
|
31
|
+
const data = await this.request(`/catalog/${this.storefront}/songs/${id}`);
|
|
32
|
+
return data.data?.[0] ? mapSong(data.data[0]) : null;
|
|
33
|
+
}
|
|
34
|
+
async getAlbum(id) {
|
|
35
|
+
const data = await this.request(`/catalog/${this.storefront}/albums/${id}`);
|
|
36
|
+
return data.data?.[0] ? mapAlbum(data.data[0]) : null;
|
|
37
|
+
}
|
|
38
|
+
async getArtist(id) {
|
|
39
|
+
const data = await this.request(`/catalog/${this.storefront}/artists/${id}`);
|
|
40
|
+
return data.data?.[0] ? mapArtist(data.data[0]) : null;
|
|
41
|
+
}
|
|
42
|
+
async getPlaylist(id) {
|
|
43
|
+
const data = await this.request(`/catalog/${this.storefront}/playlists/${id}`);
|
|
44
|
+
return data.data?.[0] ? mapPlaylist(data.data[0]) : null;
|
|
45
|
+
}
|
|
46
|
+
async getPlaylistTracks(id, options = {}) {
|
|
47
|
+
if (this.userToken) {
|
|
48
|
+
try {
|
|
49
|
+
const libraryTracks = await this.request(`/me/library/playlists/${id}/tracks`, listQuery(options), true);
|
|
50
|
+
return (libraryTracks.data || []).map(mapLibrarySongToAppleMusicSong);
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
if (!isAppleNotFoundError(error)) {
|
|
54
|
+
throw error;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
const data = await this.request(`/catalog/${this.storefront}/playlists/${id}/tracks`, listQuery(options));
|
|
59
|
+
return (data.data || []).map(mapSong);
|
|
60
|
+
}
|
|
61
|
+
async getRecentlyPlayedTracks(options = {}) {
|
|
62
|
+
const data = await this.request('/me/recent/played/tracks', listQuery(options), true);
|
|
63
|
+
return (data.data || []).map(mapSong);
|
|
64
|
+
}
|
|
65
|
+
async getLibrarySongs(options = {}) {
|
|
66
|
+
const data = await this.request('/me/library/songs', listQuery(options), true);
|
|
67
|
+
return (data.data || []).map(mapLibrarySong);
|
|
68
|
+
}
|
|
69
|
+
async getLibraryAlbums(options = {}) {
|
|
70
|
+
const data = await this.request('/me/library/albums', listQuery(options), true);
|
|
71
|
+
return (data.data || []).map(mapLibraryAlbum);
|
|
72
|
+
}
|
|
73
|
+
async getLibraryPlaylists(options = {}) {
|
|
74
|
+
const data = await this.request('/me/library/playlists', listQuery(options), true);
|
|
75
|
+
return (data.data || []).map(mapLibraryPlaylist);
|
|
76
|
+
}
|
|
77
|
+
async request(path, query, requireUserToken = false) {
|
|
78
|
+
const url = new URL(`${APPLE_MUSIC_API_BASE}${path}`);
|
|
79
|
+
if (query) {
|
|
80
|
+
for (const [key, value] of Object.entries(query)) {
|
|
81
|
+
url.searchParams.set(key, value);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
const headers = {
|
|
85
|
+
Authorization: `Bearer ${this.developerToken}`,
|
|
86
|
+
};
|
|
87
|
+
if (requireUserToken) {
|
|
88
|
+
if (!this.userToken) {
|
|
89
|
+
throw new Error('Apple Music user token required for library endpoints');
|
|
90
|
+
}
|
|
91
|
+
headers['Music-User-Token'] = this.userToken;
|
|
92
|
+
}
|
|
93
|
+
const response = await fetch(url, { headers });
|
|
94
|
+
if (!response.ok) {
|
|
95
|
+
const detail = await response.text();
|
|
96
|
+
throw new Error(`Apple Music API error: ${response.status} ${detail}`);
|
|
97
|
+
}
|
|
98
|
+
return (await response.json());
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
function listQuery(options) {
|
|
102
|
+
const query = {};
|
|
103
|
+
if (typeof options.limit === 'number') {
|
|
104
|
+
query.limit = options.limit.toString();
|
|
105
|
+
}
|
|
106
|
+
if (typeof options.offset === 'number') {
|
|
107
|
+
query.offset = options.offset.toString();
|
|
108
|
+
}
|
|
109
|
+
return query;
|
|
110
|
+
}
|
|
111
|
+
function mapSong(resource) {
|
|
112
|
+
return {
|
|
113
|
+
id: resource.id,
|
|
114
|
+
name: resource.attributes.name,
|
|
115
|
+
artistName: resource.attributes.artistName,
|
|
116
|
+
albumName: resource.attributes.albumName,
|
|
117
|
+
durationMs: resource.attributes.durationInMillis,
|
|
118
|
+
url: resource.attributes.url,
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
function mapAlbum(resource) {
|
|
122
|
+
return {
|
|
123
|
+
id: resource.id,
|
|
124
|
+
name: resource.attributes.name,
|
|
125
|
+
artistName: resource.attributes.artistName,
|
|
126
|
+
releaseDate: resource.attributes.releaseDate,
|
|
127
|
+
trackCount: resource.attributes.trackCount,
|
|
128
|
+
url: resource.attributes.url,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
function mapArtist(resource) {
|
|
132
|
+
return {
|
|
133
|
+
id: resource.id,
|
|
134
|
+
name: resource.attributes.name,
|
|
135
|
+
url: resource.attributes.url,
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
function mapPlaylist(resource) {
|
|
139
|
+
return {
|
|
140
|
+
id: resource.id,
|
|
141
|
+
name: resource.attributes.name,
|
|
142
|
+
curatorName: resource.attributes.curatorName,
|
|
143
|
+
trackCount: resource.attributes.trackCount,
|
|
144
|
+
url: resource.attributes.url,
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
function mapLibrarySong(resource) {
|
|
148
|
+
return {
|
|
149
|
+
id: resource.id,
|
|
150
|
+
name: resource.attributes.name,
|
|
151
|
+
artistName: resource.attributes.artistName,
|
|
152
|
+
albumName: resource.attributes.albumName,
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
function mapLibrarySongToAppleMusicSong(resource) {
|
|
156
|
+
return {
|
|
157
|
+
id: resource.id,
|
|
158
|
+
name: resource.attributes.name,
|
|
159
|
+
artistName: resource.attributes.artistName,
|
|
160
|
+
albumName: resource.attributes.albumName,
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
function mapLibraryAlbum(resource) {
|
|
164
|
+
return {
|
|
165
|
+
id: resource.id,
|
|
166
|
+
name: resource.attributes.name,
|
|
167
|
+
artistName: resource.attributes.artistName,
|
|
168
|
+
trackCount: resource.attributes.trackCount,
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
function mapLibraryPlaylist(resource) {
|
|
172
|
+
return {
|
|
173
|
+
id: resource.id,
|
|
174
|
+
name: resource.attributes.name,
|
|
175
|
+
trackCount: resource.attributes.trackCount,
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
/** Map Apple Music song to provider-agnostic TrackInfo */
|
|
179
|
+
function mapSongToTrackInfo(song) {
|
|
180
|
+
return {
|
|
181
|
+
id: song.id,
|
|
182
|
+
name: song.name,
|
|
183
|
+
artist: song.artistName,
|
|
184
|
+
album: song.albumName || '',
|
|
185
|
+
durationMs: song.durationMs || 0,
|
|
186
|
+
uri: song.url || `apple:song:${song.id}`,
|
|
187
|
+
provider: 'apple',
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
function mapLibrarySongToTrackInfo(song) {
|
|
191
|
+
return {
|
|
192
|
+
id: song.id,
|
|
193
|
+
name: song.name,
|
|
194
|
+
artist: song.artistName,
|
|
195
|
+
album: song.albumName || '',
|
|
196
|
+
durationMs: 0,
|
|
197
|
+
uri: `apple:song:${song.id}`,
|
|
198
|
+
provider: 'apple',
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Adapts AppleMusicClient to the MusicProvider interface.
|
|
203
|
+
*/
|
|
204
|
+
export class AppleMusicProvider {
|
|
205
|
+
name = 'apple';
|
|
206
|
+
client;
|
|
207
|
+
connected;
|
|
208
|
+
constructor(client, connected = true) {
|
|
209
|
+
this.client = client;
|
|
210
|
+
this.connected = connected;
|
|
211
|
+
}
|
|
212
|
+
isConnected() {
|
|
213
|
+
return this.connected;
|
|
214
|
+
}
|
|
215
|
+
async search(query, limit) {
|
|
216
|
+
const result = await this.client.search(query, ['songs'], { limit });
|
|
217
|
+
return result.songs.map(mapSongToTrackInfo);
|
|
218
|
+
}
|
|
219
|
+
async getLibraryTracks(options) {
|
|
220
|
+
const songs = await this.client.getLibrarySongs(options);
|
|
221
|
+
return songs.map(mapLibrarySongToTrackInfo);
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* I reject synthetic top-track semantics so the Apple provider stays honest
|
|
225
|
+
* about the personal-history surface it actually implements.
|
|
226
|
+
*/
|
|
227
|
+
async getTopTracks(options) {
|
|
228
|
+
void options;
|
|
229
|
+
throw new Error('Apple Music top tracks are not available from the current provider contract. Use recently played tracks instead.');
|
|
230
|
+
}
|
|
231
|
+
async getRecentlyPlayed(options) {
|
|
232
|
+
const songs = await this.client.getRecentlyPlayedTracks(options);
|
|
233
|
+
return songs.map(mapSongToTrackInfo);
|
|
234
|
+
}
|
|
235
|
+
async getPlaylistTracks(playlistId, options) {
|
|
236
|
+
const songs = await this.client.getPlaylistTracks(playlistId, options);
|
|
237
|
+
return songs.map(mapSongToTrackInfo);
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* I build Apple recommendations from the user's recent plays plus catalog
|
|
241
|
+
* artist searches because Apple does not expose a simple seed-track
|
|
242
|
+
* recommendations endpoint that matches the shared provider contract.
|
|
243
|
+
*/
|
|
244
|
+
async getRecommendations(options) {
|
|
245
|
+
const limit = Math.max(1, Math.min(options.limit ?? 20, 50));
|
|
246
|
+
const seeds = await this.resolveRecommendationSeeds(options.seedTrackIds);
|
|
247
|
+
if (seeds.length === 0) {
|
|
248
|
+
return [];
|
|
249
|
+
}
|
|
250
|
+
const perSeed = Math.max(2, Math.ceil(limit / seeds.length));
|
|
251
|
+
const excludedIds = new Set(seeds.map((seed) => seed.id));
|
|
252
|
+
const recommendations = [];
|
|
253
|
+
const seen = new Set();
|
|
254
|
+
for (const seed of seeds) {
|
|
255
|
+
const searchTerm = [seed.artistName, seed.albumName].filter(Boolean).join(' ').trim() || seed.name;
|
|
256
|
+
const result = await this.client.search(searchTerm, ['songs'], { limit: perSeed + 4 });
|
|
257
|
+
for (const song of result.songs) {
|
|
258
|
+
if (excludedIds.has(song.id) || seen.has(song.id)) {
|
|
259
|
+
continue;
|
|
260
|
+
}
|
|
261
|
+
seen.add(song.id);
|
|
262
|
+
recommendations.push(mapSongToTrackInfo(song));
|
|
263
|
+
if (recommendations.length >= limit) {
|
|
264
|
+
return recommendations;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
return recommendations;
|
|
269
|
+
}
|
|
270
|
+
async getTrackFeatures(trackIds) {
|
|
271
|
+
// Apple Music has no audio features API — return nulls
|
|
272
|
+
return trackIds.map(() => null);
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* I prefer explicit seed tracks and fall back to recent listening history so
|
|
276
|
+
* recommendation discovery remains provider-aware for Apple sessions.
|
|
277
|
+
*/
|
|
278
|
+
async resolveRecommendationSeeds(seedTrackIds) {
|
|
279
|
+
const explicitSeeds = await Promise.all((seedTrackIds || [])
|
|
280
|
+
.slice(0, 3)
|
|
281
|
+
.map(async (trackId) => this.client.getSong(trackId)));
|
|
282
|
+
const resolvedSeeds = explicitSeeds.filter((song) => Boolean(song));
|
|
283
|
+
if (resolvedSeeds.length > 0) {
|
|
284
|
+
return resolvedSeeds;
|
|
285
|
+
}
|
|
286
|
+
return this.client.getRecentlyPlayedTracks({ limit: 3 });
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
export function createAppleMusicProvider(client) {
|
|
290
|
+
return new AppleMusicProvider(client);
|
|
291
|
+
}
|
|
292
|
+
export function createAppleMusicClient(config) {
|
|
293
|
+
return new AppleMusicClientImpl(config);
|
|
294
|
+
}
|
|
295
|
+
function isAppleNotFoundError(error) {
|
|
296
|
+
return error instanceof Error && error.message.startsWith('Apple Music API error: 404');
|
|
297
|
+
}
|
|
298
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/logo.svg
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" width="64" height="64" fill="none">
|
|
2
|
+
<!-- I am the Apple mark: a person reaching toward a playback phone. -->
|
|
3
|
+
<rect width="64" height="64" rx="16" fill="#F3E7D4"/>
|
|
4
|
+
<g stroke="#171513" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round">
|
|
5
|
+
<rect x="34" y="14" width="14" height="30" rx="4.5"/>
|
|
6
|
+
<path d="M39.5 20V30"/>
|
|
7
|
+
<path d="M39.5 21L45 19V27"/>
|
|
8
|
+
<circle cx="37.5" cy="32" r="3.5"/>
|
|
9
|
+
<circle cx="45" cy="28" r="3.5"/>
|
|
10
|
+
<path d="M17 49L19 37"/>
|
|
11
|
+
<path d="M18 31L28 26"/>
|
|
12
|
+
</g>
|
|
13
|
+
<g fill="#171513">
|
|
14
|
+
<circle cx="18" cy="23" r="5"/>
|
|
15
|
+
<path d="M12 36C14 31 22 31 24 36V42H12V36Z"/>
|
|
16
|
+
</g>
|
|
17
|
+
</svg>
|
package/package.json
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@sriinnu/harmon-apple",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Apple Music API client",
|
|
5
|
+
"license": "AGPL-3.0-only",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "https://github.com/sriinnu/harmon.git",
|
|
9
|
+
"directory": "packages/harmon-apple"
|
|
10
|
+
},
|
|
11
|
+
"homepage": "https://github.com/sriinnu/harmon/tree/main/packages/harmon-apple#readme",
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/sriinnu/harmon/issues"
|
|
14
|
+
},
|
|
15
|
+
"type": "module",
|
|
16
|
+
"main": "./dist/index.js",
|
|
17
|
+
"types": "./dist/index.d.ts",
|
|
18
|
+
"files": [
|
|
19
|
+
"dist/",
|
|
20
|
+
".chitragupta-ecosystem/",
|
|
21
|
+
"README.md",
|
|
22
|
+
"SKILL.md",
|
|
23
|
+
"logo.svg"
|
|
24
|
+
],
|
|
25
|
+
"exports": {
|
|
26
|
+
".": {
|
|
27
|
+
"types": "./dist/index.d.ts",
|
|
28
|
+
"import": "./dist/index.js"
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"publishConfig": {
|
|
32
|
+
"access": "public"
|
|
33
|
+
},
|
|
34
|
+
"dependencies": {
|
|
35
|
+
"@sriinnu/harmon-protocol": "0.1.0",
|
|
36
|
+
"@sriinnu/harmon-core": "0.1.0"
|
|
37
|
+
},
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"@types/node": "^25.0.8",
|
|
40
|
+
"typescript": "^5.9.3"
|
|
41
|
+
},
|
|
42
|
+
"scripts": {
|
|
43
|
+
"auth": "node ./dist/auth-cli.js bootstrap",
|
|
44
|
+
"auth:refresh": "node ./dist/auth-cli.js refresh",
|
|
45
|
+
"auth:status": "node ./dist/auth-cli.js status",
|
|
46
|
+
"build": "node --experimental-strip-types ../../scripts/clean-build.ts ./dist ./tsconfig.tsbuildinfo && tsc",
|
|
47
|
+
"dev": "tsc --watch",
|
|
48
|
+
"lint": "tsc --noEmit",
|
|
49
|
+
"test": "vitest --root ../.. packages/harmon-apple/src/index.test.ts",
|
|
50
|
+
"test:run": "vitest --root ../.. run packages/harmon-apple/src/index.test.ts"
|
|
51
|
+
}
|
|
52
|
+
}
|