From 7d01ebc1fc76667076937da4c812cae3aad059c9 Mon Sep 17 00:00:00 2001 From: lartsch Date: Thu, 8 Dec 2022 05:08:14 -0500 Subject: [PATCH] add some try/catches so no irrelevant exceptions bubble up in ext. view, move script el to head (popup), move some code inject.js to separate function, bump version --- firefox/manifest.json | 2 +- manifest.json | 2 +- src/background.js | 58 ++++++++++++++-------- src/background.min.js | 2 +- src/inject.js | 109 ++++++++++++++++++++++++------------------ src/inject.min.js | 2 +- src/popup.html | 4 +- src/popup.js | 64 +++++++++++++++++-------- src/popup.min.js | 2 +- 9 files changed, 152 insertions(+), 93 deletions(-) diff --git a/firefox/manifest.json b/firefox/manifest.json index f7e8c6c..293477c 100644 --- a/firefox/manifest.json +++ b/firefox/manifest.json @@ -1,6 +1,6 @@ { "name": "FediAct", - "version": "0.9.1", + "version": "0.9.2", "description": "Simplifies interactions on other Mastodon instances than your own. Visit https://github.com/lartsch/FediFollow-Chrome for more.", "manifest_version": 2, "content_scripts": [ diff --git a/manifest.json b/manifest.json index b5d989f..26c6709 100644 --- a/manifest.json +++ b/manifest.json @@ -1,6 +1,6 @@ { "name": "FediAct", - "version": "0.9.1", + "version": "0.9.2", "description": "Simplifies interactions on other Mastodon instances than your own. Visit https://github.com/lartsch/FediFollow-Chrome for more.", "manifest_version": 3, "content_scripts": [ diff --git a/src/background.js b/src/background.js index 1954ab9..66b7737 100644 --- a/src/background.js +++ b/src/background.js @@ -1,20 +1,16 @@ var browser, chrome, settings; -var enableConsoleLog = true; -var logPrepend = "[FediAct]"; -var tokenInterval = 5 +const enableConsoleLog = true; +const logPrepend = "[FediAct]"; +const tokenInterval = 3 // minutes -var tokenRegex = /"access_token":".*?",/gm; +const tokenRegex = /"access_token":".*?",/gm; // required settings keys with defauls -var settingsDefaults = { +const settingsDefaults = { fediact_homeinstance: null, fediact_showfollows: true } -function onError(error){ - console.error(`${logPrepend} Error: ${error}`); -} - // wrapper to prepend to log messages function log(text) { if (enableConsoleLog) { @@ -25,10 +21,15 @@ function log(text) { // get redirect url (it will be the url on the toot authors home instance) async function resolveToot(url) { return new Promise(async function(resolve) { - var res = await fetch(url, {method: 'HEAD'}) - if (res.redirected) { - resolve(res.url) - } else { + try { + var res = await fetch(url, {method: 'HEAD'}) + if (res.redirected) { + resolve(res.url) + } else { + resolve(false) + } + } catch(e) { + log(e) resolve(false) } }); @@ -37,8 +38,13 @@ async function resolveToot(url) { // fetch API token here (will use logged in session automatically) async function fetchBearerToken() { var url = "https://" + settings.fediact_homeinstance; - var res = await fetch(url); - var text = await res.text(); + try { + var res = await fetch(url); + var text = await res.text(); + } catch(e) { + log(e) + return false + } if (text) { // dom parser is not available in background workers, so we use regex to parse the html.... // for some reason, regex groups do also not seem to work in chrome background workers... the following is ugly but should work fine @@ -49,10 +55,9 @@ async function fetchBearerToken() { if (indexOne > -1 && indexTwo > -1) { indexOne = indexOne + 16 var token = content[0].substring(indexOne, indexTwo); - console.log(token) if (token.length > 16) { settings.fediact_token = token; - return; + return true } } } @@ -63,13 +68,22 @@ async function fetchBearerToken() { } async function fetchData() { - settings = await (browser || chrome).storage.local.get(settingsDefaults); + try { + settings = await (browser || chrome).storage.local.get(settingsDefaults) + } catch(e) { + log(e) + return false + } if (settings.fediact_homeinstance) { await fetchBearerToken() } else { log("Home instance not set"); } - await (browser || chrome).storage.local.set(settings); + try { + await (browser || chrome).storage.local.set(settings) + } catch { + log(e) + } } // fetch api token right after install (mostly for debugging, when the ext. is reloaded) @@ -96,7 +110,11 @@ chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { // if the tabId of the update event is the same like the tabId that started the listener in the first place AND when the update event is an URL if (tabId === sender.tab.id && changeInfo.url) { // ... then let the content script know about the change - chrome.tabs.sendMessage(tabId, {urlchanged: changeInfo.url}) + try { + chrome.tabs.sendMessage(tabId, {urlchanged: changeInfo.url}) + } catch(e) { + log(e) + } } }); } diff --git a/src/background.min.js b/src/background.min.js index a31d0ed..b0db8b3 100644 --- a/src/background.min.js +++ b/src/background.min.js @@ -1 +1 @@ -var browser,chrome,a,t=!0,n="[FediAct]",o=/"access_token":".*?",/gm,e={fediact_homeinstance:null,fediact_showfollows:!0};function s(e){console.error(n+" Error: "+e)}function i(e){t&&console.log(n+" "+e)}async function r(n){return new Promise(async function(e){var t=await fetch(n,{method:"HEAD"});t.redirected?e(t.url):e(!1)})}async function c(){var e="https://"+a.fediact_homeinstance,e=await(await fetch(e)).text();if(e){e=e.match(o);if(e){var t=e[0].search(/"access_token":"/),n=e[0].search(/",/);if(-1{if(e.url)return r(e.url).then(t),!0;e.updatedsettings&&d(),e.running&&chrome.tabs.onUpdated.addListener(function(e,t,n){e===a.tab.id&&t.url&&chrome.tabs.sendMessage(e,{urlchanged:t.url})})}); \ No newline at end of file +var browser,chrome,n;const a=!0,c="[FediAct]",t=3,r=/"access_token":".*?",/gm,s={fediact_homeinstance:null,fediact_showfollows:!0};function i(t){a&&console.log(c+" "+t)}async function o(a){return new Promise(async function(e){try{var t=await fetch(a,{method:"HEAD"});t.redirected?e(t.url):e(!1)}catch(t){i(t),e(!1)}})}async function d(){var t="https://"+n.fediact_homeinstance;try{var e=await(await fetch(t)).text()}catch(t){return i(t),!1}if(e){t=e.match(r);if(t){var e=t[0].search(/"access_token":"/),a=t[0].search(/",/);if(-1{if(t.url)return o(t.url).then(e),!0;t.updatedsettings&&u(),t.running&&chrome.tabs.onUpdated.addListener(function(t,e,a){if(t===n.tab.id&&e.url)try{chrome.tabs.sendMessage(t,{urlchanged:e.url})}catch(t){i(t)}})}); \ No newline at end of file diff --git a/src/inject.js b/src/inject.js index b11eb82..1faf8b0 100644 --- a/src/inject.js +++ b/src/inject.js @@ -120,7 +120,12 @@ async function makeRequest(method, url, extraheaders) { statusText: xhr.statusText }); }; - xhr.send(); + try { + xhr.send() + } catch(e) { + log(e) + resolve(false) + } }); } @@ -411,13 +416,18 @@ function resolveTootToExternalHome(tooturl) { // TODO: check if a delay is necessary here too if (tooturl) { return new Promise(resolve => { - chrome.runtime.sendMessage({url: tooturl}, function(response) { - if(response) { - resolve(response); - } else { - resolve(false); - } - }); + try { + chrome.runtime.sendMessage({url: tooturl}, function(response) { + if(response) { + resolve(response); + } else { + resolve(false); + } + }); + } catch (e) { + log(e); + resolve(false) + } }); } else { return false @@ -738,6 +748,24 @@ async function processToots() { async function processFollow() { // for mastodon v3 - v4 does not show follow buttons / account cards on /explore async function process(el) { + // wrapper for follow/unfollow action + async function execFollow(action, id) { + if (action == "follow") { + var followed = await followHomeInstance(id) + if (followed) { + $(el).text("Unfollow"); + action = "unfollow" + return true + } + } else { + var unfollowed = await unfollowHomeInstance(id) + if (unfollowed) { + $(el).text("Follow"); + action = "follow" + return true + } + } + } var fullHandle var action = "follow" // for mastodon v3 explore page @@ -773,39 +801,12 @@ async function processFollow() { clicks++; if (clicks == 1) { timer = setTimeout(async function() { - if (action == "follow") { - var followed = await followHomeInstance(resolvedHandle[0]) - if (followed) { - $(el).text("Unfollow"); - action = "unfollow" - } - } else { - var unfollowed = await unfollowHomeInstance(resolvedHandle[0]) - if (unfollowed) { - $(el).text("Follow"); - action = "follow" - } - } + execFollow(action, resolvedHandle[0]) clicks = 0; }, 350); } else { clearTimeout(timer); - var done - if (action == "follow") { - var followed = await followHomeInstance(resolvedHandle[0]) - if (followed) { - $(el).text("Unfollow"); - action = "unfollow" - done = true - } - } else { - var unfollowed = await unfollowHomeInstance(resolvedHandle[0]) - if (unfollowed) { - $(el).text("Follow"); - action = "follow" - done = true - } - } + var done = await execFollow(action, resolvedHandle[0]) if (done) { var saveText = $(el).text() var redirectUrl = 'https://' + settings.fediact_homeinstance + '/@' + resolvedHandle[1] @@ -828,7 +829,9 @@ async function processFollow() { } } } + // create css selector from selector array var allFollowPaths = followButtonPaths.join(",") + // one domnodeappear to rule them all $(document).DOMNodeAppear(async function(e) { process($(e.target)) }, allFollowPaths) @@ -930,21 +933,32 @@ async function checkSite() { } function urlChangeMonitor() { - // send message to initialize onUpdated listener (this way we do not need to bind the listener for ALL sites) - chrome.runtime.sendMessage({running: true}) - // then wait for any url changes + // wait for any url change messages from background script chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) { if (request.urlchanged) { // reset already processed elements processed = [] } }); + // send message to initialize onUpdated listener in background script (this way it gets the tabid and we do not need to bind the listener for ALL sites) + try { + chrome.runtime.sendMessage({running: true}) + return true + } catch(e) { + log(e) + } + return false } // run wrapper async function run() { - // get settings - settings = await (browser || chrome).storage.local.get(settingsDefaults); + // get setting + try { + settings = await (browser || chrome).storage.local.get(settingsDefaults) + } catch(e) { + log(e) + return false + } if (settings) { // validate settings if (checkSettings()) { @@ -953,9 +967,12 @@ async function run() { if (fedireply) { processReply() } else { - urlChangeMonitor(); - processFollow(); - processToots(); + if (urlChangeMonitor()) { + processFollow() + processToots() + } else { + log("Failed to initialize background script.") + } } } else { log("Will not process this site.") @@ -966,4 +983,4 @@ async function run() { } } -run() +run() \ No newline at end of file diff --git a/src/inject.min.js b/src/inject.min.js index de72d71..afe6eb8 100644 --- a/src/inject.min.js +++ b/src/inject.min.js @@ -1 +1 @@ -const e=["div.account__header button.logo-button","div.public-account-header a.logo-button","div.account-card a.logo-button","div.directory-card a.icon-button","div.detailed-status a.logo-button"],a=["div.account__header__tabs__name small","div.public-account-header__tabs__name small","div.detailed-status span.display-name__account","div.display-name > span"],i=/^([a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,}$/,u=/^[^@]*@(?\w+)(@(?([\w-]+\.)+?\w+))?(\/(?\d+))?\/?$/,n=!0,o="[FediAct]",J=200,r="/api/v1/instance",s="/api/v1/statuses",c="/api/v2/search",l="/api/v1/accounts",d=500;var browser,chrome,f,h,p={};const t={fediact_homeinstance:null,fediact_alert:!1,fediact_mode:"blacklist",fediact_whitelist:null,fediact_blacklist:null,fediact_target:"_self",fediact_autoaction:!0,fediact_token:null,fediact_showfollows:!0,fediact_redirects:!0,fediact_enabledelay:!0};var m={};function v(t){n&&console.log(o+" "+t)}!function(i){i.fn.DOMNodeAppear=function(e,a){var t=i(this);if(!(a=a||"function"==typeof t.selector&&t.selector))return!1;i(document).on("animationstart webkitAnimationStart oanimationstart MSAnimationStart",function(t){"nodeInserted"==t.originalEvent.animationName&&i(t.target).is(a)&&"function"==typeof e&&e(t)})},jQuery.fn.onAppear=jQuery.fn.DOMNodeAppear}(jQuery);var g=function(t){for(var e,a=window.location.search.substring(1).split("&"),i=0;i{setTimeout(function(){t()},d-e)}),f=t),new Promise(function(t,e){let a=new XMLHttpRequest;if(a.open(n,o),a.timeout=3e3,r)for(var i in r)a.setRequestHeader(i,r[i]);a.onload=function(){200<=this.status&&this.status<300?t(a.responseText):t(!1)},a.onerror=function(){e({status:this.status,statusText:a.statusText})},a.send()})}function w(t){return t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function _(t,e,a){return t.replace(new RegExp(w(e),"g"),a)}function k(t){var e;p.fediact_redirects?(p.fediact_alert&&alert("Redirecting..."),e=window.open(t,p.fediact_target),v("Redirected to "+t),e?e.focus():v("Could not open new window. Please allow popups for this website.")):v("Redirects disabled.")}async function y(t){if(p.fediact_autoaction){t=await b("POST","https://"+p.fediact_homeinstance+l+"/"+t+"/follow",p.tokenheader);if(t)return!(!(t=JSON.parse(t)).following&&!t.requested&&(v("Follow failed."),1))}else v("Auto-action disabled.")}async function T(t){if(p.fediact_autoaction){t=await b("POST","https://"+p.fediact_homeinstance+l+"/"+t+"/unfollow",p.tokenheader);if(t)return!(t=JSON.parse(t)).following&&!t.requested||(v("Unfollow failed."),!1)}else v("Auto-action disabled.")}async function A(t){if(p.fediact_autoaction){t=await b("POST","https://"+p.fediact_homeinstance+s+"/"+t+"/reblog",p.tokenheader);if(t)return!!JSON.parse(t).reblogged||(v("Boost failed."),!1)}else v("Auto-action disabled.")}async function O(t){if(p.fediact_autoaction){t=await b("POST","https://"+p.fediact_homeinstance+s+"/"+t+"/unreblog",p.tokenheader);if(t)return!JSON.parse(t).reblogged||(v("Unboost failed."),!1)}else v("Auto-action disabled.")}async function x(t){if(p.fediact_autoaction){t=await b("POST","https://"+p.fediact_homeinstance+s+"/"+t+"/favourite",p.tokenheader);if(t)return!!JSON.parse(t).favourited||(v("Favourite failed."),!1)}else v("Auto-action disabled.")}async function S(t){if(p.fediact_autoaction){t=await b("POST","https://"+p.fediact_homeinstance+s+"/"+t+"/unfavourite",p.tokenheader);if(t)return!JSON.parse(t).favourited||(v("Unfavourite failed."),!1)}else v("Auto-action disabled.")}async function N(t){if(p.fediact_autoaction){t=await b("POST","https://"+p.fediact_homeinstance+s+"/"+t+"/bookmark",p.tokenheader);if(t)return!!JSON.parse(t).bookmarked||(v("Bookmark failed."),!1)}else v("Auto-action disabled.")}async function C(t){if(p.fediact_autoaction){t=await b("POST","https://"+p.fediact_homeinstance+s+"/"+t+"/unbookmark",p.tokenheader);if(t)return!JSON.parse(t).bookmarked||(v("Unbookmark failed."),!1)}else v("Auto-action disabled.")}async function P(t){var e="https://"+p.fediact_homeinstance+l+"/relationships?";for(const o of t)e+="id[]="+o.toString()+"&";var a=await b("GET",e,p.tokenheader),i=Array(t.length).fill(!1);if(a)for(var a=JSON.parse(a),n=0;n{chrome.runtime.sendMessage({url:t},function(t){e(t||!1)})})}function I(t,e,a){var i,n,o=$(t).toggleClass(a).hasClass(a);for(i of e)o?$(t).css(i[0],i[2]):"!remove"==i[1]?(n=_($(t).attr("style"),i[0]+": "+i[2]+";",""),$(t).attr("style",n)):$(t).css(i[0],i[1])}function q(t,e,a,i){return a=a&&a.join(","),new MutationObserver(function(t){t.forEach(function(t){var e=t.addedNodes;null!==e&&$(e).each(function(){(!a||$(this).is(a))&&i(this,t)})})}).observe($(t)[0],e)}function F(t){for(const e of t)if($(e).length)return $(e).text().trim();return!1}async function j(){$(document).DOMNodeAppear(function(t){$(t.target).find("button:has(i.fa-reply), button:has(i.fa-reply-all)").click()},"div.detailed-status__action-bar")}async function z(){async function f(t,e,a){var i=function(t){var e=!1;$(t.currentTarget).children("i.fa-retweet").length?e=$(t.currentTarget).children("i.fa-retweet").hasClass("fediactive")?"unboost":"boost":$(t.currentTarget).children("i.fa-star").length?e=$(t.currentTarget).hasClass("fediactive")?"unfavourite":"favourite":$(t.currentTarget).children("i.fa-bookmark").length?e=$(t.currentTarget).hasClass("fediactive")?"unbookmark":"bookmark":$(t.currentTarget).attr("href")&&(~$(t.currentTarget).attr("href").indexOf("type=reblog")?e=$(t.currentTarget).hasClass("fediactive")?"unboost":"boost":~$(t.currentTarget).attr("href").indexOf("type=favourite")&&(e=$(t.currentTarget).hasClass("fediactive")?"unfavourite":"favourite"));return e}(a);return i?await D(e,i)?("boost"==i||"unboost"==i?(I($(a.currentTarget).find("i"),[["color","!remove","rgb(140, 141, 255)"],["transition-duration","!remove","0.9s"],["background-position","!remove","0px 100%"]],"fediactive"),t in m&&(m[t][2]=!m[t][2])):"favourite"==i||"unfavourite"==i?(I($(a.currentTarget),[["color","!remove","rgb(202, 143, 4)"]],"fediactive"),t in m&&(m[t][3]=!m[t][3])):(I($(a.currentTarget),[["color","!remove","rgb(255, 80, 80)"]],"fediactive"),t in m&&(m[t][4]=!m[t][4])),!0):(v("Could not execute action on home instance."),!1):(v("Could not determine action."),!1)}async function e(i){$(i).is("div.detailed-status")&&(i=$(i).closest("div.focusable"));var t,o,r,s,e,a,n,c=function(t){var e,a,[i,n,o]=[!1,!1,!1];return $(t).find("span.display-name__account").length&&(n=$(t).find("span.display-name__account").first().text().trim()),$(t).is(".detailed-status__wrapper")?i=(a=window.location.href.split("?")[0].split("/")).pop()||a.pop():$(t).find("a.status__relative-time").attr("href")?!(a=$(t).find("a.status__relative-time").attr("href").split("?")[0]).startsWith("http")||(e=new URL(a),location.hostname==e.hostname)?i=(a=a.split("/")).pop()||a.pop():(i=a,o=!0):$(t).find("a.detailed-status__datetime").attr("href")?i=(a=$(t).find("a.detailed-status__datetime").attr("href").split("?")[0].split("/")).pop()||a.pop():$(t).attr("data-id")?i=$(t).attr("data-id").split("-").slice(-1)[0]:$(t).closest("article[data-id], div[data-id]").length?i=$(t).closest("article[data-id], div[data-id]")[0].attr("data-id").split("-").slice(-1)[0]:$(t).find("a.modal-button").length&&(i=(a=$(t).find("a.modal-button").attr("href").split("?")[0].split("/")).pop()||a.pop()),[i,n,o]}($(i));function l(t,e,a){$(i).find(".feditriggered").remove(),$(s).removeClass("disabled").removeAttr("disabled"),e&&!$(o).hasClass("fediactive")&&I($(o),[["color","!remove","rgb(202, 143, 4)"]],"fediactive"),t&&!$(r).find("i.fediactive").length&&I($(r).find("i"),[["color","!remove","rgb(140, 141, 255)"],["transition-duration","!remove","0.9s"],["background-position","!remove","0px 100%"]],"fediactive"),a&&!$(s).hasClass("fediactive")&&I($(s),[["color","!remove","rgb(255, 80, 80)"]],"fediactive")}function d(i,n){$(e).on("click",function(t){t.preventDefault(),t.stopImmediatePropagation(),k(n[5]+"?fedireply")}),$([o,r,s]).each(function(){var e,a=0;$(this).on("click",async function(t){t.preventDefault(),t.stopImmediatePropagation(),1==++a?e=setTimeout(async function(){await f(i,n[1],t)||v("Action failed."),a=0},350):(clearTimeout(e),await f(i,n[1],t)?k(n[5]):v("Action failed."),a=0)}).on("dblclick",function(t){t.preventDefault(),t.stopImmediatePropagation()})})}c?(o=$(i).find("button:has(i.fa-star), a.icon-button:has(i.fa-star)").first(),r=$(i).find("button:has(i.fa-retweet), a.icon-button:has(i.fa-retweet)").first(),s=$(i).find("button:has(i.fa-bookmark)").first(),e=$(i).find("button:has(i.fa-reply), button:has(i.fa-reply-all), a.icon-button:has(i.fa-reply), a.icon-button:has(i.fa-reply-all)").first(),c[0]in m?(l((a=m[c[0]])[2],a[3],a[4]),d(c[0],a)):(c[2]?t=c[0]:!(a=c[1].match(u)).groups.handledomain||~location.hostname.indexOf(a.groups.handledomain)?t=location.protocol+"//"+location.hostname+"/users/"+a.groups.handle+"/statuses/"+c[0]:(a=await E(location.protocol+"//"+location.hostname+"/"+c[1]+"/"+c[0]))?~a.indexOf("/users/")?t=a:u.test(a)&&(n=a.match(u))&&(t=a.split("@")[0]+"users/"+n.groups.handle+"/statuses/"+n.groups.tootid):(v("Resolve fallback #1"),t=location.protocol+"//"+location.hostname+"/"+c[1]+"/"+c[0]),t?(a=await U(t))?(l(a[2],a[3],a[4]),n="https://"+p.fediact_homeinstance+"/@"+a[0]+"/"+a[1],a.push(n),m[c[0]]=a,d(c[0],a)):(v("Failed to resolve: "+t),m[c[0]]=!1,$(i).find(".feditriggered").remove(),$("Not resolved").insertAfter($(o))):v("Could not identify a post URI for home resolving."))):v("Could not get toot data.")}$(document).DOMNodeAppear(async function(t){e($(t.target))},"div.status, div.detailed-status")}async function G(){var t=e.join(",");$(document).DOMNodeAppear(async function(t){!async function(n){var t,o,r,s,c="follow";if($(n).closest("div.account-card").length)t=$(n).closest("div.account-card").find("div.display-name > span").text().trim();else for(const e of a)if($(e).length){t=$(e).text().trim();break}t&&((o=await R(t))?(p.fediact_showfollows&&(await P([o[0]]))[0]&&($(n).text("Unfollow"),c="unfollow"),r=0,$(n).off(),$(n).unbind(),$(n).on("click",async function(t){var e,a,i;t.preventDefault(),t.stopImmediatePropagation(),1==++r?s=setTimeout(async function(){"follow"==c?await y(o[0])&&($(n).text("Unfollow"),c="unfollow"):await T(o[0])&&($(n).text("Follow"),c="follow"),r=0},350):(clearTimeout(s),"follow"==c?await y(o[0])&&($(n).text("Unfollow"),c="unfollow",e=!0):await T(o[0])&&($(n).text("Follow"),c="follow",e=!0),e?(a=$(n).text(),i="https://"+p.fediact_homeinstance+"/@"+o[1],$(n).text("Redirecting..."),setTimeout(function(){k(i),$(n).text(a)},1e3)):v("Action failed."),r=0)}).on("dblclick",function(t){t.preventDefault(),t.stopImmediatePropagation()})):v("Could not resolve user home ID."))}($(t.target))},t)}function M(t){var e,a=[];for(e of t.split(/\r?\n/))e=e.trim(),i.test(e)?a.push(e):v("Removed invalid domain "+e+" from blacklist/whitelist.");return[...new Set(a)]}function B(){if(null==p.fediact_homeinstance||!p.fediact_homeinstance)return v("Mastodon home instance is not set."),!1;if(!p.fediact_token)return v("No API token available. Are you logged in to your home instance? If yes, wait for 1-2 minutes and reload page."),!1;if(p.tokenheader={Authorization:"Bearer "+p.fediact_token},!i.test(p.fediact_homeinstance))return v("Instance setting is not a valid domain name."),!1;if($.inArray(p.fediact_mode,["blacklist","whitelist"])<0&&(p.fediact_mode="blacklist"),$.inArray(p.fediact_target,["_blank","_self"])<0&&(p.fediact_target="_blank"),"whitelist"==p.fediact_mode){if(p.fediact_whitelist=M(p.fediact_whitelist),p.fediact_whitelist.length<1)return v("Whitelist is empty or invalid."),!1}else p.fediact_blacklist=M(p.fediact_blacklist);return!0}async function L(){if(location.hostname!=p.fediact_homeinstance||(h=g("fedireply"))){if("whitelist"==p.fediact_mode){if($.inArray(location.hostname,p.fediact_whitelist)<0)return v("Current site is not in whitelist."),!1}else if(-1<$.inArray(location.hostname,p.fediact_blacklist))return v("Current site is in blacklist."),!1;var t=await b("GET",location.protocol+"//"+location.hostname+r,null);if(t)if(JSON.parse(t).uri)return!0;v("Does not look like a Mastodon instance.")}else v("Current site is your home instance.");return!1}function Q(){chrome.runtime.sendMessage({running:!0}),chrome.runtime.onMessage.addListener(function(t,e,a){t.urlchanged&&(m=[])})}async function W(){(p=await(browser||chrome).storage.local.get(t))?B()&&(await L()?(h?j:(Q(),G(),z))():v("Will not process this site.")):v("Could not load settings.")}W(); \ No newline at end of file +const e=["div.account__header button.logo-button","div.public-account-header a.logo-button","div.account-card a.logo-button","div.directory-card a.icon-button","div.detailed-status a.logo-button"],a=["div.account__header__tabs__name small","div.public-account-header__tabs__name small","div.detailed-status span.display-name__account","div.display-name > span"],i=/^([a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,}$/,u=/^[^@]*@(?\w+)(@(?([\w-]+\.)+?\w+))?(\/(?\d+))?\/?$/,n=!0,o="[FediAct]",M=200,r="/api/v1/instance",s="/api/v1/statuses",c="/api/v2/search",d="/api/v1/accounts",l=500;var browser,chrome,f,h,p={};const t={fediact_homeinstance:null,fediact_alert:!1,fediact_mode:"blacklist",fediact_whitelist:null,fediact_blacklist:null,fediact_target:"_self",fediact_autoaction:!0,fediact_token:null,fediact_showfollows:!0,fediact_redirects:!0,fediact_enabledelay:!0};var m={};function v(t){n&&console.log(o+" "+t)}!function(i){i.fn.DOMNodeAppear=function(e,a){var t=i(this);if(!(a=a||"function"==typeof t.selector&&t.selector))return!1;i(document).on("animationstart webkitAnimationStart oanimationstart MSAnimationStart",function(t){"nodeInserted"==t.originalEvent.animationName&&i(t.target).is(a)&&"function"==typeof e&&e(t)})},jQuery.fn.onAppear=jQuery.fn.DOMNodeAppear}(jQuery);var g=function(t){for(var e,a=window.location.search.substring(1).split("&"),i=0;i{setTimeout(function(){t()},l-e)}),f=t),new Promise(function(e,t){let a=new XMLHttpRequest;if(a.open(n,o),a.timeout=3e3,r)for(var i in r)a.setRequestHeader(i,r[i]);a.onload=function(){200<=this.status&&this.status<300?e(a.responseText):e(!1)},a.onerror=function(){t({status:this.status,statusText:a.statusText})};try{a.send()}catch(t){v(t),e(!1)}})}function w(t){return t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function _(t,e,a){return t.replace(new RegExp(w(e),"g"),a)}function k(t){var e;p.fediact_redirects?(p.fediact_alert&&alert("Redirecting..."),e=window.open(t,p.fediact_target),v("Redirected to "+t),e?e.focus():v("Could not open new window. Please allow popups for this website.")):v("Redirects disabled.")}async function y(t){if(p.fediact_autoaction){t=await b("POST","https://"+p.fediact_homeinstance+d+"/"+t+"/follow",p.tokenheader);if(t)return!(!(t=JSON.parse(t)).following&&!t.requested&&(v("Follow failed."),1))}else v("Auto-action disabled.")}async function T(t){if(p.fediact_autoaction){t=await b("POST","https://"+p.fediact_homeinstance+d+"/"+t+"/unfollow",p.tokenheader);if(t)return!(t=JSON.parse(t)).following&&!t.requested||(v("Unfollow failed."),!1)}else v("Auto-action disabled.")}async function O(t){if(p.fediact_autoaction){t=await b("POST","https://"+p.fediact_homeinstance+s+"/"+t+"/reblog",p.tokenheader);if(t)return!!JSON.parse(t).reblogged||(v("Boost failed."),!1)}else v("Auto-action disabled.")}async function A(t){if(p.fediact_autoaction){t=await b("POST","https://"+p.fediact_homeinstance+s+"/"+t+"/unreblog",p.tokenheader);if(t)return!JSON.parse(t).reblogged||(v("Unboost failed."),!1)}else v("Auto-action disabled.")}async function S(t){if(p.fediact_autoaction){t=await b("POST","https://"+p.fediact_homeinstance+s+"/"+t+"/favourite",p.tokenheader);if(t)return!!JSON.parse(t).favourited||(v("Favourite failed."),!1)}else v("Auto-action disabled.")}async function x(t){if(p.fediact_autoaction){t=await b("POST","https://"+p.fediact_homeinstance+s+"/"+t+"/unfavourite",p.tokenheader);if(t)return!JSON.parse(t).favourited||(v("Unfavourite failed."),!1)}else v("Auto-action disabled.")}async function N(t){if(p.fediact_autoaction){t=await b("POST","https://"+p.fediact_homeinstance+s+"/"+t+"/bookmark",p.tokenheader);if(t)return!!JSON.parse(t).bookmarked||(v("Bookmark failed."),!1)}else v("Auto-action disabled.")}async function C(t){if(p.fediact_autoaction){t=await b("POST","https://"+p.fediact_homeinstance+s+"/"+t+"/unbookmark",p.tokenheader);if(t)return!JSON.parse(t).bookmarked||(v("Unbookmark failed."),!1)}else v("Auto-action disabled.")}async function P(t){var e="https://"+p.fediact_homeinstance+d+"/relationships?";for(const o of t)e+="id[]="+o.toString()+"&";var a=await b("GET",e,p.tokenheader),i=Array(t.length).fill(!1);if(a)for(var a=JSON.parse(a),n=0;n{try{chrome.runtime.sendMessage({url:t},function(t){e(t||!1)})}catch(t){v(t),e(!1)}})}function I(t,e,a){var i,n,o=$(t).toggleClass(a).hasClass(a);for(i of e)o?$(t).css(i[0],i[2]):"!remove"==i[1]?(n=_($(t).attr("style"),i[0]+": "+i[2]+";",""),$(t).attr("style",n)):$(t).css(i[0],i[1])}function E(t){for(const e of t)if($(e).length)return $(e).text().trim();return!1}async function F(){$(document).DOMNodeAppear(function(t){$(t.target).find("button:has(i.fa-reply), button:has(i.fa-reply-all)").click()},"div.detailed-status__action-bar")}async function z(){async function f(t,e,a){var i=function(t){var e=!1;$(t.currentTarget).children("i.fa-retweet").length?e=$(t.currentTarget).children("i.fa-retweet").hasClass("fediactive")?"unboost":"boost":$(t.currentTarget).children("i.fa-star").length?e=$(t.currentTarget).hasClass("fediactive")?"unfavourite":"favourite":$(t.currentTarget).children("i.fa-bookmark").length?e=$(t.currentTarget).hasClass("fediactive")?"unbookmark":"bookmark":$(t.currentTarget).attr("href")&&(~$(t.currentTarget).attr("href").indexOf("type=reblog")?e=$(t.currentTarget).hasClass("fediactive")?"unboost":"boost":~$(t.currentTarget).attr("href").indexOf("type=favourite")&&(e=$(t.currentTarget).hasClass("fediactive")?"unfavourite":"favourite"));return e}(a);return i?await D(e,i)?("boost"==i||"unboost"==i?(I($(a.currentTarget).find("i"),[["color","!remove","rgb(140, 141, 255)"],["transition-duration","!remove","0.9s"],["background-position","!remove","0px 100%"]],"fediactive"),t in m&&(m[t][2]=!m[t][2])):"favourite"==i||"unfavourite"==i?(I($(a.currentTarget),[["color","!remove","rgb(202, 143, 4)"]],"fediactive"),t in m&&(m[t][3]=!m[t][3])):(I($(a.currentTarget),[["color","!remove","rgb(255, 80, 80)"]],"fediactive"),t in m&&(m[t][4]=!m[t][4])),!0):(v("Could not execute action on home instance."),!1):(v("Could not determine action."),!1)}async function e(i){$(i).is("div.detailed-status")&&(i=$(i).closest("div.focusable"));var t,o,r,s,e,a,n,c=function(t){var e,a,[i,n,o]=[!1,!1,!1];return $(t).find("span.display-name__account").length&&(n=$(t).find("span.display-name__account").first().text().trim()),$(t).is(".detailed-status__wrapper")?i=(a=window.location.href.split("?")[0].split("/")).pop()||a.pop():$(t).find("a.status__relative-time").attr("href")?!(a=$(t).find("a.status__relative-time").attr("href").split("?")[0]).startsWith("http")||(e=new URL(a),location.hostname==e.hostname)?i=(a=a.split("/")).pop()||a.pop():(i=a,o=!0):$(t).find("a.detailed-status__datetime").attr("href")?i=(a=$(t).find("a.detailed-status__datetime").attr("href").split("?")[0].split("/")).pop()||a.pop():$(t).attr("data-id")?i=$(t).attr("data-id").split("-").slice(-1)[0]:$(t).closest("article[data-id], div[data-id]").length?i=$(t).closest("article[data-id], div[data-id]")[0].attr("data-id").split("-").slice(-1)[0]:$(t).find("a.modal-button").length&&(i=(a=$(t).find("a.modal-button").attr("href").split("?")[0].split("/")).pop()||a.pop()),[i,n,o]}($(i));function d(t,e,a){$(i).find(".feditriggered").remove(),$(s).removeClass("disabled").removeAttr("disabled"),e&&!$(o).hasClass("fediactive")&&I($(o),[["color","!remove","rgb(202, 143, 4)"]],"fediactive"),t&&!$(r).find("i.fediactive").length&&I($(r).find("i"),[["color","!remove","rgb(140, 141, 255)"],["transition-duration","!remove","0.9s"],["background-position","!remove","0px 100%"]],"fediactive"),a&&!$(s).hasClass("fediactive")&&I($(s),[["color","!remove","rgb(255, 80, 80)"]],"fediactive")}function l(i,n){$(e).on("click",function(t){t.preventDefault(),t.stopImmediatePropagation(),k(n[5]+"?fedireply")}),$([o,r,s]).each(function(){var e,a=0;$(this).on("click",async function(t){t.preventDefault(),t.stopImmediatePropagation(),1==++a?e=setTimeout(async function(){await f(i,n[1],t)||v("Action failed."),a=0},350):(clearTimeout(e),await f(i,n[1],t)?k(n[5]):v("Action failed."),a=0)}).on("dblclick",function(t){t.preventDefault(),t.stopImmediatePropagation()})})}c?(o=$(i).find("button:has(i.fa-star), a.icon-button:has(i.fa-star)").first(),r=$(i).find("button:has(i.fa-retweet), a.icon-button:has(i.fa-retweet)").first(),s=$(i).find("button:has(i.fa-bookmark)").first(),e=$(i).find("button:has(i.fa-reply), button:has(i.fa-reply-all), a.icon-button:has(i.fa-reply), a.icon-button:has(i.fa-reply-all)").first(),c[0]in m?(d((a=m[c[0]])[2],a[3],a[4]),l(c[0],a)):(c[2]?t=c[0]:!(a=c[1].match(u)).groups.handledomain||~location.hostname.indexOf(a.groups.handledomain)?t=location.protocol+"//"+location.hostname+"/users/"+a.groups.handle+"/statuses/"+c[0]:(a=await q(location.protocol+"//"+location.hostname+"/"+c[1]+"/"+c[0]))?~a.indexOf("/users/")?t=a:u.test(a)&&(n=a.match(u))&&(t=a.split("@")[0]+"users/"+n.groups.handle+"/statuses/"+n.groups.tootid):(v("Resolve fallback #1"),t=location.protocol+"//"+location.hostname+"/"+c[1]+"/"+c[0]),t?(a=await U(t))?(d(a[2],a[3],a[4]),n="https://"+p.fediact_homeinstance+"/@"+a[0]+"/"+a[1],a.push(n),m[c[0]]=a,l(c[0],a)):(v("Failed to resolve: "+t),m[c[0]]=!1,$(i).find(".feditriggered").remove(),$("Not resolved").insertAfter($(o))):v("Could not identify a post URI for home resolving."))):v("Could not get toot data.")}$(document).DOMNodeAppear(async function(t){e($(t.target))},"div.status, div.detailed-status")}async function j(){var t=e.join(",");$(document).DOMNodeAppear(async function(t){!async function(i){async function n(t,e){if("follow"==t){if(await y(e))return $(i).text("Unfollow"),t="unfollow",!0}else if(await T(e))return $(i).text("Follow"),t="follow",!0}var t,o,r,s,c="follow";if($(i).closest("div.account-card").length)t=$(i).closest("div.account-card").find("div.display-name > span").text().trim();else for(const e of a)if($(e).length){t=$(e).text().trim();break}t&&((o=await R(t))?(p.fediact_showfollows&&(await P([o[0]]))[0]&&($(i).text("Unfollow"),c="unfollow"),r=0,$(i).off(),$(i).unbind(),$(i).on("click",async function(t){var e,a;t.preventDefault(),t.stopImmediatePropagation(),1==++r?s=setTimeout(async function(){n(c,o[0]),r=0},350):(clearTimeout(s),await n(c,o[0])?(e=$(i).text(),a="https://"+p.fediact_homeinstance+"/@"+o[1],$(i).text("Redirecting..."),setTimeout(function(){k(a),$(i).text(e)},1e3)):v("Action failed."),r=0)}).on("dblclick",function(t){t.preventDefault(),t.stopImmediatePropagation()})):v("Could not resolve user home ID."))}($(t.target))},t)}function J(t){var e,a=[];for(e of t.split(/\r?\n/))e=e.trim(),i.test(e)?a.push(e):v("Removed invalid domain "+e+" from blacklist/whitelist.");return[...new Set(a)]}function G(){if(null==p.fediact_homeinstance||!p.fediact_homeinstance)return v("Mastodon home instance is not set."),!1;if(!p.fediact_token)return v("No API token available. Are you logged in to your home instance? If yes, wait for 1-2 minutes and reload page."),!1;if(p.tokenheader={Authorization:"Bearer "+p.fediact_token},!i.test(p.fediact_homeinstance))return v("Instance setting is not a valid domain name."),!1;if("whitelist"==p.fediact_mode){if(p.fediact_whitelist=J(p.fediact_whitelist),p.fediact_whitelist.length<1)return v("Whitelist is empty or invalid."),!1}else p.fediact_blacklist=J(p.fediact_blacklist);return!0}async function B(){if(location.hostname!=p.fediact_homeinstance||(h=g("fedireply"))){if("whitelist"==p.fediact_mode){if($.inArray(location.hostname,p.fediact_whitelist)<0)return v("Current site is not in whitelist."),!1}else if(-1<$.inArray(location.hostname,p.fediact_blacklist))return v("Current site is in blacklist."),!1;var t=await b("GET",location.protocol+"//"+location.hostname+r,null);if(t)if(JSON.parse(t).uri)return!0;v("Does not look like a Mastodon instance.")}else v("Current site is your home instance.");return!1}function L(){chrome.runtime.onMessage.addListener(function(t,e,a){t.urlchanged&&(m=[])});try{return chrome.runtime.sendMessage({running:!0}),!0}catch(t){v(t)}return!1}async function Q(){try{p=await(browser||chrome).storage.local.get(t)}catch(t){return v(t),!1}p?G()&&(await B()?h?F():L()?(j(),z()):v("Failed to initialize background script."):v("Will not process this site.")):v("Could not load settings.")}Q(); \ No newline at end of file diff --git a/src/popup.html b/src/popup.html index af6b891..86a54e3 100644 --- a/src/popup.html +++ b/src/popup.html @@ -13,6 +13,8 @@ margin-bottom: 5px; } + +
@@ -58,7 +60,5 @@
- - diff --git a/src/popup.js b/src/popup.js index 54b2179..0a2af24 100644 --- a/src/popup.js +++ b/src/popup.js @@ -1,6 +1,6 @@ // required settings keys with defauls -var settings = { +const settingsDefaults = { fediact_homeinstance: null, fediact_alert: false, fediact_mode: "blacklist", @@ -14,23 +14,28 @@ var settings = { } // fix for cross-browser storage api compatibility -var browser, chrome; +var browser, chrome, settings; +const enableConsoleLog = true; +const logPrepend = "[FediAct]"; -function onError(error){ - console.error(`[FediAct] Error: ${error}`); +// wrapper to prepend to log messages +function log(text) { + if (enableConsoleLog) { + console.log(logPrepend + ' ' + text) + } } // this performs loading the settings into the popup, reacting to changes and saving changes -function popupTasks(settings) { - +function popupTasks() { + // function to show confirmation when settings were updated successfully function showConfirmation() { $("span#indicator").show(); setTimeout(function() { $("span#indicator").hide(); }, 1500); } - - function updateSettings(){ + // get all current values and write them to the local storage + async function updateSettings(){ // update settings values settings.fediact_homeinstance = $("input#homeinstance").val().trim(); settings.fediact_alert = $("input#alert").is(':checked'); @@ -43,11 +48,16 @@ function popupTasks(settings) { settings.fediact_redirects = $("input#redirects").is(':checked'); settings.fediact_enabledelay = $("input#delay").is(':checked'); // write to storage - const waitForSaved = (browser || chrome).storage.local.set(settings); + try { + await (browser || chrome).storage.local.set(settings) + } catch { + log(e) + return false + } // show saved indicator after successful save - waitForSaved.then(showConfirmation(), onError); + showConfirmation() } - + // restore form based on loaded settings function restoreForm() { // set all default/configured values and show fields accordingly $("input#homeinstance").val(settings.fediact_homeinstance); @@ -77,20 +87,34 @@ function popupTasks(settings) { } }); } - - $(document).ready(async function() { + $(document).ready(function() { // restore the form values restoreForm(); // perform storage actions on form submit $("form#fediact-settings").on('submit', function(e){ // prevent default - e.preventDefault(); + e.preventDefault() // update settings - updateSettings(); - chrome.runtime.sendMessage({updatedsettings: true}); - }); - }); - + updateSettings() + try { + chrome.runtime.sendMessage({updatedsettings: true}) + } catch(e) { + log(e) + } + }) + }) } -(browser || chrome).storage.local.get(settings).then(popupTasks, onError) \ No newline at end of file +async function loadAndRun() { + try { + settings = await (browser || chrome).storage.local.get(settingsDefaults) + } catch(e) { + log(e) + return false + } + if (settings) { + popupTasks() + } +} + +loadAndRun() \ No newline at end of file diff --git a/src/popup.min.js b/src/popup.min.js index cfc4db5..e5ad0ab 100644 --- a/src/popup.min.js +++ b/src/popup.min.js @@ -1 +1 @@ -var browser,chrome,t={fediact_homeinstance:null,fediact_alert:!1,fediact_mode:"blacklist",fediact_whitelist:null,fediact_blacklist:null,fediact_target:"_self",fediact_autoaction:!0,fediact_showfollows:!0,fediact_redirects:!0,fediact_enabledelay:!0};function i(t){console.error("[FediAct] Error: "+t)}function e(t){function e(){t.fediact_homeinstance=$("input#homeinstance").val().trim(),t.fediact_alert=$("input#alert").is(":checked"),t.fediact_mode=$("select#mode").val(),t.fediact_whitelist=$("textarea#whitelist_content").val(),t.fediact_blacklist=$("textarea#blacklist_content").val(),t.fediact_target=$("select#target").val(),t.fediact_autoaction=$("input#autoaction").is(":checked"),t.fediact_showfollows=$("input#showfollows").is(":checked"),t.fediact_redirects=$("input#redirects").is(":checked"),t.fediact_enabledelay=$("input#delay").is(":checked"),(browser||chrome).storage.local.set(t).then(($("span#indicator").show(),void setTimeout(function(){$("span#indicator").hide()},1500)),i)}$(document).ready(async function(){$("input#homeinstance").val(t.fediact_homeinstance),$("textarea#blacklist_content").val(t.fediact_blacklist),$("textarea#whitelist_content").val(t.fediact_whitelist),$("select#mode").val(t.fediact_mode),$("select#target").val(t.fediact_target),$("input#alert").prop("checked",t.fediact_alert),$("input#autoaction").prop("checked",t.fediact_autoaction),$("input#showfollows").prop("checked",t.fediact_showfollows),$("input#redirects").prop("checked",t.fediact_redirects),$("input#delay").prop("checked",t.fediact_enabledelay),("whitelist"==$("select#mode").val()?$("div#whitelist_input"):$("div#blacklist_input")).show(),$("select#mode").change(function(){("whitelist"==$("select#mode").val()?($("div#blacklist_input").hide(),$("div#whitelist_input")):($("div#whitelist_input").hide(),$("div#blacklist_input"))).show()}),$("form#fediact-settings").on("submit",function(t){t.preventDefault(),e(),chrome.runtime.sendMessage({updatedsettings:!0})})})}(browser||chrome).storage.local.get(t).then(e,i); \ No newline at end of file +const t={fediact_homeinstance:null,fediact_alert:!1,fediact_mode:"blacklist",fediact_whitelist:null,fediact_blacklist:null,fediact_target:"_self",fediact_autoaction:!0,fediact_showfollows:!0,fediact_redirects:!0,fediact_enabledelay:!0};var browser,chrome,a;const i=!0,c="[FediAct]";function l(t){i&&console.log(c+" "+t)}function n(){async function i(){a.fediact_homeinstance=$("input#homeinstance").val().trim(),a.fediact_alert=$("input#alert").is(":checked"),a.fediact_mode=$("select#mode").val(),a.fediact_whitelist=$("textarea#whitelist_content").val(),a.fediact_blacklist=$("textarea#blacklist_content").val(),a.fediact_target=$("select#target").val(),a.fediact_autoaction=$("input#autoaction").is(":checked"),a.fediact_showfollows=$("input#showfollows").is(":checked"),a.fediact_redirects=$("input#redirects").is(":checked"),a.fediact_enabledelay=$("input#delay").is(":checked");try{await(browser||chrome).storage.local.set(a)}catch{return l(e),!1}$("span#indicator").show(),setTimeout(function(){$("span#indicator").hide()},1500)}$(document).ready(function(){$("input#homeinstance").val(a.fediact_homeinstance),$("textarea#blacklist_content").val(a.fediact_blacklist),$("textarea#whitelist_content").val(a.fediact_whitelist),$("select#mode").val(a.fediact_mode),$("select#target").val(a.fediact_target),$("input#alert").prop("checked",a.fediact_alert),$("input#autoaction").prop("checked",a.fediact_autoaction),$("input#showfollows").prop("checked",a.fediact_showfollows),$("input#redirects").prop("checked",a.fediact_redirects),$("input#delay").prop("checked",a.fediact_enabledelay),("whitelist"==$("select#mode").val()?$("div#whitelist_input"):$("div#blacklist_input")).show(),$("select#mode").change(function(){("whitelist"==$("select#mode").val()?($("div#blacklist_input").hide(),$("div#whitelist_input")):($("div#whitelist_input").hide(),$("div#blacklist_input"))).show()}),$("form#fediact-settings").on("submit",function(t){t.preventDefault(),i();try{chrome.runtime.sendMessage({updatedsettings:!0})}catch(t){l(t)}})})}async function d(){try{a=await(browser||chrome).storage.local.get(t)}catch(t){return l(t),!1}a&&n()}d(); \ No newline at end of file