steadygaze / frame-randomizer

Web app to generate and guess random frames from a TV show.
GNU Affero General Public License v3.0
5 stars 3 forks source link
ffmpeg nuxt nuxt3

Frame Randomizer

This is a web app that generates and serves random frames from a TV show or similar content, as both a curiosity and a guessing game. It is free software licensed under the AGPL, meaning anyone can set up their own instance for their favorite show, as long as they make the source code (if modified) freely available.

Note that this software is agnostic of what show is randomized from. The content served is the instance operator's sole responsibility. If you have concerns about the content served by a specific instance, contact the site operator instead of the maintainers of this project.

Setting up your own

If you just want to set up an instance, you need to supply a JSON config file with information about your show, a recent version of Node.js, and have episodes accessible on disk. These instructions are for Linux, but it may be possible to set up a server on other platforms.

Prepare external dependencies

The built version doesn't require running npm install, instead pre-bundling all dependencies needed thanks to Nuxt. However, the following dependencies aren't packaged with it.

Show config

You need to supply a config file for the show. (Comments are not allowed in normal JSON; they are just used to document this example.) The episodes section can be downloaded from TMDB using its API and the tool frame-randomizer-create.

{
  "commonTimings": {
    // Common timings for all episodes.
    "credits": {
      // If there are credits that play until the end.
      "start": "22:12"
    }
  },
  // Fallback language if episode data is unavailable in the user's locale.
  "defaultLanguage": "en",
  // List of episodes.
  "episodes": [
    {
      "episode": 1, // Season number.
      "perLanguage": [
        {
          "language": "en",
          "name": "My First Episode", // Episode name.
          // Plot overview (synopsis).
          "overview": "In the first episode, wacky hijinks occurred."
        }
      ],
      "season": 1, // Season number.
      // Episode timing info, used to ignore sections. See Timings in utils/file.ts.
      "timings": {
        "intro": {
          // If there is an intro that plays from the beginning.
          "end": "1:10"
        }
      }
    } // Rest of the episodes...
  ],
  "name": {
    // Default language name.
    "name": "My Great TV Show",
    // Per-language show names.
    "perLanguage": [{ "language": "en", "name": "My Great TV Show" }]
  }
}

Running

Consult the RuntimeConfig section of nuxt.config.ts for all the settings that are available. Each will be configurable as environment variables. For example, you might create a simple script:

app.env:

export NUXT_SHOW_DATA_PATH="/path/to/episode_config.json"
export NUXT_PUBLIC_INSTANCE_NAME="My Randomizer"
export NUXT_VIDEO_SOURCE_DIR="/path/to/video/files/"
# Include file contents in variable.
export NUXT_PUBLIC_INSTANCE_INFO_DATA="$(cat info.json)"
export PORT=3000
# Additional configs...

Once these configs are set, grab a built version from releases on Github or build a custom one using the development instructions. Inside, running server/index.mjs will start the server.

# Simple version.
$ source app.env && node path/to/server/index.mjs
# Launch in a subshell so variables don't persist between runs. Otherwise, you
# may not realize that variables that you remove from app.env are still set in
# the current shell.
$ (source app.env && node path/to/server/index.mjs)
# sh version; don't have to (and can't) include "export" in app.env.
$ sh -ac '. ./app.env && node path/to/server/index.mjs'

Changing the favicon

There are a couple options for favicon in the base version without building a custom app.

Changing the favicon to a custom image requires building the app yourself. Unfortunately, moving new images into public/ in the prebuilt version won't work, because the file size of the image is hardcoded.

Stability

Currently, the software is in an unstable state; required options, option availability, and option interpretation can change between versions. Check the changelog or commit history when upgrading or merging from upstream.

Hosting

One of the main constraints for cloud hosting is the amount of disk needed. For a long running TV show, SSD can be quite expensive. Settling for regular disk may be the pragmatic option. At the time of this writing, Oracle Cloud's free tier offers a relatively large amount of SSD (200 GB).

Depending on load, the server can also be quite CPU-intensive due to running ffmpeg. However, unless high load is constant, you may be able to get by with less than you think thanks to pregeneration evening out load.

Development

This app is built on Nuxt 3; check out the Nuxt 3 documentation to learn more.

Setup

Make sure to install the dependencies:

npm install

Development Server

Start the development server on http://localhost:3000

npm run dev

Note that there will be an error message:

 ERROR
[vue-tsc] Found 0 errors. Watching for file changes.

This is a spurious error message/not an error; disregard it.

Production

Build the application for production:

npm run build

Locally preview production build:

npm run preview

Check out the deployment documentation for more information.

Known issue: Nuxt appears to hardcode some paths at build time, so running npm run build and then deploying on a server as a user with a different username will result in it looking for paths with the user it was originally built as. An easy, disgusting workaround is to symlink the entire user directory (/home/username) to the real user.

Linting

A Husky precommit hook is set up to check the formatting and lint the code before committing. You can run npm run format and npm run check to format and lint your code periodically.