Skip to content
This repository has been archived by the owner on Jan 19, 2025. It is now read-only.

Commit

Permalink
feat(bluesky): add support for video
Browse files Browse the repository at this point in the history
  • Loading branch information
MagsMagnoli authored and louisgrasset committed Jan 19, 2025
1 parent 10dfac4 commit 57d58e4
Show file tree
Hide file tree
Showing 5 changed files with 112 additions and 15 deletions.
45 changes: 45 additions & 0 deletions src/helpers/bluesky/__tests__/create-media-record.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { createMediaRecord } from "../create-media-record";

describe("createMediaRecord", () => {
const mockImageAttachments = [
{ alt_text: "Alt text 1", data: { blob: { original: "image1.jpg" } } },
{ alt_text: "Alt text 2", data: { blob: { original: "image2.jpg" } } },
];

const mockVideoAttachment = [
{ alt_text: null, data: { blob: { original: "video.mp4" } } },
];

it("should an image media record for 'image' mediaType", () => {
const result = createMediaRecord("image", mockImageAttachments);
expect(result).toEqual({
media: {
$type: "app.bsky.embed.images",
images: [
{ alt: "Alt text 1", image: "image1.jpg" },
{ alt: "Alt text 2", image: "image2.jpg" },
],
},
});
});

it("should a video media record for 'video' mediaType", () => {
const result = createMediaRecord("video", mockVideoAttachment);
expect(result).toEqual({
media: {
$type: "app.bsky.embed.video",
video: "video.mp4",
},
});
});

it("should return an empty object for undefined mediaType", () => {
const result = createMediaRecord(undefined, []);
expect(result).toEqual({});
});

it("should return an empty object for unhandled mediaType", () => {
const result = createMediaRecord("audio", []);
expect(result).toEqual({});
});
});
37 changes: 37 additions & 0 deletions src/helpers/bluesky/create-media-record.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { BlueskyMediaAttachment } from "../../types";

/**
* Creates a media record based on the given media type and attachments.
*
* @param {'image' | 'video' | undefined} mediaType - The type of the media (image or video).
* @param {BlueskyMediaAttachment[]} mediaAttachments - The media attachments to include in the record.
* @returns {Object} The media record object tailored to the media type.
*/
export const createMediaRecord = (
mediaType: "image" | "video" | undefined,
mediaAttachments: BlueskyMediaAttachment[],
) => {
switch (mediaType) {
case "image":
return {
media: {
$type: "app.bsky.embed.images",
images: mediaAttachments.map((i) => ({
alt: i.alt_text ?? "",
image: i.data.blob.original,
})),
},
};

case "video":
return {
media: {
$type: "app.bsky.embed.video",
video: mediaAttachments[0].data.blob.original,
},
};

default:
return {};
}
};
1 change: 1 addition & 0 deletions src/helpers/medias/parse-blob-for-bluesky.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export const parseBlobForBluesky = async (
"image/jpg",
"image/jpeg",
"image/webp",
"video/mp4",
];
const mimeType = blob.type;

Expand Down
30 changes: 26 additions & 4 deletions src/services/__tests__/bluesky-sender.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,13 @@ const embedMedia = {
},
};

const embedVideo = {
$type: "blob",
mimeType: "video/mp4",
ref: "blobRef",
size: "1024",
};

describe("blueskySenderService", () => {
beforeEach(() => {
postSpy.mockClear();
Expand Down Expand Up @@ -141,14 +148,26 @@ describe("blueskySenderService", () => {
});
});

describe("when the tweet as a video", () => {
describe("when the tweet is a video", () => {
beforeAll(() => {
mediaDownloaderServiceMock.mockResolvedValue(
makeBlobFromFile("video-mp4.mp4", "video/mp4"),
);
uploadBlobSpy.mockResolvedValue({
data: {
blob: {
original: {
$type: "blob",
ref: "blobRef",
mimeType: "video/mp4",
size: "1024",
},
},
},
});
});

it("should send the post without media ", async () => {
it("should send the post with media ", async () => {
const mediaVideo: Media = {
type: "video",
id: "id",
Expand All @@ -157,14 +176,17 @@ describe("blueskySenderService", () => {
};
await blueskySenderService(client, post, [mediaVideo], log);

expect(uploadBlobSpy).toHaveBeenCalledTimes(0);
expect(uploadBlobSpy).toHaveBeenCalledTimes(1);
expect(postSpy).toHaveBeenCalledTimes(1);
expect(postSpy).toHaveBeenCalledWith({
$type: "app.bsky.feed.post",
createdAt: new Date(post.tweet.timestamp!).toISOString(),
text: "Tweet text",
facets: undefined,
embed: undefined,
embed: {
$type: "app.bsky.embed.video",
video: embedVideo,
},
});
});
});
Expand Down
14 changes: 3 additions & 11 deletions src/services/bluesky-sender.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
buildReplyEntry,
getBlueskyChunkLinkMetadata,
} from "../helpers/bluesky";
import { createMediaRecord } from "../helpers/bluesky/create-media-record";
import { savePostToCache } from "../helpers/cache/save-post-to-cache";
import { oraProgress } from "../helpers/logs";
import { parseBlobForBluesky } from "../helpers/medias/parse-blob-for-bluesky";
Expand Down Expand Up @@ -147,17 +148,8 @@ export const blueskySenderService = async (
}
: {};

const mediaRecord = mediaAttachments.length
? {
media: {
$type: "app.bsky.embed.images",
images: mediaAttachments.map((i) => ({
alt: i.alt_text ?? "",
image: i.data.blob.original,
})),
},
}
: {};
const mediaType = medias[0]?.type;
const mediaRecord = createMediaRecord(mediaType, mediaAttachments);

const card = await getBlueskyChunkLinkMetadata(richText, client);
const externalRecord = card
Expand Down

0 comments on commit 57d58e4

Please sign in to comment.