How to self-host a movie night!

about

de niro taxi driver cinema

It's 2021 and we've been at home for a....long....fucking...time. All over the world, movie theaters have been closed. We can't have friends over. For many of us, movies are a common bond, and the joy of sharing a cinematic experience with friends and family can be powerful and amazing...and a great way to unplug from the grind of work and the existential stress of modern life.

Especially in covid times, it's hard to connect and to bond. Watching a movie together is a great way to create a shared experience.

There were many commercial tools created during the pandemic, but they all require a subscription to a paid service.

Maybe you're just a DIY kind of person, or maybe (more likely?) the types of films you want to watch are not readily available on the commercial services.

Here in the future, we have technology on our side! With a few tools and some setup, we can self-host our own movie night streaming server and watch whatever we want, whenever we want, with our friends and family.

MovieNight software

The first critical piece of software in this setup is zorchenhimer's MovieNight server. If you are experienced, maybe you can just skip this entire HOWTO and just follow that README and be in business. Godspeed!

This software is a server that receives the master RTMP video stream and serves up that stream to a browser-based player app.

You can run this software by setting up a golang dev environment and running it right from the cloned repo.
I think it is just easier to run MovieNight via docker.

Ideally, you would just clone the zorchenhimer repo and follow the docker instructions. If you're especially lazy and don't mind being out of date, you can leverage a pre-built docker image from spencerhughes (that's what I do)

MovieNight configuration

There are a few things to consider when running MovieNight:

Earlier versions used environment vars to configure everything, but it looks like the current version now uses a file. I have startup configured in a file named movienight-run.sh so that I do not have to remember or type long docker commands:

#!/bin/bash

DIR=$(pwd)

# change inbound RTMP port here if needed
# RTMP_PORT=1234

docker run \
  -d \
  -p 127.0.0.1:8089:8089 \
  -p "${RTMP_PORT}:1935" \
  -v "${DIR}/movienight-settings.json:/config/settings.json" \
  --name movienight \
  --restart unless-stopped \
  spencerhughes/movienight:latest

You can find an example settings file and customize it for your specific needs. I recommend setting up a secure admin password and changing the default stream key to something else.

transcoding

Note: This section subject to change if MovieNight changes from FLV to HLS, like in this issue

The client-side browser application is pretty particular about the video stream format. If you have a video file that you want to watch with friends, you will need to transcode the file to a new format for it to be compatible. While it is possible (in theory) to do this in realtime, there are many factors in play and I have found it to be much more reliable to transcode in advance of a screening.

The current version of MovieNight uses flv.js on the client side, and this requires video to be in FLV format. Don't worry, even though it says "Flash Video" in the name, it doesn't need Flash Player or any shitty Adobe addons. It's just a file format.

Apparently you can use OBS for this. If you're streaming from a camera this is fine, and apparently OBS can also do the transcoding and I had some success with this...but for my main use case, I wanted to be able to run a lightweight streamer on a cloud instance.

I use ffmpeg to do the transcoding. Through a process of experimentation and testing, I settled on the following:

You can run the following:

$ ffmpeg -i my-input-movie.mkv \
    -c:v libx264 \
    -vf scale=-1:720 \
    -crf 18 \
    -c:a aac \
    -ar 44100 -ac 2 \
    my-output-movie-720p.flv

There's no great way to accurately predict how long the transcoding process will take. I highly recommend doing this well in advance, and, to save time, I run this on physical hardware instead of a cloud instance. Running on a cloud node is fine, but it will likely take much longer (think single-digit multipliers).

On common laptops, I would expect encodes to run somewhere between 0.75x and 3x, which means a 90min movie would take somewhere between 20min and 115min. You should experiment to get the feel for this...but there are also so many factors. CPU, memory, and even video content can all impact this.

If you find other settings that work better, please let me know! (would love to hear it).

streaming

Now that you have your video file prepared, you can now stream ito to the RTMP port on the MovieNight server. As mentioned above, you might be able to use OBS for this, but I find it easy to run ffmpeg inside of a screen session on the same cloud host that the MovieNight server is running on. Note that you may need to change the RTMP port if you have customized it:

$ ffmpeg -re -i my-output-movie-720p.flv \
    -c copy -f flv \
    rtmp://your-movienight-host.example.com:1935/live/YourSpecialStreamKey

This will run in "real time", or rather, it will basically take as long as your video duration is. I run it in a screen session so that things keep working even if my network connection gets screwed up or I have to reboot or something.

Now that ffmpeg is streaming the video data over to MovieNight, it is time to open up the web client by visiting http://your-movienight-host.example.com:8089.

The UI is pretty straightforward, but in most browsers you will have to click the video or play or something to get thing started. Don't fret if the client buffers/hiccuups in the first minute or two -- it increases its buffer so that video plays smoothly.

Your video playback will NOT be perfectly synchronized with other viewers. In my experience, you could be up to a minute ahead/behind other viewers. Your best bet is to have everybody refresh their tab and click play immediately. It will be good enough for most uses.

I'm sure the chat is cool, but we don't use it (you probably have 100 other chat services that you're already using).

nginx

For several reasons (like TLS and default port mapping) it is often desirable to run a reverse proxy in front of your MovieNight server. NGINX running on the same host is a good choice for this. I also recommend using certbot/letsencrypt so that you can provide TLS.

If you are running movienight on movienight.example.com your nginx config may look something like this:

# /etc/nginx/sites-enable/movienight.conf

upstream movienight-site {
    server 127.0.0.1:8089;
}
server {
    server_name movienight.example.com;
    root /home/www/movienight/;
    access_log /var/log/nginx/movienight.log;

    location / {
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "Upgrade";
        proxy_pass http://movienight-site;
    }

    # certbot will inject additional things here.
}

hosting

statements

not just going to succumb to what netflix wants us to watch. yes I pay for netflix and spend way way too much money on streaming video services.

I would love a way to pay the creators directly.

what about watching on a tv?
kodi etc. laptop hookup chromecast tab

what about scaling?