I have learnt a lot on this mission, including about bolt, more node js, and about ssh as well.\
So far for this mission, I have done four commands:
/m26-ping. It gets the latency of the bot. For this one I copy pasted it from the guide but I understand how it works. First it records the current time. Then, it acknowledges the command and when that’s done, it subtracts the current time from the previous time, giving it the latency./m26-joke. It grabs a joke from the api: https://official-joke-api.appspot.com/random_joke. I also copy pasted this one. It uses axios to fetch a joke. Here’s a joke from the bot:Have you heard of the band 1023MB?They haven't got a gig yet.
/m26-wordle. It gets the wordle answer of the day. I used the api: https://www.nytimes.com/svc/wordle/v2/YYYY-MM-DD.json. I made this one by myself. I have to fill in the dates, so I use this bit of code to get the date: const today = new Date();
const yyyy = today.getFullYear();
const mm = String(today.getMonth() + 1).padStart(2, '0');
const dd = String(today.getDate()).padStart(2, '0');
Then I just fill in the blanks:
await axios.get(`https://www.nytimes.com/svc/wordle/v2/${yyyy}-${mm}-${dd}.json`)
/m26-help This is the last and simplest one. It returns a fixed answer: await respond({
text:
`Available Commands:
/m26-ping - Check bot latency
/m26-joke - Get a joke
/m26-wordle - Cheat at wordle`
});
I think this might be the first and last devlog of this mission. Time to ship.
Today for MultiCopy, I added viewing functionality! It took so much longer than I thought because I had a few bugs in my copying code that prevented me from actually copying anything. I fixed those up, and then I added the viewbox. It was a lot of work, learning about shadow roots and grapheme clusters, but it was all worth it.
Basically, what happens is that the service worker (background.js) detects the keyboard shortcut that the user specified, and sends a message to the content script (content.js). In response to the message, the content script modifies an already created shadow root to display the text sent by the service worker. The content script shows the box for five seconds, then hides it.
But what if the copied text is too long?
Well that’s how grapheme clusters come into play. I want the text to be cut off at around 30 characters, but emojis to slice() are two characters long. That means that an emoji may get cut in half and be show incorrectly (😃😃=>😃�), so we use the spread operator in an array.
[..."value😃"].slice(0,30)+"..."
I’m not going to go into the specifics of actually how it works, but that’s the general idea.
Next, I’m going to do the pasting work (how am i going to do this) then I’m going to work on the CSS! Wish me luck!
I have never made a Chrome Extension before, so I used a fair bit of AI to look up commands (I pieced it together myself though).
MultiCopy is going to be a Chrome Extension that you can use to copy and paste content with multiple shortcuts.
For example:
|--------| Copy -| Paste -| View -----|
|--------|-------|-------|------------|
| Slot 1 | Alt+Z | Alt+A | Ctrl+Alt+Z |
| Slot 2 | Alt+X | Alt+S | Ctrl+Alt+X |
| Slot 3 | Alt+C | Alt+D | Ctrl+Alt+C |
etc.
Today, I managed to get the service worker successfully communicate with the injected script when I pressed the keyboard shortcut Alt+X. When the keyboard shortcut is pressed, the service worker communicates to the injected script by executing
const response = await chrome.tabs.sendMessage(tab.id, message)
and the injected script listens for it via
chrome.runtime.onMessage.addListener(() => {/*code*/})
So when the keyboard shortcut is pressed, the service worker sends an instruction to the injected script telling it to copy the current selected text. We do this with
const text = window.getSelection().toString()
This approach can’t copy images though, so I’ll have to make support for it later.
Then, we send a response back to the service worker:
sendResponse({ status:"success", text: [text] })
I haven’t added the storage logic yet, so now the service worker just logs the text to the console:
console.log(response.text)
Next I will add the copying logic, then I will add the pasting logic. The pasting logic will be a challenge because I have to find a way to paste it into the middle of text, but hopefully it will not be too much of a challenge.
Adding CSS was probably the easiest part of the mission. I just added a font (Google Sans Code, if you’re wondering), changed the background colour (to #001), and added some pseudo elements (I omitted the zigzag, as it looked quite weird). You can see the CSS below.
Also, I think that the mountains look pretty cool. 🏔️ 🏔️
Now all that’s left to do is write a README!
I made a music player! I used some AI since it’s been a while since I coded JavaScript, but I put together the thing myself. Here’s how it works.
First, I get the file from the user in the form of <input id="musicFile" accept"audio/*" type="file">.
Then, I listen for a change in the input by adding an event listener: musicFile.addEventListener("change", loadMusic);.
Once the user adds a file, I fetch the file :const file = this.files[0];.
Then I assign it to a blob URL: musicURL = URL.createObjectURL(file);.
Next, I assign the blob URL to the source tag: musicSource.src = musicURL;.
Finally, I reload the audio tag for the changes to take place: musicPlayer.load();.
Here’s the code:
HTML Code:
<input id="musicFile" type="file" accept="audio/*">
<audio id="musicPlayer" controls>
<source id="musicSource" src="">
</audio>
JavaScript Code:
function loadMusic() {
const file = this.files[0];
if (file) {
if (globalThis.musicURLblob){
URL.revokeObjectURL(globalThis.musicURLblob);
}
globalThis.musicURLblob = URL.createObjectURL(file);
musicSource.src = globalThis.musicURLblob;
musicPlayer.load();
musicPlayer.play();
}
}
let musicURLblob = null;
const musicFile = document.querySelector("#musicFile");
const musicSource = document.querySelector("#musicSource");
const musicPlayer = document.querySelector("#musicPlayer");
musicFile.addEventListener("change", loadMusic);
Cricket is a very basic operating system. When it’s done, it will have a lot of features, including:
So far, I’ve done the first one, the second two are in progress, and the third has not been started yet.
Here is an image: