diff --git a/package-lock.json b/package-lock.json index 6c985c8..b05547f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -218,10 +218,18 @@ "steno": "^0.4.1" } }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "requires": { + "yallist": "^4.0.0" + } + }, "luxon": { - "version": "1.25.0", - "resolved": "https://registry.npmjs.org/luxon/-/luxon-1.25.0.tgz", - "integrity": "sha512-hEgLurSH8kQRjY6i4YLey+mcKVAWXbDNlZRmM6AgWDJ1cY3atl8Ztf5wEY7VBReFbmGnwQPz7KYJblL8B2k0jQ==" + "version": "1.26.0", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-1.26.0.tgz", + "integrity": "sha512-+V5QIQ5f6CDXQpWNICELwjwuHdqeJM1UenlZWx5ujcRMc9venvluCjFb4t5NYLhb6IhkbMVOxzVuOqkgMxee2A==" }, "merge-stream": { "version": "2.0.0", @@ -278,6 +286,14 @@ "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" }, + "semver": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", + "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", + "requires": { + "lru-cache": "^6.0.0" + } + }, "shortid": { "version": "2.2.16", "resolved": "https://registry.npmjs.org/shortid/-/shortid-2.2.16.tgz", @@ -342,10 +358,15 @@ "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.5.tgz", "integrity": "sha512-hsRUr4FFrvhhRH12wOdfs38Gy7k2FFzB9qgN9v3aLykRq0dRcdcpz5C9FxdS2NuhOrI/628b/KSTJ3rwHysYSg==" }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, "yargs": { - "version": "16.1.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.1.1.tgz", - "integrity": "sha512-hAD1RcFP/wfgfxgMVswPE+z3tlPFtxG8/yWUrG2i17sTWGCGqWnxKcLTF4cUKDUK8fzokwsmO9H0TDkRbMHy8w==", + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", "requires": { "cliui": "^7.0.2", "escalade": "^3.1.1", @@ -357,9 +378,9 @@ } }, "yargs-parser": { - "version": "20.2.4", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", - "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==" + "version": "20.2.5", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.5.tgz", + "integrity": "sha512-jYRGS3zWy20NtDtK2kBgo/TlAoy5YUuhD9/LZ7z7W4j1Fdw2cqD0xEEclf8fxc8xjD6X5Qr+qQQwCEsP8iRiYg==" } } } diff --git a/package.json b/package.json index fd3dfe7..3afd939 100644 --- a/package.json +++ b/package.json @@ -30,8 +30,9 @@ "easytimer.js": "^4.3.1", "home-dir": "^1.0.0", "lowdb": "^1.0.0", - "luxon": "^1.25.0", + "luxon": "^1.26.0", + "semver": "^7.3.4", "shortid": "^2.2.16", - "yargs": "^16.1.1" + "yargs": "^16.2.0" } } diff --git a/src/commands/start.js b/src/commands/start.js index d8a2fe7..f35e088 100644 --- a/src/commands/start.js +++ b/src/commands/start.js @@ -1,6 +1,6 @@ const { Timer } = require("easytimer.js"); const dialog = require("dialog"); -const doNotDisturb = require("@sindresorhus/do-not-disturb"); +const doNotDisturb = require("../dnd").getDndProvider(); const {clearLineAndWrite} = require("../helpers/cli"); const {startCountdownTimer} = require("../helpers/timer"); const TimerSession = require("../db/session"); diff --git a/src/dnd/index.js b/src/dnd/index.js new file mode 100644 index 0000000..6deaeb0 --- /dev/null +++ b/src/dnd/index.js @@ -0,0 +1,21 @@ +const os = require('os'); +const semverParse = require('semver/functions/parse'); +const LegacyDndProvider = require("./legacy-dnd"); +const ShellBigSurDndProvider = require("./shell-bigsur-dnd"); + +function isBigSurOrNewer() { + const { major } = semverParse(os.release()) + return major >= 20; +} + +function getDndProvider() { + if (isBigSurOrNewer()) { + return new ShellBigSurDndProvider(); + } + + return new LegacyDndProvider(); +} + +module.exports = { + getDndProvider, +} diff --git a/src/dnd/legacy-dnd.js b/src/dnd/legacy-dnd.js new file mode 100644 index 0000000..09c3250 --- /dev/null +++ b/src/dnd/legacy-dnd.js @@ -0,0 +1,13 @@ +const doNotDisturb = require("@sindresorhus/do-not-disturb"); + +class LegacyDndProvider { + enable() { + return doNotDisturb.enable(); + } + + disable() { + return doNotDisturb.disable(); + } +} + +module.exports = LegacyDndProvider; diff --git a/src/dnd/shell-bigsur-dnd/check.sh b/src/dnd/shell-bigsur-dnd/check.sh new file mode 100755 index 0000000..0ad6b51 --- /dev/null +++ b/src/dnd/shell-bigsur-dnd/check.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env zsh + +# https://github.com/sindresorhus/do-not-disturb/issues/9#issuecomment-768492417 +plutil -extract dnd_prefs xml1 -o - /Users/"$USER"/Library/Preferences/com.apple.ncprefs.plist | xmllint --xpath "string(//data)" - | base64 --decode | plutil -convert xml1 - -o - | xmllint --xpath 'boolean(//key[text()="userPref"]/following-sibling::dict/key[text()="enabled"])' - diff --git a/src/dnd/shell-bigsur-dnd/disable.sh b/src/dnd/shell-bigsur-dnd/disable.sh new file mode 100755 index 0000000..e6c0830 --- /dev/null +++ b/src/dnd/shell-bigsur-dnd/disable.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env zsh + +# https://github.com/sindresorhus/do-not-disturb/issues/9#issuecomment-768492417 +defaults read /Users/"$USER"/Library/Preferences/com.apple.ncprefs.plist >/dev/null +DND_HEX_DATA=$(plutil -extract dnd_prefs xml1 -o - /Users/"$USER"/Library/Preferences/com.apple.ncprefs.plist | xmllint --xpath "string(//data)" - | base64 --decode | plutil -convert xml1 - -o - | plutil -remove userPref - -o - | plutil -convert binary1 - -o - | xxd -p | tr -d '\n') +defaults write com.apple.ncprefs.plist dnd_prefs -data "$DND_HEX_DATA" +PROCESS_LIST=( + #cfprefsd + usernoted + #NotificationCenter +) +while IFS= read -r line || [[ -n "$line" ]]; do + if [[ "$line" == "" ]]; then continue; fi + i="$line" + #echo "$i" + if [[ $(ps aux | grep "$i" | grep -v grep | awk '{print $2;}') != "" ]]; then + killall "$i" && sleep 0.1 && while [[ $(ps aux | grep "$i" | grep -v grep | awk '{print $2;}') == "" ]]; do sleep 0.5; done + else + : + fi +done <<<"$(printf "%s\n" "${PROCESS_LIST[@]}")" diff --git a/src/dnd/shell-bigsur-dnd/enable.sh b/src/dnd/shell-bigsur-dnd/enable.sh new file mode 100755 index 0000000..5fcf38c --- /dev/null +++ b/src/dnd/shell-bigsur-dnd/enable.sh @@ -0,0 +1,29 @@ +#!/usr/bin/env zsh + +# https://github.com/sindresorhus/do-not-disturb/issues/9#issuecomment-768492417 +defaults read /Users/"$USER"/Library/Preferences/com.apple.ncprefs.plist >/dev/null +DND_HEX_DATA=$(plutil -extract dnd_prefs xml1 -o - /Users/"$USER"/Library/Preferences/com.apple.ncprefs.plist | xmllint --xpath "string(//data)" - | base64 --decode | plutil -convert xml1 - -o - | plutil -insert userPref -xml " + + date + $(date -u +"%Y-%m-%dT%H:%M:%SZ") + enabled + + reason + 1 + " - -o - | plutil -convert binary1 - -o - | xxd -p | tr -d '\n') +defaults write com.apple.ncprefs.plist dnd_prefs -data "$DND_HEX_DATA" +PROCESS_LIST=( + #cfprefsd + usernoted + #NotificationCenter +) +while IFS= read -r line || [[ -n "$line" ]]; do + if [[ "$line" == "" ]]; then continue; fi + i="$line" + #echo "$i" + if [[ $(ps aux | grep "$i" | grep -v grep | awk '{print $2;}') != "" ]]; then + killall "$i" && sleep 0.1 && while [[ $(ps aux | grep "$i" | grep -v grep | awk '{print $2;}') == "" ]]; do sleep 0.5; done + else + : + fi +done <<<"$(printf "%s\n" "${PROCESS_LIST[@]}")" diff --git a/src/dnd/shell-bigsur-dnd/index.js b/src/dnd/shell-bigsur-dnd/index.js new file mode 100644 index 0000000..3bc4d7d --- /dev/null +++ b/src/dnd/shell-bigsur-dnd/index.js @@ -0,0 +1,28 @@ +const util = require('util'); +const path = require('path'); +const execFile = util.promisify(require('child_process').execFile); + +const execShellScript = filename => execFile(path.resolve(__dirname, filename)); + +class ShellBigsurDndProvider { + async enable() { + if (await this._isDnDEnabled()) { + return; + } + return execShellScript('./enable.sh'); + } + + async disable() { + if (!await this._isDnDEnabled()) { + return; + } + return execShellScript('./disable.sh'); + } + + async _isDnDEnabled() { + const { stdout } = await execShellScript('./check.sh'); + return stdout === 'true'; + } +} + +module.exports = ShellBigsurDndProvider;