wip jamtrack player
This commit is contained in:
parent
5b750cc3d9
commit
7af01a6c61
|
|
@ -3313,6 +3313,21 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"@fingerprintjs/fingerprintjs": {
|
||||
"version": "4.4.3",
|
||||
"resolved": "https://registry.npmjs.org/@fingerprintjs/fingerprintjs/-/fingerprintjs-4.4.3.tgz",
|
||||
"integrity": "sha512-sm0ZmDp5Oeq8hQTf+bAHKsuuteVAYme/YOY9UPP/GrUBrR5Fzl1P5oOv6F5LvyBrO7qLjU5HQkfU0MmFte/8xA==",
|
||||
"requires": {
|
||||
"tslib": "^2.4.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"tslib": {
|
||||
"version": "2.6.3",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz",
|
||||
"integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"@fortawesome/fontawesome-common-types": {
|
||||
"version": "0.2.35",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-0.2.35.tgz",
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
"private": true,
|
||||
"dependencies": {
|
||||
"@farfetch/react-context-responsive": "^1.5.0",
|
||||
"@fingerprintjs/fingerprintjs": "^4.4.3",
|
||||
"@fortawesome/fontawesome-free": "^5.15.1",
|
||||
"@fortawesome/fontawesome-svg-core": "^1.2.30",
|
||||
"@fortawesome/free-brands-svg-icons": "^5.14.0",
|
||||
|
|
|
|||
|
|
@ -0,0 +1,252 @@
|
|||
import React, { useState, useEffect } from 'react';
|
||||
import { Table, Row, Col, Input, Button } from 'reactstrap';
|
||||
import JKInstrumentIcon from '../profile/JKInstrumentIcon';
|
||||
import Select from 'react-select';
|
||||
import { useForm, Controller } from 'react-hook-form';
|
||||
import { createMixdown } from '../../helpers/rest';
|
||||
|
||||
const JKCreateCustomMix = ({ jamTrack }) => {
|
||||
const [tracks, setTracks] = useState([]);
|
||||
//const [selectedTracks, setSelectedTracks] = useState([]);
|
||||
|
||||
const TEMPO_OPTIONS = [
|
||||
{ value: '0', label: 'Original tempo' },
|
||||
{ value: '-5', label: 'Slower by 5%' },
|
||||
{ value: '-10', label: 'Slower by 10%' },
|
||||
{ value: '-15', label: 'Slower by 15%' },
|
||||
{ value: '-20', label: 'Slower by 20%' },
|
||||
{ value: '-25', label: 'Slower by 25%' },
|
||||
{ value: '-30', label: 'Slower by 30%' },
|
||||
{ value: '-35', label: 'Slower by 35%' },
|
||||
{ value: '-40', label: 'Slower by 40%' },
|
||||
{ value: '-45', label: 'Slower by 45%' },
|
||||
{ value: '-50', label: 'Slower by 50%' },
|
||||
{ value: '-60', label: 'Slower by 60%' },
|
||||
{ value: '-70', label: 'Slower by 70%' },
|
||||
{ value: '-80', label: 'Slower by 80%' },
|
||||
{ value: '5', label: 'Faster by 5%' },
|
||||
{ value: '10', label: 'Faster by 10%' },
|
||||
{ value: '15', label: 'Faster by 15%' },
|
||||
{ value: '20', label: 'Faster by 20%' },
|
||||
{ value: '30', label: 'Faster by 30%' },
|
||||
{ value: '40', label: 'Faster by 40%' },
|
||||
{ value: '50', label: 'Faster by 50%' }
|
||||
];
|
||||
|
||||
const PITCH_OPTIONS = [
|
||||
{ value: '0', label: 'Original pitch' },
|
||||
{ value: '-1', label: 'Down 1 semitone' },
|
||||
{ value: '-2', label: 'Down 2 semitone' },
|
||||
{ value: '-3', label: 'Down 3 semitone' },
|
||||
{ value: '-4', label: 'Down 4 semitone' },
|
||||
{ value: '-5', label: 'Down 5 semitone' },
|
||||
{ value: '-6', label: 'Down 6 semitone' },
|
||||
{ value: '-7', label: 'Down 7 semitone' },
|
||||
{ value: '-8', label: 'Down 8 semitone' },
|
||||
{ value: '-9', label: 'Down 9 semitone' },
|
||||
{ value: '-10', label: 'Down 10 semitone' },
|
||||
{ value: '-11', label: 'Down 11 semitone' },
|
||||
{ value: '-12', label: 'Down 12 semitone' },
|
||||
{ value: '1', label: 'Up 1 semitone' },
|
||||
{ value: '2', label: 'Up 2 semitone' },
|
||||
{ value: '3', label: 'Up 3 semitone' },
|
||||
{ value: '4', label: 'Up 4 semitone' },
|
||||
{ value: '5', label: 'Up 5 semitone' },
|
||||
{ value: '6', label: 'Up 6 semitone' },
|
||||
{ value: '7', label: 'Up 7 semitone' },
|
||||
{ value: '8', label: 'Up 8 semitone' },
|
||||
{ value: '9', label: 'Up 9 semitone' },
|
||||
{ value: '10', label: 'Up 10 semitone' },
|
||||
{ value: '11', label: 'Up 11 semitone' },
|
||||
{ value: '12', label: 'Up 12 semitone' }
|
||||
];
|
||||
|
||||
const {
|
||||
control,
|
||||
handleSubmit,
|
||||
formState: { errors },
|
||||
setValue,
|
||||
getValues
|
||||
} = useForm({
|
||||
defaultValues: {
|
||||
mixName: '',
|
||||
tempo: {
|
||||
value: '0',
|
||||
label: 'Original tempo'
|
||||
},
|
||||
pitch: {
|
||||
value: '0',
|
||||
label: 'Original pitch'
|
||||
},
|
||||
mixdownTracks: []
|
||||
}
|
||||
});
|
||||
const onSubmit = data => {
|
||||
console.log('data', data);
|
||||
const _tracks = [];
|
||||
let countIn = false;
|
||||
const selectedTracks = getValues('mixdownTracks');
|
||||
tracks.forEach(track => {
|
||||
const muted = selectedTracks.includes(track.id);
|
||||
if (track.id === 'count-in') {
|
||||
if (countIn === false) {
|
||||
countIn = !muted;
|
||||
}
|
||||
} else {
|
||||
_tracks.push({
|
||||
id: track.id,
|
||||
mute: selectedTracks.includes(track.id)
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
setValue('mixdownTracks', _tracks);
|
||||
|
||||
const mixData = {
|
||||
jamTrackID: jamTrack.id,
|
||||
name: data.mixName,
|
||||
settings: { speed: data.tempo.value, pitch: data.pitch.value, 'count-in': countIn, tracks: _tracks }
|
||||
};
|
||||
|
||||
console.log('mixData', mixData);
|
||||
|
||||
createMixdown(mixData)
|
||||
.then(response => {
|
||||
console.log('mixdown created', response);
|
||||
//TODO: add this mixdown to global state of jamtrack mixdowns
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('mixdown create error', error);
|
||||
});
|
||||
};
|
||||
|
||||
const toggleTrack = e => {
|
||||
const trackId = e.target.value;
|
||||
const selectedTracks = getValues('mixdownTracks');
|
||||
if (selectedTracks.includes(trackId)) {
|
||||
//setSelectedTracks(selectedTracks.filter(track => track !== trackId));
|
||||
setValue('mixdownTracks', selectedTracks.filter(track => track !== trackId));
|
||||
} else {
|
||||
//setSelectedTracks([...selectedTracks, trackId]);
|
||||
setValue('mixdownTracks', [...selectedTracks, trackId]);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (jamTrack) {
|
||||
setTracks(jamTrack.tracks.filter(track => track.track_type === 'Track' || track.track_type === 'Click'));
|
||||
}
|
||||
}, [jamTrack]);
|
||||
|
||||
const trackName = track => {
|
||||
if (track.track_type === 'Track' || track.track_type === 'Click') {
|
||||
if (track.track_type === 'Click') {
|
||||
return 'Clicktrack';
|
||||
} else if (track.instrument) {
|
||||
const instrumentDescription = track.instrument.description;
|
||||
let part = '';
|
||||
if (track.part && track.part !== instrumentDescription) {
|
||||
part = `(${track.part})`;
|
||||
}
|
||||
return `${instrumentDescription} ${part}`;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<p>
|
||||
Mute any tracks you like. Adjust the pitch or tempo of playback. Then give your mix a descriptive name, and
|
||||
click the Create Mix button. It will take few minutes for us to create your custom mix.
|
||||
</p>
|
||||
|
||||
<form onSubmit={handleSubmit(onSubmit)}>
|
||||
<Row>
|
||||
<Col>
|
||||
<Table striped bordered className="fs--1">
|
||||
<thead className="bg-200 text-900">
|
||||
<tr>
|
||||
<th>Tracks {tracks.length > 0 && <>({tracks.length})</>}</th>
|
||||
<th>Mute</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{tracks &&
|
||||
tracks.map((track, index) => (
|
||||
<tr key={index}>
|
||||
<td>
|
||||
<JKInstrumentIcon instrumentId={track.instrumentId} instrumentName={trackName(track)} />
|
||||
<span className="ml-1">{trackName(track)}</span>
|
||||
</td>
|
||||
<td>
|
||||
<input type="checkbox" value={track.id} onClick={toggleTrack} />
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</Table>
|
||||
<Controller
|
||||
name="mixdownTracks"
|
||||
control={control}
|
||||
rules={{
|
||||
required: 'Select at least one track to create a mix'
|
||||
}}
|
||||
render={({ field }) => <Input type='hidden' {...field} />}
|
||||
/>
|
||||
{errors.mixdownTracks && (
|
||||
<div className="text-danger">
|
||||
<small>{errors.mixdownTracks.message}</small>
|
||||
</div>
|
||||
)}
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
<Row className="mb-1">
|
||||
<Col>Tempo</Col>
|
||||
<Col>
|
||||
<Controller
|
||||
name="tempo"
|
||||
control={control}
|
||||
render={({ field }) => <Select {...field} options={TEMPO_OPTIONS} />}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row className="mb-1">
|
||||
<Col>Pitch</Col>
|
||||
<Col>
|
||||
<Controller
|
||||
name="pitch"
|
||||
control={control}
|
||||
render={({ field }) => <Select {...field} options={PITCH_OPTIONS} />}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row className="mb-1">
|
||||
<Col>Mix Name</Col>
|
||||
<Col>
|
||||
<Controller
|
||||
name="mixName"
|
||||
control={control}
|
||||
rules={{
|
||||
required: 'Mix name is required'
|
||||
}}
|
||||
render={({ field }) => <Input {...field} />}
|
||||
/>
|
||||
{errors.mixName && (
|
||||
<div className="text-danger">
|
||||
<small>{errors.mixName.message}</small>
|
||||
</div>
|
||||
)}
|
||||
</Col>
|
||||
</Row>
|
||||
<Row>
|
||||
<Col>
|
||||
<Button>Create Mix</Button>
|
||||
</Col>
|
||||
</Row>
|
||||
</form>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default JKCreateCustomMix;
|
||||
|
|
@ -6,6 +6,8 @@ import { Card, CardBody, Row, Col, Progress } from 'reactstrap';
|
|||
import FalconCardHeader from '../common/FalconCardHeader';
|
||||
import { getJamTrack, getUserDetail, postUserEvent, userOpenedJamTrackWebPlayer } from '../../helpers/rest';
|
||||
import JKJamTrackPlayer from './JKJamTrackPlayer';
|
||||
import JKMyJamTrackMixes from './JKMyJamTrackMixes';
|
||||
import JKCreateCustomMix from './JKCreateCustomMix';
|
||||
import { useAuth } from '../../context/UserAuth';
|
||||
|
||||
const JKJamTrack = () => {
|
||||
|
|
@ -23,6 +25,7 @@ const JKJamTrack = () => {
|
|||
setLoading(true);
|
||||
const resp = await getJamTrack({ id });
|
||||
const data = await resp.json();
|
||||
console.log('jam track 123', data);
|
||||
setJamTrack(data);
|
||||
} catch (error) {
|
||||
console.log('Error when fetching jam track', error);
|
||||
|
|
@ -58,26 +61,24 @@ const JKJamTrack = () => {
|
|||
fetchJamTrack();
|
||||
}, [id]);
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<Row>
|
||||
<Col>
|
||||
<Card className="mx-auto mb-4">
|
||||
<FalconCardHeader title={t('jamtrack.player.title')} titleClass="font-weight-semi-bold" />
|
||||
<CardBody className="pt-3">
|
||||
{jamTrack && <JKJamTrackPlayer jamTrack={jamTrack} />}
|
||||
</CardBody>
|
||||
<CardBody className="pt-3">{jamTrack && <JKJamTrackPlayer jamTrack={jamTrack} />}</CardBody>
|
||||
</Card>
|
||||
<Card className="mx-auto">
|
||||
<FalconCardHeader title={t('jamtrack.my_mixes.title')} titleClass="font-weight-semi-bold" />
|
||||
<CardBody className="pt-3" />
|
||||
<CardBody className="pt-3">{jamTrack && <JKMyJamTrackMixes jamTrack={jamTrack} />}</CardBody>
|
||||
</Card>
|
||||
</Col>
|
||||
<Col>
|
||||
<Card className="mx-auto">
|
||||
<FalconCardHeader title={t('jamtrack.create_mix.title')} titleClass="font-weight-semi-bold" />
|
||||
<CardBody className="pt-3" />
|
||||
<CardBody className="pt-3">
|
||||
{ jamTrack && <JKCreateCustomMix jamTrack={jamTrack} /> }
|
||||
</CardBody>
|
||||
</Card>
|
||||
</Col>
|
||||
<Col />
|
||||
|
|
|
|||
|
|
@ -0,0 +1,101 @@
|
|||
import React, { useState, useEffect, useMemo } from 'react';
|
||||
import Select from 'react-select';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import { Row, Col } from 'reactstrap';
|
||||
import PropTypes from 'prop-types';
|
||||
import { markMixdownActive } from '../../helpers/rest';
|
||||
import useJamTrackAudio from '../../hooks/useJamTrackAudio';
|
||||
|
||||
const JKJamTrackPlayer = ({ jamTrack }) => {
|
||||
const [mixes, setMixes] = useState([]);
|
||||
const [options, setOptions] = useState([]);
|
||||
const [selectedMix, setSelectedMix] = useState(null);
|
||||
const { audioUrls, loadJamTrack } = useJamTrackAudio(jamTrack);
|
||||
|
||||
const handleChange = selectedOption => {
|
||||
const mix = mixes.find(mix => mix.value === selectedOption.value);
|
||||
setSelectedMix(mix);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (jamTrack) {
|
||||
console.log('_JamTrack_ jamTrack', jamTrack);
|
||||
const _opts = jamTrack.mixdowns.map(mix => ({ value: mix.id, label: mix.name }));
|
||||
_opts.unshift({ value: 'original', label: 'Original' });
|
||||
setOptions(_opts);
|
||||
|
||||
//set the default mix to the original
|
||||
const activeMix = jamTrack.mixdowns.find(mix => mix.id === jamTrack.last_mixdown_id)
|
||||
|
||||
console.log('_JamTrack_ activeMix', activeMix);
|
||||
|
||||
setSelectedMix(activeMix);
|
||||
}
|
||||
}, [jamTrack]);
|
||||
|
||||
const activateMasterTrack = async () => {
|
||||
console.log('playing original');
|
||||
await markMixdownActive({ id: jamTrack.id, mixdown_id: null });
|
||||
await loadJamTrack();
|
||||
};
|
||||
|
||||
const activateCustomMix = async () => {
|
||||
console.log('playing mix', selectedMix.value);
|
||||
try {
|
||||
await markMixdownActive({ id: jamTrack.id, mixdown_id: selectedMix.value });
|
||||
await loadJamTrack();
|
||||
}catch(error){
|
||||
console.log('Error when activating custom mix', error);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!selectedMix) {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('_JamTrack_ selectedMix', selectedMix);
|
||||
|
||||
if (selectedMix.value === 'original') {
|
||||
//console.log('_JAMTRACK_ activating master track');
|
||||
activateMasterTrack().then(() => {
|
||||
//TODO: commiunicate with the client back end. Following is copied from the Rails front end
|
||||
//SessionActions.mixdownActive({id:null})
|
||||
});
|
||||
} else {
|
||||
//console.log('_JAMTRACK_ activating custom mix:', selectedMix);
|
||||
activateCustomMix().then(() => {
|
||||
//TODO: commiunicate with the client back end. Following is copied from the Rails front end
|
||||
//context.jamClient.JamTrackStopPlay();
|
||||
//SessionActions.mixdownActive(mixdown)
|
||||
});
|
||||
}
|
||||
}, [selectedMix]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Select options={mixes} placeholder="Select Mix" onChange={handleChange} value={selectedMix} />
|
||||
{ JSON.stringify(audioUrls)}
|
||||
<Row className='mt-2'>
|
||||
<Col>
|
||||
{audioUrls.length > 0 && (
|
||||
<figure>
|
||||
<audio controls style={{ width: '100%'}}>
|
||||
{audioUrls.map((url, index) => (
|
||||
<source key={index} src={url} type={`audio/${url.split('.').pop()}`} />
|
||||
))}
|
||||
</audio>
|
||||
</figure>
|
||||
)}
|
||||
</Col>
|
||||
</Row>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
JKJamTrackPlayer.propTypes = {
|
||||
jamTrack: PropTypes.object.isRequired
|
||||
};
|
||||
|
||||
export default JKJamTrackPlayer;
|
||||
|
|
@ -1,73 +1,87 @@
|
|||
import React, { useState, useEffect, useMemo } from 'react';
|
||||
import React, { useState, useEffect, useRef } from 'react';
|
||||
import Select from 'react-select';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import { Row, Col } from 'reactstrap';
|
||||
import PropTypes from 'prop-types';
|
||||
import { markMixdownActive } from '../../helpers/rest';
|
||||
import useJamTrackAudio from '../../hooks/useJamTrackAudio';
|
||||
import FingerprintJS from '@fingerprintjs/fingerprintjs';
|
||||
|
||||
const JKJamTrackPlayer = ({ jamTrack }) => {
|
||||
const [mixes, setMixes] = useState([]);
|
||||
const [selectedMix, setSelectedMix] = useState(null);
|
||||
const { audioUrls } = useJamTrackAudio(jamTrack);
|
||||
|
||||
const handleChange = selectedOption => {
|
||||
setSelectedMix(selectedOption);
|
||||
};
|
||||
const [options, setOptions] = useState([]);
|
||||
const [selectedOption, setSelectedOption] = useState(null);
|
||||
const fpPromise = FingerprintJS.load();
|
||||
const [audioUrl, setAudioUrl] = useState(null);
|
||||
const audioRef = useRef(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (jamTrack) {
|
||||
const mixes = jamTrack.mixdowns.map(mix => ({ value: mix.id, label: mix.name, mix }));
|
||||
mixes.unshift({ value: 'original', label: 'Original', jamTrack });
|
||||
setMixes(mixes);
|
||||
|
||||
//set the default mix to the original
|
||||
setSelectedMix(mixes[0]);
|
||||
console.log('_JamTrackPlayer_ jamTrack', jamTrack);
|
||||
const opts = jamTrack.mixdowns.map(mix => ({ value: mix.id, label: mix.name }));
|
||||
opts.unshift({ value: 'original', label: 'Original' });
|
||||
setOptions(opts);
|
||||
if (jamTrack.last_mixdown_id) {
|
||||
setSelectedOption(opts.find(opt => opt.value === jamTrack.last_mixdown_id));
|
||||
} else {
|
||||
setSelectedOption(opts[0]);
|
||||
}
|
||||
}
|
||||
}, [jamTrack]);
|
||||
|
||||
const activateMasterTrack = async () => {
|
||||
console.log('playing original');
|
||||
await markMixdownActive({ id: selectedMix.jamTrack.id, mixdown_id: null });
|
||||
};
|
||||
|
||||
const activateCustomMix = async () => {
|
||||
console.log('playing mix', selectedMix.value);
|
||||
await markMixdownActive({ id: selectedMix.jamTrack.id, mixdown_id: selectedMix.value });
|
||||
const handleOnChange = selectedOption => {
|
||||
const option = options.find(opt => opt.value === selectedOption.value);
|
||||
setSelectedOption(option);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!selectedMix) {
|
||||
if (!selectedOption) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (selectedMix.value === 'original') {
|
||||
console.log('activating master track');
|
||||
activateMasterTrack().then(() => {
|
||||
//TODO: commiunicate with the client back end. Following is copied from the Rails front end
|
||||
//SessionActions.mixdownActive({id:null})
|
||||
});
|
||||
|
||||
console.log('_JamTrackPlayer_ selectedOption', selectedOption);
|
||||
|
||||
if (selectedOption.value === 'original') {
|
||||
const audioUrl = getMasterTrack();
|
||||
setAudioUrl(audioUrl);
|
||||
if(audioRef.current)
|
||||
audioRef.current.load();
|
||||
} else {
|
||||
console.log('activating custom mix:', selectedMix.value);
|
||||
activateCustomMix().then(() => {
|
||||
//TODO: commiunicate with the client back end. Following is copied from the Rails front end
|
||||
//context.jamClient.JamTrackStopPlay();
|
||||
//SessionActions.mixdownActive(mixdown)
|
||||
//it's a mixdown
|
||||
getMixdown().then(audioUrl => {
|
||||
setAudioUrl(audioUrl);
|
||||
if(audioRef.current)
|
||||
audioRef.current.load();
|
||||
});
|
||||
}
|
||||
}, [selectedMix]);
|
||||
}, [selectedOption]);
|
||||
|
||||
const getMasterTrack = () => {
|
||||
const masterTrack = jamTrack.tracks.find(track => track.track_type === 'Master');
|
||||
console.log('_JamTrackPlayer_ master', masterTrack);
|
||||
if (masterTrack) {
|
||||
const audioUrl = masterTrack.preview_mp3_url;
|
||||
return audioUrl;
|
||||
}
|
||||
};
|
||||
|
||||
const getMixdown = async () => {
|
||||
const activeMix = jamTrack.mixdowns.find(mix => mix.id === selectedOption.value);
|
||||
const fp = await fpPromise;
|
||||
const result = await fp.get();
|
||||
const audioUrl =
|
||||
process.env.REACT_APP_API_BASE_URL +
|
||||
`/mixdowns/${activeMix.id}/download.mp3?file_type=mp3&sample_rate=48&mark=${result.visitorId}`;
|
||||
return audioUrl;
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Select options={mixes} placeholder="Select Mix" onChange={handleChange} value={selectedMix} />
|
||||
<Row className='mt-2'>
|
||||
<Select options={options} placeholder="Select Mix" onChange={handleOnChange} value={selectedOption} />
|
||||
<Row className="mt-2">
|
||||
<Col>
|
||||
{audioUrls.length > 0 && (
|
||||
{audioUrl && (
|
||||
<figure>
|
||||
<audio controls style={{ width: '100%'}}>
|
||||
{audioUrls.map((url, index) => (
|
||||
<source key={index} src={url} type={`audio/${url.split('.').pop()}`} />
|
||||
))}
|
||||
<audio controls style={{ width: '100%' }} ref={audioRef}>
|
||||
<source src={audioUrl} type={`audio/${audioUrl.split('.').pop()}`} />
|
||||
</audio>
|
||||
</figure>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,78 @@
|
|||
import React, { useState, useEffect } from 'react';
|
||||
import { Table } from 'reactstrap';
|
||||
import FingerprintJS from '@fingerprintjs/fingerprintjs';
|
||||
|
||||
const JKMyJamTrackMixes = ({ jamTrack }) => {
|
||||
const [mixes, setMixes] = useState([]);
|
||||
const fpPromise = FingerprintJS.load();
|
||||
|
||||
useEffect(() => {
|
||||
if(!jamTrack) {
|
||||
return;
|
||||
}
|
||||
setMixes(jamTrack.mixdowns)
|
||||
}, []);
|
||||
|
||||
const downloadJamTrack = async () => {
|
||||
console.log('Downloading JamTrack');
|
||||
if(!jamTrack.can_download) {
|
||||
console.log('Cannot download JamTrack');
|
||||
return
|
||||
}
|
||||
const fp = await fpPromise;
|
||||
const result = await fp.get();
|
||||
const redirectTo = `${process.env.REACT_APP_API_BASE_URL}/jamtracks/${jamTrack.id}/stems/master/download.mp3?file_type=mp3&download=1&mark=${result.visitorId}`;
|
||||
window.open(redirectTo, '_blank');
|
||||
}
|
||||
|
||||
const downloadMix = async (mixId) => {
|
||||
console.log('Download mixdown')
|
||||
const mixdown = mixes.find(m => m.id === mixId);
|
||||
const mixdownPackage = mixdown.packages.find(p => p.file_type === 'mp3');
|
||||
if(mixdownPackage?.signing_state == 'SIGNED'){
|
||||
const fp = await fpPromise;
|
||||
const result = await fp.get();
|
||||
const redirectTo = `${process.env.REACT_APP_API_BASE_URL}/mixdowns/${mixdown.id}/download.mp3?file_type=mp3&sample_rate=48&download=1&mark=${result.visitorId}`
|
||||
window.open(redirectTo, '_blank');
|
||||
}
|
||||
}
|
||||
|
||||
const deleteMix = (mixId) => {
|
||||
if(window.confirm("Delete this custom mix?")){
|
||||
console.log("Deleting mixdown", mixId)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<p>You can save a maximum of 5 mixes on JamKazam. If you need to make more mixes, download a mix to save it, then delete it to make more room</p >
|
||||
<Table striped bordered className="fs--1" >
|
||||
<thead className="bg-200 text-900">
|
||||
<tr>
|
||||
<th>Mix</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Full JamTrack</td>
|
||||
<td>
|
||||
<button onClick={downloadJamTrack}>Download</button>
|
||||
</td>
|
||||
</tr>
|
||||
{mixes.map(mix => (
|
||||
<tr key={mix.id}>
|
||||
<td>{mix.name}</td>
|
||||
<td>
|
||||
<button onClick={() => downloadMix(mix.id)}>Download</button>
|
||||
<button onClick={() => deleteMix(mix.id)}>Delete</button>
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</Table>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default JKMyJamTrackMixes;
|
||||
|
|
@ -512,3 +512,14 @@ export const markMixdownActive = options => {
|
|||
.catch(error => reject(error));
|
||||
});
|
||||
}
|
||||
|
||||
export const createMixdown = options => {
|
||||
return new Promise((resolve, reject) => {
|
||||
apiFetch(`/mixdowns`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(options)
|
||||
})
|
||||
.then(response => resolve(response))
|
||||
.catch(error => reject(error));
|
||||
});
|
||||
}
|
||||
|
|
@ -1,33 +1,63 @@
|
|||
import { useState, useEffect } from 'react';
|
||||
import { getJamTrack } from '../helpers/rest';
|
||||
import FingerprintJS from '@fingerprintjs/fingerprintjs';
|
||||
|
||||
const useJamTrackAudio = (jamTrack) => {
|
||||
const useJamTrackAudio = jamTrack => {
|
||||
const [audioUrls, setAudioUrls] = useState([]);
|
||||
const [jamTrackRecord, setJamTrackRecord] = useState(jamTrack);
|
||||
const fpPromise = FingerprintJS.load();
|
||||
|
||||
const loadMedia = () => {
|
||||
const activeMixdown = jamTrack.mixdowns.find(mixdown => mixdown.id === jamTrack.last_mixdown_id)
|
||||
const activeStem = jamTrack.tracks.find(stem => stem.id === jamTrack.last_stem_id);
|
||||
const loadJamTrack = async () => {
|
||||
//console.log('_JAMTRACK_ loading jam track');
|
||||
try {
|
||||
const resp = await getJamTrack({ id: jamTrack.id });
|
||||
const data = await resp.json();
|
||||
setJamTrackRecord(data);
|
||||
} catch (error) {
|
||||
console.log('Error when fetching jam track', error);
|
||||
}
|
||||
};
|
||||
|
||||
if ( activeStem ) {
|
||||
} else if ( activeMixdown ) {
|
||||
|
||||
const updateMedia = async () => {
|
||||
//console.log('_JAMTRACK_ updating media', jamTrackRecord);
|
||||
const activeMixdown = jamTrackRecord.mixdowns.find(mixdown => mixdown.id === jamTrackRecord.last_mixdown_id);
|
||||
const activeStem = jamTrackRecord.tracks.find(stem => stem.id === jamTrackRecord.last_stem_id);
|
||||
|
||||
|
||||
if (activeStem) {
|
||||
//console.log('_JAMTRACK_ this is a stem', activeStem);
|
||||
} else if (activeMixdown) {
|
||||
//console.log('_JAMTRACK_ this is a mixdown', activeMixdown);
|
||||
const fp = await fpPromise;
|
||||
const result = await fp.get();
|
||||
const audioUrl =
|
||||
process.env.REACT_APP_API_BASE_URL +
|
||||
`/mixdowns/${activeMixdown.id}/download.mp3?file_type=mp3&sample_rate=48&mark=${result.visitorId}`;
|
||||
console.log('mixdown audioUrl', audioUrl);
|
||||
setAudioUrls([audioUrl]);
|
||||
} else if (jamTrack) {
|
||||
const masterTrack = jamTrack.tracks.find(track => track.track_type === 'Master');
|
||||
//console.log('_JAMTRACK_ this is the master track', masterTrack);
|
||||
if (masterTrack) {
|
||||
setAudioUrls([masterTrack.preview_mp3_url]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
// useEffect(() => {
|
||||
// if (!jamTrack) {
|
||||
// return;
|
||||
// }
|
||||
// loadJamTrack();
|
||||
// }, [jamTrack]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!jamTrack) {
|
||||
return;
|
||||
if (jamTrackRecord) {
|
||||
updateMedia();
|
||||
}
|
||||
loadMedia();
|
||||
|
||||
}, [jamTrack]);
|
||||
}, [jamTrackRecord]);
|
||||
|
||||
return { audioUrls };
|
||||
return { audioUrls, loadJamTrack };
|
||||
};
|
||||
|
||||
export default useJamTrackAudio;
|
||||
export default useJamTrackAudio;
|
||||
|
|
|
|||
Loading…
Reference in New Issue