MyGo 云音乐
用 Go 与 MyGo 写成的第三方网易云音乐桌面客户端。原生界面,没有 WebView;边下边播,无损与 Hi-Res,逐字歌词与「律动」,刘海播放器。
Translation pending
Discover hidden poetry inside classic literary texts by erasing words.
Translation pending
MediaGitHub @victorsmkOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
Repository information has not been collected yet.
No updates detected yet. GitHub releases will appear here.
The maker's introduction consists of the line above. Read the repository README for more details. Repository README ↗
Loading the full README.
Read the full README ↗A found-poetry and erasure workshop. Open a page of an old book, cover the words around the ones that strike you, keep the rest where they stand, and see the poem that was hiding there all along.
Live site: https://palimpsest-inky.vercel.app
.txt or .docx file or paste text, correct it, and use it like any book. Signed out, it
stays in your browser; signed in, it is kept in your account and follows you to any browser.| What | Used |
|---|---|
| App | Next.js 16 (App Router), React 19, TypeScript |
| Styling | Tailwind CSS 4; fonts Playfair Display, Literata and DM Sans |
| Database | Supabase Postgres (free plan), reached through the pg driver |
| Sign-in | Supabase Auth, with Google sign-in (an email one-time code is supported too) |
| Hosting | Vercel (Hobby plan); a daily call to /api/health keeps the free Supabase project awake |
| Syllable counts | CMUdict, turned into a lookup table by scripts/preprocess-cmudict.mjs |
| Books | Project Gutenberg, imported by hand (see "Adding books") |
| Picture export | html-to-image |
| Tests | Vitest, Testing Library, Playwright, and PGlite (Postgres running inside the tests) |
screens (app/, components/)
└── services (PoemService, BookService) lib/services
└── repositories lib/repositories
├── in the browser: localStorage poems and your own texts when signed out
└── on the server: /api/… poems and texts for signed-in readers, and the library of books
└── Postgres (Supabase) lib/server, db/schema.sql
lib/services/container.ts is the one place that chooses where data lives. With NEXT_PUBLIC_DATA_BACKEND=browser
(the default) there are no accounts and everything is kept in the browser. With server, signed-in readers' poems and
texts are stored in Postgres through the app's own API, and the library of books is read from the database.
You need Node.js 22.12 or newer.
npm install
npm run dev # http://localhost:3000, no accounts: poems are kept in your browser
To try the version with accounts and a database, with no keys and no setup:
npm run dev:demo # http://localhost:3200
The "server" and its database are part of that one process. Sign in with any email address and the code 123456.
It starts empty and forgets everything when stopped. It has a small library of three books.
Both have free plans. It takes about an hour the first time. You make the accounts and keep the keys in the settings
pages named below, never in a file you commit (.env* files are ignored by git; .env.example lists every setting).
Supabase: make the database. Create a project. In SQL Editor, run the whole of db/schema.sql, then the whole
of db/supabase.sql (both are safe to run again). Run them again whenever a new version of the app adds a table.
Supabase: collect the settings.
?sslmode=require
on the end. This is DATABASE_URL.sb_publishable_…) and the secret key
(sb_secret_…, only used to delete accounts, and never to be shared).Google sign-in (needs no email service). In Google Cloud Console, make a project, set up the OAuth consent
screen (External, then publish it so anyone can sign in), and create an OAuth client ID of type Web
application with your site's address as an authorised JavaScript origin and Supabase's callback address as a
redirect URI. In Supabase → Authentication → Providers → Google, switch Google on and enter the client ID and
secret. The site's privacy page is /privacy.
Vercel: import the repository (Add New → Project). Before the first deploy, add these under Settings → Environment Variables (Production):
| Name | Value |
|---|---|
NEXT_PUBLIC_DATA_BACKEND | server |
NEXT_PUBLIC_SUPABASE_URL | the Project URL |
NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY | the publishable key |
NEXT_PUBLIC_GOOGLE_CLIENT_ID | the Google client ID |
NEXT_PUBLIC_EMAIL_SIGN_IN | off for Google-only sign-in; leave it out to offer an email code too |
DATABASE_URL | the connection string from step 2 |
SUPABASE_URL | the Project URL |
SUPABASE_PUBLISHABLE_KEY | the publishable key |
SUPABASE_SECRET_KEY | the secret key (mark it as a secret) |
Free-plan notes. Supabase pauses a free project after about a week without activity. vercel.json has Vercel call
/api/health once a day to prevent that (check Settings → Cron Jobs in Vercel). Vercel's Hobby plan is for
non-commercial use. The free Supabase plan is not a backup service: export your data now and then.
The library holds public-domain books (first published in 1930 or earlier) from Project Gutenberg, cut into excerpts of about 450 words that end at a paragraph. The import never downloads anything: Gutenberg asks that automated downloading be avoided, so you save the plain-text files yourself.
Choose a list of books: data/library/pilot.json is a ready ten-book example (Gutenberg numbers, titles, authors,
years, and whether a book is prose or verse).
For each, save its Plain Text UTF-8 file from https://www.gutenberg.org/ebooks/<number> as
data/library/raw/pg<number>.txt (this folder is ignored by git).
Check what would happen (this needs no database), then import (this needs DATABASE_URL, for example in .env.local):
npm run import:library -- --list data/library/pilot.json --dry-run
npm run import:library -- --list data/library/pilot.json
The import checks that each file is really that book, removes Gutenberg's header and licence, finds the chapters, and adds the book and its excerpts to the database, all or none. A book already there is left exactly as it is, because saved poems point at the words of an excerpt by position; an excerpt must never be changed after people have used it.
npm test # unit tests (Vitest)
npm run lint # ESLint
npx tsc --noEmit # types
npm run test:e2e # browser tests (Playwright) on a production build, on port 3100
npm run test:e2e:server # the same app with accounts and the server API, on a real SQL database in the test process
npm run test:e2e:demo # the local demo with accounts
The first time, download the browsers with npx playwright install chromium (add firefox webkit to run all three).
The server and demo suites are run in Chromium only.
data/cmudict/LICENSE.txt).The NEXT_PUBLIC_ settings are put into the page when it is built, so changing one needs a new deployment. In
Settings → Functions, pick the region closest to your Supabase project.
Check /api/health. It needs no sign-in and should answer
{"ok": true, "settings": "ok", "database": "ok", "signIn": "ok", "accountDeletion": "ready", "rateLimiting": "ok", "library": "ok", "texts": "ok"}.
Anything else names what is missing (for example a table to create by running db/schema.sql again).
Optional, recommended: a firewall rule (the app cannot make it). Project → Firewall → New Rule: request
path starts with /api/, Rate Limit, fixed window 60 seconds, 120 requests, key IP. The library's endpoints
are public, so this is what limits them. Signed-in users are limited inside the app as well.