1.解决Firefox浏览器 canvas太长无法绘制的问题 2.解决云端返回列表格式不一致问题

This commit is contained in:
amass 2023-06-21 14:17:10 +08:00
parent 8bd230ba0b
commit 69b07afc78
8 changed files with 56 additions and 36 deletions

View File

@ -1,7 +1,7 @@
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import { useSelector, useDispatch } from 'react-redux' import { useSelector, useDispatch } from 'react-redux'
import AppBar from './AppBar'; import AppBar from './AppBar';
import RecordList from './RecordList'; import RecordList from './components/RecordList';
import PlayerBar from './PlayerBar'; import PlayerBar from './PlayerBar';
import store from './business/store'; import store from './business/store';
import yzs from "./business/request.js"; import yzs from "./business/request.js";
@ -33,15 +33,24 @@ const theme = createTheme({
}, },
}); });
const lyricsBrowserStyle = {
marginTop: 16,
paddingBottom: 40,
padding: 24,
}
function fetchRecord(accessToken, record) { function fetchRecord(accessToken, record) {
yzs.download(accessToken, record.transResultUrl).then( if (record.transResultUrl) {
blob => blob.text() yzs.download(accessToken, record.transResultUrl).then(
).then(text => { blob => blob.text()
// console.log("type", record.type, text); ).then(text => {
let payload = record.type === 1 ? JSON.parse(text) : text; // console.log("type", record.type, text);
store.dispatch(setCurrentLyric(payload)); let payload = record.type === 1 ? JSON.parse(text) : text;
}); store.dispatch(setCurrentLyric(payload));
});
}
yzs.download(accessToken, record.audioUrl).then(blob => { yzs.download(accessToken, record.audioUrl).then(blob => {
store.dispatch(setCurrentBlob(URL.createObjectURL(blob))); store.dispatch(setCurrentBlob(URL.createObjectURL(blob)));
}); });
@ -96,8 +105,11 @@ export default function () {
const passportId = useSelector(state => state.user.passportId); const passportId = useSelector(state => state.user.passportId);
const currentTime = useSelector(state => state.recorder.currentTime); const currentTime = useSelector(state => state.recorder.currentTime);
const currentLyric = useSelector(state => state.recorder.currentLyric); const currentLyric = useSelector(state => state.recorder.currentLyric);
const currentIndex = useSelector(state => state.recorder.currentIndex);
const recordList = useSelector(state => state.recorder.list);
const [playerBarWidth, setPlayerBarWidth] = useState(0); const [playerBarWidth, setPlayerBarWidth] = useState(0);
const [open, setOpen] = useState(true); const [open, setOpen] = useState(true);
const [hasLyric, setHasLyric] = useState(true);
useEffect(() => { useEffect(() => {
if (passportId <= 0) return; if (passportId <= 0) return;
yzs.get_record_list(accessToken, passportId).then(list => { yzs.get_record_list(accessToken, passportId).then(list => {
@ -110,6 +122,14 @@ export default function () {
}); });
}, [passportId]); }, [passportId]);
useEffect(() => {
if (recordList.length <= 0) {
setHasLyric(false);
return;
}
setHasLyric((recordList.at(currentIndex).transResultUrl));
}, [currentIndex, currentLyric]);
const onClick = () => { const onClick = () => {
setOpen(!open); setOpen(!open);
setPlayerBarWidth(document.documentElement.clientWidth - 240 - 48); // 防止中途底部出现scrollbar setPlayerBarWidth(document.documentElement.clientWidth - 240 - 48); // 防止中途底部出现scrollbar
@ -138,13 +158,15 @@ export default function () {
<ThemeProvider theme={theme}> <ThemeProvider theme={theme}>
<CssBaseline /> <CssBaseline />
<AppBar /> <AppBar />
<RecordList open={open} fetchRecord={fetchRecord} /> <RecordList open={open} recordList={recordList} currentIndex={currentIndex} fetchRecord={fetchRecord} />
<ClickHanlde open={open} onClick={onClick} /> <ClickHanlde open={open} onClick={onClick} />
<Main open={open} <Main open={open}
onTransitionEnd={onTransitionEnd} onTransitionEnd={onTransitionEnd}
> >
<PlayerBar width={playerBarWidth} currentTime={currentTime} /> <PlayerBar width={playerBarWidth} currentTime={currentTime} />
<RecordLyrics currentLyric={currentLyric} currentTime={currentTime} /> {hasLyric ? <RecordLyrics style={lyricsBrowserStyle} currentLyric={currentLyric} currentTime={currentTime} /> :
<div style={lyricsBrowserStyle}
/>}
</Main> </Main>
</ThemeProvider> </ThemeProvider>
</Box > </Box >

View File

@ -5,7 +5,7 @@ import pauseIcon from "./assets/play.png";
import playIcon from "./assets/pause.png"; import playIcon from "./assets/pause.png";
import downloadIcon from "./assets/download.png"; import downloadIcon from "./assets/download.png";
import { setCurrentTime, setPauseState, togglePauseState, setCurrentWaveData } from "./business/recorderSlice.js" import { setCurrentTime, setPauseState, togglePauseState, setCurrentWaveData } from "./business/recorderSlice.js"
import { audioWaveData } from "./business/utilities" import { audioWaveData, sampleInterval } from "./business/utilities"
import ProgressBar from "./components/ProgressBar"; import ProgressBar from "./components/ProgressBar";
const durationFormat = (time) => { const durationFormat = (time) => {
@ -33,7 +33,7 @@ export default function ({ width, currentTime }) {
useEffect(() => { useEffect(() => {
if (currentBlob.length <= 0) return; if (currentBlob.length <= 0) return;
audioWaveData(currentBlob, (duration > 20 * 60) ? 200 : 100) audioWaveData(currentBlob, sampleInterval(duration))
.then(data => dispatch(setCurrentWaveData(data))); .then(data => dispatch(setCurrentWaveData(data)));
}, [duration]); }, [duration]);

View File

@ -1,6 +1,5 @@
import React from "react"; import React from "react";
import { Typography, Paper } from "@mui/material"; import { Typography, Paper } from "@mui/material";
import styles from './RecordLyrics.module.css';
import { useSelector, useDispatch } from 'react-redux' import { useSelector, useDispatch } from 'react-redux'
function isHighlight(currentTime, { start, end }) { function isHighlight(currentTime, { start, end }) {
@ -8,17 +7,15 @@ function isHighlight(currentTime, { start, end }) {
return (currentTime > start) && (currentTime <= end); return (currentTime > start) && (currentTime <= end);
} }
export default function ({ style, currentLyric, currentTime }) {
export default function ({ currentLyric, currentTime }) {
const currentIndex = useSelector(state => state.recorder.currentIndex); const currentIndex = useSelector(state => state.recorder.currentIndex);
const recordList = useSelector(state => state.recorder.list); const recordList = useSelector(state => state.recorder.list);
if (recordList.length === 0) return <React.Fragment />; if (recordList.length === 0) return <React.Fragment />;
return <Paper className={styles.lyricsBrowser}> return <Paper style={style}>
{recordList.at(currentIndex).type === 1 ? (typeof currentLyric === "object" ? currentLyric.map((lyric, index) => { {recordList.at(currentIndex).type === 1 ? (typeof currentLyric === "object" ? currentLyric.map((lyric, index) => {
return <div className={styles.lyricItem}> return <div style={{ paddingBottom: 40 }}>
<Typography align="left" color={isHighlight(currentTime, lyric) ? "red" : "black"}>{lyric.text}</Typography> <Typography align="left" color={isHighlight(currentTime, lyric) ? "red" : "black"}>{lyric.text}</Typography>
</div> </div>
}) : <React.Fragment />) : <div style={{ whiteSpace: "pre-wrap" }}>{typeof currentLyric === "string" ? currentLyric : ""}</div>} }) : <React.Fragment />) : <div style={{ whiteSpace: "pre-wrap" }}>{typeof currentLyric === "string" ? currentLyric : ""}</div>}

View File

@ -1,9 +0,0 @@
.lyricsBrowser {
margin-top: 16px;
padding-bottom: 40px;
padding: 24px;
}
.lyricItem {
padding-bottom: 40px;
}

View File

@ -183,10 +183,11 @@ const yzs = {
'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8', 'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8',
}, },
}).then(response => response.json()).then((json) => { }).then(response => response.json()).then((json) => {
console.log("flushToken: ", json.result.flushToken); if (json.returnCode != "uc_0000") {
throw json.message;
}
// console.log("flushToken: ", json.result.flushToken);
return json.result.flushToken; return json.result.flushToken;
}).catch(error => {
console.log(error);
}); });
}, },
dynamic_code_login: function (udid, userCell, phoneCode) { dynamic_code_login: function (udid, userCell, phoneCode) {

View File

@ -1,3 +1,12 @@
// 间隔多长时间取一个采样点
// duration 秒,有小数点
const sampleInterval = (duration) => {
let interval = (duration > 20 * 60) ? 200 : 100;
let isFirefox = window.navigator.userAgent.includes("Firefox");
if (isFirefox && (interval < 400)) interval = 400; // firefox canvas width 不能过长
return interval;
}
// interval 间隔ms采点 // interval 间隔ms采点
function audioWaveData(url, interval) { function audioWaveData(url, interval) {
if (url.length <= 0) return; if (url.length <= 0) return;
@ -24,4 +33,4 @@ function audioWaveData(url, interval) {
}); });
} }
export { audioWaveData }; export { sampleInterval, audioWaveData };

View File

@ -1,4 +1,6 @@
import { useRef, useCallback, useState, useEffect } from "react"; import { useRef, useCallback, useState, useEffect } from "react";
import { sampleInterval } from "../business/utilities"
import { useMemo } from "react";
const pointWidth = 2; const pointWidth = 2;
const pointMargin = 3; const pointMargin = 3;
@ -82,7 +84,7 @@ const paintCanvas = ({
// duration ms // duration ms
export default function ({ width, duration, currentTime, playing, seek, waveData }) { export default function ({ width, duration, currentTime, playing, seek, waveData }) {
const interval = (duration > 20 * 60 * 1000) ? 200 : 100; // ms const interval = useMemo(() => sampleInterval(duration / 1000), [duration]);
const container = useRef(null); const container = useRef(null);
const canvas = useRef(null); const canvas = useRef(null);
const [scrollLeft, setScrollLeft] = useState(0); const [scrollLeft, setScrollLeft] = useState(0);

View File

@ -8,16 +8,14 @@ import ListItemButton from '@mui/material/ListItemButton';
import ListItemText from '@mui/material/ListItemText'; import ListItemText from '@mui/material/ListItemText';
import Typography from '@mui/material/Typography'; import Typography from '@mui/material/Typography';
import Toolbar from '@mui/material/Toolbar'; import Toolbar from '@mui/material/Toolbar';
import { setCurrentIndex } from "./business/recorderSlice.js" import { setCurrentIndex } from "../business/recorderSlice.js"
import AccessTimeFilledIcon from '@mui/icons-material/AccessTimeFilled'; import AccessTimeFilledIcon from '@mui/icons-material/AccessTimeFilled';
const drawerWidth = 240; const drawerWidth = 240;
export default function ({ open, fetchRecord }) { export default function ({ open, recordList, currentIndex, fetchRecord }) {
const dispatch = useDispatch(); const dispatch = useDispatch();
const accessToken = useSelector(state => state.user.accessToken); const accessToken = useSelector(state => state.user.accessToken);
const currentIndex = useSelector(state => state.recorder.currentIndex);
const recordList = useSelector(state => state.recorder.list);
const onSelected = (event, index) => { const onSelected = (event, index) => {
console.log("onSelected", index, recordList.at(index).transResultUrl) console.log("onSelected", index, recordList.at(index).transResultUrl)
dispatch(setCurrentIndex(index)); dispatch(setCurrentIndex(index));