Sparrow He 做烂尾的玩意。我用 JS 重写了社交逻辑,但是渲染贴贴圈那块真是令人头大,甚至连排序和 CSS 都没做…凑合着看吧。MIT licensed
试图复刻 Bluesky 贴贴圈
171 lines 5.7 kB view raw
1<!DOCTYPE html> 2<html> 3 <head> 4 <meta charset="UTF-8" /> 5 <title>半个贴贴圈</title> 6 <script> 7 async function getReplyScore(handle) { 8 const ENDPOINT_URL = "https://public.api.bsky.app/xrpc/"; 9 10 async function handle2DID(handle) { 11 try { 12 const response = await fetch( 13 `${ENDPOINT_URL}com.atproto.identity.resolveHandle?handle=${handle}` 14 ); 15 if (!response.ok) { 16 throw new Error(`http response code: ${response.status}`); 17 } 18 const data = await response.json(); 19 console.log("data:", data); 20 return data; 21 } catch (error) { 22 console.error("request fail:", error); 23 throw error; 24 } 25 } 26 27 async function getPosts(did) { 28 try { 29 const response = await fetch( 30 `${ENDPOINT_URL}app.bsky.feed.getAuthorFeed?actor=${did}&limit=100&includePins=true` 31 ); 32 console.log( 33 `${ENDPOINT_URL}app.bsky.feed.getAuthorFeed?actor=${did}&limit=100&includePins=true` 34 ); 35 if (!response.ok) { 36 throw new Error(`http response code: ${response.status}`); 37 } 38 const data = await response.json(); 39 // console.log("data:", data); 40 return data; 41 } catch (error) { 42 console.error("request fail:", error); 43 throw error; 44 } 45 } 46 47 async function getReplies(uri) { 48 try { 49 const response = await fetch( 50 `${ENDPOINT_URL}app.bsky.feed.getPostThread?uri=${uri}&depth=1` 51 ); 52 console.log( 53 `${ENDPOINT_URL}app.bsky.feed.getPostThread?uri=${uri}&depth=1` 54 ); 55 if (!response.ok) { 56 throw new Error(`http response code: ${response.status}`); 57 } 58 const data = await response.json(); 59 // console.log("data:", data); 60 return data; 61 } catch (error) { 62 console.error("request fail:", error); 63 throw error; 64 } 65 } 66 67 async function getHandle(did) { 68 try { 69 const response = await fetch( 70 `${ENDPOINT_URL}app.bsky.actor.getProfile?actor=${did}` 71 ); 72 console.log( 73 `${ENDPOINT_URL}app.bsky.actor.getProfile?actor=${did}` 74 ); 75 if (!response.ok) { 76 throw new Error(`http response code: ${response.status}`); 77 } 78 const data = await response.json(); 79 // console.log("data:", data); 80 return data; 81 } catch (error) { 82 console.error("request fail:", error); 83 throw error; 84 } 85 } 86 87 function getDidByAtUrl(aturl) { 88 return aturl.split("/")[2]; 89 } 90 91 var result = {}; 92 93 const did_result = await handle2DID(handle); 94 var did = did_result.did; 95 96 const posts_result = await getPosts(did); 97 for (const item of posts_result.feed) { 98 // will recognize posts with no reason, whose replies will + 1.5 99 // posts has reply.parent, parent + 1 100 if ("reason" in item) { 101 console.warn( 102 `${item.post.uri} has reason ${item.reason.$type}, ignored` 103 ); 104 } else { 105 if ("reply" in item) { 106 console.log(`${item.post.uri} replies ${item.reply.parent.uri}`); 107 did_of_the_guy = getDidByAtUrl(item.reply.parent.uri); 108 if (!(did_of_the_guy in result)) { 109 result[did_of_the_guy] = 0.0; 110 } 111 result[did_of_the_guy] += 1.0; 112 } else { 113 main_uri = item.post.uri; 114 reply_result = await getReplies(main_uri); 115 if ("thread" in reply_result) { 116 for (const replypost of reply_result.thread.replies) { 117 reply_post_uri = replypost.post.uri; 118 did_of_the_guy = getDidByAtUrl(reply_post_uri); 119 if (!(did_of_the_guy in result)) { 120 result[did_of_the_guy] = 0.0; 121 } 122 result[did_of_the_guy] += 1.5; 123 } 124 } else { 125 console.warn(`${item.post.uri} has no replies`); 126 } 127 } 128 } 129 } 130 131 result_html = '<div class="result">\n'; 132 133 for (const final_did in result) { 134 reply_count = result[final_did]; 135 handle_result = await getHandle(final_did); 136 handle = handle_result.handle; 137 avatar = handle_result.avatar; 138 // console.log(`${handle}'s reply_count is ${reply_count}, avatar ${handle_result.avatar}`); 139 result_html += `<div did="${final_did}">\n`; 140 result_html += `<img src="${avatar}">\n`; 141 result_html += `<a class="handle">${handle}</a>\n`; 142 result_html += `<span class="replycount">${reply_count}</span>\n`; 143 result_html += "</div>\n"; 144 // console.log(result_html); 145 } 146 147 result_html += "</div>"; 148 149 return result_html; 150 } 151 152 // 使用示例 153 async function main() { 154 try { 155 const did = await getReplyScore(document.getElementById("bruh").value); 156 console.log("result:", did); 157 document.getElementById("result").innerHTML = did 158 } catch (error) { 159 console.error("fail:", error); 160 } 161 } 162 163 main(); 164 </script> 165 </head> 166 <body> 167 <input type="text" id="bruh" value="输入 handle" /> 168 <button onclick="main()">启动</button> 169 <div id="result"></div> 170 </body> 171</html>