Thread viewer for Bluesky

scanning specific users (MVP)

+6 -2
index.html
··· 100 100 <input type="radio" name="scan_type" id="scan_type_list" value="list"> 101 101 <label for="scan_type_list">List feed</label> 102 102 103 - <input type="radio" name="scan_type" id="scan_type_users" value="users" disabled> 104 - <label for="scan_type_users">Selected users (coming soon)</label> 103 + <input type="radio" name="scan_type" id="scan_type_users" value="users"> 104 + <label for="scan_type_users">Selected users</label> 105 105 106 106 <input type="radio" name="scan_type" id="scan_type_you" value="you"> 107 107 <label for="scan_type_you">Your profile</label> ··· 114 114 <p class="list-choice"> 115 115 <label>Select list:</label> 116 116 <select name="scan_list"></select> 117 + </p> 118 + 119 + <p class="user-choice"> 120 + <textarea name="scan_users"></textarea> 117 121 </p> 118 122 119 123 <p>
+45 -10
posting_stats_page.js
··· 40 40 let value = $(r, HTMLInputElement).value; 41 41 42 42 $(this.pageElement.querySelector('.list-choice')).style.display = (value == 'list') ? 'block' : 'none'; 43 + $(this.pageElement.querySelector('.user-choice')).style.display = (value == 'users') ? 'block' : 'none'; 43 44 44 45 this.table.style.display = 'none'; 45 46 }); ··· 145 146 } 146 147 147 148 this.updateResultsTable(items, startTime, requestedDays, { showReposts: false }); 149 + } else if (scanType == 'users') { 150 + let textarea = $(this.pageElement.querySelector('textarea'), HTMLTextAreaElement); 151 + let users = textarea.value.split(/\n/).map(x => x.trim()).filter(x => x.length > 0); 152 + let dids = await Promise.all(users.map(u => accountAPI.resolveHandle(u))); 153 + 154 + let requests = dids.map(d => accountAPI.loadUserTimeline(d, requestedDays, { 155 + filter: 'posts_no_replies', 156 + onPageLoad: (data) => { 157 + if (this.scanStartTime != startTime) { 158 + return { cancel: true }; 159 + } 160 + 161 + //this.updateProgress(data, startTime); 162 + }, 163 + keepLastPage: true 164 + })); 165 + 166 + let datasets = await Promise.all(requests); 167 + 168 + if (this.scanStartTime != startTime) { 169 + return; 170 + } 171 + 172 + let items = datasets.flat(); 173 + 174 + this.updateResultsTable(items, startTime, requestedDays, { 175 + showTotal: false, showPercentages: false, countFetchedDays: false 176 + }); 148 177 } else { 149 178 let items = await accountAPI.loadUserTimeline(accountAPI.user.did, requestedDays, { 150 179 filter: 'posts_no_replies', ··· 193 222 * @param {json[]} items 194 223 * @param {number} startTime 195 224 * @param {number} requestedDays 196 - * @param {{ showTotal?: boolean, showPercentages?: boolean, showReposts?: boolean }} [options] 225 + * @param {{ showTotal?: boolean, showPercentages?: boolean, showReposts?: boolean, countFetchedDays?: boolean }} [options] 197 226 */ 198 227 199 228 updateResultsTable(items, startTime, requestedDays, options = {}) { ··· 209 238 return; 210 239 } 211 240 212 - let lastTimestamp = last.reason ? last.reason.indexedAt : last.post.record.createdAt; 213 - let lastDate = Date.parse(lastTimestamp); 214 - let fetchedDays = (startTime - lastDate) / 86400 / 1000; 241 + let daysBack; 215 242 216 - if (Math.ceil(fetchedDays) < requestedDays) { 217 - let scanInfo = $(this.pageElement.querySelector('.scan-info')); 218 - scanInfo.innerText = `🕓 Showing data from ${Math.round(fetchedDays)} days (the timeline only goes that far):`; 219 - scanInfo.style.display = 'block'; 243 + if (options.countFetchedDays !== false) { 244 + let lastTimestamp = last.reason ? last.reason.indexedAt : last.post.record.createdAt; 245 + let lastDate = Date.parse(lastTimestamp); 246 + let fetchedDays = (startTime - lastDate) / 86400 / 1000; 247 + 248 + if (Math.ceil(fetchedDays) < requestedDays) { 249 + let scanInfo = $(this.pageElement.querySelector('.scan-info')); 250 + scanInfo.innerText = `🕓 Showing data from ${Math.round(fetchedDays)} days (the timeline only goes that far):`; 251 + scanInfo.style.display = 'block'; 252 + } 253 + 254 + daysBack = Math.min(requestedDays, fetchedDays); 255 + } else { 256 + daysBack = requestedDays; 220 257 } 221 258 222 259 items = items.filter(x => { 223 260 let timestamp = x.reason ? x.reason.indexedAt : x.post.record.createdAt; 224 261 return Date.parse(timestamp) > startTime - requestedDays * 86400 * 1000; 225 262 }); 226 - 227 - let daysBack = Math.min(requestedDays, fetchedDays); 228 263 229 264 for (let item of items) { 230 265 if (item.reply) { continue; }
+10
style.css
··· 778 778 display: none; 779 779 } 780 780 781 + #posting_stats_page .user-choice { 782 + display: none; 783 + } 784 + 785 + #posting_stats_page .user-choice textarea { 786 + width: 250px; 787 + height: 100px; 788 + font-size: 10pt; 789 + } 790 + 781 791 #posting_stats_page .scan-info { 782 792 display: none; 783 793 font-weight: 600;