Writing (Greasemonkey) Userscripts to Add a Feature in IMDb.com

Say, hypothetically, you want to watch the best episodes of The Twilight Zone, or perhaps a sitcom like Malcolm in the Middle. The show is episodic, so you’re not missing anything by skipping subpar episodes.

Sorting a season by rating is not a native feature in IMDb.com (surprisingly), so here are the steps you would take to do that using a browser and a notepad:

1- Go to the seasons page on IMDb https://www.imdb.com/title/tt0212671/.
2- Write down ALL episode numbers and user ratings.
3- Sort the episodes by rating.

But as Douglas Adams would say “I am rarely happier than when spending an entire day programming my computer to perform automatically a task that would otherwise take me a good ten seconds to do by hand.” Therefore, I’m going to automate the previous task >:)

One solution is to crawl the data of the pages (using BeautifulSoup or a similar library), but that’s against the terms of use of IMDb. We could get the data from IMDb interface which is provided officially for personal, non-commercial use, but I find this approach time-consuming as we still have to create an application to display the results — an application that practically mirrors the IMDb season page but slightly altered.

Alternatively, we could “hack” the page our browser is currently seeing and add a client-faced button that sorts the episodes for us. And we can do that using a Greasemonkey script.

I already wrote a script that sorts the episodes. It uses pretty straightforward JavaScript to add a button on the page. You have to have the Greasemonkey plugin for Firefox (or a similar alternative like Tampermonkey for Chrome) to install it https://greasyfork.org/en/scripts/418936-imdb-sort-episodes-by-rating

Example of my script’s result!

Greasemonkey is a plugin for Firefox that allows you to run 3rd party scripts. Many of them can be found in https://greasyfork.org. For example, here’s a collection of scripts by various authors to extend the functionality of Youtube.com https://greasyfork.org/en/scripts/by-site/youtube.com. You can find scripts for any website really. Back in the day, I used a lot of scripts on Newgrounds.com to see who’s online, and display hidden stats that were only intended to be seen by the web developers.

Hope that was helpful, hack away!

Game Release: “Nectar Thief A” Arabic Translation

Nectar Thief is a short text-based game made by Loren Schmidt. It’s intended to be a narrative prototype for her upcoming gardening game, “Nectar Thief.”

I’m very honored that I got to translate it to Arabic because I was genuinely a fan of this game before I was contacted by the author! I knew it would be challenging to localize because the whole game is presented in English text, and I don’t know any other Arabic text-based games for reference.

You can play the Arabic translation here:

And you can play the original in English here:

I used Courier as a typeface because it’s monospaced (each character has a fixed width). I believe this makes the typing animation (displaying each character one by one) more comfortable.

Technical Info on the Arabic Localization

Loren had already created a powerful localization script that could grab translated strings from a spreadsheet and switch per-language settings for formatting, making CSS changes, etc. Still, there was some features missing for Arabic so I did some work to get the game presenting perfectly:

1- Displaying the text from right-to-left. Done mostly by setting this tag and fixing anything that breaks:

<html lang="ar" dir="rtl">

2- Transliterating the numbers from Western Arabic numerals (standard in English) to Eastern Arabic numerals (standard in Arabic).
Done by converting the displayed number to a string then replacing the numeral glyphs. You can check out this tiny project that I made Arabic Numberizer which implements the following function:

// Alex Clay. English-to-Arabic number transliterating

