···
import styles from "./App.module.css";
import { BskyAgent } from "@atproto/api";
let [notices, setNotices] = createSignal<string[]>([], { equals: false });
let [progress, setProgress] = createSignal(0);
let [followCount, setFollowCount] = createSignal(0);
+
let [followRecords, setFollowRecords] = createStore<FollowRecord[]>([]);
const fetchFollows = async (agent: any) => {
···
+
const fetchHiddenAccounts = async (handle: string, password: string) => {
+
const serviceURL = await fetchServiceEndpoint(handle);
const agent = new BskyAgent({
···
updateNotices(e.message);
+
if (followRecords.length == 0) {
await fetchFollows(agent).then((follows) =>
follows.forEach((record: any) => {
+
setFollowRecords(followRecords.length, {
+
did: record.value.subject,
+
status: RepoStatus.ACTIVE,
+
setFollowCount(followRecords.length);
+
followRecords.forEach(async (record, index) => {
+
const res = await agent.getProfile({ actor: record.did });
if (res.data.viewer?.blockedBy) {
+
setFollowRecords(index, "handle", res.data.handle);
+
setFollowRecords(index, "status", RepoStatus.BLOCKEDBY);
+
record.did.startsWith("did:web")
+
? "https://" + record.did.split(":")[2] + "/.well-known/did.json"
+
: "https://plc.directory/" + record.did,
+
await res.json().then((doc) => {
+
for (const alias of doc.alsoKnownAs) {
+
if (alias.includes("at://")) {
+
return alias.split("//")[1];
if (e.message.includes("not found")) {
+
setFollowRecords(index, "status", RepoStatus.DELETED);
} else if (e.message.includes("deactivated")) {
+
setFollowRecords(index, "status", RepoStatus.DEACTIVATED);
} else if (e.message.includes("suspended")) {
+
setFollowRecords(index, "status", RepoStatus.SUSPENDED);
setProgress(progress() + 1);
+
// const unfollowCount = Object.values(followRecords).filter(
+
// (record) => record.toBeDeleted,
+
// const writes = Object.values(followRecords)
+
// .filter((record) => record.toBeDeleted)
+
// $type: "com.atproto.repo.applyWrites#delete",
+
// collection: "app.bsky.graph.follow",
+
// rkey: record.uri.split("/").pop(),
+
// const BATCHSIZE = 200;
+
// if (agent.session) {
+
// for (let i = 0; i < writes.length; i += BATCHSIZE) {
+
// await agent.com.atproto.repo.applyWrites({
+
// repo: agent.session.did,
+
// writes: writes.slice(i, i + BATCHSIZE),
+
// setNotices([`Unfollowed ${unfollowCount} accounts.`]);
+
const Form: Component = () => {
+
const [handle, setHandle] = createSignal("");
+
const [password, setPassword] = createSignal("");
···
+
onInput={(e) => setHandle(e.currentTarget.value)}
placeholder="App Password"
+
onInput={(e) => setPassword(e.currentTarget.value)}
+
onclick={() => fetchHiddenAccounts(handle(), password())}
···
<h1>cleanfollow-bsky</h1>
<div class={styles.Warning}>
+
Unfollows blocked by, deleted, suspended, and deactivated accounts
<a href="https://github.com/notjuliet/cleanfollow-bsky">Source Code</a>
<Show when={followCount()}>
Progress: {progress()}/{followCount()}