swiftie-api
v0.1.0
Published
A free, fan-made library for Taylor Swift discography, eras, quotes, and metadata - offline-bundled data with an optional hosted client.
Maintainers
Readme
swiftie-api
A free, fan-made library for Taylor Swift discography, eras, quotes, and metadata — offline-bundled data with an optional hosted client.
swiftie-api ships every album, song, era, and curated quote in the published bundle, so most calls are synchronous and zero-network. Per-album subpaths let you load one album at a time, and an optional createClient factory targets the hosted REST API when you want server-side filtering or shared state.
Install
pnpm add swiftie-api
# or
npm install swiftie-api
# or
yarn add swiftie-apiNo peer dependencies. Works in Node 18+, modern browsers, Bun, and Deno.
Quick start
Offline mode (default — bundles data)
import {
getAlbum,
getAllAlbums,
getAlbumWithSongs,
getSong,
getSongs,
searchSongs,
getRandomQuote,
getDailyQuote,
getQuotes,
getRandomSong,
getEra,
getAllEras,
} from 'swiftie-api';
const lover = getAlbum('lover'); // sync
const eras = getAllEras(); // sync
const todaysQuote = getDailyQuote(); // sync (deterministic by UTC date)
const cardigan = getSong('cardigan'); // sync, SongMeta (lyrics omitted)
const loverFull = await getAlbumWithSongs('lover'); // async, one album bundleHosted mode
import { createClient, SwiftieApiError } from 'swiftie-api';
const client = createClient({
baseUrl: 'https://swiftie-api.hrshvrdhn.com',
timeoutMs: 5000,
apiKey: 'optional',
});
try {
const albums = await client.albums.list({ era: 'lover' });
const cardigan = await client.songs.get('cardigan');
const quote = await client.quotes.daily();
console.log(albums.data.length, cardigan.title, quote.text);
} catch (err) {
if (err instanceof SwiftieApiError) {
console.error(err.status, err.url, err.body);
}
}Per-album subpath (tree-shake friendly)
import lover from 'swiftie-api/albums/lover';
console.log(lover.title, lover.songs.length);
console.log(lover.songs[0].title);Only the album you import lands in your bundle.
Full lyric text is not currently redistributed. Lyric-related APIs return results only for songs whose structured lyric sections are available in the dataset.
API reference
Offline
| Function | Signature | Returns | Sync/Async |
| --- | --- | --- | --- |
| getAlbum | (slug: string) | Album | sync |
| getAllAlbums | () | Album[] | sync |
| getAlbumWithSongs | (slug: string) | Promise<AlbumWithSongs> | async |
| getSong | (slug: string) | SongMeta | sync |
| getSongs | (filter?: ListSongsFilter) | SongMeta[] | sync |
| searchSongs | (query: string) | SongMeta[] | sync |
| getRandomSong | () | SongMeta | sync |
| searchLyrics | (query: string, opts?) | Promise<LyricSearchResult[]> | async |
| getRandomQuote | () | Quote | sync |
| getDailyQuote | (date?: Date) | Quote | sync |
| getQuotes | (filter?: ListQuotesFilter) | Quote[] | sync |
| getEra | (slug: string) | Era | sync |
| getAllEras | () | Era[] | sync |
SongMeta is Omit<Song, 'lyrics'>. Sync APIs return SongMeta so the inlined metadata stays small; reach for getAlbumWithSongs(slug) or the per-album subpath when you need the full song object for one album. Current published data does not include a full lyric corpus.
Note: the first call to searchLyrics lazy-imports every per-album bundle to build the search index. If you import searchLyrics in the same module as a single-album subpath, expect all album chunks to land in your bundle.
Hosted client
| Method | HTTP target |
| --- | --- |
| client.albums.list(query?) | GET /api/v1/albums |
| client.albums.get(slug) | GET /api/v1/albums/:slug |
| client.albums.songs(slug) | GET /api/v1/albums/:slug/songs |
| client.songs.list(query?) | GET /api/v1/songs |
| client.songs.get(slug, query?) | GET /api/v1/songs/:slug |
| client.lyrics.search(q, query?) | GET /api/v1/lyrics/search |
| client.lyrics.bySong(songSlug) | GET /api/v1/lyrics/:songSlug |
| client.quotes.list(query?) | GET /api/v1/quotes |
| client.quotes.random() | GET /api/v1/quotes/random |
| client.quotes.daily(query?) | GET /api/v1/quotes/daily |
| client.eras.list() | GET /api/v1/eras |
| client.eras.get(slug) | GET /api/v1/eras/:slug |
All methods are async. Non-2xx responses throw SwiftieApiError with status, url, and parsed body. Network and timeout failures throw SwiftieApiError with status: 0.
Compatibility
- Node: 18+
- Browsers: every evergreen browser that ships
fetch+ dynamicimport() - Bun / Deno: yes
- The offline mode does not import any
node:*modules or make network requests.
Bundle size
The eager metadata bundle holds every album + every song without lyrics + every quote + every era. Per-album song objects are loaded on demand. Lyrics search lazy-imports all per-album chunks on first call, then caches the MiniSearch index.
After publishing, see the bundlephobia page for current numbers.
Data provenance
Album and song metadata is curated by hand and cross-referenced against MusicBrainz and Spotify catalog IDs. See CREDITS.md at the repo root for full attribution.
License
MIT © Harshvardhan Singh.
Swiftie API is a fan-made project. It is not affiliated with, endorsed by, or sponsored by Taylor Swift, her management, her record labels, or any rights-holder.
