How would I serve / stream a video file?

I want to serve or stream video files in the phoenix web ui of my software. I store video filenames and file sources in my database. The source table have columns called id and location. When a user visits /video/1/test.mkv the video file called test.mkv from the source with the id of 1 should start playing. Not all video files live in the same source and the sources could be anywhere on filesystem, but not inside the the priv/static directory. Those videos files can be placed in this sources at any time after deployment and if a requested file exists in the given source it should be played in the browser. Otherwise 404 error should be sent along with a error message.
What do you think? What would be the best way to do this? Please ask if something is unclear!

Thanks for your time!

1 Like

It should be the task of plug static to serve those files, but if You don’t want to put them in priv/static, You might serve them with a controller.

You can use send_file, or send_download.

Or You can have a template with video tag, to render those files.

The problem with the static plug is that plug static serves files that was compiled with the software. I need to start playing the files that was added after the software was deployed. The files should start playing directly and load more of the video as the user continues to play it. Videos are usually bigger than pictures in file size and if the internet connection from the browser to the server was slow I wouldnt want fully load the file in the browser before playing it. I am not fully sure how send_file does this but I will look into it.


No, I don’t think so… You can configure plug static to accept wildcards, or directories.

Then what if I have one source in /mnt/video with source id and another in /mnt/video2 with source id 2? I need to serve / stream them as with the path as I said earlier. Sure I can use Plug Static for serving files outside of priv/static. But not like this. Also isnt it a bit weird to use to use a plug called static to serve content that gets added during runtime?

Static files should be in priv/static. If You want to put the files anywhere, then use a controller to serve those files.

Parameters passed to controllers should allow file selection, them just serve them…

Something like /videos/:id/:filename

By the way plug static serve this by default, and your OP title is … static video file.

only: ~w(css fonts images js favicon.ico robots.txt)

Anything put in css, or images etc. will be served. In addition, those files are not compiled.

What do you mean by “just serve them”? Using send_file?
Aha well what I meant by “static” was that it is a non changing video file, I is not a live stream or so. The files do not belong in priv/static because they are added duing runtime after deployment. I am changing my title to remove the word “static”.

It’s in your your title… How would I serve…

Yes, and that is my question. How would play the video in the browser? I am unsure how to send it to the browser.

You need a controller that serve those file with a send_file.

Then You can use thoses path as the src of a video tag.

Would this start playing the file and load more when if the user continue to watch?

Yes, video tag has controls attributes.

No, loading more needs to be triggered…

Then I am still unsure how to do this. How would I trigger to load more?

It depends on the player.

I often use jwplayer which has an option for playlist. With a playlist in automode, then I can run multiple videos.

But it is a commercial product.

You might hook an event when the player stop to play.

1 Like

In case you are still struggling with this problem, you can add several plug Plug.Static closes to the endpoint file to correspond different locations on your file system and configure your directories in config file.
For example, like this:

plug Plug.Static,
  at: "/uploads", from: Application.get_env(:my_app, : uploads_dir) |> Path.expand(), gzip: false

plug Plug.Static,
  at: "/other_uploads", from: Application.get_env(:my_app, : other_uploads_dir) |> Path.expand(), gzip: false

As for the browser part of the question, video tag has event “ended”, you can start playing next video using a callback for this event.
Like this:

document.querySelector('.my-video').addEventListener('ended', function(ev) {playNextVideo();});
function playNextVideo() {/* here is the logic to start next video */}

I have the suspicion that you all get the question wrong.

If I understand @smolcatgirl correctly, she wants true video streaming.

What send_file or Plug.Static do is to send the whole video file to the browser.

So she wants partial video streaming. Like buffering x amount of seconds ahead of current playtime or if the user starts the video from the middle, don’t even load the first half.

I can’t give an answer for how to do this but I hope someone else might have an idea.


Well this article is outdated but have very useful information: . Not hard to make it work with the lastest version of Phoenix.

But the problem when you want to stream videos is to allow different qualities/bitrate depending on bandwidth and/or device screen-size/performance.

1 Like

Exactly, thank for you understanding! :slight_smile:

1 Like

Thanks for the link! I will look into it. :slight_smile: