Sunday, 1 October 2017

Cinema Time API

Continuing on from the earlier success of my dashboard API's to date: Twitter, National Rail Enquiries as well as a google finance integration and a home made Burton Albion score API. Now, on request from Louise I have looked to display all the films and film times for the local cinema.

I did a quick google of "Cinema API" and came up with something called "moviesapi" which you can find here: http://moviesapi.herokuapp.com which is a screen scraping API for https://www.findanyfilm.com which is a website that lets film fans find how to download, watch, buy and rent films - all above the board may I add.

The API itself is a non authenticated, JSON returning API that appears to have no rate limit (or so far as I can tell). It's quite a simple idea, there are two GET API's, find a nearby cinema and list films from a specific cinema using the id we can get from the nearby cinema API. 

In curl we can do "curl -X GET "http://moviesapi.herokuapp.com/cinemas/find/SO23"" (my nearby area)
which returns the following data (I've cut it down for readability):
[{"venue_id":"7144","name":"VUE Eastleigh, Eastleigh","address":"VUE Eastleigh, Swan Centre, Wells Place, Eastleigh, Eastleigh, SO50 5SF","url":"https://www.myvue.com/cinema/eastleigh?SC_CMP=AFF_indtrust","distance":""}]
We can then use this "venue_id" to get the selected cinemas film list for all times on the same day. The same day part is a significant restriction, but works for a dashboard that only wants to show this reduced information.

In curl we can do "curl -X GET "http://moviesapi.herokuapp.com/cinemas/7144/showings"" which returns the following film data (I've cut it down again for readability):
[{"title":"The Emoji Movie","link":"","time":["10:00","12:15","13:20","15:10"]},{"title":"The Nut Job 2: Nutty By Nature","link":"","time":["10:00","11:45"]}]
For the purpose of displaying the full information for the selected cinema I have created a server side http request using the request node module (npm). My code looks like a getFilmTimes function which is itself a promise, I create the request options and which has a url and a method, send the the request and then resolve the parsed JSON body.
function getFilmTimes(venueId) {
return new Promise(function (resolve, reject) {
var postOptions = {
url: 'http://moviesapi.herokuapp.com/cinemas/' + venueId + '/showings',
method: 'GET'
};
request(postOptions, function cb(err, res, body) {
if (err) {
log.dashErr(JSON.stringify(err))
reject();
}
if (res.statusCode === 200) {
resolve(JSON.parse(body));
}
});
});
}
I want to get all the information as a single string (html formatted) so that I can push it to the browser and display on new lines each film and all the times associated to it.

To do this, I want to cycle through the results and add them to a string variable using the "async" node module (npm), it will also mean cycling the film times to add them to the end of the derived strings. See the code below:
var films = JSON.parse(body);
var sendFilms = "";
async.eachSeries(films, function cycleThroughFilms(currentFilm, filmCallback) {
var filmTimes = currentFilm.time;
sendFilms = sendFilms + currentFilm.title + ": ";
async.eachSeries(filmTimes, function cycleThroughTimes(currentTime, currentTimeCallback) {
sendFilms = sendFilms + currentTime + " ";
currentTimeCallback();
}, function afterTimesDone() {
sendFilms = sendFilms + "<br>";
});
filmCallback();
}, function afterFilmsProcessed(err) {
resolve(sendFilms);
});
The above code takes an array "films" and cycles through each set of results. We add first the film title to our global "sendFilms" variable before cycling the times array within the film array. This cycles "filmTimes" which is the current films times array and adds the current time to the global variable. When we have cycled through the film times we add a "<br>" html break line tag and then continue to the next film using callbacks available.

Upon completion of all the films within the array I resolve the promise and send the string on - eventually to the browser.

This worked well but was displaying film times that had already passed so to fix this we can add a little function to get the current time and compare the times as we process them to see if they have already started.
...
async.eachSeries(filmTimes, function cycleThroughTimes(currentTime, currentTimeCallback) {
var timenow = new Date().toISOString().substr(11, 5);
if (currentTime > timenow) {
sendFilms = sendFilms + currentTime + " ";
}
currentTimeCallback();
}, function afterTimesDone() {
...
With that we're all done:
The last thought is that we could remove the films that have no more showings for the day. But I personally like to see what might be available the next day throughout the day. I'll see how it feels.

Any questions? Anything you would change/improve upon. Give me an email on aiden.g@live.co.uk or leave a comment. 


No comments:

Post a Comment