safer-indie-wiki-buddy/background.js

166 lines
7.4 KiB
JavaScript

// onBeforeNavigate captures right before navigation to a new page starts;
// onCreatedNavigationTarget captures new tabs/windows;
// onCommitted captures after onBeforeNavigate, used to catch redirects.
chrome.webNavigation.onBeforeNavigate.addListener(event => main(event, 'onBeforeNavigation'));
chrome.webNavigation.onCreatedNavigationTarget.addListener(event => main(event, 'onCreatedNavigationTarget'));
chrome.webNavigation.onCommitted.addListener(event => main(event, 'onCommitted'));
function redirectToBreezeWiki(storage, eventInfo, url) {
function processRedirect(host) {
const subdomain = url.hostname.split(".")[0];
const article = url.href.split('fandom.com/wiki/')[1];
if (article) {
chrome.tabs.update(eventInfo.tabId, { url: host + '/' + subdomain + '/search?q=' + article });
} else {
chrome.tabs.update(eventInfo.tabId, { url: host + '/' + subdomain });
}
chrome.storage.sync.set({ 'countBreezeWiki': (storage.countBreezeWiki ?? 0) + 1 });
if ((storage.notifications ?? 'on') === 'on') {
// Notify that user is being redirected to BreezeWiki
let notifID = 'independent-wiki-redirector-notification-' + Math.floor(Math.random() * 1E16);
chrome.notifications.create(notifID, {
"type": "basic",
"iconUrl": 'images/logo-48.png',
"title": "You've been redirected to BreezeWiki!",
"message": "Indie Wiki Buddy has sent you to BreezeWiki for a cleaner, ad-free experience on Fandom."
});
// Self-clear notification after 6 seconds:
setTimeout(function () { chrome.notifications.clear(notifID); }, 6000);
}
}
if (url.href.includes('fandom.com/wiki/')) {
if (!(storage.breezewikiHost ?? null)) {
fetch('http://bw.getindie.wiki/instances.json')
.then((response) => response.json())
.then((breezewikiHosts) => {
const host = breezewikiHosts[Math.floor(Math.random() * breezewikiHosts.length)].instance;
chrome.storage.sync.set({ 'breezewikiHost': host });
chrome.storage.sync.set({ 'breezewikiHostOptions': breezewikiHosts });
chrome.storage.sync.set({ 'breezewikiHostFetchTimestamp': Date.now() });
processRedirect(host);
});
} else {
processRedirect(storage.breezewikiHost);
}
}
}
// Load website data.
async function getData() {
const LANGS = ["DE", "EN", "ES", "IT"];
let sites = [];
let promises = [];
for (let i = 0; i < LANGS.length; i++) {
promises.push(fetch(chrome.runtime.getURL('data/sites' + LANGS[i] + '.json'))
.then((resp) => resp.json())
.then(function (jsonData) {
sites = sites.concat(jsonData);
}));
}
await Promise.all(promises);
return sites;
}
async function main(eventInfo, eventName) {
// Create object prototypes for getting and setting attributes:
Object.prototype.get = function(prop) {
this[prop] = this[prop] || {};
return this[prop];
};
Object.prototype.set = function(prop, value) {
this[prop] = value;
}
// Store tab URL and remove any search parameters and section anchors:
const url = new URL(eventInfo.url.replace(/(\?|#).*/i, ''));
// Check if tabId is > 0 (some background events may have tabId < 0)
// & check for fandom.com in hostname and quit early if it's not:
if (eventInfo.tabId > 0 && url.hostname.includes('.fandom.com')) {
// Check if tab is actually available
// This is mainly to prevent background processes from triggering an event
chrome.tabs.get(eventInfo.tabId, async function (tab) {
if (tab) {
let sites = [];
sites = await getData();
chrome.storage.sync.get(function (storage) {
if ((storage.power ?? 'on') === 'on') {
// Check if site is in our list of wikis:
let matchingSites = sites.filter(el => url.href.replace(/^https?:\/\//, '').startsWith(el.origin_base_url));
if (matchingSites.length > 0) {
// Select match with longest base URL
let closestMatch = "";
matchingSites.forEach(site => {
if (site.origin_base_url.length > closestMatch.length) {
closestMatch = site.origin_base_url;
}
});
let site = matchingSites.find(site => site.origin_base_url === closestMatch);
if (site) {
// Get user's settings for the wiki
let settings = storage.siteSettings || {};
let id = site['id'];
let siteSetting = 'alert';
if (settings.hasOwnProperty(id) && settings[id].hasOwnProperty('action')) {
siteSetting = settings[id].action;
}
// Check if redirects are enabled for the site:
if (siteSetting === 'redirect') {
// Get article name from the end of the URL;
// We can't just take the last part of the path due to subpages;
// Instead, we take everything after the wiki's base URL + content path:
let article = url.href.split(site['origin_base_url'] + site['origin_content_path'])[1];
// Set up URL to redirect user to based on wiki platform:
if (article || (!article && !url.href.split(site['origin_base_url'] + '/')[1])) {
let newURL = '';
if (article) {
let searchParams = '';
switch (site['destination_platform']) {
case 'mediawiki':
searchParams = '?title=Special:Search&search=' + article;
break;
case 'doku':
searchParams = 'start?do=search&q=' + article;
break;
}
newURL = 'https://' + site["destination_base_url"] + site["destination_content_path"] + searchParams;
} else {
newURL = 'https://' + site["destination_base_url"];
}
// Perform redirect:
chrome.tabs.update(eventInfo.tabId, { url: newURL });
// Increase global redirect count:
chrome.storage.sync.set({ 'countRedirects': (storage.countRedirects ?? 0) + 1 });
// Notify if enabled
if ((storage.notifications ?? 'on') === 'on') {
// Notify that user is being redirected
let notifID = 'independent-wiki-redirector-notification-' + Math.floor(Math.random() * 1E16);
chrome.notifications.create(notifID, {
"type": "basic",
"iconUrl": 'images/logo-48.png',
"title": "You've been redirected!",
"message": "Indie Wiki Buddy has sent you from " + site['origin'] + " to " + site['destination']
});
// Self-clear notification after 6 seconds:
setTimeout(function () { chrome.notifications.clear(notifID); }, 6000);
}
}
} else if ((storage.breezewiki ?? 'off') === 'on') {
redirectToBreezeWiki(storage, eventInfo, url);
}
}
} else if ((storage.breezewiki ?? 'off') === 'on') {
redirectToBreezeWiki(storage, eventInfo, url);
}
}
});
}
});
}
}