Using YouTube API to embed videos dinamically on your web site

It is easy to embed a given YouTube video on a web site, simply use the wizard to get code required code, but what about to do the some automatically using JavaScript? Yes, suppose you have a preferred user you follow all his videos and would like to put his/her latest video in your web site.

Every YouTube video has a unique identifier so the challenge is how to get the id if the latest uploaded (or updated if you prefer) video.

Searching for videos

YouTube has a very rich API and you have lot of parameters available to use, but, probably most important are the ways to search. Mainly you have two options to search videos for a given user:

  • Search video feeds:
    http://gdata.youtube.com/feeds/api/videos?author=SOME_USER&more_parameters
  • Search videos uploaded for specific user:
    https://gdata.youtube.com/feeds/api/users/USERNAME/uploads?more_parameters

First way is more flexible than second, because you can use lot of parameters to chose and author, limit results number, order by, etc, while the second is like setting the author parameter in the first one.

IMPORTANT !!! Read careful the YouTube API documentacion, concretely the sentence:

Requests using other parameters, such as orderby, will return cached results.

That makes me (on other folks) spent lot of time trying to find way searched doesn't get really updated results.

The requests

What will be our test request? Yeah !!! We are going to check for the lastest video of the user... ironmaiden !!!

We want to get maximum one videos from ironmaiden user and ordered by date of publication. In addition, we want the response be in JSON format (not in XML) so we use the 'alt' parameter too:

http://gdata.youtube.com/feeds/api/videos?author=ironmaiden&max-results=1&orderby=published&v=2&alt=jsonc

https://gdata.youtube.com/feeds/api/users/ironmaiden/uploads?max-results=1&orderby=published&v=2&alt=jsonc

The response

By default, the returning data is specified in XML format (see here) but with the help of alt=jsonc parameter it is returned in JSON notation (see here). For the previous first request the response is:

