Search code examples
javascripthtmldjangobackend

How to play different audios on a single <audio> tag Django app


I'm making a music streaming website. On the homepage I have a carousel with songs and I want to play them onclick in a single HTML <audio> tag. How can I achieve that? Do I have to write a JavaScript function? If yes, how it should look like?

This is my HTML:

<div class="main-carousel" data-flickity='{"groupCells":5 , "contain": true, "pageDots": false, "draggable": false, "cellAlign": "left", "lazyLoad": true}'>
        {% for i in songs %}
            <div class="carousel-cell">
                <section class="main_song">
                    <div class="song-card">
                        <div class="containera">
                            <img src="{{i.image}}" id="A_{{i.id}}" alt="song cover">
                            <div class="overlaya"></div>
                            <div>
                                <a class="play-btn" href="...?" id="{{i.id}}"><i class="fas fa-play-circle fa-2x"></i></a>
                                {% if user.is_authenticated %}
                                    <div class="add-playlist-btn">
                                        <a id="W_{{i.song_id}}" title="Add to Playlist" onclick="showDiv(this)"></a>
                                    </div>
                                {% endif %}
                            </div>
                        </div>
                    </div>
                    <div>
                        <p class="songName" id="B_{{i.id}}">{{i.name}}</p>
                        <p class="artistName">{{i.artist}}</p>
                    </div>
                </section>
            </div>
        {% endfor %}
    </div>
    <audio preload="auto" controls id="audioPlayer">
        <source src=...?>
        </audio>

My models.py:

class Song(models.Model):
    song_id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=50)
    artist = models.CharField(max_length=50)
    album = models.CharField(max_length=50, blank=True)
    genre = models.CharField(max_length=20, blank=True, default='Album')
    song = models.FileField(upload_to="songs/", validators=[FileExtensionValidator(allowed_extensions=['mp3', 'wav'])], default="name")
    image = models.ImageField(upload_to="songimage/", validators=[FileExtensionValidator(allowed_extensions=['jpeg', 'jpg', 'png'])], default="https://placehold.co/300x300/png")
    data = models.DateTimeField(auto_now=False, auto_now_add=True)
    slug = models.SlugField(unique=True)

    def __str__(self):
        return self.name

    class Meta:
        ordering = ['name']

Solution

  • You need to write a Javascript function.

    Update your HTML to include the song URL in a data attribute for each play button:

    <div class="main-carousel" data-flickity='{"groupCells":5 , "contain": true, "pageDots": false, "draggable": false, "cellAlign": "left", "lazyLoad": true}'>
        {% for i in songs %}
            <div class="carousel-cell">
                <section class="main_song">
                    <div class="song-card">
                        <div class="containera">
                            <img src="{{i.image.url}}" id="A_{{i.id}}" alt="song cover">
                            <div class="overlaya"></div>
                            <div>
                                <a class="play-btn" href="#" data-song-url="{{i.song.url}}" id="{{i.id}}" onclick="playSong(this)"><i class="fas fa-play-circle fa-2x"></i></a>
                                {% if user.is_authenticated %}
                                    <div class="add-playlist-btn">
                                        <a id="W_{{i.song_id}}" title="Add to Playlist" onclick="showDiv(this)"></a>
                                    </div>
                                {% endif %}
                            </div>
                        </div>
                    </div>
                    <div>
                        <p class="songName" id="B_{{i.id}}">{{i.name}}</p>
                        <p class="artistName">{{i.artist}}</p>
                    </div>
                </section>
            </div>
        {% endfor %}
    </div>
    <audio preload="auto" controls id="audioPlayer">
        <source src="" id="audioSource">
    </audio>
    

    Create the JavaScript function to play the song:

    function playSong(element) {
        var songUrl = element.getAttribute('data-song-url');
        var audioPlayer = document.getElementById('audioPlayer');
        var audioSource = document.getElementById('audioSource');
        audioSource.src = songUrl;
        audioPlayer.load();
        audioPlayer.play();
    }
    

    Ensure you include the JavaScript in your HTML file or in a linked JS file:

    <script>
        function playSong(element) {
            var songUrl = element.getAttribute('data-song-url');
            var audioPlayer = document.getElementById('audioPlayer');
            var audioSource = document.getElementById('audioSource');
            audioSource.src = songUrl;
            audioPlayer.load();
            audioPlayer.play();
        }
    </script>