diff options
| author | Jules Laplace <julescarbon@gmail.com> | 2021-03-11 00:06:51 +0100 |
|---|---|---|
| committer | Jules Laplace <julescarbon@gmail.com> | 2021-03-11 00:06:51 +0100 |
| commit | f634e938d956268b66545a61a36e26887684a375 (patch) | |
| tree | 2c4b7e8b308fe81e3ac7cbbb9f52b7940869f6c9 | |
| parent | 382224e0f6ad0d226548046d23ef6df940a24414 (diff) | |
uploading peaks and audio file works!
13 files changed, 151 insertions, 39 deletions
diff --git a/animism-align/cli/app/controllers/upload_controller.py b/animism-align/cli/app/controllers/upload_controller.py index a81312d..5ec4d77 100644 --- a/animism-align/cli/app/controllers/upload_controller.py +++ b/animism-align/cli/app/controllers/upload_controller.py @@ -54,41 +54,35 @@ class UploadView(FlaskView): try: username = request.form.get('username') + print(username) except: raise APIError('No username specified') try: tag = request.form.get('tag') + print(tag) except: raise APIError('No tag specified') - param_name = 'image' - if param_name not in request.files: + if 'image' in request.files: + file = request.files['image'] + print(fn) + elif 'file' in request.files: + file = request.files['file'] + # print(request.form.get('__image_filename')) + print(fn) + else: raise APIError('No file uploaded') - file = request.files[param_name] - # get sha256 sha256 = sha256_stream(file) _, ext = os.path.splitext(file.filename) if ext == '.jpeg': ext = '.jpg' - # TODO: here check sha256 - # upload = Upload.query.get(id) - - # if ext[1:] not in VALID_IMAGE_EXTS: - # return jsonify({ 'status': 'error', 'error': 'Not a valid image' }) + ext = ext[1:] - # convert string of image data to uint8 file.seek(0) - # nparr = np.fromstring(file.read(), np.uint8) - - # decode image - # try: - # im = Image.fromarray(nparr) - # except: - # return jsonify({ 'status': 'error', 'error': 'Image parse error' }) uploaded_im_fn = secure_filename(file.filename) uploaded_im_abspath = os.path.join(app_cfg.DIR_UPLOADS, tag) @@ -97,14 +91,14 @@ class UploadView(FlaskView): session = Session() upload = session.query(Upload).filter_by(sha256=sha256).first() if upload is not None: - print("Already uploaded image") + print("Already uploaded file") if not os.path.exists(uploaded_im_fullpath): # if we got in some weird state where the record wasnt deleted.... os.makedirs(uploaded_im_abspath, exist_ok=True) file.save(uploaded_im_fullpath) response = { 'status': 'ok', - 'notes': 'Image already uploaded', + 'notes': 'File already uploaded', 'res': upload.toJSON(), } session.close() diff --git a/animism-align/frontend/app/api/crud.upload.js b/animism-align/frontend/app/api/crud.upload.js index b4d9d4e..2837dd4 100644 --- a/animism-align/frontend/app/api/crud.upload.js +++ b/animism-align/frontend/app/api/crud.upload.js @@ -1,4 +1,5 @@ import { as_type } from 'app/api/crud.types' +import { session } from 'app/session' export function crud_upload(type, data, dispatch) { return new Promise( (resolve, reject) => { @@ -13,7 +14,7 @@ export function crud_upload(type, data, dispatch) { Object.keys(data).forEach(key => { if (key.indexOf('__') !== -1) return if (key === 'id') return - const fn_key = '__' + key + '_filename' + const fn_key = `__${key}_filename` if (fn_key in data) { fd.append(key, data[key], data[fn_key]) } else { @@ -31,12 +32,11 @@ export function crud_upload(type, data, dispatch) { xhr.addEventListener("error", uploadFailed, false) xhr.addEventListener("abort", uploadCancelled, false) xhr.open("POST", url) + xhr.setRequestHeader("Authorization", "Bearer " + session.get("access_token")) xhr.send(fd) dispatch && dispatch({ type: as_type(type, 'upload_loading')}) - let complete = false - function uploadProgress (e) { if (e.lengthComputable) { const percent = Math.round(e.loaded * 100 / e.total) || 0 diff --git a/animism-align/frontend/app/utils/index.js b/animism-align/frontend/app/utils/index.js index 693a185..d76a319 100644 --- a/animism-align/frontend/app/utils/index.js +++ b/animism-align/frontend/app/utils/index.js @@ -81,6 +81,14 @@ export const timestamp = (n = 0, fps = 1, ms = false, h_label = ':', m_label = ' return (n % 60) + m_label + s + s_label } +export const formatSize = n => { + if (n < 1000) return n + " b." + if (n < 1000000) return (n / 1000).toFixed(1) + " kb." + if (n < 1000000000) return (n / 1000000).toFixed(1) + " mb." + if (n < 1000000000000) return (n / 1000000000).toFixed(1) + " gb." + return "Quite large." +} + export const timestampHMS = n => timestamp(n, 1, false, 'h', 'm', 's') export const timestampToSeconds = time_str => { diff --git a/animism-align/frontend/app/views/editor/align/components/sidebar/waveUpload.component.js b/animism-align/frontend/app/views/editor/align/components/sidebar/waveUpload.component.js index 68ef1e0..27047ef 100644 --- a/animism-align/frontend/app/views/editor/align/components/sidebar/waveUpload.component.js +++ b/animism-align/frontend/app/views/editor/align/components/sidebar/waveUpload.component.js @@ -1,13 +1,17 @@ import React, { Component } from 'react' -// import { Link } from 'react-router-dom' import { connect } from 'react-redux' +import extractPeaks from 'webaudio-peaks' -// import actions from 'app/actions' +import actions from 'app/actions' +import { formatSize, timestampHMS } from 'app/utils' +import { Loader } from 'app/common' class WaveUpload extends Component { state = { working: false, status: "", + filename: "", + duration: 0, } upload(e) { @@ -24,18 +28,83 @@ class WaveUpload extends Component { console.log('No file specified') return } - this.setState({ working: true, status: "Loading" }) + this.setState({ working: true, status: "Loading MP3...", filename: file.name, size: file.size, duration: 0 }) const fileReader = new FileReader() - fileReader.onload = fileReaderEvent => { + fileReader.onload = event => { fileReader.onload = null - this.processAudioFile({ file }) + this.processAudioFile(file, event.target.result) } - fileReader.readAsDataURL(file) + fileReader.readAsArrayBuffer(file) } - processAudioFile(file) { - var context = new (window.AudioContext); - source = context.createBufferSource(); + processAudioFile(audioFile, arrayBuffer) { + this.setState({ working: true, status: "Extracting peaks..." }) + var audioContext = new (window.AudioContext || window.webkitAudioContext)(); + audioContext.decodeAudioData(arrayBuffer, (audioBuffer) => { + // buffer, samplesPerPixel, isMono, startOffset, endOffset, bitResolution + this.setState({ duration: audioBuffer.duration }) + var peaks = extractPeaks(audioBuffer, 441, true); + console.log(peaks) + const array = Array.from(peaks.data[0]) + const peaksBlob = new Blob([ JSON.stringify(array) ], {type: "application/json"}); + this.uploadAudioAndPeaks(audioFile, peaksBlob) + }) + } + + uploadAudioAndPeaks(audioFile, peaksBlob) { + const { episode } = this.props + const updatedEpisode = { ...episode } + this.setState({ status: "Removing old files..." }) + this.destroyTaggedFile('peaks') + this.destroyTaggedFile('audio') + .then(() => { + return this.uploadTaggedFile(peaksBlob, 'peaks', 'episode-' + this.props.episode.id + '-peaks.json') + }) + .then(peaksResult => { + updatedEpisode.settings.peaks = peaksResult + return this.uploadTaggedFile(audioFile, 'audio', this.state.filename) + }) + .then(audioResult => { + updatedEpisode.settings.audio = audioResult + return actions.episode.update(updatedEpisode) + }) + .then(res => { + this.setState({ status: "Upload complete", working: false }) + }) + } + + uploadTaggedFile(file, tag, fn) { + return new Promise((resolve, reject) => { + this.setState({ status: "Uploading " + tag + "..." }) + const uploadData = { + tag, + file, + __file_filename: fn, + username: this.props.currentUser.username, + } + console.log(uploadData) + return actions.upload.upload(uploadData).then(data => { + console.log(data) + resolve(data.res) + }) + }) + } + + destroyTaggedFile(tag) { + return new Promise((resolve, reject) => { + if (!this.props.episode.settings[tag]) { + return resolve(); + } + actions.upload.destroy(this.props.episode.settings[tag]) + .then(() => { + console.log('Destroy successful') + resolve() + }) + .catch(() => { + console.log('Error deleting the image') + reject() + }) + }) } render() { @@ -64,9 +133,15 @@ class WaveUpload extends Component { /> </div> <small>Upload an MP3, encoded 192kbit constant bitrate, 44.1kHz stereo</small> - <div> - {this.state.status} - </div> + {this.state.status && ( + <div className='status'> + {this.state.working && <Loader />} + <div className='status-message'>{this.state.status}</div> + {this.state.filename && <small>{this.state.filename}</small>} + {this.state.size && <small>{'Size: '}{formatSize(this.state.size)}</small>} + {!!this.state.duration && <small>{'Duration: '}{timestampHMS(this.state.duration)}</small>} + </div> + )} </div> ) } @@ -74,6 +149,8 @@ class WaveUpload extends Component { const mapStateToProps = state => ({ peaks: state.align.peaks, + currentUser: state.auth.user, + project: state.site.project, episode: state.site.episode, }) diff --git a/animism-align/frontend/app/views/editor/align/sidebar.css b/animism-align/frontend/app/views/editor/align/sidebar.css index 4836127..7c19797 100644 --- a/animism-align/frontend/app/views/editor/align/sidebar.css +++ b/animism-align/frontend/app/views/editor/align/sidebar.css @@ -51,6 +51,19 @@ display: block; text-align: center; } +.wave-upload .status { + padding: 1rem 0 0 0; + text-align: center; +} +.wave-upload .circular-loader { + margin: 0 auto 1rem auto; +} +.wave-upload .status-message { +} +.wave-upload .status small { + display: block; + margin-top: 0.25rem; +} /* table of contents */ diff --git a/animism-align/frontend/app/views/editor/media/components/media.form.js b/animism-align/frontend/app/views/editor/media/components/media.form.js index 2c89fcd..df86516 100644 --- a/animism-align/frontend/app/views/editor/media/components/media.form.js +++ b/animism-align/frontend/app/views/editor/media/components/media.form.js @@ -143,7 +143,7 @@ export default class MediaForm extends Component { } render() { - const { isNew } = this.props + const { isNew, currentUser } = this.props const { title, submitTitle, errorFields, data } = this.state // console.log(data) return ( @@ -161,6 +161,7 @@ export default class MediaForm extends Component { {data.type === 'image' && <MediaImageForm data={data} + currentUser={currentUser} onChange={this.handleSelect} onSettingsChange={this.handleSettingsChange} /> @@ -169,6 +170,7 @@ export default class MediaForm extends Component { {data.type === 'video' && <MediaVideoForm data={data} + currentUser={currentUser} onChange={this.handleSelect} onSettingsChange={this.handleSettingsChange} /> @@ -177,6 +179,7 @@ export default class MediaForm extends Component { {data.type === 'file' && <MediaFileForm data={data} + currentUser={currentUser} onChange={this.handleSelect} onSettingsChange={this.handleSettingsChange} /> @@ -185,6 +188,7 @@ export default class MediaForm extends Component { {data.type === 'gallery' && <MediaGalleryForm data={data} + currentUser={currentUser} onChange={this.handleSelect} onSettingsChange={this.handleSettingsChange} /> diff --git a/animism-align/frontend/app/views/editor/media/components/media.formFile.js b/animism-align/frontend/app/views/editor/media/components/media.formFile.js index d3b1ae8..bec0a90 100644 --- a/animism-align/frontend/app/views/editor/media/components/media.formFile.js +++ b/animism-align/frontend/app/views/editor/media/components/media.formFile.js @@ -38,7 +38,7 @@ export default class MediaFileForm extends Component { const uploadData = { image: file, tag: "file", - username: 'animism', + username: this.props.currentUser.username, } // uploadData['__image_filename'] = file.filename return actions.upload.upload(uploadData).then(data => { diff --git a/animism-align/frontend/app/views/editor/media/components/media.formGallery.js b/animism-align/frontend/app/views/editor/media/components/media.formGallery.js index 2cf894b..4003c7d 100644 --- a/animism-align/frontend/app/views/editor/media/components/media.formGallery.js +++ b/animism-align/frontend/app/views/editor/media/components/media.formGallery.js @@ -181,7 +181,7 @@ export default class MediaGalleryForm extends Component { const uploadData = { image, tag, - username: 'animism', + username: this.props.currentUser.username, } if (fn) { uploadData['__image_filename'] = fn diff --git a/animism-align/frontend/app/views/editor/media/components/media.formImage.js b/animism-align/frontend/app/views/editor/media/components/media.formImage.js index dbbf69f..027926b 100644 --- a/animism-align/frontend/app/views/editor/media/components/media.formImage.js +++ b/animism-align/frontend/app/views/editor/media/components/media.formImage.js @@ -103,7 +103,7 @@ export default class MediaImageForm extends Component { const uploadData = { image, tag, - username: 'animism', + username: this.props.currentUser.username, } if (fn) { uploadData['__image_filename'] = fn diff --git a/animism-align/frontend/app/views/editor/media/components/media.formVideo.js b/animism-align/frontend/app/views/editor/media/components/media.formVideo.js index 315925c..656ad2f 100644 --- a/animism-align/frontend/app/views/editor/media/components/media.formVideo.js +++ b/animism-align/frontend/app/views/editor/media/components/media.formVideo.js @@ -60,7 +60,7 @@ export default class MediaVideoForm extends Component { const uploadData = { image: file, tag: "poster", - username: 'animism', + username: this.props.currentUser.username, } // uploadData['__image_filename'] = file.filename return actions.upload.upload(uploadData).then(data => { diff --git a/animism-align/frontend/app/views/editor/media/containers/media.edit.js b/animism-align/frontend/app/views/editor/media/containers/media.edit.js index 37a91ef..6799494 100644 --- a/animism-align/frontend/app/views/editor/media/containers/media.edit.js +++ b/animism-align/frontend/app/views/editor/media/containers/media.edit.js @@ -38,6 +38,7 @@ class MediaEdit extends Component { <MediaMenu mediaActions={this.props.mediaActions} /> <MediaForm data={show.res} + currentUser={this.props.currentUser} onSubmit={this.handleSubmit.bind(this)} /> </div> @@ -48,6 +49,7 @@ class MediaEdit extends Component { const mapStateToProps = state => ({ media: state.media, episode_id: state.site.episode.id, + currentUser: state.auth.user, }) export default connect(mapStateToProps)(MediaEdit) diff --git a/animism-align/frontend/app/views/editor/media/containers/media.new.js b/animism-align/frontend/app/views/editor/media/containers/media.new.js index 1a41503..0a1be55 100644 --- a/animism-align/frontend/app/views/editor/media/containers/media.new.js +++ b/animism-align/frontend/app/views/editor/media/containers/media.new.js @@ -63,6 +63,7 @@ class MediaNew extends Component { <MediaForm isNew data={this.state.initialData} + currentUser={this.props.currentUser} onSubmit={this.handleSubmit.bind(this)} /> </div> @@ -73,6 +74,7 @@ class MediaNew extends Component { const mapStateToProps = state => ({ media: state.media, episode_id: state.site.episode.id, + currentUser: state.auth.user, }) export default connect(mapStateToProps)(MediaNew) diff --git a/animism-align/frontend/app/views/site/site.reducer.js b/animism-align/frontend/app/views/site/site.reducer.js index 36f50ca..b8c1ddf 100644 --- a/animism-align/frontend/app/views/site/site.reducer.js +++ b/animism-align/frontend/app/views/site/site.reducer.js @@ -22,6 +22,18 @@ export default function siteReducer(state = initialState, action) { episode: action.episode, } + case types.project.update_loaded: + return { + ...state, + project: action.data.res, + } + + case types.episode.update_loaded: + return { + ...state, + episode: action.data.res, + } + default: return state } |
