From b375b89e4016327073537a5ad054aeebfbc1208d Mon Sep 17 00:00:00 2001 From: Neil Richter Date: Mon, 24 Jul 2023 23:11:04 +0200 Subject: [PATCH] feat: audiobooks API --- src/api/audiobooks.ts | 100 ++++++++++++++++ src/api/client.ts | 5 +- src/api/index.ts | 1 + src/types/audiobook.ts | 259 +++++++++++++++++++++++++++++++++++++++++ src/types/index.ts | 1 + 5 files changed, 365 insertions(+), 1 deletion(-) create mode 100644 src/api/audiobooks.ts create mode 100644 src/types/audiobook.ts diff --git a/src/api/audiobooks.ts b/src/api/audiobooks.ts new file mode 100644 index 0000000..c727f4e --- /dev/null +++ b/src/api/audiobooks.ts @@ -0,0 +1,100 @@ +import type { GetAudiobookChapterOptions, GetAudiobookOptions, GetAudiobooksResponse, PaginatedResults, PaginationQueryOptions, SimplifiedAudiobookObject, SimplifiedChapterObject } from '../types' +import { ApiPart } from './api.part' + +export class AudiobooksApi extends ApiPart { + /** + * Get Spotify catalog information for a single audiobook. + * + * **Note:** Audiobooks are only available for the US, UK, Ireland, New Zealand and Australia markets. + * @param id The [Spotify ID](https://developer.spotify.com/documentation/web-api/concepts/spotify-uris-ids) for the audiobook. + */ + public getAudiobook(id: string, opts: GetAudiobookOptions = {}) { + return this.$fetch(`/audiobooks/${id}`, { + query: opts, + }) + } + + /** + * Get Spotify catalog information for several audiobooks identified by their Spotify IDs. + * + * **Note:** Audiobooks are only available for the US, UK, Ireland, New Zealand and Australia markets. + * @param ids A list of the Spotify IDs. For example: `ids=18yVqkdbdRvS24c0Ilj2ci,1HGw3J3NxZO1TP1BTtVhpZ`. + * @max `50` IDs. + */ + public getAudiobooks(ids: string[], opts: GetAudiobookOptions = {}): Promise { + return this.$fetch('/audiobooks', { + query: { + ids: ids.join(','), + ...opts, + }, + }) + } + + /** + * Get Spotify catalog information about an audiobook's chapters. + * + * **Note:** Audiobooks are only available for the US, UK, Ireland, New Zealand and Australia markets. + * @param opts + * @returns + */ + public getAudiobookChapters(id: string, opts: GetAudiobookChapterOptions = {}) { + return this.$fetch>(`/audiobooks/${id}/chapters`, { + query: opts, + }) + } + + /** + * Get a list of the audiobooks saved in the current Spotify user's 'Your Music' library. + * @param opts + * @scope `user-library-read` + */ + public getSavedAudiobooks(opts: PaginationQueryOptions = {}): Promise>> { + return this.$fetch>>('/me/audiobooks', { + query: opts, + }) + } + + /** + * Save one or more audiobooks to the current Spotify user's library. + * @param ids A list of the [Spotify IDs]([Spotify ID](https://developer.spotify.com/documentation/web-api/concepts/spotify-uris-ids)). + * @max `50` IDs. + * @scope `user-library-modify` + */ + public async saveAudiobooks(ids: string[]): Promise { + await this.$fetch('/me/audiobooks', { + method: 'PUT', + query: { + ids: ids.join(','), + }, + }) + } + + /** + * Remove one or more audiobooks to the current Spotify user's library. + * @param ids A list of the [Spotify IDs]([Spotify ID](https://developer.spotify.com/documentation/web-api/concepts/spotify-uris-ids)). + * @max `50` IDs. + * @scope `user-library-modify` + */ + public async removeAudiobooks(ids: string[]): Promise { + await this.$fetch('/me/audiobooks', { + method: 'DELETE', + query: { + ids: ids.join(','), + }, + }) + } + + /** + * Check if one or more audiobooks are already saved in the current Spotify user's library. + * @param ids A list of the [Spotify IDs]([Spotify ID](https://developer.spotify.com/documentation/web-api/concepts/spotify-uris-ids)). + * @max `50` IDs. + * @scope `user-library-read` + */ + public checkUserSavedAudiobooks(ids: string[]): Promise { + return this.$fetch('/me/audiobooks/contains', { + query: { + ids: ids.join(','), + }, + }) + } +} diff --git a/src/api/client.ts b/src/api/client.ts index 395f6df..668ce85 100644 --- a/src/api/client.ts +++ b/src/api/client.ts @@ -1,6 +1,6 @@ import type { $Fetch } from 'ofetch' import { Headers, ofetch } from 'ofetch' -import { AlbumsApi, ArtistsApi, CategoriesApi, GenresApi, MarketsApi, PlayerApi, PlaylistsApi, SearchApi, UsersApi } from '.' +import { AlbumsApi, ArtistsApi, AudiobooksApi, CategoriesApi, GenresApi, MarketsApi, PlayerApi, PlaylistsApi, SearchApi, UsersApi } from '.' export class SpotifyClient { private token: null | string = null @@ -20,6 +20,7 @@ export class SpotifyClient { this.albums = new AlbumsApi(this.$fetch) this.artists = new ArtistsApi(this.$fetch) + this.audiobooks = new AudiobooksApi(this.$fetch) this.categories = new CategoriesApi(this.$fetch) this.genres = new GenresApi(this.$fetch) this.markets = new MarketsApi(this.$fetch) @@ -39,6 +40,8 @@ export class SpotifyClient { public artists: ArtistsApi + public audiobooks: AudiobooksApi + public categories: CategoriesApi public genres: GenresApi diff --git a/src/api/index.ts b/src/api/index.ts index c345882..fb74bc5 100644 --- a/src/api/index.ts +++ b/src/api/index.ts @@ -1,5 +1,6 @@ export * from './albums' export * from './artists' +export * from './audiobooks' export * from './categories' export * from './genres' export * from './markets' diff --git a/src/types/audiobook.ts b/src/types/audiobook.ts new file mode 100644 index 0000000..c53b458 --- /dev/null +++ b/src/types/audiobook.ts @@ -0,0 +1,259 @@ +import type { CopyrightsObject, ExternalUrlObject, ImageObject, Market, PaginatedResults, PaginationQueryOptions } from './common' + +export interface GetAudiobookOptions { +/** + * An [ISO 3166-1 alpha-2](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2) country code. If a country code is specified, + * only content that is available in that market will be returned. + */ + market?: Market +} + +export interface GetAudiobookChapterOptions extends PaginationQueryOptions, GetAudiobookOptions {} + +export interface GetAudiobooksResponse { + audiobooks: AudiobookObject[] +} + +export interface AudiobookAuthor { + /** + * The name of the author. + */ + name: string +} + +export interface AudiobookNarrator { + /** + * The name of the narrator. + */ + name: string +} + +export interface SimplifiedChapterObject { + /** + * A URL to a 30 second preview (MP3 format) of the episode. null if not available. + */ + audio_preview_url: string | null + + /** + * /** + * A list of the countries in which the track can be played, identified by their + * [ISO 3166-1 alpha-2](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2) code. + */ + available_markets: string[] + + /** + * The number of the chapter + */ + chapter_number: number + + /** + * A description of the audiobook. HTML tags are stripped away from this field, use `html_description` field in case HTML tags are needed. + */ + description: string + + /** + * A description of the audiobook. This field may contain HTML tags. + */ + html_description: string + + /** + * The episode length in milliseconds. + */ + duration_ms: number + + /** + * Whether or not the audiobook has explicit content (`true` = yes it does; `false` = no it does not OR unknown). + */ + explicit: boolean + + /** + * External URLs for this episode. + */ + external_urls: ExternalUrlObject + + /** + * A link to the Web API endpoint providing full details of the episode. + */ + href: string + + /** + * The [Spotify ID](https://developer.spotify.com/documentation/web-api/concepts/spotify-uris-ids) for the episode. + */ + id: string + + /** + * he cover art for the episode in various sizes, widest first. + */ + images: ImageObject[] + + /** + * `true` if the episode is playable in the given market. Otherwise `false`. + */ + is_playable: boolean + + /** + * A list of the languages used in the audiobook, identified by their [ISO 639](https://en.wikipedia.org/wiki/ISO_639) code. + */ + languages: string[] + + /** + * The name of the episode + */ + name: string + + /** + * The date the episode was first released, for example `"1981-12-15"`. Depending on the precision, it might be shown as `"1981"` or `"1981-12"`. + */ + release_date: string + + /** + * The precision with which `release_date` value is known. + */ + release_date_precision: 'year' | 'month' | 'day' + + /** + * The user's most recent position in the episode. Set if the supplied access token is a user token and has the scope 'user-read-playback-position'. + */ + resume_point?: { + /** + * Whether or not the episode has been fully played by the user. + */ + fully_played: boolean + + /** + * The user's most recent position in the episode in milliseconds. + */ + resume_position_ms: number + } + + /** + * The object type. + */ + type: 'episode' + + /** + * The [Spotify URI](https://developer.spotify.com/documentation/web-api/concepts/spotify-uris-ids) for the episode. + */ + uri: string + + /** + * Included in the response when a content restriction is applied. + */ + restrictions?: { + /** + * The reason for the restriction. Supported values: + * - `market` - The content item is not available in the given market. + * - `product` - The content item is not available for the user's subscription type. + * - `explicit` - The content item is explicit and the user's account is set to not play explicit content. + * - `payment_required` - Payment is required to play the content item. + * + * Additional reasons may be added in the future. + * + * **Note:** If you use this field, make sure that your application safely handles unknown values. + */ + reason: string + } +} + +export interface AudiobookObject { + authors: AudiobookAuthor[] + + /** + * /** + * A list of the countries in which the track can be played, identified by their + * [ISO 3166-1 alpha-2](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2) code. + */ + available_markets: string[] + + /** + * The copyright statements of the audiobook. + */ + copyrights: CopyrightsObject[] + + /** + * A description of the audiobook. HTML tags are stripped away from this field, use `html_description` field in case HTML tags are needed. + */ + description: string + + /** + * A description of the audiobook. This field may contain HTML tags. + */ + html_description: string + + /** + * The edition of the audiobook. + */ + edition?: string + + /** + * Whether or not the audiobook has explicit content (`true` = yes it does; `false` = no it does not OR unknown). + */ + explicit: boolean + + /** + * External URLs for this audiobook. + */ + external_urls: ExternalUrlObject + + /** + * A link to the Web API endpoint providing full details of the audiobook. + */ + href: string + + /** + * The [Spotify ID](https://developer.spotify.com/documentation/web-api/concepts/spotify-uris-ids) for the audiobook. + */ + id: string + + /** + * he cover art for the audiobook in various sizes, widest first. + */ + images: ImageObject[] + + /** + * A list of the languages used in the audiobook, identified by their [ISO 639](https://en.wikipedia.org/wiki/ISO_639) code. + */ + languages: string[] + + /** + * The media type of the audiobook. + */ + media_type: string + + /** + * The name of the audiobook. + */ + name: string + + /** + * The narrator(s) for the audiobook. + */ + narrators: AudiobookNarrator[] + + /** + * The publisher of the audiobook. + */ + publisher: string + + /** + * Allowed values: "audiobook" + */ + type: 'audiobook' + + /** + * The [Spotify URI](https://developer.spotify.com/documentation/web-api/concepts/spotify-uris-ids) for the audiobook. + */ + uri: string + + /** + * The number of chapters in this audiobook. + */ + total_chapters: number + + /** + * The chapters of the audiobook. + */ + chapters: PaginatedResults +} + +export type SimplifiedAudiobookObject = Omit diff --git a/src/types/index.ts b/src/types/index.ts index 9124b44..0d41174 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -1,6 +1,7 @@ export * from './common' export * from './artist' export * from './album' +export * from './audiobook' export * from './categories' export * from './episode' export * from './markets'