-1

I am attempting to redirect a URL in Flask. e.g : localhost/x/e/f/i.mp4. Where e and f are integer inputs (There isn't an actual file) to a another URL, which actually has the file name i.mp4. e.g localhost/static/i.mp4.
This URL is part of a request in a template. But with the template, it will request i.mp4, which is localhost/e/f/i.mp4. I have tried using add_url_rule with the endpoint being redirect_to=send_from_directory(something), send_from_directory after the template, send_from_directory before the template, but that only sends the mp4. The current snippet for Flask is this.

    @app.route('/watch/<int:s>/<int:ep>/', methods=['GET'])
    def vid(s,ep):
        return app.add_url_rule(f'/watch/{s}/{ep}/S{s}-{ep}sub.m4v', redirect_to=send_from_directory('static', f'S{s}-{ep}sub.m4v'))
    def sub(s, ep):
        return app.add_url_rule(f'/watch/{s}/{ep}/S{s}-{ep}.vtt', redirect_to=send_from_directory('static',f'S{s}-{ep}.vtt'))
    def watch(s, ep):
        return render_template('watch.html', s=s, ep=ep)

The template is this:

<!DOCTYPE html>
<html lang="en" style="height:100%;">
<head>
    <title>{{s}}-{{ep}}</title>
</head>
<body style="margin:0; text-align: center; height:100%;">
    <video autoplay=" "controls="" style="margin: 0 auto; height:100vh;">
        <source src="S{{s}}-{{ep}}sub.m4v" type="video/mp4">
        <track label="English" kind="subtitles" srclang="en" src="S{{s}}-{{ep}}.vtt" default>
    </video>
</body>
</html>
Phoenix
  • 188
  • 1
  • 15

1 Answers1

1

I think you're over-complicating things. Also the first version of your question was clearer, so based on that...

It's not possible to decorate several functions with one app.route decorator like you were trying. The way to put this together is probably to have your watch route render the template, then have a vid and sub route, which the browser hits when the watch page loads:

@app.route('/vid/<int:s>/<int:ep>')
def vid(s,ep):
    return send_from_directory('static', f'S{s}-{ep}sub.m4v')

@app.route('/sub/<int:s>/<int:ep>')
def sub(s, ep):
    return send_from_directory('static',f'S{s}-{ep}.vtt')

@app.route('/watch/<int:s>/<int:ep>', methods=['GET'])
def watch(s, ep):
    return render_template('watch.html', s=s, ep=ep)

Then in the template you can use the url_for function to render the URLs for the vid and sub routes:

<source src="{{ url_for('vid', s=s, ep=ep) }}" type="video/mp4">
<track label="English" kind="subtitles" srclang="en" src="{{ url_for('vid', s=s, ep=ep)}}" default>

While the above shows how to pass these variables around in Flask, it's probably worth mentioning that this isn't really the best way to serve video content. It will probably do if you want to view your own media collection through a browser.

v25
  • 7,096
  • 2
  • 20
  • 36
  • So the template will pass the variables used in the ```/watch``` into ```/vids``` and ```/sub```? – Phoenix Apr 03 '20 at 02:20
  • 1
    Yeah. The first `{{ url_for() }}` function in my second code block will render the URL as: something like `/vid/01/02` and serve the file `static/S01-02.vtt`. However it's worth noting by using this method (send_from_directory) that the app server is then handling serving that file. This should probably be left to the reverse proxy. Really you want to use `{{ url_for('static', filename=filename) }}` then pass a value which was computed in python for `filename` to the render_template function. This still doesn't solve the problem of it not being the best way to serve video files. – v25 Apr 03 '20 at 02:24