Python Forum
Redirect upon submit button linking to send_file
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Redirect upon submit button linking to send_file
#1
Hi guys,

I've been researching and coding til my fingers have fallen off on this one!

I'm currently building a youtube video downloader simply to embed python into my brain by doing small projects.

So my current setup (just a brief overview).

1. index page to enter youtube URL - hit the submit button which then executes a function to download youtube video to folder on server, follwed by a return redirect to goto 'conversion complete' page.

2. Arrive at the 'conversion complete' page where you are shown a download button. Click this and it downloads the file but stays on that page with the download button still there.

button for step 2 is...

<a href='download' type='button'><button class='btn btn-default'>Download!</button></a>

My 'download' page doesn't actually show, it simply executes a send_file function to grab the file from step 1 off the server and give to user to download in browser.

So, ultimately, everythings works as I want it to, except that I want to redirect the page after clicking the download button (just to show a page saying download complete, or goto the index page, whatever, location isn't important, it's the fact it won't actually redirect anywhere), however I have seen many people have issues with a redirect following a send file and hope you guys can help!


Popped my python code below incase needed. Feel free to tell me if there's a better way to do something i'm doing. (I'm aware there maybe some imports at the top being used that aren't needed, I'll clean those up later along with removing get/post requests on routes that aren't needed - i put them there for now just to ensure that doesn't trip me up)

Really appreciate any help here! I've come this far without asking for help, but just need a little advice to get over the finish line!

###################################
####### Youtube Downloader ########
###################################

from flask import Flask, render_template, redirect, url_for, session, request, flash, send_file
from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField, BooleanField
from pytube import YouTube
import os
import random, string
import re

app = Flask(__name__)

app.config['SECRET_KEY'] = 'mysecretkey'
session_id = ''.join(random.choices(string.ascii_letters + string.digits, k=6))

######################################
############## Forms #################
######################################

class url_form(FlaskForm):
    link = StringField('Enter link of YouTube video you would like to convert...')
    audio = BooleanField('Audio Only')
    submit = SubmitField('Convert')

######################################
############## Functions##############
######################################

def download_video(link, just_audio):

    yt = YouTube(link)
    download_path = 'conversions/'
    #global myvar
    if just_audio == True:

        stream = yt.streams.filter(only_audio=True).first()
        tag = 'video'


    else:

        stream = yt.streams.filter(adaptive=True).first()
        tag = 'audio only'

    download_video.name = yt.title
    download_video.cleanString = re.sub('[^a-zA-Z0-9 \n\.]', '', download_video.name)
    download_video.thumbnail = yt.thumbnail_url
    download_video.path = stream.download(filename = download_video.cleanString, output_path = download_path)

    return



######################################
############## MAIN ##################
######################################

@app.route('/', methods=['GET', 'POST'])
def index():
    result = False
    form = url_form()


    if form.validate_on_submit():

        session['link'] = form.link.data

        if form.audio.data:
            just_audio = True
        else:
            just_audio = False

        session['just_audio'] = just_audio
        link = session.get('link')
        just_audio = session.get('just_audio')
        download_video(link, just_audio)
        #download_video(link, just_audio)
        #return send_file(download_video.path, attachment_filename=download_video.cleanString + '.mp4', as_attachment=True) # CURRENTLY GETTING FROM ROOT FOLDER!
        return redirect(url_for('conversion_complete'))
    return render_template('index.html', form=form, result=result) # URL Variable here relates to decorator variable


@app.route('/conversion_complete', methods=['GET', 'POST'])
def conversion_complete():


    return render_template('conversion_complete.html') # URL Variable here relates to decorator variable


@app.route('/download/', methods=['GET'])
def download():

    return send_file(download_video.path, attachment_filename=download_video.cleanString + '.mp4', as_attachment=True) # CURRENTLY GETTING FROM ROOT FOLDER!

    return render_template('result.html')

if __name__ == '__main__':
    app.run(debug=True)
Reply
#2
Disappointed that nobody was able to help however, I've figured this out and I hope it helps somebody in my position in the future - sorry if the formatting is a touch messy, it's been a long day, but will tidy up if required!

The problem I found is that when pressing download and using the route with the send_file function on as the href, the send_file kicked in, but not the template.

So, do this!...

1. HTML Page and Flask route with your download button (please note, your file will exist on the server at this point, i.e I generated mine on generate.html and then sent the user to here, passing over the file location to this Flask route) - for this example, lets say download.html.

2. HTML Page and Flask route you want to display after downloading the file, i.e Thanks for your download - for this example, let's say thankyou.html

3. Flask route with your send_file function. (HTML page not needed as it wont render after the send_file is called.) - let's call this flask route grab_file

On download.html

<a href='download' target='_self' type='button'>
  <button class='btn btn-default'>Download!</button>
</a>
Flask route for download.html located in (for example) your app.py

@app.route('/download/', methods=['GET'])
def download():
        filename = download_video.session_id

        return render_template('download.html') 
On thankyou.html

Within the body tags.

<script>

  $(document).ready(function() {
    window.location.replace("/grab_file/");
    // Code to run as soon as the page is ready
  })

 </script>
Don't forget to call jquery between the head tags.

<head>

  <script src='https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js'>

</script>
</head>
...and on your route for thankyou.html

@app.route('/thankyou/', methods=['GET'])
def thankyou():


    return render_template('thankyou.html')
On your grab_file route - this is the route we're calling in the jquery over on thankyou.html...

@app.route('/grab_file/', methods=['GET', 'POST'])
def grab_file():

    return send_file(CHECK THE DOCS FOR ATTRIBUTES HERE but you need as_attachment=True)
Reply
#3
Since moderators are all volunteers, occasionally a thread will not get answered on the same day posted,
however, thanks for sharing.
Your thread has been moved to code sharing so others can find it.
Thanks again.
Reply
#4
Totally understand Larz!

It's frustrating when stuck on an issue for days on end, however I didn't mean for my post to come across as a dig at the moderators.

Hope the post helps somebody out!
Reply
#5
Quote:however I didn't mean for my post to come across as a dig at the moderators.
No problem, didn't think it was.
Jamesunsworth likes this post
Reply


Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020