// glyphs representing Arabic numerals
var arabicNumbersMap =
function getArabicNumbers(enNum)
	var newStr = "";
	enNum = String(enNum);
        // concat plus/minus sign
	if (enNum[0] == "-" || enNum[0] == "+"){
		newStr += enNum[0];

    for (i = 0; i < enNum.length; i +=1) {

     // parseInt("1") returns 1.
     // This means it will return arabicNumbersMap[1]

     if (arabicNumbersMap[parseInt(enNum.charAt(i))] != undefined) {
			newStr += arabicNumbersMap[parseInt(enNum.charAt(i))];

	return newStr;

3- Adding Arabic keyboard charCodes for input.
English digits have char codes from 48 to 57 (you can check here) but on an Arabic keyboard, the codes go from 1777 to 1785. Similar case for letters.

A duct-tape fix was a matter of adding extra checks for all the variant keyboard charCodes. I think this is acceptable for a free web prototype.

Char codes behave slightly different based on the browser and OS so I made sure the keys work on every mainstream browser, on Windows and Linux, in English and Arabic.

Write Arabic Text in Pico8 – ArSpr

Every variation of every character in the font. 150+ glyphs.

ArSpr is a set of 2 utility functions that let’s you write Arabic text in Pico8. You input a Latin text and it will transliterate it to Arabic. I made it because I want to make localized Pico8 games, and to practice writing my own implementation for Right-to-Left text and Arabic Shaping.

You can get it from the Pico8 forum:

Or you can download the following p8.png cart and import it to Pico8:


Usage is easy, but slightly different from the regular Print() function in Pico8; you have to initialize a variable to contain the text data then draw it. Here’s an example:

function _init()

function _draw()
  draw_ar(text1, [x], [y])
Usage example

The text has 3 colors. One for the letters, one for the dots, and one for the tashkeel. We can easily change colors like this:

function _init()

function _draw()
  ar_col1=[1-16] --letters color
  ar_col2=[1-16] --dots color
  ar_col3=[1-16] --tashkeel color

Changing colors example

[Reading past this point is optional]


This project was inspired by Tiny Text, which uses a similar method to encode a Pico8 font.

ArSpr’s specifications:
2 sprites
510 out of 8192 tokens
~30% of compressed space

No dropped frames when filling the screen


Each character’s height is fixed at 8 pixels max. The width is variable, but most characters are 5 pixels wide including an empty 1 pixel space on the right of Initial and Isolated glyphs.

I decided early that I wasn’t going to do a mono-spaced font because some letters need more space to be legible. Such as ض which is as wide as 2 typical letters when pixelated.


The compressed font is made up of 2 sprites total:

Basically, we draw text on screen by copying and pasting chunk areas from the sprite map.

The glyph on the left can be broken up to create any of the glyphs on the right

The chunk data is encoded in a few long strings as Pico8 doesn’t consider string data in the Token count. Let’s take a look at one of them. This one contains all the tashkeel characters:

_ar_tash = ",^__121__,/__121_6,~_112__1,▥_22111_+__32____,❎_2211__+__221__1+__321___,🐱_2211__,ˇ_2211y_+__2211__,⬇️_2211_6,✽_2211y6+__2211_6"

The string _ar_tash has the crop and draw locations for every drawn chunk. Each character in the string is converted to a letter or number. The format is “[character], [character advance], [sprite X pos], [sprite Y pos], [sprite width], [sprite height], [draw offset X], [draw offset Y], [end chunk or add a new chunk to same character]” (every bracket in the list is a single character. Underscore equals zero or null.)

Let’s take an example:


That translates to “The letter ✽ will advance the line 0 pixels. It has a chunk at (x=2,y=2), size (1,1), drawn at offset (-2, 6) and another chunk (2, 2), size (1, 1), drawn at offset (0, 6).”

Arabic Shaping

Letters have 4 glyph variations (initial, medial, final, isolated). Arabic Shaping is when we pick the needed glyph based on A) the position of the letter in the word and B) the “Joining Type” of letter.

In the alphabet, there are 2 Joining Types: 1- Some letters can connect to the previous and following letter and we call them Dual-Joining. They have all 4 glyph variations (initial, medial, final, isolated), such as ب
ببب ب – بـ ـبـ ـب ب

2- Other letters can only join the previous letter and we call them Previous-Joining. They have 2 glyph variations (final, isolated), such as د
ددد بدددد – ـد د

Full list of Arabic letters split into the 2 groups.

Other characters, such as (space, numbers, punctuation), do not join with letters and so only have a single, isolated glyph.

Tashkeels (diacritics) are completely ignored by the Arabic Shaper and they have zero width so they could be drawn in the same position as a letter. They only have a single glyph each.

My Arabic Shaping implementation is a simple case-switch (pseudo code):

function _get_font(previousChar,currentChar,nextChar)
	if currentChar is tashkeel
            return _ar_tashkeel_glyph

	elseif currentChar is (space, number, punctuation)
	     return _ar_nonletter_glyph
	elseif previousChar is any except dual-joining letter
	and currentChar is dual-joining letter
	and nextChar is any except (space, number, punctuation)
	     return _ar_init_glyph
	elseif previousChar is dual-joining
	and currentChar is dual-joining
	and nextChar is any except (space, number, punctuation)
	     return _ar_medial_glyph
	elseif previousChar is dual-joining 
	and currentChar is dual-joining
	and nextChar is (space, number, punctuation)
	     return _ar_final_glyph
	elseif previousChar is dual-joining letter
	and currentChar is previous-joining letter
	     return _ar_final_glyph
        -- all previous checks failed.
	     return _ar_isolated_glyph

For a different implementation of Arabic Shaping you can check out MiniBidi by Ahmad Khalifa.

Possible Improvements

  • We can eliminate duplicate chunk data in the strings by letting characters reference common chunks.
  • We can try using caaz’s sprite compression technique.
  • In an earlier version, I had one function called printAr(str,x,y) that didn’t need to initialize strings by caching string after being drawn for the first time. It was neat to have everything in one function! But I removed it to save tokens. It would be nice to bring it back…