From 71aa7e2fd2c54502551c6c9b7bc8475e5d6e9447 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Thu, 9 Jan 2025 16:25:47 -0600 Subject: [PATCH] Fix types, port getPostData to new interface --- bskyogcard/package.json | 2 +- bskyogcard/src/components/Post.tsx | 11 +- bskyogcard/src/components/StarterPack.tsx | 3 +- bskyogcard/src/data/getPostData.ts | 298 +++++++--------------- bskyogcard/src/routes/post.tsx | 1 - bskyogcard/src/routes/starter-pack.tsx | 11 +- bskyogcard/src/util/parseEmbed.ts | 152 +++++++++++ bskyogcard/yarn.lock | 57 +++-- 8 files changed, 292 insertions(+), 243 deletions(-) create mode 100644 bskyogcard/src/util/parseEmbed.ts diff --git a/bskyogcard/package.json b/bskyogcard/package.json index 59d81118c7..670883d413 100644 --- a/bskyogcard/package.json +++ b/bskyogcard/package.json @@ -10,7 +10,7 @@ "install-fonts": "node --loader ts-node/esm scripts/install-fonts.ts" }, "dependencies": { - "@atproto/api": "^0.13.4", + "@atproto/api": "0.14.0-next.2", "@atproto/common": "^0.4.0", "@resvg/resvg-js": "^2.6.2", "express": "^4.19.2", diff --git a/bskyogcard/src/components/Post.tsx b/bskyogcard/src/components/Post.tsx index e6857b828a..1673995375 100644 --- a/bskyogcard/src/components/Post.tsx +++ b/bskyogcard/src/components/Post.tsx @@ -49,7 +49,7 @@ export function Post({ data: PostData moderatorData: ModeratorData }) { - if (AppBskyFeedPost.isRecord(post.record)) { + if (AppBskyFeedPost.isValidRecord(post.record)) { const avatar = data.images.get(post.author.avatar) const rt = post.record.text ? new RichTextApi({ @@ -325,8 +325,8 @@ export function Embeds({ } if ( - AppBskyGraphDefs.isStarterPackViewBasic(embed.record) && - AppBskyGraphStarterpack.isRecord(embed.record.record) + AppBskyGraphDefs.isValidStarterPackViewBasic(embed.record) && + AppBskyGraphStarterpack.isValidRecord(embed.record.record) ) { const uri = getStarterPackImageUri(embed.record) const {name, description} = embed.record.record @@ -550,9 +550,8 @@ export function QuoteEmbed({ moderatorData: ModeratorData }) { if ( - AppBskyEmbedRecord.isViewRecord(embed.record) && - AppBskyFeedPost.isRecord(embed.record.value) && - AppBskyFeedPost.validateRecord(embed.record.value).success + AppBskyEmbedRecord.isValidViewRecord(embed.record) && + AppBskyFeedPost.isValidRecord(embed.record.value) ) { const {author, value: post, embeds} = embed.record const avatar = data.images.get(author.avatar) diff --git a/bskyogcard/src/components/StarterPack.tsx b/bskyogcard/src/components/StarterPack.tsx index 92a86070ba..e3c4112c31 100644 --- a/bskyogcard/src/components/StarterPack.tsx +++ b/bskyogcard/src/components/StarterPack.tsx @@ -1,5 +1,4 @@ /* eslint-disable bsky-internal/avoid-unwrapped-text */ -import React from 'react' import {AppBskyGraphDefs, AppBskyGraphStarterpack} from '@atproto/api' import {Butterfly} from './Butterfly.js' @@ -18,7 +17,7 @@ export function StarterPack(props: { images: Map }) { const {starterPack, images} = props - const record = AppBskyGraphStarterpack.isRecord(starterPack.record) + const record = AppBskyGraphStarterpack.isValidRecord(starterPack.record) ? starterPack.record : null const imagesArray = [...images.values()] diff --git a/bskyogcard/src/data/getPostData.ts b/bskyogcard/src/data/getPostData.ts index 86067a3451..44323b0c5e 100644 --- a/bskyogcard/src/data/getPostData.ts +++ b/bskyogcard/src/data/getPostData.ts @@ -1,14 +1,8 @@ -import { - AppBskyEmbedExternal, - AppBskyEmbedImages, - AppBskyEmbedRecord, - AppBskyEmbedRecordWithMedia, - AppBskyFeedDefs, - AppBskyGraphDefs, -} from '@atproto/api' +import {AppBskyFeedDefs} from '@atproto/api' import {httpLogger} from '../logger.js' import {getStarterPackImageUri} from '../util/getStarterPackImageUri.js' +import {Embed,parseEmbed} from '../util/parseEmbed.js' import {getImage} from './getImage.js' export type Metadata = { @@ -39,13 +33,99 @@ function normalizeAspectRatio(aspectRatio?: { return aspectRatio } +export function getEmbedData(embed: Embed, images: Map) { + switch (embed.type) { + case 'images': { + for (const image of embed.view.images) { + images.set(image.fullsize, { + aspectRatio: normalizeAspectRatio(image.aspectRatio), + }) + } + break + } + case 'link': { + if (embed.view.external.thumb) { + images.set(embed.view.external.thumb, { + aspectRatio: { + width: 1200, + height: 630, + }, + }) + } + break + } + case 'video': { + if (embed.view.thumbnail) { + images.set(embed.view.thumbnail, { + aspectRatio: normalizeAspectRatio(embed.view.aspectRatio), + }) + } + break + } + case 'feed': { + if (embed.view.avatar) { + images.set(embed.view.avatar, { + aspectRatio: { + width: 1000, + height: 1000, + }, + }) + } + break + } + case 'list': { + if (embed.view.avatar) { + images.set(embed.view.avatar, { + aspectRatio: { + width: 1000, + height: 1000, + }, + }) + } + break + } + case 'starter_pack': { + const uri = getStarterPackImageUri(embed.view) + images.set(uri, { + aspectRatio: { + width: 1200, + height: 630, + }, + }) + break + } + case 'post': { + if (embed.view.author.avatar) { + images.set(embed.view.author.avatar, { + aspectRatio: { + width: 1000, + height: 1000, + }, + }) + } + for (const _e of embed.view.embeds) { + getEmbedData(parseEmbed(_e), images) + } + break + } + case 'post_with_media': { + getEmbedData(embed.view, images) + getEmbedData(embed.media, images) + break + } + case 'post_blocked': + case 'post_detached': + case 'post_not_found': + default: + break + } +} + export async function getPostData( post: AppBskyFeedDefs.PostView, ): Promise { const images: Map = new Map() - // console.log(JSON.stringify(post, null, 2)) - if (post.author.avatar) { images.set(post.author.avatar, { aspectRatio: { @@ -56,203 +136,7 @@ export async function getPostData( } if (post.embed) { - if (AppBskyEmbedImages.isView(post.embed)) { - // get OPs media - for (const image of post.embed.images) { - images.set(image.fullsize, { - aspectRatio: normalizeAspectRatio(image.aspectRatio), - }) - } - } - - if (AppBskyEmbedExternal.isView(post.embed)) { - if (post.embed.external.thumb) { - images.set(post.embed.external.thumb, { - aspectRatio: { - width: 1200, - height: 630, - }, - }) - } - } - - if (AppBskyEmbedRecord.isView(post.embed)) { - if (AppBskyEmbedRecord.isViewRecord(post.embed.record)) { - if (post.embed.record.author.avatar) { - images.set(post.embed.record.author.avatar, { - aspectRatio: { - width: 1000, - height: 1000, - }, - }) - } - - for (const embed of post.embed.record.embeds) { - if (AppBskyEmbedImages.isView(embed)) { - for (const image of embed.images) { - images.set(image.fullsize, { - aspectRatio: normalizeAspectRatio(image.aspectRatio), - }) - } - } - if (AppBskyEmbedExternal.isView(embed)) { - if (embed.external.thumb) { - images.set(embed.external.thumb, { - aspectRatio: { - width: 1200, - height: 630, - }, - }) - } - } - if (AppBskyEmbedRecordWithMedia.isView(embed)) { - if (AppBskyEmbedImages.isView(embed.media)) { - for (const image of embed.media.images) { - images.set(image.fullsize, { - aspectRatio: normalizeAspectRatio(image.aspectRatio), - }) - } - } else if (AppBskyEmbedExternal.isView(embed.media)) { - if (embed.media.external.thumb) { - images.set(embed.media.external.thumb, { - aspectRatio: { - width: 1200, - height: 630, - }, - }) - } - } - } - - if (AppBskyGraphDefs.isListView(embed.record)) { - if (embed.record.avatar) { - images.set(embed.record.avatar, { - aspectRatio: { - width: 1000, - height: 1000, - }, - }) - } - } - - if (AppBskyFeedDefs.isGeneratorView(embed.record)) { - if (embed.record.avatar) { - images.set(embed.record.avatar, { - aspectRatio: { - width: 1000, - height: 1000, - }, - }) - } - } - - if (AppBskyGraphDefs.isStarterPackViewBasic(embed.record)) { - const uri = getStarterPackImageUri(embed.record) - images.set(uri, { - aspectRatio: { - width: 1200, - height: 630, - }, - }) - } - } - } - - if (AppBskyGraphDefs.isListView(post.embed.record)) { - if (post.embed.record.avatar) { - images.set(post.embed.record.avatar, { - aspectRatio: { - width: 1000, - height: 1000, - }, - }) - } - } - - if (AppBskyFeedDefs.isGeneratorView(post.embed.record)) { - if (post.embed.record.avatar) { - images.set(post.embed.record.avatar, { - aspectRatio: { - width: 1000, - height: 1000, - }, - }) - } - } - - if (AppBskyGraphDefs.isStarterPackViewBasic(post.embed.record)) { - const uri = getStarterPackImageUri(post.embed.record) - images.set(uri, { - aspectRatio: { - width: 1200, - height: 630, - }, - }) - } - } - - if (AppBskyEmbedRecordWithMedia.isView(post.embed)) { - // get OPs media - if (AppBskyEmbedImages.isView(post.embed.media)) { - for (const image of post.embed.media.images) { - images.set(image.fullsize, { - aspectRatio: normalizeAspectRatio(image.aspectRatio), - }) - } - } - - if (AppBskyEmbedExternal.isView(post.embed.media)) { - if (post.embed.media.external.thumb) { - images.set(post.embed.media.external.thumb, { - aspectRatio: { - width: 1200, - height: 630, - }, - }) - } - } - - // get media from embedded post - if (AppBskyEmbedRecord.isViewRecord(post.embed.record.record)) { - for (const embed of post.embed.record.record.embeds) { - if (AppBskyEmbedImages.isView(embed)) { - for (const image of embed.images) { - images.set(image.fullsize, { - aspectRatio: normalizeAspectRatio(image.aspectRatio), - }) - } - } - if (AppBskyEmbedExternal.isView(embed)) { - if (embed.external.thumb) { - images.set(embed.external.thumb, { - aspectRatio: { - width: 1200, - height: 630, - }, - }) - } - } - if (AppBskyEmbedRecordWithMedia.isView(embed)) { - if (AppBskyEmbedImages.isView(embed.media)) { - for (const image of embed.media.images) { - images.set(image.fullsize, { - aspectRatio: normalizeAspectRatio(image.aspectRatio), - }) - } - } else if (AppBskyEmbedExternal.isView(embed.media)) { - if (embed.media.external.thumb) { - images.set(embed.media.external.thumb, { - aspectRatio: { - width: 1200, - height: 630, - }, - }) - } - } - } - } - } - } + getEmbedData(parseEmbed(post.embed), images) } const deduped = Array.from(images.entries()) diff --git a/bskyogcard/src/routes/post.tsx b/bskyogcard/src/routes/post.tsx index 763d3afb42..c792656f50 100644 --- a/bskyogcard/src/routes/post.tsx +++ b/bskyogcard/src/routes/post.tsx @@ -1,4 +1,3 @@ -import React from 'react' import {AppBskyFeedPost, AtUri} from '@atproto/api' import resvg from '@resvg/resvg-js' import {Express} from 'express' diff --git a/bskyogcard/src/routes/starter-pack.tsx b/bskyogcard/src/routes/starter-pack.tsx index f6b6dc20f4..e287463bc5 100644 --- a/bskyogcard/src/routes/starter-pack.tsx +++ b/bskyogcard/src/routes/starter-pack.tsx @@ -1,7 +1,6 @@ import assert from 'node:assert' -import React from 'react' -import {AppBskyGraphDefs, AtUri} from '@atproto/api' +import {AppBskyActorDefs,AppBskyGraphDefs, AtUri} from '@atproto/api' import resvg from '@resvg/resvg-js' import {Express} from 'express' import satori from 'satori' @@ -37,7 +36,13 @@ export default function (ctx: AppContext, app: Express) { return res.status(404).end('not found') } const imageEntries = await Promise.all( - [starterPack.creator] + ( + [] as ( + | AppBskyActorDefs.ProfileViewBasic + | AppBskyActorDefs.ProfileView + )[] + ) + .concat([starterPack.creator]) .concat(starterPack.listItemsSample.map(li => li.subject)) // has avatar .filter(p => p.avatar) diff --git a/bskyogcard/src/util/parseEmbed.ts b/bskyogcard/src/util/parseEmbed.ts new file mode 100644 index 0000000000..97c3dc33e7 --- /dev/null +++ b/bskyogcard/src/util/parseEmbed.ts @@ -0,0 +1,152 @@ +/** + * This file is a copy of what exists in the social-app + */ + +import { + AppBskyEmbedExternal, + AppBskyEmbedImages, + AppBskyEmbedRecord, + AppBskyEmbedRecordWithMedia, + AppBskyEmbedVideo, + AppBskyFeedDefs, + AppBskyGraphDefs, + AppBskyLabelerDefs, +} from '@atproto/api' + +export type Embed = + | { + type: 'post' + view: AppBskyEmbedRecord.ViewRecord + } + | { + type: 'post_not_found' + view: AppBskyEmbedRecord.ViewNotFound + } + | { + type: 'post_blocked' + view: AppBskyEmbedRecord.ViewBlocked + } + | { + type: 'post_detached' + view: AppBskyEmbedRecord.ViewDetached + } + | { + type: 'feed' + view: AppBskyFeedDefs.GeneratorView + } + | { + type: 'list' + view: AppBskyGraphDefs.ListView + } + | { + type: 'labeler' + view: AppBskyLabelerDefs.LabelerView + } + | { + type: 'starter_pack' + view: AppBskyGraphDefs.StarterPackViewBasic + } + | { + type: 'images' + view: AppBskyEmbedImages.View + } + | { + type: 'link' + view: AppBskyEmbedExternal.View + } + | { + type: 'video' + view: AppBskyEmbedVideo.View + } + | { + type: 'post_with_media' + view: Embed + media: Embed + } + | { + type: 'unknown' + view: null + } + +export type EmbedType = Extract + +export function parseEmbedRecordView({record}: AppBskyEmbedRecord.View): Embed { + if (AppBskyEmbedRecord.isViewRecord(record)) { + return { + type: 'post', + view: record, + } + } else if (AppBskyEmbedRecord.isViewNotFound(record)) { + return { + type: 'post_not_found', + view: record, + } + } else if (AppBskyEmbedRecord.isViewBlocked(record)) { + return { + type: 'post_blocked', + view: record, + } + } else if (AppBskyEmbedRecord.isViewDetached(record)) { + return { + type: 'post_detached', + view: record, + } + } else if (AppBskyFeedDefs.isGeneratorView(record)) { + return { + type: 'feed', + view: record, + } + } else if (AppBskyGraphDefs.isListView(record)) { + return { + type: 'list', + view: record, + } + } else if (AppBskyLabelerDefs.isLabelerView(record)) { + return { + type: 'labeler', + view: record, + } + } else if (AppBskyGraphDefs.isStarterPackViewBasic(record)) { + return { + type: 'starter_pack', + view: record, + } + } else { + return { + type: 'unknown', + view: null, + } + } +} + +export function parseEmbed(embed: AppBskyFeedDefs.PostView['embed']): Embed { + if (AppBskyEmbedImages.isView(embed)) { + return { + type: 'images', + view: embed, + } + } else if (AppBskyEmbedExternal.isView(embed)) { + return { + type: 'link', + view: embed, + } + } else if (AppBskyEmbedVideo.isView(embed)) { + return { + type: 'video', + view: embed, + } + } else if (AppBskyEmbedRecord.isView(embed)) { + return parseEmbedRecordView(embed) + } else if (AppBskyEmbedRecordWithMedia.isView(embed)) { + return { + type: 'post_with_media', + view: parseEmbedRecordView(embed.record), + media: parseEmbed(embed.media), + } + } else { + return { + type: 'unknown', + view: null, + } + } +} diff --git a/bskyogcard/yarn.lock b/bskyogcard/yarn.lock index 08b65797ac..9a3a6eb9bc 100644 --- a/bskyogcard/yarn.lock +++ b/bskyogcard/yarn.lock @@ -2,18 +2,19 @@ # yarn lockfile v1 -"@atproto/api@^0.13.4": - version "0.13.4" - resolved "https://registry.yarnpkg.com/@atproto/api/-/api-0.13.4.tgz#47631e622760b2a18e4aee75b728e9cf8952e221" - integrity sha512-Fwn37hP+Xr9YjA/hadvn7ZKbUPQhJiUus1+govgNKF3/jNdyk2ICoEe0z+hxaO3xX8LCU5yARbgt3SRoXbIwrg== +"@atproto/api@0.14.0-next.2": + version "0.14.0-next.2" + resolved "https://registry.yarnpkg.com/@atproto/api/-/api-0.14.0-next.2.tgz#c42313217dc5cbbd81438706018963d4232a4ba6" + integrity sha512-1FADZQAklDozrGDxrb6ydkrlBBES4sKP7wJZTtwzqb1bSUOqRD8vjuvVvklt2ahhAQvslsBUC1wBrMa7VGS6hA== dependencies: - "@atproto/common-web" "^0.3.0" - "@atproto/lexicon" "^0.4.1" - "@atproto/syntax" "^0.3.0" - "@atproto/xrpc" "^0.6.1" + "@atproto/common-web" "^0.3.2" + "@atproto/lexicon" "^0.4.5" + "@atproto/syntax" "^0.3.1" + "@atproto/xrpc" "^0.6.6" await-lock "^2.2.2" multiformats "^9.9.0" tlds "^1.234.0" + zod "^3.23.8" "@atproto/common-web@^0.3.0": version "0.3.0" @@ -25,6 +26,16 @@ uint8arrays "3.0.0" zod "^3.21.4" +"@atproto/common-web@^0.3.2": + version "0.3.2" + resolved "https://registry.yarnpkg.com/@atproto/common-web/-/common-web-0.3.2.tgz#4cf78ad4d24fed801882f3d35afc39bceccdff51" + integrity sha512-Vx0JtL1/CssJbFAb0UOdvTrkbUautsDfHNOXNTcX2vyPIxH9xOameSqLLunM1hZnOQbJwyjmQCt6TV+bhnanDg== + dependencies: + graphemer "^1.4.0" + multiformats "^9.9.0" + uint8arrays "3.0.0" + zod "^3.23.8" + "@atproto/common@^0.4.0": version "0.4.0" resolved "https://registry.npmjs.org/@atproto/common/-/common-0.4.0.tgz" @@ -37,28 +48,28 @@ multiformats "^9.9.0" pino "^8.15.0" -"@atproto/lexicon@^0.4.1": - version "0.4.1" - resolved "https://registry.yarnpkg.com/@atproto/lexicon/-/lexicon-0.4.1.tgz#19155210570a2fafbcc7d4f655d9b813948e72a0" - integrity sha512-bzyr+/VHXLQWbumViX5L7h1NKQObfs8Z+XZJl43OUK8nYFUI4e/sW1IZKRNfw7Wvi5YVNK+J+yP3DWIBZhkCYA== +"@atproto/lexicon@^0.4.5": + version "0.4.5" + resolved "https://registry.yarnpkg.com/@atproto/lexicon/-/lexicon-0.4.5.tgz#4fcf3731193c674286e9e8d677bbab5dd530b817" + integrity sha512-fljWqMGKn+XWtTprBcS3F1hGBREnQYh6qYHv2sjENucc7REms1gtmZXSerB9N6pVeHVNOnXiILdukeAcic5OEw== dependencies: - "@atproto/common-web" "^0.3.0" - "@atproto/syntax" "^0.3.0" + "@atproto/common-web" "^0.3.2" + "@atproto/syntax" "^0.3.1" iso-datestring-validator "^2.2.2" multiformats "^9.9.0" zod "^3.23.8" -"@atproto/syntax@^0.3.0": - version "0.3.0" - resolved "https://registry.npmjs.org/@atproto/syntax/-/syntax-0.3.0.tgz" - integrity sha512-Weq0ZBxffGHDXHl9U7BQc2BFJi/e23AL+k+i5+D9hUq/bzT4yjGsrCejkjq0xt82xXDjmhhvQSZ0LqxyZ5woxA== +"@atproto/syntax@^0.3.1": + version "0.3.1" + resolved "https://registry.yarnpkg.com/@atproto/syntax/-/syntax-0.3.1.tgz#4346418728f9643d783d2ffcf7c77e132e1f53d4" + integrity sha512-fzW0Mg1QUOVCWUD3RgEsDt6d1OZ6DdFmbKcDdbzUfh0t4rhtRAC05KbZYmxuMPWDAiJ4BbbQ5dkAc/mNypMXkw== -"@atproto/xrpc@^0.6.1": - version "0.6.1" - resolved "https://registry.yarnpkg.com/@atproto/xrpc/-/xrpc-0.6.1.tgz#dcd1315c8c60eef5af2db7fa4e35a38ebc6d79d5" - integrity sha512-Zy5ydXEdk6sY7FDUZcEVfCL1jvbL4tXu5CcdPqbEaW6LQtk9GLds/DK1bCX9kswTGaBC88EMuqQMfkxOhp2t4A== +"@atproto/xrpc@^0.6.6": + version "0.6.6" + resolved "https://registry.yarnpkg.com/@atproto/xrpc/-/xrpc-0.6.6.tgz#28f58270ef4a8056f7f718bd52512e74bcd3702f" + integrity sha512-umXEYVMo9/pyIBoKmIAIi64RXDW9tSXY+wqztlQ6I2GZtjLfNZqmAWU+wADk3SxUe54mvjxxGyA4TtyGtDMfhA== dependencies: - "@atproto/lexicon" "^0.4.1" + "@atproto/lexicon" "^0.4.5" zod "^3.23.8" "@cbor-extract/cbor-extract-darwin-arm64@2.2.0":