Bob Belderbos | Software Developer

Certified Advanced Java

Success is the result of perfection, hard work, learning from failure, loyalty, and persistence. - Colin Powell

Java Advanced certificate


I did it :)

Just before O’Reilly School of Technology (OST) closes, I managed to get certified in Advanced Java, more details here (java5 and -6).

I am pretty happy and proud of this achievement. The two modules were known to be the most complex ones the school had to offer and some exercises were a real struggle, but hey … that’s how you learn, right? I got some good practice in distributed app development and algorithms (30 coding projects).

I copied the (already publicly available) course PDFs to my certifications page if interested.

For those interested in algorithms:

  • The author of the algorithms part of this certificate has a good video course where he goes over a lot of the same material using Python.
  • Coursera just kicked off Algorithms, part I (Princeton).

If you liked this post, you can share it with your followers or follow me on Twitter!

Migrating my blog to Jekyll

Jekyll is a static site generator, an open-source tool for creating simple yet powerful websites of all shapes and sizes. From the readme:

Jekyll is a simple, blog aware, static site generator. It takes a template directory […] and spits out a complete, static website suitable for serving with Apache or your favorite web server. This is also the engine behind GitHub Pages, which you can use to host your project’s page or blog right here from GitHub.

Hello, Jekyll

Here are some links and notes from the migration I am doing from Wordpress to Jekyll:

  1. get started: very good post which starts with the poole base theme.

  2. you need to install some dependencies and I needed to changes to _config.yml to get it running locally, see here

  3. import posts from WP, see here and Stackoverflow - how awesome:

     $ ruby -rubygems -e 'require "jekyll-import"; \
       JekyllImport::Importers::WordpressDotCom.run({ \ 
       "source" => "bobbelderbos.wordpress.2016-01-27.xml" } )'
     Downloading images for Chrome for web development
       http://bobbelderbos.com/wp-content/uploads/2010/03/...
         OK!
     ..
     ..
     Downloading images for How to programatically get a youtube movie trailer
     ..
         OK!
     Imported 151 posts
    
  4. permalinks: easily configurable here
  5. considering changing the Poole them to the nice two-column Hyde theme
  6. write posts in markdown? Not a problem
  7. I will update after having used Jekyll for some time …

If you liked this post, you can share it with your followers or follow me on Twitter!

How to programatically get a youtube movie trailer

youtube_trailer_themoviedb

I really liked Youtube's Gdata API, I had it all working nicely. As you can see from that post I had a nice popup overlay on Sharemovi.es with the movie trailer video embedded. Till it broke ... Gdata is gone. So needed to fix it ...

Alternative

Turns out that you can get the trailer via themoviedb API. See here: you need themoviedb's movieID and call the /videos method. When testing it gave me 5 trailers. I will show you the PHP code I use to query the API and how to convert the youtube to HMTL you can embed into your page. I use the Jquery boxy plugin for the overlay (see printscreen at the bottom).

Code

 $ more trailer.php 
<?php
if (!isset($_GET["id"])){
  echo "Please call with movie ID";
  return;
}
include 'libs/functions.php';
$id = $_GET["id"];
if(!is_numeric($id)){
  echo "Need numeric ID";
  return;
}
// Gdata died, themoviedb is your friend though
// https://www.themoviedb.org/talk/5451ec02c3a3680245005e3c
$res = queryApi3("movie", $id, "videos");
//print_r($res); -- stdClass Object notation
$youtubeId = $res->results[0]->key; // monitor if first trailer is always OK enough
echo getTrailerSnippet($youtubeId, '640', '385', 1, 1);                                                                                                                  
?>

Below the functions I use. Essentially you need to curl this URL: http://api.themoviedb.org/3/movie/<movieID>/videos?api_key=<YOUR_API_KEY> and json_decode the results. The function args make it more generic so you can use it for other API calls too (as I do for my movie site).

$ more libs/functions
..
..
function queryApi3($category, $id, $method) {
  // query and lang optional, only needed for search
  $key = getKey();
  $query = "http://api.themoviedb.org/3"; 
  if($category != '') $query .= "/$category"; 
  if($id != '') $query .= "/$id";
  if($method != '') $query .= "/$method"; 
  $query .= "?api_key=$key";
  // use curl, not file_get_contents
  // http://stackoverflow.com/questions/555523/file-get-contents-vs-curl-what-has-better-performance
  $results = useCurl($query);
  return json_decode($results);
}
..
..
function useCurl($url) {  
  $ch = curl_init();
  curl_setopt($ch, CURLOPT_URL, $url);
  curl_setopt($ch, CURLOPT_HEADER, 0);
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
  curl_setopt($ch, CURLOPT_FAILONERROR, 1);
  $results = curl_exec($ch);
  $headers = curl_getinfo($ch);
  $error_number = curl_errno($ch);
  $error_message = curl_error($ch);
  curl_close($ch);
  return $results;
}
..
..
function getTrailerSnippet($youtubeId, $width, $height) {
  if( $youtubeId ) {
    echo "<iframe class='youtube-player' type='text/html' width='$width' height='$height' src='http://www.youtube.com/embed/$youtubeId?autoplay=1' frameborder='0'>";               
  } else {
    echo "No Trailer found";
  }
}

 


On the main page I have a link to this script with a GET variable called "id" that receives the movieID. The class "boxy" is required to make the Jquery boxy overlay work.

echo "<a href='trailer.php?id=$movieId' class='boxy trailerOverlay' title='Trailer of ".str_replace("'","",$dataMovie['title'])."'><img src='i/youtube.png'></a>";


