custom audio player

change the defaut html audio player to a custom player
This commit is contained in:
Nuwan 2024-12-27 01:47:08 +05:30
parent f8462dbb84
commit d7eef09946
19 changed files with 347 additions and 23 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 256 256" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g>
<g>
<g>
<path d="M114.7,10.6C80.5,14.5 49.1,34 29.4,63.5C25.2,69.9 18.4,83.8 15.9,91.1C8,115.2 8,140.8 16.1,165.1C33.5,217 85.2,250.8 139.3,245.4C183.9,241 223.1,210.6 238.9,168.2C246.2,148.4 248,125.3 243.7,104.4C233.7,55.6 192.3,17.2 142.7,10.9C135.6,9.9 121.7,9.8 114.7,10.6ZM140.5,19C196.1,25 237.5,71.6 237.5,128.1C237.5,165.1 219.6,198.8 189,219.3C167.9,233.4 141.1,239.8 115,236.8C77.7,232.5 46,210.1 29.6,176.5C14.7,146.2 14.8,109.6 29.7,79.3C35.3,67.7 41,59.8 50.4,50.3C67.4,33 90.5,21.8 114.9,19C120.9,18.3 134.3,18.3 140.5,19Z" style="fill:rgb(64,124,222);fill-rule:nonzero;stroke:rgb(64,124,222);stroke-width:1px;"/>
<path d="M104.3,86.7C104.1,87.1 104.1,104.9 104.1,126.3L104.3,165.2L118.9,165.2L118.9,86.3L111.7,86.1C106.3,86 104.5,86.2 104.3,86.7Z" style="fill:rgb(64,124,222);fill-rule:nonzero;stroke:rgb(64,124,222);stroke-width:1px;"/>
<path d="M136.6,87.3C136.4,88.4 136.4,149.5 136.7,162L136.8,165.5L144.3,165.3L151.7,165.1L151.7,86.3L144.3,86.1C136.9,86 136.8,86 136.6,87.3Z" style="fill:rgb(64,124,222);fill-rule:nonzero;stroke:rgb(64,124,222);stroke-width:1px;"/>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 256 256" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g>
<g>
<g>
<path d="M115,10.4C93.4,12.8 72.1,21.7 54.5,35.4C49.4,39.5 40,48.8 35.7,54.2C22.7,70.3 14.1,90.4 10.9,111.5C9.7,120.1 9.7,136 10.9,144.5C15.3,174 29.7,199.7 52.8,219C78.4,240.4 113.5,250.1 146.3,244.8C197.7,236.4 237.4,196.2 245.1,144.7C246.3,136.3 246.3,119.9 245.1,111.4C241.4,86.2 230.7,64.4 213,46.1C202.5,35.2 192.4,27.9 179.3,21.6C159.4,12 136.4,8 115,10.4ZM146,20.7C193.8,29.3 229.1,65.9 235.9,114.2C236.8,120.8 236.7,136.8 235.6,143.7C230.8,174.4 214.5,200.4 189.1,217.8C168.3,232 142.2,238.7 117.3,236.2C78.4,232.3 44.2,207.5 28.6,172C21.3,155.4 18.5,139.2 19.6,120.5C21.5,86.8 40.8,54.3 69.6,36.2C82.5,28.1 98,22.3 111.8,20.4C114.4,20 117.3,19.6 118.3,19.5C122.1,19.1 140.9,19.8 146,20.7Z" style="fill:rgb(64,124,222);fill-rule:nonzero;stroke:rgb(64,124,222);stroke-width:1px;"/>
<path d="M110,81.1C106.9,82.4 107,80.4 107,128.1L107,172.5L108.3,173.9C109.1,174.7 110.4,175.2 111.6,175.2C113.4,175.2 116.8,172.5 139.5,153.8C153.7,142 165.9,131.8 166.5,131.2C167,130.6 167.5,129.1 167.5,128.1C167.5,127 167,125.6 166.5,125C165.9,124.4 155.1,115.3 142.4,104.8C129.8,94.4 118.2,84.8 116.7,83.6C113.8,81 111.8,80.3 110,81.1ZM136.7,112.3C146.9,120.7 155.3,127.8 155.3,127.9C155.4,128.1 148,134.4 138.9,141.9C129.8,149.5 121.1,156.6 119.6,157.9L116.8,160.3L116.8,128C116.8,102.2 117,95.9 117.6,96.3C117.9,96.7 126.6,103.9 136.7,112.3Z" style="fill:rgb(64,124,222);fill-rule:nonzero;stroke:rgb(64,124,222);stroke-width:1px;"/>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@ -11,3 +11,4 @@
@import './custom/chips';
@import './custom/common';
@import './custom/partner_agreement_v1';
@import './custom/audio_player';

