YouTube, like any reasonable video service, offers closed captioning. They'll even throw machine learning at the problem, and autogenerate captions, though that is usually only good for comedy, rather than actual accesibility.
Any closed captioning system will generally let you specify the colors of the captions as well as the actual text. YouTube is no exception to that. YouTube offers an online editor, but anyone serious about producing content is going to upload their own subtitle files, and up until recently, this could be done in an XML file which would allowed a lot of control over the styling of the captions.
But XML isn't cool, so YouTube rolled out a new JSON format. Which broke everything. Specifically, instead of being able to set any hex triplet as your color, you could only set a relative handful, and any "invalid" triple would just turn to white.
For some reason, whatever the user inputs isn't propogated to this as a hex triplet, like #FF0000
, but instead as a hex value- 0xFF0000
, or 16711680
, in decimal. I'm not sure if that's on the "filling out the JSON" side, or if it's a conversion which happens elsewhere, but regardless: the front end needs to map a value like 16711680
to #FF0000
. Well, a value like that, but not exactly that value, as we'll see.
An anonymous submitter already trawled through the minified code and found the code block responsible, which they've helpfully de-minified for us:
var colorMap = new Map([
[0xFFF, "#fff"],
[0xFF0, "#ff0"],
[0x0F0, "#0f0"],
[0x0FF, "#0ff"],
[0x00F, "#00f"],
[0xF0F, "#f0f"],
[0xF00, "#f00"],
[0x080808, "#080808"]
]);
if (jsonPen.fcForeColor)
pen.color = colorMap.get(jsonPen.fcForeColor) || "#fff";
Original, unminifed version. In that version, I want to note that the hex values were expanded into decimal: new Map([[4095,"#fff"],[4080,"#ff0"],[240,"#0f0"],[255,"#0ff"],[15,"#00f"],[3855,"#f0f"],[3840,"#f00"],[526344,"#080808"]]
.
Setting aside the "I know, let's break a feature that worked fine," this… is wrong. You can set red, for example, but not by doing 0xFF0000
- you must instead do 0xF00
. If you send 0x000F00
, expecting a dark green color, you'll get red.
And if the rule were "hey, we only support a single hex digit per color channel," you could document that and move on. But it doesn't: we can see that 0x080808
is valid. That's nearly black, which it's worth noting that actually black isn't in the whitelist of colors, and worse: it wouldn't even check to see if black (0
) is in there, because if (jsonPen.fcForeColor)
is falsy. We won't even change the color if you try and set the color to black! Don't worry, elsewhere in the code it still defaults back to being white.
This code is, at the time of this writing, disabled. It went live, briefly, last week, breaking a bunch of closed captioned videos in ugly ways. I have no idea what the final version of this will look like- maybe exactly like this, but with clearer documentation?- but it is an ugly way to solve a problem which is already well solved.