diff options
| author | Gregor Kleen <gkleen@yggdrasil.li> | 2018-06-02 17:58:57 +0200 |
|---|---|---|
| committer | Gregor Kleen <gkleen@yggdrasil.li> | 2018-06-02 17:58:57 +0200 |
| commit | d49dd672463aff72bd754d657abbd11cf8a0d8e0 (patch) | |
| tree | 87f2c40733ec18528a518013f84e2dd523d15f66 | |
| parent | 329245b4e3b9a2a9bbf7afd4570d7da311c58a42 (diff) | |
| download | nixos-d49dd672463aff72bd754d657abbd11cf8a0d8e0.tar nixos-d49dd672463aff72bd754d657abbd11cf8a0d8e0.tar.gz nixos-d49dd672463aff72bd754d657abbd11cf8a0d8e0.tar.bz2 nixos-d49dd672463aff72bd754d657abbd11cf8a0d8e0.tar.xz nixos-d49dd672463aff72bd754d657abbd11cf8a0d8e0.zip | |
revamp uucp-mediaclient
| -rw-r--r-- | custom/notify-user.hs | 50 | ||||
| -rw-r--r-- | custom/notify-user.nix | 69 | ||||
| -rw-r--r-- | custom/notify-users.nix | 53 | ||||
| -rw-r--r-- | custom/recv-media.sh | 56 | ||||
| -rw-r--r-- | custom/uucp-mediaclient.nix | 89 | ||||
| -rw-r--r-- | hel.nix | 22 | ||||
| -rw-r--r-- | hel/recv-media.nix | 72 |
7 files changed, 259 insertions, 152 deletions
diff --git a/custom/notify-user.hs b/custom/notify-user.hs new file mode 100644 index 00000000..f9cc2369 --- /dev/null +++ b/custom/notify-user.hs | |||
| @@ -0,0 +1,50 @@ | |||
| 1 | {-# LANGUAGE ViewPatterns, StandaloneDeriving #-} | ||
| 2 | |||
| 3 | import System.FilePath.Glob (glob) | ||
| 4 | import System.Environment (setEnv, getArgs) | ||
| 5 | import System.Process (spawnProcess, waitForProcess) | ||
| 6 | import System.Exit (exitWith, ExitCode(..)) | ||
| 7 | |||
| 8 | import Data.List (isPrefixOf, dropWhile, dropWhileEnd, init) | ||
| 9 | import Data.Char (isSpace, toLower, toUpper) | ||
| 10 | |||
| 11 | import Control.Monad (forM_, void) | ||
| 12 | |||
| 13 | import qualified Libnotify as Notify | ||
| 14 | import Data.Monoid | ||
| 15 | |||
| 16 | import System.Console.GetOpt.Simple | ||
| 17 | |||
| 18 | import qualified Data.Map as Map | ||
| 19 | |||
| 20 | import Data.Maybe | ||
| 21 | import Text.Read (readMaybe) | ||
| 22 | |||
| 23 | deriving instance Read Notify.Urgency | ||
| 24 | |||
| 25 | main :: IO () | ||
| 26 | main = do | ||
| 27 | envFiles <- glob "@userHome@/.dbus/session-bus/*" | ||
| 28 | forM_ envFiles $ \envFile -> do | ||
| 29 | sessionAddr <- unQuote . tail . snd . break (== '=') . head . filter ("DBUS_SESSION_BUS_ADDRESS=" `isPrefixOf`) . lines <$> readFile envFile | ||
| 30 | setEnv "DBUS_SESSION_BUS_ADDRESS" sessionAddr | ||
| 31 | lines <- lines <$> getContents | ||
| 32 | case lines of | ||
| 33 | ((trim -> summary):(trim . unlines -> contents)) -> do | ||
| 34 | (opts, _) <- flip getUsingConf [] [ (arg, "urgency", Optional, "") | ||
| 35 | , (arg, "app-name", Optional, "") | ||
| 36 | , (arg, "category", Optional, "") | ||
| 37 | ] | ||
| 38 | let | ||
| 39 | urgency = fromMaybe Notify.Normal $ readMaybe . caseForRead =<< Map.lookup "urgency" opts | ||
| 40 | appName = fromMaybe "notify-@userName@" $ Map.lookup "app-name" opts | ||
| 41 | category = fromMaybe "" $ Map.lookup "category" opts | ||
| 42 | Notify.display_ $ Notify.summary summary <> Notify.body contents <> Notify.appName appName <> Notify.urgency urgency <> Notify.category category | ||
| 43 | _ -> exitWith $ ExitFailure 2 | ||
| 44 | where | ||
| 45 | trim = dropWhileEnd isSpace . dropWhile isSpace | ||
| 46 | unQuote ('\'':xs) = init xs | ||
| 47 | unQuote ('"':xs) = init xs | ||
| 48 | unQuote xs = xs | ||
| 49 | caseForRead [] = [] | ||
| 50 | caseForRead (x:xs) = toUpper x : map toLower xs | ||
diff --git a/custom/notify-user.nix b/custom/notify-user.nix deleted file mode 100644 index e9e98ddc..00000000 --- a/custom/notify-user.nix +++ /dev/null | |||
| @@ -1,69 +0,0 @@ | |||
| 1 | { stdenv, writeTextFile | ||
| 2 | , ghcWithPackages | ||
| 3 | , user ? "gkleen" | ||
| 4 | # , libnotify | ||
| 5 | }: | ||
| 6 | |||
| 7 | stdenv.mkDerivation { | ||
| 8 | name = ''notify-${user}''; | ||
| 9 | src = writeTextFile { name = ''notify-${user}.hs''; text = '' | ||
| 10 | {-# LANGUAGE ViewPatterns, StandaloneDeriving #-} | ||
| 11 | |||
| 12 | import System.FilePath.Glob (glob) | ||
| 13 | import System.Environment (setEnv, getArgs) | ||
| 14 | import System.Process (spawnProcess, waitForProcess) | ||
| 15 | import System.Exit (exitWith, ExitCode(..)) | ||
| 16 | |||
| 17 | import Data.List (isPrefixOf, dropWhile, dropWhileEnd, init) | ||
| 18 | import Data.Char (isSpace, toLower, toUpper) | ||
| 19 | |||
| 20 | import Control.Monad (forM_, void) | ||
| 21 | |||
| 22 | import qualified Libnotify as Notify | ||
| 23 | import Data.Monoid | ||
| 24 | |||
| 25 | import System.Console.GetOpt.Simple | ||
| 26 | |||
| 27 | import qualified Data.Map as Map | ||
| 28 | |||
| 29 | import Data.Maybe | ||
| 30 | import Text.Read (readMaybe) | ||
| 31 | |||
| 32 | deriving instance Read Notify.Urgency | ||
| 33 | |||
| 34 | main = do | ||
| 35 | envFiles <- glob "/home/${user}/.dbus/session-bus/*" | ||
| 36 | forM_ envFiles $ \envFile -> do | ||
| 37 | sessionAddr <- unQuote . tail . snd . break (== '=') . head . filter ("DBUS_SESSION_BUS_ADDRESS=" `isPrefixOf`) . lines <$> readFile envFile | ||
| 38 | setEnv "DBUS_SESSION_BUS_ADDRESS" sessionAddr | ||
| 39 | lines <- lines <$> getContents | ||
| 40 | case lines of | ||
| 41 | ((trim -> summary):(trim . unlines -> contents)) -> do | ||
| 42 | (opts, _) <- flip getUsingConf [] [ (arg, "urgency", Optional, "") | ||
| 43 | , (arg, "app-name", Optional, "") | ||
| 44 | , (arg, "category", Optional, "") | ||
| 45 | ] | ||
| 46 | let | ||
| 47 | urgency = fromMaybe Notify.Normal $ readMaybe . caseForRead =<< Map.lookup "urgency" opts | ||
| 48 | appName = fromMaybe "notify-${user}" $ Map.lookup "app-name" opts | ||
| 49 | category = fromMaybe "" $ Map.lookup "category" opts | ||
| 50 | Notify.display_ $ Notify.summary summary <> Notify.body contents <> Notify.appName appName <> Notify.urgency urgency <> Notify.category category | ||
| 51 | _ -> exitWith $ ExitFailure 2 | ||
| 52 | where | ||
| 53 | trim = dropWhileEnd isSpace . dropWhile isSpace | ||
| 54 | unQuote ('\''':xs) = init xs | ||
| 55 | unQuote ('"':xs) = init xs | ||
| 56 | unQuote xs = xs | ||
| 57 | caseForRead [] = [] | ||
| 58 | caseForRead (x:xs) = toUpper x : map toLower xs | ||
| 59 | ''; }; | ||
| 60 | phases = [ "buildPhase" "installPhase" ]; | ||
| 61 | buildPhase = '' | ||
| 62 | ${ghcWithPackages (p: with p; [ Glob process libnotify getopt-simple containers ])}/bin/ghc -odir . -hidir . $src -o notify-${user} | ||
| 63 | ''; | ||
| 64 | installPhase = '' | ||
| 65 | mkdir -p $out/bin | ||
| 66 | cp notify-${user} $out/bin | ||
| 67 | chmod +x $out/bin/notify-${user} | ||
| 68 | ''; | ||
| 69 | } | ||
diff --git a/custom/notify-users.nix b/custom/notify-users.nix new file mode 100644 index 00000000..e68b0be2 --- /dev/null +++ b/custom/notify-users.nix | |||
| @@ -0,0 +1,53 @@ | |||
| 1 | { config, lib, pkgs, ... }: | ||
| 2 | |||
| 3 | with lib; | ||
| 4 | |||
| 5 | let | ||
| 6 | cfg = config.services.notify-users; | ||
| 7 | |||
| 8 | notify-user = userName: with pkgs; stdenv.mkDerivation { | ||
| 9 | name = "notify-${userName}"; | ||
| 10 | src = ./notify-user.hs; | ||
| 11 | |||
| 12 | phases = [ "unpackPhase" "buildPhase" "installPhase" ]; | ||
| 13 | |||
| 14 | unpackPhase = '' | ||
| 15 | cp $src notify-user.hs | ||
| 16 | ''; | ||
| 17 | |||
| 18 | inherit userName; | ||
| 19 | userHome = config.users.users."${userName}".home; | ||
| 20 | |||
| 21 | buildPhase = '' | ||
| 22 | substituteAllInPlace notify-user.hs | ||
| 23 | ${ghcWithPackages (p: with p; [ Glob process libnotify getopt-simple containers ])}/bin/ghc -odir . -hidir . $src -o notify-${userName} | ||
| 24 | ''; | ||
| 25 | |||
| 26 | installPhase = '' | ||
| 27 | mkdir -p $out/bin | ||
| 28 | |||
| 29 | install -m 755 -t $out/bin \ | ||
| 30 | notify-${userName} | ||
| 31 | ''; | ||
| 32 | }; | ||
| 33 | in { | ||
| 34 | options = { | ||
| 35 | services.notify-users = mkOption { | ||
| 36 | type = with types; listOf str; | ||
| 37 | default = []; | ||
| 38 | description = '' | ||
| 39 | Users to install a notify-user script for | ||
| 40 | ''; | ||
| 41 | }; | ||
| 42 | }; | ||
| 43 | |||
| 44 | config = mkIf (cfg != []) { | ||
| 45 | security.wrappers = listToAttrs (map (user: nameValuePair "notify-${user}" { | ||
| 46 | owner = user; | ||
| 47 | setuid = true; | ||
| 48 | setgid = false; | ||
| 49 | permissions = "u+rx,g+x,o+x"; | ||
| 50 | source = "${notify-user user}/bin/notify-${user}"; | ||
| 51 | }) cfg); | ||
| 52 | }; | ||
| 53 | } | ||
diff --git a/custom/recv-media.sh b/custom/recv-media.sh new file mode 100644 index 00000000..29e3d158 --- /dev/null +++ b/custom/recv-media.sh | |||
| @@ -0,0 +1,56 @@ | |||
| 1 | #!@zsh@/bin/zsh | ||
| 2 | |||
| 3 | pid=$? | ||
| 4 | |||
| 5 | exec 1> >(@utillinux@/bin/logger --id=$pid -t recv-media -p user.notice) | ||
| 6 | exec 2> >(@utillinux@/bin/logger --id=$pid -t recv-media -p user.error) | ||
| 7 | |||
| 8 | [[ -z "$1" || -z "$2" ]] && exit 2 | ||
| 9 | |||
| 10 | dir=@mediaDir@ | ||
| 11 | group=$(@coreutils@/bin/stat -c '%G' $dir) | ||
| 12 | tmpFile="${dir}/.tmp/${1:t}" | ||
| 13 | target="${dir}/${1:t}" | ||
| 14 | |||
| 15 | if [[ -n "${3}" ]]; then | ||
| 16 | target="${dir}"/$(@coreutils@/bin/base64 -d <<<${3}) | ||
| 17 | fi | ||
| 18 | |||
| 19 | @utillinux@/bin/logger --id=$pid -t recv-media -p user.debug <<EOF | ||
| 20 | $(id) | ||
| 21 | $(stat ${dir}) | ||
| 22 | $(stat ${1}) | ||
| 23 | $(echo ${2}) | ||
| 24 | EOF | ||
| 25 | |||
| 26 | if [[ $(id -Gn) != *"$group"* ]]; then | ||
| 27 | printf "Groups are ‘%s’. Trying to switch primary group to ‘%s’..." $(id -Gn) $group | ||
| 28 | exec -- @wrapperDir@/sg $group "$0 $*" | ||
| 29 | fi | ||
| 30 | |||
| 31 | typeset -a failures | ||
| 32 | failures=() | ||
| 33 | |||
| 34 | ( | ||
| 35 | if ! cp -lnv --preserve=all "$1" "${target}"; then | ||
| 36 | @coreutils@/bin/mkdir -pv "${tmpFile:h}" || failures+="mkdir" | ||
| 37 | |||
| 38 | @utillinux@/bin/ionice -c 3 -t @coreutils@/bin/cp -vn --preserve=all "$1" "${tmpFile}" && mv -v "${tmpFile}" "${target}" || failures+="cp" | ||
| 39 | fi | ||
| 40 | @coreutils@/bin/touch -c -m -t "$2" "${target}" || failures+="touch" | ||
| 41 | ) | ||
| 42 | |||
| 43 | if @doNotify@ && [[ $#failures -gt 0 ]]; then | ||
| 44 | printf "%s\n%s\n%s" "${target:t}" "Failed to download" ${(j:, :)failures} | @notify@ -a recv-media -u Critical | ||
| 45 | fi | ||
| 46 | |||
| 47 | if @doNotify@; then | ||
| 48 | ( | ||
| 49 | if @showTitle@; then | ||
| 50 | summary=$(@ffmpeg@/bin/ffmpeg -i "${target}" -f ffmetadata pipe:1 2>/dev/null | sed -r '/\[CHAPTER\]/q; /^title=/!d; s/^title=//') | ||
| 51 | else | ||
| 52 | summary=${target:t} | ||
| 53 | fi | ||
| 54 | printf "%s\n%s\n" "${summary}" "" | @notify@ -a recv-media || true | ||
| 55 | ) || true | ||
| 56 | fi | ||
diff --git a/custom/uucp-mediaclient.nix b/custom/uucp-mediaclient.nix new file mode 100644 index 00000000..07afeda4 --- /dev/null +++ b/custom/uucp-mediaclient.nix | |||
| @@ -0,0 +1,89 @@ | |||
| 1 | { config, lib, pkgs, ... }: | ||
| 2 | |||
| 3 | with lib; | ||
| 4 | |||
| 5 | let | ||
| 6 | cfg = config.services.uucp.media-client; | ||
| 7 | |||
| 8 | recv-media = with pkgs; stdenv.mkDerivation rec { | ||
| 9 | name = "recv-media"; | ||
| 10 | src = ./recv-media.sh; | ||
| 11 | |||
| 12 | phases = [ "unpackPhase" "buildPhase" "installPhase" ]; | ||
| 13 | |||
| 14 | unpackPhase = '' | ||
| 15 | cp $src recv-media | ||
| 16 | ''; | ||
| 17 | |||
| 18 | inherit zsh coreutils; | ||
| 19 | inherit (config.security) wrapperDir; | ||
| 20 | inherit (cfg) mediaDir; | ||
| 21 | utillinux = util-linux; | ||
| 22 | doNotify = cfg.notify.users != []; | ||
| 23 | ffmpeg = if doNotify then ffmpeg-full else "/no-such-path"; | ||
| 24 | notify = writeScript "notify.sh" '' | ||
| 25 | #!${zsh}/bin/zsh | ||
| 26 | |||
| 27 | ${concatMapStringsSep "\n" ({ name, ... }: "${notify-user name}/bin/notify-${name} $@") notify.users} | ||
| 28 | ''; | ||
| 29 | |||
| 30 | buildPhase = '' | ||
| 31 | substituteAllInPlace recv-media | ||
| 32 | ''; | ||
| 33 | |||
| 34 | installPhase = '' | ||
| 35 | mkdir -p $out/bin | ||
| 36 | |||
| 37 | install -m 755 -t $out/bin \ | ||
| 38 | recv-media | ||
| 39 | ''; | ||
| 40 | }; | ||
| 41 | |||
| 42 | |||
| 43 | in { | ||
| 44 | options = { | ||
| 45 | services.uucp.media-client = { | ||
| 46 | remoteNodes = mkOption { | ||
| 47 | type = with types; listOf str; | ||
| 48 | default = []; | ||
| 49 | description = '' | ||
| 50 | Servers to receive media from | ||
| 51 | ''; | ||
| 52 | }; | ||
| 53 | |||
| 54 | notify = { | ||
| 55 | users = mkOption { | ||
| 56 | type = with types; listOf str; | ||
| 57 | default = []; | ||
| 58 | description = '' | ||
| 59 | Users to notify | ||
| 60 | ''; | ||
| 61 | }; | ||
| 62 | |||
| 63 | extractTitle = mkOption { | ||
| 64 | type = types.bool; | ||
| 65 | default = true; | ||
| 66 | description = '' | ||
| 67 | Use ffmpeg to include the media title in notifications | ||
| 68 | ''; | ||
| 69 | }; | ||
| 70 | }; | ||
| 71 | |||
| 72 | mediaDir = mkOption { | ||
| 73 | type = types.path; | ||
| 74 | default = "/var/media"; | ||
| 75 | description = "Media directory"; | ||
| 76 | }; | ||
| 77 | }; | ||
| 78 | }; | ||
| 79 | |||
| 80 | config = mkIf (cfg.remoteNodes != []) { | ||
| 81 | imports = [ ./custom/notify-users.nix ]; | ||
| 82 | |||
| 83 | services.uucp.commandPath = [ "${recv-media}/bin" ]; | ||
| 84 | services.uucp.remoteNodes = genAttrs cfg.remoteNodes (name: { commands = ["recv-media"]; } ); | ||
| 85 | |||
| 86 | services.notify-users = notify.users; | ||
| 87 | }; | ||
| 88 | } | ||
| 89 | |||
| @@ -15,6 +15,8 @@ | |||
| 15 | ./custom/tinc/yggdrasil.nix | 15 | ./custom/tinc/yggdrasil.nix |
| 16 | ./custom/uucp.nix | 16 | ./custom/uucp.nix |
| 17 | ./custom/borgbackup.nix | 17 | ./custom/borgbackup.nix |
| 18 | ./custom/uucp-mediaclient.nix | ||
| 19 | ./custom/notify-users.nix | ||
| 18 | ./utils/nix/module.nix | 20 | ./utils/nix/module.nix |
| 19 | ]; | 21 | ]; |
| 20 | 22 | ||
| @@ -214,7 +216,7 @@ | |||
| 214 | "odin" = { | 216 | "odin" = { |
| 215 | publicKeys = ["ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKcDj49TqmflGTmtGBqDawxmCBWW1txj61CZ7KT0hTHK uucp@odin"]; | 217 | publicKeys = ["ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKcDj49TqmflGTmtGBqDawxmCBWW1txj61CZ7KT0hTHK uucp@odin"]; |
| 216 | hostnames = ["odin.asgard.yggdrasil"]; | 218 | hostnames = ["odin.asgard.yggdrasil"]; |
| 217 | commands = lib.mkForce ["recv-media" "notify-gkleen"]; | 219 | commands = ["notify-gkleen"]; |
| 218 | }; | 220 | }; |
| 219 | "ymir" = { | 221 | "ymir" = { |
| 220 | publicKeys = ["ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFH1QWdgoC03nzW5GBuCl2pqASHeIXIYtE9IInHdaKcO uucp@ymir"]; | 222 | publicKeys = ["ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFH1QWdgoC03nzW5GBuCl2pqASHeIXIYtE9IInHdaKcO uucp@ymir"]; |
| @@ -222,9 +224,16 @@ | |||
| 222 | }; | 224 | }; |
| 223 | }; | 225 | }; |
| 224 | 226 | ||
| 225 | commandPath = [ "${pkgs.callPackage ./hel/recv-media.nix {}}/bin" config.security.wrapperDir ]; | 227 | commandPath = [ "${config.security.wrapperDir}" ]; |
| 226 | defaultCommands = lib.mkForce []; | 228 | defaultCommands = lib.mkForce []; |
| 229 | |||
| 230 | media-client = { | ||
| 231 | remoteNodes = [ "odin" ]; | ||
| 232 | notify.users = [ "gkleen" ]; | ||
| 233 | }; | ||
| 227 | }; | 234 | }; |
| 235 | |||
| 236 | notify-users = [ "gkleen" ]; | ||
| 228 | 237 | ||
| 229 | postfix = { | 238 | postfix = { |
| 230 | enable = true; | 239 | enable = true; |
| @@ -357,15 +366,6 @@ | |||
| 357 | "mount.cifs".source = "${pkgs.cifs-utils}/bin/mount.cifs"; | 366 | "mount.cifs".source = "${pkgs.cifs-utils}/bin/mount.cifs"; |
| 358 | "thinklight".source = | 367 | "thinklight".source = |
| 359 | "${(pkgs.callPackage ./custom/thinklight.nix { thinklight = "kbd_backlight"; })}/bin/thinklight"; | 368 | "${(pkgs.callPackage ./custom/thinklight.nix { thinklight = "kbd_backlight"; })}/bin/thinklight"; |
| 360 | "notify-gkleen" = { | ||
| 361 | group = "users"; | ||
| 362 | owner = "gkleen"; | ||
| 363 | setgid = true; | ||
| 364 | setuid = true; | ||
| 365 | permissions = "u+rx,g+x,o+x"; | ||
| 366 | source = let notify-user = pkgs.callPackage ./custom/notify-user.nix { inherit (pkgs.haskellPackages) ghcWithPackages; }; | ||
| 367 | in "${notify-user}/bin/notify-gkleen"; | ||
| 368 | }; | ||
| 369 | }; | 369 | }; |
| 370 | 370 | ||
| 371 | polkit = { | 371 | polkit = { |
diff --git a/hel/recv-media.nix b/hel/recv-media.nix deleted file mode 100644 index 91801593..00000000 --- a/hel/recv-media.nix +++ /dev/null | |||
| @@ -1,72 +0,0 @@ | |||
| 1 | { stdenv | ||
| 2 | , coreutils | ||
| 3 | , writeScriptBin | ||
| 4 | , eject | ||
| 5 | , notifyUser ? "gkleen" | ||
| 6 | , showTitle ? true | ||
| 7 | , ffmpeg ? null | ||
| 8 | , gnused ? null | ||
| 9 | , wrapperDir ? "/run/wrappers/bin" | ||
| 10 | }: | ||
| 11 | |||
| 12 | assert showTitle -> ffmpeg != null && gnused != null && notifyUser != null; | ||
| 13 | |||
| 14 | writeScriptBin "recv-media" '' | ||
| 15 | #!${stdenv.shell} | ||
| 16 | |||
| 17 | pid=$? | ||
| 18 | notify=${if notifyUser == null then "false" else "true"} | ||
| 19 | notifyUser=${if notifyUser == null then "" else notifyUser} | ||
| 20 | |||
| 21 | PATH=${wrapperDir}:${eject}/bin:${coreutils}/bin${if showTitle then '':${ffmpeg}/bin:${gnused}/bin'' else ""} | ||
| 22 | |||
| 23 | exec 1> >(logger --id=$pid -t recv-media -p user.notice) | ||
| 24 | exec 2> >(logger --id=$pid -t recv-media -p user.error) | ||
| 25 | |||
| 26 | [[ -z "$1" || -z "$2" ]] && exit 2 | ||
| 27 | |||
| 28 | dir=/var/media | ||
| 29 | group=$(stat -c '%G' $dir) | ||
| 30 | tmpFile="''${dir}/.tmp/''${1:t}" | ||
| 31 | target="''${dir}/''${1:t}" | ||
| 32 | |||
| 33 | if [[ -n "''${3}" ]]; then | ||
| 34 | target="''${dir}"/$(base64 -d <<<''${3}) | ||
| 35 | fi | ||
| 36 | |||
| 37 | logger --id=$pid -t recv-media -p user.debug <<EOF | ||
| 38 | $(id) | ||
| 39 | $(stat ''${dir}) | ||
| 40 | $(stat ''${1}) | ||
| 41 | $(echo ''${2}) | ||
| 42 | EOF | ||
| 43 | |||
| 44 | if [[ $(id -Gn) != *"$group"* ]]; then | ||
| 45 | printf "Groups are ‘%s’. Trying to switch primary group to ‘%s’..." $(id -Gn) $group | ||
| 46 | exec -- sg $group "$0 $*" | ||
| 47 | fi | ||
| 48 | |||
| 49 | typeset -a failures | ||
| 50 | failures=() | ||
| 51 | |||
| 52 | ( | ||
| 53 | if ! cp -lnv --preserve=all "$1" "''${target}"; then | ||
| 54 | mkdir -pv "''${tmpFile:h}" || failures+="mkdir" | ||
| 55 | |||
| 56 | ionice -c 3 -t cp -vn --preserve=all "$1" "''${tmpFile}" && mv -v "''${tmpFile}" "''${target}" || failures+="cp" | ||
| 57 | fi | ||
| 58 | touch -c -m -t "$2" "''${target}" || failures+="touch" | ||
| 59 | ) | ||
| 60 | |||
| 61 | if $notify && [[ $#failures -gt 0 ]]; then | ||
| 62 | printf "%s\n%s\n%s" $(basename "$1") "Failed to download" ''${(j:, :)failures} | notify-''${notifyUser} -a recv-media -u Critical | ||
| 63 | fi | ||
| 64 | |||
| 65 | if $notify; then | ||
| 66 | ( | ||
| 67 | summary=${if showTitle then ''$(ffmpeg -i "''${target}" -f ffmetadata pipe:1 2>/dev/null | sed -r '/^\[CHAPTER\]$/q; /^title=/!d; s/^title=//')'' else ''""''} | ||
| 68 | [[ -z "''${summary}" ]] && summary=$(basename "$1") | ||
| 69 | printf "%s\n%s\n" "''${summary}" "" | notify-''${notifyUser} -a recv-media || true | ||
| 70 | ) || true | ||
| 71 | fi | ||
| 72 | '' | ||
