diff --git a/api/src/processing/match-action.js b/api/src/processing/match-action.js index 9e2ba4ff..0fd2b32b 100644 --- a/api/src/processing/match-action.js +++ b/api/src/processing/match-action.js @@ -78,6 +78,7 @@ export default function({ r, host, audioFormat, isAudioOnly, isAudioMuted, disab case "instagram": case "twitter": case "snapchat": + case "bsky": params = { picker: r.picker }; break; diff --git a/api/src/processing/match.js b/api/src/processing/match.js index b1e2538f..a408e6c5 100644 --- a/api/src/processing/match.js +++ b/api/src/processing/match.js @@ -239,7 +239,8 @@ export default async function(host, patternMatch, obj) { case "bsky": r = await bluesky({ - ...patternMatch + ...patternMatch, + alwaysProxy: obj.alwaysProxy }); break; diff --git a/api/src/processing/services/bluesky.js b/api/src/processing/services/bluesky.js index 0d0b5b41..14e606d0 100644 --- a/api/src/processing/services/bluesky.js +++ b/api/src/processing/services/bluesky.js @@ -1,5 +1,6 @@ import HLS from "hls-parser"; import { cobaltUserAgent } from "../../config.js"; +import { createStream } from "../../stream/manage.js"; const extractVideo = async ({ getPost, filename }) => { const urlMasterHLS = getPost?.thread?.post?.embed?.playlist; @@ -24,7 +25,41 @@ const extractVideo = async ({ getPost, filename }) => { } } -export default async function ({ user, post }) { +const extractImages = async ({ 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", @@ -47,6 +82,9 @@ export default async function ({ user, post }) { if (embedType === "app.bsky.embed.video#view") { return await extractVideo({ getPost, filename }); } + if (embedType === "app.bsky.embed.images#view") { + return await extractImages({ getPost, filename, alwaysProxy }); + } return { error: "fetch.empty" }; } diff --git a/api/src/util/tests.json b/api/src/util/tests.json index 021eb0f6..dcf11757 100644 --- a/api/src/util/tests.json +++ b/api/src/util/tests.json @@ -1438,6 +1438,24 @@ "code": 200, "status": "stream" } + }, + { + "name": "single image", + "url": "https://bsky.app/profile/thehardyboycats.bsky.social/post/3l33flpoygt26", + "params": {}, + "expected": { + "code": 200, + "status": "redirect" + } + }, + { + "name": "several images", + "url": "https://bsky.app/profile/tracey-m.bsky.social/post/3kzxuxbiul626", + "params": {}, + "expected": { + "code": 200, + "status": "picker" + } } ] } \ No newline at end of file