MyGo 云音乐
用 Go 与 MyGo 写成的第三方网易云音乐桌面客户端。原生界面,没有 WebView;边下边播,无损与 Hi-Res,逐字歌词与「律动」,刘海播放器。
Translation pending
Dead simple RSS reader.
Translation pending
MediaPythonGitHub @grahamhagenahOnlineOwner 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
Loading the full README. The saved excerpt is shown below.
Two plain, black pages built from the same code:
• Newsfeed, the latest posts, podcast episodes and videos from a few sites, newest first: https://news.grahamhagenah.com/
• Events, concerts over the next 60 days (venues announce them further ahead) and films, and art and talks, over the next 30, grouped by day (MUSIC_DAYS_AHEAD and DAYS_AHEAD in events/build.py): pushpin.city, a site for each city.Read the full README ↗Two plain, black pages built from the same code:
MUSIC_DAYS_AHEAD and DAYS_AHEAD in events/build.py): pushpin.city, a site for each city. events.grahamhagenah.com was this page before Pushpin had a site of its own; it now holds the listings each build keeps for the next one (listings.json) and a page sending readers on to Pushpin Boston.news/: the newsfeed. feeds.txt lists its sites; build.py reads their feeds (and links podcast episodes to Apple Podcasts); sources.py is the bot behind the "Add a site" page.events/verify/ is published at pushpin.city's root as it is, for a file a service asks for to know the site is ours (Google Search Console's googleXXXX.html).events/: the events page. sources.txt lists its venues and how to read each (Boston's; sources-westernma.txt and sources-bayarea.txt for the other cities); skip.txt has words and phrases that keep a listing off both events pages when its name has one ("comedy"), except films; build.py has a reader for each kind of source and combines a film showing at several theaters into one row; find_venue.py looks up Ticketmaster venue ids.shared/: what both use. site.py has the page around each list (head, header, the styles they share, icons, the script that ages timestamps), fetching with retries, and the fallback and failure bookkeeping; alerts.py opens and closes "Source failing" issues.jobs/: the job board. sources.txt lists the boards and the city each covers; keywords.txt the titles worth listing; build.py reads each board.housing/: the housing tracker. build.py reads Boston's and Cambridge's lists of development projects, and MassBuilds for the towns around them; edits.txt holds our own changes to them and projects they don't list.tests/: each page's readers against saved samples of real sources (tests/fixtures/news, tests/fixtures/events), the fallback rules, and the shared page and alerts.Run everything from this top folder, with only the Python standard library:
python3 -m news.build and python3 -m events.build write dist/news and dist/events; open their index.html. python3 -m housing.build writes dist/housing, python3 -m jobs.build writes dist/jobs.python3 -m unittest runs the tests.Add or remove sites from the sources page, which opens a pre-filled issue that the sources.yml workflow applies to news/feeds.txt, or edit that file directly. A homepage URL is enough; the build finds the feed. Options like limit=5, days=14 and only="Full Performance" (only posts whose titles have that in them) go at the end of a line, and apple=<id> ties a podcast to its show in Apple Podcasts when the feed address Apple has on file isn't the one here.
YouTube channels work like any site (a channel's page is enough). Their videos, and any post linking straight to a YouTube video, play on the page in YouTube's privacy-enhanced embedded player, in a plain window that closes when the video ends, before YouTube can suggest another. A video opens in a corner of the screen, small, where it plays on while the list is read and scrolled behind it, and can be dragged anywhere by the bar across its top, which also holds a button that copies the video's own address (the video itself is YouTube's own page, which answers every press inside it). The whole screen is YouTube's own full-screen button, in its controls: it takes its frame there and hands it back to the corner afterwards, still playing, where asking for the screen ourselves meant a second player, a second set of rules for phones that won't grant it, and a window that remembered where it had been dragged to while it filled the screen. Its controls fade out on their own when the pointer leaves, so the corner is quiet most of the time. Shorts are left out. Hold a modifier key while clicking to open YouTube instead. YouTube's channel feeds sometimes answer 404 for a while; with a free YouTube Data API key kept as this repo's YOUTUBE_KEY secret, a channel whose feed fails comes from the API instead (its uploads without Shorts, one of the key's 10,000 daily units a request).
Make your own (/make-your-own/, linked from the sources page) walks someone else through setting up a newsfeed of their own, from the grahamhagenah/newsfeed template: that's this newsfeed's code on its own — news/, shared/, their tests, a starter feeds.txt and a workflow that builds and publishes it — written by python3 -m news.template <folder>, which checks its tests and a build pass inside the copy before it's published. template.yml keeps the template repo in step whenever the newsfeed's code changes here, given a TEMPLATE_TOKEN secret (a fine-grained token with Contents: read and write on that repo); without one it says so and stops. The newsfeed takes the repo it belongs to and the address it's published at from the environment (, ), so a copy points at its own repo for Add a site and its own page for the last build's posts, and names a sister site in the header only where is set — which this repo's workflow does, and a copy doesn't.
Web and design jobs around a few metro areas, newest first, at https://grahamhagenah.github.io/jobs/ (pushed to the grahamhagenah/jobs repo's gh-pages branch, as the other pages are to theirs, with JOBS_DEPLOY_KEY). It rebuilds every two hours (JOBS_EVERY_HOURS), since boards list the same openings all day.
CITIES (jobs/build.py), and Remote, which is a city here: a job belongs to whichever source listed it. The menu over the list chooses one (?city=), the filter beside it chooses engineering, design or remote work, and the search looks through everything on the page, as the newsfeed's does.jobs/sources.txt: how to read each, its address, its city, and its name. Built In has a site per metro (Boston, NYC, SF, Seattle, Colorado, Chicago, Austin, LA) whose robots.txt allows its job pages; its engineering and design listings give each job's company, where it is, what it pays, how it's worked and how senior, and the schema.org list on the same page gives the description. Remote jobs come from We Work Remotely's feeds, Remote OK's JSON (its terms ask for the link back, which every listing is) and Remotive's, which answers the same latest jobs whatever category is asked for, so it's read once.jobs/keywords.txt are listed — web, design, UI, UX, developer, JavaScript and the like — so a board's other openings stay off the page. A posting older than DAYS_TO_KEEP (30 days) is dropped, and no board gives more than PER_SOURCE.board.json, the same bookkeeping the other pages use), and the page says so.PushpinBot to them, as fetch's user_agent lets a source do. Both run WordPress's Theater plugin and book through Jacro's TaPoS, so one reader (wptheatre) does the pair. A site's productions give each film or show its name, description, poster and page — "Ken Russell's The Devils" where the ticketing says only "The Devils" — and say whether it's a film (the Somerville Theatre files them under "movie", the Capitol under "movies") or a live show, so a film with an orchestra is filed as a film. A theatre's events page gives concerts and the like their days and times; the Capitol shows only films and has no such page, which it says with a 404, where any other answer is the source failing. A film's times are only on the film's own page, which would be a fetch per film every build, so those come from the ticketing each books through (CSBSOM and CSBARL, the same sales their own pages send readers to), leaving three fetches a build for everything a theatre is showing. A name is matched to the nearest of the site's holding it, so the Somerville Theatre's ticketing's "House" is its site's "House (Hausu)" and not its "House on Haunted Hill"; anything on both an events page and the showtimes is listed once.Pushpin has a site for each city at a path of its own on pushpin.city: Pushpin Boston at /boston/, Pushpin Western Mass at /westernma/ (the Pioneer Valley and the Berkshires), and Pushpin Bay Area at /bayarea/ (San Francisco and Oakland). Venues to consider for the Bay Area are in events/bayarea-venues.md. Each city is a City in events/build.py (CITIES): its slug (its folder, and its sources file, sources-<slug>.txt; Boston's is sources.txt), its name, its state (which the cities page lists it under) and its clock (zone: what time its listings' times are in — Pacific for the Bay Area, so an 8pm show reads 8pm and its calendar entry says so; the page carries it as ZONE, which is what its script means by today, tomorrow, and what's already started), and what its pages say, every city's from city_texts (its name, its place for titles, "Western Mass", and where it covers for the rest, "the Pioneer Valley and the Berkshires"), with kinds giving a kind's page its own title, description or tagline where the shared words are too plain for it (Boston's film page: "Movie showtimes and repertory film in Boston"). The PUBLIC_ names are whichever city's pages are being written; they start at Boston's and use_city points them at each in turn. One build reads every city's sources; the personal events page shows only Boston's, and its listings.json keeps every city's to fall back on. Each city's pages are then written in turn (write_city), with use_city pointing the PUBLIC_ names at it. The site's root lists the cities under the state each is in, with where it covers (render_cities, a City's state and around; its header and the line under it the same as a city's pages'), then any being worked on (COMING_SOON) and a way to ask for another. One contact form serves every city, at /contact/ (render_contact), which each city's footer and About page link to and its old /<city>/contact/ sends on to; the root's own pages are built by site_page, with a city's header and styles, and listed in its own sitemap.xml, its 404 page sends an address under a city's folder to that city (a passed listing's to its view) and any other, from before there were cities, to the same under Boston's (render_not_found), and its robots.txt names each city's sitemap. Each city's footer links to the root ("All cities"). Its About page leaves out Boston's question about the Capitol Theatre.
To add a city: add a City to CITIES (with city_texts), a sources-<slug>.txt, its venues' addresses to VENUE_ADDRESSES, and its cards to CARDS in share_cards.py, then run python3 -m events.share_cards.
Western Mass's venues, from surveys of independent ones there (the Pearl Street Ballroom looked closed; the Clark, Jacob's Pillow and Williams College (its '62 Center and events calendar) block automated visits; Hawks & Reed's calendar has had nothing on it since 2021; Tanglewood's season is the summer's, and the BSO's calendar is built in the browser from a search service, so it waits for spring):
massmoca): its WordPress calendar (The Events Calendar, the tribe reader), sorted into our kinds by its own categories (MASS_MOCA_KINDS: concerts; book and artist talks, performances, public programs and exhibition openings), not Kidspace's storytimes. Its titles set a subtitle in a lighter span, sometimes left open ("Madison Cunningham <span class="title-light">Ace Tour"), which becomes the listing's detail (tribe_title, for every Events Calendar site). Its long-running exhibitions, open for years, are left out.amherstcinema): a calendar page for each day, /calendar/month/2026-09-16 despite its name, each film with its series and times, and each film's own page for its picture and description (not its notes for particular days, "On Tuesday 9/15, the 2:10 showtime is presented with Open Captions").indy): both run on Indy Systems, whose pages are an app that asks its GraphQL API for showings, one day at a time; the API answers only for the theater the request names, as the app does, with client-type: consumer and the theater's site and circuit ids, which go in the source's URL (?site=57&circuit=49, Images'; ?site=115&circuit=76, the Triplex's). A showing with no seats left is sold out.elfsight): one calendar for both, an Elfsight Event Calendar widget on the Iron Horse's site, read from the data the widget loads (its boot address, with the page and the widget's id). Each source keeps the shows in the room its name names (THE PARLOR ROOM for Parlor Room), not its kids' events, musician's workshops or open mics (ELFSIGHT_SKIP, by event type), or ones that repeat. Its price line ("TIX START @ $42 incl. all fees") gives the price, and a SOLD OUT button, sold out. Its shows elsewhere (the Shea Theater, Black Birch Vineyard) could be sources too, named for those rooms.squarespace), like the Lilypad. A show's supporting acts, after its name ("MINI TREES - w/ Frown Line"), become its detail ("with Frown Line", with_support), for Squarespace and Elfsight venues.mahaiwe): its calendar feed, by its categories (MAHAIWE_KINDS: concerts and opera; films and its HD broadcasts; lectures), not its comedy or dance classes. Its Indigo Room's shows, next door, are the Mahaiwe's, saying Indigo Room.shea, Turners Falls): its calendar, a month's grid to a page, each show's picture at an address from its id. "Shea Presents:" comes out of a name; another presenter ("DSP Shows Presents: Beth Orton") becomes the detail ().The events build also writes the same listings for anyone, as Pushpin Boston (dist/public), published from the grahamhagenah/pushpin repo's gh-pages branch at https://pushpin.city/boston/ (four A records for pushpin.city point at GitHub Pages, a CNAME record for www at grahamhagenah.github.io). Each city gets a path of its own there (PUBLIC_URL); the site's root lists the cities (above). It was first published as Boston, Daily at boston.grahamhagenah.com, whose pages now send each old address on to the same page here, keeping any ?venue= or ?q= (python3 -m events.moved, published once from the grahamhagenah/boston-daily repo). It has its own name in place of the Newsfeed/Events switcher, an About page (what it is, and every venue), the site's Contact form, a footer listing every page (Browse: all events and each kind; When: tonight and the weekends; About and Contact) with the current one marked (public_footer), each page's own line over its listings (the film page's, "Films around Boston, Cambridge, and Somerville, from repertory screenings to new releases…"; the home page's, the site in short, PUBLIC_SHORT), and what the site is in full at the foot of every page (public_footer, PUBLIC_TAGLINE), shorter previews of the venues' own descriptions (all of one in a listing's view), no "Add a source" link, and lets search engines list it.
VENUE_ADDRESSES in events/build.py unless the source gives the event's own, so add a new venue's there), a sitemap.xml and a robots.txt pointing to it./boston/music/, /boston/film/ and /boston/talks/, with only its events and its own title, description and tagline (PUBLIC_PAGES in events/build.py). The filter's choices link to them; on the home page, which has every event, the filter shows a kind in place and puts its page's address in the address bar. The pages link to each other from the city's root (/boston/about/), since a relative link would go astray after that./boston/tonight/ lists what's still to come today, on one page (PUBLIC_TONIGHT). It holds tomorrow's listings too and shows only the day it is where it's read, so it rolls over at midnight rather than waiting up to three hours for the next build./boston/weekend/ lists Friday to Sunday: the weekend it is, or from Monday to Thursday the one coming (weekend_days), and /boston/weekend/next/ the weekend after; each shows the whole weekend on one page and links to the other where the pager would be (PUBLIC_WEEKENDS). Their filter shows a kind in place. Every public page's footer links to this weekend's./boston/calendar/: one for each kind (music.ics, film.ics, talks.ics) and one for each venue (the-sinclair.ics), of what's coming up (calendar_feeds). Each listing is one event, at its first time for two hours or all day without one, its other times in its notes, with an id that stays the same from build to build so a calendar app updates it rather than adding it again. The About page's Calendars section links each kind's for Apple Calendar (webcal://) and Google Calendar; the footer links there too. The venues' own feeds are still written, for anyone already subscribed, but no longer linked (webcal:// does nothing in most desktop browsers).Build Housing Boston: new housing being proposed, approved and built around Boston, at buildhousing.org: a map of it, then a list for each town, newest news first. A project opens in a panel (a sheet on a phone), as Pushpin's listings do, with what its source says about it: its dates, cost, size, developer and description, our note, and for Boston's projects the rendering from its page on bostonplans.org, which each build looks up only for projects it hasn't seen before (images in projects.json). Its address (?project=boston-4930) links straight to it. A page carries none of the panels' details: they're in panels.json, the same for every page, asked for as a project is about to be opened (when the reader first points at a row, or once the page is quiet). The map's library, a megabyte, is fetched only as the map comes near the window. Over the map, a Recently updated line turns over the newest changes, as Pushpin's Just announced does, and leads to Recent updates (/recent/): every project with something that happened in the last RECENT_DAYS days (90; the cities refresh their lists every few weeks or months), newest first, each saying what: a status seen to change ("Proposed → Approved", or "Newly listed"), a Boston filing or board approval, an update in MassBuilds, or our own note. The map is MapLibre's (from cdnjs), on OpenFreeMap's dark vector tiles, which need no key; the browser draws their roads and names itself, so they're sharp on any screen. The map draws every project at the zooms a reader starts at, so a town with little going on looks that way because it is; only further out, where the whole region is in view, does it leave the smaller ones out (40 homes or more, then 120 at its farthest), with a note in its corner saying so. A search, Recent updates and Large projects always show every one. Large projects (/large/) lists those of LARGE_HOMES homes or more (300) across every town, biggest first, each with a bar of four steps (proposed, approved, under construction, complete) showing how far along it is. Have your say (/have-your-say/) lists Boston's open comment periods and upcoming public meetings, soonest first: each comment period from its project's page on bostonplans.org ("Comment period ends Sep 30, 2026"), read each build for projects under review or filed in the last 120 days; each meeting from the Planning Department's calendar feed, whose descriptions link to the projects they're about. A project's panel lists its own in a Have your say box, its row carries a tag with the soonest, and a line under Recently updated shows the soonest of all. Cambridge's are its Planning Board's meetings, from its table of what's scheduled for each, whose items name the case numbers (PB-410) the development log gives for each project; its table has no times, so those say only their day. The towns MassBuilds covers publish neither, and their pages say so. Each town has a page of its own (). The site's pages link to each other from its root (), as Pushpin's do, so (the entry in ) serves it as it's published. A project's address is its panel's, on whichever page it's opened: (an older link still opens it), which its name in any list links to and its panel's Copy link copies. Search engines are welcome: every page has a heading of its own (the header says the same in its own way), a description and a canonical address; a town's page says a few lines about its town; each page carries what it is in JSON-LD (the site, the page, a town's projects as a list, and Have your say's meetings as events, with when each starts and where to join); and lists them all. A link to a project (, which its panel's Copy link copies) shows the project's own rendering, name and description, and whoever opens it lands on its panel; a link to any other page shows (the house and the statuses' rings on the site's black, drawn by with the icons), with the page's own title and description as its words. Every page ends in a footer, as Pushpin's: its pages, each town ( opens that town's list on the home page) and the sources. The site's mark is Tabler Icons' "building-community" (MIT), beside its name in the header; the icons in , and the picture a link shows, are drawn from that same path by , which strokes it as Tabler does.
INNER_RING: Somerville, Brookline, Medford and the rest) come from MAPC's MassBuilds, which MAPC's staff and the towns' planners keep up, some towns far more often than others, so each of those lists says when its data was last updated, in amber after six months. MassBuilds' "planning" (filed, approved or not) shows as proposed, and its "stalled" flag as stalled. Only projects with homes are listed, and finished ones only from 2020 on (COMPLETE_SINCE).projects.json) and the date on our own edit. The first build has nothing to compare with, so Cambridge's projects, which have no dates of their own, go undated until they change.housing/edits.txt (its top explains how) and push; the page rebuilds at once. An edit that can't be used is reported in the build's log and skipped.housing-notes.yml applies the repo owner's straight to edits.txt (housing/notes.py), replies, closes it and redeploys; anyone else's is labelled correction and left for the owner to judge, the site saying nothing until they note it themselves.python3 -m housing.upstream lists what our edits would change there, each with its MassBuilds page, and whether it can go as an edit (MassBuilds takes one only if it leaves the whole record valid) or needs a flag. With --send, and MASSBUILDS_EMAIL and MASSBUILDS_PASSWORD in the environment (never in the repo), it posts each: an edit or a flag, both of which a MassBuilds moderator sees before anything changes there. It's run by hand, never by a build, since it posts publicly under that account; housing/sent.txt keeps what's gone up, so nothing goes twice.Pushpin Boston's visits are counted with GoatCounter, free for a personal, non-commercial site. It uses no cookies and keeps nothing personal, so no cookie notice is needed; the About page's "Does it track me?" answer says so. Only Pushpin Boston is counted, not the newsfeed or the personal events page.
https://gc.zgo.at/count.js pointed at GOATCOUNTER in events/build.py (https://hagenah.goatcounter.com/count); to move to another GoatCounter site, change that./boston/, /boston/film/, /boston/weekend/; a ?venue= or ?q= doesn't make another), with where it came from, country, and device. Switching to Music, Film or Art & talks on the home page counts as a visit to that page. And, as events, which appear in the same list marked as events:
open/<venue>: a listing's view opened.listing/<venue>: a listing followed to its venue's page, from its view or straight from its name, with the event's name as its title. Which venues send people out.venue/<venue>: a venue chosen from the menu.share/<venue>: a listing shared (share/several theaters for a film at more than one).hagenah.goatcounter.com/count for each page (none in a browser that's toggled off). In the console, goatcounter.filter() gives false when it's counting, or the reason it isn't. It never counts localhost, so a local build isn't counted.https://pushpin.city/boston/sitemap.xml).feeds.json and listings.json. When a source fails, or suddenly returns nothing while it had items coming up, the next build uses its items from there instead, if they're under two days old, and says so at the bottom of the page. A feed that's just quiet isn't a failure.tests/fixtures too.deploy.yml runs the tests, then builds and publishes both pages:
gh-pages branch of grahamhagenah/events. The push uses a deploy key that can write to that repo only, kept as the EVENTS_DEPLOY_KEY secret here (its public half is under that repo's Settings → Deploy keys). Deploy keys don't expire.HOUSING_DEPLOY_KEY secret. Without that secret it's built but not published.GitHub's own schedule trigger skips most runs, so a cron-job.org job named "Newsfeed build" starts the deploy every 15 minutes instead. Each run rebuilds the newsfeed; the events pages rebuild only when their last build is 3 hours old (EVENTS_EVERY_HOURS in deploy.yml, which a push, or a manual run with "events" ticked, skips). The schedule in deploy.yml stays as a backup.
POST https://api.github.com/repos/grahamhagenah/news/actions/workflows/deploy.yml/dispatches with body {"ref":"main"} and headers Authorization: Bearer <token>, Accept: application/vnd.github+json, X-GitHub-Api-Version: 2022-11-28, Content-Type: application/json, and User-Agent: cron-job.org. GitHub answers 204. Without the User-Agent header it answers 403.keepalive job makes an empty commit if the repo has been quiet for 50 days.Looking after it:
gh run list -R grahamhagenah/news --workflow deploy.yml --event workflow_dispatch -L 5 should show a run every 15 minutes, as should the Actions tab filtered by event. A cancelled one now and then is a run a push replaced. The newsfeed's "Updated" time in its header says when it last built.Bearer <new token>; save. The job's "Test run" should answer 204, and a new dispatched run should appear within a minute. Never paste the token anywhere else.gh workflow enable deploy.yml -R grahamhagenah/news, or Actions → Build and deploy → Enable workflow.deploy.yml's own schedule, just less often: GitHub drops many of its scheduled runs.GITHUB_REPOSITORYSITE_URLEVENTS_URL?source=). The events pages' ("All venues") shows one venue's events of every kind, kept in the address (?venue=); a film playing at several theaters narrows to the chosen one's times. On Pushpin Boston's music, film and talks pages, a choice goes to the home page, which has every kind; on the weekend and tonight pages it lists only the venues with events then.NEW_DAYS), concerts and talks only (NEW_KINDS; a theater adds showtimes every day, which would crowd them out). The home page carries a line over its filters (fresh_banner): one of the week's newest, opening its view, which the page's script picks from the newest few (FRESH, FRESH_SHOWN), so a different one shows each visit; and "See all" to the page of the rest; it stays when nothing's turned up this week, saying so (/boston/new/, render_index(added=True)), one list under Recently added, newest first, with the day it's on beside each name. Each build stamps every listing a source lists — not just what's inside the window, so a show announced months ahead isn't new when it comes into it — and keeps the stamps in listings.json (first_seen). A source's first build, and the first build of all, stamp their listings as older than new, so adding a venue doesn't announce its whole calendar; a source that fails keeps the stamps of what it still has ahead. The page is empty for the first week after all this went in.?event=2026-09-15-akira-4k-restoration-coolidge-corner (listing_id: the date, then its series, its name and venue's, which the same show on other days shares), so Back and Esc close it and a shared link opens it; a link to a showing that's passed opens the next of its series, saying so. The name is still a link to the venue's page, so a click with a modifier key, or a middle click, goes straight there. From the view, ‹ and › beside its close button step through the list as the page has it (whatever the filters, the search and the pager have left, across the days), and so do the left and right arrow keys, or j and k, which leave up and down to scroll a long description; each step replaces ?event= rather than adding to history, so Back still closes the view, and the next listing's picture and description are fetched as the view opens.sold_out (all of it) and sold_out_times ("19:15"), which merge_showings combines. The Coolidge marks each showtime (sales-state--DisplayCustomMessage, its key's "Sold out/unavailable"); its showtimes pages can be an hour behind, so each film's own page is read too (coolidge_film_states) and wins. The Sinclair's and AEG's ticket buttons say "Sold Out", Passim's has a sold-out class, DICE's page data a sold-out status, schema.org offers SoldOut, and some venues put it in the name ("Yana – SOLD OUT!", "SOLD OUT: …"), which comes out of the name (SOLD_OUT_NAME). Ticketmaster's venues don't say. It's as fresh as the last events build, every 3 hours on the schedule (EVENTS_EVERY_HOURS); the venue's page is the last word.event's image, price and ages), and the rows carry the picture and price as data-image and data-price for the view — not a film's price, which a cinema sells at several at once, and not ages at all, which are the venue's to give. A wide picture fills its frame; a poster or square flyer is shown whole, the same picture blurred and darkened either side of it; one that doesn't load is left out. While it loads, its frame shimmers faintly; it fades in once it's fully loaded and decoded, rather than drawing itself top to bottom, and it's fetched as a listing is pressed, a moment before its view opens. The pictures load from the venues' own sites, a smaller copy where the host makes one (lighter, aeg_image, ticketmaster_image, alamo_image), mostly 30–200 KB. Nearly every source has pictures; Midway Cafe's calendar feed and ArtsEmerson's listings have none. A price is the source's own where it has one (the Brattle, Deep Cuts, The Rockwell, MIT and Ticketmaster's venues), else read from a listing's short lines of facts, "$10 cover · 21+" (price_from), never its prose, where "$4 from every ticket goes to…" isn't one; "Free" only when a line says the event is ("Free", "No cover", "Free admission"), not "18 and under free". Ages likewise (ages_from): AEG's and The Sinclair's own, else from those lines, or a description's "Ages: This event is 21+". AEG's venues list $0 for every show, so theirs have no price.clip; 240 on Pushpin Boston), unseen, which the view shows at once and the search matches. The view shows all of it, up to ABOUT_FULL_CHARS (2400): Pushpin Boston's rows carry data-more where there's more, which the view fetches from the listing's own page (/boston/e/<its id>/, which has it all) when it's pressed or opened, keeping the home page from doubling in size. A long one shows a few lines, fading out, and Read more. Sources that say nothing (the MFA, the Middle East) have none.TICKETMASTER_KEY secret. To add one, find its venue id with Actions → "Find a Ticketmaster venue".presentedacademyofmusic, Northampton): its calendar's event cards, and each event's page for its picture, description and price. It doesn't say what kind each event is, so guess_kind does, from its name and description: comedy left out, a screening a film, dance, talks, readings and young people's productions art & talks, the rest music. Not its notes on presales and fees.phoenix, Pittsfield): Phoenix Theatres' showtimes, as its page asks for them, a day at a time by the cinema's number (005), each showing sold out or not, and a film's wide backdrop, as its pages ask for it (phoenix_image: its backdrop's id, with f- before it; else its poster).spektrix, Pittsfield): Berkshire Theatre Group's public Spektrix data, its events and performances, kept to those on the Colonial's stage (not the Unicorn's in Stockbridge); the source's address is BTG's calendar, with ?spektrix=berkshiretheatregroup. Each event's own page is found among the calendar's and home page's links by its name, or at the address WordPress would give it. Kinds guessed, as the Academy's.umassfac): its performing arts events page, each with its date and time (no year), its hall (its detail, as they're around campus, and some at The Drake), a line on it and its picture. Kinds guessed. No street address, as its halls are several./boston/e/<its id>/event_pagesshare_title?event=share/<venue>events/pushpin/: favicon.svg, white in a browser in dark mode and black in light, with no background; and apple-touch-icon.png, white on black for a phone's home screen, made by share_cards.py. In the header, the same pin, in white like the name, comes before it, and the city's name is lighter than Pushpin's.events/share/<slug>/; and pushpin.city's own, in events/share/site/. They don't change with the listings, so they're made by hand with Chrome: python3 -m events.share_cards, again after adding or renaming a city or rewording a page.public=no in events/sources.txt stays off it, for one that isn't ours to republish.PUBLIC_CONTACT; its first message asks that address to confirm, and FormSubmit then offers a random alias to use there instead of the address.PUBLIC_DEPLOY_KEY secret. To move it to another domain: point the domain at GitHub Pages, set it in that repo's Pages settings, change the CNAME the deploy writes, and change PUBLIC_URL./somerville//recent/python3 -m http.server --directory dist/housinghousing.claude/launch.json?project=boston-4930#boston-4930sitemap.xml/p/boston-4930/share.pngmake_icons.py#town-somervillehousing/staticpython3 -m housing.make_icons