Process npubs one by one

This commit is contained in:
minimo-io 2024-04-27 15:33:29 -03:00
parent a613e622d8
commit da657383aa
7 changed files with 124 additions and 147 deletions

View File

@ -5,8 +5,7 @@ Let promote some reciprocity here! 😹
## ToDo ## ToDo
- Actually load builds at minimo.io/app/ or something alike. - Create groups to checks to fire simultaneously instad of one by one (to remember: fireing all the `fetchProfile` at once for a given npub resulted in a permanent halt of the process -mainly for big users). Maybe using https://lodash.com/docs `_.chunk(array, [size=1])`
- Ask community for help about the bug (see below) so I can keep understanding the protocol and the library.
- Polish the proof-of-concept code, making it TS code and remove `// @ts-nocheck`! - Polish the proof-of-concept code, making it TS code and remove `// @ts-nocheck`!
- Create interfaces or new types instead of loose variables - Create interfaces or new types instead of loose variables
- Save followbackers and not followbackers in lists to see details. - Save followbackers and not followbackers in lists to see details.
@ -15,10 +14,6 @@ Let promote some reciprocity here! 😹
- Show the relay list to be used - Show the relay list to be used
- Upload a localStorage list of relays - Upload a localStorage list of relays
- ~~Actually load builds at minimo.io/app/ or something alike.~~
- ~~Configure Vite for the miniapp to be loaded in the article's url as base.~~ - ~~Configure Vite for the miniapp to be loaded in the article's url as base.~~
- ~~Remove SvelteKit (just Vite + Svelte).~~ - ~~Remove SvelteKit (just Vite + Svelte).~~
## BUG
- **When user follows lots of people, progress freezes:**<br>
[NDK](https://github.com/nostr-dev-kit/ndk) keeps trying to re-connect to relays, and progress slows down or halts completly. Maybe slow requests down? Are they blocking the requests because they are too many too fast?

View File

@ -1,24 +1,24 @@
{ {
"name": "nostr-followback", "name": "nostr-followback",
"private": true, "private": true,
"version": "0.0.0", "version": "0.0.1",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite", "dev": "vite",
"build": "vite build", "build": "vite build",
"preview": "vite preview", "preview": "vite preview",
"check": "svelte-check --tsconfig ./tsconfig.json" "check": "svelte-check --tsconfig ./tsconfig.json"
}, },
"devDependencies": { "devDependencies": {
"@sveltejs/vite-plugin-svelte": "^3.0.2", "@sveltejs/vite-plugin-svelte": "^3.0.2",
"@tsconfig/svelte": "^5.0.2", "@tsconfig/svelte": "^5.0.2",
"svelte": "^4.2.12", "svelte": "^4.2.12",
"svelte-check": "^3.6.7", "svelte-check": "^3.6.7",
"tslib": "^2.6.2", "tslib": "^2.6.2",
"typescript": "^5.2.2", "typescript": "^5.2.2",
"vite": "^5.2.0" "vite": "^5.2.0"
}, },
"dependencies": { "dependencies": {
"@nostr-dev-kit/ndk": "^2.8.1" "@nostr-dev-kit/ndk": "^2.8.1"
} }
} }

View File