{
    "apiVersion":"2.1",
    "data":{
        "updated":"2011-10-31T19:24:09.441Z",
        "totalItems":14,
        "startIndex":1,
        "itemsPerPage":1,
        "items":[{
            "id":"O9f1bBeYpqA",
            "uploaded":"2011-10-19T13:07:28.000Z",
            "updated":"2011-10-31T16:57:34.000Z",
            "uploader":"ironmaiden",
            "category":"Music",
            "title":"IMTV London",
            "description":"A quick IMTV from the O2. The full IMTV UK episode will be available to fanclub members soon!",
            "tags":["iron","maiden","imtv","on","board","flight","666","Iron Maiden","United Kingdom","Metal"],
            "thumbnail":{
                "sqDefault":"http://i.ytimg.com/vi/O9f1bBeYpqA/default.jpg",
                "hqDefault":"http://i.ytimg.com/vi/O9f1bBeYpqA/hqdefault.jpg"
            },
            "player":{
                "default":"http://www.youtube.com/watch?v=O9f1bBeYpqA&feature=youtube_gdata_player",
                "mobile":"http://m.youtube.com/details?v=O9f1bBeYpqA"
            },
            "content":{
                "5":"http://www.youtube.com/v/O9f1bBeYpqA?version=3&f=videos&app=youtube_gdata",
                "1":"rtsp://v3.cache5.c.youtube.com/CiILENy73wIaGQmgppgXbPXXOxMYDSANFEgGUgZ2aWRlb3MM/0/0/0/video.3gp",
                "6":"rtsp://v2.cache8.c.youtube.com/CiILENy73wIaGQmgppgXbPXXOxMYESARFEgGUgZ2aWRlb3MM/0/0/0/video.3gp"
            },
            "duration":316,
            "aspectRatio":"widescreen",
            "rating":4.9898734,
            "likeCount":"394",
            "ratingCount":395,
            "viewCount":47086,
            "favoriteCount":110,
            "commentCount":105,
            "accessControl":{
                "comment":"allowed",
                "commentVote":"allowed",
                "videoRespond":"moderated",
                "rate":"allowed",
                "embed":"allowed",
                "list":"allowed",
                "autoPlay":"allowed",
                "syndicate":"allowed"
            }
        }]
    }

As you can see the ID of the video is at:

data.items[0].id

Embeding a video

Embeding a video by hand is easy, you simply click on "share" button, then on "embed", copy and paste the code and that's all:

But hey !!! We are bad boys, worst if it is possible, we are programmers and we live to programming, so we are going to do the same than any other mortal but programming, so program once run forever !!! (mmm... that slogan sounds me like a island name programming language).

The intention is to make the code necessary to get the latest video identifier and inject the code to embed video on page, like this:

<iframe width="420" height="315" src="http://www.youtube.com/embed/PieS0zG228A"
frameborder="0" allowfullscreen></iframe>

Automatically embedding the latest video

Finally arrive to the most interesting section. As you can imagine we can do it in the AJAX way, making an asynchronous request and injecting the code but in addition I will put a more "static" way to do, thanks to the callback parameter in the request.

The AJAX way

First, create div elements to contain the video frame and a button to start the loading process:

<div id="ajax_video"></div>
<button id="ajaxbutton">AJAX way</button>

In the head section of the document Ihave added the required JavaScript code (I'm using jQuery to do it):

<script type="text/javascript">
    $(document).ready(function(){
        $('#ajaxbutton').click(function(event){
            $.get('https://gdata.youtube.com/feeds/api/users/ironmaiden/uploads?max-results=1&orderby=published&v=2&alt=jsonc',
            function(response) {
                if(response.data && response.data.items) {
                    var items = response.data.items;
                    if(items.length>0) {
                        var item = items[0];
                        var videoid = "http://www.youtube.com/embed/"+item.id;
                        console.log("Latest ID: '"+videoid+"'");
                        var video = "<iframe width='420' height='315' src='"+videoid+"' frameborder='0' allowfullscreen></iframe>";
                        $('#ajax_video').html(video);
                    }
                }
            });
        });
    });
</script>

As we mention, the request get the latest video from ironmaiden user, creates an iframe element containing it and add it to the previously created div element.

Using callback parameter

This version differs from previous one because the request is made when page is loaded. What I'm saying? Exactly this, the request is made including JavaScript code:

<script type="text/javascript" src="https://gdata.youtube.com/feeds/api/users/ironmaiden/uploads?max-results=1&orderby=published&v=2&alt=jsonc&callback=showVideo"></script>

The url includes the callback parameter which is responsible to call the specified function once the code is loaded.

Putting it all together, in the same way that previous case you need a div element that contains the video iframe and a JavaScript code to add the iframe from the response:

<div id="static_video"></div>
<script type="text/javascript">
    function showVideo(response) {
        if(response.data && response.data.items) {
            var items = response.data.items;
            if(items.length>0) {
                var item = items[0];
                var videoid = "http://www.youtube.com/embed/"+item.id;
                console.log("Latest ID: '"+videoid+"'");
                var video = "<iframe width='420' height='315' src='"+videoid+"' frameborder='0' allowfullscreen></iframe>";
                $('#static_video').html(video);
            }
        }
    }
</script>
<script type="text/javascript" src="https://gdata.youtube.com/feeds/api/users/ironmaiden/uploads?max-results=1&orderby=published&v=2&alt=jsonc&callback=showVideo"></script>

The browser load the elements in the order it encounters, so it is important to put the code in the right place so browser finds first the 'showVideo' function before loading the YouTube code request.

Demo

You can see a demo working here.

References

http://code.google.com/apis/youtube/2.0/reference.html#Searching_for_videos

http://code.google.com/apis/youtube/2.0/developers_guide_protocol.html#Retrieving_and_searching_for_videos

http://code.google.com/apis/youtube/2.0/developers_guide_json.html

»
Author's profile picture acanimal

Sending emails with Java

I start writing this post as a simple "how to send an email" using Java, but later I found I need to briefly explain more things. So, here is this kind of all in one summary about sending emails with Java.

Outside the Java SE platform, but included in JavaEE one, the JavaMail package provides a platform to build mail and messaging applications. Lets go with an example.

Sending a simple text message

// Common variables
String host = "your_smtp_server";
String from = "from_address";
String to = "to_address";

// Set properties
Properties props = new Properties();
props.put("mail.smtp.host", host);
props.put("mail.debug", "true");

// Get session
Session session = Session.getInstance(props);

try {
    // Instantiate a message
    Message msg = new MimeMessage(session);

    // Set the FROM message
    msg.setFrom(new InternetAddress(from));

    // The recipients can be more than one so we use an array but you can
    // use 'new InternetAddress(to)' for only one address.
    InternetAddress[] address = {new InternetAddress(to)};
    msg.setRecipients(Message.RecipientType.TO, address);

    // Set the message subject and date we sent it.
    msg.setSubject("Email from JavaMail test");
    msg.setSentDate(new Date());

    // Set message content
    msg.setText("This is the text for this simple demo using JavaMail.");

    // Send the message
    Transport.send(msg);
}
catch (MessagingException mex) {
    mex.printStackTrace();
}

Alternatively, instead using:

msg.setText("This is the text for this simple demo using JavaMail.");

you can use next to set the message content:

msg.setContent("This is the text for this simple demo using JavaMail.", "text/plain");

Checking an email address

Here is a little trick to check, using a regular expression, if an email address is well formed:

Pattern rfc2822 = Pattern.compile("^[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$");
if(rfc2822.matcher(EMAIL_ADDRESS).matches()) {
    // Well formed email
}

Multipart messages

That's fine, but usually you don't send simple text messages. Instead you send nice HTML body messages with bold or italic text, images, and so on.

NOTE: See below at references section to see about MIME format which extends the data you can attach to an email to allow multiparts, attachments, etc.

When you write a multipart message the content is composed of different parts, for example one part is the message written as simple text and a second part with the same message written in an enhanced way using HTML. Then the client that reads the message is responsible to render the appropriate part depending on its capabilities.

...
...
// Here create two parts and set as message contect
// Create and fill first part
MimeBodyPart part1 = new MimeBodyPart();
part1.setText("This is part one of this multipart message.");

// Create and fill second part
MimeBodyPart part2 = new MimeBodyPart();
part2.setText("This is part two of this multipart message.");

// Create the Multipart.
Multipart mp = new MimeMultipart();
mp.addBodyPart(part1);
mp.addBodyPart(part2);

// Set the message's content
msg.setContent(mp);
...
...

 

Sending attachments

Terrific, we know how to send a plain text email and something more incredible like a multipart message with HTML content. Next step is to send an email attaching too some files.

Create an email with attached file is similar to create a multipart message where one part can be the text of the message and another part is the attached file. The secret is in the next lines:

...
...
// Create a new part for the attached file
MimeBodyPart part3 = new MimeBodyPart();

// Put a file in the second part
FileDataSource fds = new FileDataSource("THE_FILE_NAME");
part3.setDataHandler(new DataHandler(fds));
part3.setFileName(fds.getName());

// 'mp' is the previously created 'MimeMultipart' object
mp.addBodyPart(part3);

// 'msg' is the previously created 'Message' object
msg.setContent(mp);
...
...

 

HTML messages

Create a message o multipart message with HTML content is really easy, simply specify the MIME type in the setContent method:

...
...
MimeBodyPart htmlPart = new MimeBodyPart();
htmlPart.setContent("<h1>Sample</h1><p>This is a sample HTML part</p>", "text/html");
...
...

Attaching images within the HTML code

If you write a rich message using HTML you can, of course, add images using the 'img' tag. If the image is referenced from an external server there is no problem, but: how to attach an image to the message and render within the HTML message body?

The idea is as follow:

  • first you need to attach the image file and set an identifier and
  • second you need to write your HTML code and reference the image identifier in the 'img' tag.
...
...
// Create and fill html part
MimeBodyPart htmlPart = new MimeBodyPart();
htmlPart.setContent("<h1>Sample</h1><p>This is a sample HTML part with an attached image</p>" +
	"<img src='cid:some_image_id'>", "text/html");

// Create a new part for the attached image and set the CID image identifier
MimeBodyPart imagePart = new MimeBodyPart();
FileDataSource fds = new FileDataSource("THE_IMAGE_FILE_NAME");
imagePart.setDataHandler(new DataHandler(fds));
imagePart.setHeader("Content-ID", "some_image_id");

mp.addBodyPart(htmlPart);
mp.addBodyPart(imagePart);
...
..

Anything more to say?

Arrived to this point you are almost a master of sending emails. You know how to send simple emails, multipart emails with richest HTML content and attach files and images on your message.

What more can a programmer desire?

Probably, a more easy to use API and that is what Apache Commons Email project offer you. See the 'user guide' section http://commons.apache.org/email/userguide.html to understand what I say. It offers a more abstract API more close to humans than to protocols.

References

JavaMail - JavaMail project home page.

Apache Commons Email - Apache Commons subproject to simplify the way to work with JavaMail API. See the 'user guide' section http://commons.apache.org/email/userguide.html.

MIME (Multipurpose Internet Mail Extensions) - Description of MIME format for multipart emails.

»
Author's profile picture acanimal

Clinker, a software development ecosystem

Recently I discovered Clinker, a so called Software Development Ecosystem.

Mysteriously there is no definition for Development Ecosystem on Wikipedia yet but a close definition could be:

»
Author's profile picture acanimal

Crop image on the client side with JCrop and HTML5 canvas element

Suppose you are working on a nice web application where the user can upload images to, for example, a shop catalogue (mmm... that makes me think on something :p ) but wait... you don't the catalogue uses the whole image you upload instead a piece of it. So, we need to crop the image.

»
Author's profile picture acanimal

A word about LESS

Woow!!! That is the word that best defines Less.

From time to time someone creates something really useful with a touch of magic. John Resig creates jQuery, not the only one neither the first one, but it is the most famous JavaScript library.

»
Author's profile picture acanimal

Customizing jQuery UI Dialog: hiding close button and changing opacity

Sometimes when you are programming small things are the hard things, little details becomes difficult to solve and you need to spend lot of time to solve them. This is logically :) because you spent the major part of your time thinking and designing the big or complex things, leaving in a second plane the small things and because this they became the new "big" things. Ok, stop talking with buggy sentences and talk about this post. Recently I was working in a web page using jQuery UI dialogs that have a couple of special requirements that takes me some time and because this I want to share here with you:

»
Author's profile picture acanimal

Local storage: Storing sticky notes on your machine with HTML5

Every history has a beginning and for this post it starts when some time ago I saw this good post from tutorialzine.com. Really I love the tutorials at tutorialzine.com, they are great quality examples to learn.

Looking for similar things, it seems I was not the first trying to do something similar :) http://rqru.com/sticky. but what I wanted too was to learn a bit more about HTML5 features, concretely about local storage.

