Anime, series, films and music in one place: a site and a desktop app with watch parties, offline downloads and a Rust server.
翻译准备中
正在加载完整 README。
查看完整 README ↗Anime, series and films from one API, served as one site and one desktop app.
| Hostname | What it serves | Container |
|---|---|---|
akidev.live | The site: Home, Anime, Series and Films | frontend |
anime.akidev.live | Retired: redirects to akidev.live/anime | frontend |
tv.akidev.live | Retired: redirects to akidev.live/films | frontend |
api.akidev.live | The REST API and the video | api |
| Directory | What it is | Port |
|---|---|---|
desktop/server/ | The API: a Rust binary, akidev-server. Catalogue from AniList, Cinemeta and TVMaze, releases from torrent indexers, video from a debrid CDN, a torrent swarm or the Internet Archive, converted for the browser only as far as it has to be. See desktop/server/API.md. | 9000 |
desktop/core/ | The library the server and the desktop app share: providers, indexers, ranking, the torrent engine. | |
akidev-frontend/ | Next.js app (App Router, TypeScript). One build, one container, every hostname. | 3000 |
desktop/app/ | The native macOS app, with the same backend built in. See desktop/README.md. |
The server and the desktop app are built on one library, so there is one copy of every indexer, provider and ranking rule. A fix to how a release is found or ranked lands in both. This replaced a Node API that duplicated all of it.
The frontend's UI began as a derivative of Kitsune (MIT) and has since been redesigned to match the desktop app; see ATTRIBUTION.md.
There is one frontend image and one frontend container, and one site: Home, Anime,
Series and Films tabs over the same catalogue the desktop app shows, with the same design
(akidev-frontend/src/constants/site.ts holds the catalogues, sorts and genres).
anime.akidev.live and tv.akidev.live are retired. The middleware
(akidev-frontend/src/middleware.ts) redirects them with a 308 to /anime and /films on
the bare zone, and keeps the path for anything deeper, so old title and watch links work.
They still have to reach the container, so their DNS records stay and Caddy serves them.
Every media id is self-describing, which is what lets one API and one set of routes serve three catalogues:
anime-16498-ep1 an anime, episode 1
series-169-s1e5 a series, season 1 episode 5
movie-tt27548557 a film, no episode
series-169 a title, for a detail page
The type is part of the id because the ids come from different providers and would otherwise collide - TVMaze's show 1 and YTS's film 1 are different titles. It also means the watch page knows what it is looking at from the URL alone.
The provider's own id is alphanumeric rather than digits-only because providers do not
agree on a form: AniList and TVMaze use numbers, Cinemeta uses IMDb ids
(tt27548557). desktop/core/src/media_id.rs and akidev-frontend/src/lib/media-id.ts
must agree.
Both are data, not code: signed JSON definitions that the engine in desktop/core follows, so a
change to what is asked of an upstream does not need a release. They are in desktop/sources/;
see desktop/sources/README.md for the format and for how they are
signed and published. The server and the app both load the signed copy from
https://sources.akidev.live and keep the last good one on disk.
A stream source is different: it is code, because where the bytes come from is a different
mechanism each time (desktop/server/src/sources/ for debrid and the Internet Archive, and the
torrent engine in desktop/core). STREAM_SOURCES lists them in order of preference: debrid
serves from a CDN cache, torrent joins a swarm and relays, archive-org returns a direct HTTPS
URL. A source that is not usable - debrid without an API key - is skipped rather than failing
the request, and GET /health reports what is configured.
Two rules worth knowing, because both were bugs and both are easy to reintroduce.
A "newest" row means released, not announced. AniList reports a null date for a
title that has not come out and sorts it first under its date sort, and Cinemeta's
date-ordered catalogue leads with announcements. Each provider's definition therefore bounds its
own date sort: AniList excludes unreleased and undated titles, and Cinemeta drops a title
whose exact release date is in the future. A provider that cannot do this has no
recent sort offered for it, rather than a sort that quietly returns the wrong thing.
Cinemeta's date catalogue is also not contiguously ordered upstream - measured, its first page mixes 2020, 2025 and 2026 and its second repeats rows from its first - so that row is read as a window and sorted and paged here. Paging it upstream produced six duplicate rows across two pages.
A search spans every catalogue. A title is addressed by a provider-specific id, so
GET /v1/search asks anime, series and films and interleaves the answers (akidev_core::search).
Searching one catalogue would silently hide a third of the site: "Breaking Bad" is a series and
"Dangal" is a film. Results whose title starts with the term are moved ahead of fuzzy matches,
because TVMaze's own search returned "D.N.Angel" above "Dangal".
POST /v1/play finds a source and answers with a URL. Between the file and the URL, the server
reads the file's header (ffprobe, through the same reader the player will use, since a torrent's
file on disk is sparse until its pieces arrive) and takes the lightest delivery that works, in
this order (desktop/server/src/media.rs):
以上为 README 的开头部分。其余内容请阅读原文。 查看完整 README ↗