import * as dotenv from "dotenv"
import fs from "fs"
dotenv.config({ path: ".env.local" })
const fetchJson = async (url) => {
const res = await fetch(url, {
headers: { Authorization: `Bearer ${process.env.PATREON_ACCESS_TOKEN}` },
})
return await res.json()
}
const sleep = (waitTime) =>
new Promise((resolve) => setTimeout(resolve, waitTime))
let url = `https://www.patreon.com/api/oauth2/v2/campaigns/${process.env.PATREON_CAMPAIGN_ID}/members?include=user,currently_entitled_tiers&fields%5Bmember%5D=full_name,lifetime_support_cents,patron_status,pledge_relationship_start,note&fields%5Buser%5D=image_url&fields%5Btier%5D=title`
const membersByTiers = {}
const tierMap = {}
while (true) {
console.log("Fetching page...")
const data = await fetchJson(url)
const profilePictureMap = {}
if (!data.included) {
console.log("Unexpected response:", data)
break
}
data.included.forEach((included) => {
switch (included.type) {
case "user":
profilePictureMap[included.id] = included.attributes.image_url
break
case "tier":
tierMap[included.id] = included.attributes.title
break
}
})
data.data.forEach((member) => {
const userId = member.relationships.user.data.id
if (member.attributes.patron_status !== "active_patron") {
return
}
const currentlyEntitledTiers =
member.relationships.currently_entitled_tiers.data
if (currentlyEntitledTiers?.length < 1) {
return
}
const tierId = currentlyEntitledTiers[0].id
const tierName = tierMap[tierId]
const members = membersByTiers[tierName] || []
members.push({
id: userId,
picture: profilePictureMap[userId],
name: member.attributes.full_name,
joinedAt: member.attributes.pledge_relationship_start,
lifetimeSupportCents: member.attributes.lifetime_support_cents,
note: member.attributes.note,
tier: tierName,
})
membersByTiers[tierName] = members
})
url = data?.links?.next
if (!url) {
break
}
await sleep(1000)
}
const silver = membersByTiers["Silver sponsor"]
.map((member) => ({
url: member.note,
name: member.name,
logo: member.picture,
nofollow: true,
date: member.joinedAt,
}))
.concat(
membersByTiers["Silver sponsor (grandfathered)"].map((member) => ({
url: member.note,
name: member.name,
logo: member.picture,
nofollow: false,
date: member.joinedAt,
}))
)
.sort((a, b) => new Date(a.date) - new Date(b.date))
.map((member) => ({
url: member.url,
logo: member.logo,
name: member.name,
url: member.url,
nofollow: member.nofollow,
}))
const generalHighlighted = membersByTiers["Highlighted sponsor"]
.sort((a, b) => b.lifetimeSupportCents - a.lifetimeSupportCents)
.map((member) => member.name)
const general = membersByTiers["Sponsor"]
.sort((a, b) => b.lifetimeSupportCents - a.lifetimeSupportCents)
.map((member) => member.name)
fs.writeFile(
"./data/patreon.json",
JSON.stringify(
{
silver,
generalHighlighted,
general,
},
null,
" "
),
(err) => {
if (err) {
console.error(err)
return
}
console.log("File updated")
}
)