MyGo 云音乐
用 Go 与 MyGo 写成的第三方网易云音乐桌面客户端。原生界面,没有 WebView;边下边播,无损与 Hi-Res,逐字歌词与「律动」,刘海播放器。
Translation pending
An index of actual play TTRPG credits, by person. Every show, every season, every guest spot — including the indie long tail.
Translation pending
MediaTypeScript · AstroGitHub @jazzsequenceOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Verify in one minuteAsk about other verification options
Actual Play Database - A community-sourced IMDB for actual plays
Translation pending
Taken from the repository README
Loading the full README. The saved excerpt is shown below.
An index of actual-play TTRPG credits organised by person.
Existing AP discovery tools index by show, game and channel. None index by
performer. This one does, and it is built around the two things that omission
breaks:Read the full README ↗An index of actual-play TTRPG credits organised by person.
Existing AP discovery tools index by show, game and channel. None index by performer. This one does, and it is built around the two things that omission breaks:
There is no database, no CMS and no auth backend. The data is flat YAML in git.
data/people/<slug>.yml, data/shows/<slug>.yml,
and so on. Never a monolith: sharded files keep PRs atomic and diffs readable.Pages are statically generated, one real route per person and per show, because the discovery premise dies without individually indexable pages.
Flat files give you no referential integrity for free — a typo'd show id is a
broken link that nothing catches. npm run validate is the replacement for
every constraint a database would have enforced, and it runs on every PR:
show / season / channel / game /
alias id referenced by a credit resolves to something that exists.npm run build runs the validator first and refuses to render a site from
invalid data, so a broken reference can never reach the published pages.
npm install
npm run validate # the CI gate
npm run dev # local site
npm run build # validate, build, index for search
npm run filmography -- "Aabria Lipscomb" # print a filmography to the terminal
npm run audit # spot-check imports for bad data
npm run discover:person -- --person aabria-iyengar # what are we missing for one person?
npm run report:discovery -- --person out/sweep.json # fold a sweep into one report
npm run collect -- --sources # import sources + licence status
| Entity | Lives in | Notes |
|---|---|---|
| Person | data/people/ | Canonical identity. Holds its aliases and credits inline. |
| Alias | inside Person | name, alias_type, optional active range. The alias-gap fix. |
| Credit | inside Person | The polymorphic join. References a show, optionally a season and a free-text episode locator. |
| Show | data/shows/ | Series under one or more channels. Holds its seasons. |
| Season | inside Show | ordinal, game reference, date range. |
| Channel | data/channels/ | Producing entity: network, indie studio or solo creator — all first class. |
| Game | data/games/ | edition is required; PF2e vs PF1e is a real discovery filter. |
Episodes are not entities. A credit references an episode by a free-text
locator ("S2E14") plus the show and season ids. This is what lets a single
indie guest appearance surface on a performer's page without anyone having to
catalogue an entire show episode by episode.
Main-cast credits reference the season. One-off guest credits additionally carry an episode locator — that distinction is the long-tail feature.
Every credit carries a source declaring its tier, ranked by how close the
source was to the thing happening: official → recording → participant →
firsthand → reference → community. The tier renders next to the credit,
and CI enforces the tiers that make claims about their own evidence:
recording must carry a locator, firsthand must name who attested it.
There is deliberately no inferred tier, and no inference status anywhere.
Nobody files a credit without having observed something — streams are watched —
so inference never explains how a credit came to exist. And if a value was
derived from sources, those sources are the account, so cite them; if it was
derived from nothing, it isn't knowledge and shouldn't be a value. Fields nobody
established are simply omitted: alias is optional, and such credits render as
"billed name not established" rather than carrying a guess.
Note that firsthand — someone who watched the episode — outranks published
reference works. It is closer to the fact. Wikipedia's filmography table lists
Aabria Iyengar as a player on Pirates of Salt Bay when she ran it; anyone who
watched would have got that right.
Corroboration is derived, never asserted. Each credit carries a list of
sources and its status falls out of them: corroborated when two or more
independent sources agree, single-source otherwise. Independence is checked by
who attested a source or which page it cites, so one person filing twice does
not count.
That list is what makes community verification work. A second listener who watched the same stream and files their own account moves a credit from single-source to corroborated — with no publisher involved anywhere.
The sourcing model is adapted from Wikipedia's, with one deliberate divergence: unpublished first-hand accounts are admissible here. Wikipedia's No Original Research rule assumes published sources reliably exist, which is false for the indie long tail — applying it would delete exactly the data no other index has. Testimony is admitted, labelled and ranked, never disguised as something stronger. The full reasoning is in POLICY.md.
Git history covers the rest.
The site is built to be fetched, not just crawled — an agent or script shouldn't need to parse rendered HTML to get the underlying facts.
data/./api/people.json, /api/shows.json, /api/channels.json,
/api/games.json are the full collections, same shape as the YAML,
generated straight from the validated dataset./people/{id}.json and /shows/{id}.json mirror each HTML page —
fetch one record without downloading the whole collection.reference or community
source, never firsthand, no matter how confident the page sounded.robots.txt that explicitly welcomes AI crawlers
(GPTBot, ClaudeBot, PerplexityBot, CCBot and others by name, not just a
wildcard) round it out — the data is meant to be found, cited and
corrected, not walled off from the tools that would do that at scale.npm run collect has two modes.
Fan wikis (--wiki) are where the credits actually are. Fandom and Miraheze
expose a real MediaWiki API with template-structured infoboxes, so this reads
data rather than scraping prose:
npm run collect -- --wiki dimension20.fandom.com --page "Fantasy High" --show dimension-20 --season 1
npm run collect -- --wiki criticalrole.fandom.com --page "Campaign 1" --show critical-role --season 1
Crucially, these wikis mark guest players as their own infobox field, so
one-off guest spots arrive already distinguished from main cast — the long
tail, machine-readable. Field names differ per wiki (players/guest_players
on Dimension 20, starring/sguests on Critical Role), so the field→role
mapping is data in src/lib/sources/mediawiki.ts; add a row for a new wiki.
Cast fields interleave performers and characters, and every wiki formats that
differently — so the parser doesn't read formatting at all. It resolves each
linked page against the wiki's own categories (Cast / Voice Actors vs
Characters vs Companies) in one batched API call, then walks the links in
order: a person opens an entry, a character attaches to the entry before it, an
organisation is dropped.
That one rule handles every layout encountered without knowing anything about any of them, and it is what stops a character being filed as a performer or a production company being filed as a person.
Show discovery (--discover) builds the show catalogue. A wiki already
knows which of its pages are campaigns, so ask it — this enumerates pages
transcluding the campaign infobox, no page names typed by hand:
npm run collect -- --wiki dimension20.fandom.com --discover --dry-run
npm run collect -- --wiki dimension20.fandom.com --discover --channel dropout
That finds 30 campaigns on the Dimension 20 wiki and 61 on the Critical Role
wiki. Staged shows carry deliberately invalid placeholder ids for channel and
game, so CI blocks a merge until a curator sets real ones — mapping a system
string onto a game id needs a judgement about edition, which is required here.
YouTube (--youtube) reads a production's own video descriptions, which
for shows with no fan wiki is often the only place a cast is written down — and
is a better source than a wiki, because it's the producer describing their own
episode. Credits from here are official tier.
export YOUTUBE_API_KEY=... # free: console.cloud.google.com, YouTube Data API v3
npm run collect -- --youtube --playlist <PLAYLIST_ID> --show <show-id> --season 1 --dry-run
It reads only lines that name a role (DM:, Starring, Cast:, Produced by)
and understands both X as Y and X (Y). A description with no cast line yields
nothing rather than a guess. Episode credits roll up to the season — an index of
who was in a show doesn't need a row per episode.
There is no keyless fallback: YouTube blocks unauthenticated access, and scraping around that would breach their terms.
Podcasts (src/lib/sources/podcast.ts) — Apple's lookup/search endpoints
are public and keyless, and hand back the show's real RSS feed. Show metadata
from there is official tier, because it's the production's own feed. It's also
the route in for Spotify-only shows: read the identity from the page's og: tags,
then look the title up on Apple.
Feeds carry title, description, author and episode count reliably. They rarely carry a structured cast, so hosts are read only from an explicit "hosted by" phrase and per-episode casts are not guessed at.
Wikidata (--qid, --search) is the identity backbone: stable QIDs,
canonical names and, usefully, birth names. It carries almost no AP credits, so
it is not used for them — but its works claims (P800, and a reverse P161
lookup) are read by the person-first sweep below, because a thin record of a
show missing from the catalogue entirely is still the only pointer to it.
Wikipedia (npm run discover:person) is the only person-first source here,
and it exists because every other adapter is show-first: they start from a show
already in data/shows and read its cast down, so a show nobody has catalogued
contributes nothing to anybody's filmography. That blind spot is worst for the
people with the most credits, whose long lists look complete. Aabria Iyengar had
42 credits, a stored QID, a stored Wikipedia link and four missing series — all
four named on the article this repo already linked to and had never read.
So this reads the person's article: filmography tables and prose both, since a
credit lives in prose until someone builds a table row for it. Everything it
finds is filtered through src/lib/sources/actual-play.ts, which classifies each
candidate from the work's own article — only actual play belongs here, and a
performer's filmography is mostly other things. Output is a review queue, never
data: Wikipedia is reference tier and demonstrably fallible, which is a point
this project makes with Wikipedia's own claim that Aabria played on a show she
ran.
Internet Archive (npm run import:archive) is where shows go when they
stop — productions whose sites are gone and whose feeds are dead. No other
index has them, because there is no live source left to find. The search and
metadata APIs are keyless.
Items are per-episode uploads rather than show records, so the work is
grouping: creator is the producer, and a common title prefix across their
uploads is a series. Systems come from the uploader's own subject tags; a
series whose tags name no system is reported, not assigned one.
robots.txt disallows /api/, and the public pages carry
no ld+json or embedded state. Their actual-play posts are prose.Imports land in data/_incoming/ for review and become a PR like any other
contribution. Curated data always wins: an import never overwrites an existing
bio, links, credits or alias notes.
Sources that are not licence-cleared are refused by the collector until someone
deliberately clears them in src/lib/sources/registry.ts.
You do not need git, or YAML. The site has a /submit page: pick the person, show and season from what's already indexed, say how you know, and it writes the data file for you and deep-links a pre-filled GitHub issue. If you saw a different name on screen, it also writes the alias stanza.
Failing that, the add a credit and name change issue forms work too.
If you do use git, edit the YAML directly, run npm run validate, and open a PR.
See CONTRIBUTING.md.
Astro, static output, deployed to GitHub Pages. The data layer
(src/lib/) is deliberately framework-agnostic — plain TypeScript, Zod and
YAML, with no Astro imports — so validation and the entity model survive a move
to Next.js or anything else. Only the rendering layer is Astro-specific.