diff --git a/DEVELOP.md b/DEVELOP.md new file mode 100644 index 00000000..035b7e2f --- /dev/null +++ b/DEVELOP.md @@ -0,0 +1,112 @@ +# Hackers zone + +## Build from source + +### TL;DR + +```bash +VENDOR=you +IMAGE_NAME=super_image +IMAGE_TAG=sometag +./build.sh +``` + +### The what + +This image is built using `dubodubonduponey/base:builder-$DEBIAN_DATE` and its runtime uses `dubodubonduponey/base:runtime-$DEBIAN_DATE`. + +Both these images are built upon `dubodubonduponey/debian:$DEBIAN_DATE`, a debootstrapped version of Debian Buster, built from a Debian snapshot at `$DEBIAN_DATE`. + +At the time of this writing, `DEBIAN_DATE` evaluates to `2019-12-01`, and is updated every 15 days. + +You can find out more here: + + * https://github.com/dubo-dubon-duponey/docker-debian for the debootstrapped Debian base + * https://github.com/dubo-dubon-duponey/docker-base for the builder and runtime images + +These images provide very little - they are (mostly) barebone Buster with some ONBUILD +Docker syntactic sugar (metadata, user creation, entrypoint). + +Let me repeat: you have very little reason to go and add anything up there. + +### Configuration reference + +```bash +# Controls to which registry your image gets pushed (default to Docker Hub if left unspecified) +REGISTRY="registry-1.docker.io" + +# "Vendor" name of the image (eg: `REGISTRY/VENDOR/IMAGE`) +VENDOR="dubodubonduponey" + +# Image name (as in `REGISTRY/VENDOR/IMAGE`) +IMAGE_NAME="super_image" + +# Tag name to publish +IMAGE_TAG="v1" + +# Image metadata (applied through labels) +TITLE="My super image title" +DESCRIPTION="My super image description" + +# Platforms you want to target (note: certain platforms may be unavailable for the underlying software) +PLATFORMS="linux/amd64,linux/arm64,linux/arm/v7,linux/arm/v6}" + +# Base debian image date to use (from our own base images) +DEBIAN_DATE=2019-12-01 + +# Controls which user-id to assign to the in-container user +BUILD_UID=2000 +``` + +### Behavior control + +```bash +# Do NOT push the built image if left empty (useful for debugging) - default to true +PUSH= +# Do NOT use buildkit cache if left empty - default to true +CACHE= + +``` + +## Develop + +### TL;DR + +Hack away. + +Be sure to run `./test.sh` before submitting anything. + +### About branches + +`1` is the currently stable version that published images are based on. + +`master` contains (usually stable) changes likely to land in a release soon. + +`work` is a development branch, with possibly unstable / dramatic changes. + +### Philosophy + + * keep it simple + * entrypoint should be kept self-contained + * minimize runtime dependencies + * base images should be kept dead simple + * one process per container (letsencrypt refresh being the only exception) + * unrelated ops should go elsewhere + * advanced logging infrastructure does not belong inside a container + * no init system, failing containers should fail, exit, and be handled from the outside + * keep it secure + * no root + * no write + * no cap + * use existing infrastructure + * runnable artifacts go to: + * `/boot/bin` (read-only) + * configuration goes to: + * `/config` (read-only) + * certificates go to: + * `/certs` (either read-only or read-write) + * persistent application data goes to: + * `/data` (usually read-write) + * volatile data go to: + * `/tmp` (usually read-write) + * only use chroot if you really REALLY need root first diff --git a/Dockerfile b/Dockerfile index ca1b2e84..05476317 100644 --- a/Dockerfile +++ b/Dockerfile @@ -20,37 +20,39 @@ RUN arch="${TARGETPLATFORM#*/}"; \ # hadolint ignore=DL3006 FROM $RUNTIME_BASE -LABEL dockerfile.copyright="Dubo Dubon Duponey " +WORKDIR /boot/bin +ARG PLEX_VERSION=1.18.3.2156-349e9837e +# XXX verify why this is not set by the base image +ARG TARGETPLATFORM -ARG DEBIAN_FRONTEND="noninteractive" -ENV TERM="xterm" LANG="C.UTF-8" LC_ALL="C.UTF-8" -# XXX tzdata -RUN apt-get update -qq && \ - apt-get install -qq --no-install-recommends \ - ca-certificates=20190110 \ - curl=7.64.0-4 \ - xmlstarlet=1.6.1-2 \ - uuid-runtime=2.33.1-0.1 && \ - apt-get -qq autoremove && \ - apt-get -qq clean && \ - rm -rf /var/lib/apt/lists/* && \ - rm -rf /tmp/* && \ - rm -rf /var/tmp/* +USER root -WORKDIR /dubo-dubon-duponey +ARG DEBIAN_FRONTEND="noninteractive" +ENV TERM="xterm" LANG="C.UTF-8" LC_ALL="C.UTF-8" -# plex -ARG PLEX_VERSION=1.16.5.1554-1e5ff713d +# Custom package in +COPY "./cache/$PLEX_VERSION/$TARGETPLATFORM/plex.deb" /tmp +RUN dpkg -i --force-confold /tmp/plex.deb -ARG TARGETPLATFORM +# All of this is required solely by the init script +RUN apt-get update -qq \ + && apt-get install -qq --no-install-recommends \ + curl=7.64.0-4 \ + xmlstarlet=1.6.1-2 \ + uuid-runtime=2.33.1-0.1 \ + dnsutils=1:9.11.5.P4+dfsg-5.1 \ + && apt-get -qq autoremove \ + && apt-get -qq clean \ + && rm -rf /var/lib/apt/lists/* \ + && rm -rf /tmp/* \ + && rm -rf /var/tmp/* -COPY "./cache/$PLEX_VERSION/$TARGETPLATFORM/plex.deb" /tmp -RUN dpkg -i --force-confold /tmp/plex.deb +USER dubo-dubon-duponey # Change home directory for plex -RUN usermod -d /config plex +# RUN usermod -d /config plex -COPY entrypoint.sh . +# COPY entrypoint.sh . # Environment ENV DBDB_LOGIN="" @@ -67,7 +69,6 @@ EXPOSE 32400/tcp # 3005/tcp 8324/tcp 32469/tcp 1900/udp 32410/udp 32412/udp 32413/udp 32414/udp # Volumes we need -VOLUME /config VOLUME /transcode VOLUME /data # VOLUME /certs diff --git a/Preferences.xml b/Preferences.xml deleted file mode 100644 index ac84b17a..00000000 --- a/Preferences.xml +++ /dev/null @@ -1,26 +0,0 @@ - - diff --git a/README.md b/README.md index d1c5ad5b..7353ded5 100644 --- a/README.md +++ b/README.md @@ -1,169 +1,7 @@ -# Official Docker container for Plex Media Server +Unofficial Plex image meant for my own use. -# plexinc/pms-docker +Experimental. -With our easy-to-install Plex Media Server software and your Plex apps, available on all your favorite phones, tablets, streaming devices, gaming consoles, and smart TVs, you can stream your video, music, and photo collections any time, anywhere, to any device. +## Moar? -## Usage - -Before you create your container, you must decide on the type of networking you wish to use. There are essentially three types of networking available: - -- `bridge` (default) -- `host` -- `macvlan` - -The `bridge` networking creates an entirely new network within the host and runs containers within there. This network is connected to the physical network via an internal router and docker configures this router to forward certain ports through to the containers within. The `host` networking uses the IP address of the host running docker such that a container's networking appears to be the host rather than separate. The `macvlan` networking creates a new virtual computer on the network which is the container. For purposes of setting up a plex container, the `host` and `macvlan` are very similar in configuration. - -Using `host` or `macvlan` is the easier of the three setups and has the fewest issues that need to be worked around. However, some setups may be restricted to only running in the `bridge` mode. Plex can be made to work in this mode, but it is more complicated. - -For those who use docker-compose, this repository provides the necessary YML template files to be modified for your own use. - -### Host Networking - -```bash -docker run \ --d \ ---name plex \ ---network=host \ --e TZ="" \ --e PLEX_CLAIM="" \ --v :/config \ --v :/transcode \ --v :/data \ -plexinc/pms-docker -``` - -### Macvlan Networking - -```bash -docker run \ --d \ ---name plex \ ---network=physical \ ---ip= \ --e TZ="" \ --e PLEX_CLAIM="" \ --h \ --v :/config \ --v :/transcode \ --v :/data \ -plexinc/pms-docker -``` - -Similar to `Host Networking` above with these changes: - -- The network has been changed to `physical` which is the name of the `macvlan` network (yours is likely to be different). -- The `--ip` parameter has been added to specify the IP address of the container. This parameter is optional since the network may specify IPs to use but this parameter overrides those settings. -- The `-h ` has been added since this networking type doesn't use the hostname of the host. - -### Bridge Networking - -```bash -docker run \ --d \ ---name plex \ --p 32400:32400/tcp \ --p 3005:3005/tcp \ --p 8324:8324/tcp \ --p 32469:32469/tcp \ --p 1900:1900/udp \ --p 32410:32410/udp \ --p 32412:32412/udp \ --p 32413:32413/udp \ --p 32414:32414/udp \ --e TZ="" \ --e PLEX_CLAIM="" \ --e ADVERTISE_IP="http://:32400/" \ --h \ --v :/config \ --v :/transcode \ --v :/data \ -plexinc/pms-docker -``` - -Note: In this configuration, you must do some additional configuration: - -- If you wish your Plex Media Server to be accessible outside of your home network, you must manually setup port forwarding on your router to forward to the `ADVERTISE_IP` specified above. By default you can forward port 32400, but if you choose to use a different external port, be sure you configure this in Plex Media Server's `Remote Access` settings. With this type of docker networking, the Plex Media Server is essentially behind two routers and it cannot automatically setup port forwarding on its own. -- (Plex Pass only) After the server has been set up, you should configure the `LAN Networks` preference to contain the network of your LAN. This instructs the Plex Media Server to treat these IP addresses as part of your LAN when applying bandwidth controls. The syntax is the same as the `ALLOWED_NETWORKS` below. For example `192.168.1.0/24,172.16.0.0/16` will allow access to the entire `192.168.1.x` range and the `172.16.x.x` range. - -## Parameters - -- `-p 32400:32400/tcp` Forwards port 32400 from the host to the container. This is the primary port that Plex uses for communication and is required for Plex Media Server to operate. -- `-p …` Forwards complete set of other ports used by Plex to the container. For a full explanation of which you may need, please see the help article: [https://support.plex.tv/hc/en-us/articles/201543147-What-network-ports-do-I-need-to-allow-through-my-firewall](https://support.plex.tv/hc/en-us/articles/201543147-What-network-ports-do-I-need-to-allow-through-my-firewall) -- `-v :/config` The path where you wish Plex Media Server to store its configuration data. This database can grow to be quite large depending on the size of your media collection. This is usually a few GB but for large libraries or libraries where index files are generated, this can easily hit the 100s of GBs. If you have an existing database directory see the section below on the directory setup. **Note**: the underlying filesystem needs to support file locking. This is known to not be default enabled on remote filesystems like NFS, SMB, and many many others. The 9PFS filesystem used by FreeNAS Corral is known to work but the vast majority will result in database corruption. Use a network share at your own risk. -- `-v :/transcode` The path where you would like Plex Media Server to store its transcoder temp files. If not provided, the storage space within the container will be used. Expect sizes in the 10s of GB. -- `-v :/data` This is provided as examples for providing media into the container. The exact structure of how the media is organized and presented inside the container is a matter of user preference. You can use as many or as few of these parameters as required to provide your media to the container. -- `-e KEY="value"` These are environment variables which configure the container. See below for a description of their meanings. - -The following are the recommended parameters. Each of the following parameters to the container are treated as first-run parameters only. That is, all other parameters are ignored on subsequent runs of the server. We recommend that you set the following parameters: - -- **HOSTNAME** Sets the hostname inside the docker container. For example `-h PlexServer` will set the servername to `PlexServer`. Not needed in Host Networking. -- **TZ** Set the timezone inside the container. For example: `Europe/London`. The complete list can be found here: [https://en.wikipedia.org/wiki/List_of_tz_database_time_zones](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) -- **PLEX_CLAIM** The claim token for the server to obtain a real server token. If not provided, server will not be automatically logged in. If server is already logged in, this parameter is ignored. You can obtain a claim token to login your server to your plex account by visiting [https://www.plex.tv/claim](https://www.plex.tv/claim) -- **ADVERTISE_IP** This variable defines the additional IPs on which the server may be be found. For example: `http://10.1.1.23:32400`. This adds to the list where the server advertises that it can be found. This is only needed in Bridge Networking. - -These parameters are usually not required but some special setups may benefit from their use. As in the previous section, each is treated as first-run parameters only: - -- **PLEX_UID** The user id of the `plex` user created inside the container. -- **PLEX_GID** The group id of the `plex` group created inside the container - -## Users/Groups -Permissions of mounted media outside the container do apply to the Plex Media Server running within the container. As stated above, the Plex Media Server runs as a specially created `plex` user within the container. This user may not exist outside the container and so the `PLEX_UID` and `PLEX_GID` parameters are used to set the user id and group id of this user within the container. If you wish for the Plex Media Server to run under the same permissions as your own user, execute the following to find out these ids: - -```bash -id `whoami` -``` - -You'll see a line like the following: - -```bash -uid=1001(myuser) gid=1001(myuser) groups=1001(myuser) -``` - -In the above case, if you set the `PLEX_UID` and `PLEX_GID` to `1001`, then the permissions will match that of your own user. - -## Tags -In addition to the standard version and `latest` tags, two other tags exist: `beta` and `public`. These two images behave differently than your typical containers. These two images do **not** have any Plex Media Server binary installed. Instead, when these containers are run, they will perform an update check and fetch the latest version, install it, and then continue execution. They also run the update check whenever the container is restarted. To update the version in the container, simply stop the container and start container again when you have a network connection. The startup script will automatically fetch the appropriate version and install it before starting the Plex Media Server. - -The `public` restricts this check to public versions only where as `beta` will fetch beta versions. If the server is not logged in or you do not have Plex Pass on your account, the `beta` tagged images will be restricted to publicly available versions only. - -To view the Docker images head over to [https://hub.docker.com/r/plexinc/pms-docker/tags/](https://hub.docker.com/r/plexinc/pms-docker/tags/) - -## Config Directory -Inside the docker container, the database is stored with a `Library/Application Support/Plex Media Server` in the `config` directory. - -If you wish to migrate an existing directory to the docker config directory: - -- Locate the current config directory as directed here: [https://support.plex.tv/hc/en-us/articles/202915258-Where-is-the-Plex-Media-Server-data-directory-located-](https://support.plex.tv/hc/en-us/articles/202915258-Where-is-the-Plex-Media-Server-data-directory-located-) -- If the config dir is stored in a location such as `/var/lib/plexmediaserver/Library/Application Support/Plex Media Server/`, the config dir will be `/var/lib/plexmediaserver`. -- If the config dir does not contain `Library/Application Support/Plex Media Server/` or the directory containing `Library` has data unrelated to Plex, such as OS X, then you should: - - Create a new directory which will be your new config dir. - - Within that config dir, create the directories `Library/Application Support` - - Copy `Plex Media Server` into that `Library/Application Support` -- Note: by default Plex will claim ownership of the entire contents of the `config` dir (see CHANGE_CONFIG_DIR_OWNERSHIP for more information). As such, there should be nothing in that dir that you do not wish for Plex to own. - -## Useful information -- Start the container: `docker start plex` -- Stop the container: `docker stop plex` -- Shell access to the container while it is running: `docker exec -it plex /bin/bash` -- See the logs given by the startup script in real time: `docker logs -f plex` -- Restart the application and upgrade to the latest version: `docker restart plex` - -## Fedora, CentOS, Red Hat - -If you get the following output after you have started the container, then this is due to a patched version of Docker ([#158](https://github.com/just-containers/s6-overlay/issues/158#issuecomment-266913426)) -```bash -plex | s6-supervise (child): fatal: unable to exec run: Permission denied -plex | s6-supervise avahi: warning: unable to spawn ./run - waiting 10 seconds -``` -As a workaround you can add `- /run` to volumes in your docker-compose.yml or `-v /run` to the docker create command. - -## Windows (Not Recommended) - -Docker on Windows works differently than it does on Linux; it uses a VM to run a stripped-down Linux and then runs docker within that. The volume mounts are exposed to the docker in this VM via SMB mounts. While this is fine for media, it is unacceptable for the `/config` directory because SMB does not support file locking. This **will** eventually corrupt your database which can lead to slow behavior and crashes. If you must run in docker on Windows, you should put the `/config` directory mount inside the VM and not on the Windows host. It's worth noting that this warning also extends to other containers which use SQLite databases. - -## Running on a headless server with container using host networking - -If the claim token is not added during initial configuration you will need to use ssh tunneling to gain access and setup the server for first run. During first run you setup the server to make it available and configurable. However, this setup option will only be triggered if you access it over http://localhost:32400/web, it will not be triggered if you access it over http://ip_of_server:32400/web. If you are setting up PMS on a headless server, you can use a SSH tunnel to link http://localhost:32400/web (on your current computer) to http://localhost:32400/web (on the headless server running PMS): - -`ssh username@ip_of_server -L 32400:ip_of_server:32400 -N` +See [DEVELOP.md](DEVELOP.md) diff --git a/build.sh b/build.sh index 0c0785c6..551d7001 100755 --- a/build.sh +++ b/build.sh @@ -4,7 +4,7 @@ set -o errexit -o errtrace -o functrace -o nounset -o pipefail export TITLE="Plex" export DESCRIPTION="A dubo image for Plex" export IMAGE_NAME="plex" -export PLATFORMS="linux/amd64,linux/arm64,linux/arm/v7" # No v6 +export PLATFORMS="${PLATFORMS:-linux/amd64,linux/arm64,linux/arm/v7}" # No v6 # shellcheck source=/dev/null . "$(cd "$(dirname "${BASH_SOURCE[0]:-$PWD}")" 2>/dev/null 1>&2 && pwd)/helpers.sh" diff --git a/cache/1.16.5.1554-1e5ff713d/linux/amd64/plex.deb b/cache/1.18.3.2156-349e9837e/linux/amd64/plex.deb similarity index 77% rename from cache/1.16.5.1554-1e5ff713d/linux/amd64/plex.deb rename to cache/1.18.3.2156-349e9837e/linux/amd64/plex.deb index 376329fa..e96f5179 100644 Binary files a/cache/1.16.5.1554-1e5ff713d/linux/amd64/plex.deb and b/cache/1.18.3.2156-349e9837e/linux/amd64/plex.deb differ diff --git a/cache/1.16.5.1554-1e5ff713d/linux/arm/v7/plex.deb b/cache/1.18.3.2156-349e9837e/linux/arm/v7/plex.deb similarity index 82% rename from cache/1.16.5.1554-1e5ff713d/linux/arm/v7/plex.deb rename to cache/1.18.3.2156-349e9837e/linux/arm/v7/plex.deb index a8f4fb00..aee996a9 100644 Binary files a/cache/1.16.5.1554-1e5ff713d/linux/arm/v7/plex.deb and b/cache/1.18.3.2156-349e9837e/linux/arm/v7/plex.deb differ diff --git a/cache/1.16.5.1554-1e5ff713d/linux/arm64/plex.deb b/cache/1.18.3.2156-349e9837e/linux/arm64/plex.deb similarity index 83% rename from cache/1.16.5.1554-1e5ff713d/linux/arm64/plex.deb rename to cache/1.18.3.2156-349e9837e/linux/arm64/plex.deb index 01a99d38..f55fc3dd 100644 Binary files a/cache/1.16.5.1554-1e5ff713d/linux/arm64/plex.deb and b/cache/1.18.3.2156-349e9837e/linux/arm64/plex.deb differ diff --git a/root/etc/cont-init.d/40-plex-first-run b/root/etc/cont-init.d/40-plex-first-run deleted file mode 100755 index 43babf80..00000000 --- a/root/etc/cont-init.d/40-plex-first-run +++ /dev/null @@ -1,190 +0,0 @@ -#!/usr/bin/with-contenv bash - -# If we are debugging, enable trace -if [ "${DEBUG,,}" = "true" ]; then - set -x -fi - -# If the first run completed successfully, we are done -if [ -e /.firstRunComplete ]; then - exit 0 -fi - -function getPref { - local key="$1" - - xmlstarlet sel -T -t -m "/Preferences" -v "@${key}" -n "${prefFile}" -} - -function setPref { - local key="$1" - local value="$2" - - count="$(xmlstarlet sel -t -v "count(/Preferences/@${key})" "${prefFile}")" - count=$(($count + 0)) - if [[ $count > 0 ]]; then - xmlstarlet ed --inplace --update "/Preferences/@${key}" -v "${value}" "${prefFile}" - else - xmlstarlet ed --inplace --insert "/Preferences" --type attr -n "${key}" -v "${value}" "${prefFile}" - fi -} - -home="$(echo ~plex)" -[ -f /etc/default/plexmediaserver ] && . /etc/default/plexmediaserver -pmsApplicationSupportDir="${PLEX_MEDIA_SERVER_APPLICATION_SUPPORT_DIR:-${home}/Library/Application Support}" -prefFile="${pmsApplicationSupportDir}/Plex Media Server/Preferences.xml" - -# Setup user/group ids -if [ ! -z "${PLEX_UID}" ]; then - if [ ! "$(id -u plex)" -eq "${PLEX_UID}" ]; then - - # usermod likes to chown the home directory, so create a new one and use that - # However, if the new UID is 0, we can't set the home dir back because the - # UID of 0 is already in use (executing this script). - if [ ! "${PLEX_UID}" -eq 0 ]; then - mkdir /tmp/temphome - usermod -d /tmp/temphome plex - fi - - # Change the UID - usermod -o -u "${PLEX_UID}" plex - - # Cleanup the temp home dir - if [ ! "${PLEX_UID}" -eq 0 ]; then - usermod -d /config plex - rm -Rf /tmp/temphome - fi - fi -fi - -if [ ! -z "${PLEX_GID}" ]; then - if [ ! "$(id -g plex)" -eq "${PLEX_GID}" ]; then - groupmod -o -g "${PLEX_GID}" plex - fi -fi - -# Update ownership of dirs we need to write -if [ "${CHANGE_CONFIG_DIR_OWNERSHIP,,}" = "true" ]; then - if [ -f "${prefFile}" ]; then - if [ ! "$(stat -c %u "${prefFile}")" = "$(id -u plex)" ]; then - chown -R plex:plex /config - fi - else - chown -R plex:plex /config - fi - chown -R plex:plex /transcode -fi - -# Create empty shell pref file if it doesn't exist already -if [ ! -e "${prefFile}" ]; then - echo "Creating pref shell" - mkdir -p "$(dirname "${prefFile}")" - cat > "${prefFile}" <<-EOF - - -EOF - chown -R plex:plex "$(dirname "${prefFile}")" -fi - -# Setup Server's client identifier -serial="$(getPref "MachineIdentifier")" -if [ -z "${serial}" ]; then - serial="$(uuidgen)" - setPref "MachineIdentifier" "${serial}" -fi -clientId="$(getPref "ProcessedMachineIdentifier")" -if [ -z "${clientId}" ]; then - clientId="$(echo -n "${serial}- Plex Media Server" | sha1sum | cut -b 1-40)" - setPref "ProcessedMachineIdentifier" "${clientId}" -fi - -# Get server token and only turn claim token into server token if we have former but not latter. -token="$(getPref "PlexOnlineToken")" - -if [ -z "${token}" ] && [ "$PLEX_LOGIN" ] && [ "$PLEX_PASSWORD" ]; then - authtoken="$(curl -s -X POST \ - --data-urlencode "login=$PLEX_LOGIN" \ - --data-urlencode "password=$PLEX_PASSWORD" \ - -H "Cookie: plex_tv_client_identifier=$serial" \ - "https://plex.tv/api/v2/users/signin?X-Plex-Product=Plex%20Auth%20App&X-Plex-Version=3.24.0&X-Plex-Client-Identifier=${serial}&X-Plex-Platform=Chrome&X-Plex-Platform-Version=61.0&X-Plex-Device=OSX&X-Plex-Device-Name=Plex%20Web%20%28Chrome%29&X-Plex-Device-Screen-Resolution=1167x1057%2C1920x1200" \ - | grep -oP '(?<=authToken=")[^"]+')" - - PLEX_CLAIM=$(curl -s \ - -H "X-Plex-Client-Identifier: $serial" \ - -H "X-Plex-Token: $authtoken" \ - https://plex.tv/api/claim/token.json | grep -oP "(?<=claim-)[^\"]+") -fi - -if [ ! -z "${PLEX_CLAIM}" ] && [ -z "${token}" ]; then - echo "Attempting to obtain server token from claim token" - loginInfo="$(curl -X POST \ - -H 'X-Plex-Client-Identifier: '${clientId} \ - -H 'X-Plex-Product: Plex Media Server'\ - -H 'X-Plex-Version: 1.1' \ - -H 'X-Plex-Provides: server' \ - -H 'X-Plex-Platform: Linux' \ - -H 'X-Plex-Platform-Version: 1.0' \ - -H 'X-Plex-Device-Name: PlexMediaServer' \ - -H 'X-Plex-Device: Linux' \ - "https://plex.tv/api/claim/exchange?token=${PLEX_CLAIM}")" - token="$(echo "$loginInfo" | sed -n 's/.*\(.*\)<\/authentication-token>.*/\1/p')" - - if [ "$token" ]; then - echo "Token obtained successfully" - setPref "PlexOnlineToken" "${token}" - fi -fi - -if [ ! -z "${ADVERTISE_IP}" ]; then - setPref "customConnections" "${ADVERTISE_IP}" -fi - -if [ ! -z "${ALLOWED_NETWORKS}" ]; then - setPref "allowedNetworks" "${ALLOWED_NETWORKS}" -fi - -# Set transcoder temp if not yet set -if [ -z "$(getPref "TranscoderTempDirectory")" ]; then - setPref "TranscoderTempDirectory" "/transcode" -fi - -touch /.firstRunComplete -echo "Plex Media Server first run setup complete" - -if [ ! -z "${ADVERTISE_IP}" ]; then - setPref "customConnections" "${ADVERTISE_IP}" -fi - -if [ ! -z "${ALLOWED_NETWORKS}" ]; then - setPref "allowedNetworks" "${ALLOWED_NETWORKS}" -fi - -# Set transcoder temp if not yet set -if [ -z "$(getPref "TranscoderTempDirectory")" ]; then - setPref "TranscoderTempDirectory" "/transcode" -fi - -setPref "AcceptedEULA" "1" -setPref "ManualPortMappingPort" "443" - -# PlexOnlineUsername="%PLEX_USERNAME%" -# PlexOnlineMail="%PLEX_EMAIL%" -# FriendlyName="%PLEX_FRIENDLY_NAME%" -# PublishServerOnPlexOnlineKey="1" -# GdmEnabled="0" -# DlnaEnabled="0" -# DlnaReportTimeline="0" -# sendCrashReports="0" -# FSEventLibraryPartialScanEnabled="1" -# FSEventLibraryUpdatesEnabled="1" -# ScannerLowPriority="1" -# ScheduledLibraryUpdateInterval="900" -# ScheduledLibraryUpdatesEnabled="1" -# LastAutomaticMappedPort="0" -# ManualPortMappingMode="1" -# customCertificateDomain="%PLEX_DOMAIN%" -# customCertificateKey="" -# customCertificatePath="/certs/plex.pfx"/> - -touch /.firstRunComplete -echo "Plex Media Server first run setup complete" diff --git a/root/etc/services.d/plex/run b/root/etc/services.d/plex/run deleted file mode 100755 index 80546ef2..00000000 --- a/root/etc/services.d/plex/run +++ /dev/null @@ -1,18 +0,0 @@ -#!/usr/bin/with-contenv bash - -echo "Starting Plex Media Server." -home="$(echo ~plex)" -export PLEX_MEDIA_SERVER_APPLICATION_SUPPORT_DIR="${PLEX_MEDIA_SERVER_APPLICATION_SUPPORT_DIR:-${home}/Library/Application Support}" -export PLEX_MEDIA_SERVER_HOME=/usr/lib/plexmediaserver -export PLEX_MEDIA_SERVER_MAX_PLUGIN_PROCS=6 -export PLEX_MEDIA_SERVER_INFO_VENDOR=Docker -export PLEX_MEDIA_SERVER_INFO_DEVICE="Docker Container" -export PLEX_MEDIA_SERVER_INFO_MODEL=$(uname -m) -export PLEX_MEDIA_SERVER_INFO_PLATFORM_VERSION=$(uname -r) - -if [ ! -d "${PLEX_MEDIA_SERVER_APPLICATION_SUPPORT_DIR}" ]; then - /bin/mkdir -p "${PLEX_MEDIA_SERVER_APPLICATION_SUPPORT_DIR}" - chown plex:plex "${PLEX_MEDIA_SERVER_APPLICATION_SUPPORT_DIR}" -fi - -exec s6-setuidgid plex /bin/sh -c 'LD_LIBRARY_PATH=/usr/lib/plexmediaserver:/usr/lib/plexmediaserver/lib /usr/lib/plexmediaserver/Plex\ Media\ Server' diff --git a/runtime/boot/entrypoint.sh b/runtime/boot/entrypoint.sh new file mode 100755 index 00000000..93b843c6 --- /dev/null +++ b/runtime/boot/entrypoint.sh @@ -0,0 +1,199 @@ +#!/usr/bin/env bash +set -o errexit -o errtrace -o functrace -o nounset -o pipefail + +# XXX cleanup plex/plexmediaserver.pid if there on start + +# Environment +DBDB_LOGIN=${DBDB_LOGIN:-unknown} +DBDB_PASSWORD=${DBDB_PASSWORD:-} +DBDB_MAIL=${DBDB_MAIL:-unknown@unknown.com} +# dig +short host-home.farcloser.world | grep -E "^[0-9.]+$" +# dig A +short powacroquette.synology.me +DBDB_ADVERTISE_IP=${DBDB_ADVERTISE_IP:-$(dig +short myip.opendns.com @resolver1.opendns.com)} +DBDB_SERVER_NAME=${DBDB_SERVER_NAME:-Some name} + +# Server conf +export PLEX_MEDIA_SERVER_APPLICATION_SUPPORT_DIR="/data/Library/Application Support" +export PLEX_MEDIA_SERVER_HOME=/usr/lib/plexmediaserver +export PLEX_MEDIA_SERVER_MAX_PLUGIN_PROCS=6 +export PLEX_MEDIA_SERVER_MAX_STACK_SIZE=3000 +export PLEX_MEDIA_SERVER_TMPDIR=/tmp +export PLEX_MEDIA_SERVER_USE_SYSLOG=false + +# Info +export PLEX_MEDIA_SERVER_INFO_VENDOR=Docker +export PLEX_MEDIA_SERVER_INFO_DEVICE="Docker Container" +export PLEX_MEDIA_SERVER_INFO_MODEL +export PLEX_MEDIA_SERVER_INFO_PLATFORM_VERSION +PLEX_MEDIA_SERVER_INFO_MODEL="$(uname -m)" +PLEX_MEDIA_SERVER_INFO_PLATFORM_VERSION="$(uname -r)" + +# XML attribute manipulation +dc::xml::get(){ + local key="$1" + local root="${2:-/}" + local file="${3:-/dev/stdin}" + + xmlstarlet sel -T -t -m "$root" -v "@${key}" -n "$file" +} + +dc::xml::set(){ + local key="$1" + local value="$2" + local root="${3:-/}" + local file="${4:-/dev/stdin}" + + local count + + count="$(xmlstarlet sel -t -v "count($root/@${key})" "$file")" + count=$((count + 0)) + if [ "$count" -gt 0 ]; then + xmlstarlet ed --inplace --update "$root/@$key" -v "$value" "$file" + else + xmlstarlet ed --inplace --insert "$root" --type attr -n "$key" -v "$value" "$file" + fi +} + +# Preferences manipulation +plex::preferences::init(){ + local prefFile="${PLEX_MEDIA_SERVER_APPLICATION_SUPPORT_DIR}/Plex Media Server/Preferences.xml" + [ -e "$prefFile" ] && return + + >&2 printf "Creating pref shell\n" + + mkdir -p "$PLEX_MEDIA_SERVER_APPLICATION_SUPPORT_DIR/Plex Media Server" + printf '\n\n' > "${prefFile}" +# cat > "${prefFile}" <<-EOF +# +# +#EOF +} + +plex::preferences::read(){ + local prefFile="${PLEX_MEDIA_SERVER_APPLICATION_SUPPORT_DIR}/Plex Media Server/Preferences.xml" + + >&2 printf "Reading pref %s\n" "$1" + + dc::xml::get "$1" "Preferences" "$prefFile" +} + +plex::preferences::write(){ + local prefFile="${PLEX_MEDIA_SERVER_APPLICATION_SUPPORT_DIR}/Plex Media Server/Preferences.xml" + + >&2 printf "Writing pref %s=%s\n" "$1" "$2" + + dc::xml::set "$1" "$2" "Preferences" "$prefFile" +} + +plex::start(){ + >&2 printf "Starting Plex Media Server." + rm -f "${PLEX_MEDIA_SERVER_APPLICATION_SUPPORT_DIR}/Plex Media Server/plexmediaserver.pid" + export LD_LIBRARY_PATH=/usr/lib/plexmediaserver:/usr/lib/plexmediaserver/lib + exec /usr/lib/plexmediaserver/Plex\ Media\ Server "$@" +} + +# If the first run completed successfully, start and go +if [ -e /data/.firstRun ]; then + plex::start "$@" + exit +fi + +# Ensure we have a shell pref file +plex::preferences::init + +# Setup Server's client identifier +serial="$(plex::preferences::read "MachineIdentifier")" +if [ ! "$serial" ]; then + serial="$(uuidgen)" + plex::preferences::write "MachineIdentifier" "$serial" +fi + +clientId="$(plex::preferences::read "ProcessedMachineIdentifier")" +if [ ! "$clientId" ]; then + clientId="$(printf "%s-Plex Media Server" "$serial" | sha1sum | cut -b 1-40)" + plex::preferences::write "ProcessedMachineIdentifier" "$clientId" +fi + +# Get server token and only turn claim token into server token if we have former but not latter. +token="$(plex::preferences::read "PlexOnlineToken")" + +PLEX_CLAIM= +if [ ! "${token}" ] && [ "$DBDB_LOGIN" ] && [ "$DBDB_PASSWORD" ]; then + authtoken="$(curl -s -X POST \ + --data-urlencode "login=$DBDB_LOGIN" \ + --data-urlencode "password=$DBDB_PASSWORD" \ + -H "Cookie: plex_tv_client_identifier=$clientId" \ + "https://plex.tv/api/v2/users/signin?X-Plex-Product=Plex%20Auth%20App&X-Plex-Version=3.24.0&X-Plex-Client-Identifier=$clientId&X-Plex-Platform=Chrome&X-Plex-Platform-Version=61.0&X-Plex-Device=OSX&X-Plex-Device-Name=Plex%20Web%20%28Chrome%29&X-Plex-Device-Screen-Resolution=1167x1057%2C1920x1200" \ + | grep -oP '(?<=authToken=")[^"]+')" + + PLEX_CLAIM=$(curl -s \ + -H "X-Plex-Client-Identifier: $clientId" \ + -H "X-Plex-Token: $authtoken" \ + https://plex.tv/api/claim/token.json | grep -oP "(?<=claim-)[^\"]+") +fi + +# https://plex.tv/api/claim/subscribe?X-Plex-Product=Plex%20Web&X-Plex-Version=3.108.2&X-Plex-Client-Identifier=zgddlh84ron98pw0jw6stf1i&X-Plex-Platform=Chrome&X-Plex-Platform-Version=76.0&X-Plex-Sync-Version=2&X-Plex-Features=external-media&X-Plex-Model=bundled&X-Plex-Device=OSX&X-Plex-Device-Name=Chrome&X-Plex-Device-Screen-Resolution=1836x1299%2C3008x1692&X-Plex-Token=55vAuCc_1WyRumhj7xUu&X-Plex-Language=en + +#if [ "$PLEX_CLAIM" ] && [ ! "$token" ]; then +# >&2 printf "Attempting to obtain server token from claim token\n" +# loginInfo="$(curl -X POST \ +# -H "X-Plex-Client-Identifier: $clientId" \ +# -H 'X-Plex-Product: Plex Media Server'\ +# -H 'X-Plex-Version: 1.1' \ +# -H 'X-Plex-Provides: server' \ +# -H 'X-Plex-Platform: Linux' \ +# -H 'X-Plex-Platform-Version: 1.0' \ +# -H 'X-Plex-Device-Name: PlexMediaServer' \ +# -H 'X-Plex-Device: Linux' \ +# "https://plex.tv/api/claim/exchange?token=${PLEX_CLAIM}")" +# token="$(printf "%s" "$loginInfo" | sed -n 's/.*\(.*\)<\/authentication-token>.*/\1/p')" +# +# >&2 printf "Token obtained: %s\n" "$token" +#fi + +[ ! "$PLEX_CLAIM" ] || plex::preferences::write "PlexOnlineToken" "$PLEX_CLAIM" +plex::preferences::write "AcceptedEULA" 1 +plex::preferences::write "ManualPortMappingMode" 1 +plex::preferences::write "ManualPortMappingPort" 443 +plex::preferences::write "DlnaEnabled" 0 +plex::preferences::write "PlexOnlineUsername" "$DBDB_LOGIN" +plex::preferences::write "PlexOnlineMail" "$DBDB_MAIL" +plex::preferences::write "FriendlyName" "$DBDB_SERVER_NAME" + +plex::preferences::write "PublishServerOnPlexOnlineKey" 1 +plex::preferences::write "PlexOnlineHome" 1 +plex::preferences::write "OldestPreviousVersion" "legacy" + +[ ! "$DBDB_ADVERTISE_IP" ] || plex::preferences::write "customConnections" "$DBDB_ADVERTISE_IP" +plex::preferences::write "GdmEnabled" 0 +plex::preferences::write "sendCrashReports" 0 +plex::preferences::write "TranscoderTempDirectory" "/transcode" + + +touch /data/.firstRun +>&2 printf "Plex Media Server first run setup complete\n" + +plex::start "$@" + +# As generated by a working server +# AnonymousMachineIdentifier="50d88b84-ecc9-4d50-a872-b7a2eea5859d" +# MetricsEpoch="1" +# LastAutomaticMappedPort="0" +# DvrIncrementalEpgLoader="0" +# CertificateUUID="ea2e0a83cc7a4d7491c88b580a2258a8" +# CertificateVersion="2" +# PubSubServer="184.105.148.82" +# PubSubServerRegion="sjc" +# PubSubServerPing="12" +# FSEventLibraryUpdatesEnabled="1" +# LanguageInCloud="1"/> + +# XXX old notes +# DlnaReportTimeline="0" +# FSEventLibraryPartialScanEnabled="1" +# ScannerLowPriority="1" +# ScheduledLibraryUpdateInterval="900" +# ScheduledLibraryUpdatesEnabled="1" +# customCertificateDomain="%PLEX_DOMAIN%" +# customCertificateKey="" +# customCertificatePath="/certs/plex.pfx"/>