How to embed a simple javascript audio player with Django - code tutorial.

Share your content, pictures on other people’s pages

You can click PLAY and listen to it 🔊. This is an audioplayer that actually is not on this page. The hvitis.dev is a pure static page. You can of course ⏺️ record your own thought in seconds but probably - for now - you just want to read how it’s done.

The coolest thing about it is that you can embed anything! You have a badge? Audio player? Video player? A GAME? Awesome. Let’s do it.

How it is done

It’s super simple: iframes

It’s a way of embedding content from other pages on other pages. You have seen it maybe already on some pages. YouTube?

youtube

Exactly. It is important to know that the attributes you have there can be of course set by yourself by changing the link content but they are verified on the server.

If you have opened the iframes link then you have seen that we get tons of attributes there including such as: allowpaymentrequest, allowfullscreen and others. They are very important security measurements because after all - it’s another page on your page. You do not know what does it do, what source code it has etc.

We read that this is embeded browser context and we know some basics already but I told you that we are going to do our own, right?

Django - let’s start! 🐍

We don’t want to just show any content, let’s make this tutorial slightly above beginner level and change the content dynamically. From now on you need basic django knowledge. I assume you know how to start a project and install new application (e.g. podcasts), add templates.

We need to:

  • Make an audio model.
  • Make a view (Pass some url kwargs).
  • Make the HTML template to return.
  • Return an HTML template.
  • Use JavaScript to display what we want.

I will make a super simple model with podcast title and file:

# podcasts/models.py
from django.db import models

class Podcast(models.Model):

    audio_file = models.FileField(
        upload_to='podcasts/', null=True, blank=True)
    title = models.CharField(
        max_length=255, blank=True, null=True)

    def __str__(self):
        return self.title

Now let’s register this model in admin to later be able to test the functionality by uploading test file.

# podcasts/admin.py
from django.contrib import admin
from .models import Podcast

admin.site.register(Podcast)

And let’s make url with dynamic parameter that will help us query Podcasts. Don’t forget to add it to main urls.ps.

# podcasts/urls.py
from django.urls import path
from .views import RenderHTMLPlayer # We are about to make this view in next step.

urlpatterns = [
    # This is our URL int id attribute we later get with KWARGS.
    path("/<int:id>", RenderHTMLPlayer.as_view(), name="podcasts-player"),
    # id is automatically generated on created new Podcast so if you have
    # uploaded your first file via admin you should have one podcast with id=1
]

Then we run short steps (again - I am assuming here basic Django knowledge as stated before):

  1. run migrations
  2. create admin user
  3. add one track (via admin panel using admin user)
  4. we create view.
# podcasts/views.py
from django.views.generic import TemplateView
from django.shortcuts import render
from .models import Podcast

class RenderHTMLPlayer(TemplateView):
    pass

Now let’s add template (we haven’t made it yet!). Remember that templates are by default in templates folder and have default naming convention. I am calling it podcastsplayer.html_ to be more verbose.

#...
class RenderHTMLPlayer(TemplateView):
    template_name = "podcasts_player.html"
    model = Podcast

Now we just need to get a track and return it’s MEDIA_URL to the rendered view.

#...
    def get(self, request, *args, **kwargs):
        # Let's get our id from URL
        id = self.kwargs.get('id')

        # then we use this id to find corresponding podcast
        podcast = Podcast.objects.filter(id=id).first()

        # We obtain URL for saved media file.
        podcast_uri = '/media' + \
            request.build_absolute_uri(podcast.file.url).split('media')[1]

        # We finally return the track URL in the context.
        # It's needed to load audio via audio player.
        context = {'track_url': track_uri}
        return render(request, self.template_name, context)

That’s almost it! Remember when I told you that there is a lot of attributes in iframes and they are there for a reason ?

☝️☝️ Those security attributes can be verified and added by Django and by server you are running it on (e.g. NGINx). If you want to serve your page as an iframe for others you must know more about Django middleware. That’s Out of Scope for this tutorial.

Alright! What are we missing?

podcastsplayer.html_ of course.

JavaScript - We are comming! 💛

We need to build a small audio player now!

In order to make it as lightweight as possible I am using pure-css module and font-awesome icons (that’s maybe an overkill).

<link
  rel="stylesheet"
  href="https://unpkg.com/purecss@2.0.3/build/pure-min.css"
  integrity="sha384-cg6SkqEOCV1NbJoCu11+bm0NvBRc8IYLRGXkmNrqUBfTjmMYwNKPWBTIKyw9mHNJ"
  crossorigin="anonymous"
/>
<link
  rel="stylesheet"
  href="https://netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.css"
/>