View File

@ -0,0 +1,135 @@
.audio-player {
height: 30px;
background: #ffffff;
//box-shadow: 0 0 20px 0 #000a;
font-family: arial;
color: #1b1a1a;
font-size: 0.75em;
overflow: hidden;
// display: grid;
// grid-template-rows: 6px auto;
}
.audio-player .controls {
display: flex;
justify-content: space-between;
align-items: stretch;
padding: 0;
gap: 2px;
}
.audio-player .controls > * {
display: flex;
// justify-content: center;
align-items: center;
}
.audio-player .controls .timeline {
margin-top: auto;
margin-bottom: auto;
margin-left: 5px;
margin-right: 5px;
background: rgb(14, 157, 223);
width: 100%;
height: 4px;
cursor: pointer;
//box-shadow: 0 2px 10px 0 #0008;
}
.audio-player .controls .timeline .progress {
background: coral;
width: 0%;
height: 100%;
transition: 0.25s;
}
.audio-player .controls .play-pause-button{
background: "none";
border: "none";
cursor: "pointer";
outline: "none";
left: 0;
}
.audio-player .controls .time {
display: flex;
}
.audio-player .controls .time > * {
padding: 2px;
}
.audio-player .controls .volume-container {
margin-right: 5px;
cursor: pointer;
position: relative;
z-index: 2;
width: 30px;
}
.audio-player .controls .volume-container .volume-button {
height: 26px;
display: flex;
align-items: center;
}
.audio-player .controls .volume-container .volume-button .volume {
transform: scale(1.4);
}
.audio-player .controls .volume-container .volume-slider {
position: absolute;
left: -4px;
top: 12px;
z-index: -1;
width: 0;
height: 10px;
background: white;
box-shadow: 0 0 10px #000a;
transition: 0.25s;
}
.audio-player .controls .volume-container .volume-slider .volume-percentage {
background: coral;
height: 100%;
width: 75%;
}
.audio-player .controls .volume-container:hover .volume-slider {
left: -123px;
width: 120px;
}
// .audio-player .controls .toggle-play.play {
// cursor: pointer;
// position: relative;
// left: 0;
// height: 0;
// width: 0;
// border: 7px solid #0000;
// border-left: 13px solid white;
// }
// .audio-player .controls .toggle-play.play:hover {
// transform: scale(1.1);
// }
// .audio-player .controls .toggle-play.pause {
// height: 15px;
// width: 20px;
// cursor: pointer;
// position: relative;
// }
// .audio-player .controls .toggle-play.pause:before {
// position: absolute;
// top: 0;
// left: 0px;
// background: white;
// content: "";
// height: 15px;
// width: 3px;
// }
// .audio-player .controls .toggle-play.pause:after {
// position: absolute;
// top: 0;
// right: 8px;
// background: white;
// content: "";
// height: 15px;
// width: 3px;
// }
// .audio-player .controls .toggle-play.pause:hover {
// transform: scale(1.1);
// }

View File

