Przejdź do treści
fansuby

Referencja API

Adres bazowy: https://fansuby.cc/api/v1. Odpowiedzi to JSON w UTF-8, daty w ISO 8601 (UTC), CORS jest włączony.

  • Wersja v1
  • Tylko odczyt
  • 120 zapytań na minutę

Klucz API

Każde zapytanie (poza openapi.json i /api/health) wymaga klucza w jednym z nagłówków. W przeglądarce, w której jesteś zalogowany, klucz nie jest potrzebny.

Nagłówki
Authorization: Bearer fsb_…
# albo
X-Api-Key: fsb_…

Do pięciu kluczy na konto, zarządzasz nimi w ustawieniach konta. Klucz działa jak hasło tylko do odczytu: nie wrzucaj go do repozytorium ani do kodu, który zobaczą inni.

Limity

Zapytania API
120 na minutę na konto, wspólnie dla wszystkich kluczy. Stan limitu podają nagłówki X-RateLimit-Limit, X-RateLimit-Remaining i X-RateLimit-Reset (koniec okna, Unix w sekundach).
Pobieranie plików
Bez dziennego limitu, z przerwą przeciw masowemu ściąganiu: 30 plików na minutę, dla zaufanych tłumaczy 60.
Po przekroczeniu
Dostajesz 429 i nagłówek Retry-After z liczbą sekund do odczekania.
Pamięć podręczna
Odpowiedzi z kluczem mają Cache-Control: private. Wyniki zmieniają się rzadko, więc zapisuj je u siebie na kilka minut.

Paginacja

Listy zwracają data i pagination. Kolejne strony pobierasz parametrami page i limit (maksymalnie 100).

Kształt listy
{
  "data": [ … ],
  "pagination": { "page": 1, "limit": 20, "total": 143, "totalPages": 8 }
}

Błędy

Każdy błąd ma ten sam kształt, a komunikat jest po polsku. Kod w polu code nadaje się do obsługi w programie.

Odpowiedź z błędem
{ "error": { "code": "unauthorized", "message": "API wymaga konta. …" } }
400 invalid_parameter
Zły parametr. Pole details wskazuje który i dlaczego.
401 unauthorized
Brak klucza, klucz błędny albo usunięty. Konto zbanowane też dostaje 401.
404 not_found
Nie ma takiej serii, napisów lub wersji, albo napisy są ukryte.
429 rate_limited
Za dużo zapytań. Poczekaj tyle, ile mówi Retry-After.
500 internal_error
Błąd po naszej stronie. Spróbuj ponownie za chwilę.
503 search_unavailable
Wyszukiwarka chwilowo nie działa. Dotyczy tylko /series z frazą q.

Endpointy

Wszystkie to GET. Każdy ma przykład do skopiowania, który zakłada klucz w zmiennej FANSUBY_KEY.

GET/api/v1/match

Jedno wywołanie zamiast szukania serii, listy napisów i wyboru. Z nazwy pliku odczytuje serię, odcinek, grupę i rozdzielczość, a napisy zwraca od najlepiej pasujących. Pierwszy element data to najlepszy wybór, a score pokazuje punktację.

Parametry

filenametekstwymagany
Nazwa pliku wideo, np. [SubsPlease] Frieren - 05 (1080p).mkv.
anilistId, malId, seriesIdliczba
Wskazują serię wprost, bez szukania po tytule. Wystarczy jeden.
episodeliczba
Nadpisuje numer odcinka odczytany z nazwy.
durationms
Długość wideo w milisekundach. Poprawia dobór napisów.
formatass | srt
Preferowany format przy remisie (domyślnie ass).
langtekst
Kod języka.

Przykład

Terminal
curl -G -H "Authorization: Bearer $FANSUBY_KEY" \
  --data-urlencode "filename=Frieren - 05.mkv" \
  https://fansuby.cc/api/v1/match

Zwraca: Obiekt z match (seria, odcinek, odczytane pola) i data (napisy z polem score). Pusta data oznacza, że serii nie brakuje, ale nie ma jeszcze napisów do odcinka. 404, gdy nie znaleziono serii.

GET/api/v1/match/download

Te same parametry co /match. Zamiast JSON-a przekierowuje (302) do pliku najlepszych napisów.

Przykład

Terminal
curl -L -OJ -G -H "Authorization: Bearer $FANSUBY_KEY" \
  --data-urlencode "filename=Frieren - 05.mkv" \
  https://fansuby.cc/api/v1/match/download

Zwraca: 302 z nagłówkiem Location albo 404, gdy nic nie pasuje.

