-
Notifications
You must be signed in to change notification settings - Fork 0
/
app.ts
169 lines (131 loc) · 5.05 KB
/
app.ts
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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
//
// Pouet Discord Bot (aka "Klaxon")
// (C) Tammo Hinrichs 2020, see LICENSE for details (spoilers: it's MIT)
//
import * as Discord from "discord.js"
import fetch from "node-fetch";
import * as schedule from "node-schedule";
import * as fs from "fs";
const ordinal = require("ordinal");
const apiRoot = "https://api.pouet.net/v1/";
const capitalize = (word: string) => word.charAt(0).toUpperCase() + word.slice(1);
//------------------------------------------------------------------------------
// Configuration
interface Config {
bottoken: string,
pouetchannel: string,
totm_minute: number,
totm_maxrank: number,
}
const config = JSON.parse(fs.readFileSync("config.json", "utf8")) as Config;
//------------------------------------------------------------------------------
// Pouet API helper functions
async function getMonthlyTop()
{
const response = await fetch(apiRoot + "front-page/top-of-the-month/");
const result: pouet.TopListResult = await response.json();
return result.success ? result.prods : null;
}
async function getProd(id: number) {
const response = await fetch(apiRoot + "prod/?id=" + id);
const result: pouet.ProdResult = await response.json();
return result.success ? result.prod : null;
}
async function getParty(id: number) {
const response = await fetch(apiRoot + "party/?id=" + id);
const result: pouet.PartyResult = await response.json();
return result.success ? result.party : null;
}
//------------------------------------------------------------------------------
// Discord functionality
const client = new Discord.Client();
let pouetChannel: Discord.TextChannel;
// post a prod to channel as a rich embed
async function PostProd(channel: Discord.TextChannel, id: number, header: string = "") {
// fetch prod details from pouet...
const prod = await getProd(id);
// .... and make a post about it!
const url = 'https://www.pouet.net/prod.php?which=' + id;
let embed = new Discord.MessageEmbed()
.setColor('#557799')
.setTitle(prod.name)
.setURL(url)
.setImage(prod.screenshot)
.setTimestamp(Date.parse(prod.releaseDate));
// description ...
var desc = prod.types.map(capitalize).join(", ");
if (desc) desc += " for ";
desc += Object.values(prod.platforms).map(pl => pl.name).join(", ");
// ... invi?
if (prod.invitation) {
const party = await getParty(parseInt(prod.invitation))
if (desc) desc += "\n";
desc += `Invitation for ${party.name} ${prod.invitationyear}`;
}
// .. placings
for (let pl of prod.placings) {
const rank = parseInt(pl.ranking);
if (pl.compo_name == "none") {
desc += `\nReleased at ${pl.party.name} ${pl.year}`;
}
else if (rank < 97) {
desc += `\nPlaced ${ordinal(rank)} in the ${pl.compo_name} compo at ${pl.party.name} ${pl.year}`;
}
}
if (desc)
embed.setDescription(desc);
// groups
if (prod.groups.length)
embed.setAuthor(prod.groups.map(g => g.name).join(" & "));
// credits
if (prod.credits.length) {
const credits = prod.credits.map(c => `${c.user.nickname} (${c.role})`);
embed.addField("Credits", credits, true);
}
// links
let dlfield = `**[Download](${prod.download})**`;
for (let link of prod.downloadLinks)
dlfield += `\n[${capitalize(link.type)}](${link.link})`;
embed.addField("Links", dlfield, true);
await channel.send(header + url, embed);
}
//------------------------------------------------------------------------------
// Jobs
async function TopOfTheMonth() {
try {
console.log("posting new Top Of The Month...");
// get seen prod ids
const seenfile = "seenids.json";
let seenIds: number[] = [];
if (fs.existsSync(seenfile)) {
seenIds = JSON.parse(fs.readFileSync(seenfile, "utf8"));
}
let prods = await getMonthlyTop();
for (let p of prods) {
let prod = p.prod;
// find a prod that we haven't posted about yet
let id = parseInt(prod.id);
if (seenIds.includes(id) || p.rank > config.totm_maxrank)
continue;
console.log(`it is #${prod.id}: ${prod.name}`);
await PostProd(pouetChannel, id, `New in the top of the month at rank ${p.rank}: `);
seenIds.push(id);
break; // one is enough
}
fs.writeFileSync(seenfile, JSON.stringify(seenIds));
}
catch (e) {
console.error(`Could not update Top Of The Month: ${e}`);
}
}
//------------------------------------------------------------------------------
// Top level function
async function Bot() {
console.log("pouet-discord-bot starting...");
// log in and get channel
await client.login(config.bottoken);
pouetChannel = await client.channels.fetch(config.pouetchannel) as Discord.TextChannel;
console.log(`logged in; channel: ${pouetChannel.name}`);
schedule.scheduleJob({ minute: config.totm_minute }, TopOfTheMonth);
}
Bot();