Call python's object method from flask jinja2 html file - python

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.

Related

Unable to add a task to todo list

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".

How to automatically play an mp4 uploaded in flask app

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.

How to return flask output to the same html page

I have an html file which reads like this:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Robots Uploader</title>
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<section id="content">
<section class="module w100P">
<div id="error_bar" style = "display:none" class="message-bar error">
<p><span class="icon">Error:</span> Uh-oh, something broke! Close</p>
</div>
<div id="success_bar" style="display:none" class="message-bar success">
<p><span class="icon">Success:</span> Your changes have been made. Close</p>
</div>
<div class="module-inner">
<h3>DailyHunt Robots Uploader</h3>
<div class="module-content frm">
<form action="http://localhost:5000/uploadFile" method="post" enctype="multipart/form-data">
<table>
<tr>
<td>
<select name ="domain">
<option selected>Select Domain</option>
<option value="m">m</option>
<option value="www">www/option>
</select>
</td>
<td>
<input type="file" name="robots" accept='robots.txt'>
<button type="submit">Upload</button>
</td>
</tr>
</table>
</form>
<form action="http://localhost:5000/uploadApk" method="post" enctype="multipart/form-data">
<table>
<tr>
<td>
Enter APK you want to upload:
</td>
<td>
<input type="file" name="apk">
<button type="submit">Upload</button>
</td>
</table>
</form>
</div>
</div>
</section>
</section>
</section>
</body>
</html>
on hitting submit, it hits the flask api engine, where the 2 functions to be hit are defined as
#app.route('/uploadFile', methods=['POST'])
def upload_robots():
domain = request.form.get('domain')
if not domain:
return "Domain does not exist"
f = request.files[ROBOTS_IDENTIFIER]
if f.filename!=ROBOTS_FILE_NAME:
return "Incorrect file name. File name has to be robots.txt"
if domain == 'm':
robots_file_path = ROBOTS_MOBILE_FILE_PATH
elif domain == 'www':
robots_file_path = ROBOTS_WEB_FILE_PATH
else:
return "Domain not recognized"
filename = secure_filename(f.filename)
if os.path.isfile(robots_file_path + ROBOTS_FILE_NAME):
folder_name = datetime.utcfromtimestamp(int(os.path.getmtime(robots_file_path + ROBOTS_FILE_NAME))).strftime('%Y-%m-%d %H:%M:%S')
os.makedirs(robots_file_path + folder_name)
shutil.move(robots_file_path + ROBOTS_FILE_NAME, robots_file_path + folder_name +'/' + ROBOTS_FILE_NAME)
f.save(os.path.join(robots_file_path, ROBOTS_FILE_NAME))
return "file uploaded successfully, This will reflect in prod after the next cron cycle"
#app.route('/uploadApk', methods=['POST'])
def upload_apk():
f = request.files[APK_IDENTIFIER]
if f.filename.split('.')[-1] != 'apk':
return "upload file type must be apk"
filename = secure_filename(f.filename)
fname = '.'.join(f.filename.split('.')[0:-1])
rename = False
while os.path.isfile(APK_FILE_PATH + fname + '.apk'):
rename = True
fname += '_'
if rename:
shutil.move(APK_FILE_PATH + f.filename, APK_FILE_PATH + fname + '.apk')
f.save(os.path.join(APK_FILE_PATH, filename))
return "APK uploaded successfully"
Now when I hit submit the api returns some texts and it gets directed to a new page with just the text rendered. I would like this to remain in the same page and display the error_bar or success_bar divs in the html rather than it being redirected to a new page. Is it possible to achieve this without rendering a template or creating a new static html page?
Let's assume that your current page is: index.html.
I thought about two ways for resolving.
The first way,
After making request to your API, just render_template index.html again, including extra data (error=True/False, message=...) and you have update your index.html to check condition when receive extra data to display the error/success message.
=> By this way, you should modify the template and use Flask's render_template.
I prefer this way because of having control of the template (index.html) it just needs small update.
The second way, make request by using AJAX (XHR), when click submit button, you prevent the default form submit and use AJAX to request, then receive response and display the message.
The AJAX script can stay in index.html or another *.js where your index.html can locate.
=> By this way, you are working in non-Flask dependent way, by using Ajax you make request and modify the document (index.html) by using a little Javascript.

NameError: name '' is not defined using bottle in python

