diff --git a/gigs/are-na-annual-vol-8/source-swaps.md b/gigs/are-na-annual-vol-8/source-swaps.md new file mode 100644 index 000000000..061b40777 --- /dev/null +++ b/gigs/are-na-annual-vol-8/source-swaps.md @@ -0,0 +1,118 @@ +# Source swaps — remove wikipedia, add primary sources + +current channel: 68 blocks · **52 are wikipedia** · 3 go to the wrong page entirely + +## critical fixes (wikipedia redirected to unrelated page) + +| # | current (broken) | swap to | +|---|---|---| +| 1 | `Renegade_(dance)` → goes to "Lottery (K Camp song)" | **NYT 2020 — Taylor Lorenz profile of Jalaiah Harmon**: https://www.nytimes.com/2020/02/13/style/the-original-renegade.html — the actual primary source for the story | +| 33 | `Water_Yam` → goes to "Dioscorea alata" (yam tuber!) | **Monoskop — George Brecht, Water Yam**: https://monoskop.org/Water_Yam — scans + bibliography | +| 31 | `Gahu` → goes to "Gahuiyeh, Kerman" (Iranian village) | **Ladzekpo / CNMAT archive** or **Mustapha Tettey Addy** – https://cnmat.berkeley.edu/library/cdr/ewa or drop for another drum tradition | +| 52 | `moma.org/s/ge/curated_ge/styles/list_ge/artists/1191/` → Page not found | **MoMA — Notations (1969) catalog**: https://www.moma.org/calendar/exhibitions/3282 | + +## graphic-score canon — swap to ubuweb, monoskop, foundations + +| # | wiki | primary | +|---|---|---| +| 38 | Treatise (Cardew) | **Monoskop — Cornelius Cardew**: https://monoskop.org/Cornelius_Cardew | +| 39 | Fontana Mix | **UbuWeb — Cage Fontana Mix**: https://www.ubu.com/sound/cage.html | +| 40 | Aria (Cage) | **UbuWeb — Cage Aria**: https://www.ubu.com/film/cage_aria.html | +| 41 | Concert for Piano and Orchestra (Cage) | **Edition Peters — Cage Concert**: https://www.edition-peters.com/product/concert-for-piano-and-orchestra/ep6705 | +| 42 | Variations I (Cage) | **UbuWeb — Cage Variations**: https://www.ubu.com/historical/cage/ | +| 43 | December 1952 (Earle Brown) | **Earle Brown Music Foundation**: https://earle-brown.org | +| 44 | Morton Feldman | **CNVill Feldman archive**: https://cnvill.net/mfhome.htm | +| 45 | Christian Wolff | **CNVill Wolff archive**: https://cnvill.net/mfwolff.htm | +| 46 | Artikulation (Ligeti) | **UbuWeb — Wehinger listening score video**: https://www.ubu.com/film/wehinger_artikulation.html | +| 47 | Metastaseis (Xenakis) | **Iannis Xenakis site / CIX**: https://www.iannis-xenakis.org | +| 48 | Sonic Meditations (Oliveros) | **Pauline Oliveros Foundation / Deep Listening**: https://deeplistening.rpi.edu | +| 49 | I Am Sitting in a Room | **UbuWeb — Lucier**: https://www.ubu.com/sound/lucier.html | +| 50 | In C (Riley) | **Terry Riley**: https://terryriley.net | +| 51 | Composition 1960 (La Monte Young) | **Mela Foundation**: https://www.melafoundation.org | +| 53 | Notations 21 | **Mark Batty / Theresa Sauer**: https://www.notations21.com (or author site) | + +## fluxus / event scores + +| # | wiki | primary | +|---|---|---| +| 32 | Grapefruit (Yoko Ono) | **imagine-peace.com / Ono Grapefruit scans on Monoskop**: https://monoskop.org/images/c/c7/Ono_Yoko_Grapefruit_1971.pdf | +| 34 | Dick Higgins | **Something Else Press archive / Estate of Dick Higgins**: http://www.dickhiggins.org | +| 35 | An Anthology of Chance Operations | **Monoskop**: https://monoskop.org/An_Anthology_of_Chance_Operations | +| 36 | Alison Knowles | **aknowles.com** (primary): https://www.aknowles.com | + +## vernacular / folk notation + +| # | wiki | primary | +|---|---|---| +| 24 | Shape note | **Fasola.org — Sacred Harp Musical Heritage**: https://fasola.org | +| 25 | Sacred Harp | **Sacred Harp Publishing Co.**: https://originalsacredharp.com | +| 26 | Tablature | **Lute Society of America**: https://lutesocietyofamerica.org (or guitar tablature primary source?) | +| 27 | Neume | **Gregobase — Gregorian chant notation**: https://gregobase.selapa.net | +| 28 | Jianpu | consider dropping, or: **Zhu Zaiyu / historical primer**; no strong primary online | +| 29 | Gongche notation | consider dropping, or a Kunqu / Peking opera archive link | +| 30 | Sargam | **ITC Sangeet Research Academy**: https://www.itcsra.org | + +## body / movement notation + +| # | wiki | primary | +|---|---|---| +| 14 | Labanotation | **Dance Notation Bureau**: https://dancenotation.org | +| 15 | Eshkol–Wachman | **Noa Eshkol Foundation**: https://www.noaeshkol.org | +| 16 | Benesh | **Royal Academy of Dance — Benesh**: https://www.royalacademyofdance.org/benesh | +| 17 | Kata | **JKA — Japan Karate Association / kata catalog**: https://jka.or.jp | +| 18 | American football plays | **Walsh's West Coast Offense playbook scans / NFL Coaches' resources** — or drop for a Bill Walsh interview | + +## sport / line + +| # | wiki | primary | +|---|---|---| +| 19 | Skateboarding | **Thrasher Mag**: https://www.thrashermagazine.com | +| 20 | Dogtown and Z-Boys | **Stacy Peralta / Z-Boys documentary**: https://www.imdb.com/title/tt0275309/ or https://www.dogtownskateboards.com | +| 21 | Surf break | **Surfline**: https://www.surfline.com | +| 22 | Yardage book | **StrackaLine — modern yardage-book publisher**: https://strackaline.com | +| 23 | Parkour | **ADAPT / parkour UK governing body**: https://parkour.uk | + +## instructional / craft + +| # | wiki | primary | +|---|---|---| +| 6 | Knitting abbreviations | **Craft Yarn Council standards**: https://www.craftyarncouncil.com/standards/knit-abbreviations | +| 7 | Crease pattern | **Erik Demaine — origami and folding**: https://erikdemaine.org/origami | +| 9 | Sewing pattern | **McCall's / Vogue pattern archive**: https://mccall.com | +| 10 | IKEA | **IKEA assembly instructions library**: https://www.ikea.com/us/en/customer-service/services/assembly | +| 11 | Lego | **LEGO building instructions archive**: https://www.lego.com/en-us/service/buildinginstructions | +| 12 | Julia Child | **WGBH — The French Chef / American Archive of Public Broadcasting**: https://americanarchive.org/catalog?q=julia+child | +| 13 | Japanese tea ceremony | **Urasenke**: https://www.urasenke.or.jp | + +## viral / social kin + +| # | current | primary | +|---|---|---| +| 2 | Harlem Shake (meme) | **Filthy Frank original video**: https://www.youtube.com/watch?v=384IUU43bfQ | +| 3 | Know Your Meme — Squidward (404!) | **Squidward tutorial original video** (YouTube search needed) | +| 4 | Pictogram | **Otl Aicher — Munich '72 pictogram archive**: https://www.designreviewed.com/otl-aicher-munich-1972 | +| 5 | ISOTYPE | **Otto Neurath / Gerd Arntz Web Archive**: https://www.gerdarntz.org/isotype | + +## additional blocks to *add* (from whistlegraph.tex citations) + +these are specific, real, less cliché: + +- **Goodiepal — El Camino del Hardcore** (ALKU 83, 2012) — https://alku.org/alku-83 or discogs +- **Jacob Ciocci — "The Butterfly Effect / Rules Set You Free"** (Whistlegraph Zine, 2023) — zine catalog page if exists +- **Asher Penn — Sex Magazine**: https://sexmagazine.us +- **Dirt Magazine — "What is a Whistlegraph?"** (2023): https://dirt.fyi/article/2023/09/whistlegraph +- **Rhizome — First Look: The Longest Whistlegraph Ever**: https://rhizome.org/editorial/2022/sep/13/first-look-the-longest-whistlegraph-ever-so-far +- **Feral File — Ten Whistlegraphs exhibition page**: https://feralfile.com/exhibitions/ten-whistlegraphs-thv +- **Schloss-Post — Manifesto for Radical Digital Painting** (2017): https://schloss-post.com/manifesto-radical-digital-painting +- **Creative Independent — "Drawing is the Best Videogame"** (2019): https://thecreativeindependent.com/weekends/drawing-is-the-best-videogame-by-jeffrey-alan-scudder +- **Paper Rad** (Jacob Ciocci): http://www.paperrad.org + +## execution plan + +1. `gigs/are-na-annual-vol-8/swap-sources.mjs` — read approved swaps, for each: delete old block from channel, post new URL with same description +2. keep positions stable — post in reverse reading order so nothing rearranges +3. text blocks (§9 framing, §6 Ono quote) are untouched — they're already primary + +## what the `nearby` validator can't tell us without a token + +are.na's `/v2/search/blocks` requires auth. once `ARENA_TOKEN` is exported, re-run `node validate-sources.mjs` and it will surface which URLs already have dozens of connections on are.na — those are the de-facto primaries. diff --git a/gigs/are-na-annual-vol-8/validate-sources.mjs b/gigs/are-na-annual-vol-8/validate-sources.mjs new file mode 100644 index 000000000..5730b17bf --- /dev/null +++ b/gigs/are-na-annual-vol-8/validate-sources.mjs @@ -0,0 +1,168 @@ +#!/usr/bin/env node +// Validate the blocks in "the-score-that-teaches-itself": +// - flag every Wikipedia link (we want primary sources) +// - for each block, search are.na for existing uses of the same URL +// and of the topic name — so we can see what other people +// are connecting to for the same idea (usually the real source) +// +// Usage: +// ARENA_TOKEN=... node validate-sources.mjs # all blocks +// ARENA_TOKEN=... node validate-sources.mjs --wiki # wiki only +// ARENA_TOKEN=... node validate-sources.mjs --json > report.json +// +// ARENA_TOKEN is optional but greatly raises rate limits. + +const SLUG = "the-score-that-teaches-itself"; +const TOKEN = process.env.ARENA_TOKEN; +const API = "https://api.are.na/v2"; + +const args = new Set(process.argv.slice(2)); +const WIKI_ONLY = args.has("--wiki"); +const JSON_OUT = args.has("--json"); + +const headers = TOKEN + ? { Authorization: `Bearer ${TOKEN}` } + : {}; + +async function j(url) { + const r = await fetch(url, { headers }); + if (!r.ok) throw new Error(`${r.status} ${r.statusText} — ${url}`); + return r.json(); +} + +function isWiki(url) { + return url && /wikipedia\.org/i.test(url); +} + +function hostOf(url) { + try { return new URL(url).hostname.replace(/^www\./, ""); } catch { return ""; } +} + +// Pull a short topic phrase out of a title like "Treatise (Cardew) - Wikipedia" +function topicOf(title) { + if (!title) return ""; + return title + .replace(/\s*[-–—|]\s*Wikipedia.*$/i, "") + .replace(/^\s+|\s+$/g, ""); +} + +// Search are.na for any blocks whose source matches the URL (or title) +// Returns an array of { url, host, count, sample: [{channelSlug, user}] } +async function searchSimilar(block) { + const out = { exact: [], nearby: [] }; + const url = block.source?.url; + const topic = topicOf(block.title) || block.generated_title || ""; + // 1) exact URL — search /search/blocks for the URL itself + if (url) { + try { + const q = encodeURIComponent(url); + const r = await j(`${API}/search/blocks?q=${q}&per=10`); + for (const b of r.blocks || []) { + if (b.source?.url === url) { + out.exact.push({ + id: b.id, + title: b.title || b.generated_title, + url: b.source.url, + connections: b.connections_count || 0, + }); + } + } + } catch (e) { out.err = e.message; } + } + // 2) topic phrase — find the most-connected non-wiki blocks for the same idea + if (topic) { + try { + const q = encodeURIComponent(topic); + const r = await j(`${API}/search/blocks?q=${q}&per=20`); + const seen = new Set(); + for (const b of r.blocks || []) { + const bu = b.source?.url; + if (!bu) continue; + if (seen.has(bu)) continue; + seen.add(bu); + if (bu === url) continue; + if (isWiki(bu)) continue; + out.nearby.push({ + url: bu, + host: hostOf(bu), + title: b.title || b.generated_title, + connections: b.connections_count || 0, + }); + } + out.nearby.sort((a, b) => b.connections - a.connections); + out.nearby = out.nearby.slice(0, 5); + } catch (e) { out.err = (out.err || "") + "; " + e.message; } + } + return out; +} + +function fmtReport(rows) { + const lines = []; + for (const row of rows) { + const flag = row.isWiki ? "🟡 WIKI" : "⚪ primary"; + const url = row.url || "(text)"; + const host = hostOf(url) || "—"; + lines.push(`\n#${row.position} ${flag} [${host}]`); + lines.push(` title : ${row.title || row.content?.slice(0, 80) || "(empty)"}`); + lines.push(` url : ${url}`); + lines.push(` desc : ${(row.description || "").slice(0, 100)}`); + if (row.sim) { + if (row.sim.exact?.length) { + lines.push(` ↳ already on are.na: ${row.sim.exact.length} exact block(s), top connections: ${row.sim.exact.slice(0, 3).map(e => e.connections).join("/")}`); + } else if (url) { + lines.push(` ↳ not on are.na (exact URL) — fresh`); + } + if (row.sim.nearby?.length) { + lines.push(` ↳ alternate sources people connect for this topic:`); + for (const n of row.sim.nearby) { + lines.push(` • [${n.host}] ${n.connections}× conn — ${n.url}`); + } + } + } + } + return lines.join("\n"); +} + +async function main() { + console.error(`fetching /channels/${SLUG}/contents …`); + const ch = await j(`${API}/channels/${SLUG}/contents?per=100&direction=desc`); + const blocks = ch.contents || []; + console.error(`got ${blocks.length} blocks${TOKEN ? "" : " (unauthed, rate limits apply)"}\n`); + + const rows = []; + for (const b of blocks) { + const url = b.source?.url; + const row = { + position: b.position, + class: b.class, + title: b.title, + content: b.content, + description: b.description, + url, + isWiki: isWiki(url), + }; + if (WIKI_ONLY && !row.isWiki) { rows.push(row); continue; } + if (b.class === "Link") { + try { + row.sim = await searchSimilar(b); + process.stderr.write("."); + } catch (e) { + row.simErr = e.message; + process.stderr.write("x"); + } + await new Promise(r => setTimeout(r, 400)); // gentle rate limit + } + rows.push(row); + } + console.error("\n"); + + if (JSON_OUT) { + console.log(JSON.stringify({ channel: SLUG, at: new Date().toISOString(), rows }, null, 2)); + } else { + console.log(fmtReport(rows)); + const wikiCount = rows.filter(r => r.isWiki).length; + console.log(`\n\nsummary: ${rows.length} blocks · ${wikiCount} wikipedia link(s) flagged for swap`); + } +} + +main().catch(e => { console.error("error:", e.message); process.exit(1); });