Added Online converter
This commit is contained in:
parent
daab4fa3d8
commit
20410b3bda
5 changed files with 90 additions and 11 deletions
|
@ -5,11 +5,14 @@
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/core": "^7.13.13",
|
"@babel/core": "^7.13.13",
|
||||||
|
"@ffmpeg/core": "^0.9.0",
|
||||||
|
"@ffmpeg/ffmpeg": "^0.9.8",
|
||||||
"@material-ui/core": "^4.11.3",
|
"@material-ui/core": "^4.11.3",
|
||||||
"@material-ui/icons": "^4.11.2",
|
"@material-ui/icons": "^4.11.2",
|
||||||
"@testing-library/jest-dom": "^4.2.4",
|
"@testing-library/jest-dom": "^4.2.4",
|
||||||
"@testing-library/react": "^9.5.0",
|
"@testing-library/react": "^9.5.0",
|
||||||
"@testing-library/user-event": "^7.2.1",
|
"@testing-library/user-event": "^7.2.1",
|
||||||
|
"fork-me-on-github": "^1.0.6",
|
||||||
"react": "^16.14.0",
|
"react": "^16.14.0",
|
||||||
"react-copy-to-clipboard": "^5.0.3",
|
"react-copy-to-clipboard": "^5.0.3",
|
||||||
"react-dom": "^16.14.0",
|
"react-dom": "^16.14.0",
|
||||||
|
|
|
@ -25,7 +25,7 @@ import { FilePicker } from '../src/Components'
|
||||||
import { CopyToClipboard } from 'react-copy-to-clipboard';
|
import { CopyToClipboard } from 'react-copy-to-clipboard';
|
||||||
|
|
||||||
import ControlledAccordions from './ControlledAccordions'
|
import ControlledAccordions from './ControlledAccordions'
|
||||||
|
import OnlineConverter from "./OnlineConverter";
|
||||||
import 'react-notifications-component/dist/theme.css'
|
import 'react-notifications-component/dist/theme.css'
|
||||||
|
|
||||||
import ReactNotification from 'react-notifications-component'
|
import ReactNotification from 'react-notifications-component'
|
||||||
|
@ -179,7 +179,7 @@ class ChecksumResolver extends React.Component {
|
||||||
// return;
|
// return;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
this.setState({ fileName: file.name });
|
this.setState({ fileName: file.name, file:file });
|
||||||
const slic = file.slice(653, 653 + 20);
|
const slic = file.slice(653, 653 + 20);
|
||||||
const results = this.buf2hex(await slic.arrayBuffer());
|
const results = this.buf2hex(await slic.arrayBuffer());
|
||||||
this.setChecksum(results)
|
this.setChecksum(results)
|
||||||
|
@ -189,7 +189,7 @@ class ChecksumResolver extends React.Component {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { classes } = this.props;
|
const { classes } = this.props;
|
||||||
const { checksum, activationBytes, fileName } = this.state;
|
const { checksum, activationBytes, fileName, file } = this.state;
|
||||||
|
|
||||||
// const { files, onClick, errors, HiddenFileInput } = useFilePicker({
|
// const { files, onClick, errors, HiddenFileInput } = useFilePicker({
|
||||||
// maxFileSize: 1000000,
|
// maxFileSize: 1000000,
|
||||||
|
@ -296,6 +296,7 @@ class ChecksumResolver extends React.Component {
|
||||||
<ControlledAccordions
|
<ControlledAccordions
|
||||||
fileName={fileName}
|
fileName={fileName}
|
||||||
activationBytes={activationBytes}
|
activationBytes={activationBytes}
|
||||||
|
file ={file}
|
||||||
/>
|
/>
|
||||||
<Box mt={1}>
|
<Box mt={1}>
|
||||||
<this.Copyright />
|
<this.Copyright />
|
||||||
|
|
|
@ -21,6 +21,7 @@ import { Radio, RadioGroup } from '@material-ui/core';
|
||||||
import FormControlLabel from '@material-ui/core/FormControlLabel';
|
import FormControlLabel from '@material-ui/core/FormControlLabel';
|
||||||
import FormControl from '@material-ui/core/FormControl';
|
import FormControl from '@material-ui/core/FormControl';
|
||||||
import FormLabel from '@material-ui/core/FormLabel';
|
import FormLabel from '@material-ui/core/FormLabel';
|
||||||
|
import OnlineConverter from "./OnlineConverter";
|
||||||
|
|
||||||
class ControlledAccordions extends React.Component {
|
class ControlledAccordions extends React.Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
|
@ -71,7 +72,7 @@ class ControlledAccordions extends React.Component {
|
||||||
{ os: "osx", cmd: "./ffmpeg", discriminator: '\'' },
|
{ os: "osx", cmd: "./ffmpeg", discriminator: '\'' },
|
||||||
];
|
];
|
||||||
|
|
||||||
let fileNameWithoutExtension = fileName.split('.')[0];
|
let fileNameWithoutExtension = fileName.split('.').slice(0, -1).join('.');
|
||||||
fileNameWithoutExtension = fileNameWithoutExtension == 'input' ? 'output' : fileNameWithoutExtension;
|
fileNameWithoutExtension = fileNameWithoutExtension == 'input' ? 'output' : fileNameWithoutExtension;
|
||||||
|
|
||||||
const osMap = osToBinMaps.filter(x => x.os == operatingSystem)[0];
|
const osMap = osToBinMaps.filter(x => x.os == operatingSystem)[0];
|
||||||
|
@ -89,10 +90,8 @@ class ControlledAccordions extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { classes } = this.props;
|
const { classes, file, activationBytes} = this.props;
|
||||||
const { expanded, outputFormat, operatingSystem } = this.state;
|
const { expanded, outputFormat, operatingSystem } = this.state;
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classes.root}>
|
<div className={classes.root}>
|
||||||
<Accordion expanded={expanded === 'panel2'} onChange={this.handleChange('panel2')}>
|
<Accordion expanded={expanded === 'panel2'} onChange={this.handleChange('panel2')}>
|
||||||
|
@ -101,10 +100,10 @@ class ControlledAccordions extends React.Component {
|
||||||
aria-controls="panel2bh-content"
|
aria-controls="panel2bh-content"
|
||||||
id="panel2bh-header"
|
id="panel2bh-header"
|
||||||
>
|
>
|
||||||
<Typography className={classes.heading}>Command</Typography>
|
<Typography className={classes.heading}>Command and Convert</Typography>
|
||||||
<Typography className={classes.secondaryHeading}>
|
<Typography className={classes.secondaryHeading}>
|
||||||
Generate ffmpeg command
|
Generate ffmpeg command or convert in browser
|
||||||
</Typography>
|
</Typography>
|
||||||
</AccordionSummary>
|
</AccordionSummary>
|
||||||
<AccordionDetails style={{ display: 'block' }}>
|
<AccordionDetails style={{ display: 'block' }}>
|
||||||
<OutputFormatSelection
|
<OutputFormatSelection
|
||||||
|
@ -144,6 +143,9 @@ class ControlledAccordions extends React.Component {
|
||||||
}}
|
}}
|
||||||
|
|
||||||
/>
|
/>
|
||||||
|
<OnlineConverter file={file}
|
||||||
|
activationBytes={activationBytes}
|
||||||
|
outputFormat = {outputFormat}/>
|
||||||
</AccordionDetails>
|
</AccordionDetails>
|
||||||
</Accordion>
|
</Accordion>
|
||||||
</div>
|
</div>
|
||||||
|
|
67
src/OnlineConverter.jsx
Normal file
67
src/OnlineConverter.jsx
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
import React, {useState} from "react";
|
||||||
|
import Button from '@material-ui/core/Button';
|
||||||
|
import { createFFmpeg, fetchFile } from '@ffmpeg/ffmpeg';
|
||||||
|
import Typography from "@material-ui/core/Typography";
|
||||||
|
|
||||||
|
const downloadFile= (data, outputFileName, outputFormat) => {
|
||||||
|
let a = document.createElement("a");
|
||||||
|
document.body.appendChild(a);
|
||||||
|
const blob = new Blob([data.buffer], { type: 'audio/'+outputFormat});
|
||||||
|
const url = window.URL.createObjectURL(blob);
|
||||||
|
a.href = url;
|
||||||
|
a.download = outputFileName;
|
||||||
|
a.click();
|
||||||
|
window.URL.revokeObjectURL(url);
|
||||||
|
}
|
||||||
|
const getCommandAsList = (file, outputFileName, outputFormat, activationBytes) =>{
|
||||||
|
const outputFormatCodecMaps = [
|
||||||
|
{ format: "m4b", codec: "copy" },
|
||||||
|
{ format: "flac", codec: "flac" },
|
||||||
|
{ format: "mp3", codec: "libmp3lame" },
|
||||||
|
];
|
||||||
|
const codec = outputFormatCodecMaps.filter(x => x.format === outputFormat)[0].codec;
|
||||||
|
const filename = file.name;
|
||||||
|
return [`-y`,
|
||||||
|
'-activation_bytes', activationBytes,
|
||||||
|
'-i', filename,
|
||||||
|
'-c:a', codec,
|
||||||
|
'-vn', outputFileName
|
||||||
|
];
|
||||||
|
}
|
||||||
|
const doTranscode = async (file, outputFileName, outputFormat, activationBytes, setMessage) => {
|
||||||
|
const ffmpeg = createFFmpeg({
|
||||||
|
log: true,
|
||||||
|
progress: ({ ratio }) => {
|
||||||
|
setMessage(`Complete: ${(ratio * 100.0).toFixed(2)}%`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const command = getCommandAsList(file, outputFileName, outputFormat, activationBytes);
|
||||||
|
setMessage('Loading ffmpeg-core.js');
|
||||||
|
await ffmpeg.load();
|
||||||
|
setMessage('Start transcoding');
|
||||||
|
ffmpeg.FS('writeFile', file.name, await fetchFile(file));
|
||||||
|
await ffmpeg.run(...command);
|
||||||
|
setMessage('Complete transcoding');
|
||||||
|
const data = ffmpeg.FS('readFile', outputFileName);
|
||||||
|
downloadFile(data,outputFileName, outputFormat)
|
||||||
|
};
|
||||||
|
const OnlineConverter = (props) => {
|
||||||
|
const {file, activationBytes, outputFormat} = props
|
||||||
|
const [message, setMessage] = useState('Click Start to transcode');
|
||||||
|
|
||||||
|
const downloadDisabled = !(file && activationBytes && outputFormat)
|
||||||
|
|
||||||
|
return(
|
||||||
|
<div>
|
||||||
|
<Button onClick={()=>{
|
||||||
|
let fileNameWithoutExtension = file.name.split('.').slice(0, -1).join('.');
|
||||||
|
fileNameWithoutExtension = fileNameWithoutExtension === 'input' ? 'output' : fileNameWithoutExtension;
|
||||||
|
const outputFileName = `${fileNameWithoutExtension}.${outputFormat}`
|
||||||
|
return doTranscode(file,outputFileName,outputFormat,activationBytes,setMessage)
|
||||||
|
}} variant="contained" color="primary" disabled={downloadDisabled}>Convert in Browser</Button>
|
||||||
|
<Typography>{message}</Typography>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default OnlineConverter
|
|
@ -4,6 +4,8 @@ import './index.css';
|
||||||
import * as serviceWorker from './serviceWorker';
|
import * as serviceWorker from './serviceWorker';
|
||||||
import ChecksumResolver from './ChecksumResolver';
|
import ChecksumResolver from './ChecksumResolver';
|
||||||
import ReactNotification from 'react-notifications-component'
|
import ReactNotification from 'react-notifications-component'
|
||||||
|
import ForkMeOnGithub from 'fork-me-on-github';
|
||||||
|
|
||||||
|
|
||||||
import ReactGA from 'react-ga';
|
import ReactGA from 'react-ga';
|
||||||
ReactGA.initialize('UA-174657678-1');
|
ReactGA.initialize('UA-174657678-1');
|
||||||
|
@ -15,7 +17,11 @@ ReactDOM.render(
|
||||||
<ReactNotification />
|
<ReactNotification />
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
<ForkMeOnGithub
|
||||||
|
repo="https://github.com/audible-tools/audible-tools.github.io"
|
||||||
|
colorOctocat="black"
|
||||||
|
isPride
|
||||||
|
/>
|
||||||
<ChecksumResolver />
|
<ChecksumResolver />
|
||||||
</div>,
|
</div>,
|
||||||
document.getElementById('root')
|
document.getElementById('root')
|
||||||
|
|
Loading…
Reference in a new issue