import HLS from "hls-parser"; import { cobaltUserAgent } from "../../config.js"; import { createStream } from "../../stream/manage.js"; const extractVideo = async ({ media, filename }) => { const urlMasterHLS = media?.playlist; if (!urlMasterHLS) return { error: "fetch.empty" }; if (!urlMasterHLS.startsWith("https://video.bsky.app/")) return { error: "fetch.empty" }; const masterHLS = await fetch(urlMasterHLS) .then(r => { if (r.status !== 200) return; return r.text(); }) .catch(() => {}); if (!masterHLS) return { error: "fetch.empty" }; const video = HLS.parse(masterHLS) ?.variants ?.reduce((a, b) => a?.bandwidth > b?.bandwidth ? a : b); const videoURL = new URL(video.uri, urlMasterHLS).toString(); return { urls: videoURL, filename: `${filename}.mp4`, audioFilename: `${filename}_audio`, isM3U8: true, } } const extractImages = ({ getPost, filename, alwaysProxy }) => { const images = getPost?.thread?.post?.embed?.images; if (!images || images.length === 0) { return { error: "fetch.empty" }; } if (images.length === 1) return { urls: images[0].fullsize, isPhoto: true, filename: `${filename}.jpg`, } const picker = images.map((image, i) => { let url = image.fullsize; let proxiedImage = createStream({ service: "bluesky", type: "proxy", u: url, filename: `${filename}_${i + 1}.jpg`, }); if (alwaysProxy) url = proxiedImage; return { type: "photo", url, thumb: proxiedImage, } }); return { picker }; } export default async function ({ user, post, alwaysProxy }) { const apiEndpoint = new URL("https://public.api.bsky.app/xrpc/app.bsky.feed.getPostThread?depth=0&parentHeight=0"); apiEndpoint.searchParams.set( "uri", `at://${user}/app.bsky.feed.post/${post}` ); const getPost = await fetch(apiEndpoint, { headers: { "user-agent": cobaltUserAgent } }).then(r => r.json()).catch(() => {}); if (!getPost) return { error: "fetch.empty" }; if (getPost.error) { switch (getPost.error) { case "NotFound": case "InternalServerError": return { error: "content.post.unavailable" }; case "InvalidRequest": return { error: "link.unsupported" }; default: return { error: "fetch.empty" }; } } const embedType = getPost?.thread?.post?.embed?.$type; const filename = `bluesky_${user}_${post}`; if (embedType === "app.bsky.embed.video#view") { return extractVideo({ media: getPost.thread?.post?.embed, filename, }) } if (embedType === "app.bsky.embed.recordWithMedia#view") { return extractVideo({ media: getPost.thread?.post?.embed?.media, filename, }) } if (embedType === "app.bsky.embed.images#view") { return extractImages({ getPost, filename, alwaysProxy }); } return { error: "fetch.empty" }; }