GET/api/v1/series

Szuka po tytułach (romaji, angielskim, japońskim i synonimach). Bez q zwraca najpopularniejsze serie.

Parametry

qtekst
Fraza wyszukiwania, do 200 znaków.
adult1 | 0
1 dodaje serie dla dorosłych, domyślnie są ukryte.
pageliczba
Numer strony, od 1.
limitliczba
Wyników na stronę, od 1 do 100 (domyślnie 20).

Przykład

Terminal
curl -H "Authorization: Bearer $FANSUBY_KEY" "https://fansuby.cc/api/v1/series?q=frieren"

Zwraca: Lista data z podsumowaniami serii i obiekt pagination. 503, gdy wyszukiwarka chwilowo nie działa.

GET/api/v1/series/{id}

Pełne dane serii: opisy, gatunki, studia, następny odcinek, powiązane serie i linki.

Parametry

idtekstwymagany
Nasz identyfikator, anilist:154587 albo mal:52991.

Przykład

Terminal
curl -H "Authorization: Bearer $FANSUBY_KEY" https://fansuby.cc/api/v1/series/anilist:154587

Zwraca: Obiekt data z polami serii opisanymi niżej.

GET/api/v1/series/{id}/episodes

Odcinki z liczbą dostępnych napisów. Domyślnie 100 na stronę.

Parametry

idtekstwymagany
Nasz identyfikator, anilist:154587 albo mal:52991.
pageliczba
Numer strony, od 1.
limitliczba
Wyników na stronę, od 1 do 100 (domyślnie 20).

Przykład

Terminal
curl -H "Authorization: Bearer $FANSUBY_KEY" https://fansuby.cc/api/v1/series/mal:52991/episodes

Zwraca: Lista data z odcinkami i pagination.

GET/api/v1/subtitles

Opublikowane napisy (bieżące wersje) z filtrami. Najczęściej: wszystkie napisy do jednego odcinka. Bez filtra serii zwraca najnowsze.

Parametry

anilistId, malId, seriesIdliczba
Seria. Wystarczy jeden.
episodeliczba
Numer odcinka, np. 5 albo 12.5.
langtekst
Kod języka (obecnie pl).
formatass | srt
Format pliku.
resolutiontekst
480p, 576p, 720p, 1080p lub 2160p.
sourcetekst
WEB-DL, WEBRip, BD, BDRip, TV, DVD lub OTHER.
grouptekst
Grupa wydania (np. SubsPlease, bez względu na wielkość liter) albo slug grupy tłumaczy.
sinceISO 8601
Tylko napisy dodane lub zmienione od tej chwili, od najnowszych. Do synchronizacji bez pobierania wszystkiego.
adult1 | 0
Bez filtra serii: uwzględnia serie dla dorosłych.
pageliczba
Numer strony, od 1.
limitliczba
Wyników na stronę, od 1 do 100 (domyślnie 20).

Przykład

Terminal
curl -H "Authorization: Bearer $FANSUBY_KEY" \
  "https://fansuby.cc/api/v1/subtitles?anilistId=154587&episode=1&resolution=1080p"

Zwraca: Lista data z napisami i pagination.

GET/api/v1/subtitles/{id}

Wydanie, ekipa, sumy kontrolne i historia wersji z listą zmian (pole versions).

Parametry

idliczbawymagany
Identyfikator napisów.

Przykład

Terminal
curl -H "Authorization: Bearer $FANSUBY_KEY" https://fansuby.cc/api/v1/subtitles/42

Zwraca: Obiekt data z polami napisów i versions.

GET/api/v1/subtitles/{id}/download

Przekierowuje (302) do pliku. Domyślnie bieżąca wersja.

Parametry

idliczbawymagany
Identyfikator napisów.
vliczba
Numer wersji, jeśli chcesz starszą.

Przykład

Terminal
curl -L -OJ -H "Authorization: Bearer $FANSUBY_KEY" https://fansuby.cc/api/v1/subtitles/42/download

Zwraca: 302 z nagłówkiem Location albo 404, gdy nie ma napisów lub wersji.

Pola odpowiedzi

Wszystkie adresy są bezwzględne i prowadzą do fansuby.cc. Pola, których nie ma w danych, mają wartość null.

Seria

