You might remember Txty Jukebox, our free to use collaborative music web app that we built on top of the YouTube Data API. We were happy to find that our original version was well received and even got some press from the folks over at makeuseof.com. Well, we’ve finally got a chance to spend some time ( big thanks to our new hire Josh who led the charge ) to make improvements based on the feedback we received and re-branded it under jointdj.com!
The main idea behind our music inspired web application is to create an easy way for groups of people to collaboratively share and listen to song (and video) requests. Any user with a smart phone or computer can enter the event code provided by the event’s host on jointdj.com and start submitting songs to the event’s playlist. The “event” doesn’t always have to be a traditional party either, for example, we’ve been using Joint DJ ourselves in our office as a Pandora or Spotify replacement.
- One big lesson learned from our first go around with Txty Jukebox was that while it’s great when everyone at your event is engaged and the song queue is filled up you can run into awkward silences if the playlist runs of songs when people get distracted, say, doing work or playing an intense game of flip cup. In the past you had to wait until someone queued another song so it became a bit of a chore for the event host. To solve this issue and ensure there will never be a silent moment, we’ve created a new feature that lets the event host to pick a genre of music when they create an event from which a song will be randomly selected and played if a playlist ever runs out. For example, I could create an event with “Top 40 / Pop” as the auto fill genre. If at any point during my event the playlist is empty, all the sudden the latest Chainsmokerz song will magically be queued up!
- Another issue we saw in the first version was that sometimes users didn’t get the exact song played that they were searching for. That was because we automatically selected the first result from Youtube regardless of whether it’s the desired result. For Joint DJ, we’ve added the ability for users to use an intuitive browser based UI to easily search for a song and then review the list of music video results from YouTube along with the thumbnail. Once the user finds exactly what song they want to play they can simply select it to add it to the event’s playlist.
- Lastly, we improved the design of the live player view where events users can watch and listen to the music videos associated with the requests. You’ll see “flash” messages when songs are added that show the artist, title and which “DJ” submitted it. Additionally we show the next 4-5 upcoming songs in the queue along with their thumbnails on the left side of the player window. Overall, the new look is more colorful and crisp and should be more impressive to the events users keeping them engaged, having fun, and contributing songs to the event. Below is a screenshot of what the live player view looks like:
- PhantomJS (for this tutorial we’ll be using Linux for this particular example) http://phantomjs.org/download.html
1. Create the PhantomJS Script
The first step is to create a script that will be executed by PhantomJS. This script will do the following:
- Take in a JSON “configuration” object with the site URL and a CSS selector of the HTML element that contains the target data
- Load up the page based on the Site URL from the JSON configuration object
- Include jQuery on the page (so we can use it even if the target site doesn’t have it!)
- Use jQuery and CSS selector from configuration object to find and alert the html of the target element. You’ll notice on line 37 that we wrap the target element in a paragraph tag then traverse to it in order to pull the entire table html.
- We can save this file as ‘phantomJsBlogExample.js’
- One thing to note is that on line 24 below we set a timeout inside the evaluate function to allow for the page to fully load before we call the pullHtmlString function. To learn more about the ins and outs of PhantomJS functions read here http://phantomjs.org/documentation/
2. Create PHP function to run PhantomJS script and convert output into a SimpleXmlElement Object
Next, we want to create a PHP function that actually executes the above script and converts the html to a SimpleXmlElement object.
- On line 3 below you’ll construct a “configuration” object that we’ll pass into the PhantomJS script above that will contain the site url and CSS selector
- Next on line 10 we’ll actually read in the base PhantomJs Script we created in step 1. Notice that we actually make a copy of the script so that we leave the base script intact. This becomes important if you are executing this multiple times in production using different site urls each time.
- On line 20 we prepend the configuration object onto the copied version of the phantomJS script, make sure you json_encode this so it’s inserted as a proper json object.
- Next on line 29 we execute the phantomJs script using the PHP exec function and save the output into an $output array. Each time the PhantomJS script alerts a string, it’s added as an element in this array. Alerted html strings will split out as one line per element in the array. After we get the output from the script we can go ahead and delete the copied version of the script.
- Starting on line 38, we clean up the $output array a bit, for example when we initially inject jQuery in PhantomJS a line is alerted into the output array which we do not want as it doesn’t represent the actual html data we are scraping. Similarly, want to remove the last element of the $output array where we alert (‘EXIT’) to end the script.
- Now that it’s cleaned up, we have an array of individual html strings representing our target data. We’ll want to remove the whitespace and also join all the elements into one big html string to use for constructing a SimpleXmlElement on line 49.
3. Call the function and iterate through the SimpleXmlElement Object to get to the table data
- Call the function from step 2 making sure to pass in the target site url and CSS selector
- Now that we have the SimpleXmlObject on line 7 we’ll want to iterate through the rows of the table body and pull out the state name and population table cells. It may help to var_dump the entire SimpleXmlObject to get a sense for what the structure looks like.
- For purposes of this example we’ll just echo out the state name and population but you could really do anything you wanted with the data at this point (i.e., persist to database etc.)
4. Final Output
Finally, running the function from step 3 should result in something like this.
Because sometimes it’s just fun to make something absurd: http://taken.setfive.com/.
If you aren’t familiar, the Taken movie series (http://www.imdb.com/title/tt0936501/) is a set of ridiculous action dramas that have acquired a strong cult following over the years (deservedly or not). All of the movies basically involve someone close to a retired CIA agent, played by Liam Neeson, being “Taken” and Neeson subsequently raining hell over anyone involved in wronging him. As a result of the movie series, Liam Neeson has made a formidable run at Kiefer Sutherland’s title of today’s Chuck Norris. Neeson, who plays the main character in the movie employs his signature throat punch in place of Norris’ roundhouse kick.
Our team seems to share a fondness for laughable action movies and actually took the afternoon off to watch the latest Taken 3 film when it debuted a couple weeks ago. With a little bit of vacation downtime prior to the debut and the urge to develop a web application as preposterous as the film series, we came up with the idea of creating Taken Audio MadLibs (http://taken.setfive.com/). For those of you not familiar MadLibs (http://en.wikipedia.org/wiki/Mad_Libs) is a phrasal template word game where one player prompts others for a list of words to substitute for blanks in a story, before reading the – often comical or nonsensical – story aloud.
So our take on the MadLibs program works something like this:
-There are four different “story lines” which all involve dialog between Liam Neesons character and a second character
-Neesons lines are actual lines from the Taken movies
-The other character’s lines are transformed into audio clips by Google’s unofficial Text To Speech (TTS) API and are based on the words you enter into a simple webform
-The lines are combined together into a hilarious back and forth dialog between Neeson and your character
Technically, there really isn’t too much “magic” going on with the program. It’s built on the Symfony2 framework and employs a simple one page parallax scrolling design for the web forms. Once the user submits the web form for their story we send it off to the controller where the user entered words are inserted into a set of templated lines. These text lines are then sent off to the Google TTS API which returns an .mp3 audio file with the audio representation of the text. We then splice together the Google TTS mp3 lines with the Taken audio files that we have stored on the server and combine into one audio file. The audio file is returned to the UI in the form of a HTML5 audio tag where the user can play or download the file. We also provide the user with the option of emailing the audio file to a friend if they would like to.
There were two problems that we ran into worth mentioning for those of you playing around with Google’s TTS api or combining multiple audio files of different formats.
1. Google’s TTS API only accepts 100 characters per call so you’ll have to split a given line or sentence into 100 character chunks and then combine the multiple mp3s back into one. This isn’t too difficult to do but worth mentioning if you ever plan to play around with this API.
2. We did run into a bit of trouble trying to combine the .mp3 files that Google returned with the Taken audio .mp3 files we got from (http://www.soundboard.com/sb/Taken_sound_clips). The problem is that the frame rate of the Google .mp3 files is different than the Taken files so when we tried to combine them into one some audio players would not render the resulting file. To get around these issues we took the following steps the combine and massage the audio files via a couple different server-side Linux-based Audio programs (avconv and oggCat):
- combine the “chunked” Google .mp3s into one .ogg representing a single line in the dialog: “avconv -i [mp3_input_file] -acodec libvorbis -q:a 5 [ogg_output_file]”
- convert the Taken “line” .mp3 files to individual .ogg files: “avconv -i [mp3_input_file] -acodec libvorbis -q:a 5 [ogg_output_file]”
- combine the final Google “line” .ogg files with the Taken “line” .ogg files: “oggCat [ogg_output_file] [ogg_input_file_1] [ogg_input_file_2] [ogg_input_file_3] ….”
- convert the final .ogg file to .wav so all browser types will play nice (shakes fist at safari): “avconv -i [ogg_input_file] [wav_output_file]”
Anyways, if you haven’t checked out the final program yet it can be seen here http://taken.setfive.com/ and if you have any questions, comments, or feedback feel free to leave them below.
Posted In: Tips n' Tricks
We’d like to extend congratulations to one of our clients, SoonSpoon, on being acquired by Reserve, a New York-based restaurant reservations application. Led by one of the co-founders of Uber, Reserve aims to simplify the restaurant reservation process much like Uber did for the taxi industry. You can read more about them in this recent Boston Globe article.
With Priceline recently purchasing OpenTable for a cool $2.5 billion, the online reservation space seems to be gaining momentum and piling up more success stories. Although we’re sad to see them go, we are excited for the SoonSpoon guys and are glad to have helped them build out their beta product (you may have remembered our blog post from their launch).
SoonSpoon had a great idea and relentlessly executed on it, building a strong community of partner restaurants and users. In the day in age where many try but few succeed it’s always inspiring to see a start-up success story – as Michael Dell once put it, “Ideas are commodity. Execution of them is not.”
Looking for a way to preview online display ads and automatically save a screenshot/grab/capture?
Based on conversations we’ve had with one of our consulting clients, Datapoint Media, who are very familiar with the online advertising industry, it became quickly apparent that there really isn’t a good automated solution currently out there. When a buyer asks for “proofs” of their banner ads on the main sites that they will appear in, Ad Operations personnel are faced with two less than thrilling (and quite time intensive) options:
- Grab screenshots of the sites that the client would like to preview and download the standalone display ad images the client is buying. Then open up Photoshop or other photo editor and copy and paste those ad images over the existing banner ads on the screenshot of the target websites.
- Wait until the campaign is in flight and hope to catch lightning in a bottle by loading up the website the ad is likely to rotate into, refreshing the page continuously until the ads the clients bought appear, and finally taking a screenshot of the site.
Imagine having to do this every day week in and week out for hundreds of client orders.
Given the strong demand for a tool and a lack of automated solutions, we worked with Datapoint Media to build a tool as part of their existing Audience Extension platform .
Here’s how the Banner Ad preview tool works:
- Simple web based UI allows users to enter a website URL for which they’d like to preview the ads on. Once selected, the website is displayed in an iframe “preview window” to allow the user to get the lay of the land and see the current ad layout of the website.
- Users can choose from 3 options on how they want to input the banner ad/creative images they want to display on the selected site. The 3 options are:
- At this point, users submit the preview request. If they chose the Ad Server ID entry method, the Ad Servers API is pinged for a listing of all the associated creative images. After that, users select which creatives they want to include in the screenshot.
- The request is placed in a queue to be automatically processed. Next, users are presented with a confirmation that they will receive an email with the screenshot file attached within a few minutes. No need for any more work to be done by humans, it’s time for the robots to do the heavy lifting.
- Behind the scenes the tool loads up an “invisible” browser window on the server which points to the target website. Next it executes a series of commands to inspect the website determining where the valid ad slots are located. Once the slots are defined, it matches up the open slots with the dimensions of the banner ads that the user has selected. If the dimensions match, it replaces the existing ads on the website with the user entered banner ads and takes a screenshot.
- The resulting screenshot file is saved on the application server and automatically emailed to the user.
If you have any questions or are interested in gaining access to the tool, feel free to contact the guys over at http://www.datapointmedia.com.
Posted In: General