4
0
Bifurcation 1

feat(player): add the song duration and display it properly

pull/12/head
Jérôme Lebleu 2022-02-28 17:03:30 +01:00
Parent 5d04971013
révision 9110b55710
4 fichiers modifiés avec 45 ajouts et 3 suppressions

Voir le fichier

@ -25,7 +25,7 @@
<div class="player-progress" unicorn:ignore>
<input aria-label="Seek" aria-valuemax="0" aria-valuemin="0" aria-valuenow="0" autocomplete="off" class="player-progress__range" data-player-target="progressSlider" max="100" min="0" role="slider" step="0.01" type="range" value="0">
</div>
<time class="player-time" data-player-target="duration" unicorn:ignore>--:--</time>
<time class="player-time" data-player-target="duration" unicorn:ignore>
</div>
<div class="player__container player__container--current">
<div class="song-title">

Voir le fichier

@ -1,3 +1,4 @@
from datetime import timedelta
from pathlib import Path
from django.test.html import parse_html
@ -5,7 +6,7 @@ from django.test.html import parse_html
import pytest
from wagtail_factories import ImageFactory
from wagtail_webradio.components.player import PlayerView, Playlist
from wagtail_webradio.components.player import PlayerView, Playlist, Song
from .factories import PodcastFactory
from .utils import prettify_html
@ -19,6 +20,22 @@ def player():
return component
class TestSong:
@pytest.mark.parametrize(
'duration, result',
[
(None, '--:--'),
(timedelta(), '--:--'),
(timedelta(seconds=2), '00:02'),
(timedelta(minutes=3), '03:00'),
(timedelta(minutes=12, seconds=10), '12:10'),
(timedelta(hours=1, seconds=10), '01:00:10'),
],
)
def test_duration_str(self, duration, result):
assert Song('t', 's', 'u', duration=duration).duration_str == result
class TestPlaylist:
def test_iter_items(self):
song = {
@ -158,6 +175,7 @@ class TestPlayer:
title="The podcast",
radio_show__title="The show",
sound_url='https://example.org',
duration=timedelta(minutes=3, seconds=10),
)
player.add_podcast(podcast.pk)
@ -166,6 +184,7 @@ class TestPlayer:
assert song.title == "The podcast"
assert song.subtitle == "The show"
assert song.url == 'https://example.org'
assert song.duration_str == '03:10'
assert song.download_url == 'https://example.org'
assert song.thumbnail_url == ''

Voir le fichier

@ -1,8 +1,11 @@
from collections import OrderedDict
from collections.abc import Sequence
from dataclasses import dataclass
from datetime import timedelta
from typing import Optional, Union
from django.utils.functional import cached_property
from django_unicorn.components import UnicornView
from ..models import Podcast
@ -13,9 +16,24 @@ class Song:
url: str
title: str
subtitle: str
duration: timedelta = None
download_url: str = ''
thumbnail_url: str = ''
@cached_property
def duration_str(self):
if not self.duration:
return '--:--'
result = []
seconds = self.duration.total_seconds()
if seconds >= 3600:
hours, seconds = divmod(seconds, 3600)
result.append('{:02n}'.format(hours))
minutes, seconds = divmod(seconds, 60)
result.append('{:02n}'.format(minutes))
result.append('{:02n}'.format(seconds))
return ':'.join(result)
class Playlist(Sequence):
def __init__(self):
@ -256,6 +274,7 @@ class PlayerView(UnicornView):
url=podcast.sound_url,
title=podcast.title,
subtitle=podcast.radio_show.title,
duration=podcast.duration,
download_url=podcast.sound_url,
)

Voir le fichier

@ -41,7 +41,7 @@
<input type="range" class="player-progress__range" min="0" max="100" step="0.01" value="0" autocomplete="off" role="slider" aria-label="{% trans "Seek" %}" aria-valuenow="0" aria-valuemin="0" aria-valuemax="0" data-player-target="progressSlider">
</div>
<time class="player-time" data-player-target="duration" unicorn:ignore>--:--</time>
<time class="player-time" data-player-target="duration" unicorn:ignore>{{ current.duration_str }}</time>
</div>
<div class="player__container player__container--current">
{% if current.thumbnail_url %}
@ -75,6 +75,10 @@
<p class="song__subtitle">{{ song.subtitle }}</p>
</button>
{% if song.duration %}
<time class="song__time">{{ song.duration_str }}</time>
{% endif %}
<button type="button" class="btn btn-sm" aria-label="{% trans "Remove this song from the playlist" %}" unicorn:click="remove({{ id }})">
{% block delete_icon %}
<i class="fa fa-trash-o" aria-hidden="true"></i>