From 69d6b370b2e395d0ffd23f244653fb8a299c44ea Mon Sep 17 00:00:00 2001 From: Marcus Date: Wed, 14 Jan 2026 15:51:56 -0600 Subject: [PATCH] Add gopher documentation to README and execution notes - Update README with gopher/phlog section, publishing commands, URLs, and first-time SDF setup instructions - Add gopher workflow documentation to execution-notes.txt - Include planning docs in docs/ directory --- README.md | 59 ++- docs/gopher-code-review.md | 224 ++++++++++ docs/gopher-integration-plan.md | 697 ++++++++++++++++++++++++++++++++ scripts/execution-notes.txt | 43 ++ 4 files changed, 1019 insertions(+), 4 deletions(-) create mode 100644 docs/gopher-code-review.md create mode 100644 docs/gopher-integration-plan.md diff --git a/README.md b/README.md index 62afa28..4c0c949 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # marcus-web -Personal blog powered by Hugo. Many references to I Saw The TV Glow its a fantastic movie. +Personal blog powered by Hugo with gopher/phlog support. Many references to I Saw The TV Glow its a fantastic movie. ## Clone @@ -9,7 +9,7 @@ git clone ssh://git@git.sdf.org/mnw/marcus-web.git cd marcus-web ``` -## Setup Scripts +## Setup ```bash ./scripts/setup.sh @@ -34,6 +34,57 @@ python scripts/new_lunajuice.py python scripts/new_techpost.py ``` -## Build +## Publishing -Hugo builds happen on SDF, but using this repo and the scripts I can work on it locally where I am. +```bash +# Hugo site only +./scripts/remote_publish.sh + +# Hugo + Gopher +./scripts/remote_publish.sh --gopher + +# Gopher only +./scripts/remote_publish.sh --gopher-only +``` + +Hugo builds happen on SDF via git pull. Gopher content is built locally and rsynced to `~/gopher/blog/`. + +## Gopher / Phlog + +Posts can be published to SDF gopherspace by adding `phlog: true` to the frontmatter: + +```yaml +--- +title: 'My Post' +phlog: true +--- +``` + +### First-Time Gopher Setup on SDF + +Before the first gopher deploy, make sure the `blog/` directory exists on SDF: + +```bash +ssh mnw@sdf.org "mkdir -p ~/gopher/blog" +``` + +Then run the initial deploy: + +```bash +./scripts/remote_publish.sh --gopher-only +``` + +### Gopher URLs + +| Location | URL | +|----------|-----| +| Gopher root | `gopher://sdf.org/1/users/mnw/` | +| Blog index | `gopher://sdf.org/1/users/mnw/blog/` | +| Frank's Couch | `gopher://sdf.org/1/users/mnw/blog/franks-couch/` | +| Fun Center | `gopher://sdf.org/1/users/mnw/blog/fun-center/` | +| Web proxy | [Floodgap Proxy](https://gopher.floodgap.com/gopher/gw?a=gopher://sdf.org/1/users/mnw/) | + +### References + +- [SDF Gopher Setup](https://wiki.sdf.org/doku.php?id=gopher_site_setup_and_hosting_features) +- [Tilde.town Gopher Guide](https://tilde.town/wiki/editing-your-homepage/gopher.html) diff --git a/docs/gopher-code-review.md b/docs/gopher-code-review.md new file mode 100644 index 0000000..c0cffd4 --- /dev/null +++ b/docs/gopher-code-review.md @@ -0,0 +1,224 @@ +# Gopher Integration Code Review + +> **Date:** 2026-01-13 +> **Reviewer:** Claude (Opus 4.5) +> **Status:** Ready for deployment + +--- + +## Summary + +Implementation of gopher integration for marcus-web is complete. The system converts Hugo blog posts with `phlog: true` frontmatter to gopher-friendly plain text and deploys them to SDF gopherspace. + +**7 commits total** | **All tests passing** | **1 critical bug found and fixed** + +--- + +## Files Created + +### scripts/gopher/ascii_art.py +ASCII art assets and helper functions for gopher content. + +**Contents:** +- Post header (MNW owl logo) +- Category headers (Fun Center, Frank's Couch, Beercalls) +- Post footer (SDF box) +- Series-to-directory mapping +- Movie metadata ASCII table generator +- Text wrapping utilities + +**Review:** Clean, well-organized. All art fits within 70-char line width constraint. + +--- + +### scripts/gopher/convert_to_gopher.py +Main conversion script: markdown to gopher text. + +**Key functions:** +- `parse_frontmatter()` - YAML extraction +- `extract_links()` - Converts `[text](url)` to `text [1]` with footer references +- `convert_headings()` - `#` → section headers, `##` → subheadings +- `convert_formatting()` - `**bold**` → `*bold*`, `*italic*` → `_italic_` +- `convert_code_blocks()` - Fenced blocks → 4-space indented +- `handle_imdbposter()` - Hugo shortcode → ASCII movie table +- `wrap_paragraphs()` - 70-char line wrapping + +**Review:** Solid implementation. Handles edge cases well. The imdbposter conversion extracts viewing info tables and preserves them as plain text. + +**Fixed bug:** Added `sys.path.insert()` for imports to work when called from shell script. + +--- + +### scripts/gopher/generate_gophermaps.py +Generates gophermap index files for categories. + +**Outputs:** +- `blog/gophermap` - Main index with category links and post counts +- `blog/fun-center/gophermap` - Tech posts listing +- `blog/franks-couch/gophermap` - Movie reviews listing +- `blog/beercalls/gophermap` - Beer logs listing (when posts exist) + +**Review:** Properly formats gophermap syntax with tab-separated fields. Sorts posts by date (newest first). Includes ASCII art headers per category. + +**Fixed bug:** Same `sys.path` fix as convert_to_gopher.py. + +--- + +### scripts/gopher/update_root_gophermap.py +Generates updated root gophermap with "FROM THE WEB" section. + +**Review:** Contains full gophermap template. One-time use script for initial setup. Includes dynamic `=echo` directives for latest post detection. + +**Note:** This needs to be run manually after first deployment: +```bash +python3 scripts/gopher/update_root_gophermap.py +scp gopher_build/gophermap mnw@sdf.org:~/gopher/gophermap +``` + +--- + +## Files Modified + +### scripts/remote_publish.sh +Added `--gopher` and `--gopher-only` flags. + +**Changes:** +- Argument parsing with help text +- Conditional Hugo deployment (skipped with `--gopher-only`) +- Gopher build: runs convert + generate scripts locally +- rsync with `--delete` to sync to SDF +- Permission fixing on remote (644 files, 755 dirs) + +**Review:** Good error handling via `set -e`. Clear output messages. The `--delete` flag means removing `phlog: true` from a post will remove it from gopher on next deploy. + +--- + +### scripts/new_techpost.py +Added phlog prompt after summary input. + +**Changes:** +- New prompt: "Publish to gopher phlog? (y/N)" +- Added `phlog` parameter to `create_post()` +- Frontmatter now includes `phlog: true/false` + +**Review:** Clean integration. Defaults to "no" which is appropriate. + +--- + +### scripts/import_letterboxd.py +Added phlog prompt after viewing details. + +**Changes:** +- Prompt added in `import_movie()` function +- `phlog` parameter passed to `create_draft_post()` +- Frontmatter updated + +**Review:** Good placement - asks after all other inputs are collected. + +--- + +### scripts/new_movie.py +Added phlog prompt after TMDB fetch. + +**Changes:** +- Same pattern as other scripts +- Frontmatter includes phlog field + +**Review:** Consistent with other scripts. + +--- + +### .gitignore +Added `gopher_build/` to ignore list. + +--- + +### requirements.txt +Added `pyyaml` dependency. + +--- + +## Content Changes + +Three posts enabled for gopher with `phlog: true`: +- `content/posts/blog-posting.md` (Fun Center) +- `content/posts/recovering-failed-ubuntu-upgrade.md` (Fun Center) +- `content/posts/megalopolis.md` (Frank's Couch) + +--- + +## Bug Found and Fixed + +### Critical: Import Path Issue + +**Problem:** `from ascii_art import ...` failed when scripts were invoked from `remote_publish.sh` because Python couldn't find the module. + +**Root cause:** When running `python3 scripts/gopher/convert_to_gopher.py` from the project root, Python's working directory doesn't include `scripts/gopher/`. + +**Fix:** Added to both convert and generate scripts: +```python +import sys +from pathlib import Path +sys.path.insert(0, str(Path(__file__).parent)) +``` + +**Commit:** `b5bb06e` + +--- + +## Minor Issues Fixed + +1. **No-op regex removed** - `re.sub(r"_([^_]+)_", r"_\1_", text)` did nothing +2. **Unused variable removed** - `in_code_block = False` was never used + +--- + +## Testing Performed + +1. **Conversion test:** `python3 scripts/gopher/convert_to_gopher.py --all` - 3 posts converted +2. **Gophermap test:** `python3 scripts/gopher/generate_gophermaps.py` - All maps generated +3. **Output verification:** Manually inspected generated .txt files and gophermaps +4. **Import fix verification:** Re-ran after fix, all working + +--- + +## Deployment Checklist + +- [ ] `git push` to sync with origin +- [ ] Run `./scripts/remote_publish.sh --gopher` for first deployment +- [ ] Run `python3 scripts/gopher/update_root_gophermap.py` to generate root map +- [ ] `scp gopher_build/gophermap mnw@sdf.org:~/gopher/gophermap` to update root +- [ ] Verify at `gopher://sdf.org/1/users/mnw/blog/` +- [ ] Test via web proxy: https://gopher.floodgap.com/gopher/gw?a=gopher://sdf.org/1/users/mnw/blog/ + +--- + +## Future Considerations + +1. **Beercalls:** No beercall posts have `phlog: true` yet. The category exists but is empty. + +2. **Movie metadata:** The `megalopolis.md` post doesn't have `year`, `director`, `runtime`, or `genres` in frontmatter, so the ASCII movie table only shows title and web link. Consider backfilling metadata for better gopher output. + +3. **Link handling:** External links become numbered references. Very long URLs may look awkward in the links section but are functional. + +4. **Line wrapping:** Code blocks preserve formatting. Very long single words won't wrap (expected behavior). + +--- + +## Commit History + +``` +b5bb06e Fix import path issue in gopher scripts +2f20e02 Add pyyaml to requirements.txt (Phase 6) +96e350c Add phlog: true to existing posts for gopher (Phase 5) +2941c7b Add phlog prompt to post creation scripts (Phase 4) +99495eb Add gopher deployment to remote_publish.sh (Phase 3) +468d238 Add gophermap generation scripts (Phase 2) +c4c18ed Add gopher integration core infrastructure (Phase 1) +``` + +--- + +## Verdict + +**Ready for deployment.** All functionality implemented per the integration plan. One critical bug was found during review and fixed. Code is clean, well-structured, and tested. diff --git a/docs/gopher-integration-plan.md b/docs/gopher-integration-plan.md new file mode 100644 index 0000000..73657ab --- /dev/null +++ b/docs/gopher-integration-plan.md @@ -0,0 +1,697 @@ +# Gopher Integration Plan + +> **Status:** Planning +> **Created:** 2025-01-13 +> **Goal:** Publish Hugo blog posts to SDF gopherspace with `phlog: true` frontmatter flag + +--- + +## Overview + +Enhance the marcus-web project to deploy selected blog posts to both the Hugo site (mnw.sdf.org) and the SDF gopherspace (gopher://sdf.org/1/users/mnw/). Posts are opted-in via frontmatter, converted from markdown to gopher-friendly plain text, and organized by series/category. + +--- + +## Current State + +### Hugo Site (mnw.sdf.org) +- **Series:** "Frank's Couch" (movies), "Fun Center" (tech), beercall content +- **Frontmatter:** title, date, series, summary, tags, draft +- **Deploy:** `remote_publish.sh` → SSH to SDF → git pull && hugo && mkhomepg -p + +### Existing Gopherspace (/sdf/arpa/gm/m/mnw/gopher) +- Rich structure with ASCII art headers and footers +- Categories as directories: `journal/`, `older/`, `LISA19/`, `hope_2024/`, etc. +- Dynamic CGI: latest phlog, user info via `=echo` directives +- Template style established in `templates/phlogpost.txt` + +--- + +## Design Decisions + +| Decision | Choice | Rationale | +|----------|--------|-----------| +| Opt-in mechanism | `phlog: true` frontmatter | Explicit control per post | +| Category mapping | Hugo series → gopher directories | Natural organization | +| Beercall handling | One gopher file per year | Matches existing yearly logs | +| Movie poster | Link to web blog post | Gopher can't display images | +| Movie metadata | ASCII table | Old-school aesthetic | +| ASCII art headers | Category-specific art | Visual distinction, same size as current | +| Root gophermap | Script-managed with makeover | Cohesive, automated experience | +| Sync strategy | rsync with --delete | Git-tracked, reversible | + +--- + +## Directory Structure + +### On SDF (~/gopher aka /sdf/arpa/gm/m/mnw/gopher) + +``` +~/gopher/ +├── gophermap # Root menu (UPDATED by script) +├── journal/ # Existing daily phlogs +├── older/ # Existing historical +├── LISA19/ # Existing conference notes +├── hope_2024/ # Existing conference notes +├── blog/ # NEW: Hugo-sourced content +│ ├── gophermap # Blog index +│ ├── franks-couch/ # Movie reviews +│ │ ├── gophermap # Category index with summaries +│ │ ├── megalopolis.txt +│ │ ├── joker-folie-a-deux.txt +│ │ └── ... +│ ├── fun-center/ # Tech posts +│ │ ├── gophermap +│ │ ├── is-it-me.txt +│ │ └── ... +│ └── beercalls/ # Yearly beer logs +│ ├── gophermap +│ ├── 2023.txt +│ └── 2024.txt +└── templates/ # Existing templates +``` + +### Local Build Directory + +``` +marcus-web/ +├── gopher_build/ # Staging area (gitignored) +│ └── blog/ +│ ├── gophermap +│ ├── franks-couch/ +│ ├── fun-center/ +│ └── beercalls/ +``` + +--- + +## Frontmatter Extension + +Add `phlog` field to any post: + +```yaml +--- +title: 'Megalopolis' +date: 2024-10-05T00:03:15Z +draft: false +series: "Frank's Couch" +summary: "A sprawling mess of ambition" +phlog: true # <-- NEW: publish to gopher +imdb: "tt10128846" +poster: "/images/posters/megalopolis.jpg" +year: 2024 +runtime: 138 +director: "Francis Ford Coppola" +genres: + - Drama + - Sci-Fi +tags: + - alamo-drafthouse +--- +``` + +**Behavior:** +- `phlog: true` → Convert and deploy to gopher +- `phlog: false` or absent → Hugo only (web exclusive) + +--- + +## Content Conversion + +### Markdown → Gopher Text + +| Markdown | Gopher | +|----------|--------| +| `# Heading` | `═══════════════════════════════════════`
` HEADING`
`═══════════════════════════════════════` | +| `## Subheading` | `--- Subheading ---` | +| `**bold**` | `*bold*` | +| `*italic*` | `_italic_` | +| `[text](url)` | `text [1]` + links section at bottom | +| `{{< imdbposter >}}` | ASCII metadata table (see below) | +| Code blocks | Preserve, indent 4 spaces | +| `---` (hr) | `────────────────────────────────────────` | + +### Line Wrapping +- Wrap at 70 characters +- Preserve code block formatting +- Handle URLs gracefully (collect for footer) + +### Movie Metadata Table + +Convert the `{{< imdbposter >}}` shortcode to ASCII table: + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ MEGALOPOLIS (2024) │ +├─────────────────────────────────────────────────────────────────┤ +│ Director: Francis Ford Coppola │ +│ Runtime: 138 minutes │ +│ Genres: Drama, Sci-Fi │ +│ │ +│ View on web: https://mnw.sdf.org/posts/megalopolis/ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +--- + +## ASCII Art Headers + +Each category gets unique ASCII art. Size constraint: **No larger than current template (~12 lines max)**. + +### Fun Center (Tech) + +``` + ___ ___ _ + | __| _ _ _ / __|___ _ _| |_ ___ _ _ + | _| || | ' \ | (__/ -_) ' \ _/ -_) '_| + |_| \_,_|_||_| \___\___|_||_\__\___|_| + + Tech posts from the Double Lunch Dispatch +``` + +### Frank's Couch (Movies) + +``` + ___ _ _ ___ _ + | __| _ __ _ _ _| |_( )___ / __|___ _ _ __| |_ + | _| '_/ _` | ' \ / /|_-< | (__/ _ \ || (_-< ' \ + |_||_| \__,_|_||_\_\ /__/ \___\___/\_,_/__/_||_| + + Movie reviews from the couch +``` + +### Beercalls (Beer) + +``` + ___ _ _ + | _ ) ___ ___ _ _ __ __ _| | |___ + | _ \/ -_) -_) '_/ _/ _` | | (_-< + |___/\___\___|_| \__\__,_|_|_/__/ + + Thursday night adventures in Austin +``` + +### Blog Index + +``` + ___ _ ___ _ _ + | _ )| |___ __ | __|_ _ | |_ _ _ (_)___ ___ + | _ \| / _ \/ _|| _|| ' \| _| '_|| / -_|_-< + |___/|_\___/\__||___|_||_|\__|_| |_\___/__/ + + Posts from mnw.sdf.org +``` + +--- + +## Gophermap Formats + +### Category Gophermap (e.g., `blog/franks-couch/gophermap`) + +``` +i ___ _ _ ___ _ fake (NULL) 0 +i | __| _ __ _ _ _| |_( )___ / __|___ _ _ __| |_ fake (NULL) 0 +i | _| '_/ _` | ' \ / /|_-< | (__/ _ \ || (_-< ' \ fake (NULL) 0 +i |_||_| \__,_|_||_\_\ /__/ \___\___/\_,_/__/_||_| fake (NULL) 0 +i fake (NULL) 0 +i Movie reviews from the couch fake (NULL) 0 +i fake (NULL) 0 +i──────────────────────────────────────────────────── fake (NULL) 0 +i fake (NULL) 0 +0[2024-10-05] Megalopolis megalopolis.txt +i A sprawling mess of ambition fake (NULL) 0 +i fake (NULL) 0 +0[2024-10-07] Joker: Folie a Deux joker-folie-a-deux.txt +i Not what you'd expect fake (NULL) 0 +i fake (NULL) 0 +0[2024-10-12] Terrifier 3 terrifier-3.txt +i Art the Clown returns fake (NULL) 0 +i fake (NULL) 0 +i──────────────────────────────────────────────────── fake (NULL) 0 +1Back to Blog Index ../ +1Back to Main Menu /users/mnw/ +``` + +### Blog Index Gophermap (`blog/gophermap`) + +``` +i ___ _ ___ _ _ fake (NULL) 0 +i | _ )| |___ __ | __|_ _ | |_ _ _ (_)___ ___ fake (NULL) 0 +i | _ \| / _ \/ _|| _|| ' \| _| '_|| / -_|_-< fake (NULL) 0 +i |___/|_\___/\__||___|_||_|\__|_| |_\___/__/ fake (NULL) 0 +i fake (NULL) 0 +i Posts from mnw.sdf.org fake (NULL) 0 +i The Double Lunch Dispatch fake (NULL) 0 +i fake (NULL) 0 +i──────────────────────────────────────────────── fake (NULL) 0 +i fake (NULL) 0 +1Frank's Couch - Movie Reviews franks-couch/ +i X posts about films watched from the couch fake (NULL) 0 +i fake (NULL) 0 +1Fun Center - Tech Posts fun-center/ +i X posts about technology and open source fake (NULL) 0 +i fake (NULL) 0 +1Beercalls - Thursday Night Adventures beercalls/ +i Yearly logs of Austin beer adventures fake (NULL) 0 +i fake (NULL) 0 +i──────────────────────────────────────────────── fake (NULL) 0 +hView on the web URL:https://mnw.sdf.org/posts/ +1Back to Main Menu /users/mnw/ +``` + +--- + +## Root Gophermap Makeover + +Update the main gophermap to incorporate blog content while preserving existing sections. + +### Proposed Structure + +``` +i fake (NULL) 0 +i ''~`` fake (NULL) 0 +i ( o o ) fake (NULL) 0 +i+-------------------.oooO--(_)--Oooo.---------------+ fake (NULL) 0 +i| | fake (NULL) 0 +i| THE DOUBLE LUNCH DISPATCH | fake (NULL) 0 +i| mnw @ sdf | fake (NULL) 0 +i| | fake (NULL) 0 +i+---------------------------------------------------+ fake (NULL) 0 +i fake (NULL) 0 +imnw(at)sdf.org | SDF VOIP Ext. 1908 fake (NULL) 0 +i fake (NULL) 0 +i═══════════════════════════════════════════════════ fake (NULL) 0 +i DAILY PHLOGS fake (NULL) 0 +i═══════════════════════════════════════════════════ fake (NULL) 0 +i fake (NULL) 0 +1Daily Journal journal/ +=echo "0Latest Entry journal/`ls -t journal/ | grep -v gophermap | head -1`" +1Historical Phlogs (2018-2019) older/ +i fake (NULL) 0 +i═══════════════════════════════════════════════════ fake (NULL) 0 +i FROM THE WEB fake (NULL) 0 +i═══════════════════════════════════════════════════ fake (NULL) 0 +i fake (NULL) 0 +iPosts from mnw.sdf.org fake (NULL) 0 +i fake (NULL) 0 +1Blog Categories blog/ +=echo "0Latest Blog Post `find ~/gopher/blog -name '*.txt' -type f -printf '%T@ %p\n' 2>/dev/null | sort -rn | head -1 | awk '{print $2}' | sed 's|.*/gopher/||'`" +i fake (NULL) 0 +i═══════════════════════════════════════════════════ fake (NULL) 0 +i CONFERENCE NOTES fake (NULL) 0 +i═══════════════════════════════════════════════════ fake (NULL) 0 +i fake (NULL) 0 +iPhlogs from conferences (rough notes) fake (NULL) 0 +i fake (NULL) 0 +1HOPE 2024 hope_2024/ +1FOSSY 2024 fossy_2024/ +1LISA 2019 LISA19/ +1SeaGL 2019 seagl_2019/ +1Texas Linux Fest 2019 txlf_2019/ +1HOPE 2018 hope_2018/ +1SeaGL 2018 seagl_2018/ +i fake (NULL) 0 +i═══════════════════════════════════════════════════ fake (NULL) 0 +i OTHER THINGS fake (NULL) 0 +i═══════════════════════════════════════════════════ fake (NULL) 0 +i fake (NULL) 0 +1Comedy comedy/ +1Short Stories stories/ +i fake (NULL) 0 +i .oooO fake (NULL) 0 +i ( ) Oooo. fake (NULL) 0 +i+-------------------\ (----( )-----------------+ fake (NULL) 0 +i \_) ) / fake (NULL) 0 +i (_/ fake (NULL) 0 +i fake (NULL) 0 +iMy SDF User Info fake (NULL) 0 +=echo "`/usr/pkg/bin/uinfo mnw | tr -d '\-=><'`" +i fake (NULL) 0 +i __^__ __^__ fake (NULL) 0 +i( ___ )--------------------------------------------( ___ ) fake (NULL) 0 +i | / | This gopher space proudly hosted by SDF | \ | fake (NULL) 0 +i | / | mnw on pixelfed.social and tilde.zone | \ | fake (NULL) 0 +i |___| Web: mnw.sdf.org |___| fake (NULL) 0 +i(_____)--------------------------------------------(_____) fake (NULL) 0 +i fake (NULL) 0 +iThanks for reading! Enjoy an SDF oneliner: fake (NULL) 0 +=echo "`/usr/pkg/bin/oneliner | tr -d '\-=><'`" +``` + +--- + +## Post Template + +Each converted post follows this structure: + +``` + ___ ___ ___ + /\ \ /\ \ /\ \ + |::\ \ \:\ \ _\:\ \ + |:|:\ \ \:\ \ /\ \:\ \ + __|:|\:\ \ _____\:\ \ _\:\ \:\ \ + /::::|_\:\__\ /::::::::\__\ /\ \:\ \:\__\ + \:\~~\ \/__/ \:\~~\~~\/__/ \:\ \:\/:/ / + \:\ \ \:\ \ \:\ \::/ / + \:\ \ \:\ \ \:\/:/ / + \:\__\ \:\__\ \::/ / + \/__/ \/__/ \/__/ + +mnw(at)sdf.org | SDF VOIP Ext. 1908 + +──────────────────────────────────────────────────────────────────── + 2024-11-19 | Fun Center +──────────────────────────────────────────────────────────────────── + + IS IT ME? + Marcus shares his blog writing process. + +──────────────────────────────────────────────────────────────────── + +I've always loved talking to people. Whether it's at work, at +home, or out with friends, connecting with others and hearing +about their passions brings me so much joy. There's nothing +better than a conversation with someone excited to share what +they care about. + +[... content continues, wrapped at 70 characters ...] + + +═══════════════════════════════════════════════════════════════════ + LINKS +═══════════════════════════════════════════════════════════════════ + +[1] https://example.com/macwhisper +[2] https://openai.com/chatgpt + + + __^__ __^__ +( ___ )------------------------------------------------------( ___ ) + | / | | \ | + | / | This gopher space proudly hosted by SDF | \ | + | \ | mnw on pixelfed.social and tilde.zone | / | + | \ | | / | +(_____)------------------------------------------------------(_____) + +Web version: https://mnw.sdf.org/posts/is-it-me/ +``` + +--- + +## New Scripts + +### 1. `scripts/gopher/convert_to_gopher.py` + +**Purpose:** Convert Hugo markdown to gopher-formatted text + +**Usage:** +```bash +python scripts/gopher/convert_to_gopher.py content/posts/blog-posting.md +python scripts/gopher/convert_to_gopher.py --all +python scripts/gopher/convert_to_gopher.py --all --output gopher_build/ +``` + +**Responsibilities:** +- Parse YAML frontmatter +- Check `phlog: true` flag +- Determine output directory from series +- Convert markdown syntax +- Handle `{{< imdbposter >}}` → ASCII table +- Word wrap to 70 chars +- Apply header/footer templates +- Collect and format links section + +### 2. `scripts/gopher/generate_gophermaps.py` + +**Purpose:** Generate all gophermap files + +**Usage:** +```bash +python scripts/gopher/generate_gophermaps.py +python scripts/gopher/generate_gophermaps.py --output gopher_build/ +``` + +**Responsibilities:** +- Scan converted posts by category +- Generate category gophermaps with titles + summaries +- Generate blog index gophermap +- Count posts per category +- Sort by date (newest first) + +### 3. `scripts/gopher/ascii_art.py` + +**Purpose:** ASCII art assets and helper functions + +**Contents:** +- Category header art (Fun Center, Frank's Couch, Beercalls) +- Post header template (MNW owl) +- Footer template (SDF box) +- Section dividers +- ASCII table generator for movie metadata + +### 4. `scripts/gopher/update_root_gophermap.py` + +**Purpose:** Update the main gophermap with blog section + +**Usage:** +```bash +python scripts/gopher/update_root_gophermap.py +``` + +**Responsibilities:** +- Read existing root gophermap (preserve conference notes, etc.) +- Insert/update "FROM THE WEB" section +- Update dynamic CGI for latest blog post +- Optionally apply full makeover template + +--- + +## Modified Scripts + +### `scripts/remote_publish.sh` + +Add gopher deployment support: + +```bash +#!/bin/bash +# Remote publish script for marcus-web + +GOPHER=false +GOPHER_ONLY=false + +# Parse arguments +while [[ $# -gt 0 ]]; do + case $1 in + --gopher) + GOPHER=true + shift + ;; + --gopher-only) + GOPHER_ONLY=true + GOPHER=true + shift + ;; + *) + shift + ;; + esac +done + +# ... existing git/commit logic ... + +if [[ "$GOPHER_ONLY" != "true" ]]; then + # Existing Hugo deployment + ssh "$SDF_HOST" "cd $REMOTE_DIR && git pull && hugo && mkhomepg -p" + echo "Site is live at: https://mnw.sdf.org/" +fi + +if [[ "$GOPHER" == "true" ]]; then + echo -e "${GREEN}=== Deploying to Gopher ===${NC}" + + # Build gopher content locally + python scripts/gopher/convert_to_gopher.py --all --output gopher_build/blog/ + python scripts/gopher/generate_gophermaps.py --output gopher_build/blog/ + + # Sync to SDF (--delete removes posts where phlog was set to false) + rsync -avz --delete gopher_build/blog/ "$SDF_HOST:~/gopher/blog/" + + # Fix permissions on SDF + ssh "$SDF_HOST" "find ~/gopher/blog -type f -exec chmod 644 {} \; && find ~/gopher/blog -type d -exec chmod 755 {} \;" + + echo "Gopher updated at: gopher://sdf.org/1/users/mnw/blog/" +fi +``` + +### `scripts/new_techpost.py` + +Add phlog prompt: + +```python +# After getting summary... +phlog_input = input("\nPublish to gopher phlog? (y/N): ").strip().lower() +phlog = phlog_input == 'y' + +# In frontmatter: +content = f'''--- +title: '{title}' +date: {now} +draft: true +series: "Fun Center" +summary: "{summary}" +phlog: {str(phlog).lower()} +tags: +{tags_yaml} +--- +''' +``` + +### `scripts/new_movie.py` / `scripts/import_letterboxd.py` + +Same pattern - add phlog prompt after other inputs. + +--- + +## Deployment Workflow + +### Standard Deploy (Hugo only) +```bash +./scripts/remote_publish.sh +``` + +### Deploy Hugo + Gopher +```bash +./scripts/remote_publish.sh --gopher +``` + +### Deploy Gopher Only +```bash +./scripts/remote_publish.sh --gopher-only +``` + +### One-time Root Gophermap Update +```bash +# After first blog/ deployment +python scripts/gopher/update_root_gophermap.py +scp gopher_build/gophermap mnw@sdf.org:~/gopher/gophermap +``` + +--- + +## Implementation Order + +### Phase 1: Core Infrastructure +1. [ ] Create `scripts/gopher/` directory +2. [ ] Create `scripts/gopher/ascii_art.py` - All ASCII art assets +3. [ ] Create `scripts/gopher/convert_to_gopher.py` - Markdown conversion +4. [ ] Add `gopher_build/` to `.gitignore` + +### Phase 2: Gophermap Generation +5. [ ] Create `scripts/gopher/generate_gophermaps.py` - Category + index maps +6. [ ] Create `scripts/gopher/update_root_gophermap.py` - Root gophermap + +### Phase 3: Deployment Integration +7. [ ] Modify `scripts/remote_publish.sh` - Add --gopher flags +8. [ ] Test with single post locally + +### Phase 4: Post Creation Updates +9. [ ] Modify `scripts/new_techpost.py` - Add phlog prompt +10. [ ] Modify `scripts/import_letterboxd.py` - Add phlog prompt +11. [ ] Modify `scripts/new_movie.py` - Add phlog prompt (if separate) + +### Phase 5: Content & Testing +12. [ ] Add `phlog: true` to existing posts to backfill +13. [ ] Run full deployment to SDF +14. [ ] Verify gopher content via `gopher gopher://sdf.org/1/users/mnw/blog/` +15. [ ] Update root gophermap on SDF + +### Phase 6: Polish +16. [ ] Fine-tune ASCII art sizing +17. [ ] Adjust line wrapping edge cases +18. [ ] Document in README or execution-notes.txt + +--- + +## File Checklist + +### New Files +- [ ] `scripts/gopher/ascii_art.py` +- [ ] `scripts/gopher/convert_to_gopher.py` +- [ ] `scripts/gopher/generate_gophermaps.py` +- [ ] `scripts/gopher/update_root_gophermap.py` +- [ ] `gopher_build/` directory (gitignored) + +### Modified Files +- [ ] `scripts/remote_publish.sh` +- [ ] `scripts/new_techpost.py` +- [ ] `scripts/import_letterboxd.py` +- [ ] `.gitignore` (add gopher_build/) + +### Content Files (add phlog: true) +- [ ] `content/posts/blog-posting.md` +- [ ] `content/posts/recovering-failed-ubuntu-upgrade.md` +- [ ] Movie posts as desired +- [ ] Beercall yearly files as desired + +--- + +## URLs + +After deployment: + +| Type | URL | +|------|-----| +| Gopher root | `gopher://sdf.org/1/users/mnw/` | +| Blog index | `gopher://sdf.org/1/users/mnw/blog/` | +| Fun Center | `gopher://sdf.org/1/users/mnw/blog/fun-center/` | +| Frank's Couch | `gopher://sdf.org/1/users/mnw/blog/franks-couch/` | +| Beercalls | `gopher://sdf.org/1/users/mnw/blog/beercalls/` | +| Web proxy | `https://gopher.floodgap.com/gopher/gw?a=gopher://sdf.org/1/users/mnw/` | + +--- + +## References + +- SDF Gopher Setup: https://wiki.sdf.org/doku.php?id=gopher_site_setup_and_hosting_features +- SDF Web Spaces: https://wiki.sdf.org/doku.php?id=accessing_web_spaces#gopher +- Tilde.town Gopher Guide: https://tilde.town/wiki/editing-your-homepage/gopher.html +- Floodgap Gopher Proxy: https://gopher.floodgap.com/gopher/gw + +--- + +## Gophermap Quick Reference + +From tilde.town wiki - item types we'll use: + +| Code | Type | Usage | +|------|------|-------| +| `0` | Text file | Blog posts (.txt) | +| `1` | Directory | Category folders, navigation | +| `i` | Inline text | ASCII art, descriptions, spacing | +| `h` | HTML link | Link to web version (prefix with `URL:`) | +| `7` | Search | Future: search posts (CGI) | + +**Syntax:** `{type}{description}\t{path}\t{host}\t{port}` + +- Tab character separates columns +- Host/port optional for local resources +- For inline text (`i`): use `fake` as path, `(NULL)` as host, `0` as port +- For HTML links: path should be `URL:https://...` + +**Example entries:** +``` +i fake (NULL) 0 +0[2024-10-05] Megalopolis megalopolis.txt +1Back to Blog Index ../ +hView on web URL:https://mnw.sdf.org/posts/ +``` + +--- + +## Notes + +- Gophermaps must NOT have execute permission (causes errors) +- Files need 644, directories need 755 +- CGI scripts (=echo) must use full paths on SDF +- ASCII art should stay under 12 lines for headers +- The `--delete` flag on rsync will remove posts where `phlog` was changed to `false` +- All work is git-tracked, so deletions are recoverable diff --git a/scripts/execution-notes.txt b/scripts/execution-notes.txt index 11256f1..cd32c10 100644 --- a/scripts/execution-notes.txt +++ b/scripts/execution-notes.txt @@ -98,4 +98,47 @@ To block a reply: - "https://tilde.zone/@someone/123456789" +GOPHER / PHLOG (SDF Gopherspace) +-------------------------------- +Posts can be published to gopher by adding `phlog: true` to frontmatter. + +Deploy to gopher (after --gopher-only for first run, then use --gopher): + + ./scripts/remote_publish.sh --gopher # Hugo + Gopher + ./scripts/remote_publish.sh --gopher-only # Gopher only + +What it does: + 1. Converts posts with `phlog: true` to plain text (70 char wrap) + 2. Generates gophermaps for each category + 3. Rsyncs to ~/gopher/blog/ on SDF + +URLs after deployment: + - Gopher root: gopher://sdf.org/1/users/mnw/ + - Blog index: gopher://sdf.org/1/users/mnw/blog/ + - Frank's Couch: gopher://sdf.org/1/users/mnw/blog/franks-couch/ + - Fun Center: gopher://sdf.org/1/users/mnw/blog/fun-center/ + - Web proxy: https://gopher.floodgap.com/gopher/gw?a=gopher://sdf.org/1/users/mnw/ + +Gopher scripts (in scripts/gopher/): + - convert_to_gopher.py Markdown → gopher plain text + - generate_gophermaps.py Build category menus + - ascii_art.py Headers/footers + - update_root_gophermap.py Update main gophermap (one-time) + +References: + - SDF Gopher Setup: https://wiki.sdf.org/doku.php?id=gopher_site_setup_and_hosting_features + - Tilde.town Guide: https://tilde.town/wiki/editing-your-homepage/gopher.html + + +PUBLISHING / REMOTE DEPLOY +-------------------------- +Push changes to SDF and build: + + ./scripts/remote_publish.sh # Hugo only + ./scripts/remote_publish.sh --gopher # Hugo + Gopher + ./scripts/remote_publish.sh --gopher-only # Gopher only + +The script handles git commit/push prompts automatically. + + ================================================================================