»
Author's profile picture acanimal

A geek joke

It makes me smile:

A man walks into a Doctor’s and says “Doctor, I think I’m addicted to Twitter.”

Doctor looks at him and says “Sorry, I don’t follow you.”

@opencontent - David Wiley

»
Author's profile picture acanimal

Generating map tiles without a map server. GeoTools the GIS swissknife.

Recently I was playing with latest version of GeoServer. It includes the GeoWebCache, something which can improve your server performance greatly. GeoServer solves and helps lots of problems to work and visualize geospatial data but as you know map servers lakes from scalability.

Because this GeoWebCache is a great tool. Basically, each map request is processed and the result image is stored to be directly returned on subsequent requests. The processed images are stored as a pyramid of tiles depending on the bounding box or zoom level of the request.

Another way to solve scalability problems is directly pre-generate the pyramid of tiles, something that makes Google, Bing, Yahoo, OpenStreetMaps, etc.

What I need?

I have a lightnings database with thousands of lightnings for a period of some months. I need to show lightnings in my maps but only those corresponding to a period or interval of time. For example, render the lightnings from 00:00h to 00:30h and allow the user to go forward or backward in time.

One important thing is I only need an "image" with the information in that period. I don't need to render each lightning as a feature in the map -this will degrade the performance rendering in a storm with thousands of lightnings per period.

