From 201e1222bfcc09f9bc7870f0af2b24a08148d3d9 Mon Sep 17 00:00:00 2001 From: streambinder Date: Tue, 3 Sep 2024 16:10:04 +0200 Subject: [PATCH] ci(push): update super-linter action --- .github/README.md | 2 +- .github/linters/.golangci.yml | 18 +- .github/linters/.mypy.ini | 3 + .github/linters/.python-lint | 11 ++ .github/workflows/push.yml | 15 +- arduino/ask_reliability/README.md | 1 + backup/restup/config.sample.yml | 1 + backup/restup/hooks/acl_pre.sh | 2 +- backup/restup/hooks/db_common.sh | 2 +- backup/restup/hooks/db_pre.sh | 10 +- backup/restup/hooks/fw_common.sh | 2 +- backup/restup/hooks/fw_pre.sh | 2 +- backup/restup/runner.py | 148 +++++++------- git/committer-changer/runner.sh | 32 +-- git/history-touchup/runner.sh | 16 +- image/reasize/README.md | 2 +- image/reasize/runner.sh | 98 +++++----- monitoring/scrubber/runner.sh | 54 +++--- multimedia/apto/README.md | 3 + multimedia/apto/runner.sh | 310 +++++++++++++++--------------- multimedia/blueboost/runner.sh | 12 +- multimedia/consentio/runner.sh | 84 ++++---- multimedia/inflarics/runner.go | 42 ++-- multimedia/kindle/runner.sh | 6 +- multimedia/pluffer/runner.go | 8 +- multimedia/soundhole/runner.sh | 122 ++++++------ multimedia/volnorm/runner.go | 6 +- network/ddaddy/runner.sh | 60 +++--- social/instaget/README.md | 2 +- social/instaget/runner.sh | 34 ++-- system/ego/id.py | 17 +- system/ego/runner.py | 11 +- system/ego/up.py | 42 ++-- 33 files changed, 600 insertions(+), 578 deletions(-) create mode 100644 .github/linters/.mypy.ini create mode 100644 .github/linters/.python-lint diff --git a/.github/README.md b/.github/README.md index ca24cdb..01b6bb9 100644 --- a/.github/README.md +++ b/.github/README.md @@ -1,3 +1,3 @@ -# UnciƦ +# UnciƦ documentation This is the safe place to put every mini-project worth to be kept whilst not deserving its own repository. diff --git a/.github/linters/.golangci.yml b/.github/linters/.golangci.yml index d98db4d..5dab334 100644 --- a/.github/linters/.golangci.yml +++ b/.github/linters/.golangci.yml @@ -1,13 +1,4 @@ --- -######################### -######################### -## Golang Linter rules ## -######################### -######################### - -# configure golangci-lint -# https://github.com/golangci/golangci-lint/blob/master/.golangci.example.yml - issues: exclude-rules: - path: _test\.go @@ -16,7 +7,6 @@ issues: - gosec - goconst linters: - fast: true enable: - gosec - unconvert @@ -28,15 +18,11 @@ linters: - revive linters-settings: errcheck: - # report about assignment of errors to blank identifier - # default is false: such cases aren't reported by default. check-blank: true govet: - # report about shadowed variables - check-shadowing: true + enable: + - shadowing gocyclo: - # minimal code complexity to report, 30 by default min-complexity: 15 maligned: - # print struct with more effective memory layout or not, false by default suggest-new: true diff --git a/.github/linters/.mypy.ini b/.github/linters/.mypy.ini new file mode 100644 index 0000000..6b090dd --- /dev/null +++ b/.github/linters/.mypy.ini @@ -0,0 +1,3 @@ +[mypy] +ignore_missing_imports = True +explicit_package_bases = True diff --git a/.github/linters/.python-lint b/.github/linters/.python-lint new file mode 100644 index 0000000..7113263 --- /dev/null +++ b/.github/linters/.python-lint @@ -0,0 +1,11 @@ +[MASTER] + +jobs=0 + +[MESSAGES CONTROL] + +disable= + import-error, + missing-module-docstring, + missing-class-docstring, + missing-function-docstring, diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index 78c807f..4f12c13 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -1,3 +1,4 @@ +--- name: push on: @@ -24,13 +25,17 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: docker://github/super-linter:latest + - uses: super-linter/super-linter@v7.1.0 env: GITHUB_TOKEN: ${{ secrets.GH_ACTIONS_UNCIAE }} VALIDATE_ALL_CODEBASE: false + VALIDATE_PYTHON_PYINK: false notify: needs: [commitlint, super-linter] - if: success() && github.event_name == 'push' && github.ref == 'refs/heads/master' + if: >- + success() && + github.event_name == 'push' && + github.ref == 'refs/heads/master' runs-on: ubuntu-latest steps: - uses: peter-evans/repository-dispatch@v3 @@ -38,4 +43,8 @@ jobs: token: ${{ secrets.GH_ACTIONS_UNCIAE }} repository: streambinder/clavis event-type: unciae-sync - client-payload: '{"ref": "${{ github.ref }}", "sha": "${{ github.sha }}"}' + client-payload: >- + { + "ref": "${{ github.ref }}", + "sha": "${{ github.sha }}" + } diff --git a/arduino/ask_reliability/README.md b/arduino/ask_reliability/README.md index 0b4c181..34dfb4f 100644 --- a/arduino/ask_reliability/README.md +++ b/arduino/ask_reliability/README.md @@ -10,6 +10,7 @@ This project wraps up the source code used to run Radio Frequency (RF) communica Connect the Arduino boards via USB. Open up `ask_transmitter.ino` and `ask_receiver.ino` as separated projects on Arduino IDE and load them to each specific board. Follow the flow by connecting to the USB/Serial ports (`ttyUSB` ports mapping could very likely be different): + ```bash # transmitter screen -S tx /dev/ttyUSB0; screen -X -S tx quit diff --git a/backup/restup/config.sample.yml b/backup/restup/config.sample.yml index f8031a9..741be47 100644 --- a/backup/restup/config.sample.yml +++ b/backup/restup/config.sample.yml @@ -1,3 +1,4 @@ +--- tasks: - repository: /var/restic/database password: "REDACTED" diff --git a/backup/restup/hooks/acl_pre.sh b/backup/restup/hooks/acl_pre.sh index a522d63..69a5f7a 100755 --- a/backup/restup/hooks/acl_pre.sh +++ b/backup/restup/hooks/acl_pre.sh @@ -5,4 +5,4 @@ source "$(realpath "$(dirname "$0")")/acl_common.sh" mkdir -p "${DIR_ACL}" find "${DIR_ACL}" -type f -delete -getfacl -pR / > "/var/acls/root.acl" 2> /dev/null || echo -n \ No newline at end of file +getfacl -pR / >"/var/acls/root.acl" 2>/dev/null || echo -n diff --git a/backup/restup/hooks/db_common.sh b/backup/restup/hooks/db_common.sh index 81d7f8a..c987766 100755 --- a/backup/restup/hooks/db_common.sh +++ b/backup/restup/hooks/db_common.sh @@ -1,4 +1,4 @@ #!/bin/bash # shellcheck disable=SC2034 -DIR_DB="/var/databases" \ No newline at end of file +DIR_DB="/var/databases" diff --git a/backup/restup/hooks/db_pre.sh b/backup/restup/hooks/db_pre.sh index ed8e909..1127ef2 100755 --- a/backup/restup/hooks/db_pre.sh +++ b/backup/restup/hooks/db_pre.sh @@ -5,8 +5,8 @@ source "$(realpath "$(dirname "$0")")/db_common.sh" mkdir -p "${DIR_DB}" find "${DIR_DB}" -type f -delete -mysql -sN -u root -p'2dkNKCVT9AgFaV8g' -e "SHOW DATABASES;" | \ - grep -Ev "(Database|information_schema|performance_schema)" | \ - while read -r db; do - mysqldump -u root -p'2dkNKCVT9AgFaV8g' "${db}" --add-drop-table > "${DIR_DB}/${db}.sql" -done +mysql -sN -u root -p'2dkNKCVT9AgFaV8g' -e "SHOW DATABASES;" | + grep -Ev "(Database|information_schema|performance_schema)" | + while read -r db; do + mysqldump -u root -p'2dkNKCVT9AgFaV8g' "${db}" --add-drop-table >"${DIR_DB}/${db}.sql" + done diff --git a/backup/restup/hooks/fw_common.sh b/backup/restup/hooks/fw_common.sh index e546f59..af1fbc7 100755 --- a/backup/restup/hooks/fw_common.sh +++ b/backup/restup/hooks/fw_common.sh @@ -2,4 +2,4 @@ # shellcheck disable=SC2034 FW_FNAME="/etc/sysconfig/iptables" -IPTABLES_SAVE="/sbin/iptables-save" \ No newline at end of file +IPTABLES_SAVE="/sbin/iptables-save" diff --git a/backup/restup/hooks/fw_pre.sh b/backup/restup/hooks/fw_pre.sh index 0e0fac5..2fb51ea 100755 --- a/backup/restup/hooks/fw_pre.sh +++ b/backup/restup/hooks/fw_pre.sh @@ -3,4 +3,4 @@ # shellcheck disable=SC1090,SC1091 source "$(realpath "$(dirname "$0")")/fw_common.sh" -"${IPTABLES_SAVE}" > "${FW_FNAME}" \ No newline at end of file +"${IPTABLES_SAVE}" >"${FW_FNAME}" diff --git a/backup/restup/runner.py b/backup/restup/runner.py index d020f88..c65bb6e 100755 --- a/backup/restup/runner.py +++ b/backup/restup/runner.py @@ -27,15 +27,13 @@ def __validate_config(self): for t in self.tasks: for mandatory_token in ["repository", "password", "path"]: if mandatory_token not in t or t[mandatory_token] is None: - raise Exception( - "{} key is mandatory for a task object".format(mandatory_token) + raise RuntimeError( + f"{mandatory_token} key is mandatory for a task object" ) for recommended_token in ["retention"]: if recommended_token not in t or t[recommended_token] is None: print( - "Task for {} has not {} token: it's highly recommended.".format( - t["repository"], recommended_token - ), + f"Task for {t['repository']} has not {recommended_token} token.", file=sys.stderr, ) path_checks = ["repository", "path"] @@ -43,8 +41,8 @@ def __validate_config(self): path_checks += ["postspawn"] if "postspawn" in t else [] for path_entry in path_checks: if not os.path.exists(t[path_entry]): - raise Exception( - "{} path {} does not exist".format(path_entry, t[path_entry]) + raise RuntimeError( + f"{path_entry} path {t[path_entry]} does not exist" ) def __wait(self): @@ -52,102 +50,92 @@ def __wait(self): thread.join() def __t_print(self, payload, file=sys.stdout): - try: - self.__mutex.acquire() + with self.__mutex: if isinstance(payload, (bytes, bytearray)): payload = payload.decode("utf-8") - print(payload) - finally: - self.__mutex.release() + print(payload, file=file) def __process(self, task): if "prespawn" in task: try: - self.__t_print("Running pre-hook {}...".format(task["prespawn"])) + self.__t_print(f"Running pre-hook {task['prespawn']}...") subprocess.run(task["prespawn"], shell=True, check=True) except subprocess.CalledProcessError: self.__t_print( - "Pre-task for {} exited abnormally. Breaking up backup.".format( - task["repository"] - ), + f"Pre-task for {task['repository']} exited abnormally. Breaking up backup.", file=sys.stderr, ) return - self.__t_print("Spawning {} directory restic backup".format(task["path"])) + self.__t_print(f"Spawning {task['path']} directory restic backup") regexes = [] if "regexes" in task: for regex in task["regexes"]: regexes += ["--iexclude", regex] - pipe_auth = subprocess.Popen( - ["echo", "{}".format(task["password"])], stdout=subprocess.PIPE - ) - pipe_restic = subprocess.Popen( - [ - "restic", - "-r", - task["repository"], - "backup", - task["path"], - "--exclude-caches", - ] - + regexes, - stdin=pipe_auth.stdout, - stdout=subprocess.PIPE, - ) - pipe_auth.stdout.close() - pipe_out, pipe_err = pipe_restic.communicate() - if pipe_err is not None: - self.__t_print( - "Unable to backup {} repository: {}".format( - task["respository"], str(pipe_err) - ), - file=sys.stderr, - ) - return - self.__t_print(pipe_out) - - if "postspawn" in task: - try: - self.__t_print("Running post-hook {}...".format(task["postspawn"])) - subprocess.run(task["postspawn"], shell=True, check=True) - except subprocess.CalledProcessError: - self.__t_print( - "Post-task for {} exited abnormally".format(task["repository"]), - file=sys.stderr, - ) - - if "retention" in task: - self.__t_print("Enforcing {} retention...".format(task["retention"])) - pipe_auth = subprocess.Popen( - ["echo", "{}".format(task["password"])], stdout=subprocess.PIPE - ) - pipe_restic = subprocess.Popen( + with subprocess.Popen( + ["echo", task["password"]], stdout=subprocess.PIPE + ) as pipe_auth: + with subprocess.Popen( [ "restic", "-r", task["repository"], - "forget", - "--prune", - "--keep-within", - task["retention"], - ], + "backup", + task["path"], + "--exclude-caches", + ] + + regexes, stdin=pipe_auth.stdout, stdout=subprocess.PIPE, - ) - pipe_auth.stdout.close() - pipe_out, pipe_err = pipe_restic.communicate() - if pipe_err is not None: + ) as pipe_restic: + pipe_out, pipe_err = pipe_restic.communicate() + if pipe_err is not None: + self.__t_print( + f"Unable to backup {task['respository']} repository: {pipe_err}", + file=sys.stderr, + ) + return + self.__t_print(pipe_out) + + if "postspawn" in task: + try: + self.__t_print(f"Running post-hook {task['postspawn']}...") + subprocess.run(task["postspawn"], shell=True, check=True) + except subprocess.CalledProcessError: self.__t_print( - "Unable to apply retention on {} repository: {}".format( - task["respository"], str(pipe_err) - ), + f"Post-task for {task['repository']} exited abnormally", file=sys.stderr, ) - return - self.__t_print(pipe_out) - self.__t_print("Repository {} updated".format(task["repository"])) + if "retention" in task: + self.__t_print(f"Enforcing {task['retention']} retention...") + with subprocess.Popen( + ["echo", task["password"]], stdout=subprocess.PIPE + ) as pipe_auth: + with subprocess.Popen( + [ + "restic", + "-r", + task["repository"], + "forget", + "--prune", + "--keep-within", + task["retention"], + ], + stdin=pipe_auth.stdout, + stdout=subprocess.PIPE, + ) as pipe_restic: + pipe_out, pipe_err = pipe_restic.communicate() + if pipe_err is not None: + self.__t_print( + f"Unable to apply retention on {task['respository']} repository: " + + pipe_err, + file=sys.stderr, + ) + return + self.__t_print(pipe_out) + + self.__t_print(f"Repository {task['repository']} updated") def run(self): for t in self.tasks: @@ -160,12 +148,12 @@ def run(self): if __name__ == "__main__": os.chdir(os.path.dirname(__file__)) - cfg_path = "config.yml" + CFG_PATH = "config.yml" if len(sys.argv) > 1: - cfg_path = sys.argv[1] + CFG_PATH = sys.argv[1] try: - with open(cfg_path, "r") as yml_stream: + with open(CFG_PATH, "r", encoding="utf-8") as yml_stream: Restup(yaml.safe_load(yml_stream)).run() - except Exception as e: + except OSError as e: print(e, file=sys.stderr) diff --git a/git/committer-changer/runner.sh b/git/committer-changer/runner.sh index 7d4063a..0eb783b 100755 --- a/git/committer-changer/runner.sh +++ b/git/committer-changer/runner.sh @@ -3,8 +3,8 @@ # auxiliary functions function help() { - echo -e "Usage:\n\t$(basename "$0") old@committ.er new_committer_name:new@committ.er" - exit 0 + echo -e "Usage:\n\t$(basename "$0") old@committ.er new_committer_name:new@committ.er" + exit 0 } function rprint() { echo -en "\r\e[0K$*"; } function pprint() { echo -e "\r\e[0K$*"; } @@ -14,19 +14,19 @@ function pprint() { echo -e "\r\e[0K$*"; } # arguments parsing while [[ $# -gt 0 ]]; do - case "$1" in - -h | --help) - help - ;; - *) - if [ -z "${COMMITTER_OLD}" ]; then - COMMITTER_OLD=$1 - else - COMMITTER_NEW=$1 - fi - ;; - esac - shift + case "$1" in + -h | --help) + help + ;; + *) + if [ -z "${COMMITTER_OLD}" ]; then + COMMITTER_OLD=$1 + else + COMMITTER_NEW=$1 + fi + ;; + esac + shift done # arguments validation @@ -35,7 +35,7 @@ COMMITTER_NEW_NAME="$(awk -F':' '{print $1}' <<<"${COMMITTER_NEW}")" COMMITTER_NEW_EMAIL="$(awk -F':' '{print $2}' <<<"${COMMITTER_NEW}")" if [ -z "${COMMITTER_OLD}" ] || [ -z "${COMMITTER_NEW_NAME}" ] || [ -z "${COMMITTER_NEW_EMAIL}" ]; then - help + help fi # effective script diff --git a/git/history-touchup/runner.sh b/git/history-touchup/runner.sh index 6b6d671..c9e423e 100755 --- a/git/history-touchup/runner.sh +++ b/git/history-touchup/runner.sh @@ -3,8 +3,8 @@ # auxiliary functions function help() { - echo -e "Usage:\n\t$(basename "$0")" - exit 0 + echo -e "Usage:\n\t$(basename "$0")" + exit 0 } function rprint() { echo -en "\r\e[0K$*"; } function pprint() { echo -e "\r\e[0K$*"; } @@ -14,12 +14,12 @@ function pprint() { echo -e "\r\e[0K$*"; } # arguments parsing while [[ $# -gt 0 ]]; do - case "$1" in - -h | --help) - help - ;; - esac - shift + case "$1" in + -h | --help) + help + ;; + esac + shift done # arguments validation diff --git a/image/reasize/README.md b/image/reasize/README.md index 9fad45a..657b435 100644 --- a/image/reasize/README.md +++ b/image/reasize/README.md @@ -24,4 +24,4 @@ Finally, to apply resize in both directions: reasize/runner.sh -t /path/to/images 1024x768 ``` -Omitting `-t`/`--target` flag will let the tool use the current working directory. \ No newline at end of file +Omitting `-t`/`--target` flag will let the tool use the current working directory. diff --git a/image/reasize/runner.sh b/image/reasize/runner.sh index 31da449..4cb1f4e 100755 --- a/image/reasize/runner.sh +++ b/image/reasize/runner.sh @@ -3,8 +3,8 @@ # auxiliary functions function help() { - echo -e "Usage:\n\t$(basename "$0") [-t ]" - exit 0 + echo -e "Usage:\n\t$(basename "$0") [-t ]" + exit 0 } function rprint() { echo -en "\r\e[0K$*"; } function pprint() { echo -e "\r\e[0K$*"; } @@ -14,73 +14,73 @@ function pprint() { echo -e "\r\e[0K$*"; } # arguments parsing while [[ $# -gt 0 ]]; do - case "$1" in - -h | --help) - help - ;; - -t | --target) - TARGET="$2" - shift - ;; - *) - SIZE=$1 - ;; - esac - shift + case "$1" in + -h | --help) + help + ;; + -t | --target) + TARGET="$2" + shift + ;; + *) + SIZE=$1 + ;; + esac + shift done # arguments validation if [ -z "${TARGET}" ]; then - TARGET="$(pwd)" + TARGET="$(pwd)" fi if [ -z "${SIZE}" ]; then - help + help fi SIZE_W="$(awk -F'x' '{print $1}' <<<"${SIZE,,}" | xargs)" SIZE_H="$(awk -F'x' '{print $2}' <<<"${SIZE,,}" | xargs)" if [ -z "${SIZE_W}" ] && [ -z "${SIZE_H}" ]; then - echo "At least a resolution argument must be given" - exit 1 + echo "At least a resolution argument must be given" + exit 1 fi # effective script find "${TARGET}" -type f -exec file {} \; | grep -o -P '^.+: \w+ image' | awk -F':' '{print $1}' | while read -r fname; do - pname="${fname//${TARGET}\//}" - rprint "Checking ${pname}" - - # get image data - - if ! img_data="$(exiftool "${fname}")"; then - continue - fi - - # get image resolution - img_res_w="$(awk -F': ' '/^Image Width/ {print $2}' <<<"${img_data}" | xargs)" - img_res_h="$(awk -F': ' '/^Image Height/ {print $2}' <<<"${img_data}" | xargs)" - if [ -z "${img_res_w}" ] || [ -z "${img_res_h}" ]; then - continue - fi - - # calculate resize - img_res="" - if [ -n "${SIZE_W}" ] && [ "${img_res_w}" -gt "${SIZE_W}" ]; then - img_res="${SIZE_W}x" - fi - if [ -n "${SIZE_H}" ] && [ -z "${img_res}" ] && [ "${img_res_h}" -gt "${SIZE_H}" ]; then - img_res="x${SIZE_H}" - fi - - # process resize - if [ -n "${img_res}" ]; then - pprint "Resizing ${pname} to ${img_res} from ${img_res_w}x${img_res_h} ($(du -sh "${fname}" | awk '{print $1}'))" - mogrify -resize "${img_res}" "${fname}" - fi + pname="${fname//${TARGET}\//}" + rprint "Checking ${pname}" + + # get image data + + if ! img_data="$(exiftool "${fname}")"; then + continue + fi + + # get image resolution + img_res_w="$(awk -F': ' '/^Image Width/ {print $2}' <<<"${img_data}" | xargs)" + img_res_h="$(awk -F': ' '/^Image Height/ {print $2}' <<<"${img_data}" | xargs)" + if [ -z "${img_res_w}" ] || [ -z "${img_res_h}" ]; then + continue + fi + + # calculate resize + img_res="" + if [ -n "${SIZE_W}" ] && [ "${img_res_w}" -gt "${SIZE_W}" ]; then + img_res="${SIZE_W}x" + fi + if [ -n "${SIZE_H}" ] && [ -z "${img_res}" ] && [ "${img_res_h}" -gt "${SIZE_H}" ]; then + img_res="x${SIZE_H}" + fi + + # process resize + if [ -n "${img_res}" ]; then + pprint "Resizing ${pname} to ${img_res} from ${img_res_w}x${img_res_h} ($(du -sh "${fname}" | awk '{print $1}'))" + mogrify -resize "${img_res}" "${fname}" + fi done diff --git a/monitoring/scrubber/runner.sh b/monitoring/scrubber/runner.sh index 3ac47c9..194f359 100755 --- a/monitoring/scrubber/runner.sh +++ b/monitoring/scrubber/runner.sh @@ -3,8 +3,8 @@ # auxiliary functions function help() { - echo -e "Usage:\n\t$(basename "$0") [devices...] -c " - exit 0 + echo -e "Usage:\n\t$(basename "$0") [devices...] -c " + exit 0 } # shell setup @@ -14,31 +14,31 @@ set +e # arguments parsing while [[ $# -gt 0 ]]; do - case "$1" in - -h | --help) - help - ;; - -c | --contact) - CONTACT="$2" - shift - ;; - *) - DEVICES="${DEVICES} $1" - ;; - esac - shift + case "$1" in + -h | --help) + help + ;; + -c | --contact) + CONTACT="$2" + shift + ;; + *) + DEVICES="${DEVICES} $1" + ;; + esac + shift done # arguments validation if [ -z "${DEVICES}" ]; then - echo "At least one disk path must be given" - help + echo "At least one disk path must be given" + help fi if [ -z "${CONTACT}" ]; then - echo "At least one contact email must be given" - help + echo "At least one contact email must be given" + help fi CONTACT_DOMAIN="$(awk -F'@' '{print $2}' <<<"${CONTACT}")" @@ -46,17 +46,17 @@ CONTACT_DOMAIN="$(awk -F'@' '{print $2}' <<<"${CONTACT}")" disk_scrub_log="/tmp/scrub-$$.log" for disk in ${DEVICES}; do - cat <${disk_scrub_log} + cat <${disk_scrub_log} From: "Scrubber" To: <${CONTACT}> Subject: BTRFS scrub EOF - btrfs scrub start -Bd "${disk}" >>"${disk_scrub_log}" - curl -q --ssl-reqd --insecure \ - --url "${SMTP_URI}" \ - --user "${SMTP_USER}:${SMTP_PASS}" \ - --mail-from "scrubber@${CONTACT_DOMAIN}" \ - --mail-rcpt "${CONTACT}" \ - --upload-file "${disk_scrub_log}" + btrfs scrub start -Bd "${disk}" >>"${disk_scrub_log}" + curl -q --ssl-reqd --insecure \ + --url "${SMTP_URI}" \ + --user "${SMTP_USER}:${SMTP_PASS}" \ + --mail-from "scrubber@${CONTACT_DOMAIN}" \ + --mail-rcpt "${CONTACT}" \ + --upload-file "${disk_scrub_log}" done diff --git a/multimedia/apto/README.md b/multimedia/apto/README.md index 4da5383..bc34a44 100644 --- a/multimedia/apto/README.md +++ b/multimedia/apto/README.md @@ -11,16 +11,19 @@ apto/runner.sh path/to/files ``` With `-e` (or `--exif`) flag, by default exif metadata will be used as source of truth: + ```bash apto/runner.sh --exif path/to/files ``` Conversely, with `-f` (or `--fs`) flag, FS timestamps will be used: + ```bash apto/runner.sh --fs path/to/files ``` In some cases, `-s` (or `--smart`) flag might be useful as well, for letting the tool smartly decide: + ```bash apto/runner.sh --smart path/to/files ``` diff --git a/multimedia/apto/runner.sh b/multimedia/apto/runner.sh index cd668ec..487cdda 100755 --- a/multimedia/apto/runner.sh +++ b/multimedia/apto/runner.sh @@ -3,31 +3,31 @@ # auxiliary functions function help() { - echo -e "Usage:\n\t$(basename "$0") [-e/--exif|-f/--fs|-n/--name|-s/--smart]" + echo -e "Usage:\n\t$(basename "$0") [-e/--exif|-f/--fs|-n/--name|-s/--smart]" } function install_media_file() { - # check args - src="$(sed 's|^./||' <<< "$1")" - [ -z "${src}" ] && return 1 - dst="$(sed 's|^./||' <<< "$2")" - [ -z "${dst}" ] && return 1 - # don't move if we already have a file in the right position - [ "${src}" == "${dst}" ] && return 0 - - # calculate shifts - dst_dir="$(dirname "${dst}")" - dst_base="$(basename "${dst}")" - while [ -e "${dst_dir}/${dst_base}" ]; do - echo "Shifting ${dst_base}" - secs="$(expr "${dst_base:13:2}" + 1)" - dst_base="${dst_base:0:13}$(printf %02s "${secs}").${dst_base##*.}" - # don't if we already have a file in the right position - [ "${src}" == "${dst_dir}/${dst_base}" ] && return 0 - done - - # install file - mv -vn "${src}" "${dst_dir}/${dst_base}" + # check args + src="${1//\.\//}" + [ -z "${src}" ] && return 1 + dst="${2//\.\//}" + [ -z "${dst}" ] && return 1 + # don't move if we already have a file in the right position + [ "${src}" == "${dst}" ] && return 0 + + # calculate shifts + dst_dir="$(dirname "${dst}")" + dst_base="$(basename "${dst}")" + while [ -e "${dst_dir}/${dst_base}" ]; do + echo "Shifting ${dst_base}" + secs="$((${dst_base:13:2} + 1))" + dst_base="${dst_base:0:13}$(printf %02d "${secs}").${dst_base##*.}" + # don't if we already have a file in the right position + [ "${src}" == "${dst_dir}/${dst_base}" ] && return 0 + done + + # install file + mv -vn "${src}" "${dst_dir}/${dst_base}" } # shell setup @@ -37,151 +37,153 @@ set -euo pipefail # arguments parsing MODE=interactive -TARGET=. +TARGETS=() EXTS=( - 3gp - avi - heic - jpeg - jpg - m4v - mov - mp4 - nef - png - webp - wmv + 3gp + avi + heic + jpeg + jpg + m4v + mov + mp4 + nef + png + webp + wmv ) -UNKNOWN_DATE="$(date +%s)" +UNKNOWN_DATE="$(date +'%Y:%m:%d %H:%M:%S')" _modes=0 while [[ $# -gt 0 ]]; do - case "$1" in - -h | --help) - help - exit 0 - ;; - -e | --exif) - MODE=exif - _modes=$(expr $_modes + 1) - ;; - -f | --fs) - MODE=fs - _modes=$(expr $_modes + 1) - ;; - -n | --name) - MODE=name - _modes=$(expr $_modes + 1) - ;; - -s | --smart) - MODE=smart - _modes=$(expr $_modes + 1) - ;; - *) - [ "${TARGET}" == "." ] && TARGET="" - TARGET="${TARGET} $1" - ;; - esac - shift || echo -n + case "$1" in + -h | --help) + help + exit 0 + ;; + -e | --exif) + MODE=exif + _modes="$((_modes + 1))" + ;; + -f | --fs) + MODE=fs + _modes="$((_modes + 1))" + ;; + -n | --name) + MODE=name + _modes="$((_modes + 1))" + ;; + -s | --smart) + MODE=smart + _modes="$((_modes + 1))" + ;; + *) + TARGETS+=("$1") + ;; + esac + shift || echo -n done # arguments validation -if [ ${_modes} -gt 1 ]; then - echo "--exif, --fs, --name and --smart flags are mutually exclusive" - exit 1 +if [ "${_modes}" -gt 1 ]; then + echo "--exif, --fs, --name and --smart flags are mutually exclusive" + exit 1 fi # effective script -EXTS="${EXTS[@]}" -EXTS="${EXTS// /|}" +exts="${EXTS[*]}" +exts="${exts// /|}" while read -r fname <&3; do - dirname="$(dirname "${fname}")" - basename="$(basename "${fname}")" - echo "Processing ${basename}..." - - # parse timestamps - exif_timestamps="$(exiftool -time:all "${fname}")" - exif_create_date="$(awk -F': ' '/^Create Date /{print $2}' <<< "${exif_timestamps}" | grep -v "0000:00:00" | awk -F'+' 'NR==1 {print $1}' || echo "${UNKNOWN_DATE}")" - fs_modification_time="$(awk -F': ' '/^File Modification Date\/Time /{print $2}' <<< "${exif_timestamps}" | awk -F'+' 'NR==1 {print $1}')" - name_date="${basename//[!0-9]/}" - name_date="${name_date:0:4}:${name_date:4:2}:${name_date:6:2} ${name_date:8:2}:${name_date:10:2}:${name_date:12:2}" - [ -z "${name_date}" ] && name_date="${UNKNOWN_DATE}" - - if [ "${MODE}" = "smart" ]; then - # in smart mode, let's sort it by picking the older timestamp - oldest="${name_date}" - strategy="name" - if [ "${fs_modification_time//[!0-9]/}" -lt "${oldest}" ]; then - oldest="${fs_modification_time//[!0-9]/}" - strategy="fs" - fi - if [ "${exif_create_date//[!0-9]/}" -lt "${oldest}" ]; then - oldest="${exif_create_date//[!0-9]/}" - strategy="exif" - fi - if [ "${oldest}" = "${UNKNOWN_DATE}" ]; then - echo "Can't infer best timestamp to use for ${basename}: exiting" - exit 1 - fi - elif [ "${MODE}" = "interactive" ]; then - # in interactive mode, let's ask the user - echo -n "Choose a date for ${basename}: [E] ${exif_create_date} or [f] ${fs_modification_time} or [n] ${name_date} or [i] input? " - read -n1 choice - echo - case "${choice}" in - [fF]) - strategy=fs - ;; - [nN]) - strategy=name - ;; - [iI]) - strategy=input - echo -n "Input a date: " - read t - t="${t//[!0-9]/}" - input_timestamp="${t:0:4}:${t:4:2}:${t:6:2} ${t:8:2}:${t:10:2}:${t:12:2}" - ;; - *) - strategy=exif - ;; - esac - else - strategy="${MODE}" - fi - - # choose the timestamp - if [ "${strategy}" = "exif" ]; then - final_timestamp="${exif_create_date}" - elif [ "${strategy}" = "fs" ]; then - final_timestamp="${fs_modification_time}" - elif [ "${strategy}" = "name" ]; then - final_timestamp="${name_date}" - else # input - final_timestamp="${input_timestamp}" - fi - - # compute timestamp formats - final_exif_timestamp="${final_timestamp}" - final_fs_timestamp="${final_timestamp//[!0-9]/}" - final_fs_timestamp="${final_fs_timestamp:0:12}.${final_fs_timestamp:12:2}" - final_ext="$(echo "${fname##*.}" | tr '[:upper:]' '[:lower:]' | sed 's/jpeg/jpg/')" - final_fname="${final_timestamp//:/}.${final_ext}" - final_fname="${final_fname/ /-}" - - # perform the changes - exiftool -overwrite_original -wm w \ - -time:all="${final_exif_timestamp}" "${fname}" && \ - exiftool -overwrite_original \ - -CreateDate="${final_exif_timestamp}" \ - -DateTimeOriginal="${final_exif_timestamp}" \ - -MediaCreateDate="${final_exif_timestamp}" \ - -DateTime="${final_exif_timestamp}" "${fname}" && \ - touch -c -a -m -t "${final_fs_timestamp}" "${fname}" && \ - chmod 0644 "${fname}" && \ - install_media_file "${fname}" "${dirname}/${final_fname}" + dirname="$(dirname "${fname}")" + basename="$(basename "${fname}")" + echo "Processing ${basename}..." + + # parse timestamps + exif_timestamps="$(exiftool -time:all "${fname}")" + exif_create_date="$(awk -F': ' '/^Create Date /{print $2}' <<<"${exif_timestamps}" | grep -v "0000:00:00" | awk -F'+' 'NR==1 {print $1}' || echo "${UNKNOWN_DATE}")" + [ "${#exif_create_date}" = 16 ] && exif_create_date="${exif_create_date}:00" + fs_modification_time="$(awk -F': ' '/^File Modification Date\/Time /{print $2}' <<<"${exif_timestamps}" | awk -F'+' 'NR==1 {print $1}')" + name_date="${basename%.*}" + name_date="${name_date//[!0-9]/}" + name_date="${name_date:0:4}:${name_date:4:2}:${name_date:6:2} ${name_date:8:2}:${name_date:10:2}:${name_date:12:2}" + [[ "${name_date}" =~ ^[0-9]{4}:[0-9]{2}:[0-9]{2}\ [0-2]{1}[0-9]{1}:[0-5]{1}[0-9]{1}:[0-5]{1}[0-9]{1}$ ]] || name_date="${UNKNOWN_DATE}" + + if [ "${MODE}" = "smart" ]; then + # in smart mode, let's sort it by picking the older timestamp + oldest="${name_date//[!0-9]/}" + strategy="name" + if [ "${fs_modification_time//[!0-9]/}" -lt "${oldest}" ]; then + oldest="${fs_modification_time//[!0-9]/}" + strategy="fs" + fi + if [ "${exif_create_date//[!0-9]/}" -lt "${oldest}" ]; then + oldest="${exif_create_date//[!0-9]/}" + strategy="exif" + fi + if [ "${oldest}" = "${UNKNOWN_DATE//[!0-9]/}" ]; then + echo "Can't infer best timestamp to use for ${basename}: exiting" + exit 1 + fi + elif [ "${MODE}" = "interactive" ]; then + # in interactive mode, let's ask the user + echo -n "Choose a date for ${basename}: [E] ${exif_create_date} or [f] ${fs_modification_time} or [n] ${name_date} or [i] input? " + read -rn1 choice + echo + case "${choice}" in + [fF]) + strategy=fs + ;; + [nN]) + strategy=name + ;; + [iI]) + strategy=input + echo -n "Input a date: " + read -r t + t="${t//[!0-9]/}" + input_timestamp="${t:0:4}:${t:4:2}:${t:6:2} ${t:8:2}:${t:10:2}:${t:12:2}" + ;; + *) + strategy=exif + ;; + esac + else + strategy="${MODE}" + fi + + # choose the timestamp + if [ "${strategy}" = "exif" ]; then + final_timestamp="${exif_create_date}" + elif [ "${strategy}" = "fs" ]; then + final_timestamp="${fs_modification_time}" + elif [ "${strategy}" = "name" ]; then + final_timestamp="${name_date}" + else # input + final_timestamp="${input_timestamp}" + fi + echo "Chosen date: ${final_timestamp}" + + # compute timestamp formats + final_exif_timestamp="${final_timestamp}" + final_fs_timestamp="${final_timestamp//[!0-9]/}" + final_fs_timestamp="${final_fs_timestamp:0:12}.${final_fs_timestamp:12:2}" + final_ext="$(echo "${fname##*.}" | tr '[:upper:]' '[:lower:]' | sed 's/jpeg/jpg/')" + final_fname="${final_timestamp//:/}.${final_ext}" + final_fname="${final_fname/ /-}" + + # perform the changes + exiftool -overwrite_original -wm w \ + -time:all="${final_exif_timestamp}" "${fname}" && + exiftool -overwrite_original \ + -CreateDate="${final_exif_timestamp}" \ + -DateTimeOriginal="${final_exif_timestamp}" \ + -MediaCreateDate="${final_exif_timestamp}" \ + -DateTime="${final_exif_timestamp}" "${fname}" && + touch -c -a -m -t "${final_fs_timestamp}" "${fname}" && + chmod 0644 "${fname}" && + install_media_file "${fname}" "${dirname}/${final_fname}" done 3< <( - find ${TARGET} -type f -not -name '.*' | grep -iE ".*.($EXTS)$" + find "${TARGETS[@]}" -type f -not -name '.*' | grep -iE ".*.(${exts})$" ) diff --git a/multimedia/blueboost/runner.sh b/multimedia/blueboost/runner.sh index 66d00c4..8fa0d83 100755 --- a/multimedia/blueboost/runner.sh +++ b/multimedia/blueboost/runner.sh @@ -1,8 +1,8 @@ #!/bin/bash -dbus-send --system --print-reply --dest=org.bluez / org.freedesktop.DBus.ObjectManager.GetManagedObjects \ - | awk -F'"' '/\/(sep|fd)/ {print $2}' \ - | while read -r addr; do - dbus-send --print-reply --system --dest=org.bluez "${addr}" \ - org.freedesktop.DBus.Properties.Set string:org.bluez.MediaTransport1 string:Volume variant:uint16:127 -done \ No newline at end of file +dbus-send --system --print-reply --dest=org.bluez / org.freedesktop.DBus.ObjectManager.GetManagedObjects | + awk -F'"' '/\/(sep|fd)/ {print $2}' | + while read -r addr; do + dbus-send --print-reply --system --dest=org.bluez "${addr}" \ + org.freedesktop.DBus.Properties.Set string:org.bluez.MediaTransport1 string:Volume variant:uint16:127 + done diff --git a/multimedia/consentio/runner.sh b/multimedia/consentio/runner.sh index b423c4f..9853acc 100755 --- a/multimedia/consentio/runner.sh +++ b/multimedia/consentio/runner.sh @@ -3,7 +3,7 @@ # auxiliary functions function help() { - echo -e "Usage:\n\t$(basename "$0") " + echo -e "Usage:\n\t$(basename "$0") " } # shell setup @@ -14,56 +14,56 @@ set -euo pipefail TARGET=. EXTS=( - 3gp - avi - heic - jpeg - jpg - m4v - mov - mp4 - nef - png - webp - wmv + 3gp + avi + heic + jpeg + jpg + m4v + mov + mp4 + nef + png + webp + wmv ) while [[ $# -gt 0 ]]; do - case "$1" in - -h | --help) - help - exit 0 - ;; - *) - TARGET="$1" - ;; - esac - shift || echo -n + case "$1" in + -h | --help) + help + exit 0 + ;; + *) + TARGET="$1" + ;; + esac + shift || echo -n done # effective script -EXTS="${EXTS[@]}" -EXTS="${EXTS// /|}" -find "${TARGET}" -type f -not -name '.*' | grep -iE ".*.($EXTS)$" | while read -r fname; do - # check folder settings - [ -f "$(dirname "${fname}")/.uncompliant" ] && continue +exts="${EXTS[*]}" +exts="${exts// /|}" +find "${TARGET}" -type f -not -name '.*' | grep -iE ".*.(${exts})$" | while read -r fname; do + # check folder settings + [ -f "$(dirname "${fname}")/.uncompliant" ] && continue - # check naming convention YYYYMMDD-hhmmss - stem="$(basename "${fname%.*}")" - [[ "${stem}" =~ ^[0-9]{8}\-[0-9]{6}$ ]] || echo "fname=${fname} stem=${stem}" + # check naming convention YYYYMMDD-hhmmss + stem="$(basename "${fname%.*}")" + [[ "${stem}" =~ ^[0-9]{8}\-[0-9]{6}$ ]] || echo "fname=${fname} stem=${stem}" - # check extension lowercase/reduced (e.g. jpeg to jpg) - ext="$(echo ${fname##*.} | tr '[:upper:]' '[:lower:]' | sed 's/jpeg/jpg/')" - [[ "${ext}" == "${fname##*.}" ]] || echo "fname=${fname} ext=${ext}" + # check extension lowercase/reduced (e.g. jpeg to jpg) + ext="$(echo "${fname##*.}" | tr '[:upper:]' '[:lower:]' | sed 's/jpeg/jpg/')" + [[ "${ext}" == "${fname##*.}" ]] || echo "fname=${fname} ext=${ext}" - # check permissions - perm="$(stat -c %a "${fname}")" - [[ "${perm}" == "644" ]] || echo "fname=${fname} perm=${perm}" + # check permissions + perm="$(stat -c %a "${fname}")" + [[ "${perm}" == "644" ]] || echo "fname=${fname} perm=${perm}" - # check timestamps - exif_timestamps="$(exiftool -time:all "${fname}")" - exif_create_date="$(awk -F': ' '/^Create Date /{print $2}' <<< "${exif_timestamps}" | awk 'NR==1 {print $1}')" - fs_modification_time="$(awk -F': ' '/^File Modification Date\/Time /{print $2}' <<< "${exif_timestamps}" | awk 'NR==1 {print $1}')" - [[ "${fs_modification_time}" == "${exif_create_date}" ]] || echo "fname=${fname} fst=${fs_modification_time} et=${exif_create_date}" + # check timestamps + exif_timestamps="$(exiftool -time:all "${fname}")" + exif_create_date="$(awk -F': ' '/^Create Date /{print $2}' <<<"${exif_timestamps}" | awk 'NR==1 {print $1}')" + fs_modification_time="$(awk -F': ' '/^File Modification Date\/Time /{print $2}' <<<"${exif_timestamps}" | awk 'NR==1 {print $1}')" + [[ "${fs_modification_time}" == "${exif_create_date}" ]] || echo "fname=${fname} fst=${fs_modification_time} et=${exif_create_date}" done diff --git a/multimedia/inflarics/runner.go b/multimedia/inflarics/runner.go index 8f0cb84..c02fbe1 100755 --- a/multimedia/inflarics/runner.go +++ b/multimedia/inflarics/runner.go @@ -21,37 +21,43 @@ func main() { Args: cobra.MinimumNArgs(1), RunE: func(cmd *cobra.Command, args []string) error { for _, path := range args { - tag, err := id3.Open(path, id3v2.Options{Parse: true}) - if err != nil { - return err + tag, tagErr := id3.Open(path, id3v2.Options{Parse: true}) + if tagErr != nil { + return tagErr } defer tag.Close() - artist, _ := cmd.Flags().GetString("artist") - artist = util.Fallback(artist, tag.Artist()) + artist, artistErr := cmd.Flags().GetString("artist") + if artistErr != nil { + artist = tag.Artist() + } if len(artist) == 0 { return errors.New("artist name is mandatory") } - title, _ := cmd.Flags().GetString("title") - title = util.Fallback(title, tag.Title()) + title, titleErr := cmd.Flags().GetString("title") + if titleErr != nil { + artist = tag.Title() + } if len(artist) == 0 { return errors.New("track title is mandatory") } var ( - url, _ = cmd.Flags().GetString("url") - uslt string + url, urlErr = cmd.Flags().GetString("url") + uslt string + lyricsErr error ) - if len(url) > 0 { - log.Printf("Downloading lyrics from %s...\n", url) - uslt, err = lyrics.Get(url) - } else { + + if urlErr != nil || len(url) == 0 { log.Printf("Searching lyrics for %s by %s...\n", title, artist) - uslt, err = lyrics.Search(&entity.Track{ID: util.Fallback(tag.SpotifyID(), fakeID(artist, title)), Title: title, Artists: []string{artist}}) + uslt, lyricsErr = lyrics.Search(&entity.Track{ID: util.Fallback(tag.SpotifyID(), fakeID(artist, title)), Title: title, Artists: []string{artist}}) + } else { + log.Printf("Downloading lyrics from %s...\n", url) + uslt, lyricsErr = lyrics.Get(url) } - if err != nil { - return err + if lyricsErr != nil { + return lyricsErr } if len(uslt) == 0 { @@ -71,7 +77,9 @@ func main() { cmd.Flags().StringP("artist", "a", "", "Artist name") cmd.Flags().StringP("title", "t", "", "Track title") cmd.Flags().StringP("url", "u", "", "Lyrics URL") - cmd.Execute() + if err := cmd.Execute(); err != nil { + log.Fatal(err) + } } func fakeID(artist, title string) string { diff --git a/multimedia/kindle/runner.sh b/multimedia/kindle/runner.sh index fde4a22..8c3e2b9 100755 --- a/multimedia/kindle/runner.sh +++ b/multimedia/kindle/runner.sh @@ -6,12 +6,12 @@ set -o pipefail path="$1" path_base="$(basename "${path}")" path_tmp="/tmp/.$(echo "${path_base}" | md5sum | awk '{print $1}').$$" -title="$(awk -F' - ' '{print $1}' <<< "${path_base}" | sed 's/.pdf$//g')" -author="$(awk -F' - ' '{print $2}' <<< "${path_base}" | sed 's/.pdf$//g')" +title="$(awk -F' - ' '{print $1}' <<<"${path_base}" | sed 's/.pdf$//g')" +author="$(awk -F' - ' '{print $2}' <<<"${path_base}" | sed 's/.pdf$//g')" gs -sDEVICE=pdfwrite -dCompatibilityLevel=1.4 \ -dPDFSETTINGS=/screen -dNOPAUSE -dQUIET \ - -dDetectDuplicateImages -dCompressFonts=true -r150 \ + -dDetectDuplicateImages -dCompressFonts=true -r150 \ -dBATCH -sOutputFile="${path_tmp}" "${path}" exiftool -Title="${title}" \ -Author="${author}" \ diff --git a/multimedia/pluffer/runner.go b/multimedia/pluffer/runner.go index 8f9d3c4..435e6a6 100755 --- a/multimedia/pluffer/runner.go +++ b/multimedia/pluffer/runner.go @@ -4,17 +4,17 @@ import ( "context" "flag" "log" - "math/rand" - "time" + "math/rand/v2" spotitube "github.com/streambinder/spotitube/spotify" spotify "github.com/zmb3/spotify/v2" ) -var argTimes int +var ( + argTimes int +) func init() { - rand.Seed(time.Now().UnixNano()) flag.IntVar(&argTimes, "t", 1, "How many shufflings to do") flag.Parse() } diff --git a/multimedia/soundhole/runner.sh b/multimedia/soundhole/runner.sh index 382f99e..ecf22b2 100755 --- a/multimedia/soundhole/runner.sh +++ b/multimedia/soundhole/runner.sh @@ -3,8 +3,8 @@ # auxiliary functions function help() { - echo -e "Usage:\n\t$(basename "$0") " - exit 0 + echo -e "Usage:\n\t$(basename "$0") " + exit 0 } function rprint() { echo -en "\r\e[0K$*"; } function pprint() { echo -e "\r\e[0K$*"; } @@ -14,92 +14,92 @@ function pprint() { echo -e "\r\e[0K$*"; } sound_card="quack_sink" function format_duration() { - ((hours = ${1} / 3600)) - ((minutes = (${1} % 3600) / 60)) - ((seconds = ${1} % 60)) - printf "%02d:%02d:%02d\n" "${hours}" "${minutes}" "${seconds}" + ((hours = ${1} / 3600)) + ((minutes = (${1} % 3600) / 60)) + ((seconds = ${1} % 60)) + printf "%02d:%02d:%02d\n" "${hours}" "${minutes}" "${seconds}" } # arguments parsing while [[ $# -gt 0 ]]; do - case "$1" in - -h | --help) - help - ;; - *) - TARGET="$1" - shift - ;; - esac - shift + case "$1" in + -h | --help) + help + ;; + *) + TARGET="$1" + shift + ;; + esac + shift done # arguments validation if [ -z "${TARGET}" ]; then - help + help fi # effective script trap on_stop SIGINT function on_stop() { - rprint "Timestamping..." - date_stop="$(date +%s)" - - rprint "Removing quack card(s)..." - grep -e "index" -e "sink_name=" <<<"$(pacmd list-modules)" | - grep -B1 "${sound_card}" | - head -1 | - grep -o -E "[0-9]+" | - while read -r card; do - rprint "Removing card ${card}..." - pacmd unload-module "${card}" - done - - if [ "$((date_stop - date_start))" -lt "1" ]; then - pprint "Record is too short." - exit 1 - fi - - rprint "Collecting waveform data..." - waveform="$(ffprobe -f lavfi -i amovie="${TARGET}",astats=metadata=1:reset=1 \ - -show_entries frame=pkt_pts_time:frame_tags=lavfi.astats.Overall.RMS_level,lavfi.astats.1.RMS_level,lavfi.astats.2.RMS_level \ - -of csv=p=0 2>/dev/null | - grep -E "^($(seq $((date_stop - date_start)) | xargs | sed 's/\s/|/g'))\.")" - - rprint "Trimming duration coordinates..." - trim_start="$(grep -v '\-inf' <<<"${waveform}" | - head -1 | awk -F'.' '{print $1}')" - trim_stop="$(grep -v '\-inf' <<<"${waveform}" | - tail -1 | awk -F'.' '{print $1}')" - - rprint "Trimming output file..." - ffmpeg -i "${TARGET}" -ss "$(format_duration "${trim_start}")" -to "$(format_duration "${trim_stop}")" -c copy ."${TARGET}" >/dev/null 2>&1 && - mv -f ."${TARGET}" "${TARGET}" - - pprint "Recorded at ${TARGET} ($(format_duration $((trim_stop - trim_start))))." + rprint "Timestamping..." + date_stop="$(date +%s)" + + rprint "Removing quack card(s)..." + grep -e "index" -e "sink_name=" <<<"$(pacmd list-modules)" | + grep -B1 "${sound_card}" | + head -1 | + grep -o -E "[0-9]+" | + while read -r card; do + rprint "Removing card ${card}..." + pacmd unload-module "${card}" + done + + if [ "$((date_stop - date_start))" -lt "1" ]; then + pprint "Record is too short." + exit 1 + fi + + rprint "Collecting waveform data..." + waveform="$(ffprobe -f lavfi -i amovie="${TARGET}",astats=metadata=1:reset=1 \ + -show_entries frame=pkt_pts_time:frame_tags=lavfi.astats.Overall.RMS_level,lavfi.astats.1.RMS_level,lavfi.astats.2.RMS_level \ + -of csv=p=0 2>/dev/null | + grep -E "^($(seq $((date_stop - date_start)) | xargs | sed 's/\s/|/g'))\.")" + + rprint "Trimming duration coordinates..." + trim_start="$(grep -v '\-inf' <<<"${waveform}" | + head -1 | awk -F'.' '{print $1}')" + trim_stop="$(grep -v '\-inf' <<<"${waveform}" | + tail -1 | awk -F'.' '{print $1}')" + + rprint "Trimming output file..." + ffmpeg -i "${TARGET}" -ss "$(format_duration "${trim_start}")" -to "$(format_duration "${trim_stop}")" -c copy ."${TARGET}" >/dev/null 2>&1 && + mv -f ."${TARGET}" "${TARGET}" + + pprint "Recorded at ${TARGET} ($(format_duration $((trim_stop - trim_start))))." } rprint "Generating quack card..." pacmd load-module module-null-sink sink_name="${sound_card}" quack_card="$(grep -e "index:" -e "name:" <<<"$(pacmd list-sinks)" | - grep -B1 "${sound_card}" | - head -1 | - grep -o -E "[0-9]+")" + grep -B1 "${sound_card}" | + head -1 | + grep -o -E "[0-9]+")" rprint "Setting quack card ${quack_card} as default..." pacmd set-default-sink "${quack_card}" rprint "Redirecting inputs to quack card..." pacmd list-sink-inputs | - grep -e index: | - grep -o -E "[0-9]+" | - while read -r flow; do - rprint "Redirecting input ${flow} to quack card..." - pacmd move-sink-input "${flow}" "${quack_card}" - done + grep -e index: | + grep -o -E "[0-9]+" | + while read -r flow; do + rprint "Redirecting input ${flow} to quack card..." + pacmd move-sink-input "${flow}" "${quack_card}" + done rprint "Timestamping..." date_start="$(date +%s)" diff --git a/multimedia/volnorm/runner.go b/multimedia/volnorm/runner.go index a1ed787..4d1ca89 100755 --- a/multimedia/volnorm/runner.go +++ b/multimedia/volnorm/runner.go @@ -13,7 +13,7 @@ func main() { Use: "volnorm", Short: "Reset audio file max volume", Args: cobra.MinimumNArgs(1), - RunE: func(cmd *cobra.Command, args []string) error { + RunE: func(_ *cobra.Command, args []string) error { for _, path := range args { log.Printf("Parsing max_volume for %s...\n", path) volumeDelta, err := util.FFmpeg().VolumeDetect(path) @@ -34,5 +34,7 @@ func main() { return nil }, } - cmd.Execute() + if err := cmd.Execute(); err != nil { + log.Fatal(err) + } } diff --git a/network/ddaddy/runner.sh b/network/ddaddy/runner.sh index 6f032b6..953e107 100755 --- a/network/ddaddy/runner.sh +++ b/network/ddaddy/runner.sh @@ -3,8 +3,8 @@ # auxiliary functions function help() { - echo -e "Usage:\n\t$(basename "$0") [-t seconds] " - exit 0 + echo -e "Usage:\n\t$(basename "$0") [-t seconds] " + exit 0 } # shell setup @@ -14,42 +14,42 @@ set +e # arguments parsing while [[ $# -gt 0 ]]; do - case "$1" in - -h | --help) - help - ;; - -t | --timeout) - TIMEOUT="$2" - shift - ;; - *) - RECORD="$1" - ;; - esac - shift + case "$1" in + -h | --help) + help + ;; + -t | --timeout) + TIMEOUT="$2" + shift + ;; + *) + RECORD="$1" + ;; + esac + shift done # arguments validation if [ -z "${TIMEOUT}" ]; then - TIMEOUT=150 + TIMEOUT=150 fi if [ -z "${RECORD}" ]; then - echo "At least one record name must be given" - help + echo "At least one record name must be given" + help fi DOMAIN="$(awk -F'.' '{print $(NF-1)"."$NF}' <<<"${RECORD}")" if [ -z "${DOMAIN}" ]; then - echo "Unable to reconstruct domain" - exit 1 + echo "Unable to reconstruct domain" + exit 1 fi RECORD="${RECORD/.${DOMAIN}/}" if [ -z "${API_KEY}" ] || [ -z "${API_SECRET}" ]; then - echo "Either API key or secret not exported" - exit 1 + echo "Either API key or secret not exported" + exit 1 fi # effective script @@ -57,17 +57,17 @@ fi echo "Getting latest public IP..." public_ip="$(curl -s ifconfig.me)" if [ -z "${public_ip}" ]; then - echo "Unable to get latest public IP" - exit 1 + echo "Unable to get latest public IP" + exit 1 fi echo "Setting ${RECORD} A record to ${public_ip}..." if curl -f -s -X PUT "https://api.godaddy.com/v1/domains/${DOMAIN}/records/A/${RECORD}" \ - -H "Accept: application/json" \ - -H "Content-Type: application/json" \ - -H "Authorization: sso-key ${API_KEY}:${API_SECRET}" \ - --data '[{"data":"'"${public_ip}"'","name":"'"${RECORD}"'","ttl":3600,"type":"A"}]'; then - echo "Record A for ${RECORD} succesfully updated to ${public_ip}" + -H "Accept: application/json" \ + -H "Content-Type: application/json" \ + -H "Authorization: sso-key ${API_KEY}:${API_SECRET}" \ + --data '[{"data":"'"${public_ip}"'","name":"'"${RECORD}"'","ttl":3600,"type":"A"}]'; then + echo "Record A for ${RECORD} succesfully updated to ${public_ip}" else - echo "Unable to update record A for ${RECORD} to ${public_ip}" + echo "Unable to update record A for ${RECORD} to ${public_ip}" fi diff --git a/social/instaget/README.md b/social/instaget/README.md index 7d08603..6202773 100644 --- a/social/instaget/README.md +++ b/social/instaget/README.md @@ -6,4 +6,4 @@ This script allows to quick download an image from Instagram, the `wget`ish way. ```bash instaget/runner.sh https://www.instagram.com/p/123456778_9/ -``` \ No newline at end of file +``` diff --git a/social/instaget/runner.sh b/social/instaget/runner.sh index 1ce4522..4515035 100755 --- a/social/instaget/runner.sh +++ b/social/instaget/runner.sh @@ -3,8 +3,8 @@ # auxiliary functions function help() { - echo -e "Usage:\n\t$(basename "$0") https://instagram.com/p/" - exit 0 + echo -e "Usage:\n\t$(basename "$0") https://instagram.com/p/" + exit 0 } function rprint() { echo -en "\r\e[0K$*"; } function pprint() { echo -e "\r\e[0K$*"; } @@ -14,27 +14,27 @@ function pprint() { echo -e "\r\e[0K$*"; } # arguments parsing while [[ $# -gt 0 ]]; do - case "$1" in - -h | --help) - help - ;; - *) - TARGET=$1 - ;; - esac - shift + case "$1" in + -h | --help) + help + ;; + *) + TARGET=$1 + ;; + esac + shift done # arguments validation if [ -z "${TARGET}" ]; then - help + help fi TARGET_ID="$(awk -F'/' '{print $NF}' <<<"${TARGET::-1}")" if [ -z "${TARGET_ID}" ]; then - help + help fi TARGET_FNAME="${TARGET_ID}.jpg" @@ -48,14 +48,14 @@ rprint "Fetching asset URL..." target_url="$(awk -F'content="' '/property="og:image"/ {print $2}' <<<"${target_page}" | awk -F'"' '{print $1}')" if [ -z "${target_url}" ]; then - pprint "Asset not found." - exit 1 + pprint "Asset not found." + exit 1 fi rprint "Downloading asset..." if ! wget -q "${target_url}" -O "${TARGET_FNAME}"; then - pprint "Unable to download asset." - exit 1 + pprint "Unable to download asset." + exit 1 fi pprint "Asset downloaded at: ${TARGET_FNAME}" diff --git a/system/ego/id.py b/system/ego/id.py index 2f36bee..bc127c0 100644 --- a/system/ego/id.py +++ b/system/ego/id.py @@ -18,7 +18,11 @@ def capitalize_alpha(payload: str) -> str: async def keepass(payload: str, secret: str) -> Union[Tuple[str, str], None]: - for path in os.environ.get("KPX_DB").split(":"): + db_paths = os.environ.get("KPX_DB") + if not db_paths: + return None + + for path in db_paths.split(":"): try: db = kpx.PyKeePass(path, password=secret, keyfile=os.environ.get("KPX_KEY")) if entry := db.find_entries(title=payload, regex=True, first=True): @@ -27,6 +31,7 @@ async def keepass(payload: str, secret: str) -> Union[Tuple[str, str], None]: return (entry.username, entry.password) except kpx.exceptions.CredentialsError: pass + return None @@ -34,17 +39,19 @@ async def gen( payload: str, secret: str, iteration: int, length: int ) -> Tuple[str, str]: raw = f"{payload}@{secret}{str('+') * (iteration - 1)}" - hash = f"#{hashlib.sha256(raw.encode('utf-8')).hexdigest()}" - return ("", capitalize_alpha(hash[:length])) + hashsum = f"#{hashlib.sha256(raw.encode('utf-8')).hexdigest()}" + return ("", capitalize_alpha(hashsum[:length])) -@click.command() +@click.command(name="id") @click.argument("payload") @click.option("-u", "--username", is_flag=True, default=False) @click.option("-i", "--iteration", type=int, default=1) @click.option("-l", "--length", type=int, default=16) @click.option("-g", "--generate", is_flag=True, default=False) -async def id(payload: str, username: bool, iteration: int, length: int, generate: bool): +async def cmd_id( + payload: str, username: bool, iteration: int, length: int, generate: bool +): if iteration > 1: generate = True secret = getpass.getpass() diff --git a/system/ego/runner.py b/system/ego/runner.py index 5070016..83a29ed 100755 --- a/system/ego/runner.py +++ b/system/ego/runner.py @@ -1,17 +1,16 @@ #!/usr/bin/env python import asyncclick as click -from id import id as ego_id -from up import up as ego_up +from id import cmd_id +from up import cmd_up @click.group() -async def ego(): - ... +async def ego(): ... -ego.add_command(ego_id) -ego.add_command(ego_up) +ego.add_command(cmd_id) +ego.add_command(cmd_up) if __name__ == "__main__": ego(_anyio_backend="trio") diff --git a/system/ego/up.py b/system/ego/up.py index ca8453b..a2f73b0 100644 --- a/system/ego/up.py +++ b/system/ego/up.py @@ -1,13 +1,12 @@ #!/usr/bin/env python -import distutils.spawn import functools import hashlib import os import platform -import random +import shutil import subprocess -from typing import AsyncGenerator, List, Tuple +from typing import AsyncGenerator, List, Optional, Tuple import asyncclick as click import trio @@ -25,17 +24,19 @@ async def sudo_subshell() -> trio.Process: return await trio.run_process(["sudo", "-p", "Password: ", "echo", "-n"]) -def is_os(os: str) -> bool: - return platform.system().lower().startswith(os.lower()) +def is_os(os_name: str) -> bool: + return platform.system().lower().startswith(os_name.lower()) def is_exec(cmd: str) -> bool: - return distutils.spawn.find_executable(cmd) is not None + return shutil.which(cmd) is not None -def dep(cmd: str | None = None, platform: str = "", envs: List[str] = None): - has_os = is_os(platform) - has_envs = not any([env for env in (envs or list()) if env not in os.environ]) +def dep( + cmd: str | None = None, platform_name: str = "", envs: Optional[List[str]] = None +): + has_os = is_os(platform_name) + has_envs = len([env for env in (envs or []) if env not in os.environ]) == 0 def decorator_dep(func): has_cmd = is_exec(cmd or func.__name__) @@ -57,8 +58,8 @@ async def wrapper_dep(*args, **kwargs): ) async for p_args, p_kwargs in func(*args, **kwargs): - if (type(p_args[0]) == list and p_args[0][0] == "sudo") or ( - type(p_args[0]) == str and p_args[0].startswith("sudo") + if (isinstance(p_args[0], list) and p_args[0][0] == "sudo") or ( + isinstance(p_args[0], str) and p_args[0].startswith("sudo") ): await sudo_subshell() @@ -89,7 +90,7 @@ async def wrapper_dep(*args, **kwargs): return decorator_dep -@dep(platform="linux") +@dep(platform_name="linux") async def apt() -> AsyncGenerator[Tuple[list, dict], None]: apt_env = dict(os.environ, DEBIAN_FRONTEND="noninteractive") apt_prefix = [ @@ -99,7 +100,10 @@ async def apt() -> AsyncGenerator[Tuple[list, dict], None]: ] yield [apt_prefix + ["update"]], {"env": apt_env} yield [apt_prefix + ["upgrade"]], {"env": apt_env} - yield [apt_prefix + ["dist-upgrade"]], {"env": apt_env}, + yield ( + [apt_prefix + ["dist-upgrade"]], + {"env": apt_env}, + ) yield [apt_prefix + ["autoremove"]], {"env": apt_env} @@ -110,9 +114,7 @@ async def brew() -> AsyncGenerator[Tuple[list, dict], None]: @dep() -async def managedsoftwareupdate( - *args, **kwargs -) -> AsyncGenerator[Tuple[list, dict], None]: +async def managedsoftwareupdate() -> AsyncGenerator[Tuple[list, dict], None]: yield [["sudo", "managedsoftwareupdate", "--installonly"]], {} @@ -121,8 +123,8 @@ async def omz() -> AsyncGenerator[Tuple[list, dict], None]: yield [[f"{os.getenv('ZSH')}/tools/upgrade.sh"]], {} -@dep(platform="darwin") -async def softwareupdate(*args, **kwargs) -> AsyncGenerator[Tuple[list, dict], None]: +@dep(platform_name="darwin") +async def softwareupdate() -> AsyncGenerator[Tuple[list, dict], None]: yield [["softwareupdate", "-i", "-a"]], {} @@ -138,8 +140,8 @@ async def nixenv() -> AsyncGenerator[Tuple[list, dict], None]: yield [["nix-env", "-u", "*"]], {} -@click.command() -async def up(): +@click.command(name="up") +async def cmd_up(): async with trio.open_nursery() as nursery: nursery.start_soon(apt) nursery.start_soon(brew)