Skip to content

Library quickstart

@courmap/client answers three questions: which work is this ID, what is this episode in every other numbering, and which work and episode is this release name. It runs locally and gives the same answers in both of its modes. The remote client needs nothing but a network connection, so start there.

Terminal window
npm install @courmap/client

With pnpm, pnpm add @courmap/client may print “Ignored build scripts: better-sqlite3”. It is harmless: better-sqlite3 ships prebuilt binaries, so nothing needs building. To silence it, list better-sqlite3 under ignoredBuiltDependencies in pnpm-workspace.yaml (or under pnpm.ignoredBuiltDependencies in package.json).

import { createRemoteClient } from '@courmap/client';
const courmap = createRemoteClient(); // https://data.courmap.com/v1/ by default
// Episode 12 of AniList 154587, in TVDB's numbering.
const t = await courmap.translate('anilist:154587', 12, ['tvdb_show']);
console.log(t.work.id, t.results.tvdb_show); // sousou-no-frieren { id: '424536', season: 1, episode: 12 }
// A release name to a work and episode.
const r = await courmap.resolve('[SubsPlease] Spy x Family - 17 (1080p)');
console.log(r.status, r.match?.work, r.match?.episode); // ok spy-x-family-part-2 5

status is ok only when Courmap is sure. A name that could be several works comes back ambiguous, with match empty and every candidate and its score in candidates; a name that matches nothing comes back unmatched with no candidates. Neither throws, so check status before using match. The library guide has the shapes.

The remote client fetches only the small files a call needs and caches them by data version. In a browser, import from @courmap/client/remote, which has no Node-only code.

Offline mode reads the weekly SQLite dump, so no call touches the network. Use it for PVRs and any tool that resolves many names. Download and unpack the dump of the latest data release. Its file name carries the version, so ask meta.json for the address (this uses curl and jq):

Terminal window
url=$(curl -sL https://github.com/courmap/courmap/releases/latest/download/meta.json | jq -r .dumps.sqlite.url)
curl -sL "$url" | gunzip > courmap.sqlite

Library: remote vs offline shows how to check the download against SHA256SUMS. Then open it:

import { createOfflineClient } from '@courmap/client';
const courmap = createOfflineClient('courmap.sqlite'); // the file you unpacked
// Which work is AniList 142838?
const work = await courmap.lookup('anilist:142838');
console.log(work.id, work.titles.romaji); // spy-x-family-part-2 Spy x Family Part 2
// Episode 5 of it, in other numberings.
const t = await courmap.translate('anilist:142838', 5, ['anidb', 'tvdb_show', 'absolute']);
console.log(t.results.tvdb_show); // { id: '405920', season: 1, episode: 17 }
console.log(t.results.absolute); // { sequence: 'spy-x-family-absolute', episode: 17 }
courmap.close();

The third argument of translate is a list of these names (the Target type):

Target You get
anidb, anilist, mal, kitsu The provider’s ID and the episode number in its own numbering.
tvdb_show, tmdb_show The show’s ID, a season and an episode.
tmdb_movie, imdb The ID only; these have no episode numbering.
absolute The absolute sequence’s id and the episode in it, as fansubs number it.

A target the work has no mapping for comes back under unmapped, not as an error. The library guide lists every call and error, and the API reference has the full types.

This product uses the TMDB API but is not endorsed or certified by TMDB.