mirror of https://git.lenooby09.tech/LeNooby09/social-app.git
1import {useEffect, useState} from 'react'
2import {msg} from '@lingui/macro'
3import {useLingui} from '@lingui/react'
4
5import {logger} from '#/logger'
6import {useFetchDid} from '#/state/queries/handle'
7import {useGetPost} from '#/state/queries/post'
8import {useAgent} from '#/state/session'
9import * as apilib from 'lib/api/index'
10import {POST_IMG_MAX} from 'lib/constants'
11import {
12 EmbeddingDisabledError,
13 getFeedAsEmbed,
14 getListAsEmbed,
15 getPostAsQuote,
16 getStarterPackAsEmbed,
17} from 'lib/link-meta/bsky'
18import {getLinkMeta} from 'lib/link-meta/link-meta'
19import {resolveShortLink} from 'lib/link-meta/resolve-short-link'
20import {downloadAndResize} from 'lib/media/manip'
21import {
22 isBskyCustomFeedUrl,
23 isBskyListUrl,
24 isBskyPostUrl,
25 isBskyStarterPackUrl,
26 isBskyStartUrl,
27 isShortLink,
28} from 'lib/strings/url-helpers'
29import {ImageModel} from 'state/models/media/image'
30import {ComposerOpts} from 'state/shell/composer'
31
32export function useExternalLinkFetch({
33 setQuote,
34 setError,
35}: {
36 setQuote: (opts: ComposerOpts['quote']) => void
37 setError: (err: string) => void
38}) {
39 const {_} = useLingui()
40 const [extLink, setExtLink] = useState<apilib.ExternalEmbedDraft | undefined>(
41 undefined,
42 )
43 const getPost = useGetPost()
44 const fetchDid = useFetchDid()
45 const agent = useAgent()
46
47 useEffect(() => {
48 let aborted = false
49 const cleanup = () => {
50 aborted = true
51 }
52 if (!extLink) {
53 return cleanup
54 }
55 if (!extLink.meta) {
56 if (isBskyPostUrl(extLink.uri)) {
57 getPostAsQuote(getPost, extLink.uri).then(
58 newQuote => {
59 if (aborted) {
60 return
61 }
62 setQuote(newQuote)
63 setExtLink(undefined)
64 },
65 err => {
66 if (err instanceof EmbeddingDisabledError) {
67 setError(_(msg`This post's author has disabled quote posts.`))
68 } else {
69 logger.error('Failed to fetch post for quote embedding', {
70 message: err.toString(),
71 })
72 }
73 setExtLink(undefined)
74 },
75 )
76 } else if (isBskyCustomFeedUrl(extLink.uri)) {
77 getFeedAsEmbed(agent, fetchDid, extLink.uri).then(
78 ({embed, meta}) => {
79 if (aborted) {
80 return
81 }
82 setExtLink({
83 uri: extLink.uri,
84 isLoading: false,
85 meta,
86 embed,
87 })
88 },
89 err => {
90 logger.error('Failed to fetch feed for embedding', {message: err})
91 setExtLink(undefined)
92 },
93 )
94 } else if (isBskyListUrl(extLink.uri)) {
95 getListAsEmbed(agent, fetchDid, extLink.uri).then(
96 ({embed, meta}) => {
97 if (aborted) {
98 return
99 }
100 setExtLink({
101 uri: extLink.uri,
102 isLoading: false,
103 meta,
104 embed,
105 })
106 },
107 err => {
108 logger.error('Failed to fetch list for embedding', {message: err})
109 setExtLink(undefined)
110 },
111 )
112 } else if (
113 isBskyStartUrl(extLink.uri) ||
114 isBskyStarterPackUrl(extLink.uri)
115 ) {
116 getStarterPackAsEmbed(agent, fetchDid, extLink.uri).then(
117 ({embed, meta}) => {
118 if (aborted) {
119 return
120 }
121 setExtLink({
122 uri: extLink.uri,
123 isLoading: false,
124 meta,
125 embed,
126 })
127 },
128 )
129 } else if (isShortLink(extLink.uri)) {
130 if (isShortLink(extLink.uri)) {
131 resolveShortLink(extLink.uri).then(res => {
132 if (res && res !== extLink.uri) {
133 setExtLink({
134 uri: res,
135 isLoading: true,
136 })
137 }
138 })
139 }
140 } else {
141 getLinkMeta(agent, extLink.uri).then(meta => {
142 if (aborted) {
143 return
144 }
145 setExtLink({
146 uri: extLink.uri,
147 isLoading: !!meta.image,
148 meta,
149 })
150 })
151 }
152 return cleanup
153 }
154 if (extLink.isLoading && extLink.meta?.image && !extLink.localThumb) {
155 downloadAndResize({
156 uri: extLink.meta.image,
157 width: POST_IMG_MAX.width,
158 height: POST_IMG_MAX.height,
159 mode: 'contain',
160 maxSize: POST_IMG_MAX.size,
161 timeout: 15e3,
162 })
163 .catch(() => undefined)
164 .then(localThumb => {
165 if (aborted) {
166 return
167 }
168 setExtLink({
169 ...extLink,
170 isLoading: false, // done
171 localThumb: localThumb ? new ImageModel(localThumb) : undefined,
172 })
173 })
174 return cleanup
175 }
176 if (extLink.isLoading) {
177 setExtLink({
178 ...extLink,
179 isLoading: false, // done
180 })
181 }
182 return cleanup
183 }, [_, extLink, setQuote, getPost, fetchDid, agent, setError])
184
185 return {extLink, setExtLink}
186}