Merge branch 'master' into develop 0.8.2
authorSteven Baltakatei Sandoval <baltakatei@gmail.com>
Sat, 8 Jul 2023 12:11:12 +0000 (12:11 +0000)
committerSteven Baltakatei Sandoval <baltakatei@gmail.com>
Sat, 8 Jul 2023 12:11:12 +0000 (12:11 +0000)
14 files changed:
unitproc/bkt-checkInt
unitproc/bkt-insertStr [new file with mode: 0755]
unitproc/python/bkt-humidity [new file with mode: 0644]
user/bk-copy-rand-music [changed mode: 0644->0755]
user/bk-find-git-verify
user/bkdatev
user/combine_pdfs.sh [new file with mode: 0755]
user/convert_file_to_flac.sh [changed mode: 0644->0755]
user/mp3s_to_mkv.sh [new file with mode: 0755]
user/mp3s_to_opus.sh [new file with mode: 0755]
user/mw_create_month_journal.sh
user/mw_create_month_journal_range.sh [new file with mode: 0755]
user/mw_create_year_journal.sh [new file with mode: 0755]
user/mw_create_year_journal_range.sh [new file with mode: 0755]

index cfe396ea83f5403bbe51b00764fa7fa42cb87a44..0922a141ed6630119caa93bc754a123149197026 100644 (file)
@@ -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 (executable)
index 0000000..5fdbf93
--- /dev/null
@@ -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 (file)
index 0000000..437adc7
--- /dev/null
@@ -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;
old mode 100644 (file)
new mode 100755 (executable)
index bc21e5b..b807286
@@ -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
index a94dc063169f428da5d6cdb454598289dc2b1030..333880f088590f59b8ea9c976621ff0bd9708240 100755 (executable)
@@ -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 '{}';    
index 22ff3103bdaeded393da434eec4d54af77e2d283..89388437f3701e4e16ec0baded8699c3eb0d3d8f 100755 (executable)
@@ -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
 #         * 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 (executable)
index 0000000..1c04cd0
--- /dev/null
@@ -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.
+
+
old mode 100644 (file)
new mode 100755 (executable)
diff --git a/user/mp3s_to_mkv.sh b/user/mp3s_to_mkv.sh
new file mode 100755 (executable)
index 0000000..eb32982
--- /dev/null
@@ -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 (executable)
index 0000000..0af92cc
--- /dev/null
@@ -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 "$@";
+
index 9ed0206d159a21ee43d66a065d647de438c2949b..b540fa9294251e0252f685bb6ba9ae77ad6d0ab3 100755 (executable)
@@ -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 (executable)
index 0000000..068987b
--- /dev/null
@@ -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 (executable)
index 0000000..e1a9925
--- /dev/null
@@ -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="<references>";
+s3="</references>";
+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 (executable)
index 0000000..63694ec
--- /dev/null
@@ -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+