Arc Browser: Building a plugin (Boost) with help from ChatGPT
I’ve been using the Arc Browser for a couple of months now and one of my favourite things is the simplicity of the plugin (or as they call it, 'Boost') functionality.
I wanted to port over a Chrome bookmark that I use to capture the podcasts that I’ve listened to on Player.FM. In this blog post I’ll show how ChatGPT helped me convert the bookmark code to an Arc Boost.
I started with this code that finds all the listened to podcasts and then writes them out to the console:
javascript:(()=>{
function decodeHtml(html) {
var txt = document.createElement("textarea");
txt.innerHTML = html;
return txt.value;
}
let rows = $("article[data-played-at]").map(function(idx, ele) {
let row = "* Listened to " + $(ele).attr('data-title') + " by " + $(ele).find("div.title").text() + " - https://player.fm/series/" + $(ele).attr('data-series-id') + "/" + $(ele).attr('data-slug');
return decodeHtml(row);
}).get();
setTimeout(async()=>{
console.log(rows.join("\n"));
alert(rows.length + " podcasts copied")
}, 2000)}
)()
An example of the output is shown below:
* Listened to A groundbreaking new proof for Pythagoras’ Theorem? by More or Less: Behind the Stats - https://player.fm/series/1301260/a-groundbreaking-new-proof-for-pythagoras-theorem
* Listened to Twitter storm by Trending - https://player.fm/series/1301465/twitter-storm
* Listened to After Pulse: Suddenly Unemployed by Community Pulse - https://player.fm/series/1409158/after-pulse-suddenly-unemployed
I was relying on jQuery to do find the parts of the page, but that isn’t available in an Arc Boost, so I need to use the built in APIs instead.
ChatGPT guided me towards the document.querySelectorAll
function and converted this:
$("article[data-played-at]")
to:
document.querySelectorAll("article[data-played-at]")
But then I wasn’t sure how to call the map
function on that output, so I asked ChatGPT again.
So I did that and then needed to work out how to extract attributes from each element. The function calls that ChatGPT told me to make didn’t exist, so I had to fall back on the documentation (I know!). I eventually ended up with the following code to extract the rows:
let rows = Array.from(document.querySelectorAll("article[data-played-at]")).map(function(ele) {
let row = "* Listened to " + ele.attributes['data-title'].value +
" by " + ele.querySelector("div.title").textContent +
" - https://player.fm/series/" + ele.attributes['data-series-id'].value +
"/" + ele.attributes['data-slug'].value;
return decodeHtml(row);
});
Next I asked it to add a button to the page that I could click on to copy the listened episodes to the clipboard.
It first suggested using navigator.clipboard
, but that wasn’t working for me at the time, so it suggested I used document.execCommand('copy')
instead.
The full code for the plugin looks like this:
function decodeHtml(html) {
var txt = document.createElement("textarea");
txt.innerHTML = html;
return txt.value;
}
// Create an image
const buttonDiv = document.createElement("div");
buttonDiv.style.display = "flex";
buttonDiv.style.justifyContent = "center";
buttonDiv.style.marginBottom = "16px";
const button = document.createElement("button");
button.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<path d="M11 0H3a2 2 0 0 0-2 2v9h2V2h8V2a2 2 0 0 0-2-2zm1 4H4v9h8V4z"/>
</svg> Copy Podcasts`;
button.style.display = "flex";
button.style.alignItems = "center";
button.style.gap = "8px";
button.style.backgroundColor = "white";
button.style.border = "1px solid #ccc";
button.style.borderRadius = "4px";
button.style.padding = "8px";
button.onclick = function () {
let rows = Array.from(document.querySelectorAll("article[data-played-at]")).map(function(ele) {
let row = "* Listened to " + ele.attributes['data-title'].value +
" by " + ele.querySelector("div.title").textContent +
" - https://player.fm/series/" + ele.attributes['data-series-id'].value +
"/" + ele.attributes['data-slug'].value;
return decodeHtml(row);
});
const textToCopy = rows.join("\n");
const textArea = document.createElement('textarea');
textArea.value = textToCopy;
document.body.appendChild(textArea);
textArea.select();
document.execCommand('copy');
document.body.removeChild(textArea);
console.log(textToCopy);
alert(rows.length + " podcasts copied")
};
buttonDiv.appendChild(button);
const preamble = document.querySelector(".preamble");
preamble.insertAdjacentElement("beforebegin", buttonDiv);
You can see the Boost in action below:
About the author
I'm currently working on short form content at ClickHouse. I publish short 5 minute videos showing how to solve data problems on YouTube @LearnDataWithMark. I previously worked on graph analytics at Neo4j, where I also co-authored the O'Reilly Graph Algorithms Book with Amy Hodler.