safer-indie-wiki-buddy/background.js

258 lines
10 KiB
JavaScript
Raw Normal View History

if (typeof importScripts !== 'undefined') {
importScripts('common-functions-general.js');
}
// Capture web requests
chrome.webRequest.onBeforeSendHeaders.addListener(
async (event) => {
if (event.documentLifecycle !== 'prerender') {
if (event.frameType === 'sub_frame') {
let tabInfo = await chrome.tabs.get(event.tabId);
main(tabInfo.url, event.tabId);
} else {
main(event.url, event.tabId);
}
}
},
{ urls: ['*://*.fandom.com/*', '*://*.wiki.fextralife.com/*'], types: ['main_frame', 'sub_frame'] }
);
// Listen for user turning extension on or off, to update icon
chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => {
if (msg.action === 'updateIcon') {
setPowerIcon(msg.value);
}
});
// Listen for browser starting, to set initial icon state
chrome.runtime.onStartup.addListener(() => {
chrome.storage.local.get({ 'power': 'on' }, (item) => {
setPowerIcon(item.power);
});
});
// Listen for extension installed/updating
chrome.runtime.onInstalled.addListener(async (detail) => {
// Set initial icon state
chrome.storage.local.get({ 'power': 'on' }, (item) => {
setPowerIcon(item.power);
});
// If new install, open settings with starter guide
if (detail.reason === 'install') {
chrome.tabs.create({ url: 'settings.html?newinstall=true' });
}
2023-10-16 06:08:08 +00:00
2023-11-16 10:07:24 +00:00
// If update, open changelog if setting is enabled
chrome.storage.sync.get({ 'openChangelog': 'off' }, (item) => {
2023-11-16 10:07:24 +00:00
if (item.openChangelog === 'on' && detail.reason === 'update') {
chrome.tabs.create({ url: 'https://getindie.wiki/changelog/?updated=true', active: false });
2023-11-16 10:07:24 +00:00
}
});
// Temporary functions for 3.0 migration
if (detail.reason === 'update') {
commonFunctionMigrateToV3();
}
});
function setPowerIcon(status) {
const manifestVersion = chrome.runtime.getManifest().manifest_version;
if (status === 'on') {
if (manifestVersion === 2) {
chrome.browserAction.setIcon({ path: "/images/logo-128.png" });
} else {
chrome.action.setIcon({ path: "/images/logo-128.png" });
}
} else {
if (manifestVersion === 2) {
chrome.browserAction.setIcon({ path: "/images/logo-off.png" });
} else {
chrome.action.setIcon({ path: "/images/logo-off.png" });
}
}
}
function redirectToBreezeWiki(storage, tabId, url) {
function processRedirect(host) {
// Extract article from URL
const urlFormatted = new URL(url);
const subdomain = urlFormatted.hostname.split(".")[0];
const article = url.split('fandom.com/wiki/')[1].replaceAll('%20', '_');
// Perform redirect
if (article) {
chrome.tabs.update(tabId, { url: host + '/' + subdomain + '/wiki/' + article });
} else {
chrome.tabs.update(tabId, { url: host + '/' + subdomain });
}
// Increase BreezeWiki stat count
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(() => { chrome.notifications.clear(notifID); }, 6000);
}
}
if (url.includes('fandom.com/wiki/') && !url.includes('fandom=allow')) {
if (!(storage.breezewikiHost ?? null)) {
fetch('https://bw.getindie.wiki/instances.json')
.then((response) => {
if (response.ok) {
return response.json();
}
throw new Error('Indie Wiki Buddy failed to get BreezeWiki data.');
}).then((breezewikiHosts) => {
breezewikiHosts = breezewikiHosts.filter(host =>
chrome.runtime.getManifest().version.localeCompare(host.iwb_version,
undefined,
{ numeric: true, sensitivity: 'base' }
) >= 0
);
// Check if BreezeWiki's main site is available
let breezewikiMain = breezewikiHosts.filter(host => host.instance === 'https://breezewiki.com');
if (breezewikiMain.length > 0) {
chrome.storage.sync.set({ 'breezewikiHost': breezewikiMain[0].instance });
} else {
// If BreezeWiki.com is not available, set to a random mirror
try {
chrome.storage.sync.set({ 'breezewikiHost': breezewikiHosts[Math.floor(Math.random() * breezewikiHosts.length)].instance });
} catch (e) {
console.log('Indie Wiki Buddy failed to get BreezeWiki data: ' + e);
}
}
chrome.storage.sync.set({ 'breezewikiHostOptions': breezewikiHosts });
chrome.storage.sync.set({ 'breezewikiHostFetchTimestamp': Date.now() });
processRedirect(host);
}).catch((e) => {
console.log('Indie Wiki Buddy failed to get BreezeWiki data: ' + e);
2023-10-16 05:29:31 +00:00
chrome.storage.sync.set({ 'breezewikiHost': 'https://breezewiki.com' });
});
} else {
if (storage.breezewikiHost === 'CUSTOM') {
processRedirect(storage.breezewikiCustomHost || 'https://breezewiki.com');
} else {
processRedirect(storage.breezewikiHost);
}
}
}
}
async function main(url, tabId) {
// 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;
}
// Check if tab is actually available
// This is mainly to prevent background processes from triggering an event
let sites = [];
chrome.storage.local.get((localStorage) => {
chrome.storage.sync.get(async (syncStorage) => {
const storage = { ...syncStorage, ...localStorage };
if ((storage.power ?? 'on') === 'on') {
let crossLanguageSetting = storage.crossLanguage || 'off';
let matchingSite = await commonFunctionFindMatchingSite(url, crossLanguageSetting);
if (matchingSite) {
// Get user's settings for the wiki
let settings = storage.wikiSettings || {};
let id = matchingSite['id'];
let siteSetting = settings[id] || storage.defaultWikiAction || 'alert';
// Remove query paramters
let urlObj = new URL(url);
urlObj.search = '';
url = String(decodeURIComponent(urlObj.toString()));
// 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 originArticle = decodeURIComponent(url.split(matchingSite['origin_base_url'] + matchingSite['origin_content_path'])[1] || '');
let destinationArticle = matchingSite['destination_content_prefix'] + originArticle;
// Set up URL to redirect user to based on wiki platform
let newURL = '';
if (originArticle) {
// Check if main page
if (originArticle === matchingSite['origin_main_page']) {
switch (matchingSite['destination_platform']) {
case 'doku':
destinationArticle = '';
break;
default:
destinationArticle = matchingSite['destination_main_page'];
}
}
// Replace underscores with spaces as that performs better in search
destinationArticle = destinationArticle.replaceAll('_', ' ');
// If a Fextralife wiki, replace plus signs with spaces
// When there are multiple plus signs together, this regex will only replace only the first
if (matchingSite['origin_base_url'].includes('.wiki.fextralife.com')) {
destinationArticle = destinationArticle.replace(/(?<!\+)\+/g, ' ');
}
// Encode article
destinationArticle = encodeURIComponent(destinationArticle);
let searchParams = '';
switch (matchingSite['destination_platform']) {
case 'mediawiki':
searchParams = '?search=' + destinationArticle;
break;
case 'doku':
searchParams = 'start?do=search&q=' + destinationArticle;
break;
}
newURL = 'https://' + matchingSite["destination_base_url"] + matchingSite["destination_search_path"] + searchParams;
} else {
newURL = 'https://' + matchingSite["destination_base_url"];
}
// Perform redirect
chrome.tabs.update(tabId, { url: newURL });
// Increase 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 " + matchingSite['origin'] + " to " + matchingSite['destination']
});
// Self-clear notification after 6 seconds
setTimeout(() => { chrome.notifications.clear(notifID); }, 6000);
}
} else if ((storage.breezewiki ?? 'off') === 'on' || (storage.breezewiki ?? 'off') === 'redirect') {
redirectToBreezeWiki(storage, tabId, url);
}
}
} else if ((storage.breezewiki ?? 'off') === 'on' || (storage.breezewiki ?? 'off') === 'redirect') {
redirectToBreezeWiki(storage, tabId, url);
}
});
});
}