~mser/emote-server

A simple application to list and serve emotes
Merge branch 'hotfix/1.3.1'
Bump API version

clone

read-only
https://git.sr.ht/~mser/emote-server
read/write
git@git.sr.ht:~mser/emote-server

You can also use your local clone with git send-email.

#emote-server builds.sr.ht status

A simple application to list and serve emotes

This is a small application to serve emotes (or other files) over a simple HTTP API.

#Table of contents

#Install

The recommended way to run is via Docker. Basic instructions on how to run without it are also provided.

#Installing with Docker

To use this application with Docker, you can simply pull the prebuilt image from Docker Hub:

user@local:~$ docker pull mserajnik/emote-server

Alternatively, you can also build the image yourself. The user that is used inside the container has UID 1000 and GID 1000 by default. You can adjust this (e.g., to match your host UID/GID) by providing the arguments USER_ID and GROUP_ID when making a build.

#Installing without Docker

To install without Docker, you can simply clone the repository and install dependencies.

user@local:~$ git clone https://git.sr.ht/~mser/emote-server
user@local:~$ cd emote-server
user@local:emote-server$ yarn

#Dependencies

  • Docker (when using Docker)
  • Node.js (when not using Docker)
  • Yarn (when not using Docker)

This application should work with both the latest LTS and the latest stable version of Node.js. If you encounter any issues with either of those versions when not using Docker, please let me know.

#Updating

This application follows semantic versioning and any breaking changes that require additional attention will be released under a new major version (e.g., 2.0.0). Minor version updates (e.g., 1.1.0 or 1.2.0) are therefore always safe to simply install.

When necessary, this section will be expanded with upgrade guides for new major versions.

#Updating with Docker

Simply pull the latest Docker image to update:

user@local:~$ docker pull mserajnik/emote-server
#Updating without Docker

If you chose not to use Docker, you can update via Git:

user@local:emote-server$ git pull
user@local:emote-server$ yarn

#Usage

#Running with Docker

To make using Docker as easy as possible, a working Docker Compose example setup is provided. To get started with this example setup, simply duplicate docker-compose.yml.example as docker-compose.yml and adjust the variables in the environment section as described here.

Finally, start the containers:

user@local:emote-server$ docker-compose up -d

#Running without Docker

To run without Docker, you will first need to duplicate the .env.example as .env and adjust the variables as described here.

After that, you can start the application:

user@local:emote-server$ yarn start

#Configuration

Configuration is done entirely via environment variables. Please pay special attention to the instructions to prevent issues.

  • EMOTE_SERVER_PUBLIC_URL=http://localhost:8000: the public URL the server will use to display file URLs. No trailings slashes.
  • EMOTE_SERVER_PORT=8000: the port the server is listening on.
  • EMOTE_SERVER_ACCESS_KEY=: an arbitrary string used as access key for the server's API. Can be of any (reasonable) length. If left empty, the respective routes will be publicly accessible.
  • EMOTE_SERVER_NUMBER_OF_WORKERS=: sets the number of workers. By default, one worker per logical CPU core is used. You might want to decrease or increase that number, depending on your needs/hardware. In general, the more workers are running, the more requests can be handled simultaneously. But note that increasing the number of workers beyond the number of logical CPUs might be detrimental to performance or cause even more serious issues (e.g., crashes).
  • EMOTE_SERVER_SUPPORTED_FILE_EXTENSIONS=png,gif,apng: sets the file extensions for the files the server should serve. The extensions need to be separated with ,.
  • EMOTE_SERVER_FILE_SIZE_LIMIT=0: sets the file size limit in bytes when uploading files via the HTTP API. If set to 0, there is no limit.
  • EMOTE_SERVER_EMOTES_PATH=./emotes: the path emotes are served from. Can be relative or absolute.
  • EMOTE_SERVER_FROZEN_EMOTES_PATH=./frozen-emotes: the path frozen emotes are served from. Can be relative or absolute.

#API

#General

Request and response bodies are always in JSON format (except when uploading or downloading the actual files). The Authorization header in the format Authorization: Bearer <EMOTE_SERVER_ACCESS_KEY> or the query parameter accessKey=<EMOTE_SERVER_ACCESS_KEY> is used to authenticate for all routes unless EMOTE_SERVER_ACCESS_KEY is empty, in which case these routes will be publicly accessible as well.

The base route (GET /) does not require authentication, but can optionally be used to verify access keys. To do this, simply pass an access key as you normally would, in which case it will either respond normally when using a valid access key or with an AccessKeyError when using an invalid one.

In case of any occuring errors, the response will have the following format and an appropriate HTTP status code:

{
  "success": false,
  "error": <error name>
}
#Routes
#Base

Responds with the version number and the API version number of the installation. The API version number will increase by 1 every time an existing API endpoint is modified in a way it behaves differently than before or removed altogether.

Route: GET /

Response on success:

{
  "emoteServer": {
    "version": <version number of the application>,
    "apiVersion": <API version number of the application>
  }
}

Possible errors:

  • AccessKeyError
#Emotes
#Adding emotes

Adds a new emote. If a file with the same name already exists it will be overwritten. The request has to be of type multipart-form-data and the file needs to have the key emote.

Route: POST /emotes

Response on success:

{
  "success": true,
  "message": "Add"
}

Possible errors:

  • AccessKeyError
  • FileSizeError
  • AddError
#Deleting emotes

Deletes the emote with the given filename. If the file does not exist, it will respond with an error.

Route: DELETE /emotes/<emote filename>

Response on success:

{
  "success": true,
  "message": "Delete"
}

Possible errors:

  • AccessKeyError
  • DeleteError
#Listing emotes

Responds with the list of emotes available to be served.

Route: GET /emotes

Response on success:

{
  "success": true,
  "emotes": [
    {
      "name": <name of the emote>,
      "url": <URL of the emote>
    }
    // […]
  ]
}

Possible errors:

  • AccessKeyError
  • ListError
#Getting emotes

Responds with the requested emote.

Route: GET /emotes/<emote filename>

Output on success: The requested emote

Possible errors:

  • AccessKeyError
  • GetError
#Getting frozen emotes

Responds with a "frozen" PNG version (containing the first frame) of the requested GIF or APNG emote.

Route: GET /frozen-emotes/<GIF/APNG emote filename>

Output on success: The requested frozen emote

Possible errors:

  • AccessKeyError
  • GetError
  • GenerationError
#Deleting frozen emotes

Deletes all frozen emotes (without touching their source emotes). Useful for forcing regeneration (e.g., after overwriting an emote with another of the same name).

Route: DELETE /frozen-emotes

Response on success:

{
  "success": true,
  "message": "Delete"
}

Possible errors:

  • AccessKeyError
  • DeleteError

#Maintainer

Michael Serajnik

#Contribute

You are welcome to help out!

Open a ticket or send a patch.

#License

AGPLv3 © Michael Serajnik