The problem

So why don't use GeoServer+GeoWebCache for this? I can configure a layer pointing to my lightning database, make requests and rest assured subsequent call will get the previously created map.

The problem is at this moment -while I write this post- GeoServer lakes from TIME support in requests. That means if I define a layer from my lightnings table on DB, every GeoServer request will work against all data while I only need a subset of my data -determined by an interval- to be rendered in the requested maps.

Adopted solution

Ok, be quiet. GeoServer is build on top of GeoTools, an open source Java library which provides standards compliant methods for the manipulation of geospatial data and, more important, GeoTools library implements Open Geospatial Consortium (OGC) specifications as they are developed.

With all this the solution seems easy: code a program to query the desired period of lightning data and generate a pyramid of tiles (for the desired levels).

 A brief description of the implementation

Next is a brief summary of things to do, or take into account, to generate your own pyramid of tiles programmatically with Geotools.

All the lightnings information is stored on a PostgreSQL/PostGIS table called 'lightnings'. Data related with a lightning are: date (the UTC instant in which the lightning occurs, represented as a long number in Unix time), position (latitude/longitude/altitude), value and sign (the electric charge).

Set the DataSource connection

GeoTools tries to simplify thing and because this it tries to abstracts as much as possible. Features can be provided from many source: files (shapefiles, GML, ...) or a database (PostgreSQL/PostGIS, Oracle, ...).

