diff --git a/nixos/modules/misc/ids.nix b/nixos/modules/misc/ids.nix index fcbac4c7f543..ef180be9718d 100644 --- a/nixos/modules/misc/ids.nix +++ b/nixos/modules/misc/ids.nix @@ -218,6 +218,7 @@ i2p = 190; lambdabot = 191; asterisk = 192; + plex = 193; # When adding a uid, make sure it doesn't match an existing gid. And don't use uids above 399! @@ -413,6 +414,7 @@ i2p = 190; lambdabot = 191; #asterisk = 192; # unused + plex = 193; # When adding a gid, make sure it doesn't match an existing # uid. Users and groups with the same name should have equal diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index 08b232272ffe..0c9c12962659 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -203,6 +203,7 @@ ./services/misc/nix-ssh-serve.nix ./services/misc/parsoid.nix ./services/misc/phd.nix + ./services/misc/plex.nix ./services/misc/redmine.nix ./services/misc/rippled.nix ./services/misc/ripple-data-api.nix diff --git a/nixos/modules/services/misc/plex.nix b/nixos/modules/services/misc/plex.nix new file mode 100644 index 000000000000..f4642b5157ee --- /dev/null +++ b/nixos/modules/services/misc/plex.nix @@ -0,0 +1,87 @@ +{ config, pkgs, lib, ... }: + +with lib; + +let + cfg = config.services.plex; + plex = pkgs.plex; +in +{ + options = { + services.plex = { + enable = mkEnableOption "Enable Plex Media Server"; + + # FIXME: In order for this config option to work, symlinks in the Plex + # package in the Nix store have to be changed to point to this directory. + dataDir = mkOption { + type = types.str; + default = "/var/lib/plex"; + description = "The directory where Plex stores its data files."; + }; + + user = mkOption { + type = types.str; + default = "plex"; + description = "User account under which Plex runs."; + }; + + group = mkOption { + type = types.str; + default = "plex"; + description = "Group under which Plex runs."; + }; + }; + }; + + config = mkIf cfg.enable { + # Most of this is just copied from the RPM package's systemd service file. + systemd.services.plex = { + description = "Plex Media Server"; + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + preStart = '' + test -d "${cfg.dataDir}" || { + echo "Creating initial Plex data directory in \"${cfg.dataDir}\"." + mkdir -p "${cfg.dataDir}" + chown -R ${cfg.user}:${cfg.group} "${cfg.dataDir}" + } + # Copy the database skeleton files to /var/lib/plex/.skeleton + test -d "${cfg.dataDir}/.skeleton" || mkdir "${cfg.dataDir}/.skeleton" + for db in "com.plexapp.plugins.library.db"; do + cp "${plex}/usr/lib/plexmediaserver/Resources/base_$db" "${cfg.dataDir}/.skeleton/$db" + chmod u+w "${cfg.dataDir}/.skeleton/$db" + chown ${cfg.user}:${cfg.group} "${cfg.dataDir}/.skeleton/$db" + done + ''; + serviceConfig = { + Type = "simple"; + User = cfg.user; + Group = cfg.group; + PermissionsStartOnly = "true"; + ExecStart = "/bin/sh -c '${plex}/usr/lib/plexmediaserver/Plex\\ Media\\ Server'"; + }; + environment = { + PLEX_MEDIA_SERVER_APPLICATION_SUPPORT_DIR=cfg.dataDir; + PLEX_MEDIA_SERVER_HOME="${plex}/usr/lib/plexmediaserver"; + PLEX_MEDIA_SERVER_MAX_PLUGIN_PROCS="6"; + PLEX_MEDIA_SERVER_TMPDIR="/tmp"; + LD_LIBRARY_PATH="${plex}/usr/lib/plexmediaserver"; + LC_ALL="en_US.UTF-8"; + LANG="en_US.UTF-8"; + }; + }; + + users.extraUsers = mkIf (cfg.user == "plex") { + plex = { + group = cfg.group; + uid = config.ids.uids.plex; + }; + }; + + users.extraGroups = mkIf (cfg.group == "plex") { + plex = { + gid = config.ids.gids.plex; + }; + }; + }; +} diff --git a/pkgs/servers/plex/default.nix b/pkgs/servers/plex/default.nix new file mode 100644 index 000000000000..62334de1b567 --- /dev/null +++ b/pkgs/servers/plex/default.nix @@ -0,0 +1,65 @@ +{ stdenv, fetchurl, rpmextract, glibc +, dataDir ? "/var/lib/plex" # Plex's data directory must be baked into the package due to symlinks. +}: + +stdenv.mkDerivation rec { + name = "plex-${version}"; + version = "0.9.11.16.958"; + vsnHash = "80f1748"; + + src = fetchurl { + url = "https://downloads.plex.tv/plex-media-server/${version}-${vsnHash}/plexmediaserver-${version}-${vsnHash}.x86_64.rpm"; + sha256 = "1wrl654nk10i9p01cgy9fqiqalxyl718qhp4kjnxvcwafayxkp26"; + }; + + buildInputs = [ rpmextract glibc ]; + + phases = [ "unpackPhase" "installPhase" "fixupPhase" "distPhase" ]; + + unpackPhase = '' + rpmextract $src + ''; + + installPhase = '' + install -d $out/usr/lib + cp -dr --no-preserve='ownership' usr/lib/plexmediaserver $out/usr/lib/ + + # Now we need to patch up the executables and libraries to work on Nix. + # Side note: PLEASE don't put spaces in your binary names. This is stupid. + for bin in "Plex Media Server" "Plex DLNA Server" "Plex Media Scanner"; do + patchelf --set-interpreter "${glibc}/lib/ld-linux-x86-64.so.2" "$out/usr/lib/plexmediaserver/$bin" + patchelf --set-rpath "$out/usr/lib/plexmediaserver" "$out/usr/lib/plexmediaserver/$bin" + done + + find $out/usr/lib/plexmediaserver/Resources -type f -a -perm +0100 \ + -print -exec patchelf --set-interpreter "${glibc}/lib/ld-linux-x86-64.so.2" '{}' \; + + + # Our next problem is the "Resources" directory in /usr/lib/plexmediaserver. + # This is ostensibly a skeleton directory, which contains files that Plex + # copies into its folder in /var. Unfortunately, there are some SQLite + # databases in the directory that are opened at startup. Since these + # database files are read-only, SQLite chokes and Plex fails to start. To + # solve this, we keep the resources directory in the Nix store, but we + # rename the database files and replace the originals with symlinks to + # /var/lib/plex. Then, in the systemd unit, the base database files are + # copied to /var/lib/plex before starting Plex. + RSC=$out/usr/lib/plexmediaserver/Resources + for db in "com.plexapp.plugins.library.db"; do + mv $RSC/$db $RSC/base_$db + ln -s ${dataDir}/.skeleton/$db $RSC/$db + done + ''; + + meta = with stdenv.lib; { + homepage = http://plex.tv/; + license = licenses.unfree; + platforms = platforms.linux; + maintainers = with stdenv.lib.maintainers; [ forkk ]; + description = "Media / DLNA server"; + longDescription = '' + Plex is a media server which allows you to store your media and play it + back across many different devices. + ''; + }; +} diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix index dd09411733ab..923c81d5939c 100644 --- a/pkgs/top-level/all-packages.nix +++ b/pkgs/top-level/all-packages.nix @@ -2405,6 +2405,8 @@ let plan9port = callPackage ../tools/system/plan9port { }; + plex = callPackage ../servers/plex { }; + ploticus = callPackage ../tools/graphics/ploticus { libpng = libpng12; };