2021-10-07

Tags: lisp.

Getting Started on Nyxt Hacking: Episode 1

Getting Started on Nyxt Hacking: Episode 1

By Pedro Delfino

The series

Hacking is an art and Nyxt hacking is one of its kind. Nyxt could be defined as Minecraft for web browsing in the sense that it is an open world. Being a fully computable environment, the constraints are much more on the hacker's creativity than in the system itself.

Some Nyxt users have already done impressive work. For instance, the extensions and config files exposèd in discourse's Configuration Exposè.

Unfortunately, not all users are that independent and knowledgeable. Thus, this article has a beginner friendly approach. It assumes zero to little knowledge in the Nyxt universe, which involves the Nyxt source code itself, Common Lisp, SBCL, and Emacs. However, it does assume prior knowledge of Nyxt as a Graphical User Interface (GUI) user. Hence, the reader needs to have basic understanding on how to execute commands and navigate using Nyxt.

In case you haven't reached that level, it is easy to catch-up. Start Nyxt, look for the "Tutorial" button on the starting page. Or click on the Execute icon (𝄘) and type "Tutorial". Then, read the tutorial, especially the first half.

This is the first article of a five component series. The debutant writing describes a bookmarklet which is going to be incorporated to the system using the REPL built-in on Nyxt. In the second episode, the same bookmarklet is going to be built but using SBCL straight from the command line. In the third article, again, the same bookmarklet will be added but using Emacs powered with Slime and Vim powered with Vlime. The objective of the first three articles is to isolate some variables and introduce newcommers to the multiple ways and environments available to tweak Nyxt.

In the four article of the series, a command (instead of bookmarklet-command) will be constructed to achieve the same result of the bookmarklet. This version will be more lispy than the previous javascripty ones. And, finally, in the fifth and last article, a mode will be made to achieve the same goal intended in previous articles.

All the five constructions described in the articles will be under the same challenge: hacking YouTube videos so that they can be played at a faster speed than what is allowed by YouTube's GUI.

Why using YouTube as a guinea pig? Well, firstly, because it fulfills the definition of what is a hack:

It's called a hack when you do something in an ugly way. But when you do something so clever that you somehow beat the system, that's also called a hack. – Paul Graham

Secondly, because many new Nyxt users have problems loading videos. This is so common that the Manual has Troubleshooting entry about it. Thus, let's show that it is indeed possible to watch YouTube videos in Nyxt and even hack them. Thirdly, because YouTube is a strong platform and we need more Davids beating up big tech Goliaths from the web. Hopefully, this article shows Nyxt could be a sling! Last but not least, because this was my own very first hack as a Nyxt user :)

Bookmarklets are historical hacks

The funny part about a bookmarklet to hack Youtube is that bookmarklets themselves look like historical hacks. According to Wikipedia, bookmarklets are a bookmark stored in a web browser that contains JavaScript commands adding new features to the browser. Hence, bookmarklets are JavaScripts code stored as either the URL of a bookmark or as a hyperlink on a web page. For this tutorial, the former application is the case.

Regardless of whether bookmarklet utilities are stored as bookmarks or hyperlinks, they add "one-click" functions to a browser or web page. When executed, a bookmarklet performs one of a wide variety of operations, such as running a search query or extracting data from a table. For example, clicking on a bookmarklet after selecting text on a webpage could run a Internet search on the selected text and display a search engine results page.

Time for action

Now, it is time to really start the fun. Follow the instructions below:

  1. Load a YouTube video such as this one. To do that just execute-command, call set-url. Then insert the string "https://www.youtube.com/watch?v=SVteSEjKytw" and press "Enter".

  2. Notice that Youtube's webpage shows possibles speeds of reproduction on the Settings. The playback speeds available are: 0.25, 0.5, 0.75, Normal, 1.25, 1.5, 1.75, and 2.0. The default is Normal.

  3. Open the inspector. To do that execute-command, call open-inspector. Click on the Console button.

  4. Now, insert this code snippet of Javascript in the inspector's Console:

This JS code is a self executing anonymous function that, first, prompts the user for data (a new playback rate) and then uses the answer to set the new playback rate for the video.

  1. Do some tests with numbers. For instance, test inputting the (decimal) number of the beast: 0.666. After pressing enter and playing the video, you will notice the youtuber is speaking slower than usual.

  2. Now, let's get into the real transgression. Let's play videos in a faster speed than the one allowed by YouTube. Thus, try inputting values beyond 2, such as 2.5, 3, or 4. For some videos, 4 is the final threshold due to audio quality. After this value, the sound is muted but the video will be running at faster speeds. In other videos, such as the example we are using, it is possible to use higher values, such as 10x. But, unless you have super powers, it is pretty impossible to understand at this rate.

As you probably realized, you have just hacked YouTube's UI. Now, you have a more granular speed control and you have new upper bound limits.

