Yet another day, yet another post about stuff going wrong. This time, I’ve got a bug report that “videos are jumping around” on Facebook and some other pages. I tried to verify the problem … and everything worked fine for me. Then I decided to boot up Windows and there it was — the problem as described. So nice — we have a problem that happens on some operating systems and doesn’t on others, even though that shouldn’t be the case in theory.
But eventually, the issue was reproduced and that’s all that matters. The issue appears very familiar — it has been observed on reddit before.
A video and a player
In a very ELI5 way, every webpage is made out of a bunch of rectangles (layers, elements), one within another. In order to properly crop a video, we must know which of these elements is actually the player (‘player’ element is to our video what picture frame is to a picture), and we need to know which element is the player element. Picking the wrong element can result in extension cropping to little, too much, or moving the video out of the picture altogether.
We can’t just assume that the first element above the video is a player, either: sometimes sites put addiitonal elements between the two. This is why we need ‘guess’ the player element by looking at the size.
Side note: not all extensions use that approach. Some seem to just assume you use a 21:9 monitor and slap a ‘enlarge this element by 1.3’ on the video element. Great and foolproof strategy for fullscreen. Less great for youtube’s theater mode, twitch with chat opened at the side, or non-fullscreen Netflix.
Legacy and technical debt
The code for determining which element is the player element has some weird quirks thanks to the history of the addon. Most notably, the extension used to work by determining how tall and how wide the video should be back in the day when it was only focused on Youtube and Netflix. This method has a few drawbacks, with most notable ones being:
- If you ask browser to tell you the size of the video, it’ll tell you the dimensions you specified
- It worked for youtube and netflix, but not for everything else
In general, we can assume that initial size of the player will be exactly as wide as the video or exactly as tall as the video. However, since we actually changed the size of the video (as opposed to telling browser to just enlarge the video by some factor), we couldn’t check for that as if the video was cropped, browser would tell us the post-crop size (and post-crop size is useless for that purpose). Some wonky code was written to deal with this issue and it worked well enough for Youtube and Netflix and sometimes even other sites. However, said code is — in retrospect — pretty bad. Looking at it invokes a few questions that every programmer sometimes asks themselves: “the hell was I trying to do with this shit” and “how the fuck did this even work at all?”
Due to problems with #2, a better solution to resizing the video needed to be implemented, and eventually it was in the form of
transform: scale(x,y). Using this to crop video (as opposed to modifying width and height attributes of the video) has some nifty advantages: it’s possible to get the size of the video without taking
transform into account. This allows us to rewrite the player detect loop in a way that will correctly detect the player element.
Dealing with duplicates
Another thing worth addressing is “duplicates” — that is, what happens when more than one element on our way from video element to the root of the page has the same size. I haven’t figured out what to do in this case, since the correctness of picking innermost over outermost element for player may differ from site to site. In absence of better options, I decided to score every element that could be our player. Rules of the game:
- Every element that matches our criteria gets 100 base points
- Elements with
'player'in their ID get 75 bonus points
- Elements with
'player'in their classlist get 50 bonus points
- The farther the element is from our video, the more penalty points it gets. First match gets 0 penalty points, second gets one, third gets two and so on.
I haven’t had the chance to test this thoroughly, so results may vary.
That’s it for the day.