MyGo 云音乐
用 Go 与 MyGo 写成的第三方网易云音乐桌面客户端。原生界面,没有 WebView;边下边播,无损与 Hi-Res,逐字歌词与「律动」,刘海播放器。
Translation pending
Pick a family movie for tonight by who's watching, time, mood, and age limits
AI summary · website content
MediaJavaScript · HTMLGitHub @tokim25OnlineOwner 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
tokim25/movie-app-repo
Translation pending
Taken from the repository README
Loading the full README. The saved excerpt is shown below.
A web app pairing a family movie list with Common Sense Media's
"what parents need to know" content, built as a personal checklist with
per-device persistence (localStorage). The UI is a static page with no
build step; the only backend is a handful of small Vercel serverless
functions under api/ that broker Google's OAuth refresh token for
sync (see "Optional Google sync" below) — everything else is static files.Read the full README ↗**Stop re-litigating "what do we watch tonight" every Friday.** Family Feature is a free, no-login family movie watchlist that pairs a shared list with real content guidance from Common Sense Media — so you can say yes or no in five seconds instead of ten minutes of trailer-scrubbing.
**Try it now → [movies.tonykim.io](https://movies.tonykim.io)** — no account required, works on any device. Also linked (unlisted) from [tonykim.io/movies](https://tonykim.io/movies).
Features & Benefits**One shared list, zero setup.** Add a movie once and everyone in the family sees it — no accounts, no sign-up forms, no backend to manage. Progress is saved per device by default (localStorage), with a manual "Sync across devices" code for moving it between devices without any account at all, or automatic Google Drive sync if you want it to just happen.
**Real content guidance, not just a star rating.** Every title includes Common Sense Media's actual "what parents need to know" — concrete content concerns and positive takeaways — plus a recommended age, so you know *why* something is or isn't a fit, not just a number.
**Filter to what actually matters tonight.** Decade, recommended age, genre, and studio — combinable, and clearable with one button. Browse by studio (chronological by default) or the full catalog (by release year, age, title, or your own custom order).
**Star what you actually want to watch.** A priority toggle, independent of the watched checkbox, with its own filter and count — so "want to watch" and "already seen" never get tangled together. Both travel with you through device sync.
**Request a movie.** A simple in-app form — no accounts, no page navigation — drops requests straight into a shared queue that gets triaged and added.
**Works offline, installs like an app.** It's an installable PWA: add it to your home screen and the app shell, data, and policy pages keep working without a connection.
**Private by design.** No ads, no behavioral tracking, no analytics, nothing sold. Optional Google sync uses Google's most restricted Drive permission (drive.appdata) — it can only touch this app's own hidden data file, never the rest of your Drive — and the refresh token that powers it is stored in an HttpOnly cookie a page-level script bug could never read. Full details in the [Privacy Policy](https://movies.tonykim.io/privacy.html) and [Terms](https://movies.tonykim.io/terms.html).
**A catalog that keeps growing.** 832 movies and counting — Disney, Pixar, DreamWorks, Marvel/DC, Studio Ghibli, Nickelodeon, Disney Channel Original Movies, and more — each hand-classified by genre and studio and checked against Common Sense Media or a comparable source, not scraped and dumped. New titles are flagged automatically so the list never goes stale.
How it's builtA static page with no build step; the only backend is a handful of small Vercel serverless functions under api/ that broker Google's OAuth refresh token for sync (see "Optional Google sync" below) — everything else is static files.
**Live app:** https://movies.tonykim.io
**Also linked (unlisted) from:** https://tonykim.io/movies
**Legacy Vercel URL:** https://family-movie-watchlist-kim-family-projects.vercel.app now redirects to the live app.
Device syncProgress lives in localStorage per device/browser, same as always. To carry progress to another device, use "Sync across devices" in the app: it shows a code (copy it) and a box to paste a code from elsewhere (load it) — a manual, no-account, no-backend way to move your watched list and ordering between devices.
Optional Google syncOptional Google sync stores a single family-feature-state-v3.jsonfile in the user's Google DriveappDataFolderwith the limiteddrive.appdatascope. The OAuth consent screen should use the public app name "Family Feature" and point to the live policy pages:https://movies.tonykim.io/privacy.html` and https://movies.tonykim.io/terms.html. The OAuth client should include https://movies.tonykim.io as an authorized JavaScript origin. The consent screen's publishing status is In production (not Testing), which matters for the point below — Google caps refresh-token lifetime at 7 days for unverified/Testing apps, but production apps keep them until the user revokes access or leaves the app unused for 6+ months.`
Sign-in uses the authorization-code flow, not the older implicit token flow, specifically so it can get a refresh token: google.accounts.oauth2.initCodeClient(...)(withaccess_type:'offline', prompt:'consent') runs client-side and hands the resulting one-time code to api/google-exchange.js, a Vercel serverless function that exchanges it with Google for an access token and a refresh token. The refresh token is set as an HttpOnly/Secure cookie (gsync_rt, scoped to /api) — it's never readable from page JS, which keeps a client-side XSS bug from being able to steal it. On every later page load, api/google-refresh.jsuses that cookie to mint a fresh access token with a same-originfetch, no Google popup or account picker involved. api/google-logout.js clears the cookie and best-effort revokes the refresh token when the user disconnects.
This needs a GOOGLE_CLIENT_SECRETenvironment variable set in the Vercel project (Project Settings → Environment Variables) — grab it from the same Google Cloud Console credentials page as the client ID. The client ID itself isn't secret (it's already public inindex.html) and defaults in code if the env var is unset, but the token-exchange calls will 500 without the secret configured.
The app is also installable as a PWA. site.webmanifestdefines the install metadata and icons, whilesw.jscaches the app shell, data files, icons, and policy pages for offline loading. Movie posters remain remote Wikimedia images and are not promised offline; when an image is unavailable, its fixed-size slot shows the generic movie/year artwork instead of disappearing or shifting the row. Google sync keeps local changes saved first, then queues and retries Drive writes when the device comes back online or the tab becomes visible again. A Drive write that comes back401(access token expired mid-session, which happens every ~hour on a long-open tab) triggers one silentapi/google-refresh call and retry before giving up — most mid-session expiries never surface to the user at all. The app also remembers that Google sync was enabled separately from Google's short-lived access token. After reloads, installs, or app updates it silently re-derives a fresh access token from the refresh cookie; if that refresh itself fails (revoked access, or the refresh token going stale from 6+ months of disuse), the sync panel shows "Google sync paused — sign in again" instead of silently looking disconnected. That reconnect state also appears as a top-level alert near the app header, so users do not have to open the full movie browser or sync panel to discover that Google sync needs attention.
Catalog structureEvery movie also carries genre(1-3 tags from a fixed list) andstudio(the real production studio, not just which curated list it came from), on top of the existingy(year) andca (Common Sense Media recommended age). The app filters on all four: decade, max recommended age, genre, and studio, combinable and cleared with one button.
Studio sections list movies chronologically by release year by default. The full browser also defaults to release-year order and can switch to recommended age, title, or the saved custom order.
Each row also has a star toggle, independent of the watched checkbox, for flagging movies you want to prioritize — a "Want to watch" filter button and header count go with it. Priority marks travel through "Sync across devices" alongside watched status and custom order.
A "Request a movie" form at the bottom (added 2026-08-24, replacing an earlier mailto: link) posts a single title straight to a Google Form in the background — no page navigation, no accounts, just a text field and a toast confirmation. Responses land in a linked Google Sheet, which the weekly scheduled update job reads.
Files — the entire UI (HTML/CSS/JS in one file, Apple-inspired design system) — three Vercel serverless functions brokering the Google OAuth refresh token for sync (google-exchange.js, google-refresh.js, google-logout.js), plus a shared _google.js helper (the leading underscore keeps Vercel from routing it) — PWA service worker for offline app-shell/data caching— auto-generated concatenation of every data-*.js file below (vianode scripts/bundle-data.mjs), the single file index.html actually loads; never edit it directly — the original 100 movies (Big Life Journal's "100 Best Family Movies") — 36 additional movies from Rotten Tomatoes' "50 Essential Movies For Kids" — 116 movies: all 115 official Disney Channel Original Movies (1997-2022) plus The Magic Faraway Tree (2026) — 231 movies: the Walt Disney Animation Studios canon, Disneytoon direct-to-video sequels, Disneynature documentaries, and Disney live-action family films spanning 1937-2025 — 15 additional Pixar features not already covered elsewhere — 44 DreamWorks Animation theatrical films (1998-2024) — 34 Nickelodeon Movies theatrical and streaming films (1996-2023) — 31 movies requested directly (e.g. via "Request a movie") rather than pulled from a curated external list: the Free Willy and Air Bud franchises, the Sony Spider-Man live-action run plus Across the Spider-Verse, a batch of best-of-90s live-action kids films, and The Sheep Detectives — 67 movies for ages 5-9, sourced from Common Sense Media's own curated age-based lists ("50 Movies All Kids Should Watch Before They're 12," "Best Kids and Family Movies," and similar) and deduped against everything already in the app — 140 movies: the Marvel Cinematic Universe, legacy Marvel (Fox's X-Men series, Sony's Venom/Morbius/Madame Web, Fantastic Four, Ghost Rider, Elektra), and DC films across every era including the full DC Universe Animated Original Movies line, with R-rated titles (Deadpool & Wolverine, Logan, Zack Snyder's Justice League, and similar) left out by request — 18 movies: the rest of the Studio Ghibli theatrical catalog not already covered elsewhere in the app, added unfiltered by content/rating per request (including Grave of the Fireflies)832 movies total.
Adding more moviesUse the movie-watchlist-updater Claude skill (.claude/skills/movie-watchlist-updater/) for the full research → write-up → deploy pipeline, including poster art and a srcUrllink back to whatever page the content came from. In short: each new curated source list gets its owndata-.jsfile (never edit the existing ones). One-off single-title requests (as opposed to a whole new curated list) go indata-extra.jsinstead of spawning a new file each time. Requested titles waiting to be added live in the "Movie Night Requests (Responses)" Google Sheet (fed by the in-app request form);PENDING_REQUESTS.md is now a processed-log the skill writes to, not a queue.
Run node scripts/validate-data.mjs after catalog edits. It checks duplicate movie numbers, duplicate normalized title/year pairs, required fields, HTTPS source URLs, allowed genres, orphan poster keys, the required runtime trio (runtimeMinutes, runtimeSourceId, runtimeVerifiedAt), and that sw.js's DATA_VERSIONanddata-bundle.jsare both in sync with the source files. If either is stale, runnode scripts/data-version.mjsandnode scripts/bundle-data.mjsand commit the results — a newdata-.jsfile also needs a newtag added to thedataFileslist inscripts/data-version.mjs(both other scripts import that same list), not toindex.htmldirectly, sinceindex.htmlonly loads the generateddata-bundle.js.
TestingA small Playwright suite in tests/ covers regression-prone behavior: catalog rendering, watched/priority persistence, clearing watched marks, manual sync code export/import, the PWA manifest and service worker, offline app-shell reloads, Google Drive sync failure/retry handling, and the reconnect prompt shown when a previously enabled Google sync session can no longer silently refresh.
Install once, then run:
npm install
npx playwright install chromium
npm test
npm test starts a plain static file server (tests/static-server.mjs) on http://127.0.0.1:4319`, points Playwright at it, and runs headless Chromium. No build step, running serverless function, or real Google account is required. Everything runs against the repo's static files as-is; the app's own fetch calls to api/google-refresh.js and friends just 404 against this static server (there's nothing at /api here), and the reconnect-path tests rely on exactly that — see tests/google-sync.spec.js.`
index.htmlis a single classic (non-module)tag, so its top-levellet/const/functiondeclarations are already reachable from Playwright'spage.evaluate(), the same way they'd be reachable from the browser's dev console. The Google Drive sync tests use this directly: they set the app's own googleAccessTokenvariable and call itspushToGoogleDrive()/syncFromGoogleDrive()functions, while mocking the Drive REST calls withpage.route(), to exercise the real save-first/offline-status/backoff-retry code paths without a real OAuth flow. No helper extraction from index.html was needed for this.
Useful variants:
npx playwright test tests/google-sync.spec.js # one file
npx playwright test --ui # interactive runner
npx playwright show-report # HTML report after a run
DeployingThe Vercel project ("family-movie-watchlist") is connected to this repo via Vercel's Git integration (as of 2026-08-24) — a plain git pushtomaster(or a merged PR) redeploys the whole site automatically, every file in the repo including alldata-*.jsfiles and theapi/serverless functions. There is no manual deploy step anymore. The project used to route data files through jsDelivr's CDN with manual cache-busting to work around Vercel not being Git-connected; that workaround is gone and any reference tocdn.jsdelivr.netleft inindex.html is a bug, not the current design.
The api/functions need aGOOGLE_CLIENT_SECRETenvironment variable set in the Vercel project (Project Settings → Environment Variables → all environments) — without it,api/google-exchange.jsandapi/google-refresh.js both return 500 and Google sync falls back to asking for a manual reconnect every time, the exact problem this architecture exists to avoid. This is a one-time, per-project setup step, not something a code push can carry.
vercel.jsonredirects the original Vercel-generated app domain tohttps://movies.tonykim.io/`. index.html also includes a client-side fallback for *.vercel.app hosts so stale static copies still end up at the canonical domain.`
data-posters.js — poster artwork for 813 of 832 movies, sourced from Wikipedia poster thumbnails, keyed by each movie's num