The Nyxt REPL

Nyxt is a fully computable environment. Thus, it includes a Common Lisp REPL (Read Eval Print Loop) which is a powerful tool behaving as as a "shell language" and the cornerstone of interactive programming.

In the REPL, it is possible to do arithmetic operations such as

Moreover, Nyxt's GUI REPL has all of Nyxt's APIs available for client use. Hence, beyond just doing arithmetic functions, users can also change the name of commands. Or create new ones!

In order to use the Common Lisp REPL with Nyxt's files loaded, press execute-command and choose lisp-repl. Try inserting some arithmetic expressions. And remember that Lisp uses Polish Notation. It feels a bit weird, but it is quite handy because you do not need to repeat operators. For instance, (1+2+3+4+5) in most programming languages becomes (+ 1 2 3 4 5) in polish notation, among other benefits.

For this tutorial, we are going to convert the Javascript code mentioned above into a bookmarklet command. Consequently, we will need a macro called define-bookmarklet-command. This macro receives three arguments: (i) the name of the bookmarklet; (ii) a string with its documentation; and (iii) the Javascript code.

Specifically, this means:

Decomposing what was written, define-bookmarklet-command is a macro being invoked. The first argument is hack-youtube-speed which is the name of our new command. Next, there is a documentation string explaining what the command does. Finally, the Javascript code is passed as a string argument to the macro function call.

It must be highlighted that macros are a powerful and famous part of Lisp languages. But it is a complex topic, since there are whole books only about it. What you need to know is that macros extend the syntax of the Common Lisp language.

Now, the grand finale is inserting this new bookmarlet command in Nyxt. To do that, you need to evaluate the expression in the REPL.

After being evalued, it becomes part of the Lisp image running Nyxt. Consequently, the new command will be listed as one of the options available to be executed. You can find it pressing execute-command and searching for hack-youtube-speed.

Summing up, instead of opening the console, writing the pure 5 lines of Javascript snippet, et cetera, you can just execute the newborn command and choose the preferred speed. Congratulations, you have just extended Nyxt's commands a little bit! :)

Make it persistent across sessions

You learned how to test JS code on the console and wrap it into a new command for Nyxt. However, this new command is not persistent across sessions yet. Therefore, if you close Nyxt and re-open it, you will not find the command created among the options.

In order to fix this, you should insert the new bookmarklet command definition in your init files. Having a file with definitions about your configurations is a common approach in classic text editors Vim and Emacs, great inspirations for Nyxt.

Your Nyxt init file will probably be in a folder like $HOME/.config/nyxt. But you do not need to guess or even find it manually. Nyxt itself is capable of identifying precisely where the file is.

Using the Nyxt REPL again, evaluate the following expression:

> (expand-path *init-file-path*)

In my case, the REPL returns: /home/pedro/.config/nyxt/init.lisp. Your result will be slightly different. Decomposing the s-expression evaluated by the REPL, expand-path is a function being called with *init-file-path* being the argument received by the function. In Common Lisp notation, the use of asterisks embracing words (such as *word*) is a convention to indicate global variables.

After finding the file location, you need to edit it to append the newly created command. You can use whatever editor you want for this action. But, guess what? You can use Nyxt :)

As said before, it is a fully computable environment. Thus, just execute command open-new-editor-with-file, add the bookmarklet command definition discussed before to the file:

Then, save the changes with editor-write-file. Now, close Nyxt and re-start it. Finally, execute command and start typing hack.... Soon, you will find the newly created command. Voialà, your creation is now persistent across sessions! This is possible because every time Nyxt starts, the init file is evaluated with the definitions being incorporated into the Nyxt Lisp image.

Actually, tweaking with the init file is so strongly tied to the Nyxt user experience that there is even a command for this purpose: edit-user-file-with-external-editor. This will open the Nyxt init file using your preferred editor. This information was postponed so that another pratical example of interaction with the REPL could be taught via the evaluation of (expand-path *init-file-path*).

Exceptionally, in case something does not work with edit-user-file-with-external-editor, you can simply open your favorite editor and change the init file.

The next episode

In the next episode of the series, we are going to have a lower level approach, tweaking to do exactly the same but in a different environment, using the command line interface running the SBCL prompt. Stay tunned and may the power of Nyxt be with you!

Disclaimer

There are multiple ways to do certain things in Nyxt and to use certain tools. To make things simple, this will be an opinionated series of articles aiming for beginner friendliness. It is a jungle trail, but you can always go into the wild.

Emacs is a particularly sensitive topic. Currently, most Nyxt hackers end up using Emacs (or Vim). However, Emacs has a steep learning curve. Thus, the series will offer explanations with and without Emacs. For now, if you want to become a serious Nyxt hacker, take Emacs as your main tool. Hopefully, in the future, Nyxt will offer a tailor-made embedded Lisp REPL and editor.