{"id":51891430,"url":"https://github.com/coldbricks/paisley-ponytail","last_synced_at":"2026-07-26T04:30:24.201Z","repository":{"id":370325170,"uuid":"1186783089","full_name":"coldbricks/paisley-ponytail","owner":"coldbricks","description":"Paisley Ponytail — the Webshots Resurrector. Search your old screen name, get your photos back from the Internet Archive at full resolution.","archived":false,"fork":false,"pushed_at":"2026-07-08T23:06:39.000Z","size":1124,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-07-08T23:09:52.535Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/coldbricks.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-20T01:36:00.000Z","updated_at":"2026-07-08T23:06:43.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/coldbricks/paisley-ponytail","commit_stats":null,"previous_names":["coldbricks/webshots-resurrector"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/coldbricks/paisley-ponytail","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coldbricks%2Fpaisley-ponytail","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coldbricks%2Fpaisley-ponytail/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coldbricks%2Fpaisley-ponytail/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coldbricks%2Fpaisley-ponytail/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/coldbricks","download_url":"https://codeload.github.com/coldbricks/paisley-ponytail/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coldbricks%2Fpaisley-ponytail/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35901460,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-07-20T02:08:10.276Z","status":"online","status_checked_at":"2026-07-26T02:00:06.503Z","response_time":89,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-07-26T04:30:23.694Z","updated_at":"2026-07-26T04:30:24.194Z","avatar_url":"https://github.com/coldbricks.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Paisley Ponytail\n\n![Paisley Ponytail nose art](assets/nose_art.jpg)\n\n**The Webshots Resurrector — bring lost photos back to life.**\n\n*(Yes, the nose art is AI. I can dig your photos out of a 105.9 TB wreck or I can learn to paint. Pick one.)*\n\n[![Python 3.10+](https://img.shields.io/badge/python-3.10%2B-3c7a3c)](https://www.python.org/)\n[![License: MIT](https://img.shields.io/badge/license-MIT-3c7a3c)](LICENSE)\n![Megawarcs on frequency](https://img.shields.io/badge/on%20frequency-2%2C437%20megawarcs%20%2F%20105.9%20TB-1f3d1f)\n\n```\nATIS PPTY  ·  PYSLY-R90  ·  v2.1\nYou are an air traffic controller at the busiest air traffic control\nradar facility on the planet. Your traffic is deleted family photos.\nThe only person who can save them is you. Good luck. We're all counting on you.\n\nWINDOWS: double-click Start_Here.bat → TRAINING MODE, a simple guided wizard\n  Type a Webshots screen name in the GREEN BOX → SEARCH → PULL\n  PROFESSIONAL MODE (top right) turns on the entire facility:\n  sector gate, live weather brief, VSCS/ZWY panels, live ADS-B on the map\npython resurrector.py scope     # radar room\npython resurrector.py --cli     # terminal cab\npython resurrector.py pull NAME # headless recovery\n\nAVIATE · NAVIGATE · COMMUNICATE  ·  multiple plans · always an out\nPrivate albums never archived. Be kind to archive.org.\nBuilt on Archive Team + the Internet Archive.\n```\n\nWebshots hosted 14 million users' photos from 1995 until December 2012, when\nits final owner deleted everything. Archive Team scrambled an emergency crawl\nin the last weeks and hauled 105.9 TB into the Internet Archive. Then the\nextraction tooling died in 2016, and the wreckage sat locked in 2,437\nfifty-gigabyte WARC blobs for a decade. Nobody knows exactly how much of\nthose 14 million users made it in; the crawl caught whatever was still\npublic in the final weeks, and even the people who saved it have never\nfully cataloged what's inside.\n\nWhether you're about to solve a 20-year-old mystery or surfing for the most\ndevastating blackmail material for your 30th high school reunion, chances are\nthe 105.9 TB of compressed image data sitting in the Webshots archive has what\nyou're looking for.\n\nThe photos are still in there. This is the recovery aircraft.\n\n\u003e Built on the work of **[Archive Team](https://wiki.archiveteam.org)** (who\n\u003e saved the data in 2012) and the **[Internet Archive](https://archive.org)**\n\u003e (who has kept it alive since). They are the only reason any of this exists.\n\u003e If this tool brings your photos home, [donate to the\n\u003e Archive](https://archive.org/donate). They earned it years ago.\n\n---\n\n## Preflight — no terminal required\n\n**Windows, never used a terminal:** green **Code** button → **Download ZIP**\n→ extract it → double-click **`Start_Here.bat`**. It checks for Python\n(pointing you to the free installer if needed), builds itself a private\nworkspace, and asks one question: *what was the screen name?* Answer it.\nThat's the whole manual.\n\n**Comfortable in a terminal:**\n\n```\npython -m venv .venv\n.venv\\Scripts\\activate          # Windows\nsource .venv/bin/activate       # macOS/Linux\npip install -r requirements.txt\n```\n\nPython 3.10+. Windows, macOS, Linux. The venv keeps the tool's four\ndependencies out of your system Python (thanks to @unquietwiki for insisting,\nin [#2](../../issues/2)). If you're a [uv](https://docs.astral.sh/uv/) person,\n`uv venv \u0026\u0026 uv pip install -r requirements.txt` and you already know the rest.\nNo APIs or logins. No encryption either, which is exactly how Webshots ran\nthings, and you probably now regret it.\n\n## Cleared for departure\n\n```\npython resurrector.py find    cooldave          # half-remember the name? sweep for it\npython resurrector.py search  yourscreenname    # what's on the scope?\npython resurrector.py pull    yourscreenname    # bring it home\npython resurrector.py friends yourscreenname    # everyone you knew in 2004\n```\n\n`search` gives you the flight-strip board: every archived album, with its\noriginal name and photo count. `pull` recovers everything and writes a\n**`gallery.html`** contact sheet. Open it in a browser and you're looking at\nyour albums again, original titles, original captions, twenty years later.\nYes, including the captions. You were very funny in 2004.\n\n![a real pull, replayed from the actual logs](assets/demo.gif)\n\n![search — the flight-strip board](assets/screenshot_search.png)\n\n\nInterrupted mid-pull? Run the same command again. Finished photos hold at the\ngate; photos that only landed at 800×600 get an automatic upgrade attempt to\nfull-size on every pass until the archive definitively says it isn't there.\n\n### Extended operations\n\n```\npython resurrector.py search yourscreenname --deep      # dig back to 2002\npython resurrector.py pull   yourscreenname --album ID  # one album only\npython resurrector.py pull   yourscreenname -j 6        # more concurrency (max 8)\n```\n\n**Only half-remember the name?** `find` sweeps the archive's own index for\nevery screen name matching a prefix and boards them as numbered strips:\nscreen name, how many archived pages, first and last seen. Then just say\nintentions: type `3` to search strip 3, `p3` to pull it on the spot. Spaces\nare handled too: `find cool dave` sweeps `cooldave`, `cool_dave`, and\n`cool-dave`, since half-remembered names tend to come back with spaces\nthat Webshots never allowed.\n\n**FLIGHT PLAN REMARKS.** Screen names are callsigns; remarks are who they\nwere. `remarks bexbee12 Becca from HS` files a note that shows up as an\n`RMK/` column on every board and at radar contact, or tag straight from\nthe board with `r3 Becca from HS`. Remarks live in a local `remarks.json`\nnext to where you run the tool. They never leave your machine.\n\n**The social graph survived, too.** Webshots profiles had friends \u0026 fans\npages, and the crawl captured them. `friends yourscreenname` reads the\narchived people pages and boards everyone you knew as numbered strips.\nOne test account surfaced **202 contacts** off 14 archived pages. From the\nboard: `3` searches strip 3, `p3` pulls their photos, `f3` walks into\n*their* friends list. Recover your account, then go get everyone else's.\n\n`--deep` runs a CDX prefix sweep over every archived variant of your profile\n(pagination pages, the date-sorted view, every site redesign from 2002 to\n2013) and resurrects albums you deleted years before the site died and\nforgot you ever had.\n\n## How it actually works\n\nThe Wayback Machine is the only door: the raw freeze-frame megawarcs went\naccess-restricted (HTTP 401) years ago and the old username index is dark. But\neverything Archive Team captured was ingested into Wayback, so recovery is a\nCDX-navigation problem:\n\n```\nscreen name\n  └─▸ CDX API: every capture of community.webshots.com/user/NAME (2002–2013)\n       └─▸ profile pages → album links (+ pagination: ?start=N and /album/ID/N)\n            └─▸ album grids → (thumbnail, photo-page) pairs + album titles\n                 └─▸ photo detail page → the photo's REAL image URL + caption\n                      └─▸ _fs.jpg original → _ph.jpg 800×600 → thumbnail\n```\n\nThe design hangs on two facts. I spent a long time trying to prove both of\nthem wrong against the live archive, and failed:\n\n- **You cannot guess a photo's image server.** A thumbnail on `thumb13` maps\n  to full-size copies on `image04`, `image12`, `image20`. The numbers are\n  unrelated. The only trustworthy source is the archived photo detail page,\n  so the tool resolves every photo through its page. (Naive URL derivation,\n  the thing every dead Webshots scraper attempted, silently misses almost\n  everything.)\n- **The 2002–2005 era is a different aircraft.** Old thumbnails ride\n  `thumbN.webshots.com` with per-image load-balancer host digits (2002 was a\n  lawless time), old albums paginate by path segment, and old full-size images\n  live at `community.webshots.com/sym/imageN/…`, which *is* derivable, from\n  the thumbnail's path digit. Paisley Ponytail speaks both eras.\n\nEvery photo descends a fallback ladder: real full-size, real 800×600, derived\nguesses, and finally the archived thumbnail itself. You always land with\n*something*, and the manifest records exactly which rung each photo reached.\n\n### Field notes from the wreckage\n\nThings the archive will not tell you until you hit them:\n\n- The CDX API interprets `limit=-1` as *\"return only the last row.\"* An early\n  version of this tool queried with `-1` for \"unlimited\" and silently saw 1 of\n  33 snapshots for its own test user. If you build on the CDX API, know this.\n- Some full-size images were archived **as their 404 pages**. The crawler\n  arrived after the image server had already given up, and Wayback faithfully\n  preserved the failure. Downloads are validated by JPEG magic bytes, never by\n  HTTP status alone.\n- Wayback playback rewrites the same `href` absolute on one page and\n  host-relative on the next, depending on which rendering path served it.\n  Every extractor here accepts both, because trusting one form loses photos.\n- Album grids emit each thumbnail *twice*: anchor-less in a filmstrip widget,\n  anchored in the photo grid. First-match pairing silently drops a third of\n  the photo-page links; the parser prefers the anchored occurrence, including\n  across pagination boundaries.\n- A photo that fails today is retried in full on every future run, on purpose:\n  the Internet Archive occasionally backfills. Definitive absence (a real 404\n  on every candidate URL) is cached in a marker file. Ambiguous failures stay\n  retryable.\n\n## Reading the instruments\n\n![pull — full-size originals landing, with the fallback ladder visible](assets/screenshot_pull.png)\n\n| Callout | Meaning |\n|---|---|\n| `LANDED  FS` | Full-size original recovered — actual camera resolution |\n| `LANDED  PH` | 800×600 copy recovered (full-size not archived) |\n| `UPGRADED FS` | A previous 800×600 was replaced by the located original |\n| `THUMB ONLY` | Only the 100×75 thumbnail survived the crawl |\n| `AT GATE` | Already on disk from an earlier run |\n| `MISSED APCH` | Genuinely not in the archive — you can't land a plane that never took off |\n\nEverything lands in `output/yourname/`, one folder per album, named by the\nalbum's original title, with `manifest.json` (per-photo records, variants,\ncaptions) and the `gallery.html` contact sheet alongside.\n\nThe UI palette is the **FAA standard ATC foreground set** from\n**DOT/FAA/AM-20/08** (*Evaluation of a New Color Palette for ATC Displays*,\nGildea et al., 2020) — Table 1 hex codes, including the HF-STD-010A revised\nRed — as evaluated on ERAM/STARS. I stared at those colors for a living once,\nso when `LANDED` prints in green, that is `#23E162`, the exact scope green\nfrom the report. A search squawks ident. No matches means no beacons\ncorrelated to the flight plan. If you're going to do a bit, do it from the\ntable.\n\n## Honest expectations\n\n- **Account public in fall 2012** — odds are genuinely good; often most photos\n  at full resolution. The Archive Team crawl was systematic.\n- **Account deleted before 2012** — sometimes. Regular Wayback crawls ran from\n  2002 on; `--deep` finds those albums, but early-era image coverage is patchy.\n  Expect partial albums and thumbnails.\n- **Albums set to private** — never archived. No tool can recover them. Your\n  secrets died with the site; the one privacy feature that actually worked.\n\n## Etiquette (read before filing complaints about speed)\n\narchive.org is the only reason any of this still exists. All traffic funnels\nthrough one global rate limiter (~1 request/second sustained), a 429/503 from\nthe tower slows *every* coroutine, retries back off exponentially, and deep\nsweeps are probe-capped. Fly the published procedure.\n\n## The NTSB docket\n\nThe full accident investigation: what Webshots was, how fourteen million\nphoto libraries went down with it, why the wreckage sat locked for a decade,\nand the reverse engineering that got it open, era by era, with findings and\nprobable cause.\n\n**[Read DOCKET.md →](DOCKET.md)**\n\n\u003e **Operator's statement:** *Now, I just need everyone to break it again.*\n\nThe investigation remains open: if a screen name that should work comes back\nempty, [file a report](../../issues). Every report gets looked at.\n\n## The robot in the room\n\nYou'll find Claude all over this repo's commit history because I build with\nAI tools, heavily, and I'm not going to pretend otherwise. So, for the person\nabout to type \"thanks claude\": the nine years of Wayback spelunking are mine.\nThe URL doctrine (which numbers derive and which ones lie), the era grammar,\nthe test accounts, and the air traffic control in your terminal are also\nmine. Claude typed most of the code at a speed I'm never going to match, and\nyes, it drafted a lot of these sentences too, working from my notes and my\nwar stories. If a paragraph lands a little too cleanly, that's why. I\nhand-rolled an earlier version of this tool years ago and it topped out\naround a third of a test account. This one gets nearly all of it, mostly\nbecause automating the grunt work let me test every assumption against the\nlive archive instead of trusting my old notes. The facts underneath are mine\nand they're checkable, photo IDs included. If one doesn't hold, file a\nreport.\n\n## Why this exists\n\nBetween 1995 and 2012, millions of people uploaded the only copies of their\nfamily photos to Webshots. Mine were in there too. I spent nine years getting\nthem back, one Wayback page at a time. Nobody should have to do that twice.\n\n---\n\n**Tailstrike Studios × Ash Airfoil** // coldbricks · MIT license ·\nNot affiliated with the Internet Archive; just a grateful guest on their frequency.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcoldbricks%2Fpaisley-ponytail","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcoldbricks%2Fpaisley-ponytail","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcoldbricks%2Fpaisley-ponytail/lists"}