Spaces:
Paused
Paused
| import HLS from "hls-parser"; | |
| import { cobaltUserAgent } from "../../config.js"; | |
| import { createStream } from "../../stream/manage.js"; | |
| const extractVideo = async ({ media, filename, dispatcher }) => { | |
| let urlMasterHLS = media?.playlist; | |
| if (!urlMasterHLS || !urlMasterHLS.startsWith("https://video.bsky.app/")) { | |
| return { error: "fetch.empty" }; | |
| } | |
| urlMasterHLS = urlMasterHLS.replace( | |
| "video.bsky.app/watch/", | |
| "video.cdn.bsky.app/hls/" | |
| ); | |
| const masterHLS = await fetch(urlMasterHLS, { dispatcher }) | |
| .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`, | |
| isHLS: 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", | |
| 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, dispatcher }) { | |
| 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, | |
| }, | |
| dispatcher | |
| }).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: "content.post.unavailable" }; | |
| } | |
| } | |
| 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" }; | |
| } | |