Playing audio and visualization will be done by wavesurfer.js that we add as a script to the end of the body (and actually before other script that actually run the wavesurfer).

<script src="https://cdnjs.cloudflare.com/ajax/libs/wavesurfer.js/1.0.53/wavesurfer.min.js"></script>

What is wavesurfer? It’s a simple javascript audio player library. It’s free and I prefer it over howler.js or amplitude.js. You get javascript audio player with waveform that is plug and play! You also have progress bar and it can be made to look like soundcloud one! (that’s a good idea for the next post!). From my experience I had quality streaming (it preloads media files automatically).

You can make this tutorial with simple audio html5 audio player. Just use

<audio></audio>

in case you don’t want to use any library. In this case just pass the link in the src but.. it’s boring and not pretty. Follow this tutorial to have a better player.

The other script (with actual logic) we will see soon. For now let’s make some simple skeleton with what we have right now:

<!-- podcasts_player.html -->
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta name="description" content="Custom Podcasts in your blog." />
    <title>Your Podcasts</title>
    <link
      rel="stylesheet"
      href="https://unpkg.com/purecss@2.0.3/build/pure-min.css"
    />
    <link
      rel="stylesheet"
      href="https://netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.css"
    />
    <style>
      /* Here we can change the look and feel */
    </style>
  </head>

  <body>
    <!-- This is a div for audiowave to be mounted by wavesurfer -->
    <div id="waveform"></div>

    <!-- Then we have some buttons for playing, stopping and pausing
 Here we are using pure css classes and font awesome icons
  Each button has onclick event assigned that we program later -->
    <button
      id="play"
      class="pure-button pure-button-secondary"
      onclick="startRecording()"
    >
      <i class="fa fa-play-circle"></i> Play
    </button>
    <button
      id="pause"
      class="pure-button pure-button-secondary"
      onclick="pauseRecording()"
    >
      <i class="fa fa-pause"></i> Pause
    </button>
    <button
      id="stop"
      class="pure-button pure-button-primary"
      onclick="stopRecording()"
    >
      <i class="fa fa-stop"></i> Stop
    </button>
    <script>
      // Uhh.. nothing fancy so far.. starts boring but here it goes - the core script!
    </script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/wavesurfer.js/1.0.53/wavesurfer.min.js"></script>
  </body>
</html>

So now we just need the last piece - the core, the heart of the operation - player and playing logic! let’s see how our custom script will look like:

<script>
  // Uhh.. nothing fancy so far.. starts boring but here it goes - the core script!
</script>

Let’s start by getting the track_url from the context that we have on that page (we got in from Django views). You can think about the following as a simple javascript audio player tutorial.

// The content of the script tags is more interesting!

// That's how we get a value from Django context in our JS script
let trackUrl = '{{ track_url|safe }}'

Before starting those buttons let’s initiate the audioplayer we got from previous script.

var wavesurfer = WaveSurfer.create({
  container: '#waveform',
  // Here you can use wavesurfer docs on configuration
  // to customize your player!
})

We load the music using the MEDIA_URL we got for the track and passed to this script right..?

wavesurfer.load(trackUrl)

Now the only thing that is left is to play it! Let’s get those buttons working by creating functions we assigned to their onclick events:

// We play, pause and stop our audio file with instanciated wavesurfer.js
function startRecording() {
  wavesurfer.play()
}
function pauseRecording() {
  wavesurfer.pause()
}
function stopRecording() {
  wavesurfer.stop()
}

You can use now some tool to compress the written JavaScript - now the 5 bytes won’t make a difference but with bigger files it’s a good practice.

Now! How do we play that?

Well, assuming that:

  • you made all that in a podcasts app (folder)
  • your urls.py are exactly the same as the one I wrote here,
  • you submitted 1 .mp3 file to podcast.
  • you are running the server on port 8000.

then we should have a url like that:

http://localhost:8000/podcasts/1

You should be able to see something like this in your browser:

youtube

Now if you have more podcasts, you will have corresponding urls ending with 2, 3 etc. All you need to do now is to attach the URL in your iframe:

<iframe src="http://localhost:3000/player/zh"></iframe>

You are of course limited by nothing but your imagination! I made audio player with playlist for websites as you can see on the beginning of this post. You could do javascript audio player on mac (the safari browser may have some hiccups with this one)

and…

DEPLOY!

Thank you for reading!


Did you make any mistakes when using embedding or you’ve seen one here? Tell me about your insights. Leave a comment with You are most welcome to see more posts of this type just go to home page

Care to Share?

Here should be a newsletter

but trust me, you don't need another spam email that would distract your from reading a paper book. Enjoy reading books, not mails!