Skip to content

Commit

Permalink
feat: Search API
Browse files Browse the repository at this point in the history
  • Loading branch information
noook committed Jun 25, 2023
1 parent 9a53eb5 commit 0e18759
Show file tree
Hide file tree
Showing 4 changed files with 107 additions and 1 deletion.
28 changes: 28 additions & 0 deletions src/api/search.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { ApiPart } from './api.part'
import type { SearchOptions, SearchResult, SearchType } from '@/types/search'

export class SearchApi extends ApiPart {
/**
* Get Spotify catalog information about albums, artists, playlists, tracks, shows, episodes or audiobooks that match a keyword string.
*
* **Note**: Audiobooks are only available for the US, UK, Ireland, New Zealand and Australia markets.
* @param types A list of item types to search across.
* @param query Your search query.
* You can narrow down your search using field filters. The available filters are `album`, `artist`,
* `track`, `year`, `upc`, `tag:hipster`, `tag:new`, `isrc`, and `genre`. Each field filter only
* applies to certain result types.
* @param opts
*/
public search<const T extends readonly SearchType[]>(
types: T,
query: string, opts: SearchOptions = {},
): Promise<SearchResult<T>> {
return this.$fetch<SearchResult<T>>('/search', {
query: {
type: types.join(','),
q: query,
...opts,
},
})
}
}
6 changes: 6 additions & 0 deletions src/types/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,17 @@ export enum ResourceType {
Artist = 'artist',
Playlist = 'playlist',
Track = 'track',
Show = 'show',
Episode = 'episode',
Audiobook = 'audiobook',

Albums = 'albums',
Artists = 'artists',
Playlists = 'playlists',
Tracks = 'tracks',
Shows = 'shows',
Episodes = 'episodes',
Audiobooks = 'audiobooks',

User = 'user',
}
Expand Down
3 changes: 2 additions & 1 deletion src/types/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export * from './common'
export * from './users'
export * from './artist'
export * from './search'
export * from './track'
export * from './users'
71 changes: 71 additions & 0 deletions src/types/search.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import type { SimplifiedAlbumObject } from './album'
import type { ArtistObject } from './artist'
import type { Market, PaginatedResults, ResourceType } from './common'
import type { TrackObject } from './track'

export type SearchType =
| ResourceType.Album
| ResourceType.Artist
| ResourceType.Playlist
| ResourceType.Track
| ResourceType.Show
| ResourceType.Episode
| ResourceType.Audiobook

export interface SearchOptions {
/**
* If include_external=audio is specified it signals that the client can play externally hosted audio content,
* and marks the content as playable in the response.
* By default externally hosted audio content is marked as unplayable in the response.
*/
include_external?: 'audio'

/**
* 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

/**
* The maximum number of items to return.
* @default `20`
* @min `1`
* @max `50`
*/
limit?: number

/**
* The index of the first item to return. Use with limit to get the next set of items.
* @default `0` (the first item).
*/
offset?: number
}

interface ResourceTypeToResultKey {
[ResourceType.Album]: ResourceType.Albums
[ResourceType.Artist]: ResourceType.Artists
[ResourceType.Track]: ResourceType.Tracks
[ResourceType.Playlist]: ResourceType.Playlists
[ResourceType.Show]: ResourceType.Shows
[ResourceType.Episode]: ResourceType.Episodes
[ResourceType.Audiobook]: ResourceType.Audiobooks
}

interface SearchResultsMap {
[ResourceType.Album]: SimplifiedAlbumObject
[ResourceType.Artist]: ArtistObject
[ResourceType.Track]: TrackObject
}

export type PartialSearchResult = {
[K in SearchType as ResourceTypeToResultKey[K]]?: PaginatedResults<K extends keyof SearchResultsMap ? SearchResultsMap[K] : any>
}

/**
* Makes all properties in SearchResults optional, unless the type T is a tuple (literal array / tuple) of SearchTypes.
*/
export type SearchResult<T extends readonly SearchType[]> = Pick<PartialSearchResult, ResourceTypeToResultKey[T[number]]> extends infer R
? number extends T['length']
? R
: Required<R>
: never

0 comments on commit 0e18759

Please sign in to comment.