My goal is to chunk client-side video uploads to separate .mp4 files that are under 100MB in size. I came across an open source library Dropzone.js that can accomplish the task I want to achieve.
Bits and pieces of my current code.
templates/upload.html:
<script type="application/javascript">
Dropzone.options.dropper = {
paramName: 'file',
chunking: true,
maxFiles: 1,
dictDefaultMessage: "Upload Match Video",
acceptedFiles: ".mp4",
forceChunking: true,
url: '/tutorial',
maxFilesize: 6144, // megabytes
chunkSize: 100000000 // bytes
}
</script>
<center>
<form method="POST" action='/upload' class="dropzone dz-clickable"
id="dropper" enctype="multipart/form-data">
</form>
</center>
flask_app.py:
#app.route('/upload', methods=['GET', 'POST'])
def upload():
if request.method == "GET":
return render_template('upload.html', static_folder='static')
f = request.files['file']
filename = secure_filename(f.filename)
path_to_video = os.path.join(app.config['UPLOAD_FOLDER'], filename)
fsr = f.stream.read()
chunkfilename = path_to_video[:-4] + f'_Chunk{int(request.form["dzchunkindex"]) + 1}.mp4'
with open(chunkfilename, "wb") as out_file:
out_file.write(fsr)
f.close()
if int(request.form['dzchunkindex']) + 1 == int(request.form['dztotalchunkcount']):
return redirect("/video")
return make_response(("Chunk upload successful", 200))
Directory structure:
app/
static/
uploaded_file.mp4
templates/
upload.html
flask_app.py
My goal:
app/
static/
uploaded_file_chunk1.mp4
uploaded_file_chunk2.mp4
uploaded_file_chunk3.mp4
templates/
upload.html
flask_app.py
My current problem is that the chunked video clips that are outputted become corrupted video files. I cannot play them in VLC or Windows Media Player, they either raise an error message, or just freeze.
I can see that they are chunked properly, since a 145MB video gets split into two .mp4 videos with the first chunk being just under 100MB, and the second chunk being the other 45MB. What gives me hope is that when I used an online corrupted video fixer (https://fix.video/), I can see that the broken contents of the video are recovered as what I expected; however, I don't know how to fix it in my code.
Any help appreciated. Thanks very much.
Related
I'm trying to display an image on a simple website, which I am using Flask for. I already tried to do this using a js script on the website itself, but it didn't work.
However, I do not know how to periodically update/refresh the image.
I'm using html and javascript for the first time right now and I'm too confused to get it to work.
This is the main .py file:
from flask import Flask, render_template
import os
#sorry for the bad code :/
app = Flask(__name__)
#app.route("/")
def running():
return "<p>Website running!</p>"
app.config['UPLOAD_FOLDER'] = os.path.join('static','images')
#app.route("/chart")
def show_img():
full_filename = os.path.join(app.config['UPLOAD_FOLDER'], 'chart.png')
return render_template("chart.html", user_image = full_filename)
if __name__ == "__main__":
app.run(port=3000)
This is chart.html:
<!DOCTYPE html>
<html>
<body>
<img src={{ url_for("static", filename="images/"+"chart.png" ) }}/>
</body>
</html>
What is the easiest way to update/reload the image every 5 seconds?
The filename stays the same, but the image itself changes
Some notes:
When working inside a request, it is better to use current_app
from Flask import current_app
#app.route("/chart")
def show_img():
# current_app.config
full_filename = os.path.join('images', 'chart.png')
return render_template("chart.html", user_image=full_filename)
We removed static as we'll be using static in the template itself.
Since you already have the user_image variable, you can add it to the file directly
<!DOCTYPE html>
<html>
<body>
<img src={{ url_for("static", filename=user_image ) }}/>
</body>
</html>
This will display the image.
Dealing with uploads
If you want to implement uploads etc, use flask-reuploaded, a maintained fork of Flask-uploads.
On the front-end, you need a file upload form. Then you need a route to accept the uploaded file. Then you need to make sure that the uploaded filename is always the same, maybe by deleting existing files beforehand.
A complete demo
Following the official docs, here is a demo.
Folder structure
.
├── app.py
├── static
│ └── images
├── templates
└── chart.html
chart.html
<!DOCTYPE html>
<html>
<body>
<form method="post" enctype=multipart/form-data action="/upload">
<input type="file" name="file">
<input type="submit" value="Upload">
</form>
<br>
<img src={{ url_for("static", filename=user_image ) }}/>
</body>
</html>
app.py
import os
from flask import Flask, flash, request, redirect, url_for, render_template
from werkzeug.utils import secure_filename
UPLOAD_FOLDER = '/path/to/the/uploads'
ALLOWED_EXTENSIONS = {'txt', 'pdf', 'png', 'jpg', 'jpeg', 'gif'}
app = Flask(__name__)
current_file = ''
#app.route("/")
def running():
return "<p>Website running!</p>"
app.config['UPLOAD_FOLDER'] = os.path.join('static','images')
def allowed_file(filename):
return '.' in filename and \
filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
#app.route('/upload', methods=['GET', 'POST'])
def upload_file():
global current_file
if request.method == 'POST':
# check if the post request has the file part
if 'file' not in request.files:
flash('No file part')
return redirect(request.url)
file = request.files['file']
# If the user does not select a file, the browser submits an
# empty file without a filename.
if file.filename == '':
flash('No selected file')
return redirect(request.url)
if file and allowed_file(file.filename):
filename = secure_filename(file.filename)
current_file = filename
file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
return redirect(url_for('show_img', name=filename))
#app.route("/chart")
def show_img():
filename = os.path.join('images', current_file)
return render_template("chart.html", user_image=filename)
if __name__ == "__main__":
app.run(port=3000)
I would like to share a JSON object as a file via the Web Share API.
However, when specifying the type as application/json, I got the DOMException: Permission denied Error:
navigator.share({
files: [new File(["{}"], "test.json", {type: "application/json"})]
})
// Uncaught (in promise) DOMException: Permission denied
However, if I change the type to text/plain and the file name extension to .txt, it works as expected:
navigator.share({
files: [new File(["{}"],"test.txt", {type: "text/plain"})]
})
// File share success
I would like to have it as a `JSON file to be shared instead.
Browser: Microsoft Edge (Chromium) 96.0.1054.43
Any helps would be appreciated.
Snippet Example:
const textbtn = () => {
navigator.share({
files: [new File(["{}"],"test.txt", {type: "text/plain"})]
}).catch(e => alert(e.message))
}
const jsonbtn = () => {
navigator.share({
files: [new File(["{}"],"test.json", {type: "application/json"})]
}).catch(e => alert(e.message))
}
<h1>WebShare Test<h1>
<button onclick="jsonbtn()">test.json | application/json</button>
<br />
<button onclick="textbtn()">text.text | text/pain</button>
This is working as intended. You can see the list of supported file types in this document.
Per this MDN documentation about shareable file types, the supported kinds of file type are only quite a few.
PDF
some audio files
some image files
some text files
some video files
The text files in particular are:
.css - text/css
.csv - text/csv
.ehtml - text/html
.htm - text/html
.html - text/html
.shtm - text/html
.shtml - text/html
.text - text/plain
.txt - text/plain
Unfortunately, JSON (application/json) is not among them, but txt (text/plain) is.
Depending on your scenario, you might want to consider sharing an URL to the file in question, via the URL parameter.
I'm setting up a simple web app on AppEngine and have some trouble with configuring the app.yaml. It includes a HTML page, a JS script and a NodeJS server.
My project structure:
\app.yaml
\package.json
\www
\index.html
\js
\server.js
\index.js
index.html:
<!DOCTYPE html>
<html>
<body>
<div id="JShere" >Hello World !</div>
<div id="ReqAnswer"></div>
</body>
<script src="js/index"></script>
</html>
index.js:
document.getElementById('JShere').innerHTML = "JS is running";
var xhr = new XMLHttpRequest();
xhr.open('GET', "/srv", true);
xhr.send();
xhr.addEventListener("readystatechange", processRequest, false);
function processRequest(e) {
if (xhr.readyState == 4 && xhr.status == 200) {
document.getElementById('ReqAnswer').innerHTML = xhr.responseText;
}
}
node.js server:
const express = require('express');
const app = express();
app.get('/srv', function (req, res) {
res.send('Request anwser')
})
const PORT = process.env.PORT || 8080;
app.listen(PORT, () => {
console.log(`Server listening on port ${PORT}...`);
});
package.json:
...
"scripts": {
"start": "node www/js/server.js",
"test": "mocha --exit test/*.test.js"
},
...
app.yaml:
runtime: nodejs10
handlers:
- url: /
static_files: www/index.html
upload: www/index.html
- url: /index
static_files: www/index.html
upload: www/index.html
- url: /page2
static_files: www/page2.html
upload: www/page2.html
- url: /www
static_dir: www
When I check locally, index.js modify index.html correctly but when I deploy it to App Engine, index.js is blocked (MIME type (« text/html »)). it then "fails to load the " on the index.html. Although, the script still launch the GET request to the server and get a 404 error.
Is it an App.yaml problem or something else is wrong?
Check closely the GAE log entries for the exact URL being requested (and rejected with 404). That's what would normally need to be matched by one of your static handlers' url pattern. If a match occurs then the file specified by the respective handler's static_file/static_dir and upload specs (which are relative to your app's top dir - where the app.yaml file exists) should happen.
Let's assume the initial request is for /. That's matched by your 1st static handler, so your www/index.html will be served.
But the index.html file references the js/index script inside, so another request will follow with that URL. But that URL doesn't match any of your handlers' pattern, so it'll get a 404. You also don't have any file named just index.
Assuming what you'd like to serve in this case is actually the www/js/index.js file you'd have to:
correct the filename reference in your index.html file:
<script src="js/index.js"></script>
make sure this reference is matched by a static handler url pattern. Something like this maybe (which for every request path ending with .js will attempt to serve a file matching that path but relative to the www/js directory):
- url: /(.*\.js)$
static_files: www/js/\1
upload: www/js/.*\.js$
Alternatively you could use a scheme that can be applied to multiple type of files, not that those ending in .js:
reference the file using the www prefix in your index.html file:
`<script src="www/js/index.js"></script>`
re-use your last handler, but adding a wildcard to its url to ensure matches for everything under www (as www/blah won't match the just www pattern):
`- url: /www/*`
It's also possible to reference the script without the .js suffix, but then you'd need a handler specifically for that file - to map it to the actual filename, you can't use wildcards. So I wouldn't recommend this as it can get pretty complex very quickly.
You'd have to similarly consider all the other static elements you need to serve.
var srcArticleImage = 'src/recommended-reads-images/';
var distArticleImage = 'dist/assets/recommended-reads-images/';
gulp.task('article-images', function() {
gulp.src(srcArticleImage + "*", srcArticleImage + "**/*"])
.pipe(gulpif(global.build, imagemin([
imagemin.gifsicle({interlaced: true}),
imagemin.jpegtran({progressive: true}),
imagemin.optipng({optimizationLevel: 5}),
imagemin.svgo({plugins: [{removeViewBox: true}]})
])))
.pipe(gulp.dest(distArticleImage))
.pipe(gulpif(global.build, size({showFiles: true, showTotal: false})))
.pipe(gulpif(!global.build, notify({message: 'Article Images Compiled', onLast: true})))
});
When the above task is run, I expect it to take the files from the src directory, minify them and then copy them over to the destination.
However I have a problem when the task runs. Only 81 images are being output to the destination folder, but there are 103 files in the src folder.
Would appreciate it if anyone could shed some light on this issue, I have bashed my head against the keyboard for an hour and a half trying to fix this issue.
Hope somebody has the fix, thanks.
Is it possible to download multiple images into the sandbox file system (without the "save as" dialog box, or at-max one saveas dialog) ?
after downloading them, i'd like to ZIP them into one.. is there any javascript archive library?
Thanks in advance..
You can use zip.js for this.
It does already have API for fetching contents to be zipped from HTTP (cf. zip.HttpReader constructor) and for writing generated zip on HTML5 filesystem (cf. zip.FileWriter constructor).
Here is an example using the filesystem API:
index.html file:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Zip JSON data from the BBC into HTML5 FileSystem</title>
</head>
<body>
<script src="zip.js"></script>
<script src="zip-fs.js"></script>
<script src="zip-ext.js"></script>
<script src="example.js"></script>
</body>
</html>
example.js file:
// create a zip virtual filesystem
var fs = new zip.fs.FS();
// add some files into the zip filesystem
// add the "bbc-music.json" file in the root directory
fs.root.addHttpContent("bbc-music.json",
"http://www.bbc.co.uk/programmes/genres/music.json");
// add the "bbc-learning.json" file in the root directory
fs.root.addHttpContent("bbc-learning.json",
"http://www.bbc.co.uk/programmes/genres/learning.json");
// create a file named "test.zip" in the root directory of the HTML5 filesystem
createFile("test.zip", function(fileEntry) {
// export the zip content into "test.zip" file
fs.root.exportFileEntry(fileEntry, function() {
console.log("done");
});
});
// function to create a file in the HTML5 temporary filesystem
function createFile(filename, callback) {
webkitRequestFileSystem(TEMPORARY, 4 * 1024 * 1024, function(fs) {
fs.root.getFile(filename, { create : true }, callback);
});
}
You can access images as regular parts of some web-pages or download them separately by means of XMLHTTPRequests. After this you can zip them in a single archive using JSZip JavaScript library. The zip can be stored as a file without a "Save As" dialog (try the example on the site). Though I'm not sure why you need the sandbox.
There exist other JavaScript libraries for zipping, for example, some are mentioned in other SO answer.