I hate writing because I’m terrible at it. As a result, I don’t write.
This post took me awhile to write because I hate writing.

haha welcome to my tumblr XD

Spooktober

Every year for October Spooktober I like to set up a 24/7 livestream of horror movies for my friends. Last year I had a pretty jank setup using OBS and the VLC plugin to stream a playlist of movies to a selfhosted Owncast instance.

The results were mixed. OBS on a Windows VM without a dedicated GPU hogged a ton of CPU, stuttered, froze, etc. There was a huge amount of delay in the player, resulting in inconsistent timing for everyone watching.

This year I used a more advanced stack consisting of the following elements:

  • ErsatzTV + Plex (I started off using Jellyfin, but there were some weird quirks I kept running in to with how media was handled)
  • OvenPlayer
  • nginx
  • a shitty plugin that I wrote for Red Discord Bot so people could see the schedule via Discord. It’s not good, I will not share it.

Setting it up

I already had an existing Plex setup, so getting the intial setup done was as easy as setting up a new VM and installing ErsatzTV. Connecting Ersatz to Plex was easy, and then I set up a simple collection of all movies tagged “horror”, and a few TV shows that also fit the bill (Tales from the Crypt fucking rules).

With ErsatzTV serving a channel, I had to figure out a way to make it public and not expose any of the rest of the Ersatz management console. I did this through nginx.
If you’re familiar with nginx, the below configuration should make sense. I’m proxying to the stream VM, and only allowing access to playlist files. I only have one channel, so the channel ID is 1.

upstream spooky {
  zone spooky 64k;
  server 192.168.254.254:5002;
  keepalive 2;
}

map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      "";
}

server {
    server_name my.stream.cool;
    listen 443 ssl;

    location / {
    	root /var/www/stream;
    }

    location /iptv {
        deny all;
    }
    location /iptv/channel {
        deny all;
    }
    location /iptv/session {
        deny all;
    }
    location /iptv/* {
        deny all;
    }

    location ~* ^/iptv/session/1/.+\.(ts|m3u8)$ {
        deny all;
        proxy_pass https://spooky;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "Upgrade";
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $host;
        proxy_connect_timeout   24h;
        proxy_send_timeout	24h;
        proxy_read_timeout	24h;
		proxy_buffers 4 256k;
		proxy_buffer_size 128k;
		proxy_busy_buffers_size 256k;
    }

    location /iptv/channel/1.m3u8 {
        proxy_pass https://spooky;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "Upgrade";
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $host;
        proxy_connect_timeout   24h;
        proxy_send_timeout	24h;
        proxy_read_timeout	24h;
		proxy_buffers 4 256k;
		proxy_buffer_size 128k;
		proxy_busy_buffers_size 256k;
    }
}

With the stream now available over the internet, I set up a web page with OvenPlayer and HLS, then invoked OvenPlayer like this:

const player = OvenPlayer.create("player_id", {
    autoStart: true,
    mute: true,
    controls: true,
    sources: [
        {
            type : "hls",
            file: "https://my.stream.cool/iptv/channel/1.m3u8?mode=segmenter"
        }
    ]
});

Boom, ErsatzTV on tap.

What I watched this year

  1. Spookies
  2. Terror at Tenkiller
  3. Mandy
  4. The Blob
  5. Bone Tomahawk
  6. The Borrower
  7. The Brood
  8. Butcher, Baker, Nightmare Maker
  9. C.H.U.D.
  10. Chopping Mall
  11. The Conjuring
  12. Dead Space: Downfall
  13. Don’t Breathe
  14. The Empty Man
  15. Friday the 13th: Part 2
  16. Jason X
  17. Older Gods
  18. Pledge Night (i fucking hate this movie why did i watch it three times)
  19. Phantasm
  20. Return of the Living Dead
  21. A Cure for Wellness
  22. mother!