@ -1,23 +1,23 @@
<script lang="ts"> <script lang="ts">
// @ts-nocheck // @ts-nocheck
// Import the package import NDK, { type NDKUserProfile } from "@nostr-dev-kit/ndk";
import NDK from "@nostr-dev-kit/ndk"; import type { userFollowData } from "./lib/types";
import { fetchUserProfile } from "./lib/fetchs";
import { relays } from "./lib/data/relays"; import { relays } from "./lib/data/relays";
// let npubToQuery = "npub1wujhdsytm3w6g0mpsqh8v7ezx83jcm64dlkwuqgm5v8lv0pds55ssudkw0"; let npubToQuery = "npub1wujhdsytm3w6g0mpsqh8v7ezx83jcm64dlkwuqgm5v8lv0pds55ssudkw0";
let npubToQuery = "";
let querying = false;
let userName = "";
let userThumb = "";
let followsCount = 0;
let querying: "completed" | "processing" | "uninitiated" = "uninitiated";
let userProfile: NDKUserProfile | null;
let followsCount = 0;
let followBackCount = 0; let followBackCount = 0;
let notFollowBackCount = 0; let notFollowBackCount = 0;
let unknownFollowBack = 0; let unknownFollowBack = 0;
let totalCountOfContactsChecked = 0; let totalCountOfContactsChecked = 0;
$: progress = ((totalCountOfContactsChecked / followsCount) * 100).toFixed() | 0; $: progress = ((totalCountOfContactsChecked / followsCount) * 100).toFixed() | 0;
$: notFollowBackPercentage = ((notFollowersBack.length / originalFollow.length) * 100) | 0;
let originalFollow = []; let originalFollow = [];
let notFollowersBack = []; let notFollowersBack = [];
@ -27,82 +27,92 @@
const ndk = new NDK({ const ndk = new NDK({
explicitRelayUrls: relays, explicitRelayUrls: relays,
}); });
await ndk.connect(); await ndk.connect(6000);
querying = "processing";
const user = await fetchUserProfile(npubToQuery, ndk); // create user instance
const user = ndk.getUser({ npub: npubToQuery });
// query for user profile
userProfile = await user.fetchProfile();
userName = user.profile.name; if (userProfile) {
userThumb = user.profile.image;
if (userName) {
// console.log(user.profile); // console.log(user.profile);
const follows = await user.follows(); const follows = await user.follows({ groupable: false }, false);
// query for a set of user followers
followsCount = follows.size; followsCount = follows.size;
let lastFollowerBack; let lastFollowerBack;
let i = 0; let i = 0;
follows.forEach(async (follower) => {
//for (const follower of follows) { for await (const follower of follows) {
// await new Promise((resolve) => setTimeout(resolve, 0));
const followerFollowList = await follower.follows(); const followerFollowList = await follower.follows();
originalFollow.push({ npub: follower.npub, followsBack: "-" }); // add to follower list try {
originalFollow = originalFollow; originalFollow.push({ npub: follower.npub, followsBack: "-" }); // add to follower list
originalFollow = originalFollow;
if (followerFollowList.size) { if (followerFollowList.size) {
// console.log(followerFollowList); // console.log(followerFollowList);
// check if the user is in the queried user follow list // check if the user is in the queried user follow list
let doesFollowBack = false; let doesFollowBack = false;
for (let contact of followerFollowList) { for (let contact of followerFollowList) {
lastFollowerBack = contact.npub; lastFollowerBack = contact.npub;
if (contact.npub == npubToQuery) { if (contact.npub == npubToQuery) {
doesFollowBack = true; doesFollowBack = true;
break; break;
}
} }
}
originalFollow[i].followBack = doesFollowBack ? "1" : "0"; originalFollow[i].followBack = doesFollowBack ? "1" : "0";
// decision making time // decision making time
if (doesFollowBack) { if (doesFollowBack) {
followBackCount++; followBackCount++;
totalCountOfContactsChecked++; totalCountOfContactsChecked++;
// add here the ones who do follow back // add here the ones who do follow back
} else {
notFollowBackCount++;
notFollowersBack.push(follower.npub);
notFollowersBack = notFollowersBack;
totalCountOfContactsChecked++;
}
} else { } else {
notFollowBackCount++; unknownFollowBack++;
notFollowersBack.push(follower.npub);
notFollowersBack = notFollowersBack;
totalCountOfContactsChecked++; totalCountOfContactsChecked++;
} }
} else { i++;
unknownFollowBack++; } catch (error) {
totalCountOfContactsChecked++; console.log(follower);
console.error(`Error fetching npub:`, error);
} }
i++; }
});
// follows.forEach(async (follower) => {
// });
} }
querying = "completed";
} catch (error) { } catch (error) {
console.error("Error fetching data:", error); console.error(`Error fetching data (${npubToQuery}):`, error);
} }
} }
function ItemCount(i: number): string {
//checkFollowBacks(); let ret = i.toString();
if (i < 10) ret = `0${i}`;
return ret;
}
</script> </script>
<form class="npub-form"> <form class="npub-form">
<input disabled={querying && progress < 100} type="text" placeholder="An npub to check" bind:value={npubToQuery} /> <input
disabled={querying == "processing" && progress < 100}
type="text"
placeholder="npub to check"
bind:value={npubToQuery}
/>
<input <input
type="button" type="button"
on:click={async () => { on:click={async () => {
querying = true; querying = true;
userName = ""; userProfile = null;
userThumb = "";
originalFollow = []; originalFollow = [];
notFollowersBack = []; notFollowersBack = [];
followBackCount = 0; followBackCount = 0;
@ -116,43 +126,35 @@
/> />
</form> </form>
<!-- {#if !querying} {#if userProfile}
{npubToQuery}
{/if} -->
{#if userThumb}
<div class="user-box"> <div class="user-box">
<img src={userThumb} width="50" style="border-radius:100%;" alt="user-thumb" /> <img src={userProfile.image} width="50" style="border-radius:100%;" alt="user-thumb" />
User: User:
<a href="https://primal.net/p/{npubToQuery}">{userName}</a> <a href="https://primal.net/p/{npubToQuery}">{userProfile.displayName}</a>
|  Follows: {followsCount} |  Follows: {followsCount}
<br /> <br />
Unknown: {unknownFollowBack} | Follow_Back: {followBackCount} | Unknown: {unknownFollowBack} - Follow_Back: {followBackCount} -
<strong>👉 Not_Follow_Back</strong> <strong>👉 Not_Follow_Back</strong>
: :
<!-- <span title="Actually Counted">{notFollowBackCount}</span>
/ -->
<span title="Actualy counted">{notFollowersBack.length}</span> <span title="Actualy counted">{notFollowersBack.length}</span>
<br /> <br />
{#if progress < 100} {#if progress < 100}
<p> <p>
Progress = Progress = <strong>{progress}%</strong>
<strong>{progress}%</strong>
- {totalCountOfContactsChecked} of {followsCount} - {totalCountOfContactsChecked} of {followsCount}
<!-- - {totalCountOfContactsChecked} of {followBackCount +
notFollowBackCount +
unknownFollowBack} -->
</p> </p>
{:else} {:else}
<p><strong>Completed!</strong></p> <p><strong>✅ Completed!</strong></p>
{/if} {/if}
<hr /> <hr />
<br /> <br />
Results ({originalFollow.length}) <strong>Not followers</strong>
: {notFollowersBack.length} of
{originalFollow.length} ({notFollowBackPercentage}%)
<ul> <ul>
{#each originalFollow as item, i} {#each originalFollow as item, i}
<li> <li>
#{i + 1} - {@html item.followBack == "0" ? "<span>🔴</span>" : "<span>🟢</span>"} #{ItemCount(i + 1)} - {@html item.followBack == "0" ? "<span>🔴</span>" : "<span>🟢</span>"}
<a target="_blank noreferrer noopener" href="https://primal.net/p/{item.npub}"> <a target="_blank noreferrer noopener" href="https://primal.net/p/{item.npub}">
{item.npub} {item.npub}
</a> </a>
@ -160,22 +162,8 @@
</li> </li>
{/each} {/each}
</ul> </ul>
<!-- <br />
<strong>They don't follow you ({notFollowersBack.length}):</strong>
<br />
<ul>
{#each notFollowersBack as item, i (item)}
<li>
#{i + 1} - <a href="https://nostr.band/{item}" target="_blank noreferrer noopener">Nostr.Band</a>
/ <a href="https://primal.net/p/{item}" target="_blank noreferrer noopener">Primal</a>
:
{item}
</li>
{/each}
</ul> -->
</div> </div>
{:else if !querying} {:else if querying == "uninitiated"}
<!-- <p>Let's find out who does not follow you back in Nostr!</p> --> <!-- <p>Let's find out who does not follow you back in Nostr!</p> -->
{:else} {:else}
<div class="loader">Loading data...</div> <div class="loader">Loading data...</div>

View File

@ -9,11 +9,11 @@ export const relays = [
"wss://nostr.mom", "wss://nostr.mom",
"wss://nostrelay.yeghro.site", "wss://nostrelay.yeghro.site",
"wss://relay.damus.io", "wss://relay.damus.io",
"wss://relay.nostr.bg", // "wss://relay.nostr.bg",
"wss://relay.snort.social", "wss://relay.snort.social",
"wss://relay.primal.net", "wss://relay.primal.net",
"wss://nostr.bitcoiner.social", "wss://nostr.bitcoiner.social",
"wss://nostr.mutinywallet.com", "wss://nostr.mutinywallet.com",
"wss://relay.current.fyi", "wss://relay.current.fyi",
"wss://brb.io", // "wss://brb.io",
]; ];

View File

@ -1,9 +0,0 @@
export async function fetchUserProfile(npub, ndk) {
const user = ndk.getUser({ npub });
await user.fetchProfile();
return user;
}
export async function fetchNotes(hexkey, ndk) {
const kind1filter = { kinds: [3], authors: [hexkey] };
return ndk.fetchEvent(kind1filter);
}

View File

@ -0,0 +1,3 @@
export type userFollowData = {
followsCount: number;
};

View File

@ -1,20 +1,20 @@
{ {
"extends": "@tsconfig/svelte/tsconfig.json", "extends": "@tsconfig/svelte/tsconfig.json",
"compilerOptions": { "compilerOptions": {
"target": "ESNext", "target": "ESNext",
"useDefineForClassFields": true, "useDefineForClassFields": true,
"module": "ESNext", "module": "ESNext",
"resolveJsonModule": true, "resolveJsonModule": true,
/** /**
* Typecheck JS in `.svelte` and `.js` files by default. * Typecheck JS in `.svelte` and `.js` files by default.
* Disable checkJs if you'd like to use dynamic types in JS. * Disable checkJs if you'd like to use dynamic types in JS.
* Note that setting allowJs false does not prevent the use * Note that setting allowJs false does not prevent the use
* of JS in `.svelte` files. * of JS in `.svelte` files.
*/ */
"allowJs": true, "allowJs": true,
"checkJs": true, "checkJs": true,
"isolatedModules": true "isolatedModules": true
}, },
"include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"],
"references": [{ "path": "./tsconfig.node.json" }] "references": [{ "path": "./tsconfig.node.json" }]
} }