Skip to content

feat(track): add manga relations & recommendations query (AniList, MyAnimeList) - #2132

Open
VictorVow wants to merge 3 commits into
Suwayomi:masterfrom
VictorVow:feat/related
Open

feat(track): add manga relations & recommendations query (AniList, MyAnimeList)#2132
VictorVow wants to merge 3 commits into
Suwayomi:masterfrom
VictorVow:feat/related

Conversation

@VictorVow

@VictorVow VictorVow commented Jun 22, 2026

Copy link
Copy Markdown

What this does

Adds a GraphQL mangaRelated query that returns relations and recommendations for a manga from AniList and MyAnimeList, so clients can show a "Related" view per manga.

mangaRelated(input: { mangaId: 42 }) {
  anilistRelations { remoteId title coverUrl trackingUrl relationType }
  anilistRecommendations { ... }
  myanimelistRelations { ... }
  myanimelistRecommendations { ... }
}

How the remote media id is resolved

For each tracker, per manga:

  1. Existing track binding — if the manga is already tracked on that site, the bound remote id is used (authoritative, user-confirmed).
  2. Title-search fallback — otherwise, if logged in, the manga title is searched on the tracker and the first result that is a confident title match is used. A loose/wrong top hit is never used.

A confident match is normalized equality, or Levenshtein similarity ≥ 0.9, compared against the candidate's primary and alternative titles (AniList romaji/english/native + synonyms, MAL en/ja + synonyms). This lets a localized source title match an entry whose primary title is in another language (e.g. an "Attack on Titan" source matching the romaji "Shingeki no Kyojin").

Per-tracker failures (not logged in, no match, network error) yield an empty list for that tracker instead of failing the whole query.

Implementation notes

  • AniList relations/recommendations are fetched over the public (unauthenticated) GraphQL endpoint and filtered to type: MANGA (drops anime adaptations).
  • MyAnimeList uses the related_manga and recommendations fields of the manga details endpoint.
  • Alternative titles ride on the in-memory TrackSearch model only — not persisted to the DB and not exposed in the tracking GraphQL types.

Testing

  • Builds, ktlintCheck clean.
  • Verified the query end-to-end against a running server (empty path + live data).
  • Verified the AniList and MyAnimeList request/response shapes against the live APIs.

Companion PR

The WebUI side (the "Related" button + modal) is Suwayomi/Suwayomi-WebUI#1122 and depends on this query being available.

Add a mangaRelated GraphQL query that returns relations and
recommendations for a manga from AniList and MyAnimeList.

The remote media id is resolved from an existing track record, falling
back to a title search on the logged-in tracker. AniList relations and
recommendations are fetched via the public (unauthenticated) GraphQL
endpoint and filtered to manga; MyAnimeList uses the related_manga and
recommendations fields of the manga details endpoint. Per-tracker
failures yield an empty list instead of failing the whole query.
When a manga has no tracker binding, the related/recommendation lookup
falls back to searching the tracker by title. Previously it used the top
search hit unconditionally, which could surface relations for an
unrelated entry when no good match existed.

Only use a search result whose title is a confident match for the manga
title (normalized equality or Levenshtein similarity >= 0.9), otherwise
return no results for that tracker.
Compare the manga title against each search result's alternative titles
(AniList romaji/english/native + synonyms, MyAnimeList en/ja + synonyms)
in addition to its primary title when resolving the related-search
fallback.

This lets a localized source title confidently match an entry whose
primary title is in another language (e.g. an "Attack on Titan" source
matching AniList/MAL's romaji "Shingeki no Kyojin"), which the previous
single-title comparison rejected.

The alternative titles are carried on the (non-persisted) TrackSearch
model and populated by the AniList and MyAnimeList search calls.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant