[READ-ONLY] Mirror of https://github.com/flo-bit/bluesky-wordcloud. showing a wordcloud of all english bluesky posts in the last 10 seconds flo-bit.dev/bluesky-visualizers/wordcloud
0

Configure Feed

Select the types of activity you want to include in your feed.

Merge pull request #3 from flo-bit/main

redirect

author
Florian
committer
GitHub
date (Nov 19, 2024, 3:56 AM +0100) commit d240798e parent 1eb44278
+7 -373
+4 -1
README.md
··· 1 1 # bluesky wordcloud 2 2 3 + > [!NOTE] 4 + > moved to be part of https://github.com/flo-bit/bluesky-visualizers 5 + 3 6 showing a wordcloud of all english bluesky posts in the last 10 seconds 4 7 5 8 built with d3-cloud, svelte, tailwind. 6 9 7 - [live here](https://flo-bit.dev/bluesky-wordcloud/) 10 + [live here](https://flo-bit.dev/bluesky-visualizers/wordcloud) 8 11 9 12 <img width="1325" alt="wordcloud" src="https://github.com/user-attachments/assets/92296478-56de-4cc8-adb4-40195fef5bcd">
-4
src/app.html
··· 1 1 <!doctype html> 2 2 <html lang="en"> 3 - <script> 4 - !function(t,e){var o,n,p,r;e.__SV||(window.posthog=e,e._i=[],e.init=function(i,s,a){function g(t,e){var o=e.split(".");2==o.length&&(t=t[o[0]],e=o[1]),t[e]=function(){t.push([e].concat(Array.prototype.slice.call(arguments,0)))}}(p=t.createElement("script")).type="text/javascript",p.async=!0,p.src=s.api_host.replace(".i.posthog.com","-assets.i.posthog.com")+"/static/array.js",(r=t.getElementsByTagName("script")[0]).parentNode.insertBefore(p,r);var u=e;for(void 0!==a?u=e[a]=[]:a="posthog",u.people=u.people||[],u.toString=function(t){var e="posthog";return"posthog"!==a&&(e+="."+a),t||(e+=" (stub)"),e},u.people.toString=function(){return u.toString(1)+".people (stub)"},o="capture identify alias people.set people.set_once set_config register register_once unregister opt_out_capturing has_opted_out_capturing opt_in_capturing reset isFeatureEnabled onFeatureFlags getFeatureFlag getFeatureFlagPayload reloadFeatureFlags group updateEarlyAccessFeatureEnrollment getEarlyAccessFeatures getActiveMatchingSurveys getSurveys getNextSurveyStep onSessionId".split(" "),n=0;n<o.length;n++)g(u,o[n]);e._i.push([i,s,a])},e.__SV=1)}(document,window.posthog||[]); 5 - posthog.init('phc_1Q4q6SdTwvStnxFWbmdOIusLc5ve0u6Fk7WpsHPoAlD',{api_host:'https://eu.i.posthog.com', person_profiles: 'identified_only', persistence: 'memory'}) 6 - </script> 7 3 8 4 <head> 9 5 <meta charset="utf-8" />
+3 -368
src/routes/+page.svelte
··· 1 1 <script lang="ts"> 2 - import { onMount } from 'svelte'; 3 - import WordCloud from './Wordcloud.svelte'; 4 - 5 - let words: { text: string; count: number }[] = []; 6 - 7 - const wordCounts = new Map<string, number>(); 8 - 9 - let posts = 0; 10 - 11 - let countdown = 3; 12 - 13 - let firstCountdown = true; 14 - 15 - let width: number; 16 - let height: number; 17 - 18 - const fillerWords = new Set([ 19 - 'a', 20 - 'an', 21 - 'the', 22 - 'and', 23 - 'or', 24 - 'but', 25 - 'if', 26 - 'then', 27 - 'so', 28 - 'because', 29 - 'as', 30 - 'of', 31 - 'at', 32 - 'by', 33 - 'for', 34 - 'with', 35 - 'about', 36 - 'against', 37 - 'between', 38 - 'into', 39 - 'through', 40 - 'during', 41 - 'before', 42 - 'after', 43 - 'above', 44 - 'below', 45 - 'to', 46 - 'from', 47 - 'up', 48 - 'down', 49 - 'in', 50 - 'out', 51 - 'on', 52 - 'off', 53 - 'over', 54 - 'under', 55 - 'again', 56 - 'further', 57 - 'then', 58 - 'once', 59 - 'here', 60 - 'there', 61 - 'when', 62 - 'where', 63 - 'why', 64 - 'how', 65 - 'all', 66 - 'any', 67 - 'both', 68 - 'each', 69 - 'few', 70 - 'more', 71 - 'most', 72 - 'other', 73 - 'some', 74 - 'such', 75 - 'no', 76 - 'nor', 77 - 'not', 78 - 'only', 79 - 'own', 80 - 'same', 81 - 'so', 82 - 'than', 83 - 'too', 84 - 'very', 85 - 's', 86 - 't', 87 - 'can', 88 - 'will', 89 - 'just', 90 - 'don', 91 - 'should', 92 - 'now', 93 - 'i', 94 - 'me', 95 - 'my', 96 - 'myself', 97 - 'we', 98 - 'our', 99 - 'ours', 100 - 'ourselves', 101 - 'you', 102 - 'your', 103 - 'yours', 104 - 'yourself', 105 - 'yourselves', 106 - 'he', 107 - 'him', 108 - 'his', 109 - 'himself', 110 - 'she', 111 - 'her', 112 - 'hers', 113 - 'herself', 114 - 'it', 115 - 'its', 116 - 'itself', 117 - 'they', 118 - 'them', 119 - 'their', 120 - 'theirs', 121 - 'themselves', 122 - 'what', 123 - 'which', 124 - 'who', 125 - 'whom', 126 - 'this', 127 - 'that', 128 - 'these', 129 - 'those', 130 - 'am', 131 - 'is', 132 - 'are', 133 - 'was', 134 - 'were', 135 - 'be', 136 - 'been', 137 - 'being', 138 - 'have', 139 - 'has', 140 - 'had', 141 - 'having', 142 - 'do', 143 - 'does', 144 - 'did', 145 - 'doing', 146 - 'a', 147 - 'an', 148 - 'the', 149 - 'and', 150 - 'or', 151 - 'but', 152 - 'if', 153 - 'then', 154 - 'else', 155 - 'because', 156 - 'as', 157 - 'of', 158 - 'at', 159 - 'by', 160 - 'for', 161 - 'with', 162 - 'about', 163 - 'against', 164 - 'between', 165 - 'into', 166 - 'through', 167 - 'during', 168 - 'before', 169 - 'after', 170 - 'above', 171 - 'below', 172 - 'to', 173 - 'from', 174 - 'up', 175 - 'down', 176 - 'in', 177 - 'out', 178 - 'on', 179 - 'off', 180 - 'over', 181 - 'under', 182 - 'again', 183 - 'further', 184 - 'then', 185 - 'once', 186 - 'here', 187 - 'there', 188 - 'when', 189 - 'where', 190 - 'why', 191 - 'how', 192 - 'all', 193 - 'any', 194 - 'both', 195 - 'each', 196 - 'few', 197 - 'more', 198 - 'most', 199 - 'other', 200 - 'some', 201 - 'such', 202 - 'no', 203 - 'nor', 204 - 'not', 205 - 'only', 206 - 'own', 207 - 'same', 208 - 'so', 209 - 'than', 210 - 'too', 211 - 'very', 212 - 's', 213 - 't', 214 - 'can', 215 - 'will', 216 - 'just', 217 - 'don', 218 - 'should', 219 - 'now' 220 - ]); 2 + import { onMount } from "svelte"; 221 3 222 4 onMount(() => { 223 - function updateDimensions() { 224 - width = window.innerWidth; 225 - height = window.innerHeight; 226 - } 227 - 228 - updateDimensions(); 229 - 230 - setTimeout(() => { 231 - updateWords(); 232 - setInterval(updateWords, 10000); 233 - }, 3000); 234 - 235 - let countdownInterval = setInterval(() => { 236 - countdown--; 237 - 238 - if (countdown === 0) { 239 - firstCountdown = false; 240 - countdown = 10; 241 - } 242 - }, 1000); 243 - 244 - window.addEventListener('resize', updateDimensions); 245 - 246 - function secondsToMicroseconds(seconds: number) { 247 - return Math.floor(seconds * 1000000); 248 - } 249 - 250 - const startTime = Date.now() * 1000 - secondsToMicroseconds(10); 251 - console.log(startTime); 252 - 253 - // WebSocket URL from BlueSky 254 - const url = 255 - 'wss://jetstream2.us-east.bsky.network/subscribe?wantedCollections=app.bsky.feed.post&cursor=' + 256 - startTime; 257 - 258 - // WebSocket logic 259 - const ws = new WebSocket(url); 260 - ws.onopen = () => { 261 - console.log('Connected to BlueSky WebSocket'); 262 - }; 263 - 264 - ws.onmessage = (event) => { 265 - const json = JSON.parse(event.data); 266 - 267 - if ( 268 - json.kind === 'commit' && 269 - json.commit.collection === 'app.bsky.feed.post' && 270 - json.commit.operation === 'create' && 271 - json.commit.record.text && 272 - (!json.commit.record.langs || json.commit.record.langs.includes('en')) 273 - ) { 274 - // get text of post 275 - const text: string = json.commit.record.text; 276 - 277 - // split text into words (split by whitespace, newlines, punctuation) 278 - const words = text.split(/[\s\n\.,!?;]+/); 279 - 280 - words.forEach((word) => { 281 - // skip words that are empty or not alphanumeric 282 - if (!word || !word.match(/^[a-zA-Z]+$/) || fillerWords.has(word.toLowerCase())) { 283 - return; 284 - } 285 - // turn to lowercase 286 - word = word.toLowerCase(); 287 - 288 - wordCounts.set(word, (wordCounts.get(word) || 0) + 1); 289 - }); 290 - 291 - posts++; 292 - } 293 - }; 294 - 295 - return () => { 296 - ws.close(); 297 - window.removeEventListener('resize', updateDimensions); 298 - 299 - clearInterval(countdownInterval); 300 - }; 5 + // redirect to /bluesky-visualizers/wordcloud 6 + window.location.href = '/bluesky-visualizers/wordcloud'; 301 7 }); 302 - 303 - function updateWords() { 304 - // get 200 most common words 305 - const mostCommonWords = Array.from(wordCounts.entries()) 306 - .sort((a, b) => b[1] - a[1]) 307 - .slice(0, 300); 308 - 309 - words = mostCommonWords.map(([text, count]) => ({ text, count })); 310 - 311 - // clear wordCounts 312 - wordCounts.clear(); 313 - } 314 8 </script> 315 - 316 - <div class="flex h-screen w-screen items-center justify-center overflow-hidden"> 317 - {#if width && height} 318 - <WordCloud {words} {width} {height} /> 319 - {/if} 320 - </div> 321 - 322 - {#if countdown > 0 && firstCountdown} 323 - <div class="absolute inset-0 flex h-full w-full items-center justify-center text-8xl font-bold"> 324 - {countdown} 325 - </div> 326 - {/if} 327 - 328 - <div 329 - class="absolute bottom-0 left-0 right-0 flex w-full justify-center bg-white/50 px-4 py-2 text-sm font-semibold text-black backdrop-blur-sm" 330 - > 331 - <div> 332 - {#if countdown > 0 && firstCountdown} 333 - collecting posts and counting words... 334 - {:else} 335 - showing most common words of the last 10 seconds excluding filler words, update in {countdown}... 336 - {/if} 337 - </div> 338 - </div> 339 - 340 - <div 341 - class="absolute left-0 top-0 flex w-full items-center justify-between px-4 py-2 text-sm font-semibold" 342 - > 343 - <div> 344 - by <a 345 - href="https://flo-bit.dev/" 346 - class="transition-colors duration-100 hover:text-cyan-600" 347 - target="_blank">flo-bit</a 348 - > 349 - </div> 350 - 351 - <div> 352 - <a 353 - class="z-10 text-black transition-colors duration-100 hover:text-cyan-600" 354 - href="https://github.com/flo-bit/bluesky-wordcloud" 355 - target="_blank" 356 - > 357 - <span class="sr-only">GitHub Code</span> 358 - <svg fill="currentColor" viewBox="0 0 24 24" aria-hidden="true" class="size-6"> 359 - <path 360 - fill-rule="evenodd" 361 - d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z" 362 - clip-rule="evenodd" 363 - /> 364 - </svg> 365 - </a> 366 - </div> 367 - </div> 368 - 369 - <style> 370 - div { 371 - overflow: hidden; 372 - } 373 - </style>