From: Steven Baltakatei Sandoval Date: Sat, 8 Jul 2023 12:11:12 +0000 (+0000) Subject: Merge branch 'master' into develop X-Git-Tag: 0.8.2^0 X-Git-Url: https://zdv2.bktei.com/gitweb/BK-2020-03.git/commitdiff_plain/65207f302c1787df989174cebd4e383ef72eda19?hp=1f725176a1e8319ebdcadb05ade95d9eb86b08c7 Merge branch 'master' into develop --- diff --git a/unitproc/bkt-checkInt b/unitproc/bkt-checkInt index cfe396e..0922a14 100644 --- a/unitproc/bkt-checkInt +++ b/unitproc/bkt-checkInt @@ -5,7 +5,7 @@ #===BEGIN Declare local script functions=== yell() { echo "$0: $*" >&2; } # print script path and all args to stderr die() { yell "$*"; exit 111; } # same as yell() but non-zero exit status -try() { "$@" || die "cannot $*"; } # runs args as command, reports args if command fails +must() { "$@" || die "cannot $*"; } # runs args as command, reports args if command fails checkInt() { # Desc: Checks if arg is integer # Usage: checkInt arg @@ -13,7 +13,7 @@ checkInt() { # Output: - return code 0 (if arg is integer) # - return code 1 (if arg is not integer) # Example: if ! checkInt $arg; then echo "not int"; fi; - # Version: 0.0.1 + # Version: 0.0.2 local returnState #===Process Arg=== @@ -22,7 +22,7 @@ checkInt() { fi; RETEST1='^[0-9]+$'; # Regular Expression to test - if [[ ! $1 =~ $RETEST1 ]] ; then + if [[ ! "$1" =~ $RETEST1 ]] ; then returnState="false"; else returnState="true"; diff --git a/unitproc/bkt-insertStr b/unitproc/bkt-insertStr new file mode 100755 index 0000000..5fdbf93 --- /dev/null +++ b/unitproc/bkt-insertStr @@ -0,0 +1,63 @@ +#!/usr/bin/env bash +# Desc: Insert string into provided string + +yell() { echo "$0: $*" >&2; } +die() { yell "$*"; exit 111; } +must() { "$@" || die "cannot $*"; } +insertStr() { + # Desc: Inserts a string into another string at a specified position. + # Input: arg1: str str_rec String to receive insertion + # arg2: int pos Insertion position (0 = append to front) + # arg3: str str_ins String to be inserted + # Output: stdout: Combined string + # Version: 0.0.2 + # Depends: BK-2020-03: yell(), die(), must() + # Ref/Attrib: * BK-2020-03: https://gitlab.com/baltakatei/baltakatei-exdev/ + # * Cooper, Mendel. “Advanced Bash-Scripting Guide: Manipulating Strings”. tldp.org https://tldp.org/LDP/abs/html/string-manipulation.html + + local str_rec pos str_ins re len_str_rec; + local pfx_pos_start pfx_len pfx; + local sfx_pos_start sfx_len sfx; + + # Check args + if [[ $# -ne 3 ]]; then + yell "ERROR:Invalid argument count:$#"; + return 1; fi; + re='^[0-9]+$'; + if [[ ! "$2" =~ $re ]]; then + yell "ERROR:Not an int:$2"; + return 1; fi; + str_rec="$1"; + pos="$2"; + str_ins="$3"; + + # Calculate string stats + len_str_rec="${#str_rec}"; + + # Form prefix + pfx_pos_start="0"; + pfx_len="$pos"; + pfx="${str_rec:$pfx_pos_start:$pfx_len}"; + + # Form suffix + sfx_pos_start="$(( pos ))"; + sfx_len="$(( len_str_rec - pos ))"; + sfx="${str_rec:$sfx_pos_start:$sfx_len}"; + + # Print output to stdout + printf "%s%s%s\n" "$pfx" "$str_ins" "$sfx"; +}; # Insert string provided at indicated position via stdout + + +# Tests +printf "\"%s\" should read \"foobarbaz\"\n" "$(insertStr "foobaz" 3 "bar";)"; + +insertStr "foobaz" 0 "bar"; +insertStr "foobaz" 1 "bar"; +insertStr "foobaz" 2 "bar"; +insertStr "foobaz" 3 "bar"; +insertStr "foobaz" 4 "bar"; +insertStr "foobaz" 5 "bar"; +insertStr "foobaz" 6 "bar"; +insertStr "foobaz" 7 "bar"; +insertStr "foobaz" 999 "bar"; diff --git a/unitproc/python/bkt-humidity b/unitproc/python/bkt-humidity new file mode 100644 index 0000000..437adc7 --- /dev/null +++ b/unitproc/python/bkt-humidity @@ -0,0 +1,185 @@ +#!/usr/bin/env python3 +# Desc: Humidity conversion functions from EVA-2020-02-2 +# Ref/Attrib: https://gitlab.com/baltakatei/ninfacyzga-01 + +def rel_to_abs(T,P,RH): + """Returns absolute humidity given relative humidity. + + Inputs: + -------- + T : float + Absolute temperature in units Kelvin (K). + P : float + Total pressure in units Pascals (Pa). + RH : float + Relative humidity in units percent (%). + + Output: + -------- + absolute_humidity : float + Absolute humidity in units [kg water vapor / kg dry air]. + + References: + -------- + 1. Sonntag, D. "Advancements in the field of hygrometry". 1994. https://doi.org/10.1127/metz/3/1994/51 + 2. Green, D. "Perry's Chemical Engineers' Handbook" (8th Edition). Page "12-4". McGraw-Hill Professional Publishing. 2007. + + Version: 0.0.1 + Author: Steven Baltakatei Sandoval + License: GPLv3+ + """ + + import math; + + # Check input types + T = float(T); + P = float(P); + RH = float(RH); + + #debug + # print('DEBUG:Input Temperature (K) :' + str(T)); + # print('DEBUG:Input Pressure (Pa) :' + str(P)); + # print('DEBUG:Input Rel. Humidity (%) :' + str(RH)); + + # Set constants and initial conversions + epsilon = 0.62198 # (molar mass of water vapor) / (molar mass of dry air) + t = T - 273.15; # Celsius from Kelvin + P_hpa = P / 100; # hectoPascals (hPa) from Pascals (Pa) + + # Calculate e_w(T), saturation vapor pressure of water in a pure phase, in Pascals + ln_e_w = -6096*T**-1 + 21.2409642 - 2.711193*10**-2*T + 1.673952*10**-5*T**2 + 2.433502*math.log(T); # Sonntag-1994 eq 7; e_w in Pascals + e_w = math.exp(ln_e_w); + e_w_hpa = e_w / 100; # also save e_w in hectoPascals (hPa) + # print('DEBUG:ln_e_w:' + str(ln_e_w)); # debug + # print('DEBUG:e_w:' + str(e_w)); # debug + + # Calculate f_w(P,T), enhancement factor for water + f_w = 1 + (10**-4*e_w_hpa)/(273 + t)*(((38 + 173*math.exp(-t/43))*(1 - (e_w_hpa / P_hpa))) + ((6.39 + 4.28*math.exp(-t / 107))*((P_hpa / e_w_hpa) - 1))); # Sonntag-1994 eq 22. + # print('DEBUG:f_w:' + str(f_w)); # debug + + # Calculate e_prime_w(P,T), saturation vapor pressure of water in air-water mixture, in Pascals + e_prime_w = f_w * e_w; # Sonntag-1994 eq 18 + # print('DEBUG:e_prime_w:' + str(e_prime_w)); # debug + + # Calculate e_prime, vapor pressure of water in air, in Pascals + e_prime = (RH / 100) * e_prime_w; + # print('DEBUG:e_prime:' + str(e_prime)); # debug + + # Calculate r, the absolute humidity, in [kg water vapor / kg dry air] + r = (epsilon * e_prime) / (P - e_prime); + # print('DEBUG:r:' + str(r)); # debug + + return float(r); + +def rel_to_dpt(T,P,RH): + """Returns dew point temperature given relative humidity. + + Inputs: + -------- + T : float + Absolute temperature in units Kelvin (K). + P : float + Total pressure in units Pascals (Pa). + RH : float + Relative humidity in units percent (%). + + Output: + -------- + T_d : float + Dew point temperature in units Kelvin (K). + + References: + -------- + 1. Sonntag, D. "Advancements in the field of hygrometry". 1994. https://doi.org/10.1127/metz/3/1994/51 + 2. Green, D. "Perry's Chemical Engineers' Handbook" (8th Edition). Page "12-4". McGraw-Hill Professional Publishing. 2007. + + Version: 0.0.1 + Author: Steven Baltakatei Sandoval + License: GPLv3+ + """ + + import math; + + # Check input types + T = float(T); + P = float(P); + RH = float(RH); + + #debug + # print('DEBUG:Input Temperature (K) :' + str(T)); + # print('DEBUG:Input Pressure (Pa) :' + str(P)); + # print('DEBUG:Input Rel. Humidity (%) :' + str(RH)); + + # Set constants and initial conversions + epsilon = 0.62198 # (molar mass of water vapor) / (molar mass of dry air) + t = T - 273.15; # Celsius from Kelvin + P_hpa = P / 100; # hectoPascals (hPa) from Pascals (Pa) + + # Calculate e_w(T), saturation vapor pressure of water in a pure phase, in Pascals + ln_e_w = -6096*T**-1 + 21.2409642 - 2.711193*10**-2*T + 1.673952*10**-5*T**2 + 2.433502*math.log(T); # Sonntag-1994 eq 7; e_w in Pascals + e_w = math.exp(ln_e_w); + e_w_hpa = e_w / 100; # also save e_w in hectoPascals (hPa) + # print('DEBUG:ln_e_w:' + str(ln_e_w)); # debug + # print('DEBUG:e_w:' + str(e_w)); # debug + + # Calculate f_w(P,T), enhancement factor for water + f_w = 1 + (10**-4*e_w_hpa)/(273 + t)*(((38 + 173*math.exp(-t/43))*(1 - (e_w_hpa / P_hpa))) + ((6.39 + 4.28*math.exp(-t / 107))*((P_hpa / e_w_hpa) - 1))); # Sonntag-1994 eq 22. + # print('DEBUG:f_w:' + str(f_w)); # debug + + # Calculate e_prime_w(P,T), saturation vapor pressure of water in air-water mixture, in Pascals + e_prime_w = f_w * e_w; # Sonntag-1994 eq 18 + # print('DEBUG:e_prime_w:' + str(e_prime_w)); # debug + + # Calculate e_prime, vapor pressure of water in air, in Pascals + e_prime = (RH / 100) * e_prime_w; + # print('DEBUG:e_prime:' + str(e_prime)); # debug + + n = 0; repeat_flag = True; + while repeat_flag == True: + # print('DEBUG:n:' + str(n)); # debug + + # Calculate f_w_td, the enhancement factor for water at dew point temperature. + if n == 0: + f = 1.0016 + 3.15*10**-6*P_hpa - (0.074 / P_hpa); # Sonntag-1994 eq 24 + f_w_td = f; # initial approximation + elif n > 0: + t_d_prev = float(t_d); # save previous t_d value for later comparison + f_w_td = 1 + (10**-4*e_w_hpa)/(273 + t_d)*(((38 + 173*math.exp(-t_d/43))*(1 - (e_w_hpa / P_hpa))) + ((6.39 + 4.28*math.exp(-t_d / 107))*((P_hpa / e_w_hpa) - 1))); # Sonntag-1994 eq 22. + # print('DEBUG:f_w_td:' + str(f_w_td)); # debug + + # Calculate e, the vapor pressure of water in the pure phase, in Pascals + e = (e_prime / f_w_td); # Sonntag-1994 eq 9 and 20 + # print('DEBUG:e:' + str(e)); # debug + + # Calculate y, an intermediate dew point calculation variable + y = math.log(e / 611.213); + # print('DEBUG:y:' + str(y)); # debug + + # Calculate t_d, the dew point temperature in degrees Celsius + t_d = 13.715*y + 8.4262*10**-1*y**2 + 1.9048*10**-2*y**3 + 7.8158*10**-3*y**4;# Sonntag-1994 eq 10 + # print('DEBUG:t_d:' + str(t_d)); # debug + + if n == 0: + # First run + repeat_flag = True; + else: + # Test t_d accuracy + t_d_diff = math.fabs(t_d - t_d_prev); + # print('DEBUG:t_d :' + str(t_d)); # debug + # print('DEBUG:t_d_prev:' + str(t_d_prev)); # debug + # print('DEBUG:t_d_diff:' + str(t_d_diff)); # debug + if t_d_diff < 0.01: + repeat_flag = False; + else: + repeat_flag = True; + + # Calculate T_d, the dew point temperature in Kelvin + T_d = 273.15 + t_d; + # print('DEBUG:T_d:' + str(T_d)); # debug + + if n > 100: + return T_d; # good enough + + # update loop counter + n += 1; + return T_d; diff --git a/user/bk-copy-rand-music b/user/bk-copy-rand-music old mode 100644 new mode 100755 index bc21e5b..b807286 --- a/user/bk-copy-rand-music +++ b/user/bk-copy-rand-music @@ -1,7 +1,7 @@ #!/usr/bin/env bash # Desc: Copies random audio files # Usage: bk-copy-rand-music [dir SOURCE] [dir DEST] [int DURATION] ([int BYTES]) -# Version: 0.1.1 +# Version: 0.2.0 # Depends: BK-2020-03: bkshuf v0.1.0 declare -Ag appRollCall # Associative array for storing app status @@ -516,13 +516,15 @@ main() { fpath="$(printf "%s" "$line" | cut -d',' -f3-)"; ## Get basename of path file_basename="$(basename "$fpath")"; + ### Get basename without unprintable non-ASCII characters + file_basename_compat="$(printf "%s" "$file_basename" | tr -dc '[:graph:][:space:]' )"; ## Get 16-character b2sum fingerprint (for different files that share basename) fingerprint="$(b2sum -l32 "$fpath" | awk '{print $1}' )"; ## Form output filename num="$(printf "$num_fmt" "$n")"; - file_name="$num"_"$fingerprint".."$file_basename"; + file_name="$num"_"$fingerprint".."$file_basename_compat"; file_name="${file_name:0:$max_filename_length}"; # Limit filename length (e.g. Windows has max of 255 characters) ## Form output path @@ -538,7 +540,7 @@ main() { printf "$log_fmt" "$num" "$fingerprint" "$fdur" "$fsize" "$fpath_can" >> "$path_log_output"; ((n++)); - unset file_basename path_output + unset file_basename file_basename_compat path_output; done < <(printf "%s\n" "${list_copy[@]}"); # Report total duration and size diff --git a/user/bk-find-git-verify b/user/bk-find-git-verify index a94dc06..333880f 100755 --- a/user/bk-find-git-verify +++ b/user/bk-find-git-verify @@ -2,7 +2,10 @@ # Finds and verifies signatures of git repositories in specified dir # Usage: bk-find-git-verify [DIR] # Depends: GNU parallel 20210822, sort (GNU coreutils) 8.32 -# Version: 0.0.1 +# Version: 0.0.2 + +# global vars +findMaxDepth=8; # Define functions yell() { echo "$0: $*" >&2; } # print script path and all args to stderr @@ -52,7 +55,7 @@ main() { if [[ ! -d "$1" ]]; then die "FATAL:Not a dir:$1"; fi; # Get list of dirs containing '.git' directory - dir_list="$(find "$1" -type d -name ".git" 2>/dev/random | parallel dirname '{}' | sort -u)"; + dir_list="$(find -L "$1" -maxdepth "$findMaxDepth" -type d -name ".git" 2>/dev/random | parallel readlink -f '{}' | sort -u | parallel dirname '{}' | sort -u)"; # Perform git verify operations on each directory printf "%s" "$dir_list" | parallel git_verify_ops '{}'; diff --git a/user/bkdatev b/user/bkdatev index 22ff310..8938843 100755 --- a/user/bkdatev +++ b/user/bkdatev @@ -2,7 +2,8 @@ # Desc: Baltakatei's verbose date command # Usage: bkdatev [args] # Example: bkdatev --date="2001-09-11T09:02:59-04" -# Version: 0.2.2 +# Version: 0.3.4 +# Depends: GNU Coreutils 8.32, Bash 3.2.57 # Ref/Attrib: [1] "ISO 8601". Wikipedia. https://en.wikipedia.org/wiki/ISO_8601 # [2] "Changing the Locale in Wine" https://stackoverflow.com/a/16428951 # [3] "Shanghai vs Beijing" https://bugs.launchpad.net/ubuntu/+source/libgweather/+bug/228554 @@ -11,7 +12,56 @@ # * For list of valid locales, see: https://manpages.ubuntu.com/manpages/bionic/man3/DateTime::Locale::Catalog.3pm.html # * Locations chosen for population, personal signifiance, and spatial coverage. # * For International Atomic Time (TAI), use offsets from UTC provided in `/usr/share/zoneinfo/leap-seconds.list`. - +# * Compatibility with macOS may be limited if any arguments +# are provided when running `bkdatev`; e.g. passing a +# `--date` option to `bkdatev` will fail. + +yell() { echo "$0: $*" >&2; } +die() { yell "$*"; exit 111; } +must() { "$@" || die "cannot $*"; } +insertStr() { + # Desc: Inserts a string into another string at a specified position. + # Input: arg1: str str_rec String to receive insertion + # arg2: int pos Insertion position (0 = append to front) + # arg3: str str_ins String to be inserted + # Output: stdout: Combined string + # Version: 0.0.2 + # Depends: BK-2020-03: yell(), die(), must() + # Ref/Attrib: * BK-2020-03: https://gitlab.com/baltakatei/baltakatei-exdev/ + # * Cooper, Mendel. “Advanced Bash-Scripting Guide: Manipulating Strings”. tldp.org https://tldp.org/LDP/abs/html/string-manipulation.html + + local str_rec pos str_ins re len_str_rec; + local pfx_pos_start pfx_len pfx; + local sfx_pos_start sfx_len sfx; + + # Check args + if [[ $# -ne 3 ]]; then + yell "ERROR:Invalid argument count:$#"; + return 1; fi; + re='^[0-9]+$'; + if [[ ! "$2" =~ $re ]]; then + yell "ERROR:Not an int:$2"; + return 1; fi; + str_rec="$1"; + pos="$2"; + str_ins="$3"; + + # Calculate string stats + len_str_rec="${#str_rec}"; + + # Form prefix + pfx_pos_start="0"; + pfx_len="$pos"; + pfx="${str_rec:$pfx_pos_start:$pfx_len}"; + + # Form suffix + sfx_pos_start="$(( pos ))"; + sfx_len="$(( len_str_rec - pos ))"; + sfx="${str_rec:$sfx_pos_start:$sfx_len}"; + + # Print output to stdout + printf "%s%s%s\n" "$pfx" "$str_ins" "$sfx"; +}; # Insert string provided at indicated position via stdout line_sep() { # Input: var: n_ln local skip_every=4; @@ -21,21 +71,56 @@ line_sep() { fi; return 0; }; # periodically print separating blank line +get_tz_offset() { + # Desc: Get from 'date' the timezone UTC offset in a way + # compatible with both GNU Coreutils and BSD versions. + # Input: env var: TZ (time zone for date; e.g. 'America/Denver') + # args: $@ # passed onto `date` + # Depends: date (GNU Coreutils 8.32 or BSD), rev + local ntz ntz ntz_out; + local last2; + + # Get numeric time zone string in way compatible with GNU Coreutils and BSD + ntz="$(date "+%z" "$@")"; # e.g. "+0530" + + # Check if last two characters are trailing zeros that can be removed. + last2="${ntz:3:2}"; # assumes $ntz is 5 characters (i.e. "±HHMM") + #last2="$(rev <<< $ntz)" && last2="${last2:0:2}" && last2="$(rev <<< "$last2")"; + if [[ "$last2" == "00" ]]; then + ## ntz_out is truncated by 2 characters + len_ntz="${#ntz}"; + len_ntz_out="$(( len_ntz - 2 ))"; + ntz_out=""${ntz:0:$len_ntz_out}; + else + ## ntz_out is ntz with semicolon inserted after HH + ntz_out="$(insertStr "$ntz" 3 ":" )"; + fi; + + # Output via stdout + printf "%s" "$ntz_out"; +}; # Format numeric time zone (for BSD date compatibility) print_dateline() { # Input: var: $id # var: $fs_1 # var: $fs_2 # var: $fs_3 - # args: $@ + # args: $@ # passed on to `date` + # env var: TZ (time zone for date; e.g. 'America/Denver') # Output: stdout # Depends: printf, date + # get_tz_offset() # Ref/Attrib: * Truncate string in printf https://stackoverflow.com/a/46812677 - local s_1 s_2 s_3 s_4; + local s_1 s_2 s_2_tz s_3 s_4; s_1="$id"; - s_2="$(date "$@" "$fs_1")"; - s_3="$(date "$@" "$fs_2")"; - s_4="$(date "$@" "$fs_3")"; + s_2="$(date "$@" "$fs_1")"; # ISO-8601 without numeric timezone + s_3="$(date "$@" "$fs_2")"; # Alternate ISO-8601 expressions + s_4="$(date "$@" "$fs_3")"; # locale-specific date strings + + # Append numeric timezone to $s_2 with appropriate format + # (e.g. '-07' for 'Arizona', '+05:45' for 'Asia/Kathmandu') + s_2_tz="$(get_tz_offset "$@")"; + s_2="$( printf "%s%s" "$s_2" "$s_2_tz" )"; printf "%-10.10s %-25.25s (%-20.20s) (%s)" "$s_1" "$s_2" "$s_3" "$s_4"; printf "\n"; @@ -47,7 +132,7 @@ main() { unset LC_TIME; # Fall back to time zone-specific locale settings. # format strings - fs_iso8601="+%Y-%m-%dT%H:%M:%S%:::z"; # typical ISO-8601 + fs_iso8601="+%Y-%m-%dT%H:%M:%S"; # typical ISO-8601 without timezone fs_iso8601_etc="+%G-W%V-%u, %Y-%j"; # alternate ISO-8601 dates fs_locale="+%Z; %A; %c"; # locale-specific date strings @@ -176,6 +261,14 @@ main() { print_dateline "$@"; ); line_sep; + # Helsinki, Finland + ( + export TZ=Europe/Helsinki; + export LANG="fi_FI.UTF8"; + id="HELSINKI"; + print_dateline "$@"; + ); line_sep; + # Cairo, Egypt ( export TZ=Africa/Cairo; @@ -316,3 +409,6 @@ main() { }; # main program main "$@"; + +# Author: Steven Baltakatei Sandoval +# License: GPLv3+ diff --git a/user/combine_pdfs.sh b/user/combine_pdfs.sh new file mode 100755 index 0000000..1c04cd0 --- /dev/null +++ b/user/combine_pdfs.sh @@ -0,0 +1,111 @@ +#!/usr/bin/env bash +# Desc: Combines PDF files into a single PDF file +# Depends: pdftk 2.02-5 ( https://www.pdflabs.com/tools/pdftk-the-pdf-toolkit/ ) +# Version 0.0.1 + +yell() { echo "$0: $*" >&2; } # print script path and all args to stderr +die() { yell "$*"; exit 111; } # same as yell() but non-zero exit status +must() { "$@" || die "cannot $*"; } # runs args as command, reports args if command fails +showUsage() { + # Desc: Display script usage information + # Usage: showUsage + # Version 0.0.2 + # Input: none + # Output: stdout + # Depends: GNU-coreutils 8.30 (cat) + cat <<'EOF' + USAGE: + combine_pdfs.sh [FILE output] [FILES input...] + + EXAMPLE: + combine_pdfs.sh output.pdf input1.pdf input2.pdf + combine_pdfs.sh output.pdf input*.pdf +EOF +} # Display information on how to use this script. +checkDepends() { + if ! command -v pdftk 1>/dev/random 2>&1; then + showUsage; + die "FATAL:Missing pdftk."; fi; +}; # Check dependencies +checkArgs() { + local narg; + + # Check arguments + narg=0; + for arg in "$@"; do + #yell "DEBUG:Checking argument:$arg"; + if [[ $narg -le 0 ]]; then + if [[ ! -f "$arg" ]]; then + ((narg++)); continue; + else + ## Get permission to overwrite existing output file + yell "WARNING:Overwrite output file \"$arg\"? (y/n)"; + read -r prompt; + case "$prompt" in + "y" | "yes" | "Yes" | "YES" ) + ;; + "n" | "no" | "No" | "NO" ) + showUsage; die "FATAL:Aborted."; + ;; + *) + showUsage; die "FATAL:Invalid response."; + ;; + esac; + fi; + fi; # handle first arg + + if [[ ! -f "$arg" ]]; then + showUsage; die "FATAL:File does not exist:$arg"; fi; + ((narg++)); + done; + + return 0; +}; +combinePDFs() { + # Desc: Combines PDFs and writes to output PDF file + # Depends: pdftk 2.02-5 + local cmd path_fo; + local -a paths_fi; + + # Save output file path + path_fo="$1"; + + # Form array of input file paths + paths_fi=("$@"); + unset 'paths_fi[0]'; # discard first path which is output file + + # Form command array + cmd+=("pdftk"); # executable + cmd+=("${paths_fi[@]}"); # input file paths + cmd+=("cat" "output"); + cmd+=("$path_fo"); + #yell "DEBUG:cmd:$(declare -p cmd)"; + #yell "DEBUG:cmd:${cmd[*]}"; + + # Execute command array + "${cmd[@]}"; +}; # Combines PDFs and writes to output PDF file +main() { + #yell "DEBUG:$(args=("$@"); declare -p args)"; + checkDepends; + checkArgs "$@"; + combinePDFs "$@"; + exit 0; +}; # main program + +main "$@"; + +# Author: Steven Baltakatei Sandoval +# License: GPLv3+ + +# # Copyright notices + +# pdftk port to java 3.2.2 a Handy Tool for Manipulating PDF Documents +# Copyright (c) 2017-2018 Marc Vinyals - https://gitlab.com/pdftk-java/pdftk +# Copyright (c) 2003-2013 Steward and Lee, LLC. +# pdftk includes a modified version of the iText library. +# Copyright (c) 1999-2009 Bruno Lowagie, Paulo Soares, et al. +# This is free software; see the source code for copying conditions. There is +# NO warranty, not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + diff --git a/user/convert_file_to_flac.sh b/user/convert_file_to_flac.sh old mode 100644 new mode 100755 diff --git a/user/mp3s_to_mkv.sh b/user/mp3s_to_mkv.sh new file mode 100755 index 0000000..eb32982 --- /dev/null +++ b/user/mp3s_to_mkv.sh @@ -0,0 +1,94 @@ +#!/bin/bash +# Desc: Converts a directory of mp3s into a single mkv file +# Usage: mp3s_to_mkv.sh [DIR in] [DIR out] [BITRATE] +# Example: mp3s_to_mkv.sh ./dir_source ./dir_output 48k +# Depends: GNU Coretils 8.32 (date) +# Version: 0.0.1 + +# plumbing +opus_bitrate="$3"; # e.g. "48k" +script_rundate="$(date +%s)"; +dir_tmp="/dev/shm"; +dir_in="$(readlink -f "$1")"; +dir_out="$(readlink -f "$2")"; +file_flist="$dir_tmp"/"$script_rundate"..flist.txt; +file_out_mkv="$dir_out"/output.mkv; +file_albumart="$dir_out"/albumart.png; + +yell() { echo "$0: $*" >&2; } # print script path and all args to stderr +die() { yell "$*"; exit 111; } # same as yell() but non-zero exit status +must() { "$@" || die "cannot $*"; } # runs args as command, reports args if command fails +show_usage() { + # Desc: Display script usage information + # Usage: showUsage + # Version 0.0.2 + # Input: none + # Output: stdout + # Depends: GNU-coreutils 8.30 (cat) + cat <<'EOF' + USAGE: + mp3s_to_mkv.sh [DIR in] [DIR out] [BITRATE] + + EXAMPLE: + mp3s_to_mkv.sh ./source_dir ./out_dir 48k +EOF +} # Display information on how to use this script. +check_depends() { + if ! command -v ffmpeg; then show_usage; die "FATAL:Missing ffmpeg."; fi; +}; # check dependencies +check_plumbing() { + if [[ $# -ne 3 ]]; then show_usage; die "FATAL:Invalid arg count:$#"; fi; + if [[ ! -d "$dir_in" ]]; then show_usage; die "FATAL:Not a dir:$dir_in"; fi; + if [[ ! -d "$dir_out" ]]; then mkdir -p "$2"; fi; +}; # check arguments +build_filelist() { + # Depends: var dir_tmp temporary directory + # var dir_in input dir + # var file_flist path file list + # Output: file: $file_flist list of mp3 files for ffmpeg + + # Change directory to input dir + pushd "$dir_in" || die "FATAL:Directory error:$(pwd)"; + + while read -r line; do + yell "$(printf "file '%s'\n" "${line#./}")"; + printf "file '%s'\n" "${line#./}" >> "$file_flist"; + done < <(find "$dir_in" -type f -iname "*.mp3" | sort); + + # Return to original dir + popd || die "FATAL:Directory error:$(pwd)"; + +}; # build file list for ffmpeg +ffmpeg_convert() { + # Depends: var dir_tmp + # dir_in + # dir_out + # Input: file $file_flist list of mp3 files for ffmpeg + + # Change directory to input dir + pushd "$dir_in" || die "FATAL:Directory error:$(pwd)"; + + # Concatenate mp3 files into a single WAV file + # # Convert WAV to 48 kbps opus mkv file + ffmpeg -f concat -safe 0 -i "$file_flist" -c:a pcm_s24le -rf64 auto -f wav - | \ + ffmpeg -i - -c:a libopus -b:a "$opus_bitrate" "$file_out_mkv"; + + # Return to original dir + popd || die "FATAL:Directory error:$(pwd)"; +}; # convert mp3s to opus mkv via ffmpeg +save_albumart() { + local file + file="$(find "$dir_in" -type f -iname "*.mp3" | sort | head -n1)"; + file="$(readlink -f "$file")"; + ffmpeg -i "$file" -an -vcodec copy "$file_albumart"; +}; # save album art from an mp3 to output dir +main() { + check_depends && yell "DEBUG:check_depends OK"; + check_plumbing "$@" && yell "DEBUG:check_plumbing OK"; + build_filelist "$@" && yell "DEBUG:build_filelist OK"; + ffmpeg_convert "$@" && yell "DEBUG:ffmpeg_convert OK"; + save_albumart "$@" && yell "DEBUG:save_albumart OK"; +}; # main program + +main "$@"; + diff --git a/user/mp3s_to_opus.sh b/user/mp3s_to_opus.sh new file mode 100755 index 0000000..0af92cc --- /dev/null +++ b/user/mp3s_to_opus.sh @@ -0,0 +1,94 @@ +#!/bin/bash +# Desc: Converts a directory of mp3s into a single opus file +# Usage: mp3s_to_opus.sh [DIR in] [DIR out] [BITRATE] +# Example: mp3s_to_opus.sh ./dir_source ./dir_output 48k +# Depends: GNU Coretils 8.32 (date) +# Version: 0.0.3 + +# plumbing +opus_bitrate="$3"; # e.g. "48k" +script_rundate="$(date +%s)"; +dir_tmp="/dev/shm"; +dir_in="$(readlink -f "$1")"; +dir_out="$(readlink -f "$2")"; +file_flist="$dir_tmp"/"$script_rundate"..flist.txt; +file_out_opus="$dir_out"/output.opus; +file_albumart="$dir_out"/albumart.png; + +yell() { echo "$0: $*" >&2; } # print script path and all args to stderr +die() { yell "$*"; exit 111; } # same as yell() but non-zero exit status +must() { "$@" || die "cannot $*"; } # runs args as command, reports args if command fails +show_usage() { + # Desc: Display script usage information + # Usage: showUsage + # Version 0.0.2 + # Input: none + # Output: stdout + # Depends: GNU-coreutils 8.30 (cat) + cat <<'EOF' + USAGE: + mp3s_to_opus.sh [DIR in] [DIR out] [BITRATE] + + EXAMPLE: + mp3s_to_opus.sh ./source_dir ./out_dir 48k +EOF +} # Display information on how to use this script. +check_depends() { + if ! command -v ffmpeg; then show_usage; die "FATAL:Missing ffmpeg."; fi; +}; # check dependencies +check_plumbing() { + if [[ $# -ne 3 ]]; then show_usage; die "FATAL:Invalid arg count:$#"; fi; + if [[ ! -d "$dir_in" ]]; then show_usage; die "FATAL:Not a dir:$dir_in"; fi; + if [[ ! -d "$dir_out" ]]; then mkdir -p "$2"; fi; +}; # check arguments +build_filelist() { + # Depends: var dir_tmp temporary directory + # var dir_in input dir + # var file_flist path file list + # Output: file: $file_flist list of mp3 files for ffmpeg + + # Change directory to input dir + pushd "$dir_in" || die "FATAL:Directory error:$(pwd)"; + + while read -r line; do + yell "$(printf "file '%s'\n" "${line#./}")"; + printf "file '%s'\n" "${line#./}" >> "$file_flist"; + done < <(find "$dir_in" -type f -iname "*.mp3" | sort); + + # Return to original dir + popd || die "FATAL:Directory error:$(pwd)"; + +}; # build file list for ffmpeg +ffmpeg_convert() { + # Depends: var dir_tmp + # dir_in + # dir_out + # Input: file $file_flist list of mp3 files for ffmpeg + + # Change directory to input dir + pushd "$dir_in" || die "FATAL:Directory error:$(pwd)"; + + # Concatenate mp3 files into a single WAV file + # # Convert WAV to 48 kbps opus file + ffmpeg -f concat -safe 0 -i "$file_flist" -c:a pcm_s24le -rf64 auto -f wav - | \ + ffmpeg -i - -c:a libopus -b:a "$opus_bitrate" "$file_out_opus"; + + # Return to original dir + popd || die "FATAL:Directory error:$(pwd)"; +}; # convert mp3s to opus via ffmpeg +save_albumart() { + local file + file="$(find "$dir_in" -type f -iname "*.mp3" | sort | head -n1)"; + file="$(readlink -f "$file")"; + ffmpeg -i "$file" -an -vcodec copy "$file_albumart"; +}; # save album art from an mp3 to output dir +main() { + check_depends && yell "DEBUG:check_depends OK"; + check_plumbing "$@" && yell "DEBUG:check_plumbing OK"; + build_filelist "$@" && yell "DEBUG:build_filelist OK"; + ffmpeg_convert "$@" && yell "DEBUG:ffmpeg_convert OK"; + save_albumart "$@" && yell "DEBUG:save_albumart OK"; +}; # main program + +main "$@"; + diff --git a/user/mw_create_month_journal.sh b/user/mw_create_month_journal.sh index 9ed0206..b540fa9 100755 --- a/user/mw_create_month_journal.sh +++ b/user/mw_create_month_journal.sh @@ -4,7 +4,7 @@ # Input: arg1: year # arg2: month # Example: /bin/bash mw_create_month_journal.sh 2023 03 > output.txt -# Version: 0.0.1 +# Version: 0.1.0 yyyy="$1"; mm="$2"; @@ -60,6 +60,7 @@ else fi; # Form and print header +printf "{{bk journal header month}}\n"; printf "Journal for [[%d]]-%02d. " "$yyyy" "$mm"; printf "Preceded by [[%d-%02d]]. " "$yyyy_prev" "$mm_prev"; printf "Followed by [[%d-%02d]]. " "$yyyy_next" "$mm_next"; @@ -101,6 +102,8 @@ printf "\n"; printf "==Ext. Links==\n"; printf "\n"; +printf "{{bk journal footer month}}\n"; + s1="[[Category:Journals by month]]"; printf "%s\n" "$s1"; printf "\n"; diff --git a/user/mw_create_month_journal_range.sh b/user/mw_create_month_journal_range.sh new file mode 100755 index 0000000..068987b --- /dev/null +++ b/user/mw_create_month_journal_range.sh @@ -0,0 +1,53 @@ +#!/usr/bin/env bash +# Desc: Wrapper for creating monthly journal page generation script +# Input: arg1: path mw_create_month_journal.sh +# arg2: year start +# arg3: year end +# Example: mw_create_month_journal_range.sh ./mw_create_month_journal.sh 2030 2040 +# Depends: BK-2020-03: mw_create_month_journal.sh +# Version: 1.0.0 + +# plumbing +path_cmj="$1"; # eg "$HOME/scripts/mw_create_month_journal.sh" +year_start="$2"; # eg 2030 +year_end="$3"; # eg 2040 +dir_out="./wikicode/"; + +yell() { echo "$0: $*" >&2; } # print script path and all args to stderr +die() { yell "$*"; exit 111; } # same as yell() but non-zero exit status +must() { "$@" || die "cannot $*"; } # runs args as command, reports args if command fails +check_depends() { + # check location of `mw_create_month_journal.sh` + if [[ ! -f "$path_cmj" ]]; then die "FATAL:Not found:$path_cmj"; fi; +}; +check_plumbing() { + if [[ ! -d "$dir_out" ]]; then + yell "STATUS:Creating missing dir_out:$dir_out"; + mkdir -p "$dir_out"; fi; +}; +main() { + check_depends; + check_plumbing; + + while read -r year; do + while read -r month; do + monthp="$(printf "%2d" "$month")"; + # Define and execute create monthly journal command + cmj_args+=("$year"); + cmj_args+=("$month"); + + # Define output file path + path_out="$dir_out"/"$(printf "%d-%02d" "$year" "$month")"; + + # Execute + "$path_cmj" "${cmj_args[@]}" > "$path_out"; + + unset cmj_args; + done < <(seq 1 12); # each month + done < <(seq "$year_start" "$year_end"); # each year +}; + +main "$@"; + +# Author: Steven Baltakatei Sandoval +# License: GPlv3+ diff --git a/user/mw_create_year_journal.sh b/user/mw_create_year_journal.sh new file mode 100755 index 0000000..e1a9925 --- /dev/null +++ b/user/mw_create_year_journal.sh @@ -0,0 +1,63 @@ +#!/usr/bin/env bash +# Desc: Prints mediawiki code for a journal year in the bk4 wiki. +# Usage: /bin/bash mw_create_year_journal.sh [int year] +# Input: arg1: year +# Example: /bin/bash mw_create_year_journal.sh 2023 > output.txt +# Version: 0.0.1 + +yyyy="$1"; + +yell() { echo "$0: $*" >&2; } # print script path and all args to stderr +die() { yell "$*"; exit 111; } # same as yell() but non-zero exit status +must() { "$@" || die "cannot $*"; } # runs args as command, reports args if command fails + +# Check input +## Check arg count +if [[ $# -ne 1 ]]; then die "FATAL:Invalid arg count:$#"; fi; +## Strip leading zeros +yyyy="$((10#${yyyy}))"; + +## Check year +re="[0-9]+"; +if [[ ! $yyyy =~ $re ]]; then die "FATAL:Invalid year string:$yyyy"; fi; +if [[ ! $yyyy -ge 1582 ]]; then die "FATAL:Invalid year string:$yyyy"; fi; + +# Calc working vars +## Years +yyyy_prev="$((yyyy - 1))"; +yyyy_next="$((yyyy + 1))"; + +# Form and print header +printf "{{bk journal header year}}\n"; +printf "[[Journal]] for the year [[%d]]. " "$yyyy"; +printf "Preceded by [[%d]]. " "$yyyy_prev"; +printf "Followed by [[%d]]. " "$yyyy_next"; +printf "\n\n"; + +printf "==Events==\n"; +printf "\n"; + +# Form and print body +for (( mm=1; mm <= 12; mm++ )); do + printf "==[[%4d-%02d]]==\n" "$yyyy" "$mm"; +done; +printf "\n"; + +# Form and print footer +s1="==References=="; +s2=""; +s3=""; +printf "%s\n%s\n%s\n" "$s1" "$s2" "$s3"; +printf "\n"; + +printf "==See Also==\n"; +printf "\n"; + +printf "==Ext. Links==\n"; +printf "\n"; + +printf "{{bk journal footer year}}\n"; + +s1="[[Category:Journals by year]]"; +printf "%s\n" "$s1"; +printf "\n"; diff --git a/user/mw_create_year_journal_range.sh b/user/mw_create_year_journal_range.sh new file mode 100755 index 0000000..63694ec --- /dev/null +++ b/user/mw_create_year_journal_range.sh @@ -0,0 +1,48 @@ +#!/usr/bin/env bash +# Desc: Wrapper for creating yearly journal page generation script +# Input: arg1: path mw_create_year_journal.sh +# arg2: year start +# arg3: year end +# Example: mw_create_year_journal_range.sh ./mw_create_year_journal.sh 2030 2040 +# Depends: BK-2020-03: mw_create_year_journal.sh +# Version: 0.0.1 + +# plumbing +path_cyj="$1"; # eg "$HOME/scripts/mw_create_year_journal.sh" +year_start="$2"; # eg 2030 +year_end="$3"; # eg 2040 +dir_out="./wikicode/"; + +yell() { echo "$0: $*" >&2; } # print script path and all args to stderr +die() { yell "$*"; exit 111; } # same as yell() but non-zero exit status +must() { "$@" || die "cannot $*"; } # runs args as command, reports args if command fails +check_depends() { + # check location of `mw_create_year_journal.sh` + if [[ ! -f "$path_cyj" ]]; then die "FATAL:Not found:$path_cyj"; fi; +}; +check_plumbing() { + if [[ ! -d "$dir_out" ]]; then + yell "STATUS:Creating missing dir_out:$dir_out"; + mkdir -p "$dir_out"; fi; +}; +main() { + check_depends; + check_plumbing; + + while read -r year; do + cyj_args+=("$year"); + + # Define output file path + path_out="$dir_out"/"$(printf "%d" "$year")"; + + # Execute + "$path_cyj" "${cyj_args[@]}" > "$path_out"; + + unset cyj_args; + done < <(seq "$year_start" "$year_end"); # each year +}; + +main "$@"; + +# Author: Steven Baltakatei Sandoval +# License: GPlv3+