├── LICENSE ├── README.md ├── docker-compose.yml.template ├── unicorn-loadbalancer ├── Dockerfile └── rootfs │ └── etc │ ├── cont-init.d │ ├── 00-check-path_plex_usr │ ├── 01-check-database_sqlite_path │ ├── 02-install-ffmpeg │ └── 03-remove-plex_relay │ ├── fix-attrs.d │ └── 00-runscripts │ └── services.d │ └── unicorn-loadbalancer │ └── run └── unicorn-transcoder ├── Dockerfile └── rootfs └── etc ├── cont-init.d ├── 00-setenv └── 01-install-transcoder ├── fix-attrs.d └── 00-runscripts └── services.d └── unicorn-transcoder └── run /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 magn2o 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Unofficial Docker container for [UnicornLoadBalancer](https://github.com/UnicornTranscoder/UnicornLoadBalancer) 2 | 3 | I created these containers in an effort to make deploying [UnicornTranscoder](https://github.com/UnicornTranscoder) quick and painless in a docker environment. The unicorn-loadbalancer container includes both UnicornLoadBalancer *as well as* UnicornFFMPEG. In addition to this container, you will also need at least one instance of [unicorn-transcoder](https://hub.docker.com/r/magn2o/unicorn-transcoder). 4 | 5 | # magn2o/unicorn-loadbalancer 6 | 7 | Ideally, this container should be used behind a reverse SSL proxy. 8 | 9 | ## Usage 10 | 11 | It is strongly advised to use this within a proper [docker-compose](https://github.com/magn2o/unicorn-docker/blob/master/docker-compose.yml.template) configuration. However, should you wish to do things the hard way, please see below: 12 | 13 | **Note**: You will want to ensure that you have a Plex container already configured and running before launching a load balancer. 14 | 15 | ~~~ 16 | docker run \ 17 | -d \ 18 | --name unicorn-loadbalancer \ 19 | -p 3001:3001/tcp \ 20 | -e SERVER_HOST="127.0.0.1" \ 21 | -e SERVER_PORT="3001" \ 22 | -e SERVER_PUBLIC="http://[hostipaddress]:3001/" \ 23 | -e PLEX_HOST="[plexipaddress]" \ 24 | -e PLEX_PORT="32400" \ 25 | -e PLEX_PATH_SESSIONS="/config/Library/Application Support/Plex Media Server/Cache/Transcode/Sessions" \ 26 | -e DATABASE_SQLITE_PATH="/config/Library/Application Support/Plex Media Server/Plug-in Support/Databases/com.plexapp.plugins.library.db" \ 27 | -e LB_URL="http://[loadbalanceripaddress]:3001/" \ 28 | -h [hostname] \ 29 | -v [path]:/usr/lib/plexmediaserver \ 30 | -v [path]:/config \ 31 | -v [path]:/media:ro \ 32 | magn2o/unicorn-loadbalancer 33 | ~~~ 34 | 35 | # magn2o/unicorn-transcoder 36 | 37 | One of the unique features of this container is that it will automagically identify the Plex version and necessary codec builds at runtime. This means that you can update your Plex server at will and then simply restart this container to **maintain version parity without any manual edits**. 38 | 39 | ## Usage 40 | 41 | ~~~ 42 | docker run \ 43 | -d \ 44 | --rm \ 45 | --name unicorn-transcoder \ 46 | -p 3000:32400/tcp \ 47 | -e SERVER_PORT="32400" \ 48 | -e LOADBALANCER_ADDRESS="http://[loadbalanceripaddress]:3001" \ 49 | -e INSTANCE_ADDRESS="http://[hostipaddress]:3000" \ 50 | -e PLEX_TOKEN="[x-plex-token]" 51 | -h [hostname] \ 52 | magn2o/unicorn-transcoder 53 | ~~~ 54 | -------------------------------------------------------------------------------- /docker-compose.yml.template: -------------------------------------------------------------------------------- 1 | version: '3' 2 | 3 | services: 4 | plex: 5 | image: plexinc/pms-docker:latest 6 | networks: 7 | - plex-network 8 | ports: 9 | - 32400:32400/tcp 10 | - 3005:3005/tcp 11 | - 8324:8324/tcp 12 | - 32469:32469/tcp 13 | - 1900:1900/udp 14 | - 32410:32410/udp 15 | - 32412:32412/udp 16 | - 32413:32413/udp 17 | - 32414:32414/udp 18 | environment: 19 | - TZ= 20 | - ADVERTISE_IP=http://:3001/ 21 | - LB_URL=http://loadbalancer:3001/ 22 | volumes: 23 | - plex_binaries:/usr/lib/plexmediaserver 24 | - plex_database:/config 25 | - plex_media:/media:ro 26 | restart: unless-stopped 27 | 28 | loadbalancer: 29 | image: magn2o/unicorn-loadbalancer:latest 30 | depends_on: 31 | - plex 32 | - redis 33 | networks: 34 | - plex-network 35 | ports: 36 | - 3001:3001/tcp 37 | environment: 38 | - SERVER_HOST=127.0.0.1 39 | - SERVER_PORT=3001 40 | - SERVER_PUBLIC=http://:3001/ 41 | - PLEX_HOST=plex 42 | - PLEX_PORT=32400 43 | - PLEX_PATH_SESSIONS=/config/Library/Application Support/Plex Media Server/Cache/Transcode/Sessions 44 | - DATABASE_SQLITE_PATH=/config/Library/Application Support/Plex Media Server/Plug-in Support/Databases/com.plexapp.plugins.library.db 45 | - REDIS_HOST=redis 46 | - REDIS_PORT=6379 47 | - LB_URL=http://loadbalancer:3001/ 48 | volumes: 49 | - plex_binaries:/usr/lib/plexmediaserver 50 | - plex_database:/config 51 | - plex_media:/media:ro 52 | restart: unless-stopped 53 | 54 | redis: 55 | image: redis:alpine 56 | networks: 57 | - plex-network 58 | sysctls: 59 | - net.core.somaxconn=511 60 | restart: unless-stopped 61 | 62 | volumes: 63 | plex_binaries: 64 | plex_database: 65 | plex_media: 66 | 67 | networks: 68 | plex-network: 69 | 70 | -------------------------------------------------------------------------------- /unicorn-loadbalancer/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:3.9 2 | MAINTAINER magn2o 3 | 4 | ARG S6_OVERLAY_VERSION="1.22.1.0" 5 | 6 | RUN \ 7 | apk add --no-cache curl npm git && \ 8 | curl -J -L https://github.com/just-containers/s6-overlay/releases/download/v${S6_OVERLAY_VERSION}/s6-overlay-amd64.tar.gz | tar zxvf - -C / && \ 9 | git -C /opt clone https://github.com/UnicornTranscoder/UnicornLoadBalancer.git && \ 10 | npm install --prefix=/opt/UnicornLoadBalancer && \ 11 | git -C /opt clone https://github.com/UnicornTranscoder/UnicornFFMPEG.git && \ 12 | apk del git && \ 13 | rm -rf /var/cache/apk/* /tmp/* /media/* 14 | 15 | COPY rootfs/ / 16 | 17 | EXPOSE 3001/tcp 18 | 19 | ENTRYPOINT ["/init"] 20 | -------------------------------------------------------------------------------- /unicorn-loadbalancer/rootfs/etc/cont-init.d/00-check-path_plex_usr: -------------------------------------------------------------------------------- 1 | #!/usr/bin/with-contenv sh 2 | 3 | PLEX_PATH_USR="${PLEX_PATH_USR:-/usr/lib/plexmediaserver/}" 4 | 5 | if [ ! -d "${PLEX_PATH_USR}" ]; then 6 | echo "" 7 | echo -e "\e[41m" 8 | echo -e " \e[1m[ERROR]\e[21m Plex binaries path not found! Run docker with the \"\e[1m-v :${PLEX_PATH_USR}\e[21m\" option" 9 | echo -e "\e[49m" 10 | echo "" 11 | exit 1 12 | fi 13 | -------------------------------------------------------------------------------- /unicorn-loadbalancer/rootfs/etc/cont-init.d/01-check-database_sqlite_path: -------------------------------------------------------------------------------- 1 | #!/usr/bin/with-contenv sh 2 | DATABASE_SQLITE_PATH="${DATABASE_SQLITE_PATH:-/var/lib/plexmediaserver/Library/Application Support/Plex Media Server/Plug-in Support/Databases/com.plexapp.plugins.library.db}" 3 | 4 | if [ ! -f "${DATABASE_SQLITE_PATH}" ]; then 5 | echo "" 6 | echo -e "\e[41m" 7 | echo -e " \e[1m[ERROR]\e[21m Plex SQLite database not found! Run docker with the \"\e[1m-v :${DATABASE_SQLITE_PATH}\e[21m\" option" 8 | echo -e "\e[49m" 9 | echo "" 10 | exit 1 11 | fi 12 | -------------------------------------------------------------------------------- /unicorn-loadbalancer/rootfs/etc/cont-init.d/02-install-ffmpeg: -------------------------------------------------------------------------------- 1 | #!/usr/bin/with-contenv sh 2 | 3 | PLEX_TRANSCODER="Plex Transcoder" 4 | PLEX_PATH_USR="${PLEX_PATH_USR:-/usr/lib/plexmediaserver/}" 5 | 6 | if [ -d "${PLEX_PATH_USR}" ]; then 7 | # hardcode loadbalancer URL 8 | sed -i 's@${config.URL}@'"$LB_URL"'@' /opt/UnicornFFMPEG/app.js 9 | 10 | # build binaries 11 | npm install --prefix=/opt/UnicornFFMPEG 12 | npm start --prefix=/opt/UnicornFFMPEG 13 | 14 | # backup existing binary (if it exists) 15 | if [ -f "${PLEX_PATH_USR}/${PLEX_TRANSCODER}" ]; then 16 | mv -n "${PLEX_PATH_USR}/${PLEX_TRANSCODER}" "${PLEX_PATH_USR}/~${PLEX_TRANSCODER}" 17 | chmod 000 "${PLEX_PATH_USR}/~${PLEX_TRANSCODER}" 18 | fi 19 | 20 | # replace with new binary 21 | cp -f "/opt/UnicornFFMPEG/bin/${PLEX_TRANSCODER}-linux" "${PLEX_PATH_USR}/${PLEX_TRANSCODER}" 22 | fi 23 | -------------------------------------------------------------------------------- /unicorn-loadbalancer/rootfs/etc/cont-init.d/03-remove-plex_relay: -------------------------------------------------------------------------------- 1 | #!/usr/bin/with-contenv sh 2 | 3 | PLEX_RELAY="Plex Relay" 4 | PLEX_PATH_USR="${PLEX_PATH_USR:-/usr/lib/plexmediaserver/}" 5 | 6 | if [ -f "${PLEX_PATH_USR}/${PLEX_RELAY}" ]; then 7 | mv "${PLEX_PATH_USR}/Plex Relay" "${PLEX_PATH_USR}/~${PLEX_RELAY}" 8 | chmod 000 "${PLEX_PATH_USR}/~${PLEX_RELAY}" 9 | fi 10 | -------------------------------------------------------------------------------- /unicorn-loadbalancer/rootfs/etc/fix-attrs.d/00-runscripts: -------------------------------------------------------------------------------- 1 | /etc/cont-init.d/* false root 0755 0755 2 | /etc/services.d/*/run false root 0755 0755 3 | -------------------------------------------------------------------------------- /unicorn-loadbalancer/rootfs/etc/services.d/unicorn-loadbalancer/run: -------------------------------------------------------------------------------- 1 | #!/usr/bin/with-contenv sh 2 | npm start --prefix=/opt/UnicornLoadBalancer 3 | -------------------------------------------------------------------------------- /unicorn-transcoder/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:3.9 2 | MAINTAINER magn2o 3 | 4 | ARG GLIBC_VERSION="2.29-r0" 5 | ARG S6_OVERLAY_VERSION="1.22.1.0" 6 | 7 | ENV \ 8 | PLEX_ARCH="amd64" \ 9 | UNICORN_PREFIX="/opt/UnicornTranscoder" 10 | 11 | RUN \ 12 | apk add --no-cache npm git curl libxml2-utils binutils file && \ 13 | curl -J -L -o /tmp/glibc-${GLIBC_VERSION}.apk https://github.com/sgerrand/alpine-pkg-glibc/releases/download/${GLIBC_VERSION}/glibc-${GLIBC_VERSION}.apk && \ 14 | curl -J -L https://github.com/just-containers/s6-overlay/releases/download/v${S6_OVERLAY_VERSION}/s6-overlay-amd64.tar.gz | tar zxvf - -C / && \ 15 | apk add --allow-untrusted /tmp/glibc-${GLIBC_VERSION}.apk && \ 16 | ln -s /lib/libz.so.1 /usr/glibc-compat/lib/libz.so.1 && \ 17 | ln -s /lib/libc.musl-x86_64.so.1 /usr/glibc-compat/lib/libc.musl-x86_64.so.1 && \ 18 | git -C /opt clone https://github.com/UnicornTranscoder/UnicornTranscoder.git && \ 19 | npm install --prefix=${UNICORN_PREFIX} && \ 20 | apk del git && \ 21 | rm -rf /var/cache/apk/* /tmp/* 22 | 23 | COPY rootfs/ / 24 | 25 | EXPOSE 3000/tcp 26 | 27 | ENTRYPOINT ["/init"] 28 | -------------------------------------------------------------------------------- /unicorn-transcoder/rootfs/etc/cont-init.d/00-setenv: -------------------------------------------------------------------------------- 1 | #!/usr/bin/with-contenv sh 2 | 3 | if [ -z "${PLEX_BUILD}" ]; then 4 | PLEX_BUILD=$(curl -s "${LOADBALANCER_ADDRESS}/?X-Plex-Token=${PLEX_TOKEN}" | xmllint --xpath "string(//MediaContainer/@version)" -) 5 | 6 | if [[ $(expr match "$PLEX_BUILD" '[0-9a-z.]*-[0-9a-z]*') -eq 0 ]]; then 7 | echo "" 8 | echo -e "\e[41m" 9 | echo -e " \e[21m WARNING: Unable to determine ${PLEX_BUILD} from ${LOADBALANCER_ADDRESS} !! " 10 | echo -e " \e[21m Please check your network connection or Plex Token and try again." 11 | echo -e "\e[49m" 12 | echo "" 13 | exit 1 14 | fi 15 | 16 | printf "${PLEX_BUILD}" > /var/run/s6/container_environment/PLEX_BUILD 17 | 18 | curl -J -L -o /tmp/plex.deb "https://downloads.plex.tv/plex-media-server-new/${PLEX_BUILD}/debian/plexmediaserver_${PLEX_BUILD}_amd64.deb" 19 | cd /tmp && ar x /tmp/plex.deb 20 | tar xf data.tar.xz "./usr/lib/plexmediaserver/Plex Media Server" -C /tmp 21 | 22 | CODECS_BUILD=$(strings "/tmp/usr/lib/plexmediaserver/Plex Media Server" | egrep '^([a-z0-9]){7}-([0-9]){4}$' | grep -v 'windows' | head -1) 23 | printf "${CODECS_BUILD}" > /var/run/s6/container_environment/CODECS_BUILD 24 | 25 | EAE_VERSION=$(strings "/tmp/usr/lib/plexmediaserver/Plex Media Server" | egrep '^eae-[a-z0-9]+-[0-9]+*$' | head -1) 26 | printf "${EAE_VERSION}" > /var/run/s6/container_environment/EAE_VERSION 27 | 28 | rm -rf /tmp/* 29 | 30 | echo "" 31 | echo -e "\e[42m" 32 | echo -e " \e[21m ----------------------------------------------" 33 | echo -e " \e[21m Versions:" 34 | echo -e " \e[21m" 35 | echo -e " \e[21m PLEX_BUILD=${PLEX_BUILD}" 36 | echo -e " \e[21m CODECS_BUILD=${CODECS_BUILD}" 37 | echo -e " \e[21m EAE_VERSION=${EAE_VERSION}" 38 | echo -e " \e[21m ----------------------------------------------" 39 | echo -e "\e[49m" 40 | echo "" 41 | fi 42 | 43 | exit 0 44 | -------------------------------------------------------------------------------- /unicorn-transcoder/rootfs/etc/cont-init.d/01-install-transcoder: -------------------------------------------------------------------------------- 1 | #!/usr/bin/with-contenv sh 2 | 3 | LIBFAKE_AVI_DECODER="${UNICORN_PREFIX}/codecs/${CODECS_BUILD}-${PLEX_ARCH}/libfake_avi_decoder.so" 4 | 5 | #npm install --prefix=${UNICORN_PREFIX} 6 | npm run install plex codecs eae cache --prefix=${UNICORN_PREFIX} 7 | 8 | # Download missing libfake_avi_decoder.so from the last known good codec build.. maybe this will get updated someday? Who knows.. 9 | if [[ $(file -b --mime-type ${LIBFAKE_AVI_DECODER}) = "text/html" ]]; then 10 | curl -J -L -o ${LIBFAKE_AVI_DECODER} https://downloads.plex.tv/codecs/e944d3a-1309/linux-ubuntu-x86_64/libfake_avi_decoder.so 11 | fi 12 | -------------------------------------------------------------------------------- /unicorn-transcoder/rootfs/etc/fix-attrs.d/00-runscripts: -------------------------------------------------------------------------------- 1 | /etc/services.d/*/run false root 0755 0755 2 | -------------------------------------------------------------------------------- /unicorn-transcoder/rootfs/etc/services.d/unicorn-transcoder/run: -------------------------------------------------------------------------------- 1 | #!/usr/bin/with-contenv sh 2 | npm start --prefix=/opt/UnicornTranscoder 3 | --------------------------------------------------------------------------------