@ -0,0 +1,169 @@
import React, { useRef, useEffect, useState } from 'react';
import playIcon from '../../assets/img/icons/play-icon.svg';
import pauseIcon from '../../assets/img/icons/pause-icon.svg';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
const JKAudioPlayer = ({ audioUrl }) => {
const audioPlayer = useRef(null);
const [audio, setAudio] = useState(null);
const [isPlaying, setIsPlaying] = useState(false);
const [isMuted, setIsMuted] = useState(false);
useEffect(() => {
if (!audioUrl) return;
console.log('audioUrl: ' + audioUrl)
if (audio) { stopAudio(); }
const audio = new Audio(audioUrl);
setAudio(audio);
}, [audioUrl]);
useEffect(() => {
if (!audio || !audioPlayer) return;
stopAudio();
const audioLoadedDataEventListener = audio.addEventListener("loadeddata", () => {
audioPlayer.current.querySelector(".time .length").textContent = getTimeCodeFromNum(
audio.duration
);
audio.volume = .75;
});
const audioPercentageCheckInterval = setInterval(() => {
const progressBar = audioPlayer.current.querySelector(".progress");
progressBar.style.width = audio.currentTime / audio.duration * 100 + "%";
audioPlayer.current.querySelector(".time .current").textContent = getTimeCodeFromNum(
audio.currentTime
);
}, 500);
//audio.play();
return () => {
stopAudio();
audio.removeEventListener("loadeddata", audioLoadedDataEventListener);
clearInterval(audioPercentageCheckInterval);
}
}, [audio, audioPlayer]);
const stopAudio = () => {
if (!audio) return;
audio.pause();
audio.currentTime = 0;
setIsPlaying(false);
}
const togglePlayPause = (e) => {
if (!audio) return;
if (audio.paused) {
audio.play();
setIsPlaying(true);
} else {
audio.pause();
setIsPlaying(false);
}
}
const onVolumeButtonClick = () => {
if (!audio) return;
audio.muted = !audio.muted;
setIsMuted(audio.muted);
}
const onClickTimeline = (e) => {
if (!audio) return;
let timeToSeek = 0;
try {
let timelineWidth = window.getComputedStyle(audioPlayer.current.querySelector(".timeline")).width;
//remove px from the string if it exists
if (timelineWidth.includes('px')) {
timelineWidth = timelineWidth.replace('px', '');
}
timeToSeek = Math.floor(e.nativeEvent.offsetX / parseInt(timelineWidth) * audio.duration);
} catch (e) {
console.error('Error seeking audio: ' + e)
timeToSeek = 0;
}
audio.currentTime = timeToSeek;
}
const onVolumeSliderClick = (e) => {
if (!audio) return;
let volume = .75;
try {
let sliderWidth = window.getComputedStyle(audioPlayer.current.querySelector(".controls .volume-slider")).width;
if (sliderWidth.includes('px')) {
sliderWidth = sliderWidth.replace('px', '');
}
volume = parseFloat((e.nativeEvent.offsetX / parseInt(sliderWidth)).toFixed(2));
} catch {
console.error('Error changing volume')
volume = .75;
}
audio.volume = volume;
audioPlayer.current.querySelector(".controls .volume-percentage").style.width = volume * 100 + '%';
}
function getTimeCodeFromNum(num) {
let seconds = parseInt(num);
let minutes = parseInt(seconds / 60);
seconds -= minutes * 60;
const hours = parseInt(minutes / 60);
minutes -= hours * 60;
if (hours === 0) return `${minutes}:${String(seconds % 60).padStart(2, 0)}`;
return `${String(hours).padStart(2, 0)}:${minutes}:${String(
seconds % 60
).padStart(2, 0)}`;
}
return (
<div className="audio-player" ref={audioPlayer}>
<div className="controls">
<div className="play-container">
<button
onClick={togglePlayPause}
className="play-pause-button"
>
{isPlaying ? (
<img src={pauseIcon} alt="Pause" width="30" />
) : (
<img src={playIcon} alt="Play" width="30" />
)}
</button>
</div>
<div className="time">
<div className="current">0:00</div>
<div className="divider">/</div>
<div className="length"></div>
</div>
{/* <div className="name">Music Song</div> */}
<div className="timeline" onClick={onClickTimeline}>
<div className="progress"></div>
</div>
<div className="volume-container">
<div className="volume-button" onClick={onVolumeButtonClick}>
<div className="volume">
{isMuted ? (
<FontAwesomeIcon icon="volume-off" width={30} height={30} />
) : (
<FontAwesomeIcon icon="volume-up" width={30} height={30} />
)}
</div>
</div>
<div className="volume-slider" onClick={onVolumeSliderClick}>
<div className="volume-percentage"></div>
</div>
</div>
</div>
</div>
)
}
export default JKAudioPlayer

