-
Notifications
You must be signed in to change notification settings - Fork 1
/
index.html
151 lines (132 loc) · 5.58 KB
/
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Bluesky List</title>
</head>
<div id="app" />
<body>
<script type="module">
import { h, Component, render } from 'https://esm.sh/preact';
import htm from 'https://esm.sh/htm';
const html = htm.bind(h);
const params = new URL(window.location.toLocaleString()).searchParams;
const users = params.has('users') ? params.get('users').split(';') : [];
async function xrpc(method, params) {
const paramStr = new URLSearchParams(params).toString();
const url = `https://bsky.social/xrpc/${method}?${paramStr}`;
try {
const response = JSON.parse(await fetch(url).then(r => r.text()));
if (response.error) {
console.error(response);
return null;
}
return response;
} catch (e) {
console.error(e);
return null;
}
}
async function listRecords(params) {
const response = await xrpc('com.atproto.repo.listRecords', params);
return response !== null ? response.records : null;
}
async function resolveHandle(handle) {
const response = await xrpc('com.atproto.identity.resolveHandle', {handle: handle});
return response !== null ? response.did : null;
}
async function getPosts(repo) {
const posts = await listRecords({collection: 'app.bsky.feed.post', repo: repo});
if (!posts) {
console.error(`Could not lookup posts for ${repo}.`);
return [];
}
return posts;
}
async function getProfile(repo) {
const records =
await listRecords({collection: 'app.bsky.actor.profile', repo: repo});
if (!records) {
console.error(`Empty profile response for ${repo}`);
return {};
}
return records[0];
}
class App extends Component {
render() {
if (this.props.users.length > 0) {
return html`
<h1>Posts</h1>
<${PostList} profiles=${this.props.profiles} posts=${this.props.posts} />
`;
} else {
return html`
<h1>Create List</h1>
<p>Enter users (one per row).</p>
<p><textarea id="users" /></p>
<p><button onClick=${createList}>Create List</button></p>
`;
}
}
}
function PostList(props) {
return html`
<ul>
${props.posts.map(post => (
html`<${Post} profiles=${props.profiles} post=${post} />`
))}
</ul>
`;
}
function Post(props) {
const post = props.post;
const profiles = props.profiles;
const uriParts = post.uri.slice(5).split('/');
if (uriParts.length != 3) {
return html`<li>(weird post with unexpected URI: ${post.uri})</li>`;
}
const did = uriParts[0];
const postId = uriParts[2];
const appUrl = `https://staging.bsky.app/profile/${did}/post/${postId}`;
const name = profiles[did]?.value?.displayName || '';
const isReply = 'reply' in post.value;
return html`
<li>
<a href="${appUrl}" target="_blank">
<b>${name}</b> ${isReply? '(reply)' : ''}
<br />${post.value.text}
</a>
</li>
`;
}
async function createList() {
const users = document.getElementById("users").value.split('\n');
const dids = await Promise.all(users.map(user => resolveHandle(user).then(handle => handle || user)));
const paramStr = new URLSearchParams({
users: dids.join(';')
}).toString();
window.location.href = `?${paramStr}`;
}
const profileLookups = Promise.all(users.map(user => getProfile(user)));
const postLookups = Promise.all(users.map(user => getPosts(user)));
const posts = (await postLookups).flat();
posts.sort((a,b) => -a.value.createdAt.localeCompare(b.value.createdAt));
console.log(JSON.stringify(posts));
const profileList = await profileLookups;
const profiles = {};
profileList.map(profile => {
if (!profile.uri) {
return;
}
const uriParts = profile.uri.slice(5).split('/');
if (uriParts.length == 0) {
console.error(`Invalid URI for profile: ${profile.uri}`);
return;
}
const did = uriParts[0];
profiles[did] = profile;
});
render(html`<${App} users=${users} profiles=${profiles} posts=${posts} />`, document.getElementById("app"));
</script>
</body>
</html>