Spaces:
Running
Running
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" }; | |
} | |