View File

@ -8,6 +8,7 @@ import { useJamTrack } from '../../hooks/useJamTrack';
import JKSigningRetryConfirmModal from './JKSigningRetryConfirmModal';
import JKSigningEstimateTimeModal from './JKSigningEstimateTimeModal';
import { markMixdownActive } from '../../helpers/rest';
import JKAudioPlayer from './JKAudioPlayer';
const JKJamTrackPlayer = () => {
const [options, setOptions] = useState([]);
@ -127,11 +128,7 @@ const JKJamTrackPlayer = () => {
<Row className="mt-2">
<Col>
{audioUrl && (
<figure>
<audio controls style={{ width: '100%' }} ref={audioRef}>
<source src={audioUrl} type={audioFileExtension(audioUrl)} />
</audio>
</figure>
<JKAudioPlayer audioUrl={audioUrl} />
)}
</Col>
</Row>

View File

@ -24,9 +24,10 @@ const JKJamTrackResourceLinks = ({jamTrack}) => {
</div>
<div className="mb-3">
<div>
<a target="_blank" href="https://jamkazam.com/jamtracks">
{/* <a target="_blank" href="/jamtracks">
{t('jamtrack.help_resources.jamtracks_home.title')}
</a>
</a> */}
<Link to="/jamtracks">{t('jamtrack.help_resources.jamtracks_home.title')}</Link>
</div>
{t('jamtrack.help_resources.jamtracks_home.description')}
</div>

View File

@ -24,7 +24,6 @@ const JKJamTrackShow = () => {
const userId = currentUser.id;
const resp = await getUserDetail({ id: userId });
const data = await resp.json();
console.log('user detail', data);
await postUserEvent({ name: 'jamtrack_web_player_open' });
if (!data.first_opened_jamtrack_web_player) {
setTimeout(async () => {

View File

@ -92,7 +92,6 @@ const JKJamTracksFilter = () => {
try {
const resp = await getJamTracks(options);
const data = await resp.json();
//console.log('jamtracks', data);
setJamTracks(prev => [...prev, ...data.jamtracks]);
setNextOffset(data.next);
setTotalJamTracks(data.count);

View File

@ -151,8 +151,6 @@ function JKPeopleFilter() {
};
const onSubmit = (data) => {
console.log("_DEBUG_ data", data)
console.log("_DEBUG_ page.current", page.current)
let genres = [];
let joined_within_days = '';
let active_within_days = '';
@ -197,7 +195,6 @@ function JKPeopleFilter() {
page.current = 0
submitPageQuery()
}else{
console.log("_DEBUG_ after loadingStatus changed. page.current", page.current, hasNextPage(), offset)
if (page.current === 1 && hasNextPage()) {
dispatch(preFetchPeople({ data: params.current, offset, limit: perPageLimit }));
page.current += 1;

View File

@ -163,14 +163,14 @@ import {
faMusic,
faRecordVinyl,
faAddressCard,
faVolumeUp,
faSpinner,
faPlayCircle,
faPauseCircle,
faStopCircle,
faInfoCircle,
faDownload,
faVolumeOff,
faVolumeUp,
} from '@fortawesome/free-solid-svg-icons';
//import { faAcousticGuitar } from "../icons";
@ -303,6 +303,7 @@ library.add(
faPlayCircle,
faPauseCircle,
faStopCircle,
faVolumeOff,
// Brand
faFacebook,
@ -349,5 +350,5 @@ library.add(
farComment,
farBell,
//faAcousticGuitar,
);