Searchable Audio Player Using Laravel

Taking a page from a recent project, we will walk through creating a Laravel application sporting an updatable audio player with search function.

(This is an advanced tutorial and requires deftness with web technologies.)

The idea is a modern (responsive & mobile friendly) audio player for a growing audio base which benefits from searching. The data is pulled from a database rather than the static JSON object used by Tipue Search.

In this example we are using sermon audio. Users can enter a book of the bible or preacher’s name etc. and come up with a set of results. Each search result contains a link (the sermon title) which changes the audio file for the player.

Project

For the purposes of testing i’ve included a complete project on Github.

I won’t post code for entire files since I’ve posted the project. But here we’ll discuss some major points in the architecture.

You will need a database configured to use with the project. Once you have established the connection with the project you will need a table with some data.

In the root folder of the project, find and run the SQL file to get started:

create_table_insert_data.sql

There are some pre-requisites if you are building from scratch. I built this project using Laravel 5.6

  1. PHP 7+
  2. Carbon 1.25.0 ( composer require nesbot/carbon:1.25.0 )
  3. Tipue Search
  4. Howler.js

Search

Tipue Search is designed as a site search which benefits from the celerity JQuery lends it. A javascript object contains the information for the website’s various pages that will be searched. Our application modifies this so that we build the javascript object from the database of (in our case) sermons. This is passed back through a Laravel route.

Player

The player itself (howler.blade.php) is displayed in an iframe and allowed to swallow the entire width of the frame. This allows it to be responsive without much effort.

Howler comes as an html file. One modification required blade templating:

var player = new Player({!! 
str_replace('"', '"', $sermons)
!!});

The player takes $sermons passed as JSON and initiates the audio. When we want to update the playlist, we pass a different value for $sermons and Howler never really has to know anything. The real trick here is to get the player to update when we click on one of the search results.

Since howler is contained in an iframe of audiosearch.blade.php, we use a trigger function to cause the iframe to reload with the new value.

A function setupPlaylist is given the URL of the audio to play. The iframe is subsequently destroyed and a new one is created in its place with the new URI.

audiosearch.blade.php javascript:

<script>
var tipuesearch = {
"pages": {!!$sermons!!}
};
$(document).ready(function() {
    $('#tipue_search_input').tipuesearch({
'show': 20,
'showURL': false
});
});
    // Rebuild the iFrame to change the Player audio
function setupPlaylist(url) {
$('#frame').empty();
$("#frame").append("<iframe id=sermon-howler src=" +
encodeURI(url) +
"style=width:100%;height:800px;></iframe>");
}
</script>

Notice that the tipuesearch variable replaces its javascript object with $sermons which contains the JSON passed at the creation of the page.

When a search is performed the criteria is taken to a Helper class server-side. The class grabs the data and builds a javascript object (JSON) string to return to the Request in the Route.

Routing

There are a few required routes. The main page, the howler page and a couple routes to retrieve data.

In web.php we have:

Route::get('audiosearch', 'PagesController@audiosearch')->name('audiosearch');

Now create a controller called PagesController using this command:

php artisan make:controller PagesController

PagesController.php

public function audiosearch()
{
$sermons = Helper::getSermonSearchlist();
    return view('audiosearch')->with('sermons', $sermons);
}

The route above receives data from a Helper function discussed below.

We’re going to need a function to update the player itself:

public function howler_update(Request $request)
{
$title = $request->input('title');
$sermons = Helper::getSermon($title);
    return view('howler')->with('sermons',$sermons);
}

And the initial route for the player page:

public function howler()
{
$sermons = Helper::getSermonPlaylist();
    return view('howler')->with('sermons', $sermons);
}

Notice one howler function retrieves an audio track by title, the other retrieves an entire playlist (determined in Helper.php)

Helper Class

We need a Helper class to make some calls to the database and perform various search tasks that return JSON to the request.

We need to add a class alias in config/app.php under ‘aliases’ => [

app.php

'Helper' => App\Helpers\Helper::class,

Next, let’s add the Helper class. Create a new folder called Helpers in the app folder and add a file called Helper.php

Helper.php

//Snippet just gives an idea of what's going on in Helper
public static function getSermon($str)
{
$playlist = array();
        // Fetch sermon record
$songs = DB::table('sermons')
->where('title', 'like', urldecode($str))
->limit(1)
->get();
        foreach ($songs as $s) {
$song = array(
"title" => $s->title,
"file" => $s->file,
"howl" => null,
);
            array_push($playlist, $song);
}
        return json_encode($playlist); 
}

The file, like the others, is available on GitHub, but I wanted to draw attention to the urldecode and json_encode functions. This is to ensure the player gets the data in a consumable form.


That should cover what you need to modify the project code or build new.

I hope this has been profitable for you. Happy Coding!