Make the rewrite rules copyable from the file, not just the render
The rules were a Markdown table, and a table cell cannot hold a bare `|`. It has to be written `\|`, which renders as a pipe and copies as a backslash and a pipe. Every one of these rules is an alternation full of pipes, so anyone reading README.md rather than a rendered view -- which, for a self-hosted thing, is most of the time -- got a regex whose alternation had quietly become literal characters. It matches nothing, and nothing about it looks wrong. That is not hypothetical: it is how this came up. The Reddit rule is the longest row, and reading it out of the file gave something that plainly did not work, so the backslashes came out. Which fixed the copy and broke the table -- four pipes turned into column separators, the row became seven cells, the separator row was widened to seven to match, and `(.*)` picked up an escape on the way past. Restoring the row would have left the trap exactly where it was, for the next person or the same one. So the table is now a code block: each rule is a comment naming the platform, then the find field, then the replace field, one per line. Nothing is escaped, the file and the render agree, and each field is a whole line to select. Every rule is checked from both directions. Out of README.md byte for byte with no unescaping step, which is the copy-from-the-file path; and out of the rendered HTML with entities decoded, which is the copy-from-the-page path. Both give all seven rules, both compile, and both rewrite all seventeen sample URLs correctly -- mobile.x.com, threads.net, the TikTok vm. and vt. hosts, five Reddit subdomains, a /s/ share link and a redd.it short code. The two extractions are byte-identical to each other, which is the property that was missing before. Also reformats the rest of the file, and stops calling it a table on the way past. Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_017nMQ2eDKnqALYhAibpTKTu
This commit is contained in:
@@ -21,15 +21,43 @@ readable in your history.
|
||||
|
||||
Replace `antisocial.example.com` with wherever you are running it.
|
||||
|
||||
| Platform | Find | Replace |
|
||||
| --------- | ------------------------------------------------------------- | ------------------------------------------- |
|
||||
| X | `/^https:\/\/(?:www\.\|mobile\.)?(?:x\|twitter)\.com\/(.*)$/` | `https://antisocial.example.com/x/$1` |
|
||||
| Threads | `/^https:\/\/(?:www\.)?threads\.(?:net\|com)\/(.*)$/` | `https://antisocial.example.com/threads/$1` |
|
||||
| Instagram | `/^https:\/\/(?:www\.)?instagram\.com\/(.*)$/` | `https://antisocial.example.com/ig/$1` |
|
||||
| TikTok | `/^https:\/\/(?:www\.\|vm\.\|vt\.)?tiktok\.com\/(.*)$/` | `https://antisocial.example.com/tiktok/$1` |
|
||||
| Bluesky | `/^https:\/\/bsky\.app\/(.*)$/` | `https://antisocial.example.com/bsky/$1` |
|
||||
| Reddit | `/^https:\/\/(?:www\.\|old\.\|new\.\|np\.\|m\.)?reddit\.com\/(.*)$/` | `https://antisocial.example.com/reddit/$1` |
|
||||
| Reddit | `/^https:\/\/redd\.it\/(.*)$/` | `https://antisocial.example.com/reddit/$1` |
|
||||
Each rule is two fields. Both are on their own line below, and neither needs any
|
||||
escaping — copy them straight out of this file.
|
||||
|
||||
```text
|
||||
# X
|
||||
/^https:\/\/(?:www\.|mobile\.)?(?:x|twitter)\.com\/(.*)$/
|
||||
https://antisocial.example.com/x/$1
|
||||
|
||||
# Threads
|
||||
/^https:\/\/(?:www\.)?threads\.(?:net|com)\/(.*)$/
|
||||
https://antisocial.example.com/threads/$1
|
||||
|
||||
# Instagram
|
||||
/^https:\/\/(?:www\.)?instagram\.com\/(.*)$/
|
||||
https://antisocial.example.com/ig/$1
|
||||
|
||||
# TikTok
|
||||
/^https:\/\/(?:www\.|vm\.|vt\.)?tiktok\.com\/(.*)$/
|
||||
https://antisocial.example.com/tiktok/$1
|
||||
|
||||
# Bluesky
|
||||
/^https:\/\/bsky\.app\/(.*)$/
|
||||
https://antisocial.example.com/bsky/$1
|
||||
|
||||
# Reddit
|
||||
/^https:\/\/(?:www\.|old\.|new\.|np\.|m\.)?reddit\.com\/(.*)$/
|
||||
https://antisocial.example.com/reddit/$1
|
||||
|
||||
# Reddit short links
|
||||
/^https:\/\/redd\.it\/(.*)$/
|
||||
https://antisocial.example.com/reddit/$1
|
||||
```
|
||||
|
||||
A code block rather than a table, because a table cell cannot hold a bare `|` — it has
|
||||
to be written `\|`, which renders correctly and copies wrongly. The alternation in these
|
||||
rules is full of them, and a regex whose pipes arrive as literal pipes matches nothing
|
||||
and says nothing about why.
|
||||
|
||||
So `https://x.com/user/status/123` becomes
|
||||
`https://antisocial.example.com/x/user/status/123`.
|
||||
@@ -42,7 +70,8 @@ where it came from Reddit. A Reddit `/r/<sub>/s/<code>` share link is followed t
|
||||
post it points at, and that permalink — not the opaque share code — is what the copy
|
||||
button hands back.
|
||||
|
||||
`/` serves this table with the live hostnames, if you'd rather read it there.
|
||||
`/` serves these rules with the live hostname already filled in, if you'd rather copy
|
||||
them from there.
|
||||
|
||||
## How it works
|
||||
|
||||
@@ -60,7 +89,7 @@ Each adapter layers its extraction, most structured first:
|
||||
4. **Open Graph tags** — the floor, and enough to show something.
|
||||
|
||||
| Platform | Loads | Reads |
|
||||
| --------- | ---------------------------- | -------------------------------------------------------- |
|
||||
| --------- | ---------------------------- | --------------------------------------------------------------- |
|
||||
| Bluesky | the public AT Protocol API | `getPostThread`; falls back to the post page |
|
||||
| X | `platform.twitter.com` embed | the `cdn.syndication.twimg.com/tweet-result` response |
|
||||
| Instagram | `/embed/captioned/` | `shortcode_media`, then the rendered `<video>`/`<img>` |
|
||||
@@ -93,7 +122,7 @@ Reddit posts come with it: every comment the first page carried, nested the way
|
||||
written. Each comment is a `<details>` element, so folding one takes its whole subtree
|
||||
with it, works without JavaScript and works from the keyboard; a collapsed comment says
|
||||
how many replies it is hiding. "Collapse all" is the one piece that needs the script,
|
||||
which is why it only appears once the script has run. What was behind a *load more* is
|
||||
which is why it only appears once the script has run. What was behind a _load more_ is
|
||||
not fetched — that is a second page and often a third — but it is counted and said out
|
||||
loud rather than quietly dropped.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user