Package: armstrong.apps.embeds
Armstrong.Apps.Embeds provides a data model and modular backend system to
extract embeddable content and metadata from external URLs. Representing
embeddable content in a database brings the typical benefits of relational
data. Programmable backends allow more flexible use of the content beyond
the one-trick pony of the standard “<iframe>” copy-paste embed code.Integrating AppsEmbeds into your site will require some work. Mostly because
this package doesn’t make assumptions forhowyou’ll be using these
external URLs. Maybe you just want to track references to embedded content,
maybe it’s the caching that’s interesting or programmatically accessing
content provider metadata is what you are after. There’s nothing extra to get
in your way, but you’ll have to customize code and/or templates.This is a stand alone component; itdoes notrequire any other pieces of the
Armstrong family. However, it does play nicely withArmLayout. If you use
ArmLayout already, AppsEmbeds is ready to go. Much of the power of AppsEmbeds
comes from templating so if you use that feature and aren’t already using
ArmLayout, it’s worth considering.The second optional package islxml, which is necessary if you use theresize_iframetemplate filter. Otherwise, this package has three fixed
requirements to provide model fields and support the backend APIs (currently
just Embedly). Seepackage.jsonfor these fixed requirements.FeaturesSingle embed, multiple relationships!Always know where you are using
external content and the number of references you have.Metadata!Access the metadata of the external content. Much more useful
than the vanilla iframe embed code.Modular backends!Get metadata and embed codes with a standard
interface to the various content provider APIs.Customizable templates!Presentation is separate from data. Make that
external content look appropriate for your site.Single embed, multiple uses!Create templates for each use case. A video
can be used as a title, thumbnail, captioned credit, in a gallery, etc.Uniform visual appearance!Each content type shares templates. Video
content can be presented in a standard format regardless of the source.Automatic backend assignment!Program an Embed in one step.
The URL is all we need.Admin preview!Examine the response data before saving. Look weird?
Switch backends and preview again.Response caching!Worry less about third-party API failure. The
response is cached indefinitely.Check for new data!See if new data is available without committing
to it, right from the Admin.Bird’s eye overview!Aggregate information on how and what types of
external content you generally use.Installation & ConfigurationSupports Django 1.3, 1.4, 1.5, 1.6, 1.7 on Python 2.6 and 2.7.
(Though if you are using Django 1.3, make sure to use django-model-utils<1.4.)pip install armstrong.apps.embeds[optional]pip install lxmlif you plan on using theresize_iframetemplate filter[optional]pip install armstrong.core.arm_layoutif you want to use
ArmLayout to render templatesAddarmstrong.apps.embedsto yourINSTALLED_APPSInstall the database schemaDjango 1.7+ usemanage.py migrateprevious Djangos use eithermanage.py syncdbormanage.py migrateif you are usingSouth(in which case use South 1.0+)Load the provided Backends into your database. (This is not provided as
initial fixture data so that you may edit them without worrying that
syncdb will restore the initial versions.)manage.py loaddata embed_backends.jsonIf you are using the Embedly backend, add your API key tosettings.pyEMBEDLY_KEY = 'your key'Logging:This component emits logging statements using thearmstrong.apps.embedslogger.UsageA quick overview of the four models–EmbedTypeandProviderdo essentially nothing besides normalize the
database and provide a quick way to perform aggregation queries. EmbedType is
based on the fouroEmbedtypes, though in practice you’ll likely have a
fiftherrortype (and that’s okay).Backendis the front-end model for the actual code that connects to
third-party APIs to retrieve response data for the external content URLs.
It’s easiest to initially load them from the fixture data file but feel free
to customize them as you will. Just don’t change theslug, which is how
the model maps to its code back-end.regexandpriorityare designed
to change. That’s how you’ll customize the auto-assignment behavior. The
Embedly backend will handle YouTube sure, but say you’ve written a more
targeted YouTube-specific backend–add it to the database with a selective
regex and a higher priority.Embedis the cornerstone. Creating a new embed object only requires aurl. The backend will auto-assign by regular expression matching the URL
and selecting from the matching backends by highest priority. Auto-assignment
is just a nice feature for faster Embed creation. You can also manually assign
a backend on object creation or later. Every other field on the model is
backend-provided metadata. Consider them read-only. So how do you get a
response? How do you get actual information?The Response object–embed_obj.update_response()will retrieve a response from the backend and
assign it if the response isvalidanddifferent, then returnTrue. If
the response is invalid or the same, no assignment is made andFalseis
returned. If you want the response object itself, useembed_obj.get_response().embed_obj.responseis the way to access the response data. This will be a
subclass of theBaseResponseobject with a standard set of attributes.is_valid()will be False in cases where the API had a problem, didn’t
return data, 404’d, etc.is_fresh()will be True when the response is
fresh off the wire. It’s used to differentiate from database cached response
data and you can probably ignore it.typeandproviderareEmbedTypeandProvidermodel objects._dataholds the actual raw
response in JSON. The goal is to never directly access this. Instead, the
BaseResponse class is subclassed by each backend/API and tailored to parse the
raw data into standardized attributes. This way who cares if it’s YouTube or
Vimeo, access the object the same and share the templates. These attributes
return an empty string when nothing is available and are thereforetemplate safe. The current data attributes are:titleauthor_nameauthor_urlimage_urlimage_heightimage_widthrenderrenderis perhaps the most important; it is the full expression of the
embedded content that the content provider offers. For Twitter, this is the
blockquote with JavaScript widget that dynamically loads the tweet into an
iframe. For YouTube and Vimeo, this is the video player. Whatever way the
service designs its content to be embedded, this is it.image_xxxmeans different things depending on the content. For a video,
this will be the still image that shows before the video is played. For
SlideShare, it’s the first slide in the presentation. For Flickr, it’s the
thumbnail. It’s worth noting that we have no idea what the image size will
be and so if you use this in a template, consider fixing the image tag’s
dimensions with attributes or CSS.Backends–Embedlyis a sort of meta-embed service. They know how to handle over 250
content providers to deliver a standardized set of metadata. Specifically this
backend uses their “Embed” service via theirembedly-pythonlibrary. It
offers a huge benefit but does require an account. Fortunately there is a quite
reasonable free tier. Configuration required to use this is mentioned under the
Installation section.Twitteris a simple wrapper for a tag that loads the tweet via Twitter’s
JavaScript widget. It does not perform any API or network calls and therefore
does not provide any metadata about the URL. The only thing it can do is embed
the Tweet as if you’d copy-pasted the embed code.Defaultjust regurgitates the provided URL. It’s the catch-all that does
nothing useful.Templates–Assuming you want to display the embed content on your site, this is where
you’ll spend the most developer time. It’s not just about what a photo looks
like versus a video. Now that you have access to more than just the “embed
code”–now that you have metadata–you can use the same embed multiple ways.
For example, a photo can be used as a preview thumbnail with a small image,
a larger image with a title for lead art, a thumbnail in a story that expands
into a modal full-size version with attribution. Whatever you want. Since
Response objects have a standard interface, it doesn’t even matter where that
photo came from. Instagram and TwitPic behave the same.Note: This concept of provider apathy hinges on theEmbedType. We can only
treat like types the same or fall back to something generic for all embeds.
If the provider or the backend reports a Flickr URL as a “link” type, even
though we know in our hearts it’s a “photo”, it won’t use the photo-specific
templates.Now for some examples. SinceArmLayoutwas designed for this purpose, we’ll
use it. It provides arender_modeltemplate tag that takes an object and a
template name then looks in a hierarchy from most-specific to least for that
template. ArmLayout usesget_layout_template_name()for the lookup and
AppsEmbeds has extended it to also look for type-specific templates.render_model embed_obj 'full'for aphototype will look in this order:layout/embeds/embedtype/photo/full.htmllayout/embeds/embed/full.htmlSo to display an Embed object as “preview”, just make the following files.
Each content type can customize what “preview” means. (Maybe a small
thumbnail or truncated intro text.)layout/embeds/embedtype/photo/preview.htmllayout/embeds/embedtype/video/preview.htmllayout/embeds/embedtype/link/preview.htmllayout/embeds/embedtype/rich/preview.htmllayout/embeds/embed/preview.html“Lead art” could be another way of displaying an embed. (Perhaps a larger
image along with title and author attribution.)layout/embeds/embedtype/photo/lead_art.htmllayout/embeds/embedtype/video/lead_art.htmllayout/embeds/embedtype/link/lead_art.htmllayout/embeds/embedtype/rich/lead_art.htmllayout/embeds/embed/lead_art.htmlLeave out a type-specific template file and ArmLayout will use the more
general file next in the hierarchy.There’s also adefault.htmltemplate used as a fallback when the response
is invalid or missing. (This template name can be customized viaembed_obj.fallback_template_name.) Without a response, there won’t be any
data to show in the normal/intended template. A fallback can provide more
helpful output and a visual reference that something isn’t right.Template tags/filters (requires lxml)–resize_iframeis a template filter that caps the width of iframes since
embedding an unexpectedly huge iframe into your layout might break the
appearance. It only shrinks large iframes; it doesn’t alter iframes that are
already the specified size (or smaller).Common usage:{{ object.response.render|resize_iframe:645|safe }}In this example, if therenderattribute contains code with iframes and
the width of any or all of those iframes is larger than 645px, the iframes’
width will be changed to 645 and the height will scale smaller accordingly.LimitationsContent provider terms of service–The service you are embedding content from may have usage guidelines and
restrictions. Pay attention and follow these. It may be against their terms
of service to rework or restyle the presentation or to use only pieces of the
metadata. Changing or reusing things may also be disrespectful and disingenuous
to the content creator. Respect the creator and respect the service.Publishing content–Embedded content is already published; it’s available from some other site.
It’s how we use and integrate that external content into our own works that
matters here. Armstrong is a platform for newsrooms and content publishers.
The typical situation is one where reporters and editors write, draft, proof
and publish. Content has eyes on it and doesn’t get published until it’s
finished. AppsEmbeds is just the same. A general assumption is that some
human is looking at the embed–maybe not the raw response data–but certainly
the end result of how it looks (i.e. how a template renders it). If it looks
wrong, it doesn’t get published.It’s likely that someday you’ll come across a content provider whose responses
don’t fit the expected form. It’s hard to account for these things but
hopefully someone is looking at the content and will notice.Custom API queries–Many APIs provide customization for the responses they provide. They may allow
you to specify maxwidth and maxheight, alignments for text or localization,
callbacks, transparency modes or word length truncation. AppsEmbeds doesn’t
do any of that primarily because it can’t make those assumptions. AppsEmbeds
gets you the raw data in its default form whatever that may be and follows
the “customize after” approach.resize_iframeis an example of this. You may want a 200px iframe for a
preview and an 800px iframe within an article body for thesameembedded
content. It wouldn’t do to set a maxwidth=200 on the API call, cache that
and then be stuck for the larger size use case.Ultimately, API use can be a finicky thing. The best course of action within
the AppsEmbeds paradigm is to customize or create a backend and/or response
class fitting the API you use and the parameters you may want to query with.
Have a better idea or an awesome backend? Please make a Pull Request!Different URLs to the same content–There is currently no way to know if multiple URLs refer to the same content.
These two YouTube links will make two separate Embed objects:https://www.youtube.com/watch?v=12345
https://www.youtube.com/watch?v=12345&feature=player_embeddedContributingDevelopment occurs on Github. Participation is welcome!Found a bug? File it onGithub Issues. Include as much detail as you
can and make sure to list the specific component since we use a centralized,
project-wide issue tracker.Testing?pip install toxand runtoxHave code to submit? Fork the repo, consolidate your changes on a topic
branch and create apull request. Thearmstrong.devpackage provides
tools for testing, coverage and South migration as well as making it very
easy to run a full Django environment with this component’s settings.Questions, need help, discussion? Use ourGoogle Groupmailing list.State of ProjectArmstrongis an open-source news platform that is freely available to any
organization. It is the result of a collaboration between theTexas TribuneandThe Center for Investigative Reportingand a grant from theJohn S. and James L. Knight Foundation. Armstrong is available as a
complete bundle and as individual, stand-alone components.