The first step then is to set a DataSource instance pointing to our database:

Map<String, Object> params = new HashMap<String, Object>();
params.put(PostgisNGDataStoreFactory.DBTYPE.key, dbconn.getType());
params.put(PostgisNGDataStoreFactory.HOST.key, dbconn.getHost());
params.put(PostgisNGDataStoreFactory.PORT.key, dbconn.getPort());
params.put(PostgisNGDataStoreFactory.SCHEMA.key, "public");
params.put(PostgisNGDataStoreFactory.DATABASE.key, dbconn.getDatabase());
params.put(PostgisNGDataStoreFactory.USER.key, dbconn.getUser());
params.put(PostgisNGDataStoreFactory.PASSWD.key, dbconn.getPassword());
params.put(PostgisNGDataStoreFactory.EXPOSE_PK.key, true);

// Get lightning store
DataStore dataStore = DataStoreFinder.getDataStore(params);
SimpleFeatureSource sfs = dataStore.getFeatureSource("lightnings");

Note: 'dbconn' is an object which stores my DB connection parameters.

Filtering data

We don't want to get all the lightnings in the database but only those withing a period of tim, so what we need is to filter the data using Filter classes. Given a period of time represented by values 'long start_date' and 'long end_date' we can define the desired filter as:

FilterFactory2 filterFactory = CommonFactoryFinder.getFilterFactory2(null);
// Create filter for specified initial and end dates
Filter filterStart = filterFactory.greaterOrEqual(filterFactory.property("date"), filterFactory.literal(start_date));
Filter filterEnd = filterFactory.less(filterFactory.property("date"), filterFactory.literal(end_date));
Filter filterTime = filterFactory.and(filterStart, filterEnd);

Create styles before rendering for features

There are some ways to create styles for our features. One is to use a SLD document and the other is doing programmatically.

In my case, I chose to use the second form so here is a bit of cumbersome code (I ommited the try/catch section) which create the desired style to identify positive and negative lightnings.

// Create style
StyleBuilder styleBuilder = new StyleBuilder();
StyleFactory styleFactory = styleBuilder.getStyleFactory();
FilterFactory2 filterFactory = styleBuilder.getFilterFactory();

// Style for Positivos
Graphic grP = styleFactory.createDefaultGraphic();
Mark markP = styleFactory.getCircleMark();
markP.setStroke(styleFactory.createStroke(filterFactory.literal(Color.BLUE), filterFactory.literal(1)));
markP.setFill(styleFactory.createFill(filterFactory.literal(Color.CYAN)));
grP.graphicalSymbols().clear();
grP.graphicalSymbols().add(markP);
grP.setSize(filterFactory.literal(5));

