Courmap-Proxy

Courmap-Proxy

Docker app from Courmap's Repository

Overview

Courmap Proxy sits between your indexers (usually through Prowlarr) and Sonarr. It recognizes anime release names and rewrites the ones it is sure about, so Sonarr imports each release as the right episode. Releases it is unsure about pass through unchanged. Setup guide: https://courmap.com/getting-started/sonarr/

Courmap: anime episode numbering, mapped across every provider.

CI data coverage resolver corpus

Courmap translates an anime episode between AniDB, AniList, MAL, Kitsu, TVDB, TMDB, IMDb and absolute (fansub) numbering, and resolves release names to the right show and episode, as open data and a library with no server to run.

The same release, counted every way:

Source Episode
Fansub release [SubsPlease] Spy x Family - 17 (1080p) 17
AniDB, AniList, MAL, Kitsu Part 2, episode 5
TVDB, TMDB S01E17

Fansub groups count straight through the show. AniDB, AniList, MAL and Kitsu split it into two cours (about 12 episodes each) that restart at 1, and TVDB and TMDB keep one season. Try it in your browser.

Pick your path

Sonarr and self-hosted users

The Courmap proxy sits between Prowlarr and Sonarr and rewrites anime releases into the numbering Sonarr understands; anything it is unsure about passes through untouched.

services:
  courmap-proxy:
    image: ghcr.io/courmap/proxy:latest
    ports:
      - "9797:9797"
    volumes:
      - ./courmap/data:/data
    environment:
      SONARR_URL: http://sonarr:8989
      SONARR_API_KEY: your-sonarr-api-key
      INDEXER_NYAA_URL: http://prowlarr:9696/1/api

Finish setup with step 3 of the quickstart, or Prowlarr's copies of your indexers will duplicate anime results.

INDEXER_NYAA_URL makes the proxy serve that Prowlarr feed at /nyaa (the 1 is the indexer's ID in Prowlarr). Then add http://courmap-proxy:9797/nyaa to Sonarr as a Torznab indexer (Newznab for usenet) with your Prowlarr API key. Sonarr quickstart; Unraid, VPN containers, usenet limits and troubleshooting are in the full guide.

Developers

import { createRemoteClient } from '@courmap/client';

const courmap = createRemoteClient(); // fetches small static files on demand, nothing to download
const t = await courmap.translate('anilist:142838', 5, ['tvdb_show', 'absolute']);
console.log(t.results.tvdb_show); // { id: '405920', season: 1, episode: 17 }
const r = await courmap.resolve('[SubsPlease] Sousou no Frieren - 12 (1080p)');
console.log(r.status, r.match?.work, r.match?.episode); // ok sousou-no-frieren 12

Works in Node, browsers and Workers, and fully offline over the weekly SQLite dump. Library quickstart. No code? Ask the HTTP API: curl "https://api.courmap.com/v1/translate?from=anilist:142838&episode=5&to=tvdb_show" (more).

Contributors

Fix a wrong mapping once, for everyone: add a short YAML file that overrides only what is wrong.

# data/works/kusuriya-no-hitorigoto-2nd-season.yaml
id: kusuriya-no-hitorigoto-2nd-season
projections:
  tmdb_show:
    - { season: 1, episodes: 1-24, start: 25 }
pnpm install
pnpm validate

Fix a mapping, and the full contributing guide.

How it works

Every provider maps to one canonical work (usually one cour, film or OVA), never to each other, so any translation is two hops. About 33,000 works are seeded weekly from anime-offline-database (IDs, titles, synonyms) and Anime-Lists (TVDB and TMDB offsets); hand-written YAML files in data/ correct and extend them. CI checks every mapping (every episode must translate to every provider and back) and compiles it all into a SQLite dump and static JSON files. Bots watch each anime season and open pull requests and issues; a person only reviews where sources disagree.

Courmap never guesses silently: an unsure answer is ambiguous, with its candidates. How it differs from TheXEM, Anime-Lists and anime-offline-database is in the FAQ.

Documentation: courmap.com. Design: docs/SPEC.md.

License and attribution

Code: Apache-2.0 (LICENSE). Data in data/ and every dump: ODbL 1.0 + DbCL 1.0 (DATA_LICENSE). Courmap builds on anime-offline-database (cedya77, continuing manami-project) and Anime-Lists; see ATTRIBUTION.md. Courmap never calls the AniDB API and never redistributes AniDB titles.

Related apps

Explore more like this

Explore all

Details

Repository
ghcr.io/courmap/proxy:latest
Last Updated2026-11-04
First Seen2026-11-04

Runtime arguments

Web UI
http://[IP]:[PORT:9797]/
Network
bridge
Privileged
false
Extra Params
--user 99:100

Template configuration

Status page portPorttcp

The proxy's status page, and the address Sonarr uses to reach each indexer (for example http://courmap-proxy:9797/tracker).

Target
9797
Default
9797
Value
9797
DataPathrw

Downloaded Courmap data and the unresolved release log. If the status page says the data folder is not writable, run chown -R 99:100 /mnt/user/appdata/courmap-proxy in the Unraid terminal.

Target
/data
Default
/mnt/user/appdata/courmap-proxy/data
Value
/mnt/user/appdata/courmap-proxy/data
ConfigPathrw

Optional courmap-proxy.yaml with the same settings as the variables below. Environment variables win over it.

Target
/config
Default
/mnt/user/appdata/courmap-proxy/config
Value
/mnt/user/appdata/courmap-proxy/config
Sonarr URLVariable

Address of your Sonarr. Without it and the API key, every release passes through unchanged. Use the host's IP address if the containers are not on one network.

Target
SONARR_URL
Default
http://sonarr:8989
Value
http://sonarr:8989
Sonarr API keyVariable

Your Sonarr API key (Sonarr, Settings, General). The proxy uses it to read your series list.

Target
SONARR_API_KEY
Indexer URLVariable

One upstream Torznab or Newznab feed, usually a Prowlarr indexer such as http://prowlarr:9696/1/api (the number is the indexer's ID in Prowlarr). The name between INDEXER_ and _URL is a label you choose: TRACKER is served at /tracker, lowercase, with underscores turned into hyphens. Add more indexers as extra variables, for example INDEXER_NYAA_URL.

Target
INDEXER_TRACKER_URL
Indexer typeVariable

Leave blank for torrents. Set to newznab for a usenet indexer. When blank, the proxy detects the type from the feed's first results. Change TRACKER to match the label of the indexer above.

Target
INDEXER_TRACKER_TYPE
Sonarr refresh minutesVariable

How often the Sonarr series list is reloaded.

Target
SONARR_REFRESH_MINUTES
Default
60
Value
60
Data refresh hoursVariable

How often the Courmap data release is checked. A new dump is downloaded only when the data version changes.

Target
REFRESH_HOURS
Default
24
Value
24
Upstream cache secondsVariable

Identical queries to an indexer within this time share one request. 0 turns the cache off.

Target
UPSTREAM_CACHE_SECONDS
Default
60
Value
60