How we used Nokogiri to fix a sizing issue in YouTube's oEmbed
At some point, one of our calls to YouTube's oEmbed endpoint was returning videos way too small; we fixed in in our Rails application by using Nokogiri
On one project, we allow people to add certain types of media to their articles. To do this, we use oEmbed implementations supplied by Facebook, YouTube, etc.
With oEmbed, you make a call to an endpoint supported by the target service. With YouTube, for example, we make a call to https://www.youtube.com/oembed?url=#{url}&format=json
, and it will return a JSON object that describes the content.
One bit of information returned is the HTML you need to display the object. When we first implemented everything, the HTML returned used a suitable size for our use case, so we thought nothing of it and shipped the feature.
At some point, YouTube changed the default size of their video to the smallest version they support, which is way too small for our needs.
With oEmbed, you can specify the max size you want back, but not a minimum size. Unfortunately, this means the solution isn’t as easy as asking for a larger video to be returned.
Enter Nokogiri
Nokogiri is a Ruby tool for working with XML and HTML.
In our code we were doing something like;
self.html = json.html
This would take the HTML given to us by the JSON object and assign it to our model that stores all the embed information.
Using Nokogiri to manipulate the HTML took fewer lines of code than I expected;
doc = Nokogiri::HTML::DocumentFragment.parse(json.html)
iframe = doc.at_css 'iframe'
iframe['height'] = '360'
iframe['width'] = '640'
self.html = doc.to_html
First, we create a doc
which appears to be a common variable name used when dealing with document objects created by Nokogiri.
Nokogiri::HTML::DocumentFragmant
is the class we want in this case because it is HTML, and it isn’t a complete HTML page, just a selection of HTML.
The parse
method accepts a string and converts it into a Nokogiri document object.
YouTube does everything within an iframe
. By calling doc.at_css 'iframe'
we use a CSS selector of “iframe” to get the element we care about.
The following two lines manipulate the attributes held against that object, namely width
and height
.
Finally, we need to turn our Nokogiri document object back into HTML; we do that with doc.to_html
.
A simplified version of our HTML might have started like this;
<iframe width='50' height='50' src='blah'>
After passing through Nokogiri, it will look identical bar the attribute changes we made;
<iframe width='640' height='360' src='blah'>
This method is not without issue. If YouTube changes how they deliver videos, then this code could break, and we’d need to revisit it. For our use case, we decided this is an acceptable trade-off.