I have a flask app with an upload button for videos (mp4), and I am trying to figure out how to get the video to play on the screen after upload. Currently, it opens a generic gray video screen, but no video plays. I am including portions of my app.py and index.html files below. I also have a predict button that I would like to be able to interact with while the video continues to play.
I would appreciate any suggestions for how to accomplish this.
#app.route('/', methods=['GET'])
def index():
# Main page
return render_template('index.html')
#app.route('/predict', methods=['GET', 'POST'])
def upload():
if request.method == 'GET':
return render_template('index.html')
if request.method == 'POST':
# Get the file from post request
f = request.files['file']
# Save the file to ./uploads
basepath = os.path.dirname(__file__)
file_path = os.path.join(
basepath, 'static', secure_filename(f.filename))
f.save(file_path)
result = model_predict(file_path, model)
return jsonify(result)
return None
if __name__ == '__main__':
# app.run(port=5002, debug=True)
# Serve the app with gevent
http_server = WSGIServer(('', 5000), app)
http_server.serve_forever()
`
<div>
<h4>
<center></center>
</h4>
<br>
</br>
<center>
<form id="upload-file" method="post" enctype="multipart/form-data">
<center>
<label for="imageUpload" class="upload-label">
Upload (mp4)
</label>
</center>
<input type="file" name="file" id="imageUpload" accept=".mp4">
</form>
</center>
<div class="image-section" style="display:none;">
<div class="img-preview">
<div id="imagePreview">
<html>
<head>
</head>
<center>
<body>
<center>
<video controls width="500" style="center">
<source src="{{url_for('static', filename=f)}}" type="video/mp4" autoplay>
Sorry, your browser doesn't support embedded videos.
</video>
</center>
</body>
</html>
<input type="file" name="file[]" class="file_multi_video" accept="video/*">
</div>
</div>
<div>
<button type="button" class="btn btn-primary btn-lg " id="btn-predict">Identify</button>
</div>
</div>
<div class="loader" style="display:none;"></div>
<h3 id="result">
<span> </span>
</h3>
</div>
</center>
You can use MJPEG to do this in HTML and you can see the answer at https://stackoverflow.com/a/61452182/10353754 to get some help.
You should just extract frmaes and send it to tag after encoding into JPEG format.
Related
I am trying to create youtube video downloader application using pytube and flask. All is done, except that a want to call pytube's stream download method from within the html script tag. How can i do it.
Here's my flask code
from flask import Flask, render_template, request
from pytube import YouTube
app = Flask(__name__)
#app.route("/")
def index():
return render_template("index.html", data=None)
#app.route("/download", methods=["POST", "GET"])
def downloadVideo():
if request.method == "POST":
url = request.form["videourl"]
if url:
yt = YouTube(url)
title = yt.title
thumbnail = yt.thumbnail_url
streams = yt.streams.filter(file_extension='mp4')
data = [title, thumbnail, streams, yt]
return render_template("index.html", data=data)
if __name__ == "__main__":
app.run(debug=True)
and here's my html code
<!DOCTYPE html>
<html>
<head>
<title> Youtube Downloader </title>
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="stylesheet" href="static/css/style.css">
</head>
<body>
<div class="main">
<div class="header">
<div>
<img src="static/img/icon.png" width="48" height="48">
<h2> Youtube Downloader </h2>
</div>
<div>
<p> Convert and download youtube videos </p>
<p> in MP4 for free </p>
</div>
</div>
{% if not data %}
<div class="dform">
<form action="http://127.0.0.1:5000/download", method="POST">
<div class="inputfield">
<input type="input" name="videourl" placeholder="Search or Paste youtube link here" autocomplete="off">
<button type="submit"> Download </button>
</div>
</form>
</div>
{% else %}
<div class="videoinfo">
<img src="" class="thumbnail">
<h2> {{data[0]}} </h2>
</div>
<div class="quality">
<select id="streams">
{% for stream in data[2][:3] %}
<option value="{{stream.itag}}"> {{stream.resolution}} </option>
{% endfor %}
</select>
</div>
{% endif %}
</div>
<script type="text/javascript">
const image = document.querySelector(".thumbnail");
const select = document.querySelector("select");
let url = `{{data[1]}}`;
if (image) {
image.src = `${url}`;
window.addEventListener('change', function() {
var option = select.options[select.selectedIndex].value;
console.log(option);
{% set stream = data[3].get_by_itag(option) %}
{% stream.download() %}
});
}
</script>
</body>
</html>
I am trying to download the video using itag when a user clicks an option in the select element by using pytube get_by_itag() method.
From what I understand you want to do two things. You want to create a route on your flask app that will let serve up the youtube video based on an itag, and you want to be able to call that route from javascript.
This answer shows how to create a route to download the video.
To call a url that starts a file download from javascript you'll need to use the fetch method and open that link into an iFrame. This answer covers it.
Let me know if that covers your question.
I have two input buttons. One is for uploading a file, and the other one is a submit button that adds the uploaded file to the database.
My problem is, after I submit the file, the first button that's used for uploading goes back to "No file chosen" next to the button. However, I want the uploaded file name to "stick" to the UI/html page as the file chosen.
Here is my File class:
class Files(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String, unique=True, nullable=False)
data = db.Column(db.LargeBinary)
Here is my HTML code:
<td>
<form class="" action="{{url_for('main.upload_file')}}" method="post" enctype="multipart/form-data">
<input type="hidden" name="id" value="{{row.id}}">
<input style="margin-bottom: 5px;" type="file" accept=".csv" name="csvfile" id="upload" value ="{{row.name}}"> <br>
<input style="margin-bottom: 10px;" type="submit" name="" value="Submit"> <br>
</form>
<a href={{ url_for('main.files') }}>Go to Downloads Page</a>
<br>
</td>
I've tried making the value attribute equal to the file name getting passed in ex. value ="{{row.name}}" for the file type <input> above, but that doesn't keep the file chosen name on the page after submission either. I can't find any videos or posts that deal with this problem, so I would really appreciate any guidance. TIA!
I think setting a default value for an input field of type file is forbidden for security reasons.
However, if you want to keep the name of the selected file, you can aim for a transfer with AJAX. Here you can suppress the standard behavior of the form. The page is not reloaded and the form is not reset.
The example below shows you how it works.
Flask (app.py)
from flask import Flask
from flask import (
render_template,
request,
)
app = Flask(__name__)
#app.route('/')
def index():
return render_template('index.html')
#app.route('/upload-file', methods=['POST'])
def upload_file():
if 'csvfile' in request.files:
file = request.files['csvfile']
if file.filename != '':
# handle file here!
return '', 200
return '', 400
HTML (templates/index.html)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<form name="my-form" method="post">
<input type="file" name="csvfile" />
<input type="submit" />
</form>
<script type="text/javascript">
((uri) => {
const elem = document.querySelector('form[name="my-form"]');
elem.addEventListener('submit', evt => {
evt.preventDefault();
const formData = new FormData(evt.target);
fetch(uri, {
method: 'post',
body: formData
}).then(resp => {
if (resp.status === 200) {
console.log('Submit successful.');
}
});
})
})({{ url_for('.upload_file') | tojson }});
</script>
</body>
</html>
I don't know if it is possible to default the value the file-input field shows but what you could do is just have a row above the input field showing the currently uploaded/chosen file (if there is any). So something like this:
<td>
<form class="" action="{{url_for('main.upload_file')}}" method="post" enctype="multipart/form-data">
<input type="hidden" name="id" value="{{row.id}}">
{% if row.name %}
<p>Currently chosen file: {{row.name}}</p>
<p>You can select a new file below</p>
{% endif %}
<input style="margin-bottom: 5px;" type="file" accept=".csv" name="csvfile" id="upload"> <br>
<input style="margin-bottom: 10px;" type="submit" name="" value="Submit"> <br>
</form>
<a href={{ url_for('main.files') }}>Go to Downloads Page</a>
<br>
</td>
When I try to add a new task on my website I get the message "POST /templates/todo" Error (404): "Not found" and cannot find what is wrong with the code. Can anyone help me figure it out? It was done on cs50ide software. If anyone could inform me whether I am able to create a functioning link for my website (I use python, flask, html and css) I would be very grateful! Thank you so much
add.html code:
<!DOCTYPE html>
<html lang="en">
<head>
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" rel="stylesheet">
<link href="/static/css/styles.css" rel="stylesheet">
<title>
Add a New Task :)
</title>
</head>
<body>
<h1 class = "aligncenter">
<img class = "img1" src = "/static/images/logocarol.jpg" alt = "Logo" height = "200" width = "550"/>
</h1>
<h1 class="centergeneral fontsize">
Add any goals, dreams and aspirations you might have here:
</h1>
<form class="aligncenter" action="todo" method="POST">
<input id="task" name="task" type="text" placeholder="New Task :)">
<input id="submit" type="submit" disabled>
</form>
<script>
document.querySelector('#task').onkeyup = function(){
if (document.querySelector('#task').value === ''){
document.querySelector('#submit').disabled = true;
} else {
document.querySelector('#submit').disabled = false;
}
}
</script>
<form action="/">
<button type="submit" id = "back" class="btn btn-info margin"> BACK TO HOMEPAGE </button> <br> <br>
</form>
<form action="todo">
<button type="submit" id = "back" class="btn btn-outline-info margin"> BACK TO TO DO LIST </button> <br> <br>
</form>
</body>
todo.html code:
<!DOCTYPE html>
<html lang="en">
<head>
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" rel="stylesheet">
<link href="/static/css/styles.css" rel="stylesheet">
<title>
To Do List! :)
</title>
</head>
<body>
<h1 class = "aligncenter">
<img class = "img1" src = "/static/images/logocarol.jpg" alt = "Logo" height = "200" width = "550"/>
</h1>
<h1 class="fonts centergeneral"> To Do List </h1>
<h2 class="fs-4 centergeneral"> What I Want to Achieve: </h2> <br>
<ul class="listcenter">
<script>
{%for todo in todos%}
<li> {{ todo }} <input type="checkbox" id="checkbox1"> </li>
{%endfor%}
</script>
</ul>
<a class="btn btn-outline-info margin" href = "add"> Add a New Task</a>
<a class="btn btn-outline-info" href = "clear"> Clear Tasks </a> <br>
<div class="backbuttons">
<form action="/">
<button type="submit" id = "back" class="btn btn-info"> BACK TO HOMEPAGE </button> <br> <br>
</form>
</div>
application.py code:
from flask import Flask, render_template, send_from_directory, request, redirect, session
from flask_session import Session
from cs50 import SQL
app = Flask(__name__)
app.config["SESSION_PERMANENT"] = False
app.config["SESSION_TYPE"] = "filesystem"
Session(app)
#app.route('/')
def index():
return render_template('index.html')
#app.route('/f1inschools')
def f1():
return render_template('f1inschools.html')
#app.route('/pdwt')
def pdwt():
return render_template('pdwt.html')
#app.route('/pros')
def pros():
return render_template('pros.html')
#app.route('/bookrecommendations')
def books():
return render_template('bookrecs.html')
#app.route('/todolist')
def todo():
if "todos" not in session:
session["todos"] = []
return render_template('todo.html', todos=session["todos"])
#app.route('/clear')
def clear():
return redirect("/todolist")
session["todos"] = []
#app.route('/add', methods=["GET", "POST"])
def add():
if request.method == "GET":
return render_template("add.html")
else:
todo = request.form.get("task")
session["todos"].append(todo)
return redirect("/todolist")
The function for adding tasks is at app.route("/add",methods=["GET","POST"]), but your form in the HTML has action="todo", so your form tries to send data to /todo which is nonexistent. To fix, simply change action="todo" to action="add".
I am trying to make a simple html webpage where a user can upload an image. This image is passed on to a flask API through a form wherein the image is passed to an image classification model. However, I am not able to recieve the image in the Flask API after I upload the file. I get an error saying
werkzeug.exceptions.BadRequestKeyError: 400 Bad Request: The browser (or proxy) sent a request that this server could not understand. KeyError: 'uploaded_img'
Can anyone guide me where I am going wrong?
My html code:
<body class="center-screen">
<div id="content">
<form id="url-form" action="/classify_image" method="post" enctype="multipart/form-data">
<h1>Upload Image</h1>
<div class="formcontainer">
<hr/>
<div class="container">
<label for="img">Upload image:</label>
<input type="file" id="img" name="uploaded_img" accept="image/*">
</div>
<button type="submit">
<strong>Classify Image</strong>
</button>
</div>
</form>
</div>
</body>
My flask endpoint:
#app.route('/classify_image', methods=['POST'])
def classify_image():
if request.method == 'POST':
print("Running")
f = request.files['uploaded_img']
model.predict(f)
I am completely new to python and Flask and I am trying to run in my computer the code showed in this page:
http://runnable.com/UhLMQLffO1YSAADK/handle-a-post-request-in-flask-for-python
This are the steeps I follow and the code:
1-I have installed Flask
2-Files
File app.py
# We need to import request to access the details of the POST request
# and render_template, to render our templates (form and response)
# we'll use url_for to get some URLs for the app on the templates
from flask import Flask, render_template, request, url_for
# Initialize the Flask application
app = Flask(__name__)
# Define a route for the default URL, which loads the form
#app.route('/')
def form():
return render_template('form_submit.html')
# Define a route for the action of the form, for example '/hello/'
# We are also defining which type of requests this route is
# accepting: POST requests in this case
#app.route('/hello/', methods=['POST'])
def hello():
name=request.form['yourname']
email=request.form['youremail']
return render_template('form_action.html', name=name, email=email)
# Run the app :)
if __name__ == '__main__':
app.run(
host="0.0.0.0",
port=int("80")
)
File form_action.html
<html>
<head>
<title>Handle POST requests with Flask</title>
<link rel=stylesheet type=text/css href="style.css">
</head>
<body>
<div id="container">
<div class="title">
<h1>POST request with Flask</h1>
</div>
<div id="content">
Hello <strong>{{name}}</strong> ({{email}})!
</div>
</div>
</div>
</body>
</html>
File form_submit.html
<html>
<head>
<title>Handle POST requests with Flask</title>
<link rel=stylesheet type=text/css href="style.css">
</head>
<body>
<div id="container">
<div class="title">
<h1>POST request with Flask</h1>
</div>
<div id="content">
<form method="post" action="{{ url_for('hello') }}">
<label for="yourname">Please enter your name:</label>
<input type="text" name="yourname" /><br />
<label for="youremail">Please enter your email:</label>
<input type="text" name="youremail" /><br />
<input type="submit" value="Send" />
</form>
</div>
</div>
</div>
</body>
</html>
3-I run the py file:
sudo python app.py
[sudo] password for jose:
* Running on http://0.0.0.0:80/ (Press CTRL+C to quit)
When I open the browser I write:
file:///home/jose/Escritorio/python/app/form_submit.html
I insert the data in the 2 forms and I press Send and this is what happens:
URL: file:///home/jose/Escritorio/python/app/{{url_for('hello')}}
Web Page: File not found
What am I doing wrong?
0.0.0.0 means that you can access the flask website from outside of the website host. Use the host ip plus the port # you specified
http://:80/hello in your case. That should display the form_action.html you specified in your routes.
If you want save form data, your code didn't work. You must have a database or save in a file.