@@ -76,30 +76,80 @@ async function login(username, password) {
76
76
return null ;
77
77
}
78
78
79
- function bucketTerms ( allTerms , opts = { } ) {
79
+ async function appBskyFeedGetAuthorFeed ( session , did ) {
80
+ if ( session === null ) {
81
+ return null ;
82
+ }
83
+ const url =
84
+ "https://bsky.social/xrpc/app.bsky.feed.getAuthorFeed?" +
85
+ new URLSearchParams ( {
86
+ actor : did ,
87
+ limit : 30 ,
88
+ } ) ;
89
+ return await fetchWithCounter ( url , {
90
+ headers : {
91
+ Authorization : `Bearer ${ session . accessJwt } ` ,
92
+ } ,
93
+ } ) ;
94
+ }
95
+
96
+ function bucketTerms ( allTerms , opts = { } ) {
80
97
let maxSearchTerms = opts [ "maxSearchTerms" ] || MAX_SEARCH_TERMS ;
81
- let pinnedPosts = [ ] ;
98
+ let posts = [ ] ;
99
+ let users = [ ] ;
82
100
let searchTerms = [ ] ;
83
101
84
102
for ( let term of allTerms ) {
85
103
if ( term . startsWith ( "at://" ) ) {
86
- pinnedPosts . push ( term ) ;
104
+ if ( term . indexOf ( "/app.bsky.feed.post/" ) > - 1 ) {
105
+ posts . push ( term ) ;
106
+ } else {
107
+ let user = term . replace ( / ^ a t : \/ \/ / , "" ) ;
108
+ users . push ( user ) ;
109
+ }
87
110
} else {
88
111
searchTerms . push ( term ) ;
89
112
}
90
113
}
91
114
92
115
return {
93
- pinnedPosts : pinnedPosts ,
116
+ posts : posts ,
117
+ users : users ,
94
118
searchTerms : searchTerms . slice ( 0 , maxSearchTerms ) ,
119
+ } ;
120
+ }
121
+
122
+ async function fetchSearchTerms ( searchTerms ) {
123
+ let responses = [ ] ;
124
+ let urls = [ ] ;
125
+ for ( let searchTerm of searchTerms ) {
126
+ let url =
127
+ "https://search.bsky.social/search/posts?" +
128
+ new URLSearchParams ( {
129
+ q : searchTerm ,
130
+ } ) ;
131
+ urls . push ( url ) ;
132
+ }
133
+ for ( let url of urls ) {
134
+ responses . push ( await fetchWithCounter ( url ) ) ;
135
+ }
136
+ return responses . map ( ( response ) => {
137
+ return { type : "search" , response : response } ;
138
+ } ) ;
139
+ }
140
+
141
+ async function fetchUsers ( session , users ) {
142
+ let responses = [ ] ;
143
+ let urls = [ ] ;
144
+ for ( let user of users ) {
145
+ responses . push ( await appBskyFeedGetAuthorFeed ( session , user ) ) ;
95
146
}
147
+ return responses . map ( ( response ) => {
148
+ return { type : "user" , response : response } ;
149
+ } ) ;
96
150
}
97
151
98
152
async function getFeedSkeleton ( request , env ) {
99
- let session = await loginWithEnv ( env ) ;
100
- console . log ( "session" , session ) ;
101
- console . log ( "auth headers" , request . headers . get ( "Authorization" ) ) ;
102
-
103
153
const url = new URL ( request . url ) ;
104
154
const feedAtUrl = url . searchParams . get ( "feed" ) ;
105
155
if ( feedAtUrl === null ) {
@@ -126,47 +176,67 @@ async function getFeedSkeleton(request, env) {
126
176
maxSearchTerms : MAX_SEARCH_TERMS ,
127
177
} ) ;
128
178
let searchTerms = allTerms . searchTerms ;
129
- let pinnedPosts = allTerms . pinnedPosts ;
179
+ let posts = allTerms . posts ;
180
+ let users = allTerms . users ;
130
181
if ( ! showPins ) {
131
- pinnedPosts = [ ] ;
182
+ posts = [ ] ;
132
183
}
133
- let responses = [ ] ;
184
+ let typedResponses = [ ] ;
134
185
let urls = [ ] ;
135
186
136
- for ( let searchTerm of searchTerms ) {
137
- let url =
138
- "https://search.bsky.social/search/posts?" +
139
- new URLSearchParams ( {
140
- q : searchTerm ,
141
- } ) ;
142
- urls . push ( url ) ;
143
- }
144
- for ( let url of urls ) {
145
- responses . push ( await fetchWithCounter ( url ) ) ;
187
+ typedResponses . push ( ...( await fetchSearchTerms ( searchTerms ) ) ) ;
188
+
189
+ let session = null ;
190
+ if ( users . length > 0 ) {
191
+ session = await loginWithEnv ( env ) ;
192
+ typedResponses . push ( ...( await fetchUsers ( session , users ) ) ) ;
146
193
}
147
194
148
195
let allItems = [ ] ;
149
- for ( let response of responses ) {
150
- if ( response !== null ) {
151
- let items = await response . json ( ) ;
152
- allItems = allItems . concat ( items ) ;
196
+ for ( let typedResponse of typedResponses ) {
197
+ if ( typedResponse !== null ) {
198
+ let response = typedResponse . response ;
199
+ if ( response !== null ) {
200
+ let jsonResponse = await response . json ( ) ;
201
+ allItems . push ( {
202
+ type : typedResponse . type ,
203
+ json : jsonResponse ,
204
+ } ) ;
205
+ }
153
206
}
154
207
}
155
208
156
209
let timestampURLs = [ ] ;
157
210
for ( let item of allItems ) {
158
- let did = item . user . did ;
159
- let rkey = item . tid . split ( "/" ) . slice ( - 1 ) [ 0 ] ;
160
- let timestamp = item . post . createdAt ;
161
- let atURL = `at://${ did } /app.bsky.feed.post/${ rkey } ` ;
162
- timestampURLs . push ( [ timestamp , atURL ] ) ;
211
+ if ( item . type === "search" ) {
212
+ let did = item . user . did ;
213
+ let rkey = item . tid . split ( "/" ) . slice ( - 1 ) [ 0 ] ;
214
+ let timestamp = item . post . createdAt ;
215
+ let atURL = `at://${ did } /app.bsky.feed.post/${ rkey } ` ;
216
+ timestampURLs . push ( [ timestamp , atURL ] ) ;
217
+ } else if ( item . type === "user" ) {
218
+ if ( item . json . feed !== undefined ) {
219
+ for ( let feedItem of item . json . feed ) {
220
+ if (
221
+ feedItem . post !== undefined &&
222
+ feedItem . post . record !== undefined
223
+ ) {
224
+ let timestamp = feedItem . post . record . createdAt ;
225
+ let atURL = feedItem . post . uri ;
226
+ timestampURLs . push ( [ timestamp , atURL ] ) ;
227
+ }
228
+ }
229
+ }
230
+ } else {
231
+ console . warn ( `Unknown item type ${ item . type } ` ) ;
232
+ }
163
233
}
164
234
165
235
timestampURLs = timestampURLs . toSorted ( ( b , a ) =>
166
236
a === b ? 0 : a < b ? - 1 : 1
167
237
) ;
168
238
var feed = [ ] ;
169
- for ( let pinnedPost of pinnedPosts ) {
239
+ for ( let pinnedPost of posts ) {
170
240
feed . push ( { post : pinnedPost } ) ;
171
241
}
172
242
for ( let timestampUrl of timestampURLs ) {
0 commit comments