@opfelmusig/lib 0.0.0-ci.0.sha-3e76884

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.
Files changed (176) hide show
  1. package/README.md +8 -0
  2. package/dist/clients/catalog/album.d.ts +12 -0
  3. package/dist/clients/catalog/album.js +14 -0
  4. package/dist/clients/catalog/genre.d.ts +13 -0
  5. package/dist/clients/catalog/genre.js +17 -0
  6. package/dist/clients/catalog/index.d.ts +71 -0
  7. package/dist/clients/catalog/index.js +99 -0
  8. package/dist/clients/catalog/musicVideo.d.ts +12 -0
  9. package/dist/clients/catalog/musicVideo.js +14 -0
  10. package/dist/clients/catalog/playlist.d.ts +12 -0
  11. package/dist/clients/catalog/playlist.js +16 -0
  12. package/dist/clients/catalog/song.d.ts +12 -0
  13. package/dist/clients/catalog/song.js +14 -0
  14. package/dist/clients/catalog/station.d.ts +14 -0
  15. package/dist/clients/catalog/station.js +34 -0
  16. package/dist/clients/catalog/stationGenre.d.ts +12 -0
  17. package/dist/clients/catalog/stationGenre.js +14 -0
  18. package/dist/clients/library/index.d.ts +39 -0
  19. package/dist/clients/library/index.js +68 -0
  20. package/dist/clients/library/playlistFolder.d.ts +12 -0
  21. package/dist/clients/library/playlistFolder.js +16 -0
  22. package/dist/clients/me/index.d.ts +25 -0
  23. package/dist/clients/me/index.js +49 -0
  24. package/dist/clients/me/musicSummary.d.ts +12 -0
  25. package/dist/clients/me/musicSummary.js +14 -0
  26. package/dist/clients/me/ratings.d.ts +15 -0
  27. package/dist/clients/me/ratings.js +34 -0
  28. package/dist/clients/me/recent.d.ts +17 -0
  29. package/dist/clients/me/recent.js +37 -0
  30. package/dist/clients/me/recommendation.d.ts +12 -0
  31. package/dist/clients/me/recommendation.js +14 -0
  32. package/dist/clients/me/station.d.ts +10 -0
  33. package/dist/clients/me/station.js +13 -0
  34. package/dist/clients/playback.d.ts +9 -0
  35. package/dist/clients/playback.js +68 -0
  36. package/dist/clients/resource.d.ts +34 -0
  37. package/dist/clients/resource.js +105 -0
  38. package/dist/clients/shared/equivalent.d.ts +10 -0
  39. package/dist/clients/shared/equivalent.js +15 -0
  40. package/dist/clients/social/index.d.ts +7 -0
  41. package/dist/clients/social/index.js +9 -0
  42. package/dist/clients/social/profile.d.ts +12 -0
  43. package/dist/clients/social/profile.js +14 -0
  44. package/dist/clients/storefront.d.ts +12 -0
  45. package/dist/clients/storefront.js +14 -0
  46. package/dist/core/client.d.ts +40 -0
  47. package/dist/core/client.js +82 -0
  48. package/dist/core/error.d.ts +23 -0
  49. package/dist/core/error.js +24 -0
  50. package/dist/core/http.d.ts +22 -0
  51. package/dist/core/http.js +232 -0
  52. package/dist/helpers/language.d.ts +1 -0
  53. package/dist/helpers/language.js +48 -0
  54. package/dist/helpers/public.d.ts +19 -0
  55. package/dist/helpers/public.js +35 -0
  56. package/dist/helpers/requestQuery.d.ts +17 -0
  57. package/dist/helpers/requestQuery.js +153 -0
  58. package/dist/index.d.ts +7 -0
  59. package/dist/index.js +4 -0
  60. package/dist/schemas/error.d.ts +29 -0
  61. package/dist/schemas/error.js +16 -0
  62. package/dist/schemas/request.d.ts +42 -0
  63. package/dist/schemas/request.js +28 -0
  64. package/dist/types/combined.d.ts +15 -0
  65. package/dist/types/combined.js +0 -0
  66. package/dist/types/config.d.ts +63 -0
  67. package/dist/types/config.js +0 -0
  68. package/dist/types/params.d.ts +22 -0
  69. package/dist/types/params.js +0 -0
  70. package/dist/types/playback.d.ts +199 -0
  71. package/dist/types/playback.js +103 -0
  72. package/dist/types/public.d.ts +56 -0
  73. package/dist/types/public.js +1 -0
  74. package/dist/types/query/helpers.d.ts +27 -0
  75. package/dist/types/query/helpers.js +0 -0
  76. package/dist/types/query/registry.d.ts +74 -0
  77. package/dist/types/query/registry.js +0 -0
  78. package/dist/types/query/resource.d.ts +29 -0
  79. package/dist/types/query/resource.js +0 -0
  80. package/dist/types/query/response.d.ts +3 -0
  81. package/dist/types/query/response.js +0 -0
  82. package/dist/types/query/results.d.ts +45 -0
  83. package/dist/types/query/results.js +0 -0
  84. package/dist/types/query/scopes.d.ts +77 -0
  85. package/dist/types/query/scopes.js +0 -0
  86. package/dist/types/request.d.ts +14 -0
  87. package/dist/types/request.js +0 -0
  88. package/dist/types/resources/catalog/activity.d.ts +15 -0
  89. package/dist/types/resources/catalog/activity.js +0 -0
  90. package/dist/types/resources/catalog/album.d.ts +47 -0
  91. package/dist/types/resources/catalog/album.js +0 -0
  92. package/dist/types/resources/catalog/artist.d.ts +57 -0
  93. package/dist/types/resources/catalog/artist.js +0 -0
  94. package/dist/types/resources/catalog/concert.d.ts +32 -0
  95. package/dist/types/resources/catalog/concert.js +0 -0
  96. package/dist/types/resources/catalog/creditArtist.d.ts +11 -0
  97. package/dist/types/resources/catalog/creditArtist.js +0 -0
  98. package/dist/types/resources/catalog/curator.d.ts +27 -0
  99. package/dist/types/resources/catalog/curator.js +0 -0
  100. package/dist/types/resources/catalog/genre.d.ts +11 -0
  101. package/dist/types/resources/catalog/genre.js +0 -0
  102. package/dist/types/resources/catalog/lyrics.d.ts +8 -0
  103. package/dist/types/resources/catalog/lyrics.js +0 -0
  104. package/dist/types/resources/catalog/musicVideo.d.ts +34 -0
  105. package/dist/types/resources/catalog/musicVideo.js +0 -0
  106. package/dist/types/resources/catalog/playlist.d.ts +35 -0
  107. package/dist/types/resources/catalog/playlist.js +0 -0
  108. package/dist/types/resources/catalog/recordLabel.d.ts +16 -0
  109. package/dist/types/resources/catalog/recordLabel.js +0 -0
  110. package/dist/types/resources/catalog/roleCategory.d.ts +12 -0
  111. package/dist/types/resources/catalog/roleCategory.js +0 -0
  112. package/dist/types/resources/catalog/song.d.ts +50 -0
  113. package/dist/types/resources/catalog/song.js +0 -0
  114. package/dist/types/resources/catalog/station.d.ts +21 -0
  115. package/dist/types/resources/catalog/station.js +0 -0
  116. package/dist/types/resources/catalog/stationGenre.d.ts +11 -0
  117. package/dist/types/resources/catalog/stationGenre.js +0 -0
  118. package/dist/types/resources/catalog/syllableLyrics.d.ts +9 -0
  119. package/dist/types/resources/catalog/syllableLyrics.js +0 -0
  120. package/dist/types/resources/catalog/venue.d.ts +20 -0
  121. package/dist/types/resources/catalog/venue.js +0 -0
  122. package/dist/types/resources/library/album.d.ts +17 -0
  123. package/dist/types/resources/library/album.js +0 -0
  124. package/dist/types/resources/library/artist.d.ts +13 -0
  125. package/dist/types/resources/library/artist.js +0 -0
  126. package/dist/types/resources/library/musicVideo.d.ts +15 -0
  127. package/dist/types/resources/library/musicVideo.js +0 -0
  128. package/dist/types/resources/library/playlist.d.ts +24 -0
  129. package/dist/types/resources/library/playlist.js +0 -0
  130. package/dist/types/resources/library/playlistFolder.d.ts +13 -0
  131. package/dist/types/resources/library/playlistFolder.js +0 -0
  132. package/dist/types/resources/library/song.d.ts +15 -0
  133. package/dist/types/resources/library/song.js +0 -0
  134. package/dist/types/resources/me/musicSummary.d.ts +37 -0
  135. package/dist/types/resources/me/musicSummary.js +0 -0
  136. package/dist/types/resources/me/profile.d.ts +32 -0
  137. package/dist/types/resources/me/profile.js +0 -0
  138. package/dist/types/resources/me/rating.d.ts +11 -0
  139. package/dist/types/resources/me/rating.js +0 -0
  140. package/dist/types/resources/me/recommendation.d.ts +27 -0
  141. package/dist/types/resources/me/recommendation.js +0 -0
  142. package/dist/types/resources/me/summaries/albumPeriodSummary.d.ts +15 -0
  143. package/dist/types/resources/me/summaries/albumPeriodSummary.js +0 -0
  144. package/dist/types/resources/me/summaries/artistPeriodSummary.d.ts +15 -0
  145. package/dist/types/resources/me/summaries/artistPeriodSummary.js +0 -0
  146. package/dist/types/resources/me/summaries/genrePeriodSummary.d.ts +12 -0
  147. package/dist/types/resources/me/summaries/genrePeriodSummary.js +0 -0
  148. package/dist/types/resources/me/summaries/monthlySongPeriodSummary.d.ts +13 -0
  149. package/dist/types/resources/me/summaries/monthlySongPeriodSummary.js +0 -0
  150. package/dist/types/resources/me/summaries/playlistPeriodSummary.d.ts +14 -0
  151. package/dist/types/resources/me/summaries/playlistPeriodSummary.js +0 -0
  152. package/dist/types/resources/me/summaries/songPeriodSummary.d.ts +15 -0
  153. package/dist/types/resources/me/summaries/songPeriodSummary.js +0 -0
  154. package/dist/types/resources/me/summaries/stationPeriodSummary.d.ts +14 -0
  155. package/dist/types/resources/me/summaries/stationPeriodSummary.js +0 -0
  156. package/dist/types/resources/other/storefront.d.ts +8 -0
  157. package/dist/types/resources/other/storefront.js +0 -0
  158. package/dist/types/resources/shared/album.d.ts +11 -0
  159. package/dist/types/resources/shared/album.js +0 -0
  160. package/dist/types/resources/shared/artist.d.ts +3 -0
  161. package/dist/types/resources/shared/artist.js +0 -0
  162. package/dist/types/resources/shared/lyrics.d.ts +5 -0
  163. package/dist/types/resources/shared/lyrics.js +0 -0
  164. package/dist/types/resources/shared/musicVideo.d.ts +13 -0
  165. package/dist/types/resources/shared/musicVideo.js +0 -0
  166. package/dist/types/resources/shared/playlist.d.ts +7 -0
  167. package/dist/types/resources/shared/playlist.js +0 -0
  168. package/dist/types/resources/shared/song.d.ts +15 -0
  169. package/dist/types/resources/shared/song.js +0 -0
  170. package/dist/types/results/chart.d.ts +8 -0
  171. package/dist/types/results/chart.js +0 -0
  172. package/dist/types/results/search.d.ts +30 -0
  173. package/dist/types/results/search.js +0 -0
  174. package/dist/types/shared.d.ts +81 -0
  175. package/dist/types/shared.js +0 -0
  176. package/package.json +64 -0