id, anilistId, malId, slug
Identyfikatory. malId bywa null.
title
Obiekt z romaji, english i native.
format, status, season, seasonYear
Wartości z AniList, np. TV, RELEASING, FALL, 2026.
episodesTotal
Zapowiedziana liczba odcinków, jeśli jest znana.
coverImage, coverImageMedium
Okładki w WebP (460×650 i 230×325). Hostujemy je sami, np. https://fansuby.cc/media/series/8/cover-3fa9….webp. Nazwa pliku zawiera skrót zawartości, więc adres się nie zmienia, dopóki obraz jest ten sam.
bannerImage
Baner w WebP (1800×450), jeśli seria go ma.
coverColor
Dominujący kolor okładki jako #rrggbb. Przydaje się do tła albo akcentu.
subtitleCount
Liczba opublikowanych napisów.
isAdult, url
Oznaczenie 18+ i adres strony serii.

Szczegóły serii (/series/{id}) dodają:

description
Oryginalny opis po angielsku, z AniList.
descriptionPl
Automatyczne tłumaczenie opisu na polski. Null, gdy go jeszcze nie ma albo opis się zmienił i czeka na nowe.
synonyms, genres, studios
Listy tekstów.
startDate, endDate, episodeDurationMin
Daty (YYYY-MM-DD) i długość odcinka w minutach.
episodeCount
Liczba odcinków w naszym katalogu.
averageScore, popularity
Ocena 0 do 100 i popularność z AniList.
nextAiringEpisode
Numer i czas (airingAt) najbliższego odcinka albo null.
relations
Powiązane serie: relationType, tytuł, seriesId i url, gdy jest w naszym katalogu.
links
Adresy anilist, mal i rss (kanał napisów serii).

Odcinek

id, number
Numer jest liczbą, więc zmieści też 12.5.
title
Obiekt z english, romaji i japanese.
airedAt
Data emisji albo null.
isFiller, isRecap
Oznaczenia odcinków specjalnych.
subtitleCount, url
Liczba napisów i adres strony odcinka.

Napisy

id, url, downloadUrl
Identyfikator, strona dla ludzi i bezpośredni adres pliku bieżącej wersji.
language, format
Język (pl) oraz ass albo srt.
releaseGroup, releaseSource, resolution
Do jakiego wydania wideo pasują, np. SubsPlease, WEB-DL, 1080p.
releaseFilename, alsoCompatible
Nazwa pliku wideo i inne wydania z pasującym timingiem.
videoDurationMs
Długość wideo, do którego zrobiono napisy.
version, sha256, sizeBytes
Numer bieżącej wersji, suma kontrolna i rozmiar pliku.
hasTypesetting, hasKaraoke, fonts
Czy plik ma typesetting i karaoke oraz jakich czcionek używa.
credits
Ekipa: role (translation, proofreading, typesetting, timing, editing, karaoke), nazwa i username.
group, uploader
Grupa tłumaczy i osoba, która wgrała napisy. Mogą być null.
series, episode
Skrót serii i odcinka, do którego należą.
downloadCount, notes
Liczba pobrań i uwagi tłumacza.
createdAt, updatedAt, versionCreatedAt
Daty dodania, zmiany i wydania bieżącej wersji.

/subtitles/{id} dodaje versions: numer, listę zmian, sumę kontrolną, rozmiar, liczbę linii i adres pobrania każdej wersji.

Kanały RSS i stan serwisu

Do śledzenia nowości nie odpytuj API w pętli. Kanały RSS nie wymagają klucza:

/rss
Najnowsze napisy z całego serwisu.
/seria/{slug}/rss
Napisy do jednej serii. Adres jest też w polu links.rss.
/grupa/{slug}/rss
Napisy jednej grupy tłumaczy.
/tlumacz/{username}/rss
Napisy jednego tłumacza. Działa też pod /uzytkownik/{username}/rss.
/api/health
Stan serwisu dla monitoringu: 200, gdy baza, wyszukiwarka i magazyn plików działają, inaczej 503. Bez klucza.

Specyfikacja OpenAPI

Pełny opis w formacie OpenAPI 3.1 jest pod /api/v1/openapi.json i działa bez klucza. Wczytasz go do Postmana albo generatora klientów dla swojego języka.

Dobre praktyki

  • Szukaj serii po AniList lub MAL ID, nie po tytule. Tytuły się różnią, ID nie.
  • Do jednego pliku wideo użyj /match. Zastępuje trzy osobne zapytania.
  • Do synchronizacji używaj parametru since zamiast pobierania całej listy za każdym razem.
  • Zapisuj odpowiedzi na kilka minut. Lista napisów do odcinka zmienia się rzadko.
  • Po 429 czekaj tyle, ile mówi Retry-After, zamiast ponawiać od razu.
  • Pokazuj autorów (pole credits) i link do strony napisów. To ich praca.
↑↓ wybórEnter otwórz