forked from saahphire/NeopetsUserscripts
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathalertPostNotifications.js
More file actions
178 lines (157 loc) · 9.14 KB
/
Copy pathalertPostNotifications.js
File metadata and controls
178 lines (157 loc) · 9.14 KB
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
// ==UserScript==
// @name Neopets: Alert and Post Notifications
// @namespace https://github.com/saahphire/NeopetsUserscripts
// @version 1.0.0
// @description Shows a native browser notification whenever you get an alert, random event, refresh your guild board and there's a new post, or refresh a topic and there's a new post.
// @author saahphire
// @homepageURL https://github.com/saahphire/NeopetsUserscripts
// @homepage https://github.com/saahphire/NeopetsUserscripts
// @downloadURL https://github.com/saahphire/NeopetsUserscripts/blob/main/alertPostNotifications.js
// @updateURL https://github.com/saahphire/NeopetsUserscripts/blob/main/alertPostNotifications.js
// @match *://*.neopets.com/*
// @icon https://www.google.com/s2/favicons?sz=64&domain=neopets.com
// @license Unlicense
// @grant GM.notification
// @grant GM.setValue
// @grant GM.getValue
// ==/UserScript==
// TODO cleanup
/*
•:•.•:•.•:•:•:•:•:•:•:••:•.•:•.•:•:•:•:•:•:•:•:•.•:•.•:•:•:•:•:•:•:••:•.•:•.•:•.•:•:•:•:•:•:•:•:•.•:•:•.•:•.••:•.•:•.••:
........................................................................................................................
☆ ⠂⠄⠄⠂⠁⠁⠂⠄⠄⠂✦ ⠂⠄⠄⠂⠁⠁⠂⠄⠄⠂☆ ⠂⠄⠄⠂⠁⠁⠂⠄⠄⠂✦ ⠂⠄⠄⠂⠁⠁⠂⠄⠂⠄⠄⠂☆ ⠂⠄⠄⠂⠁⠁⠂⠄⠄⠂✦ ⠂⠄⠄⠂⠁⠁⠂⠄⠂⠄⠄⠂☆ ⠂⠄⠄⠂⠁⠁⠂⠄⠄⠂✦
This script does the following:
- Adds native browser notifications for the following events (can be turned off individually):
- Alerts (neomail, pound, trading post, etc)
- Random events
- New posts in your guild board
- New posts in an open topic in the neoboards.
There's an optional setting to turn off alerts for neomail from theneopetsteam, because it's usually spam.
New posts are not automatically checked. You must refresh the page yourself. Anything else would be grounds for
freezing. But at least now you can refresh from another tab without looking at it!
Please note that there's no way to tell two alerts with the same name apart in the old layout. If you get an alert
with a specific text, don't get a different alert or clear your alerts, and then get another with the same text,
without visiting the beta layout for both alerts, you'll only be notified the first time.
✦ ⌇ saahphire
☆ ⠂⠄⠄⠂⠁⠁⠂⠄⠄⠂✦ ⠂⠄⠄⠂⠁⠁⠂⠄⠄⠂☆ ⠂⠄⠄⠂⠁⠁⠂⠄⠄⠂✦ ⠂⠄⠄⠂⠁⠁⠂⠄⠂⠄⠄⠂☆ ⠂⠄⠄⠂⠁⠁⠂⠄⠄⠂✦ ⠂⠄⠄⠂⠁⠁⠂⠄⠂⠄⠄⠂☆ ⠂⠄⠄⠂⠁⠁⠂⠄⠄⠂✦
........................................................................................................................
•:•.•:•.•:•:•:•:•:•:•:••:•.•:•.•:•:•:•:•:•:•:•:•.•:•.•:•:•:•:•:•:•:••:•.•:•.•:•.•:•:•:•:•:•:•:•:•.•:•:•.•:•.••:•.•:•.••:
*/
// Never remove a value from here. Set to false if you want it off, true if you want it on.
const settings = {
alerts: true,
randomevents: true,
tntneomail: true,
guildmessages: true,
neoboardmessages: true,
// So! If you only want the script to check for messages in specific topics, add their urls here, enclosed by quotes
// and separated by commas. If you do that, no other topic will have notifications! For example,
// neoboardallowlist: ["https://www.neopets.com/neoboards/topic.phtml?topic=164152582", "https://www.neopets.com/neoboards/topic.phtml?topic=164070442"]
neoboardallowlist: []
}
const getStoredPost = async (id) => (await GM.getValue("posts", [])).find(post => post.id === id);
const setStoredPost = async (data) => {
const allPosts = await GM.getValue("posts", []);
const index = allPosts.findIndex(post => post.id === data.id);
if(index !== -1) allPosts[index] = data;
else allPosts.push(data);
GM.setValue("posts", allPosts);
}
const purgePosts = async () => {
const now = new Date().getTime();
const allPosts = await GM.getValue("posts", []);
const purged = allPosts.filter(post => now - post.timestamp < 36288000000);
GM.setValue("posts", purged);
}
const notify = (title, message, url) => GM.notification({title: title, text: message, onclick: () => window.open(url, "_blank")});
const parseAlert = (alert) => {
return {
message: (alert.querySelector("p") ?? alert.childNodes[2])?.textContent.trim(),
id: alert.querySelector(".alert-x")?.dataset.delid,
title: alert.querySelector("b, h4")?.textContent,
url: alert.getElementsByTagName("a")[0]?.href
}
}
const getAlertData = (lastAlert) => {
const alert = document.querySelector(".eventIcon, #alerts li");
if(!alert) return;
const alertData = parseAlert(alert);
if(alertData.message === lastAlert.message) alertData.id ||= lastAlert.id;
return alertData;
}
const checkForAlerts = async () => {
const lastAlert = await GM.getValue("alert", {});
const newAlert = getAlertData(lastAlert);
if(!newAlert?.message || newAlert.message === lastAlert.message) return;
if(!settings.tntneomail && newAlert.message.contains("theneopetsteam")) return;
notify(newAlert.title, newAlert.message, newAlert.url);
GM.setValue("alert", {message: newAlert.message, id: newAlert.id});
}
const notifyRandomEvent = () => {
notify("Something has happened!", document.querySelector(".randomEvent .copy").textContent, window.location.href);
}
const sanitizeNeoHTML = neoHTML => neoHTML.replaceAll(/<\/?(b|i|font|div)[^>]*>|<\/p>/g, "").replaceAll(/<img[^>]+>/g, "🖼️").replaceAll(/<br>|<p>/g, "\n");
const parseGuildPost = () => {
return {
message: sanitizeNeoHTML(document.querySelector("td[align='left'][valign='top'][width='300'] br + br").nextElementSibling.innerHTML),
id: parseInt(document.querySelector("td[colspan='2'] td[align='left'] a").href.match(/_id=(\d+)/)[1]),
url: document.querySelector("td[colspan='2'] td[align='left'] a").href.match(/(.+?)&/)[1],
title: `${document.querySelector("table[cellspacing='1'] td[align='center'] a font").textContent} in your guild`
}
}
const checkForGuildPost = async () => {
if(document.querySelector("td[width='100%'] tr:last-child a font b").textContent === '<< Newer') return;
const lastId = await GM.getValue("guild", 0);
const newPost = parseGuildPost();
if(newPost.id === lastId) return;
GM.setValue("guild", newPost.id);
if(lastId) notify(newPost.title, newPost.message, newPost.url);
}
const parseNeoboardPost = () => {
return {
message: sanitizeNeoHTML(document.querySelector("div > li:last-of-type .boardPostMessage").innerHTML),
messageId: parseInt(document.querySelector("div > li:last-of-type button a").href.match(/regarding=(\d+)/)[1]),
url: window.location.href,
title: `${document.querySelector("div > li:last-of-type .postAuthorName").textContent} @ ${document.getElementsByTagName("h1")[0].textContent.trim()}`
}
}
const checkForNeoboardPost = async () => {
const isCurrentPage = !document.querySelector(".boardPageButton-active") || !document.querySelector(".boardPageButton-active ~ a");
const currentPage = parseInt(window.location.href.match(/next=(\d+)/)[1] ?? 1);
const topicId = parseInt(window.location.href.match(/topic.phtml\?topic=(\d+)/)[1]);
const lastPost = await getStoredPost(topicId);
if(!isCurrentPage) {
if(lastPost && !lastPost.warned && currentPage >= lastPost.page) {
notify("New Page!", `You're no longer in the last page of ${document.getElementsByTagName("h1")[0].textContent.trim()}!`, document.querySelector(".pageNav a:nth-last-child(2)").href);
lastPost.warned = true;
lastPost.timestamp = (new Date()).getTime();
setStoredPost(lastPost);
}
return;
}
const newPost = parseNeoboardPost();
if(lastPost?.messageId === newPost.messageId) {
lastPost.warned = false;
setStoredPost(lastPost);
return;
}
setStoredPost({id: topicId, messageId: newPost.messageId, warned: false, timestamp: (new Date()).getTime(), page: currentPage});
if(lastPost?.messageId) notify(newPost.title, newPost.message, newPost.url);
}
const canCheckNeoboardPost = () => {
if(!settings.neoboardmessages) return false;
if(!window.location.href.match('topic.phtml\\?topic=')) return false;
if(settings.neoboardallowlist.length > 0 && !settings.neoboardallowlist.some(l => window.location.href.match(l))) return false;
return true;
}
const initializeScript = async () => {
await purgePosts();
if(settings.alerts && document.querySelector("#header, nav-bell-icon__2020")) checkForAlerts();
if(settings.randomevents && document.querySelector(".randomEvent")) notifyRandomEvent();
if(settings.guildmessages && window.location.href.match('guild_board.phtml')) checkForGuildPost();
if(canCheckNeoboardPost()) checkForNeoboardPost();
}
(function() {
'use strict';
initializeScript();
})();