// Style for Negativos
Graphic grN = styleFactory.createDefaultGraphic();
Mark markN = styleFactory.getCircleMark();
markN.setStroke(styleFactory.createStroke(filterFactory.literal(Color.RED), filterFactory.literal(1)));
markN.setFill(styleFactory.createFill(filterFactory.literal(Color.ORANGE)));
grN.graphicalSymbols().clear();
grN.graphicalSymbols().add(markN);
grN.setSize(filterFactory.literal(5));

Filter filterPositiveValor = ff.and(filter, CQL.toFilter("value >= 0"));
Filter filterNegativeValor = ff.and(filter, CQL.toFilter("value < 0"));

// Create symbols and rules to render every feature
PointSymbolizer symPositivos = styleFactory.createPointSymbolizer(grP, null);
PointSymbolizer symNegativos = styleFactory.createPointSymbolizer(grN, null);

Rule ruleP = styleFactory.createRule();
ruleP.symbolizers().add(symPositivos);
ruleP.setFilter(filterPositiveValor);
FeatureTypeStyle ftsP = styleFactory.createFeatureTypeStyle(new Rule[]{ruleP});

Rule ruleN = styleFactory.createRule();
ruleN.symbolizers().add(symNegativos);
ruleN.setFilter(filterNegativeValor);
FeatureTypeStyle ftsN = styleFactory.createFeatureTypeStyle(new Rule[]{ruleN});

// Finally create out style
Style style = styleFactory.createStyle();
style.featureTypeStyles().add(ftsP);
style.featureTypeStyles().add(ftsN);

Create the map and render to a file

The map creating is straightforward:

MapContext map = new DefaultMapContext();
CoordinateReferenceSystem crs = CRS.decode("EPSG:3785");
map.setCoordinateReferenceSystem(crs);

and then render it to a file. I will paste here the code on the GTRenderer tutorial. You can play a bit with the code and change some values: area of interest, size of the output image, etc.

public void saveImage(final MapContent map, final String file, final int imageWidth) {

    GTRenderer renderer = new StreamingRenderer();
    renderer.setMapContent(map);

    Rectangle imageBounds = null;
    ReferencedEnvelope mapBounds = null;
    try {
        mapBounds = map.getMaxBounds();
        double heightToWidth = mapBounds.getSpan(1) / mapBounds.getSpan(0);
        imageBounds = new Rectangle(
                0, 0, imageWidth, (int) Math.round(imageWidth * heightToWidth));

    } catch (Exception e) {
        // failed to access map layers
        throw new RuntimeException(e);
    }

    BufferedImage image = new BufferedImage(imageBounds.width, imageBounds.height, BufferedImage.TYPE_INT_RGB);

    Graphics2D gr = image.createGraphics();
    gr.setPaint(Color.WHITE);
    gr.fill(imageBounds);

    try {
        renderer.paint(gr, imageBounds, mapBounds);
        File fileToSave = new File(file);
        ImageIO.write(image, "jpeg", fileToSave);

    } catch (IOException e) {
        throw new RuntimeException(e);
    }
}

Conclusions

Every tool is designed and built with a goal in mind, because this normally the use of a map server is always the proper selection. But sometimes you have specific needs that general tools doesn't solve and here is when open source project like GeoTools can help you.

I would to note that programing this way the image generation is much more faster than use of GeoServer because we are avoiding lots of intermediate steps a map server does: get request, parse, check and validate parameters and once query is executed, image composed it must be returned to the client via HTTP protocol.

References

http://docs.geotools.org

http://docs.geotools.org/latest/userguide/library/render/gtrenderer.html

http://docs.geotools.org/stable/tutorials/filter/query.html

 

»
Author's profile picture acanimal

A heatmaps layer for OpenLayers

As I commented on a previous post I know about heatmaps.js project some time ago and interest me a lot by its possibilities with OpenLayers. Of course it is not the only solution, see here and here but it has a great performance.

»
Author's profile picture acanimal