From ab23c2b9febbc91446418112daf6f6b119f72286 Mon Sep 17 00:00:00 2001 From: Kydoimos Date: Sat, 12 Sep 2026 11:35:32 -0300 Subject: [PATCH] Add Facebook 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/ 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 --- CLAUDE.md | 35 +- README.md | 25 +- src/platforms/facebook.ts | 451 +++ src/platforms/index.ts | 5 +- src/platforms/url.ts | 1 + src/render/layout.ts | 1 + src/render/text.ts | 1 + src/types.ts | 3 +- test/facebook.test.ts | 191 + test/fixtures/facebook/photo-post.json | 4540 ++++++++++++++++++++++++ test/fixtures/facebook/reel.json | 775 ++++ test/fixtures/facebook/video-post.json | 2662 ++++++++++++++ 12 files changed, 8681 insertions(+), 9 deletions(-) create mode 100644 src/platforms/facebook.ts create mode 100644 test/facebook.test.ts create mode 100644 test/fixtures/facebook/photo-post.json create mode 100644 test/fixtures/facebook/reel.json create mode 100644 test/fixtures/facebook/video-post.json diff --git a/CLAUDE.md b/CLAUDE.md index 05c7919..ee7ca03 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,7 +1,7 @@ # antisocial — working notes A self-hosted page that shows a social post without the app. StopTheMadness rewrites -links to X, Threads, Instagram, TikTok, Bluesky and Reddit into +links to X, Threads, Instagram, Facebook, TikTok, Bluesky and Reddit into `//`; this resolves the post by driving a real headless Chromium and renders the media, the text, a platform badge and a copy-the-original button. @@ -35,6 +35,7 @@ different fixes: | Right media, wrong count | The structured payload was missed and it fell through to the DOM, which only shows the first carousel item. | | Poster image where a video belongs | Same fall-through, plus the `