So I'm very new to all of this but I will try to tell you what question I have.
I'm trying to create a simpel wiki API using python, bottle and .txt since this is my assignment. I wrote my question further down, very thankful for quick help.
This is my .py:
from bottle import route, run, template, request, static_file, redirect
def read_articles_from_file():
articles = []
try:
my_file = open("wiki/articles.txt", "r").close()
content = my_file.read()
for article in content.slpit("/"):
if article != "":
articles.append(article)
return articles
except:
my_file = open("wiki/articles.txt", "w").close()
return articles
#route("/")
def index():
articles_from_file = read_articles_from_file()
return template("./static/index.html", articles = articles_from_file)
#route('/addera', method="POST")
#route('/addera', method="GET")
def save_article():
title = request.forms.get("title")
text = request.forms.get("text")
my_file = open("wiki/articles.txt", "a")
my_file.close()
redirect("/")
#route('/addera')
def show_save_article():
return template("./static/index.html")
#route('/<filename>.css')
def stylesheets(filename):
return static_file('{}.css'.format(filename), root='static')
if __name__ == '__main__':
run(host='localhost', port=8080, debug=True, reloader=True)
else:
print("Något gick fel")
This is my html for index:
<!doctype html>
<html lang="sv">
<head>
<meta charset="utf-8">
<link rel="stylesheet" type="text/css" href="style.css">
<title>Wiki</title>
</head>
<body>
<div class="header">
<div class="container">
<h1 class="header-heading">Inlämning 5 Wiki</h1>
</div>
</div>
<div class="nav-bar">
<div class="container">
<ul class="nav">
<li>Visa alla artiklar</li>
<li>Lägg till artikel</li>
</ul>
</div>
</div>
<div class="content">
<div class="container">
<div class="main" id="artiklar">
<h2>Basic wiki</h2>
<hr>
<h3>Alla artiklar</h3>
<ul class="list-unstyled">
% for article in articles:
<li>{{ article }}</li>
% end
</ul>
<hr>
</div>
</div>
</div>
</div>
<div class="footer">
<div class="container">
© Copyright 2017
</div>
</body>
</html>
Question:
Why do I get this error?
screen dump
You have a route for index ("/") and addera ("/addera"). In your index route, you are passing the articles to the template. You are not passing the articles in the addera route which is causing a bad reference in the template.

Uploading video from phone to Google App Engine Blobstore

I'm using Python on Google App Engine as the backend for a Desktop/Mobile web app for video sharing. I'm having an issue uploading from an iPhone to the blobstore. Usually the page redirects after the upload URL is created, but this doesn't happen on the phone. Instead the browser navigates to the upload URL, but nothing is uploaded.
I can select a video to upload just fine, and if it's a long video, the phone will take awhile to navigate to the next page which seems to imply that something is being transferred, but nothing ends up in the blobstore.
Videos are uploaded with the following Python code.
class UploadPage(webapp2.RequestHandler):
def get(self):
upload_url = blobstore.create_upload_url('/uploadvideo')
template_values = {
'upload_url': upload_url,
}
template = JINJA_ENVIRONMENT.get_template('upload.html')
self.response.write(template.render(template_values))
class UploadHandler(blobstore_handlers.BlobstoreUploadHandler):
def post(self):
upload = self.get_uploads()[0]
video = Videos(content=upload.key())
video.title = self.request.get('title')
video.description = self.request.get('description')
video.ratingDown = 0
video.ratingUp = 0
video.creator = users.get_current_user().nickname()
uniuqeIDFound = False
newID = random.randint(1000,9999)
while(uniuqeIDFound == False):
vids = db.GqlQuery("SELECT * "
"FROM Videos ")
uniuqeIDFound = True
for v in vids:
if (v.videoID == newID):
newID = random.randint(1,10000)
uniuqeIDFound = False
video.videoID = newID
db.put(video)
self.redirect('/home')
The upload page itself looks like this.
<!DOCTYPE html>
<html>
<head>
<title> Upload </title>
<meta charset="utf-8">
<link type="text/css" rel="stylesheet" href="/stylesheets/bootstrap.css" />
<link type="text/css" rel="stylesheet" href="/stylesheets/main.css" />
</head>
<body>
<div class="fill">
<div class="container">
<ul class="nav nav-tabs">
<li>Home</li>
<li class="active">Upload Video</li>
<li>Logout</li>
<li>Contact Us</li>
</ul>
<h2 class="addColor">Tribal Knowledge</h2><h3 class="addColor">Upload a Video</h3>
<form class="form-horizontal" action="{{ upload_url }}" method="POST" enctype="multipart/form-data">
<textarea placeholder="Title..." name="title" cols="50" rows="1" autofocus="autofocus" required></textarea><br>
<textarea placeholder="Description..." name="description" cols="50" rows="4" autofocus="autofocus"></textarea><br>
Upload File: <input type="file" name="file"><br> <input class="btn btn-success" type="submit" name="submit" value="Upload Video">
</form>
</div>
</div>
</body>
</html>

Categories