CI / Typecheck, test, build (pull_request) Successful in 48s
The captioned embed stopped shipping a reel's video_url and never draws a logged-out <video>, so both the payload and the DOM hand back the cover frame alone. Because that still counts as media, the post-page fallback never fired and a reel resolved to a still image. Trigger the fallback when the URL is a reel (or the payload declared a video) but no video was found, so it reaches the post page, whose payload still carries the progressive file in video_versions. The embed's caption, handle and avatar are carried forward, since the post-page payload does not include the owner. Co-authored-by: anthropic/claude-opus-4-8
52 lines
2.8 KiB
TypeScript
52 lines
2.8 KiB
TypeScript
import assert from 'node:assert/strict';
|
|
import { test } from 'node:test';
|
|
import { fromGraph } from '../src/platforms/instagram.ts';
|
|
import { findMetaMedia, mediaFromMetaNode } from '../src/platforms/meta-media.ts';
|
|
import { fixture } from './helpers.ts';
|
|
|
|
test('a carousel becomes one media entry per child, in order', () => {
|
|
const scraped = fromGraph(fixture('instagram/carousel.json'));
|
|
assert.ok(scraped.media.length > 1, 'expected a carousel');
|
|
assert.ok(scraped.media.every((m) => m.kind === 'image'));
|
|
assert.ok(scraped.media.every((m) => m.url.startsWith('https://')));
|
|
// The CDN 403s anything arriving without a referrer, so every entry has
|
|
// to carry the headers the proxy will replay.
|
|
assert.ok(scraped.media.every((m) => m.fetchHeaders?.['Referer'] === 'https://www.instagram.com/'));
|
|
assert.ok(scraped.text);
|
|
});
|
|
|
|
test('a reel becomes a progressive video with its cover frame as the poster', () => {
|
|
const scraped = fromGraph(fixture('instagram/reel.json'));
|
|
assert.equal(scraped.media.length, 1);
|
|
const [item] = scraped.media;
|
|
assert.equal(item?.kind, 'video');
|
|
assert.ok(item?.kind === 'video' && item.poster, 'expected a poster');
|
|
// Not a blob: or an HLS manifest — the native player needs a real file.
|
|
assert.match(item?.url ?? '', /^https:\/\//);
|
|
assert.ok(!item?.url.includes('.m3u8'));
|
|
assert.ok(item?.width && item.height, 'expected dimensions for the aspect ratio');
|
|
});
|
|
|
|
test('a reel whose embed only ships a cover frame still finds its video on the post page', () => {
|
|
// The captioned embed stopped shipping a reel's `video_url` and never draws
|
|
// a logged-out `<video>`, so both payload and DOM hand back the poster only.
|
|
// The post page still carries the progressive file in `video_versions`
|
|
// (the meta-media schema), which is where the adapter now falls through to.
|
|
const node = findMetaMedia(fixture('instagram/reel-video-versions.json'));
|
|
assert.ok(node, 'expected to find the media node in the post payload');
|
|
const media = mediaFromMetaNode(node!, 'https://www.instagram.com/');
|
|
assert.equal(media.length, 1);
|
|
const [item] = media;
|
|
assert.equal(item?.kind, 'video', 'a reel is a video, not its cover frame');
|
|
assert.match(item?.url ?? '', /^https:\/\/.*\.mp4/);
|
|
assert.ok(!item?.url.includes('.m3u8'), 'the native player needs a real file, not HLS');
|
|
// The cover frame becomes the poster, not the media itself.
|
|
assert.ok(item?.kind === 'video' && item.poster?.url.includes('t51.82787-15'), 'expected the cover frame as poster');
|
|
assert.ok(item?.width === 720 && item.height === 1280, 'expected dimensions for the aspect ratio');
|
|
});
|
|
|
|
test('captions keep their line breaks', () => {
|
|
const scraped = fromGraph(fixture('instagram/carousel.json'));
|
|
assert.ok(scraped.text?.includes('\n'), 'expected the caption to keep paragraph breaks');
|
|
});
|