Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Flask send_file not sending file

I'm using Flask with send_file() to have people download a file off the server.

My current code is as follows:

@app.route('/', methods=["GET", "POST"])
def index():
    if request.method == "POST":
        link = request.form.get('Link')
        with youtube_dl.YoutubeDL(ydl_opts) as ydl:
            info_dict = ydl.extract_info(link, download=False)
            video_url = info_dict.get("url", None)
            video_id = info_dict.get("id", None)
            video_title = info_dict.get('title', None)
            ydl.download([link])
        print("sending file...")
        send_file("dl/"+video_title+".f137.mp4", as_attachment=True)
        print("file sent, deleting...")
        os.remove("dl/"+video_title+".f137.mp4")
        print("done.")
        return render_template("index.html", message="Success!")
    else:
        return render_template("index.html", message=message)

The only reason I have .f137.mp4 added is because I am using AWS C9 to be my online IDE and I can't install FFMPEG to combine the audio and video on Amazon Linux. However, that is not the issue. The issue is that it is not sending the download request.

Here is the console output:

127.0.0.1 - - [12/Dec/2018 16:17:41] "POST / HTTP/1.1" 200 -
[youtube] 2AYgi2wsdkE: Downloading webpage
[youtube] 2AYgi2wsdkE: Downloading video info webpage
[youtube] 2AYgi2wsdkE: Downloading webpage
[youtube] 2AYgi2wsdkE: Downloading video info webpage
WARNING: You have requested multiple formats but ffmpeg or avconv are not installed. The formats won't be merged.
[download] Destination: dl/Meme Awards v244.f137.mp4
[download] 100% of 73.82MiB in 00:02
[download] Destination: dl/Meme Awards v244.f140.m4a
[download] 100% of 11.63MiB in 00:00
sending file...
file sent, deleting...
done.
127.0.0.1 - - [12/Dec/2018 16:18:03] "POST / HTTP/1.1" 200 -

Any and all help is appreciated. Thanks!

like image 976
jackmerrill Avatar asked Dec 12 '18 16:12

jackmerrill


2 Answers

You need to return the result of send_file:

@app.route('/', methods=["GET", "POST"])
def index():
    if request.method == "POST":
        link = request.form.get('Link')
        with youtube_dl.YoutubeDL(ydl_opts) as ydl:
            info_dict = ydl.extract_info(link, download=False)
            video_url = info_dict.get("url", None)
            video_id = info_dict.get("id", None)
            video_title = info_dict.get('title', None)
            ydl.download([link])
        print("sending file...")
        return send_file("dl/"+video_title+".f137.mp4", as_attachment=True)
    else:
        return render_template("index.html", message=message)

Unfortunately, this will make it harder for you to "clean up" after sending the file, so you probably want to do that as part of scheduled maintenance (e.g. run a cron job to delete old downloaded files). See here for more information about the problem.

like image 136
Rob Bricheno Avatar answered Oct 12 '22 17:10

Rob Bricheno


Extending @Rob Bricheno's answer, if you need to clean up after the request, you can create a deferred method that will execute after the request is complete:

@app.route('/', methods=["GET", "POST"])
def index():
    if request.method == "POST":
        link = request.form.get('Link')
        with youtube_dl.YoutubeDL(ydl_opts) as ydl:
            info_dict = ydl.extract_info(link, download=False)
            video_url = info_dict.get("url", None)
            video_id = info_dict.get("id", None)
            video_title = info_dict.get('title', None)
            ydl.download([link])
        print("sending file...")
        response = send_file("dl/"+video_title+".f137.mp4", as_attachment=True)
        # Create handle for processing display results (non-blocking, excecutes after response is returned)
        @flask.after_this_request
        def add_close_action(response):
            @response.call_on_close
            def process_after_request():
                try:
                    print("file sent, deleting...")
                    os.remove("dl/"+video_title+".f137.mp4")
                    print("done.")
                except Exception as e:
                    logger.exception(str(e))
        return response
    else:
        return render_template("index.html", message=message)
like image 37
VoteCoffee Avatar answered Oct 12 '22 18:10

VoteCoffee