mirror of https://git.lenooby09.tech/LeNooby09/social-app.git
1import {
2 AppBskyEmbedRecord,
3 AppBskyEmbedRecordWithMedia,
4 AppBskyFeedDefs,
5 AppBskyFeedPostgate,
6 AtUri,
7} from '@atproto/api'
8
9export const POSTGATE_COLLECTION = 'app.bsky.feed.postgate'
10
11export function createPostgateRecord(
12 postgate: Partial<AppBskyFeedPostgate.Record> & {
13 post: AppBskyFeedPostgate.Record['post']
14 },
15): AppBskyFeedPostgate.Record {
16 return {
17 $type: POSTGATE_COLLECTION,
18 createdAt: new Date().toISOString(),
19 post: postgate.post,
20 detachedEmbeddingUris: postgate.detachedEmbeddingUris || [],
21 embeddingRules: postgate.embeddingRules || [],
22 }
23}
24
25export function mergePostgateRecords(
26 prev: AppBskyFeedPostgate.Record,
27 next: Partial<AppBskyFeedPostgate.Record>,
28) {
29 const detachedEmbeddingUris = Array.from(
30 new Set([
31 ...(prev.detachedEmbeddingUris || []),
32 ...(next.detachedEmbeddingUris || []),
33 ]),
34 )
35 const embeddingRules = [
36 ...(prev.embeddingRules || []),
37 ...(next.embeddingRules || []),
38 ].filter(
39 (rule, i, all) => all.findIndex(_rule => _rule.$type === rule.$type) === i,
40 )
41 return createPostgateRecord({
42 post: prev.post,
43 detachedEmbeddingUris,
44 embeddingRules,
45 })
46}
47
48export function createEmbedViewDetachedRecord({uri}: {uri: string}) {
49 const record: AppBskyEmbedRecord.ViewDetached = {
50 $type: 'app.bsky.embed.record#viewDetached',
51 uri,
52 detached: true,
53 }
54 return {
55 $type: 'app.bsky.embed.record#view',
56 record,
57 }
58}
59
60export function createMaybeDetachedQuoteEmbed({
61 post,
62 quote,
63 quoteUri,
64 detached,
65}:
66 | {
67 post: AppBskyFeedDefs.PostView
68 quote: AppBskyFeedDefs.PostView
69 quoteUri: undefined
70 detached: false
71 }
72 | {
73 post: AppBskyFeedDefs.PostView
74 quote: undefined
75 quoteUri: string
76 detached: true
77 }): AppBskyEmbedRecord.View | AppBskyEmbedRecordWithMedia.View | undefined {
78 if (AppBskyEmbedRecord.isView(post.embed)) {
79 if (detached) {
80 return createEmbedViewDetachedRecord({uri: quoteUri})
81 } else {
82 return createEmbedRecordView({post: quote})
83 }
84 } else if (AppBskyEmbedRecordWithMedia.isView(post.embed)) {
85 if (detached) {
86 return {
87 ...post.embed,
88 record: createEmbedViewDetachedRecord({uri: quoteUri}),
89 }
90 } else {
91 return createEmbedRecordWithMediaView({post, quote})
92 }
93 }
94}
95
96export function createEmbedViewRecordFromPost(
97 post: AppBskyFeedDefs.PostView,
98): AppBskyEmbedRecord.ViewRecord {
99 return {
100 $type: 'app.bsky.embed.record#viewRecord',
101 uri: post.uri,
102 cid: post.cid,
103 author: post.author,
104 value: post.record,
105 labels: post.labels,
106 replyCount: post.replyCount,
107 repostCount: post.repostCount,
108 likeCount: post.likeCount,
109 quoteCount: post.quoteCount,
110 indexedAt: post.indexedAt,
111 }
112}
113
114export function createEmbedRecordView({
115 post,
116}: {
117 post: AppBskyFeedDefs.PostView
118}): AppBskyEmbedRecord.View {
119 return {
120 $type: 'app.bsky.embed.record#view',
121 record: createEmbedViewRecordFromPost(post),
122 }
123}
124
125export function createEmbedRecordWithMediaView({
126 post,
127 quote,
128}: {
129 post: AppBskyFeedDefs.PostView
130 quote: AppBskyFeedDefs.PostView
131}): AppBskyEmbedRecordWithMedia.View | undefined {
132 if (!AppBskyEmbedRecordWithMedia.isView(post.embed)) return
133 return {
134 ...(post.embed || {}),
135 record: {
136 record: createEmbedViewRecordFromPost(quote),
137 },
138 }
139}
140
141export function getMaybeDetachedQuoteEmbed({
142 viewerDid,
143 post,
144}: {
145 viewerDid: string
146 post: AppBskyFeedDefs.PostView
147}) {
148 if (AppBskyEmbedRecord.isView(post.embed)) {
149 // detached
150 if (AppBskyEmbedRecord.isViewDetached(post.embed.record)) {
151 const urip = new AtUri(post.embed.record.uri)
152 return {
153 embed: post.embed,
154 uri: urip.toString(),
155 isOwnedByViewer: urip.host === viewerDid,
156 isDetached: true,
157 }
158 }
159
160 // post
161 if (AppBskyEmbedRecord.isViewRecord(post.embed.record)) {
162 const urip = new AtUri(post.embed.record.uri)
163 return {
164 embed: post.embed,
165 uri: urip.toString(),
166 isOwnedByViewer: urip.host === viewerDid,
167 isDetached: false,
168 }
169 }
170 } else if (AppBskyEmbedRecordWithMedia.isView(post.embed)) {
171 // detached
172 if (AppBskyEmbedRecord.isViewDetached(post.embed.record.record)) {
173 const urip = new AtUri(post.embed.record.record.uri)
174 return {
175 embed: post.embed,
176 uri: urip.toString(),
177 isOwnedByViewer: urip.host === viewerDid,
178 isDetached: true,
179 }
180 }
181
182 // post
183 if (AppBskyEmbedRecord.isViewRecord(post.embed.record.record)) {
184 const urip = new AtUri(post.embed.record.record.uri)
185 return {
186 embed: post.embed,
187 uri: urip.toString(),
188 isOwnedByViewer: urip.host === viewerDid,
189 isDetached: false,
190 }
191 }
192 }
193}
194
195export const embeddingRules = {
196 disableRule: {$type: 'app.bsky.feed.postgate#disableRule'},
197}