Result

And we're good again:

http://sharemovi.es/movie/206647-spectre

I. see red trailer button

Screen Shot 2015-11-20 at 23.24.14

II. when clicked:

Screen Shot 2015-11-20 at 23.41.04

Better alternative for PHP sleep: use a dotted progress bar with Javascript

Last week I developed a playing/upcoming movie HTML newsletter. I just added a feature to add the movies to your watch list on sharemovi.es. You have to be authenticated to FB. If not I am redirecting from the adder script to the main page:

Screen Shot 2015-11-19 at 22.33.35

The problem with PHP sleep

This taught me a cool trick: you need to pause a bit so the user can read the message before being redirected. My first approach was PHP's sleep function, but that would show the initial echo only after the sleep, rendering it useless.

javascript_dotted_progress_barThen I read about ob_start() and ob_flush(). This did not work either, reason: browsers also contain their own buffers. I realized that apart from sleeping I wanted to show some sort of progress bar.

Here we enter JavaScript which is great for this kind of asynchronous stuff. I used this solution. As explained at w3schools: "the setInterval() method calls a function or evaluates an expression at specified intervals (in milliseconds). The setInterval() method will continue calling the function until clearInterval() is called".

Code:

    <script>
    var div = document.getElementById('wait');
    var counter = 0;
    var waitSecs = 8;
    var refreshId = setInterval(function () {
      ++counter;
      div.innerHTML = div.innerHTML + '&#x25cf;'
      if(counter == waitSecs){
        clearInterval(refreshId);
        top.location.href='http://sharemovi.es'
      }
    }, 1000);
    </script>

Notes:

  • See a demo of this script here.
  • I put an empty #wait div in the html and get it with document.getElementById, this element is used to append progress elements to.
  • I choose dots for progress, but I probably redo it with a count down which is more cooler, I choose a bigger dot = html encoding: &#x25cf;
  • setInterval does something for every interval (here 1 sec = 1000 ms), until waitSecs = 8 seconds, then it stops the loop by calling clearInterval and redirects to the sharemovi.es homepage (top.location.href).
  • An enhancement could be to redirect to FB login page directly but it could surprise users, hence the feedback loop.

Screen Shot 2015-11-19 at 22.33.39


Two more comments:

1. to learn to code: practice, fail, get better by doing, it takes time and effort. This is a small feature, but it taught me a few valuable things about PHP and Javascript. Follow Alec Baldwin's ABC: always be closing and replace closing by coding :)

2. the featured image for this and last 2 posts were made with a new webtool I built: CSS Featured Image Creator. I will write a blog post about it soon, it is still work in progress ...

Project: playing/upcoming weekly movie email (themoviedb API)

Hi again, some more coding today. My original attempt at this broke some time ago, because themoviedb's page HTML changed. Lesson learned: rather use an API.

So I rewrote this script, improving it and adding some cool new features. Check out the code/readme on github.


Usage

main.py [options]
Options:
  -h, --help            show this help message and exit
  -a ACTOR, --actor=ACTOR
                        filter on actor (not yet implemented)
  -c CATEGORY, --category=CATEGORY
                        category [now_playing, upcoming, top_rated, popular]
  -d DIRECTOR, --director=DIRECTOR
                        filter on director (not yet implemented)
  -g GENRES, --genres=GENRES
                        filter on genres (not yet implemented)
  -l LISTING, --listing=LISTING
                        create email from themoviedb list URL
  -m, --mailres         mail the html to recipients
  -n NUMRES, --numres=NUMRES
                        number of results
  -p, --printres        print the html

 


To use it yourself:

  1. create a flat text file called 'key' with your themoviedb API key;
  2. create a flat text file called 'recipients' with one or more emails (each one on a new line);
  3. use a cron job to call the script to send one or more notification alerts, I use the weekly.py script for this (note I also added a customized banner, if you don't want it modify generate_header in output.py).


Some things I picked up:

Apart from the end result - a rich html email with new movie details -it's nice to see what you can learn from this kind of project:

  • for any data mining, use the API if available, relying on HTML is trickier. Themoviedb has a great API I already used for my sharemovi.es site, for this exercise I used the friendly tmdbsimple Python wrapper.
  • instead of a text file or DB, I use the Python shelve for caching. I store movie IDs and movie details (info and credits = cast) as a key,value pairs. So data for each movie ID is downloaded once, then re-used for priting, mailing, etc. weekly movie emailAlso, storing objects is a pretty flex solution, you can load them from the shelve and call methods on them).  See cache.py for its implementation. I used the shelve recently for the Safari new books project too (see here)
  • use several classes (files) to decouple the design (cache, mail, output generation, movie objects, handle movie lists). The code was easy to extend, for example to work with customized (themoviedb) lists. I only had to write some code to crawl the list page (tmdbsimple does not support lists), the subsequent actions of shelving, printing and emailing worked out of the box, passing a list of movie IDs.
  • optparse / OptionParser makes CLI switch handling very easy and compact, I use it all the time.
  • I learned how to Python email using bcc and how to exclude mails and API key from the code putting them in files and ignore them from version control with .gitignore, pretty important.
  • probably a couple of things more ... comment if you like to know more ...

Example mails

I. weekly

sharemovi.es-movie-alert

II. of a customized list (hacker movies)

Screen Shot 2015-11-15 at 22.54.06


Update 19.11.2015


 

You can now add movies from the newsletter to your sharemovi.es watchlist when FB logged in - see the small link at the "Released" line, alongside the IMDB link:

Screen Shot 2015-11-19 at 22.08.54