@@ -0,0 +1,12 @@
1
+ import { ResourceClient } from "../../clients/resource.js";
2
+ import type { DefaultParams } from "../../types/params.js";
3
+ import type { Registry } from "../../types/query/registry.js";
4
+ import type { ResourceResponse } from "../../types/query/response.js";
5
+ import type { ResourceScopes } from "../../types/query/scopes.js";
6
+ declare const type: "music-summaries";
7
+ type TResource = Registry[typeof type];
8
+ export declare class MusicSummaryClient extends ResourceClient<typeof type, TResource> {
9
+ protected readonly type = "music-summaries";
10
+ getLatestReplay<const TScopes extends ResourceScopes = {}>(opts?: DefaultParams<TScopes>): Promise<ResourceResponse<import("../../types/public.js").MusicSummary, TScopes>>;
11
+ }
12
+ export {};
@@ -0,0 +1,14 @@
1
+ import { ResourceClient } from "../../clients/resource.js";
2
+ import { RequestQueryBuilder } from "../../helpers/requestQuery.js";
3
+ const type = "music-summaries";
4
+ export class MusicSummaryClient extends ResourceClient {
5
+ type = "music-summaries";
6
+ async getLatestReplay(opts = {}) {
7
+ const query = new RequestQueryBuilder().params(opts).setStringArray("filter[year]", "latest");
8
+ const result = await this.http.request(`${this.path}/${this.type}`, {
9
+ config: opts.config,
10
+ query,
11
+ });
12
+ return this.prepare(result);
13
+ }
14
+ }
@@ -0,0 +1,15 @@
1
+ import { BaseResourceClient } from "../../clients/resource.js";
2
+ import type { DefaultParams, LimitParam, PaginationParams } from "../../types/params.js";
3
+ import type { ResourceOf } from "../../types/query/helpers.js";
4
+ import type { RelationshipNames, TypeOf } from "../../types/query/resource.js";
5
+ import type { ResourceResponse } from "../../types/query/response.js";
6
+ import type { RelationshipItem, ResourceScopes, ScopedResourceIterator } from "../../types/query/scopes.js";
7
+ import type { RatingResources } from "../../types/resources/me/rating.js";
8
+ type TResource = ResourceOf<"ratings">;
9
+ export declare class RatingsClient extends BaseResourceClient {
10
+ get<const TScopes extends ResourceScopes = {}>(id: string, type: TypeOf<RatingResources>, opts?: DefaultParams<TScopes>): Promise<ResourceResponse<import("../../types/resources/me/rating.js").Rating, TScopes>>;
11
+ getMany<const TScopes extends ResourceScopes = {}>(ids: string[], type: TypeOf<RatingResources>, opts?: DefaultParams<TScopes>): Promise<ResourceResponse<import("../../types/resources/me/rating.js").Rating, TScopes>>;
12
+ getRelationship<TRelationship extends RelationshipNames<TResource>, const TScopes extends ResourceScopes = {}>(id: string, type: TypeOf<RatingResources>, relationship: TRelationship, opts?: DefaultParams<TScopes> & PaginationParams): Promise<ResourceResponse<RelationshipItem<import("../../types/resources/me/rating.js").Rating, TRelationship>, TScopes>>;
13
+ iterateRelationship<TRelationship extends RelationshipNames<TResource>, const TScopes extends ResourceScopes = {}>(id: string, type: TypeOf<RatingResources>, relationship: TRelationship, opts?: DefaultParams<TScopes> & LimitParam): ScopedResourceIterator<RelationshipItem<TResource, TRelationship>, TScopes>;
14
+ }
15
+ export {};
@@ -0,0 +1,34 @@
1
+ import { BaseResourceClient } from "../../clients/resource.js";
2
+ import { RequestQueryBuilder } from "../../helpers/requestQuery.js";
3
+ export class RatingsClient extends BaseResourceClient {
4
+ async get(id, type, opts = {}) {
5
+ const query = new RequestQueryBuilder().params(opts);
6
+ const result = await this.http.request(`${this.path}/ratings/${type}/${id}`, {
7
+ config: opts.config,
8
+ query,
9
+ });
10
+ return this.prepare(result);
11
+ }
12
+ async getMany(ids, type, opts = {}) {
13
+ const query = new RequestQueryBuilder().params(opts).setStringArray("ids", ids);
14
+ const result = await this.http.request(`${this.path}/ratings/${type}`, {
15
+ config: opts.config,
16
+ query,
17
+ });
18
+ return this.prepare(result);
19
+ }
20
+ async getRelationship(id, type, relationship, opts = {}) {
21
+ const query = new RequestQueryBuilder().params(opts);
22
+ const result = await this.http.request(`${this.path}/ratings/${type}/${id}/${relationship}`, {
23
+ config: opts.config,
24
+ query,
25
+ });
26
+ return this.prepare(result);
27
+ }
28
+ iterateRelationship(id, type, relationship, opts = {}) {
29
+ return this.iterate((offset) => this.getRelationship(id, type, relationship, {
30
+ ...opts,
31
+ offset,
32
+ }));
33
+ }
34
+ }
@@ -0,0 +1,17 @@
1
+ import { BaseResourceClient } from "../../clients/resource.js";
2
+ import type { DefaultParams, LimitParam, PaginationParams } from "../../types/params.js";
3
+ import type { ResourceOf } from "../../types/query/helpers.js";
4
+ import type { ResourceResponse } from "../../types/query/response.js";
5
+ import type { ResourceScopes, ScopedResourceIterator } from "../../types/query/scopes.js";
6
+ type RecentlyPlayedResource = ResourceOf<"albums" | "library-albums" | "playlists" | "library-playlists" | "stations">;
7
+ type RecentlyPlayedTrackResource = ResourceOf<"songs" | "library-songs" | "music-videos" | "library-music-videos">;
8
+ type RecentlyPlayedStationResource = ResourceOf<"stations">;
9
+ export declare class RecentClient extends BaseResourceClient {
10
+ getRecentlyPlayed<const TScopes extends ResourceScopes = {}>(opts?: DefaultParams<TScopes> & PaginationParams): Promise<ResourceResponse<RecentlyPlayedResource, TScopes>>;
11
+ getRecentlyPlayedTracks<const TScopes extends ResourceScopes = {}>(opts?: DefaultParams<TScopes> & PaginationParams): Promise<ResourceResponse<RecentlyPlayedTrackResource, TScopes>>;
12
+ getRecentlyPlayedStations<const TScopes extends ResourceScopes = {}>(opts?: DefaultParams<TScopes> & PaginationParams): Promise<ResourceResponse<import("../../types/public.js").CatalogStation, TScopes>>;
13
+ iterateRecentlyPlayed<const TScopes extends ResourceScopes = {}>(opts?: DefaultParams<TScopes> & LimitParam): ScopedResourceIterator<RecentlyPlayedResource, TScopes>;
14
+ iterateRecentlyPlayedTracks<const TScopes extends ResourceScopes = {}>(opts?: DefaultParams<TScopes> & LimitParam): ScopedResourceIterator<RecentlyPlayedTrackResource, TScopes>;
15
+ iterateRecentlyPlayedStations<const TScopes extends ResourceScopes = {}>(opts?: DefaultParams<TScopes> & LimitParam): ScopedResourceIterator<RecentlyPlayedStationResource, TScopes>;
16
+ }
17
+ export {};
@@ -0,0 +1,37 @@
1
+ import { BaseResourceClient } from "../../clients/resource.js";
2
+ import { RequestQueryBuilder } from "../../helpers/requestQuery.js";
3
+ export class RecentClient extends BaseResourceClient {
4
+ async getRecentlyPlayed(opts = {}) {
5
+ const query = new RequestQueryBuilder().params(opts);
6
+ const result = await this.http.request(`${this.path}/recent/played`, {
7
+ config: opts.config,
8
+ query,
9
+ });
10
+ return this.prepare(result);
11
+ }
12
+ async getRecentlyPlayedTracks(opts = {}) {
13
+ const query = new RequestQueryBuilder().params(opts);
14
+ const result = await this.http.request(`${this.path}/recent/played/tracks`, {
15
+ config: opts.config,
16
+ query,
17
+ });
18
+ return this.prepare(result);
19
+ }
20
+ async getRecentlyPlayedStations(opts = {}) {
21
+ const query = new RequestQueryBuilder().params(opts);
22
+ const result = await this.http.request(`${this.path}/recent/radio-stations`, {
23
+ config: opts.config,
24
+ query,
25
+ });
26
+ return this.prepare(result);
27
+ }
28
+ iterateRecentlyPlayed(opts = {}) {
29
+ return this.iterate((offset) => this.getRecentlyPlayed({ ...opts, offset }));
30
+ }
31
+ iterateRecentlyPlayedTracks(opts = {}) {
32
+ return this.iterate((offset) => this.getRecentlyPlayedTracks({ ...opts, offset }));
33
+ }
34
+ iterateRecentlyPlayedStations(opts = {}) {
35
+ return this.iterate((offset) => this.getRecentlyPlayedStations({ ...opts, offset }));
36
+ }
37
+ }
@@ -0,0 +1,12 @@
1
+ import { ResourceClient } from "../../clients/resource.js";
2
+ import type { DefaultParams, PaginationParams } from "../../types/params.js";
3
+ import type { Registry } from "../../types/query/registry.js";
4
+ import type { ResourceResponse } from "../../types/query/response.js";
5
+ import type { ResourceScopes } from "../../types/query/scopes.js";
6
+ declare const type: "personal-recommendation";
7
+ type TResource = Registry[typeof type];
8
+ export declare class RecommendationClient extends ResourceClient<typeof type, TResource> {
9
+ protected readonly type = "recommendations";
10
+ getDefault<const TScopes extends ResourceScopes = {}>(opts?: DefaultParams<TScopes> & PaginationParams): Promise<ResourceResponse<import("../../types/public.js").Recommendation, TScopes>>;
11
+ }
12
+ export {};
@@ -0,0 +1,14 @@
1
+ import { ResourceClient } from "../../clients/resource.js";
2
+ import { RequestQueryBuilder } from "../../helpers/requestQuery.js";
3
+ const type = "personal-recommendation";
4
+ export class RecommendationClient extends ResourceClient {
5
+ type = "recommendations";
6
+ async getDefault(opts = {}) {
7
+ const query = new RequestQueryBuilder().params(opts);
8
+ const result = await this.http.request(`${this.path}/${this.type}`, {
9
+ config: opts.config,
10
+ query,
11
+ });
12
+ return this.prepare(result);
13
+ }
14
+ }
@@ -0,0 +1,10 @@
1
+ import { BaseResourceClient } from "../../clients/resource.js";
2
+ import type { DefaultParams, LimitParam } from "../../types/params.js";
3
+ import type { ResourceOf } from "../../types/query/helpers.js";
4
+ import type { ResourceResponse } from "../../types/query/response.js";
5
+ import type { ResourceScopes } from "../../types/query/scopes.js";
6
+ type StationTrackResource = ResourceOf<"songs" | "music-videos">;
7
+ export declare class StationClient extends BaseResourceClient {
8
+ getNextTracks<const TScopes extends ResourceScopes = {}>(id: string, opts?: DefaultParams<TScopes> & LimitParam): Promise<ResourceResponse<StationTrackResource, TScopes>>;
9
+ }
10
+ export {};
@@ -0,0 +1,13 @@
1
+ import { BaseResourceClient } from "../../clients/resource.js";
2
+ import { RequestQueryBuilder } from "../../helpers/requestQuery.js";
3
+ export class StationClient extends BaseResourceClient {
4
+ async getNextTracks(id, opts = {}) {
5
+ const query = new RequestQueryBuilder().params(opts);
6
+ const result = await this.http.request(`${this.path}/stations/next-tracks/${id}`, {
7
+ config: opts.config,
8
+ method: "POST",
9
+ query,
10
+ });
11
+ return this.prepare(result);
12
+ }
13
+ }
@@ -0,0 +1,9 @@
1
+ import type { HttpClient } from "../core/http.js";
2
+ import type { ConfigParm } from "../types/params.js";
3
+ import type { PlayActivityEvent, PlayActivityResponse, PlaybackSong, PlaybackSongIds } from "../types/playback.js";
4
+ export declare class PlaybackClient {
5
+ private readonly http;
6
+ constructor(http: HttpClient);
7
+ getSong(ids: PlaybackSongIds, opts?: ConfigParm): Promise<PlaybackSong>;
8
+ reportPlayActivity(events: PlayActivityEvent | PlayActivityEvent[], opts?: ConfigParm): Promise<PlayActivityResponse>;
9
+ }
@@ -0,0 +1,68 @@
1
+ const webPlaybackUrl = "https://play.music.apple.com/WebObjects/MZPlay.woa/wa/webPlayback";
2
+ const playActivityUrl = "https://universal-activity-service.itunes.apple.com/play";
3
+ export class PlaybackClient {
4
+ http;
5
+ constructor(http) {
6
+ this.http = http;
7
+ }
8
+ async getSong(ids, opts = {}) {
9
+ const catalogId = ids.catalogId?.trim();
10
+ const libraryId = ids.libraryId?.trim();
11
+ if (!catalogId && !libraryId) {
12
+ throw new Error("webPlayback requires a catalog or library ID.");
13
+ }
14
+ const response = await this.http.requestUrl(webPlaybackUrl, {
15
+ config: opts.config,
16
+ method: "POST",
17
+ headers: {
18
+ "Content-Type": "application/json",
19
+ },
20
+ body: JSON.stringify({
21
+ ...(catalogId
22
+ ? libraryId
23
+ ? { subscriptionAdamId: catalogId }
24
+ : { salableAdamId: catalogId }
25
+ : {}),
26
+ ...(libraryId ? { universalLibraryId: libraryId } : {}),
27
+ }),
28
+ });
29
+ const song = response.songList?.[0];
30
+ if (!song) {
31
+ throw new Error(`webPlayback returned no songs${response.status === undefined ? "." : ` (status ${response.status}).`}`);
32
+ }
33
+ if (!song.assets?.length) {
34
+ throw new Error("webPlayback returned a song without assets.");
35
+ }
36
+ return song;
37
+ }
38
+ async reportPlayActivity(events, opts = {}) {
39
+ const data = Array.isArray(events) ? events : [events];
40
+ if (data.length === 0) {
41
+ throw new Error("Play activity reporting requires at least one event.");
42
+ }
43
+ return this.http.requestUrl(playActivityUrl, {
44
+ config: opts.config,
45
+ method: "POST",
46
+ headers: {
47
+ "Content-Type": "application/json",
48
+ },
49
+ body: ({ developerToken, userToken }) => {
50
+ if (!developerToken) {
51
+ throw new Error("Play activity reporting requires a developer token.");
52
+ }
53
+ if (!userToken) {
54
+ throw new Error("Play activity reporting requires a music user token.");
55
+ }
56
+ return JSON.stringify({
57
+ client_id: "JSCLIENT",
58
+ event_type: "JSPLAY",
59
+ data: data.map((event) => ({
60
+ ...event,
61
+ "developer-token": developerToken,
62
+ "user-token": userToken,
63
+ })),
64
+ });
65
+ },
66
+ });
67
+ }
68
+ }
@@ -0,0 +1,34 @@
1
+ import type { HttpClient } from "../core/http.js";
2
+ import type { DefaultParams, LimitParam, PaginationParams, SortParams } from "../types/params.js";
3
+ import type { Registry } from "../types/query/registry.js";
4
+ import type { AnyResource, RelationshipNames, ViewNames } from "../types/query/resource.js";
5
+ import type { ResourceResponse } from "../types/query/response.js";
6
+ import type { AnyResult, ResultShape, ShapedResult } from "../types/query/results.js";
7
+ import type { RelationshipItem, ResourceScopes, ScopedResourceIterator, ViewItem } from "../types/query/scopes.js";
8
+ type ResourceClientConstructor<TKey extends keyof Registry> = new (http: HttpClient, path: string) => ResourceClient<TKey>;
9
+ type LibraryResourceClientConstructor<TKey extends keyof Registry> = new (http: HttpClient, path: string) => LibraryResourceClient<TKey>;
10
+ export declare abstract class BaseResourceClient {
11
+ protected readonly http: HttpClient;
12
+ protected readonly path: string;
13
+ constructor(http: HttpClient, path: string);
14
+ protected prepare<TResource extends AnyResource, TScopes extends ResourceScopes = {}>(raw: ResourceResponse<TResource, TScopes>): ResourceResponse<TResource, TScopes>;
15
+ protected prepareResults<TResult extends AnyResult, TTypes extends ResultShape<TResult>, TScopes extends ResourceScopes = {}>(raw: ShapedResult<TResult, TTypes, TScopes>): ShapedResult<TResult, TTypes, TScopes>;
16
+ protected iterate<TResource extends AnyResource, const TScopes extends ResourceScopes = {}>(fetch: (offset: number) => Promise<ResourceResponse<TResource, TScopes>>): ScopedResourceIterator<TResource, TScopes>;
17
+ }
18
+ export declare abstract class ResourceClient<TKey extends keyof Registry, TResource extends Registry[TKey] = Registry[TKey]> extends BaseResourceClient {
19
+ protected readonly type: string;
20
+ constructor(http: HttpClient, path: string, type?: string);
21
+ get<const TScopes extends ResourceScopes = {}>(id: string, opts?: DefaultParams<TScopes>): Promise<ResourceResponse<TResource, TScopes>>;
22
+ getMany<const TScopes extends ResourceScopes = {}>(ids: string[], opts?: DefaultParams<TScopes>): Promise<ResourceResponse<TResource, TScopes>>;
23
+ getRelationship<TRelationship extends RelationshipNames<TResource>, const TScopes extends ResourceScopes = {}>(id: string, relationship: TRelationship, opts?: DefaultParams<TScopes> & PaginationParams): Promise<ResourceResponse<RelationshipItem<TResource, TRelationship>, TScopes>>;
24
+ getView<TView extends ViewNames<TResource>, const TScopes extends ResourceScopes = {}>(id: string, view: TView, opts?: DefaultParams<TScopes> & PaginationParams): Promise<ResourceResponse<ViewItem<TResource, TView>, TScopes>>;
25
+ iterateRelationship<TRelationship extends RelationshipNames<TResource>, const TScopes extends ResourceScopes = {}>(id: string, relationship: TRelationship, opts?: DefaultParams<TScopes> & LimitParam): ScopedResourceIterator<RelationshipItem<TResource, TRelationship>, TScopes>;
26
+ iterateView<TView extends ViewNames<TResource>, const TScopes extends ResourceScopes = {}>(id: string, view: TView, opts?: DefaultParams<TScopes> & LimitParam): ScopedResourceIterator<ViewItem<TResource, TView>, TScopes>;
27
+ }
28
+ export declare function createResourceClient<const TKey extends keyof Registry>(type: TKey): ResourceClientConstructor<TKey>;
29
+ export declare abstract class LibraryResourceClient<TKey extends keyof Registry, TResource extends Registry[TKey] = Registry[TKey]> extends ResourceClient<TKey, TResource> {
30
+ getAll<const TScopes extends ResourceScopes = {}>(opts?: DefaultParams<TScopes> & PaginationParams & SortParams<"dateAdded" | "name">): Promise<ResourceResponse<TResource, TScopes>>;
31
+ iterateAll<const TScopes extends ResourceScopes = {}>(opts?: DefaultParams<TScopes> & LimitParam & SortParams<"dateAdded" | "name">): ScopedResourceIterator<TResource, TScopes>;
32
+ }
33
+ export declare function createLibraryResourceClient<const TKey extends keyof Registry>(type: string): LibraryResourceClientConstructor<TKey>;
34
+ export {};
@@ -0,0 +1,105 @@
1
+ import { RequestQueryBuilder } from "../helpers/requestQuery.js";
2
+ export class BaseResourceClient {
3
+ http;
4
+ path;
5
+ constructor(http, path) {
6
+ this.http = http;
7
+ this.path = path;
8
+ }
9
+ prepare(raw) {
10
+ return raw;
11
+ }
12
+ prepareResults(raw) {
13
+ return raw;
14
+ }
15
+ async *iterate(fetch) {
16
+ let page = await fetch(0);
17
+ while (true) {
18
+ yield* page.data;
19
+ if (!page.next)
20
+ break;
21
+ const offsetValue = new URL(page.next, "https://music.apple.com").searchParams.get("offset");
22
+ if (!offsetValue)
23
+ break;
24
+ const offset = Number(offsetValue);
25
+ if (Number.isNaN(offset))
26
+ break;
27
+ page = await fetch(offset);
28
+ }
29
+ }
30
+ }
31
+ export class ResourceClient extends BaseResourceClient {
32
+ type;
33
+ constructor(http, path, type = "") {
34
+ super(http, path);
35
+ this.type = type;
36
+ }
37
+ async get(id, opts = {}) {
38
+ const query = new RequestQueryBuilder().params(opts);
39
+ const result = await this.http.request(`${this.path}/${this.type}/${id}`, {
40
+ config: opts.config,
41
+ query,
42
+ });
43
+ return this.prepare(result);
44
+ }
45
+ async getMany(ids, opts = {}) {
46
+ const query = new RequestQueryBuilder().params(opts).setStringArray("ids", ids);
47
+ const result = await this.http.request(`${this.path}/${this.type}`, {
48
+ config: opts.config,
49
+ query,
50
+ });
51
+ return this.prepare(result);
52
+ }
53
+ async getRelationship(id, relationship, opts = {}) {
54
+ const query = new RequestQueryBuilder().params(opts);
55
+ const result = await this.http.request(`${this.path}/${this.type}/${id}/${relationship}`, {
56
+ config: opts.config,
57
+ query,
58
+ });
59
+ return this.prepare(result);
60
+ }
61
+ async getView(id, view, opts = {}) {
62
+ const query = new RequestQueryBuilder().params(opts);
63
+ const result = await this.http.request(`${this.path}/${this.type}/${id}/view/${view}`, {
64
+ config: opts.config,
65
+ query,
66
+ });
67
+ return this.prepare(result);
68
+ }
69
+ iterateRelationship(id, relationship, opts = {}) {
70
+ return this.iterate((offset) => this.getRelationship(id, relationship, {
71
+ ...opts,
72
+ offset,
73
+ }));
74
+ }
75
+ iterateView(id, view, opts = {}) {
76
+ return this.iterate((offset) => this.getView(id, view, { ...opts, offset }));
77
+ }
78
+ }
79
+ export function createResourceClient(type) {
80
+ return class extends ResourceClient {
81
+ constructor(http, path) {
82
+ super(http, path, type);
83
+ }
84
+ };
85
+ }
86
+ export class LibraryResourceClient extends ResourceClient {
87
+ async getAll(opts = {}) {
88
+ const query = new RequestQueryBuilder().params(opts).setString("sort", opts.sort);
89
+ const result = await this.http.request(`${this.path}/${this.type}`, {
90
+ config: opts.config,
91
+ query,
92
+ });
93
+ return this.prepare(result);
94
+ }
95
+ iterateAll(opts = {}) {
96
+ return this.iterate((offset) => this.getAll({ ...opts, offset }));
97
+ }
98
+ }
99
+ export function createLibraryResourceClient(type) {
100
+ return class extends LibraryResourceClient {
101
+ constructor(http, path) {
102
+ super(http, path, type);
103
+ }
104
+ };
105
+ }
@@ -0,0 +1,10 @@
1
+ import { ResourceClient } from "../../clients/resource.js";
2
+ import type { DefaultParams } from "../../types/params.js";
3
+ import type { Registry } from "../../types/query/registry.js";
4
+ import type { ResourceResponse } from "../../types/query/response.js";
5
+ import type { ResourceScopes } from "../../types/query/scopes.js";
6
+ export declare abstract class EquivalentClient<TKey extends keyof Registry, TResource extends Registry[TKey] = Registry[TKey]> extends ResourceClient<TKey, TResource> {
7
+ getEquivalents<const TScopes extends ResourceScopes = {}>(ids: string | string[], opts?: DefaultParams<TScopes> & {
8
+ restrict?: ["explicit"];
9
+ }): Promise<ResourceResponse<TResource, TScopes>>;
10
+ }
@@ -0,0 +1,15 @@
1
+ import { ResourceClient } from "../../clients/resource.js";
2
+ import { RequestQueryBuilder } from "../../helpers/requestQuery.js";
3
+ export class EquivalentClient extends ResourceClient {
4
+ async getEquivalents(ids, opts = {}) {
5
+ const query = new RequestQueryBuilder()
6
+ .params(opts)
7
+ .setStringArray("filter[equivalents]", ids)
8
+ .setStringArray("restrict", opts.restrict);
9
+ const result = await this.http.request(`${this.path}/${this.type}`, {
10
+ config: opts.config,
11
+ query,
12
+ });
13
+ return this.prepare(result);
14
+ }
15
+ }
@@ -0,0 +1,7 @@
1
+ import { BaseResourceClient } from "../../clients/resource.js";
2
+ import { SocialProfileClient } from "../../clients/social/profile.js";
3
+ import type { HttpClient } from "../../core/http.js";
4
+ export declare class SocialClient extends BaseResourceClient {
5
+ profiles: SocialProfileClient;
6
+ constructor(http: HttpClient, path: string);
7
+ }
@@ -0,0 +1,9 @@
1
+ import { BaseResourceClient } from "../../clients/resource.js";
2
+ import { SocialProfileClient } from "../../clients/social/profile.js";
3
+ export class SocialClient extends BaseResourceClient {
4
+ profiles;
5
+ constructor(http, path) {
6
+ super(http, path);
7
+ this.profiles = new SocialProfileClient(http, path);
8
+ }
9
+ }
@@ -0,0 +1,12 @@
1
+ import { ResourceClient } from "../../clients/resource.js";
2
+ import type { DefaultParams } from "../../types/params.js";
3
+ import type { Registry } from "../../types/query/registry.js";
4
+ import type { ResourceResponse } from "../../types/query/response.js";
5
+ import type { ResourceScopes } from "../../types/query/scopes.js";
6
+ declare const type: "social-profiles";
7
+ type TResource = Registry[typeof type];
8
+ export declare class SocialProfileClient extends ResourceClient<typeof type, TResource> {
9
+ protected readonly type: "social-profiles";
10
+ getByHandle<const TScopes extends ResourceScopes = {}>(handles: string | string[], opts?: DefaultParams<TScopes>): Promise<ResourceResponse<import("../../types/resources/me/profile.js").SocialProfile, TScopes>>;
11
+ }
12
+ export {};
@@ -0,0 +1,14 @@
1
+ import { ResourceClient } from "../../clients/resource.js";
2
+ import { RequestQueryBuilder } from "../../helpers/requestQuery.js";
3
+ const type = "social-profiles";
4
+ export class SocialProfileClient extends ResourceClient {
5
+ type = type;
6
+ async getByHandle(handles, opts = {}) {
7
+ const query = new RequestQueryBuilder().params(opts).setStringArray("filter[handle]", handles);
8
+ const result = await this.http.request(`${this.path}/${this.type}`, {
9
+ config: opts.config,
10
+ query,
11
+ });
12
+ return this.prepare(result);
13
+ }
14
+ }
@@ -0,0 +1,12 @@
1
+ import { ResourceClient } from "../clients/resource.js";
2
+ import type { DefaultParams } from "../types/params.js";
3
+ import type { Registry } from "../types/query/registry.js";
4
+ import type { ResourceResponse } from "../types/query/response.js";
5
+ import type { ResourceScopes } from "../types/query/scopes.js";
6
+ declare const type: "storefronts";
7
+ type TResource = Registry[typeof type];
8
+ export declare class StorefrontClient extends ResourceClient<typeof type, TResource> {
9
+ protected readonly type = "storefronts";
10
+ getAll<const TScopes extends ResourceScopes = {}>(opts?: DefaultParams<TScopes>): Promise<ResourceResponse<import("../types/public.js").Storefront, TScopes>>;
11
+ }
12
+ export {};
@@ -0,0 +1,14 @@
1
+ import { ResourceClient } from "../clients/resource.js";
2
+ import { RequestQueryBuilder } from "../helpers/requestQuery.js";
3
+ const type = "storefronts";
4
+ export class StorefrontClient extends ResourceClient {
5
+ type = "storefronts";
6
+ async getAll(opts = {}) {
7
+ const query = new RequestQueryBuilder().params(opts);
8
+ const result = await this.http.request(`${this.path}/${this.type}`, {
9
+ config: opts.config,
10
+ query,
11
+ });
12
+ return this.prepare(result);
13
+ }
14
+ }
@@ -0,0 +1,40 @@
1
+ import { CatalogClient } from "../clients/catalog/index.js";
2
+ import { LibraryClient } from "../clients/library/index.js";
3
+ import { MeClient } from "../clients/me/index.js";
4
+ import { PlaybackClient } from "../clients/playback.js";
5
+ import { SocialClient } from "../clients/social/index.js";
6
+ import { StorefrontClient } from "../clients/storefront.js";
7
+ import { HttpClient } from "../core/http.js";
8
+ import type { OpfelMusigConfig } from "../types/config.js";
9
+ import type { ConfigParm } from "../types/params.js";
10
+ export declare class OpfelMusigClient {
11
+ http: HttpClient;
12
+ catalog: CatalogClient;
13
+ library: LibraryClient;
14
+ storefront: StorefrontClient;
15
+ me: MeClient;
16
+ social: SocialClient;
17
+ playback: PlaybackClient;
18
+ private readonly apiVersion;
19
+ test(opts?: ConfigParm): Promise<void>;
20
+ /**
21
+ * Use the logged in users default `storefront` and `language`.
22
+ */
23
+ useUserDefault(opts?: ConfigParm): Promise<(Pick<import("../types/resources/other/storefront.js").StorefrontAttributes, keyof import("../types/resources/other/storefront.js").StorefrontAttributes> & Pick<{}, never>) | undefined>;
24
+ /**
25
+ * Set the language from a language tag like `de-CH`
26
+ */
27
+ setLanguageFromTag(language?: string): void;
28
+ /**
29
+ * For each key:
30
+ * - `T`: use the new value
31
+ * - `undefined`: use the old value
32
+ * - `null`: delete the value
33
+ */
34
+ edit: typeof this.http.edit;
35
+ get config(): {
36
+ storefront: string | undefined;
37
+ language: import("../types/config.js").LanguageConfig | undefined;
38
+ };
39
+ constructor(config?: OpfelMusigConfig);
40
+ }
@@ -0,0 +1,82 @@
1
+ import { CatalogClient } from "../clients/catalog/index.js";
2
+ import { LibraryClient } from "../clients/library/index.js";
3
+ import { MeClient } from "../clients/me/index.js";
4
+ import { PlaybackClient } from "../clients/playback.js";
5
+ import { SocialClient } from "../clients/social/index.js";
6
+ import { StorefrontClient } from "../clients/storefront.js";
7
+ import { HttpClient } from "../core/http.js";
8
+ import { lyricScriptFromLanguage } from "../helpers/language.js";
9
+ export class OpfelMusigClient {
10
+ http;
11
+ catalog;
12
+ library;
13
+ storefront;
14
+ me;
15
+ social;
16
+ playback;
17
+ apiVersion = "v1";
18
+ async test(opts = {}) {
19
+ await this.http.request(`${this.apiVersion}/test`, {
20
+ config: opts.config,
21
+ });
22
+ }
23
+ /**
24
+ * Use the logged in users default `storefront` and `language`.
25
+ */
26
+ async useUserDefault(opts = {}) {
27
+ const storefront = await this.me.getStorefront({
28
+ config: opts.config,
29
+ });
30
+ const userDefaultStorefront = storefront.data[0];
31
+ if (!userDefaultStorefront)
32
+ throw new Error("Apple Music API returned no user storefront");
33
+ this.edit({
34
+ storefront: userDefaultStorefront.id,
35
+ });
36
+ const language = userDefaultStorefront.attributes?.defaultLanguageTag;
37
+ if (language) {
38
+ this.edit({
39
+ language: {
40
+ default: language,
41
+ lyrics: language,
42
+ script: lyricScriptFromLanguage(language),
43
+ },
44
+ });
45
+ }
46
+ return userDefaultStorefront.attributes;
47
+ }
48
+ /**
49
+ * Set the language from a language tag like `de-CH`
50
+ */
51
+ setLanguageFromTag(language) {
52
+ if (language) {
53
+ this.edit({
54
+ language: {
55
+ default: language,
56
+ lyrics: language,
57
+ script: lyricScriptFromLanguage(language),
58
+ },
59
+ });
60
+ }
61
+ }
62
+ /**
63
+ * For each key:
64
+ * - `T`: use the new value
65
+ * - `undefined`: use the old value
66
+ * - `null`: delete the value
67
+ */
68
+ edit;
69
+ get config() {
70
+ return this.http.conf;
71
+ }
72
+ constructor(config = {}) {
73
+ this.http = new HttpClient(config);
74
+ this.edit = this.http.edit;
75
+ this.catalog = new CatalogClient(this.http, `${this.apiVersion}/catalog/{{storefront}}`);
76
+ this.library = new LibraryClient(this.http, `${this.apiVersion}/me/library`);
77
+ this.me = new MeClient(this.http, `${this.apiVersion}/me`);
78
+ this.storefront = new StorefrontClient(this.http, this.apiVersion);
79
+ this.social = new SocialClient(this.http, `${this.apiVersion}/social/{{storefront}}`);
80
+ this.playback = new PlaybackClient(this.http);
81
+ }
82
+ }