forked from mastodon/joinmastodon
-
Notifications
You must be signed in to change notification settings - Fork 0
/
patreon.mjs
128 lines (108 loc) · 3.2 KB
/
patreon.mjs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
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()
}
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 = {}
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
}
}
// Sponsors are sorted by lifetimeSupportCents desc
// Highlighted sponsors are sorted by lifetimeSupportCents desc
// Silver sponsors are sorted by joinedAt asc, grandfathered ones have nofollow: false
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")
}
)