WaveSurfer player voor podcasts, voor live WIP

This commit is contained in:
NH Gooi
2024-09-24 17:29:57 +02:00
parent cff9948dda
commit 1dadbc62af
4 changed files with 231 additions and 8 deletions

View File

@@ -186,6 +186,7 @@
<script type="text/javascript" src="/js/jquery.prettyPhoto.js"></script>
<script type="text/javascript" src="/js/jquery.carouFredSel-6.2.1.min.js"></script>
<script type="text/javascript" src="/js/functions.js"></script>
<script type="text/javascript" src="/js/wavesurfer.min.js"></script>
<script type="text/javascript">
$(window).resize(function () {
// Fix sticky for mobile menu indicator

View File

@@ -36,9 +36,15 @@
</p>
@endif
<p>
<audio controls autoplay="true">
{{-- <audio controls autoplay="true">
<source src="{{$source}}" type="audio/mp3"/>
</audio>
</audio> --}}
@include('widgets.audioplayer', [
'source' =>str_replace("stream", "download", $source),
'lengte' => 0,
'waveform' => []
])
</p>
<p>
@@ -130,6 +136,7 @@
@push('scripts')
<script type="text/javascript" src="/js/jquery-3.7.1.min.js"></script>
<script type="text/javascript" src="/js/wavesurfer.min.js"></script>
<script>
function updateOnAir() {
$.ajax({
@@ -163,4 +170,3 @@
</script>
@endpush
@include('widgets.mediaplayer')

View File

@@ -112,9 +112,12 @@
</ul>
<div class="announcement">
<audio controls>
<source src="{{$streamUrl}}" type="audio/mpeg"/>
</audio>
@include("widgets.audioplayer", [
'source' => $streamUrl,
'lengte' => $podcast->duration / 1000,
'waveform' => $podcast->waveform
])
<div class="clearfix">
<a class="action_button btn" href="{{$audioUrl}}" title="Download dit fragment als MP3">
<span>Download fragment</span>

View File

@@ -0,0 +1,213 @@
<?php $id = uniqid('player_'); ?>
<div class="audioplayer" id="{{ $id }}">
{{--
<label for="lengte" class="col-12 col-sm-2 col-form-label">Lengte</label>
<div class="col-12 col-sm-10 my-auto">
@if( $lengte > 60)
{{ floor($lengte / 60) }} minuten en {{ floor(($lengte % 60)) }} seconden
@else
{{ $lengte }} seconden
@endif
</div>
--}}
<div class="waveform">
<div class="time">0:00</div>
<div class="duration">0:00</div>
<div class="hover"></div>
</div>
<div class="volume-controls">
<button class="btn-toggle-mute" type="button">
<span class="fa fa-volume-high"></span>
</button>
<input class="volume-slider" type="range" min="0" max="1" step="0.01" value="1"
onchange="wavesurfer_{{ $id }}.setVolume( this.value )" />
</div>
<div class="audio-controls">
<button class="btn btn-jump" type="button" onclick="wavesurfer_{{ $id }}.skip(-60)">
<span class="fa fa-backward-fast"></span>
<label>-60 s</label>
</button>
<button class="btn btn-jump" type="button" onclick="wavesurfer_{{ $id }}.skip(-10)">
<span class="fa fa-backward-step"></span>
<label>-10 s</label>
</button>
<button class="btn btn-play" type="button" onclick="wavesurfer_{{ $id }}.playPause()">
<span class="play-button-icon fa fa-play"></span>
<label class="play-button-label">Afspelen</label>
</button>
<button class="btn btn-jump" type="button" onclick="wavesurfer_{{ $id }}.skip(10)">
<span class="fa fa-forward-step"></span>
<label>+10 s</label>
</button>
<button class="btn btn-jump" type="button" onclick="wavesurfer_{{ $id }}.skip(60)">
<span class="fa fa-forward-fast"></span>
<label>+60 s</label>
</button>
</div>
</div>
<script>
var wavesurfer_{{ $id }};
addEventListener("DOMContentLoaded", function() {
const canvas = document.createElement('canvas')
const ctx = canvas.getContext('2d')
// Create the waveform
wavesurfer_{{ $id }} = WaveSurfer.create({
container: '#{{ $id }} .waveform',
waveColor: '#3A96EE',
progressColor: '#0118A1',
barWidth: 1,
// duration: {{ $lengte }},
// @if($waveform)
// peaks: {{ json_encode($waveform->data) }},
// normalize: true,
// @endif
url: '{{ $source }}',
});
// Play/pause on click
wavesurfer_{{ $id }}.on('click', () => {
wavesurfer_{{ $id }}.play();
})
wavesurfer_{{ $id }}.on('play', () => {
$('#{{ $id }} .play-button-icon').addClass('fa-pause').removeClass('fa-play');
$('#{{ $id }} .play-button-label').text('Pauzeren');
})
wavesurfer_{{ $id }}.on('pause', () => {
$('#{{ $id }} .play-button-icon').addClass('fa-play').removeClass('fa-pause');
$('#{{ $id }} .play-button-label').text('Verder spelen');
})
$('#{{ $id }} .btn-toggle-mute').on('click', () => {
var isMuted = !wavesurfer_{{ $id }}.getMuted();
wavesurfer_{{ $id }}.setMuted(isMuted);
if(isMuted) {
$('#{{ $id }} .btn-toggle-mute').html('<span class="fa fa-volume-xmark"></span>');
$('#{{ $id }} .volume-slider').attr('disabled', 'disabled');
} else {
$('#{{ $id }} .btn-toggle-mute').html('<span class="fa fa-volume-high"></span>');
$('#{{ $id }} .volume-slider').removeAttr('disabled');
}
});
// Hover effect
{
const hover = document.querySelector('#{{ $id }} .hover')
const waveform = document.querySelector('#{{ $id }} .waveform')
waveform.addEventListener('pointermove', (e) => (hover.style.width = `${e.offsetX}px`))
}
// Current time & duration
{
const formatTime = (seconds) => {
const minutes = Math.floor(seconds / 60)
const secondsRemainder = Math.round(seconds) % 60
const paddedSeconds = `0${secondsRemainder}`.slice(-2)
return `${minutes}:${paddedSeconds}`
}
const timeEl = document.querySelector('#{{ $id }} .time')
const durationEl = document.querySelector('#{{ $id }} .duration')
wavesurfer_{{ $id }}.on('decode', (duration) => (durationEl.textContent = formatTime(duration)))
wavesurfer_{{ $id }}.on('timeupdate', (currentTime) => (timeEl.textContent = formatTime(currentTime)))
}
});
</script>
<style>
#{{ $id }} .waveform {
cursor: pointer;
position: relative;
}
#{{ $id }} .hover {
position: absolute;
left: 0;
top: 0;
z-index: 10;
pointer-events: none;
height: 100%;
width: 0;
mix-blend-mode: overlay;
background: rgba(255, 255, 255, 0.5);
opacity: 0;
transition: opacity 0.2s ease;
}
#{{ $id }} .waveform:hover .hover {
opacity: 1;
}
#{{ $id }} .time,
#{{ $id }} .duration {
position: absolute;
z-index: 11;
top: 50%;
margin-top: -1px;
transform: translateY(-50%);
font-size: 11px;
background: rgba(0, 0, 0, 0.75);
padding: 2px;
color: #ddd;
}
#{{ $id }} .time {
left: 0;
}
#{{ $id }} .duration {
right: 0;
}
#{{ $id }} .audio-controls {
width: 100%;
justify-content: center;
display: flex;
}
#{{ $id }} .audio-controls .btn {
padding-left: 0;
padding-right: 0;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
text-transform: none;
}
@media(max-width:720px) {
#{{ $id }} .audio-controls .btn label {
display: none;
}
}
#{{ $id }} .audio-controls .btn.btn-play {
flex: 50% 1 0;
}
#{{ $id }} .volume-controls {
display: flex;
}
#{{ $id }} .volume-controls .volume-slider
{
flex: 100% 1 1;
}
#{{ $id }} .audio-controls .btn,
#{{ $id }} .volume-controls .btn-toggle-mute {
flex: 100px 1 1;
padding: 10px 0px 10px 0px;
background: #5ba8f4;
border-radius: 5px;
border-color: solid 1px #0f259d;
color: white;
font-family: Nunito, serif;
text-align: center;
text-decoration: none;
}
</style>