about summary refs log tree commit diff
path: root/nixos/modules/services/misc/plex.nix
blob: 875771dfa37fae05f190d4a5e30e115e003e2604 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
{ config, pkgs, lib, ... }:

with lib;

let
  cfg = config.services.plex;
  plex = pkgs.plex;
in
{
  options = {
    services.plex = {
      enable = mkEnableOption "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.";
      };


      managePlugins = mkOption {
        type = types.bool;
        default = true;
        description = ''
          If set to true, this option will cause all of the symlinks in Plex's
          plugin directory to be removed and symlinks for paths specified in
          <option>extraPlugins</option> to be added.
        '';
      };

      extraPlugins = mkOption {
        type = types.listOf types.path;
        default = [];
        description = ''
          A list of paths to extra plugin bundles to install in Plex's plugin
          directory. Every time the systemd unit for Plex starts up, all of the
          symlinks in Plex's plugin directory will be cleared and this module
          will symlink all of the paths specified here to that directory. If
          this behavior is undesired, set <option>managePlugins</option> to
          false.
        '';
      };

      package = mkOption {
        type = types.package;
        default = pkgs.plex;
        defaultText = "pkgs.plex";
        description = ''
          The Plex package to use. Plex subscribers may wish to use their own
          package here, pointing to subscriber-only server versions.
        '';
      };
    };
  };

  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}/Plex Media Server"
          chown -R ${cfg.user}:${cfg.group} "${cfg.dataDir}"
        }

        # Copy the database skeleton files to /var/lib/plex/.skeleton
        # See the the Nix expression for Plex's package for more information on
        # why this is done.
        test -d "${cfg.dataDir}/.skeleton" || mkdir "${cfg.dataDir}/.skeleton"
        for db in "com.plexapp.plugins.library.db"; do
            cp "${cfg.package}/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

        # If managePlugins is enabled, setup symlinks for plugins.
        ${optionalString cfg.managePlugins ''
          echo "Preparing plugin directory."
          PLUGINDIR="${cfg.dataDir}/Plex Media Server/Plug-ins"
          test -d "$PLUGINDIR" || {
            mkdir -p "$PLUGINDIR";
            chown ${cfg.user}:${cfg.group} "$PLUGINDIR";
          }

          echo "Removing old symlinks."
          # First, remove all of the symlinks in the directory.
          for f in `ls "$PLUGINDIR/"`; do
            if [[ -L "$PLUGINDIR/$f" ]]; then
              echo "Removing plugin symlink $PLUGINDIR/$f."
              rm "$PLUGINDIR/$f"
            fi
          done

          echo "Symlinking plugins."
          for path in ${toString cfg.extraPlugins}; do
            dest="$PLUGINDIR/$(basename $path)"
            if [[ ! -d "$path" ]]; then
              echo "Error symlinking plugin from $path: no such directory."
            elif [[ -d "$dest" || -L "$dest" ]]; then
              echo "Error symlinking plugin from $path to $dest: file or directory already exists."
            else
              echo "Symlinking plugin at $path..."
              ln -s "$path" "$dest"
            fi
          done
        ''}
     '';
      serviceConfig = {
        Type = "simple";
        User = cfg.user;
        Group = cfg.group;
        PermissionsStartOnly = "true";
        ExecStart = "/bin/sh -c '${cfg.package}/usr/lib/plexmediaserver/Plex\\ Media\\ Server'";
      };
      environment = {
        PLEX_MEDIA_SERVER_APPLICATION_SUPPORT_DIR=cfg.dataDir;
        PLEX_MEDIA_SERVER_HOME="${cfg.package}/usr/lib/plexmediaserver";
        PLEX_MEDIA_SERVER_MAX_PLUGIN_PROCS="6";
        PLEX_MEDIA_SERVER_TMPDIR="/tmp";
        LD_LIBRARY_PATH="${cfg.package}/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;
      };
    };
  };
}