-
Notifications
You must be signed in to change notification settings - Fork 1
/
norah.js
161 lines (144 loc) · 4.13 KB
/
norah.js
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
require("dotenv").config();
const puppeteer = require("puppeteer");
const nodemailer = require("nodemailer");
// Settings
const env = process.env;
const URL = env.TICKET_URL || "https://www.twickets.live/catalog/browse";
const ARTIST = env.ARTIST || "Norah Jones";
const LOCATION = env.LOCATION || "London";
const smtpConfig = {
host: env.SMTP_HOST || "smtp.mailgun.org",
port: parseInt(env.SMTP_PORT, 10) || 587, // must be integer
secure: false, // upgrade later with STARTTLS
auth: {
user: env.SMTP_USER || "",
pass: env.SMTP_PASS || "",
},
};
const EMAIL_SEND_TYPE = env.EMAIL_SEND_TYPE || "gmail";
const gmailConfig = {
service: "gmail",
auth: {
user: env.GMAIL_USER || "",
pass: env.GMAIL_PASS || "",
},
};
let monitoring = true;
async function sendEmail() {
const transporter = nodemailer.createTransport(
EMAIL_SEND_TYPE.toLowerCase() === "gmail" ? gmailConfig : smtpConfig
);
console.log("Sending email...");
try {
return await transporter.sendMail(
{
from: env.EMAIL_FROM || "",
to: env.EMAIL_TO || "",
subject: env.EMAIL_SUBJECT || "Ticket Available",
text:
(env.EMAIL_TEXT ||
"The ticket you were waiting for is now available! ") + ` ${URL}`,
},
(err, info) => {
if (err) {
console.error(
`Error sending email: ${JSON.stringify(err)}, ${JSON.stringify(
info
)}`
);
} else {
console.log("Email sent!");
// console.log(info);
}
}
);
} catch (e) {
console.error(e);
}
}
async function checkElement(selector, textToMatch, page) {
return await page.evaluate(
(selector, textToMatch) => {
const element = document.querySelector(selector);
console.log(selector, element.textContent);
return element && element.textContent.includes(textToMatch);
},
selector,
textToMatch
);
}
async function checkTicketAvailability() {
let browser;
try {
browser = await puppeteer.launch({
headless: "new",
});
const page = await browser.newPage();
const locationSelector = ".multi-select-style input";
let ticketFound = false;
// This will log all console messages from the page
page.on("console", (msg) => console.log("PAGE LOG:", msg.text()));
await page.goto(URL, { waitUntil: "networkidle2" });
await page.waitForSelector(locationSelector);
await page.click(locationSelector);
await page.keyboard.type(LOCATION);
await page.keyboard.press("Enter");
// wait 3 seconds for the location to be selected
await new Promise((resolve) => setTimeout(resolve, 3000));
for (let i = 0; i < 3; i++) {
const artistSelector = `#searchBlockResult_eventName_${i}`;
const locationSelector = `#searchBlockResult_venueLocation_${i}`;
await page.waitForSelector(artistSelector);
await page.waitForSelector(locationSelector);
const isCorrectArtist = await checkElement(artistSelector, ARTIST, page);
const isCorrectLocation = await checkElement(
locationSelector,
LOCATION,
page
);
if (isCorrectArtist && isCorrectLocation) {
ticketFound = true;
break;
}
}
return ticketFound;
} catch (e) {
console.error(e);
return false;
} finally {
if (browser) {
await browser.close();
}
}
}
async function monitor() {
while (monitoring) {
const available = await checkTicketAvailability();
if (available) {
console.log("Ticket is available!");
sendEmail().finally(() => {
monitoring = false;
});
} else {
const INTERVAL_IN_SECONDS = Math.floor(
Math.random() * (120 - 10 + 1) + 10
);
console.log(
`Ticket is not available yet. Retrying... in ${INTERVAL_IN_SECONDS} seconds`
);
await new Promise((resolve) =>
setTimeout(resolve, INTERVAL_IN_SECONDS * 1000)
);
}
}
}
async function startMonitoring() {
await monitor();
process.exit(0);
}
process.on("SIGINT", () => {
console.log("Stopping the monitor...");
monitoring = false;
process.exit();
});
startMonitoring();