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]>
95 lines
3.6 KiB
TypeScript
95 lines
3.6 KiB
TypeScript
import assert from 'node:assert/strict';
|
|
import { test } from 'node:test';
|
|
import {
|
|
findCaption,
|
|
findMetaMedia,
|
|
mediaFromMetaNode,
|
|
mediaFromOpenGraph,
|
|
} from '../src/platforms/meta-media.ts';
|
|
import { fixture } from './helpers.ts';
|
|
|
|
const REFERER = 'https://www.threads.com/';
|
|
|
|
test('a Threads image post normalizes to one image with referrer headers', () => {
|
|
const node = fixture<Parameters<typeof mediaFromMetaNode>[0]>('threads/image.json');
|
|
const media = mediaFromMetaNode(node, REFERER);
|
|
assert.equal(media.length, 1);
|
|
assert.equal(media[0]?.kind, 'image');
|
|
assert.equal(media[0]?.fetchHeaders?.['Referer'], REFERER);
|
|
});
|
|
|
|
test('a second real Threads post normalizes the same way', () => {
|
|
// Two captures, so the walk is not quietly fitted to one payload.
|
|
const media = mediaFromMetaNode(fixture('threads/second.json'), REFERER);
|
|
assert.equal(media.length, 1);
|
|
assert.equal(media[0]?.kind, 'image');
|
|
});
|
|
|
|
test('the largest candidate wins', () => {
|
|
const media = mediaFromMetaNode(
|
|
{
|
|
image_versions2: {
|
|
candidates: [
|
|
{ url: 'https://cdn/small.jpg', width: 320, height: 320 },
|
|
{ url: 'https://cdn/large.jpg', width: 1440, height: 1440 },
|
|
],
|
|
},
|
|
},
|
|
REFERER,
|
|
);
|
|
assert.equal(media[0]?.url, 'https://cdn/large.jpg');
|
|
});
|
|
|
|
test('a carousel flattens to its children', () => {
|
|
const media = mediaFromMetaNode(
|
|
{
|
|
carousel_media: [
|
|
{ image_versions2: { candidates: [{ url: 'https://cdn/1.jpg', width: 100 }] } },
|
|
{
|
|
image_versions2: { candidates: [{ url: 'https://cdn/poster.jpg', width: 100 }] },
|
|
video_versions: [{ url: 'https://cdn/2.mp4', width: 720 }],
|
|
},
|
|
],
|
|
},
|
|
REFERER,
|
|
);
|
|
assert.deepEqual(media.map((m) => m.kind), ['image', 'video']);
|
|
});
|
|
|
|
test('the media node is found however deeply it is buried', () => {
|
|
const real = { image_versions2: { candidates: [{ url: 'https://cdn/i.jpg', width: 100 }] }, tag: 'me' };
|
|
const found = findMetaMedia({ a: [{ b: { c: real } }] });
|
|
assert.equal((found as { tag?: string })?.tag, 'me');
|
|
});
|
|
|
|
test('a stub node with no candidates is not mistaken for the post', () => {
|
|
// These payloads are full of empty placeholders; picking one used to make
|
|
// a real post look like it had no media at all.
|
|
assert.equal(findMetaMedia({ image_versions2: { candidates: [] }, carousel_media: null }), undefined);
|
|
});
|
|
|
|
test('the caption is found the same way, and an empty one is not a caption', () => {
|
|
assert.equal(findCaption({ x: { caption: { text: 'hello' } } }), 'hello');
|
|
assert.equal(findCaption({ x: { caption: { text: '' } } }), undefined);
|
|
assert.equal(findCaption({ x: { caption: null } }), undefined);
|
|
});
|
|
|
|
test('the link preview stands in for the post when there is nothing better', () => {
|
|
const image = mediaFromOpenGraph({ 'og:image': 'https://image.example/a.jpg' }, REFERER);
|
|
assert.deepEqual(image.map((item) => [item.kind, item.url]), [['image', 'https://image.example/a.jpg']]);
|
|
assert.equal(image[0]?.fetchHeaders?.['Referer'], REFERER);
|
|
});
|
|
|
|
test('a preview naming a video is a video, and its image is the poster', () => {
|
|
const media = mediaFromOpenGraph(
|
|
{ 'og:video': 'https://video.example/a.mp4', 'og:image': 'https://image.example/a.jpg' },
|
|
REFERER,
|
|
);
|
|
assert.equal(media[0]?.kind, 'video');
|
|
assert.equal(media[0]?.kind === 'video' ? media[0].poster?.url : undefined, 'https://image.example/a.jpg');
|
|
});
|
|
|
|
test('a page with no preview at all yields no media rather than an empty asset', () => {
|
|
assert.deepEqual(mediaFromOpenGraph({ 'og:title': 'just a title' }, REFERER), []);
|
|
});
|