Spaces:
Running
Running
import { delay } from '@std/async/delay'; | |
import { shuffle } from '@std/random'; | |
type User = { | |
user: string; | |
fullname: string; | |
type: string; | |
isFollowing?: true; | |
_id: string; | |
isPro: boolean; | |
avatarUrl: string; | |
}; | |
export class HuggingFace { | |
constructor(public cookie: string) { | |
} | |
async getOrganizationFollowers(organization: string, cursor?: string): Promise<User[]> { | |
const url = new URL(`https://huggingface.co/api/organizations/${organization}/followers`); | |
cursor && url.searchParams.append('cursor', cursor); | |
const response = await fetch(url, { | |
headers: { | |
'Cookie': this.cookie, | |
}, | |
}); | |
if (!response.ok) throw Error(`${response.status} ${response.statusText}`); | |
return await response.json(); | |
} | |
async getNonFollowingUsers(organization: string): Promise<User[]> { | |
let cursor: string | undefined = undefined; | |
while (true) { | |
const users = await this.getOrganizationFollowers(organization, cursor); | |
if (!users.length) throw Error('No users found'); | |
const nonFollowing = users.filter((user) => !user.isFollowing); | |
if (nonFollowing.length) return nonFollowing; | |
cursor = users[users.length - 1]._id; | |
} | |
} | |
async followRandomUsers(organization: string): Promise<number | undefined> { | |
const users = await this.getNonFollowingUsers(organization); | |
const shuffled = shuffle(users); | |
for (let i = 0; i < shuffled.length; i++) { | |
await delay(1000); | |
const user = shuffled[i]; | |
const res = await this.follow(user.user); | |
if (res.status === 429) { | |
console.error((await res.json()).error); | |
return i; | |
} | |
const body = await res.text(); | |
if (body.trim().toLowerCase() === 'ok') { | |
console.log(`Followed ${user.user}`); | |
} else { | |
console.warn(`Failed to follow ${user.user}`); | |
continue; | |
} | |
} | |
} | |
async follow(user: string) { | |
return await fetch(`https://huggingface.co/api/users/${user}/follow`, { | |
method: 'post', | |
headers: { | |
'content-type': 'application/json', | |
'Cookie': this.cookie, | |
}, | |
}); | |
} | |
} | |