Skip to content

Instantly share code, notes, and snippets.

@magistrula
Last active June 5, 2020 17:10
Show Gist options
  • Save magistrula/1f5a2d9f6c56227c02a8e96007b0b0ae to your computer and use it in GitHub Desktop.
Save magistrula/1f5a2d9f6c56227c02a8e96007b0b0ae to your computer and use it in GitHub Desktop.
WNR Mentions Collector
// ==UserScript==
// @name WNR Mentions Collector
// @version 3.4.0
// @description Save data associated with the first mention notification on the page
// @author Anna Andresian
// @match https://www.facebook.com/whitenonsenseroundup/notifications/
// @grant none
// ==/UserScript==
(function() {
'use strict';
const NOTIF_LINK_SELECTOR = '.uiList > li:first-child,.uiList > li a';
const LOGS_SEPARATOR = '\n=============================================================\n';
const MENTION_TEXT = 'mentioned White Nonsense Roundup';
const WNR_PAGE_ID = '1155118494509189';
const HOW_TO_CLEAR = 'To clear specific mentions, run clearWnrMentions(<id1>, <id2>, ...)\nTo clear all mentions, run clearAllWnrMentions()\n';
const HOW_TO_LOG = 'To log all mentions, run logWnrMentions()';
// https://stackoverflow.com/questions/27745/getting-parts-of-a-url-regex
const URL_REGEX = /^(http[s]?|ftp):\/\/([^:\/\s]+)((\/\w+)*\/)([\w\-\.]+[^#?\s]+)(.*)?(#[\w\-]+)?$/;
const _getItem = (key) => JSON.parse(localStorage.getItem(key) || '[]');
const _setItem = (key, value) => localStorage.setItem(key, JSON.stringify(value));
const _getMentions = () => _getItem('wnrMentions');
const _setMentions = (value) => _setItem('wnrMentions', value);
const _logMentions = (mentions) => {
const mentionLogs = mentions.map(({ received, text, url, fullUrl, recurrences }, index) => {
return `${index + 1}.\nPost URL: ${url}\nFull URL: ${fullUrl}\nText: ${text}\nRecurrences: ${recurrences}\nid: ${received}\nReceived ${new Date(received)}`;
}).join(LOGS_SEPARATOR);
const timestamp = `${LOGS_SEPARATOR}= ${new Date()} =${LOGS_SEPARATOR}\n`;
const logText = `${timestamp}${mentionLogs}${LOGS_SEPARATOR}\n${HOW_TO_CLEAR}${HOW_TO_LOG}`;
console.log(logText);
};
const _buildMentionDatum = (url, text) => {
const decodedUrl = window.decodeURIComponent(url);
const [, protocol, host] = decodedUrl.match(URL_REGEX) || [];
const [, targetStory] = decodedUrl.match(/target_story=([^&]+)/) || [];
const [, userId, postId] = (targetStory || '').match(/(\d+):[^\d&]*:?(\d+)/) || [];
const [, commentId] = decodedUrl.match(/comment_id=([\d]+)/) || [];
const [, replyCommentId] = decodedUrl.match(/reply_comment_id=([\d]+)/) || [];
const postUrl = postId && `${protocol}://${host}/${userId}/posts/${postId}`;
return {
commentId,
replyCommentId,
postId,
userId,
text,
fullUrl: decodedUrl,
url: postId ? postUrl : decodedUrl
};
}
const _getOccurrenceInfo = (newMention, wnrMentions) => {
let numRecurrences = 1;
for (let i = 0; i < wnrMentions.length; i++) {
if (_haveSamePrimaryReference(newMention, wnrMentions[i])) {
if (_haveSameSecondaryReference(newMention, wnrMentions[i])) {
return { numRecurrences: null, isDuplicate: true };
}
if (numRecurrences === 1) {
numRecurrences = wnrMentions[i].recurrences + 1;
}
}
}
return { numRecurrences, isDuplicate: false };
};
const _haveSamePrimaryReference = (mention1, mention2) => (
(mention1.postId && mention1.postId === mention2.postId) ||
(mention1.commentId && mention1.commentId === mention2.commentId)
);
const _haveSameSecondaryReference = (mention1, mention2) => (
(mention1.postId && mention1.text === mention2.text) ||
(mention1.commentId && mention1.replyCommentId === mention2.replyCommentId)
);
window.logWnrMentions = () => _logMentions(_getMentions());
window.clearAllWnrMentions = () => {
if (window.confirm('Are you sure? This cannot be undone.')) {
_setMentions([]);
}
};
window.clearWnrMentions = (...receivedDates) => {
if (receivedDates.length === 0) {
window.alert('Input the ids of the mentions you would like to clear');
return;
}
if (window.confirm('Are you sure? This cannot be undone.')) {
const datesSet = new Set(receivedDates);
const remainingMentions = _getMentions().filter(m => !datesSet.has(m.received));
_setMentions(remainingMentions);
}
};
window.migrateWnrMentions = () => {
const wnrMentions = _getMentions();
for (let i = wnrMentions.length - 1; i >= 0; i--) {
const newDatum = _buildMentionDatum(wnrMentions[i].fullUrl, wnrMentions[i].text);
Object.assign(wnrMentions[i], newDatum, {
recurrences: _getOccurrenceInfo(newDatum, wnrMentions.slice(i + 1)).numRecurrences
});
}
_setMentions(wnrMentions);
};
window.onload = () => window.setTimeout(() => {
const wnrMentions = _getMentions();
const notifLinks = document.querySelectorAll(NOTIF_LINK_SELECTOR);
const firstMentionLink = Array.from(notifLinks).find(el => el.innerHTML.includes(MENTION_TEXT));
if (!firstMentionLink) {
window.logWnrMentions();
return;
}
const firstMention = _buildMentionDatum(firstMentionLink.href, firstMentionLink.textContent);
if (firstMention.userId === WNR_PAGE_ID) {
window.logWnrMentions();
return;
}
const { numRecurrences, isDuplicate } = _getOccurrenceInfo(firstMention, wnrMentions);
if (!isDuplicate){
const datum = Object.assign({}, firstMention, {
received: Date.now(),
recurrences: numRecurrences
});
_setMentions([datum, ...wnrMentions]);
}
window.logWnrMentions();
}, 2000);
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment