Adds Facebook as a platform, under /fb. One file in src/platforms/, one row
in the table, and the rewrite rule in the README.
$ npm run resolve -- 'https://www.facebook.com/share/r/1FF2LPQhgf/?mibextid=wwXIfr'
originalUrl https://www.facebook.com/reel/962551420197596/
author @thespeechprof · SpeechProf · avatar
text "I need answers."
media video 720x1280, 15s, with poster
postedAt 2026-08-30T15:38:45.000Z
Verified end to end through the route as well: badge, avatar, caption, and a <video> whose /m/ proxy answers 206 Partial Content, so the scrubber
seeks. A reel, a pfbid photo post, a /photo/?fbid= permalink and a /<page>/videos/<slug>/<id>/ post all resolve.
Picking the right post
The interesting part. A Facebook reel page ships the next five reels of the
feed in exactly the same shape as the linked one, and a video post scatters its
own pieces across four separate payload blocks — media in one, caption in
another, avatar in a third, timestamp in a fourth. Reading the first node that
carries media puts a stranger's video under someone else's name, which is the
same false attribution the lifted quote-post picture used to be.
So nothing is read until the post has been identified, and an id that matches
nothing is a failure rather than a best guess: /watch/<id> for a video
Facebook no longer has comes back as the Watch home page, feed and all. Before
that guard it cheerfully returned a stranger's reel; now it renders the error
card, which still carries the link and the copy button.
The author is whatever the payload calls the owner. author on a Facebook
page means the author of a comment, sitting right there in the same shape with
a name and a picture of its own — the video-post.json fixture keeps its
comments so that trap stays tested.
Three things worth a reviewer's attention
Multi-photo posts are the one path not confirmed against a live link. all_subattachments.nodes is handled and unit-tested both ways — the empty
stub Facebook ships on every post versus a real carousel — but five public
pages searched had no album post in their logged-out feed. If one comes back
as a single picture, that is where to look.
Instagram and Threads are touched. Both carried a byte-identical Open
Graph fallback; a third copy for Facebook is where it stops being a
coincidence, so it moved into meta-media.ts with tests of its own. Split
into its own commit.
fb.watch short links get no rewrite rule. The host is in matchesHost
so the CLI takes one, but a bare path segment on facebook.com is a profile
name, so it cannot be rebuilt from a rewritten path the way TikTok's vm.
codes are. Facebook issues /share/ links now. Easy to add later if they
still turn up.
npm test — 158 pass, 0 fail. npm run typecheck clean.
Adds Facebook as a platform, under `/fb`. One file in `src/platforms/`, one row
in the table, and the rewrite rule in the README.
```
$ npm run resolve -- 'https://www.facebook.com/share/r/1FF2LPQhgf/?mibextid=wwXIfr'
originalUrl https://www.facebook.com/reel/962551420197596/
author @thespeechprof · SpeechProf · avatar
text "I need answers."
media video 720x1280, 15s, with poster
postedAt 2026-08-30T15:38:45.000Z
```
Verified end to end through the route as well: badge, avatar, caption, and a
`<video>` whose `/m/` proxy answers `206 Partial Content`, so the scrubber
seeks. A reel, a `pfbid` photo post, a `/photo/?fbid=` permalink and a
`/<page>/videos/<slug>/<id>/` post all resolve.
## Picking the right post
The interesting part. A Facebook reel page ships the next five reels of the
feed in exactly the same shape as the linked one, and a video post scatters its
own pieces across four separate payload blocks — media in one, caption in
another, avatar in a third, timestamp in a fourth. Reading the first node that
carries media puts a stranger's video under someone else's name, which is the
same false attribution the lifted quote-post picture used to be.
So nothing is read until the post has been identified, and an id that matches
nothing is a failure rather than a best guess: `/watch/<id>` for a video
Facebook no longer has comes back as the Watch home page, feed and all. Before
that guard it cheerfully returned a stranger's reel; now it renders the error
card, which still carries the link and the copy button.
The author is whatever the payload calls the *owner*. `author` on a Facebook
page means the author of a comment, sitting right there in the same shape with
a name and a picture of its own — the `video-post.json` fixture keeps its
comments so that trap stays tested.
## Three things worth a reviewer's attention
1. **Multi-photo posts are the one path not confirmed against a live link.**
`all_subattachments.nodes` is handled and unit-tested both ways — the empty
stub Facebook ships on *every* post versus a real carousel — but five public
pages searched had no album post in their logged-out feed. If one comes back
as a single picture, that is where to look.
2. **Instagram and Threads are touched.** Both carried a byte-identical Open
Graph fallback; a third copy for Facebook is where it stops being a
coincidence, so it moved into `meta-media.ts` with tests of its own. Split
into its own commit.
3. **`fb.watch` short links get no rewrite rule.** The host is in `matchesHost`
so the CLI takes one, but a bare path segment on `facebook.com` is a profile
name, so it cannot be rebuilt from a rewritten path the way TikTok's `vm.`
codes are. Facebook issues `/share/` links now. Easy to add later if they
still turn up.
`npm test` — 158 pass, 0 fail. `npm run typecheck` clean.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Instagram and Threads both ended with the same twelve lines: read the Open
Graph tags, make og:video a video with og:image as its poster, otherwise make
og:image an image, and attach the referrer headers the CDN wants. Facebook
needs the same floor for the same reason, and three copies of a thing is where
it stops being a coincidence.
meta-media.ts already exists because these platforms are one product
underneath. The media schema it normalizes is Instagram's and Threads';
Facebook's is its own, but the headers and the link preview are shared with
both, so that is where this goes.
Co-Authored-By: Claude Opus 5 <[email protected]>
A shared Facebook link lands on a page that carries the whole post logged
out -- the caption, the author, the files, the dimensions -- in ScheduledServerJS
payloads that are plain JSON in ordinary script tags. What it does not carry
is only that post. A reel arrives with the next five reels of the feed
attached under viewer.lasso_blue_feed, a video with its related videos, and
every one of them has the same fields in the same shape as the real one.
Reading the first node with media on it gets a stranger's reel under someone
else's name, which is the same false attribution a lifted quote-post picture
used to be.
So nothing is read until the post has been picked out. partsOfPost matches the
id in the address against every node that names one; an address with no id in
it -- a pfbid permalink -- is matched on permalink_url instead. Only with
nothing to match on at all does it fall back to the route's query results,
which is still narrower than the whole payload: the page ships its entire
client configuration alongside the post, thousands of nodes carrying a name or
an id, and a plain search finds a video player setting long before it finds the
author.
An id that matches nothing is a failure rather than a best guess. Facebook
answers a link to something it no longer has by quietly serving something else
-- /watch/<id> for a video that is gone comes back as the Watch home page, feed
and all -- so the error card, which still carries the link and the copy button,
is the honest answer.
One post's pieces are spread across several payload blocks: a video post keeps
its files in one, its caption in another, its author's avatar in a third and
its timestamp in a fourth. Every claiming node is collected, not just the
first, and the author's gaps are filled only from nodes carrying the same id.
The author is whatever the payload calls the owner -- actors, owner,
video_owner, owner_as_page. `author` on a Facebook page means the author of a
comment, which sits right there in the same shape with a name and a picture of
its own.
Media is videoDeliveryLegacyFields.browser_native_hd_url with
preferred_thumbnail as its poster, photo_image or image for a picture, and
all_subattachments.nodes for a post of several -- which Facebook ships empty on
every single-picture post, so only a populated one is a carousel. The CDN is
signed and serves Range without asking for a referrer, but the assets are
proxied like everything else.
/share/{r,v,p,g} links are stubs, so the adapter follows one and hands back
where it landed: the share code says nothing about what it opens, and rdid,
share_url and fs are what the redirect leaves behind. m.facebook.com is a login
wall logged out, so the rewrite rule rebuilds on www.
Fixtures are real captures of a reel, a photo post and a video post, trimmed of
the DASH manifests and tracking blobs. The reel keeps its recommendations and
the video post keeps its comments, because those are the two things that have
to survive being read past.
Co-Authored-By: Claude Opus 5 <[email protected]>
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Adds Facebook as a platform, under
/fb. One file insrc/platforms/, one rowin the table, and the rewrite rule in the README.
Verified end to end through the route as well: badge, avatar, caption, and a
<video>whose/m/proxy answers206 Partial Content, so the scrubberseeks. A reel, a
pfbidphoto post, a/photo/?fbid=permalink and a/<page>/videos/<slug>/<id>/post all resolve.Picking the right post
The interesting part. A Facebook reel page ships the next five reels of the
feed in exactly the same shape as the linked one, and a video post scatters its
own pieces across four separate payload blocks — media in one, caption in
another, avatar in a third, timestamp in a fourth. Reading the first node that
carries media puts a stranger's video under someone else's name, which is the
same false attribution the lifted quote-post picture used to be.
So nothing is read until the post has been identified, and an id that matches
nothing is a failure rather than a best guess:
/watch/<id>for a videoFacebook no longer has comes back as the Watch home page, feed and all. Before
that guard it cheerfully returned a stranger's reel; now it renders the error
card, which still carries the link and the copy button.
The author is whatever the payload calls the owner.
authoron a Facebookpage means the author of a comment, sitting right there in the same shape with
a name and a picture of its own — the
video-post.jsonfixture keeps itscomments so that trap stays tested.
Three things worth a reviewer's attention
all_subattachments.nodesis handled and unit-tested both ways — the emptystub Facebook ships on every post versus a real carousel — but five public
pages searched had no album post in their logged-out feed. If one comes back
as a single picture, that is where to look.
Graph fallback; a third copy for Facebook is where it stops being a
coincidence, so it moved into
meta-media.tswith tests of its own. Splitinto its own commit.
fb.watchshort links get no rewrite rule. The host is inmatchesHostso the CLI takes one, but a bare path segment on
facebook.comis a profilename, so it cannot be rebuilt from a rewritten path the way TikTok's
vm.codes are. Facebook issues
/share/links now. Easy to add later if theystill turn up.
npm test— 158 pass, 0 fail.npm run typecheckclean.🤖 Generated with Claude Code
A shared Facebook link lands on a page that carries the whole post logged out -- the caption, the author, the files, the dimensions -- in ScheduledServerJS payloads that are plain JSON in ordinary script tags. What it does not carry is only that post. A reel arrives with the next five reels of the feed attached under viewer.lasso_blue_feed, a video with its related videos, and every one of them has the same fields in the same shape as the real one. Reading the first node with media on it gets a stranger's reel under someone else's name, which is the same false attribution a lifted quote-post picture used to be. So nothing is read until the post has been picked out. partsOfPost matches the id in the address against every node that names one; an address with no id in it -- a pfbid permalink -- is matched on permalink_url instead. Only with nothing to match on at all does it fall back to the route's query results, which is still narrower than the whole payload: the page ships its entire client configuration alongside the post, thousands of nodes carrying a name or an id, and a plain search finds a video player setting long before it finds the author. An id that matches nothing is a failure rather than a best guess. Facebook answers a link to something it no longer has by quietly serving something else -- /watch/<id> for a video that is gone comes back as the Watch home page, feed and all -- so the error card, which still carries the link and the copy button, is the honest answer. One post's pieces are spread across several payload blocks: a video post keeps its files in one, its caption in another, its author's avatar in a third and its timestamp in a fourth. Every claiming node is collected, not just the first, and the author's gaps are filled only from nodes carrying the same id. The author is whatever the payload calls the owner -- actors, owner, video_owner, owner_as_page. `author` on a Facebook page means the author of a comment, which sits right there in the same shape with a name and a picture of its own. Media is videoDeliveryLegacyFields.browser_native_hd_url with preferred_thumbnail as its poster, photo_image or image for a picture, and all_subattachments.nodes for a post of several -- which Facebook ships empty on every single-picture post, so only a populated one is a carousel. The CDN is signed and serves Range without asking for a referrer, but the assets are proxied like everything else. /share/{r,v,p,g} links are stubs, so the adapter follows one and hands back where it landed: the share code says nothing about what it opens, and rdid, share_url and fs are what the redirect leaves behind. m.facebook.com is a login wall logged out, so the rewrite rule rebuilds on www. Fixtures are real captures of a reel, a photo post and a video post, trimmed of the DASH manifests and tracking blobs. The reel keeps its recommendations and the video post keeps its comments, because those are the two things that have to survive being read past. Co-Authored-By: Claude Opus 5 <[email protected]>