This repository has been archived by the owner on May 1, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 4
/
index.ts
309 lines (283 loc) · 17.2 KB
/
index.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
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
#! /usr/bin/env node
import fs from 'fs';
import path from 'path';
import packageJson from './package.json';
import { getConfig } from './src/util/config';
import { deleteFiles, ensureDirectory } from './src/util/files';
import { databaseConnection, initializeTables, insertRow, isModuleScraped, queryModuleIDs } from './src/util/database';
import { authenticateAPI, authenticateAPINotifier, authenticateSite, authenticateSiteNotifier, getSiteID, isSiteAdmin } from './src/scrapers/authenticate';
import { getForums } from './src/scrapers/forums';
import { getNews } from './src/scrapers/news';
import { getAllTickets } from './src/scrapers/tickets';
import { getApplicationResponses, getApplications } from './src/scrapers/applications';
import { getAdditionalUserData, getUsers } from './src/scrapers/users';
import { getComments } from './src/scrapers/comments';
import { getSiteData } from './src/scrapers/sitedata';
import { getAvatarFiles, getGameBoxFiles, getProfileCoverFiles, getS3Files, getUserAlbumFiles, getWikiFiles } from './src/scrapers/files';
import { getWikis } from './src/scrapers/wiki';
import { getGalleries } from './src/scrapers/galleries';
import { MessageType, statusMessage } from './src/util/console';
import { getHTMLModules } from './src/scrapers/html';
import { startNotifier } from './src/util/notifier';
import { SiteAuth } from './src/interfaces/generic';
async function main(): Promise<void> {
// Needed for exit handler
process.stdin.resume();
// Print Start Message
statusMessage(MessageType.Info, `Starting ${packageJson.name} v${packageJson.version}...`);
statusMessage(MessageType.Info, `For support, please join the support Discord: https://discord.gg/2SfGAMskWt`);
// Get config
const config = await getConfig();
// Login to API and get session ID
const sessionID = config.sessionID ? config.sessionID : await authenticateAPI(config.domain, config.email, config.password);
statusMessage(MessageType.Info, `Session ID ${sessionID}`);
// Login to site and get PHPSESSID and csrf_token
const siteAuth = config.siteAuth ? config.siteAuth : await authenticateSite(config.domain, config.email, config.password);
statusMessage(MessageType.Info, `Site Auth ${siteAuth?.csrfToken}, ${siteAuth?.phpSessID}`);
var siteAuths:SiteAuth[] = [];
if (config.notifier) {
if (config.notifier.accounts) {
for (let i = 0; i < config.notifier.accounts.length; i++) {
if (config.notifier.accounts[i].email === config.email) {
config.notifier.accounts[i].sessionID = sessionID;
if (siteAuth !== null && typeof siteAuth !== 'undefined') {
config.notifier.accounts[i].siteAuth = siteAuth;
siteAuths.push(siteAuth);
}
fs.writeFileSync(path.join(process.cwd(), './config.json'), JSON.stringify(config, null, 4));
} else {
if (!config.notifier.accounts[i].sessionID) {
await authenticateAPINotifier(config.domain, config.notifier.accounts[i].email, config.notifier.accounts[i].password);
}
let curSiteAuth:SiteAuth|undefined|null = config.notifier.accounts[i].siteAuth
if (curSiteAuth !== null && typeof curSiteAuth !== 'undefined') {
siteAuths.push(curSiteAuth);
} else {
curSiteAuth = await authenticateSiteNotifier(config.domain, config.notifier.accounts[i].email, config.notifier.accounts[i].password);
if (curSiteAuth !== null && typeof curSiteAuth !== 'undefined') {
siteAuths.push(curSiteAuth);
}
}
}
}
} else {
let email = config.email;
let password = config.password;
let siteAuthOrUndefined = siteAuth != null ? siteAuth : undefined;
let account = { email, password, sessionID, siteAuthOrUndefined };
config.notifier.accounts = [ account ];
}
}
// Check if we are admin
let adminMode: boolean = true;
if (siteAuth !== null && config.adminMode !== false) {
adminMode = await isSiteAdmin(config.domain, siteAuth);
} else {
adminMode = false;
}
statusMessage(MessageType.Info, `Admin Mode: ${adminMode}`);
// Get site ID
const siteID = await getSiteID(config.domain);
statusMessage(MessageType.Info, `Site ID: ${siteID}`);
// Ensure needed directories exist
ensureDirectory('./target/recovery');
// Initialize database tables
const database = await databaseConnection();
await initializeTables(database);
// Notifier Mode
if (siteAuth != null && config.notifier && config.notifier.enabled === true && config.apiKey && siteAuths.length != 0) {
await startNotifier(database, config.domain, config.apiKey, siteAuths, config.notifier.messageSubject, config.notifier.messageBody);
deleteFiles(['./target/recovery/notifier_progress.json']);
}
// Get site data
if (await isModuleScraped(database, 'site_data')) {
statusMessage(MessageType.Critical, 'Site data already scraped, moving on...');
} else if (siteAuth != null && adminMode) {
await getSiteData(config.domain, siteAuth, database, siteID);
await insertRow(database, 'scrapers', 'site_data', true);
}
// Get HTML modules
let htmlModuleIDs = await queryModuleIDs(database, 'html');
config.excludeHTMLModuleIDs ? htmlModuleIDs.filter(id => !config.excludeHTMLModuleIDs?.includes(id)) : {};
if (htmlModuleIDs.length === 0) {
statusMessage(MessageType.Critical, 'No HTML module IDs for site, skipping forum scraping...');
} else if (config.disabledModules?.html) {
statusMessage(MessageType.Critical, 'HTML module disabled, skipping forum scraping...');
} else if (await isModuleScraped(database, 'html')) {
statusMessage(MessageType.Critical, 'HTML already scraped, skipping forum scraping...');
} else if (siteAuth != null && adminMode) {
statusMessage(MessageType.Info, 'Scraping HTML modules...');
await getHTMLModules(config.domain, siteAuth, database, htmlModuleIDs);
await insertRow(database, 'scrapers', 'html', true);
deleteFiles(['./target/recovery/html_progress.json']);
statusMessage(MessageType.Completion, 'Finished HTML module scraping');
} else {
statusMessage(MessageType.Info, 'Cannot scrape HTML modules without admin credentials, skipping...');
}
// Get forums
let forumModuleIDs = await queryModuleIDs(database, 'forum');
config.excludeForumModuleIDs ? forumModuleIDs.filter(id => !config.excludeForumModuleIDs?.includes(id)) : {};
config.manualForumModuleIDs && config.manualForumModuleIDs.length > 0 ? forumModuleIDs.push(...config.manualForumModuleIDs) : {};
if (forumModuleIDs.length === 0) {
statusMessage(MessageType.Critical, 'No forum module IDs for site, skipping forum scraping...');
} else if (config.disabledModules?.forums === true) {
statusMessage(MessageType.Critical, 'Forums module disabled, skipping forum scraping...');
} else if (await isModuleScraped(database, 'forums')) {
statusMessage(MessageType.Critical, 'Forums already scraped, skipping forum scraping...');
} else {
statusMessage(MessageType.Info, 'Scraping forums...');
await getForums(database, config.domain, sessionID, siteAuth, [...new Set(forumModuleIDs)], config.disabledModules.forums);
await insertRow(database, 'scrapers', 'forums', true);
deleteFiles(['./target/recovery/forum_progress.json']);
statusMessage(MessageType.Completion, 'Finished forum scraping');
}
//Get galleries
if (config.disabledModules?.galleries) {
statusMessage(MessageType.Critical, 'Galleries module disabled, skipping gallery scraping...');
} else if (await isModuleScraped(database, 'galleries')) {
statusMessage(MessageType.Critical, 'Galleries already scraped, skipping gallery scraping...');
} else {
statusMessage(MessageType.Info, 'Scraping galleries...');
await getGalleries(config.domain, database, sessionID);
await insertRow(database, 'scrapers', 'galleries', true);
statusMessage(MessageType.Completion, 'Finished gallery scraping');
}
// Get wikis
let wikiModuleIDs = await queryModuleIDs(database, 'wiki');
config.excludedWikiModuleIDs ? wikiModuleIDs.filter(id => !config.excludedWikiModuleIDs?.includes(id)) : {};
config.manualWikiModuleIDs && config.manualWikiModuleIDs.length > 0 ? wikiModuleIDs.push(...config.manualWikiModuleIDs) : {};
if (wikiModuleIDs.length === 0) {
statusMessage(MessageType.Critical, 'No wiki module IDs for site, skipping wiki scraping...');
} else if (config.disabledModules?.wikis) {
statusMessage(MessageType.Critical, 'Wikis module disabled, skipping wiki scraping...');
} else if (await isModuleScraped(database, 'wikis')) {
statusMessage(MessageType.Critical, 'Wikis already scraped, skipping wiki scraping...');
} else {
statusMessage(MessageType.Info, 'Scraping wikis...');
await getWikis(config.domain, database, [...new Set(wikiModuleIDs)]);
await insertRow(database, 'scrapers', 'wikis', true);
deleteFiles(['./target/recovery/wiki_progress.json']);
statusMessage(MessageType.Completion, 'Finished wiki scraping');
}
// Get news
let newsModuleIDs = await queryModuleIDs(database, 'news');
config.excludeNewsModuleIDs ? newsModuleIDs.filter(id => !config.excludeNewsModuleIDs?.includes(id)) : {};
config.manualNewsModuleIDs && config.manualNewsModuleIDs.length > 0 ? newsModuleIDs.push(...config.manualNewsModuleIDs) : {};
if (newsModuleIDs.length === 0) {
statusMessage(MessageType.Critical, 'No news module IDs for site, skipping news scraping...');
} else if (config.disabledModules?.news) {
statusMessage(MessageType.Critical, 'News module disabled, skipping news scraping...');
} else if (await isModuleScraped(database, 'news')) {
statusMessage(MessageType.Critical, 'News already scraped, skipping news scraping...');
} else {
statusMessage(MessageType.Info, 'Scraping news...');
await getNews(database, config.domain, sessionID, siteAuth, [...new Set(newsModuleIDs)]);
await insertRow(database, 'scrapers', 'news', true);
statusMessage(MessageType.Completion, 'Finished news scraping');
}
// Get applications
if (config.disabledModules?.applications) {
statusMessage(MessageType.Critical, 'Applications module disabled, skipping application scraping...');
} else if (await isModuleScraped(database, 'applications')) {
statusMessage(MessageType.Critical, 'Applications already scraped, skipping application scraping...');
} else {
statusMessage(MessageType.Info, 'Scraping application responses...');
await getApplicationResponses(database, config.domain, sessionID, siteAuth, siteID);
statusMessage(MessageType.Info, 'Scraping applications...');
siteAuth ? await getApplications(database, config.domain, siteAuth) : {};
await insertRow(database, 'scrapers', 'applications', true);
deleteFiles(['./target/recovery/remaining_applications.json', './target/recovery/application_ids.json']);
statusMessage(MessageType.Completion, 'Finished application scraping');
}
// Get comments (from applications and news posts)
if (config.disabledModules?.comments) {
statusMessage(MessageType.Critical, 'Comments module disabled, skipping comment scraping...');
} else if (await isModuleScraped(database, 'comments')) {
statusMessage(MessageType.Critical, 'Comments already scraped, skipping comment scraping...');
} else {
statusMessage(MessageType.Info, 'Scraping comments...');
siteAuth ? await getComments(database, config.domain, siteAuth) : {};
await insertRow(database, 'scrapers', 'comments', true);
deleteFiles(['./target/recovery/comments.json']);
statusMessage(MessageType.Completion, 'Finished comment scraping');
}
// Get tickets
let ticketModuleIDs = await queryModuleIDs(database, 'tickets');
config.manualTicketModuleIDs && config.manualTicketModuleIDs.length > 0 ? ticketModuleIDs.push(...config.manualTicketModuleIDs) : {};
if (config.disabledModules?.tickets) {
statusMessage(MessageType.Critical, 'Tickets module disabled, skipping ticket scraping...');
} else if (await isModuleScraped(database, 'tickets')) {
statusMessage(MessageType.Critical, 'Tickets already scraped, skipping ticket scraping...');
} else {
statusMessage(MessageType.Info, 'Scraping tickets...');
await getAllTickets(database, config.domain, config.apiKey, sessionID, siteAuth, adminMode, config.excludeTicketModuleIDs ?? null, ticketModuleIDs ?? null);
await insertRow(database, 'scrapers', 'tickets', true);
deleteFiles(['./target/recovery/module_tickets.json']);
statusMessage(MessageType.Completion, 'Finished ticket scraping');
}
// Get users
if (config.disabledModules?.users === true) {
statusMessage(MessageType.Critical, 'Users module disabled, skipping user tag scraping...');
} else if (await isModuleScraped(database, 'users') && await isModuleScraped(database, 'user_data')) {
statusMessage(MessageType.Critical, 'Users already scraped, skipping user tag scraping...');
} else {
statusMessage(MessageType.Info, 'Scraping users...');
await isModuleScraped(database, 'users') ? {} : await getUsers(database, config.domain, sessionID, config.apiKey, config.disabledModules.users, config.manualUserIDs ?? []);
await insertRow(database, 'scrapers', 'users', true);
await isModuleScraped(database, 'user_data') ? {} : await getAdditionalUserData(config.domain, sessionID, siteAuth, database, config.disabledModules.users, adminMode);
await insertRow(database, 'scrapers', 'user_data', true);
deleteFiles(['./target/recovery/user_tags.json', './target/recovery/user_data.json']);
statusMessage(MessageType.Completion, 'Finished user scraping');
}
// Get files
if (config.disabledModules?.files === true) {
statusMessage(MessageType.Critical, 'Files module disabled, skipping file scraping...');
} else if (
await isModuleScraped(database, 's3_files') &&
await isModuleScraped(database, 'wiki_files') &&
await isModuleScraped(database, 'avatar_files') &&
await isModuleScraped(database, 'profile_cover_files') &&
await isModuleScraped(database, 'game_box_files') &&
await isModuleScraped(database, 'user_album_files')
) {
statusMessage(MessageType.Critical, 'Files already scraped, skipping file scraping...');
} else {
statusMessage(MessageType.Info, 'Scraping files...');
const disabledFileModules = config.disabledModules?.files;
if (!await isModuleScraped(database, 's3_files') && ((typeof disabledFileModules === 'object') ? !(disabledFileModules.s3) : true)) {
await getS3Files(config.domain, database, siteAuth, siteID, adminMode);
await insertRow(database, 'scrapers', 's3_files', true);
}
if (!await isModuleScraped(database, 'wiki_files') && ((typeof disabledFileModules === 'object') ? !(disabledFileModules.wiki) : true)) {
await getWikiFiles(database);
await insertRow(database, 'scrapers', 'wiki_files', true);
}
if (!await isModuleScraped(database, 'avatar_files') && ((typeof disabledFileModules === 'object') ? !(disabledFileModules.avatars) : true)) {
await getAvatarFiles(database, siteID);
await insertRow(database, 'scrapers', 'avatar_files', true);
}
if (!await isModuleScraped(database, 'profile_cover_files') && ((typeof disabledFileModules === 'object') ? !(disabledFileModules.profileCovers) : true)) {
await getProfileCoverFiles(database);
await insertRow(database, 'scrapers', 'profile_cover_files', true);
}
if (!await isModuleScraped(database, 'game_box_files') && ((typeof disabledFileModules === 'object') ? !(disabledFileModules.gameBoxes) : true)) {
await getGameBoxFiles(database);
await insertRow(database, 'scrapers', 'game_box_files', true);
}
if (!await isModuleScraped(database, 'user_album_files') && ((typeof disabledFileModules === 'object') ? !(disabledFileModules.userAlbums) : true)) {
await getUserAlbumFiles(database);
await insertRow(database, 'scrapers', 'user_album_files', true);
}
deleteFiles([
'./target/recovery/s3_file_progress.json',
'./target/recovery/wiki_file_progress.json',
'./target/recovery/avatar_file_progress.json',
'./target/recovery/cover_file_progress.json',
'./target/recovery/game_box_progress.json',
'./target/recovery/user_album_progress.json'
]);
statusMessage(MessageType.Completion, 'Finished file scraping');
}
process.kill(process.pid, 'SIGINT');
}
main();