lots of fixes, new music stuff
authorIan Kelling <ian@iankelling.org>
Fri, 13 Jan 2023 22:13:37 +0000 (17:13 -0500)
committerIan Kelling <ian@iankelling.org>
Fri, 13 Jan 2023 22:13:37 +0000 (17:13 -0500)
32 files changed:
.gitconfig
beets-gen-playlists [new file with mode: 0755]
brc
brc2
btrbk-run
disabled/docker
disabled/home-vpn/README.sh [new file with mode: 0644]
disabled/home-vpn/lan-dyn-dns-update [moved from lan-dyn-dns-update with 100% similarity]
disabled/home-vpn/vpn-client-connect [moved from vpn-client-connect with 100% similarity]
distro-begin
distro-end
dynamic-ip-update
filesystem/etc/systemd/system/navidrome.service [new file with mode: 0644]
filesystem/usr/local/bin/off [new file with mode: 0755]
filesystem/usr/local/bin/spend
filesystem/usr/local/bin/us [new file with mode: 0755]
i3-sway/common.conf
keyscript-on
mount-latest-subvol
music-tag-sync [deleted file]
navidrome-playlist-export [new file with mode: 0755]
pkgs
playlists/music/10.xsp [deleted file]
playlists/music/8.xsp [deleted file]
playlists/music/sad.xsp [deleted file]
playlists/music/sad5.xsp [deleted file]
playlists/music/sy most.xsp [deleted file]
primary-setup
subdir_files/.config/beets/config.yaml [deleted file]
subdir_files/.config/mpv/mpv.conf
switch-mail-host
transmission-firewall/netns.rules

index 0c27adc460c77faedef2797ce57d183c053f6bc0..6ee3a0f6fb9097af95cfcc77ac24105ed6ba5907 100644 (file)
@@ -82,3 +82,6 @@ default = simple
 # Send this email? ([y]es|[n]o|[e]dit|[q]uit|[a]ll): y
 [sendemail]
        confirm = auto
+# https://stackoverflow.com/questions/70663523/the-unauthenticated-git-protocol-on-port-9418-is-no-longer-supported
+[url "https://github.com/"]
+       insteadOf = git://github.com/
diff --git a/beets-gen-playlists b/beets-gen-playlists
new file mode 100755 (executable)
index 0000000..085946c
--- /dev/null
@@ -0,0 +1,96 @@
+#!/bin/bash
+
+# for generating playlist config yaml
+
+f=/usr/local/lib/err;test -r $f || { echo "error: $0 no $f" >&2;exit 1;}; . $f
+
+declare -A ignore_genres_a
+ignore_genres=(
+  skit
+  spoken-w
+)
+
+declare -A slow_genres_a
+slow_genres=(
+  ambient
+  avantg
+  classical
+  noise
+)
+
+tags=(
+  expl
+  sad
+)
+
+for g in ${ignore_genres[@]}; do
+  ignore_genres_a[$g]=t
+done
+for g in ${slow_genres[@]}; do
+  slow_genres_a[$g]=t
+done
+
+# genres that have a beat
+beat_genres=()
+
+# generate genres based on what is in the db.
+genres=()
+for g in $(beet ls -f '$genre' | sort -u); do
+  if [[ ${ignore_genres_a[$g]} ]]; then continue; fi
+  genres+=($g)
+  if [[ ${slow_genres_a[$g]} ]]; then continue; fi
+  beat_genres+=($g)
+done
+
+# generate regex for beat playlist
+beat_regex=
+first=true
+for g in ${beat_genres[@]}; do
+  if $first; then
+    first=false
+    beat_regex=$g
+  else
+    beat_regex+="|$g"
+  fi
+done
+
+
+for g in ${genres[@]}; do
+  for r in {3..5}; do
+    case $g in
+      pop|rap)
+        cat <<EOF
+    - name: ${g}-${r}.m3u
+      query: 'rating:${r}..5 genre:$g ^expl:t'
+    - name: ${g}e-${r}.m3u
+      query: 'rating:${r}..5 genre:$g'
+EOF
+        ;;
+      *)
+        cat <<EOF
+    - name: ${g}-${r}.m3u
+      query: 'rating:${r}..5 genre:$g'
+EOF
+        ;;
+    esac
+  done
+done
+
+for t in ${tags[@]}; do
+  for r in {3..5}; do
+    cat <<EOF
+    - name: ${t}-${r}.m3u
+      query: 'rating:${r}..5 $t:t'
+EOF
+
+  done
+done
+
+for r in {3..5}; do
+  cat <<EOF
+    - name: beat-${r}.m3u
+      query: 'rating:${r}..5 genre::$beat_regex ^expl:t'
+    - name: beate-${r}.m3u
+      query: 'rating:${r}..5 genre::$beat_regex'
+EOF
+done
diff --git a/brc b/brc
index 470c143f87a160b931ec323aeaff1840fbcc705f..3fbf9675907ae76ad457900da2de0d49fa58b920 100644 (file)
--- a/brc
+++ b/brc
@@ -260,6 +260,8 @@ if [[ $SOE ]]; then
 fi
 
 
+
+
 mysrc() {
   local path dir file
   path=$1
@@ -435,7 +437,7 @@ cl() {
   # we have ~33 buttons as of this writing, so lets
   # prune down the history every once in a while.
   if (( start > 500 )); then
-    tac ~/.cdirs | awk '!seen[$0]++' | head -n 200 | sponge ~/.cdirs
+    tac ~/.cdirs | awk '!seen[$0]++' | head -n 200 | tac | sponge ~/.cdirs || [[ $? == 141 ]]
   fi
 
   for (( j=$start; j >= 0; j-- )); do
@@ -458,7 +460,7 @@ cl() {
   fi
   read -r -N 1 input
   if [[ $input != $'\n' ]]; then
-    c ${buttondirs[$input]}
+    c "${buttondirs[$input]}"
   fi
 }
 # back list
@@ -703,7 +705,7 @@ bwm() {
 }
 
 
-# for running in a fai rescue
+# for running in a fai rescue. iank specific.
 kdrescue() {
   d=vgata-Samsung_SSD_850_EVO_2TB_S2RLNX0J502123D
   for f in $d vgata-Samsung_SSD_870_QVO_8TB_S5VUNG0N900656V; do
@@ -836,6 +838,10 @@ cat-new-files() {
 
 }
 
+chownme() {
+  s chown -R $USER:$USER "$@"
+}
+
 # shellcheck disable=SC2032
 chown() {
   # makes it so chown -R symlink affects the symlink and its target.
@@ -869,6 +875,26 @@ despace() {
   done
 }
 
+# df progress
+# usage: dfp MOUNTPOINT [SECOND_INTERVAL]
+# SECOND_INTERVAL defaults to 90
+dfp() {
+  # mp = mountpoint
+  local a b mp interval
+  mp=$1
+  interval=${2:-90}
+  if [[ ! $mp ]]; then
+    echo "dfp: error, missing 1st arg" >&2
+    return 1
+  fi
+  while true; do
+    a=$(df --output=used $mp | tail -n1)
+    sleep $interval
+    b=$(df --output=used $mp | tail -n1)
+    printf "used mib: %'d  mib/min: %s\n" $(( b /1000 )) $(( (b-a) / (interval * 1000 / 60 ) ))
+  done
+}
+
 # get ipv4 ip from HOST. or if it is already a number, return that
 hostip() {
   local host="$1"
@@ -942,7 +968,8 @@ ea() {
     printf "%s" "${arg}" |& hexdump -C
   done
 }
-# echo vars. print var including escapes, etc
+
+# echo variables. print var including escapes, etc, like xxd for variable
 ev() {
   if (( ! $# )); then
     echo no args
diff --git a/brc2 b/brc2
index 61bd93109a60b49b3e78c64b06f0bdbf680ae124..7e57ec94117f4b70dc76e50a6a3ebd2736a4cfa6 100644 (file)
--- a/brc2
+++ b/brc2
@@ -380,6 +380,264 @@ astudio() {
   /a/opt/android-studio/bin/studio.sh "$@" &r;
 }
 
+
+iki() {
+  local url path
+  if [[ $1 ]]; then
+    path="$*"
+  else
+    read -r -p "enter path" path
+  fi
+  url=$(readlink -f "$path")
+  url="https://brains.fsf.org/wiki/${url#*brains/}"
+  url="${url%.mdwn}"
+  echo "$url"
+  # /f/brains/sysadmin/interns/2022/nick_shrader/intro_blog_post.mdwn
+  # becomes
+  # https://brains.fsf.org/wiki/sysadmin/interns/2022/nick_shrader/intro_blog_post
+
+}
+
+# Generate beet smartplaylists for navidrome.
+# for going in the reverse direction, run
+# /b/ds/navidrome-playlist-export
+beetsmartplaylists() {
+  install -m 0700 -d /tmp/ianbeetstmp
+  beet splupdate
+  # kill off any playlists we deleted. they will still need manual
+  # killing from a navidrome client.
+  rm -rf /i/converted/beetsmartplaylists
+  mkdir -p /i/converted/beetsmartplaylists
+  for f in /tmp/ianbeetstmp/*; do
+    sed 's,^/i/m,/i/converted,;s,\.flac$,.mp3,' "$f" >"/i/converted/beetsmartplaylists/${f##*/}"
+    rm "$f"
+  done
+  rmdir /tmp/ianbeetstmp
+}
+
+# Export beets ratings into navidrome
+beetrating() {
+  local tmp tmpfile myuser userid rating path cpath sqlpath
+  # plucked this from the db. im the only user.
+  userid=23cc2eb9-e35e-4811-a0f0-d5f0dd6eb634
+  tmpfile=$(mktemp)
+  beet ls -f '$rating $path' ^genre:spoken-w ^genre:skit rating:2..5 >$tmpfile
+  while read -r rating path; do
+    tmp="/i/converted${path#/i/m}"
+    cpath="${tmp%.*}.mp3" # converted path
+    sqlpath="${cpath//\'/\'\'}"
+    old_rating=$(sqlite3 /i/navidrome/navidrome.db "select rating from annotation inner join media_file on item_id = id where path = '$sqlpath' and item_type = 'media_file';")
+    if [[ $old_rating ]]; then
+      if [[ $old_rating != $rating ]]; then
+        # https://stackoverflow.com/a/50317320
+        m sqlite3 /i/navidrome/navidrome.db "
+update annotation set rating = $rating
+ where item_id in (
+ select media_file.id from annotation inner join media_file on annotation.item_id = media_file.id
+   where media_file.path = '$sqlpath' and annotation.item_type = 'media_file' );"
+      fi
+    else
+      # /a/opt/navidrome/persistence/sql_annotations.go v0.48.0
+      # https://www.sqlite.org/lang_insert.html
+      m sqlite3 /i/navidrome/navidrome.db "insert into annotation select '$(uuidgen)', '$userid', id, 'media_file', 0, NULL, $rating, 0, NULL from media_file where path = '$sqlpath';"
+    fi
+    #sqlite3 /i/navidrome/navidrome.db "select path from annotation inner join media_file on item_id = id where rating = $r;"
+  done <$tmpfile
+}
+
+# Do transcoding and hardlinking of audio files for navidrome.
+#
+# Deletes files in the converted directory which should no longer
+# be there due to a rename of the unconverted file.
+beetconvert() {
+  # directs to avoid printing every file
+  beet convert -y ^genre:spoken-w ^genre:skit ^rating:1 >/dev/null 2> >(grep -v '^convert: Skipping' ||:)
+  local l
+  local -A paths
+  while read -r l; do
+    convertedpath="/i/converted${l#/i/m}"
+    case $convertedpath in
+      *.flac) convertedpath="${convertedpath%.flac}.mp3" ;;
+    esac
+    paths[$convertedpath]=t
+  done < <(beet ls -f '$path' ^genre:spoken-w ^genre:skit ^rating:1)
+  while read -r l; do
+    if [[ ! ${paths[$l]} ]]; then
+      rm -v "$l"
+    fi
+  done < <(find /i/converted -path /i/converted/beetsmartplaylists -prune -o \( -type f -print \))
+}
+
+# tag with beets.
+# usage: beetag QUERY
+# it lists the query, reads an input char for tagging one by one
+# 1-5 = set rating
+# a-z+ = set genre/playlist.
+# enter = next song
+# , = play song
+beetag() {
+  if (( ! $# )); then
+    echo beetag: error expected a query arg >&2
+    return 1
+  fi
+  local last_genre_i fstring tag id char new_item char_i genre tag remove
+  local -a genres pl_tags buttons button_map ids tags
+  local -A button_i
+  genres=(
+    ambient
+    avant
+    blues
+    classical
+    country
+    # like power glove
+    dark-wave
+    hardcore
+    instrumental
+    jazz
+    latin
+    metal
+    musical
+    # mq = mac quale. similar to the mr robot soundtracks.
+    # slow, foreboding. usually electronic.
+    mq
+    noise
+    pop
+    rap
+    rock
+    skit
+    spoken-w
+    techno
+    world
+  )
+  pl_tags=(
+    expl
+    love
+    pump1
+    pumprap
+    rend
+    run
+    sad
+  )
+  last_genre_i=$(( ${#genres[@]} - 1 ))
+  buttons=( {a..z} 0 {6..9} )
+  button_map=(${genres[@]} ${pl_tags[@]})
+  fstring=
+  for tag in "${pl_tags[@]}"; do
+    fstring+="%ifdef{$tag,$tag }"
+  done
+
+  for (( i=0; i<${#buttons[@]}; i++ )); do
+    button_i[${buttons[i]}]=$i
+  done
+  beet ls -f '%ifdef{rating,$rating }'"$fstring"', $genre $artist - $album - $title' "$@"
+  hr
+  mapfile -t ids < <(beet ls -f '$id' "$@")
+  for id in "${ids[@]}"; do
+    lsout="$(beet ls -f '%ifdef{rating,$rating }'"$fstring"', $genre $id $artist - $album - $title' "id:$id")"
+    tags=( ${lsout%%,*} )
+    printf "%s\n" "$lsout"
+    for (( i=0; i<${#button_map[@]}; i++ )); do
+      echo ${buttons[i]} ${button_map[i]}
+    done
+    while true; do
+      read -r -N 1 -s char
+      if [[ $char == $'\n' ]]; then
+        break
+      fi
+      case $char in
+        ,)
+          beet play "id:$id"
+          continue
+          ;;
+        [1-5])
+          beet modify -y "id:$id" rating=$char
+          continue
+          ;;
+      esac
+      char_i=${button_i[$char]}
+      new_item=${button_map[$char_i]}
+      if [[ ! $char_i || ! $new_item ]]; then
+        echo "error: no mapping of input found, try again"
+        continue
+      fi
+      if (( char_i <= last_genre_i )); then
+        m beet modify -y "id:$id" genre=$new_item
+      else
+        remove=false
+        for tag in ${tags[@]}; do
+          if [[ $new_item == "$tag" ]]; then
+            remove=true
+            break
+          fi
+        done
+        if $remove; then
+          m beet modify -y "id:$id" "$new_item!"
+        else
+          m beet modify -y "id:$id" $new_item=t
+        fi
+      fi
+    done
+  done
+
+  # sadpop
+  #
+  # rending:
+  # two dollar guitar: speed
+  # black heard procession
+  # strong enough sheryl crow
+  #
+  #
+}
+
+# escape regex.
+#
+# This is not perfect but generally good enough. It escapes all
+# metachars listed man 3 pcrepattern.
+er() {
+  sed 's/[]\\^$.[|()?*+{}]/[&]/g; s/\^/\\^/g' <<<"$*"
+}
+
+# usage beegenre QUERY
+#
+# beet set genre for QUERY based on existing artist most used genre on
+#
+# inverse of query for each artist found in QUERY. If query starts with
+# "artist:" it is used as the artist instead of each artist in QUERY.
+#
+beegenre() {
+  local artist artregex genre term singleartist
+  local -a artists genres terms
+  singleartist=false
+  case $1 in
+    artist:*)
+      singleartist=true
+      artist="$term"
+      ;;
+  esac
+  if $singleartist; then
+    read count genre < <(beet ls -f '$genre' "$artist" "${@/#/^}" | sort | uniq -c | sort -n | tail -n1) ||:
+    beet modify "$artist" "$@" genre=$genre
+  else
+    while read -r artist; do
+      artregex=$(er "$artist")
+      read count genre < <(beet ls -f '$genre' "artist::^$artregex$" "${@/#/^}" | sort | uniq -c | sort -n | tail -n1) || continue
+      if [[ $count ]]; then
+        artists+=("$artregex")
+        genres+=("$genre")
+        echo "beet modify -y $@ \"artist::^$artist$\" genre=$genre # $count"
+      fi
+    done < <(beet ls -f '$artist' "$@" | sort -u)
+    read -r -N 1 -s -p "Y/n " char
+    case $char in
+      [Yy$'\n'])
+        for (( i=0; i<${#artists[@]}; i++ )); do
+          beet modify -y "$@"  "artist::^${artists[i]}$" genre=${genre[i]}
+        done
+        ;;
+    esac
+  fi
+}
+
 # note, to check for glue records
 # First, find some the .org nameservers:
 # dig +trace iankelling.org
@@ -1268,7 +1526,7 @@ lom() {
       m sudo losetup $l $fs_file
     fi
     if ! sudo cryptsetup status /dev/mapper/$base &>/dev/null; then
-      if ! sudo cryptsetup luksOpen $l $base; then
+      if ! sudo cryptsetup luksOpen $l $base; then
         m sudo losetup -d $l
         return 1
       fi
@@ -1419,6 +1677,9 @@ mpvm() {
   # get page source of https://en.wikipedia.org/w/index.php?title=Video_file_format&action=edit
   # into /a/x.log, then
   # grep '^| *\.' /a/x.log | sed 's/| *//;s/,//g'
+
+  #  note: to join them together for a regex, do:
+  # old=; for e in ${extensions[@]/./}; do if [[ ! $old ]]; then old=$e; continue; fi; echo -n "$old|"; old=$e; done; echo $e
   extensions=(
     .webm
     .mkv
index 86d29e0c7cae496ebbd20f80e6d9be83dab833bd..50e64b811f0809d2a9a09161534f5750d2e1b46a 100644 (file)
--- a/btrbk-run
+++ b/btrbk-run
@@ -40,7 +40,9 @@ EOF
 
 
 
-pre="${0##*/}: "
+script_name="${BASH_SOURCE[0]}"
+script_name="${script_name##*/}"
+pre="${SSH_CLIENT:+$HOSTNAME} $script_name:"
 m() { if $verbose; then printf "$pre%s\n"  "$*"; fi;  "$@"; }
 e() { printf "$pre%s\n"  "$*"; }
 die() { printf "$pre%s\n" "$*" >&2; echo "exiting with status 1" >&2; exit 1; }
@@ -82,10 +84,11 @@ if [[ -s $default_args_file ]]; then
   sleep 5
 fi
 
+targets=()
 early=false
 cron=false
 orig_args=("$@")
-temp=$(getopt -l cron,pull-reexec,help ceil:m:npqrs:t:vh "$@") || usage 1
+temp=$(getopt -l cron,pull-reexec,help 23ceil:m:npqrs:t:vh "$@") || usage 1
 eval set -- "$temp"
 while true; do
   case $1 in
@@ -96,24 +99,26 @@ while true; do
     --cron)
       cron=true
       pre=
-      shift
       ;;
+    # for the rare case we want to run multiple instances at the same time
+    -2) conf_suf=2 ;;
+    -3) conf_suf=3 ;;
     # only creates the config file, does not run btrbk
-    -c) conf_only=true; shift ;;
+    -c) conf_only=true ;;
     # quit early, just btrbk, no extra remounting etc.
-    -e) early=true; shift ;;
-    -i) incremental_strict=true; shift ;;
+    -e) early=true ;;
+    -i) incremental_strict=true ;;
     # bytes per second, suffix k m g
-    -l) rate_limit=$2; shift ;;
+    -l) rate_limit=$2; shift ;;
     # Comma separated mountpoints to backup. This has defaults set below.
-    -m) IFS=, mountpoints=($2); unset IFS; shift ;;
-    -n) dry_run=true; dry_run_arg=-n; shift ;;
+    -m) IFS=, mountpoints=($2); unset IFS; shift ;;
+    -n) dry_run=true ;;
     # hide progress
-    -p) progress_arg=; shift ;;
+    -p) progress_arg= ;;
     # internal option for rerunning under newer SOURCE_HOST version.
-    --pull-reexec) pull_reexec=true; shift ;;
+    --pull-reexec) pull_reexec=true;;
     # quiet
-    -q) verbose=false; verbose_arg=; progress_arg=; shift ;;
+    -q) verbose=false; verbose_arg=; progress_arg= ;;
     # source host to receive a backup from
     -s)
       source=$2
@@ -121,24 +126,25 @@ while true; do
       if [[ $source == *:* ]]; then
         bbksource="[$source]"
       fi
-      shift 2
+      shift
       ;;
     # target hosts to send to. empty is valid for just doing local
     # snapshot. we have default hosts we will populate.
-    -t) IFS=, targets=($2); unset IFS; shift ;;
+    -t) IFS=, targets=($2); unset IFS; shift ;;
     # verbose.
-    -v) verbose=true; verbose_arg=-v; shift ;;
+    -v) verbose=true; verbose_arg=-v ;;
     -h|--help) usage ;;
     --) shift; break ;;
     *) die "Internal error!" ;;
   esac
+  shift
 done
 
 cmd_arg=${1:-run}
 
 
 std_preserve="36h 14d 8w 24m"
-q_preserve="18h 14d"
+q_preserve="18h 14d 8w"
 
 case $cmd_arg in
   run|resume) : ;;
@@ -170,7 +176,7 @@ if [[ -v targets && $source ]]; then
 fi
 
 if $verbose; then
-  printf "options: conf_only=%s\ndry_run=%s\nrate_limit=%s\nverbose=%s\ncmd_arg=%s" "$conf_only" "$dry_run" "$rate_limit" "$verbose" "$cmd_arg"
+  printf "$pre options: conf_only=%s\ndry_run=%s\nrate_limit=%s\nverbose=%s\ncmd_arg=%s" "$conf_only" "$dry_run" "$rate_limit" "$verbose" "$cmd_arg"
 fi
 ### end options parsing
 
@@ -209,74 +215,73 @@ if [[ ! -v targets && ! $source ]]; then
   kd_spread=false
 
   at_work=false
+  at_home=false
+
+  case $HOSTNAME in
+    kw|kd|frodo|x2|x3|sy) : ;;
+    *)
+      die "error: no default targets for this host, use -t"
+      ;;
+  esac
 
-  # todo, fix this up once frodo is back
-  # targets=(frodo.b8.nz)
   case $HOSTNAME in
     kw)
       at_work=true
       ;;&
-    x2|x3|sy|bo)
-      if ping -q -c1 -w1 hal.office.fsf.org \
+    kd|frodo)
+      at_home=true
+      ;;&
+    x2|x3|sy)
+      if [[ $(dig +short @10.2.0.1 -x 10.2.0.2 2>&1 ||:) == kd.b8.nz. ]] \
+           && ip n show 10.2.0.1 | grep . &>/dev/null; then
+        at_home=true
+      elif ping -q -c1 -w1 hal.office.fsf.org &>/dev/null \
           && ip n show 192.168.0.26 | grep . &>/dev/null; then
         at_work=true
       fi
       ;;&
-    kw|x2|x3|sy|bo)
-      if $at_work; then
-        if ping -q -c1 -w1 iank.vpn.office.fsf.org &>/dev/null; then
-          home=iank.vpn.office.fsf.org
-        else
-          home=i.b8.nz
-        fi
-      else
-        if ping -q -c1 -w1 b8.nz &>/dev/null; then
-          home=b8.nz
+    *)
+      if $at_home; then
+        # main work machine
+        if ping -q -c1 -w1 x3.office.fsf.org &>/dev/null; then
+          targets+=(x3.office.fsf.org)
         else
-          home=i.b8.nz
+          targets+=(x3wg.b8.nz)
         fi
-      fi
-      ;;&
-    x2)
-      targets+=($home)
-      ;;
-    kw)
-      targets+=($home x2.office.fsf.org)
-      ;;
-    x3|sy|bo)
-      targets+=($home)
-      if $at_work; then
-        targets+=(x2.office.fsf.org x2.b8.nz)
-      else
-        targets+=(x2wg.b8.nz)
-      fi
-      ;;
-    kd)
-      if ! $kd_spread; then
-        if ping -q -c1 -w1 x2.office.fsf.org &>/dev/null; then
-          targets+=(x2.office.fsf.org)
+        for h in frodo kd; do
+          if [[ $HOSTNAME == "$h" ]]; then
+            continue
+          fi
+          targets+=($h.b8.nz)
+        done
+        for h in x2 x3 sy; do
+          if [[ $HOSTNAME == "$h" ]]; then
+            continue
+          fi
+          if ping -q -c1 -w1 $h.b8.nz &>/dev/null; then
+            targets+=($h.b8.nz)
+          elif ping -q -c1 -w1 ${h}w.b8.nz &>/dev/null; then
+            targets+=(${h}w.b8.nz)
+          fi
+        done
+      elif $at_work; then
+        if ping -q -c1 -w1 iank.vpn.office.fsf.org &>/dev/null; then
+          targets+=(iank.vpn.office.fsf.org)
         else
-          targets+=(x2wg.b8.nz)
+          targets+=(i.b8.nz)
         fi
-      fi
-      if ping -q -c1 -w1 sy.b8.nz &>/dev/null; then
-        targets+=(sy.b8.nz)
-      else
-        targets+=(syw.b8.nz)
-      fi
-      if ping -q -c1 -w1 x3.b8.nz &>/dev/null; then
-        targets+=(x3.b8.nz)
+        for h in x2 x3 kw; do
+          if [[ $HOSTNAME == "$h" ]]; then
+            continue
+          fi
+          if ping -q -c1 -w1 $h.office.fsf.org &>/dev/null; then
+            targets+=($h.office.fsf.org)
+          fi
+        done
       else
-        targets+=(x3w.b8.nz)
+        targets+=(i.b8.nz)
       fi
       ;;
-    frodo)
-      # no targets
-      targets=()
-      ;;
-    *)
-      die "error: no default targets for this host, use -t"
-      ;;
   esac
 fi
 
@@ -300,9 +305,6 @@ else
     prospective_mps=(/a)
   else
     case $HOSTNAME in
-      frodo)
-        prospective_mps=(/i)
-        ;;
       *)
         prospective_mps=()
         if [[ $source ]]; then
@@ -383,7 +385,7 @@ if ! command -v btrbk &>/dev/null; then
 fi
 # if our mountpoints are from stale snapshots,
 # it doesn't make sense to do a backup.
-check-subvol-stale ${mountpoints[@]} || die "found stale mountpoints in ${mountpoints[*]}"
+check-subvol-stale ${mountpoints[@]} || die "found stale mountpoints in ${mountpoints[*]}"
 
 # for an initial run, btrbk requires the dir to exist.
 mkdir -p /mnt/{root,o}/btrbk
@@ -464,7 +466,7 @@ else
 fi
 
 
-cat >/etc/btrbk.conf <<EOF
+cat >/etc/btrbk$conf_suf.conf <<EOF
 ssh_identity /q/root/h
 #ssh_identity /root/.ssh/home
 
@@ -480,7 +482,7 @@ transaction_syslog local7
 #stream_compress zstd
 
 # so we only run one at a time
-lockfile                   /var/lock/btrbk.lock
+lockfile                   /var/lock/btrbk$conf_suf.lock
 
 # default format of short does not accomidate hourly preservation setting
 timestamp_format long-iso
@@ -504,11 +506,36 @@ rate_limit $rate_limit
 EOF
 
 if $incremental_strict; then
-  cat >>/etc/btrbk.conf <<EOF
+  cat >>/etc/btrbk$conf_suf.conf <<EOF
 incremental strict
 EOF
 fi
 
+qconf() {
+  case $sub in
+    q)
+      # q has sensitive data i dont want to backup for so long
+      cat >>/etc/btrbk$conf_suf.conf <<EOF
+snapshot_preserve $q_preserve
+snapshot_preserve_min 2h
+snapshot_dir btrbk
+target_preserve $q_preserve
+target_preserve_min 2h
+EOF
+      ;;
+  esac
+
+}
+
+# make /q be last
+mp_count=${#mountpoints[@]}
+for (( i=0; i < mp_count - 1 ; i++ )); do
+  if [[ ${mountpoints[i]} == /q ]]; then
+    unset mountpoints[i]
+    mountpoints+=(/q)
+  fi
+done
+
 for m in ${mountpoints[@]}; do
   case $m in
     /o)
@@ -521,35 +548,27 @@ for m in ${mountpoints[@]}; do
 
   sub=${m#/}
   if [[ $source ]]; then
-    cat >>/etc/btrbk.conf <<EOF
+    cat >>/etc/btrbk$conf_suf.conf <<EOF
 volume ssh://$bbksource$vol
 subvolume $sub
+EOF
+    qconf
+    cat >>/etc/btrbk$conf_suf.conf <<EOF
 target send-receive $vol/btrbk
 EOF
   fi
   if (( ${#targets[@]} )); then
-    cat >>/etc/btrbk.conf <<EOF
+    cat >>/etc/btrbk$conf_suf.conf <<EOF
 volume $vol
 subvolume $sub
 EOF
-    case $sub in
-      q)
-        # q has sensitive data i dont want to backup for so long
-        cat >>/etc/btrbk.conf <<EOF
-snapshot_preserve $std_preserve
-snapshot_preserve_min 2h
-snapshot_dir btrbk
-target_preserve $std_preserve
-target_preserve_min 2h
-EOF
-        ;;
-    esac
+    qconf
     for tg in ${targets[@]}; do
       # handle ipv6
       if [[ $tg == *:* ]]; then
         tg="[$tg]"
       fi
-      cat >>/etc/btrbk.conf <<EOF
+      cat >>/etc/btrbk$conf_suf.conf <<EOF
 target send-receive ssh://$tg$vol/btrbk
 EOF
     done
@@ -567,12 +586,16 @@ fi
 
 
 if $dry_run; then
-  m btrbk -v -n $cmd_arg
+  m btrbk -c /etc/btrbk$conf_suf.conf -v -n $cmd_arg
   mexit 0
 fi
 # -q and just using the syslog option seemed nice,
 # but it doesn't show when a send has a parent and when it doesn't.
-m btrbk $preserve_arg $verbose_arg $progress_arg $cmd_arg
+m btrbk -c /etc/btrbk$conf_suf.conf $preserve_arg $verbose_arg $progress_arg $cmd_arg
+
+if $early; then
+  exit 0
+fi
 
 # todo: tp not valid anymore.
 # if we have it, sync to systems which don't
index bd9d198a67730c92127016df26efd9cd05f749a0..929f4d665c2258ff8dfcbc9c78c60a5fc321e163 100644 (file)
@@ -1,7 +1,18 @@
 
 ### begin docker install ####
 if isdeb; then
-  # https://store.docker.com/editions/community/docker-ce-server-debian?tab=description
+# https://docs.docker.com/engine/install/ubuntu/
+
+sudo mkdir -p /etc/apt/keyrings
+
+ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
+
+# lsb_release -cs -> debian-codename-compat
+echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(debian-codename-compat) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
+
+p update
+
+
   pi  software-properties-common apt-transport-https
   curl -fsSL https://download.docker.com/linux/$(distro-name-compat)/gpg | sudo apt-key add -
   url=https://download.docker.com/linux/$(distro-name-compat)
diff --git a/disabled/home-vpn/README.sh b/disabled/home-vpn/README.sh
new file mode 100644 (file)
index 0000000..bded195
--- /dev/null
@@ -0,0 +1,43 @@
+# this was in distro-end.
+#
+# Disabled because basically I don't need a home vpn and prefer just
+# port forwarding as needed.
+
+### begin home vpn server setup
+
+
+# # this section done initially to make persistent keys.
+# # Also note, I temporarily set /etc/hosts so my host was
+# # b8.nz when running this, since the vpn client config
+# # generator assumes we need to go to that server to get
+# # server keys.
+# vpn-server-setup -rds
+# s cp -r --parents /etc/openvpn/easy-rsa/keys /p/c/filesystem
+# s chown -R 1000:1000 /p/c/filesystem/etc/openvpn/easy-rsa/keys
+# # kw = kgpe work machine.
+# for host in x2 x3 kw; do
+# vpn-mk-client-cert -b $host -n home b8.nz 1196
+# dir=/p/c/machine_specific/$host/filesystem/etc/openvpn/client
+# mkdir -p $dir
+# s bash -c "cp /etc/openvpn/client/home* $dir"
+#     # note: /etc/update-resolv-conf-home also exists for all systems with /p
+# done
+
+# key already exists, so this won't generate one, just the configs.
+# m vpn-server-setup -rds
+# sudo tee -a /etc/openvpn/server/server.conf <<'EOF'
+# push "dhcp-option DNS 10.0.0.1"
+# push "route 10.0.0.0 255.255.0.0"
+# client-connect /a/bin/distro-setup/vpn-client-connect
+# EOF
+# sudo sed -i --follow-symlinks 's/10.8./10.9./g;s/^\s*port\s.*/port 1196/' /etc/openvpn/server/server.conf
+
+# if [[ $HOSTNAME == tp ]]; then
+#   if [[ -e /lib/systemd/system/openvpn-server@.service ]]; then
+#     vpn_service=openvpn-server@server
+#   else
+#     vpn_service=openvpn@server
+#   fi
+#   sgo $vpn_service
+# fi
+### end vpn server setup
index 4b591c15f536b921921701d9d18d484c1d1de6f1..9780ed65226a08ab3b12861b154aaa4f9fc94469 100755 (executable)
@@ -100,7 +100,7 @@ source $script_dir/pkgs
 set +x
 source /a/bin/distro-functions/src/identify-distros
 $interactive || set -x
-for f in kd x2 x3 frodo tp li bk je demohost kw sy bo; do
+for f in kd x2 x3 x8 frodo tp li bk je demohost kw sy bo; do
   eval "$f() { [[ $HOSTNAME == $f ]]; }"
 done
 codename=$(debian-codename)
@@ -645,6 +645,17 @@ EOF
       fi
     fi
     ;;
+  frodo)
+    tu /etc/fstab <<'EOF'
+/dev/mapper/crypt_dev_ata-ata-Hitachi_HDS722020ALA330_JK1121YAG7SXWS-part1  /i  btrfs  nofail,x-systemd.device-timeout=30s,x-systemd.mount-timeout=30s,noatime,subvol=i  0 0
+EOF
+    if ! mountpoint /i &>/dev/null; then
+      sudo mkdir -p /i
+      if [[ -d /mnt/i/i ]]; then
+        sudo mount /i
+      fi
+    fi
+    ;;
 esac
 
 if bitfolk; then
index 32a4b0e97273193a04a7ce44d2ed6043b0483af9..6efe7bf347e92816a728bcde8520d804867380bc 100755 (executable)
@@ -672,52 +672,47 @@ EOF
 client-to-client
 EOF
 
-    # sullivan d8
-    sd /etc/openvpn/client-config-hole/sd8 <<'EOF'
-ifconfig-push 10.5.5.41 255.255.255.0
-EOF
-    # hsieh d8
-    sd /etc/openvpn/client-config-hole/hd8 <<'EOF'
-ifconfig-push 10.5.5.42 255.255.255.0
-EOF
-
-    sd /etc/openvpn/client-config-hole/onep9 <<'EOF'
-ifconfig-push 10.5.5.14 255.255.255.0
+    sd /etc/openvpn/client-config-hole/kd <<'EOF'
+ifconfig-push 10.5.5.2 255.255.255.0
 EOF
-    sd /etc/openvpn/client-config-hole/bo <<'EOF'
-ifconfig-push 10.5.5.13 255.255.255.0
+    sd /etc/openvpn/client-config-hole/tp <<'EOF'
+ifconfig-push 10.5.5.3 255.255.255.0
 EOF
-    sd /etc/openvpn/client-config-hole/sy <<'EOF'
-ifconfig-push 10.5.5.12 255.255.255.0
+    sd /etc/openvpn/client-config-hole/frodo <<'EOF'
+ifconfig-push 10.5.5.5 255.255.255.0
 EOF
-    sd /etc/openvpn/client-config-hole/kw <<'EOF'
-ifconfig-push 10.5.5.9 255.255.255.0
+    sd /etc/openvpn/client-config-hole/x2 <<'EOF'
+ifconfig-push 10.5.5.7 255.255.255.0
 EOF
     sd /etc/openvpn/client-config-hole/x3 <<'EOF'
 ifconfig-push 10.5.5.8 255.255.255.0
 EOF
-    sd /etc/openvpn/client-config-hole/x2 <<'EOF'
-ifconfig-push 10.5.5.7 255.255.255.0
-EOF
-    sd /etc/openvpn/client-config-hole/wclient <<'EOF'
-ifconfig-push 10.5.5.6 255.255.255.0
+    sd /etc/openvpn/client-config-hole/kw <<'EOF'
+ifconfig-push 10.5.5.9 255.255.255.0
 EOF
-    sd /etc/openvpn/client-config-hole/frodo <<'EOF'
-ifconfig-push 10.5.5.5 255.255.255.0
+    sd /etc/openvpn/client-config-hole/sy <<'EOF'
+ifconfig-push 10.5.5.12 255.255.255.0
 EOF
-    sd /etc/openvpn/client-config-hole/amy <<'EOF'
-ifconfig-push 10.5.5.3 255.255.255.0
+    sd /etc/openvpn/client-config-hole/bo <<'EOF'
+ifconfig-push 10.5.5.13 255.255.255.0
 EOF
-    sd /etc/openvpn/client-config-hole/kd <<'EOF'
-ifconfig-push 10.5.5.2 255.255.255.0
+    sd /etc/openvpn/client-config-hole/onep9 <<'EOF'
+ifconfig-push 10.5.5.14 255.255.255.0
 EOF
+    # todo: add x8?
+
 
-    # for adding to current system:
-    #vpn-mk-client-cert -s "" -n hole 72.14.176.105
-    # adding to remove system 107,
-    #vpn-mk-client-cert -s "" -n hole -c 10.2.0.107 -b hd8 iankelling.org
+    # for adding cert to system with /p
+    #
+    # host=frodo
+    #mkc /p/c/machine_specific/$host/filesystem/etc/openvpn/client
+    #vpn-mk-client-cert -b $host -n hole -r  iankelling.org
+    #s chown -R iank:iank .
     #
-    # for wireguard hole vpn
+    # example of adding to remote system 107,
+    # vpn-mk-client-cert -n hole -c 10.2.0.107 -b hd8 iankelling.org
+    #
+    # for wireguard hole vpn, use function:
     # wghole
 
     # requested from linode via a support ticket.
@@ -1118,45 +1113,6 @@ sudo rm -fv /etc/apt/sources.list.d/iridium-browser.list
 # esac
 
 
-### begin home vpn server setup
-
-
-# # this section done initially to make persistent keys.
-# # Also note, I temporarily set /etc/hosts so my host was
-# # b8.nz when running this, since the vpn client config
-# # generator assumes we need to go to that server to get
-# # server keys.
-# vpn-server-setup -rds
-# s cp -r --parents /etc/openvpn/easy-rsa/keys /p/c/filesystem
-# s chown -R 1000:1000 /p/c/filesystem/etc/openvpn/easy-rsa/keys
-# # kw = kgpe work machine.
-# for host in x2 x3 kw; do
-# vpn-mk-client-cert -b $host -n home b8.nz 1196
-# dir=/p/c/machine_specific/$host/filesystem/etc/openvpn/client
-# mkdir -p $dir
-# s bash -c "cp /etc/openvpn/client/home* $dir"
-#     # note: /etc/update-resolv-conf-home also exists for all systems with /p
-# done
-
-# key already exists, so this won't generate one, just the configs.
-# m vpn-server-setup -rds
-# sudo tee -a /etc/openvpn/server/server.conf <<'EOF'
-# push "dhcp-option DNS 10.0.0.1"
-# push "route 10.0.0.0 255.255.0.0"
-# client-connect /a/bin/distro-setup/vpn-client-connect
-# EOF
-# sudo sed -i --follow-symlinks 's/10.8./10.9./g;s/^\s*port\s.*/port 1196/' /etc/openvpn/server/server.conf
-
-# if [[ $HOSTNAME == tp ]]; then
-#   if [[ -e /lib/systemd/system/openvpn-server@.service ]]; then
-#     vpn_service=openvpn-server@server
-#   else
-#     vpn_service=openvpn@server
-#   fi
-#   sgo $vpn_service
-# fi
-### end vpn server setup
-
 ##### rss2email
 if mountpoint /p &>/dev/null; then
   # note, see bashrc for more documentation.
@@ -1234,10 +1190,6 @@ if [[ -e /p/c/machine_specific/$HOSTNAME/filesystem/etc/openvpn/client/hole.crt
   sgo openvpn-client@hole
 fi
 
-if [[ $HOSTNAME == frodo ]]; then
-  vpn-mk-client-cert -b frodo -n hole iankelling.org
-fi
-
 ############# begin syncthing setup ###########
 case $HOSTNAME in
   kd|frodo)
@@ -1532,7 +1484,7 @@ case $HOSTNAME in
     ;;
 esac
 
-mkdir -p $tdir
+sudo mkdir -p $tdir
 
 # adapted from /var/lib/dpkg/info/transmission-daemon.postinst
 # 450 seems likely to be unused. we need to specify one or else
@@ -1582,7 +1534,7 @@ ser stop transmission-daemon
 f=$tdir/transmission-daemon
 for d in $tdir/partial-torrents $tdir/torrents $f; do
   if [[ ! -d $d ]]; then
-    mkdir $d
+    sudo mkdir -p $d
   fi
   sudo chown -R debian-transmission:user2 $d
 done
@@ -1840,11 +1792,6 @@ rm -fv /home/iank/.mpv/watch_later
 rm -rf /home/iank/.mpv
 
 
-if [[ $HOSTNAME != frodo ]]; then
-  # remove. i moved this into dns
-  echo | s cedit hole /etc/hosts ||:
-fi
-
 if [[ ! -e ~/.local/bin/pip ]]; then
   tmp=$(mktemp)
   wget -O$tmp https://bootstrap.pypa.io/get-pip.py
@@ -1928,13 +1875,13 @@ sudo fc-cache
 pi desktop-file-utils
 m /a/bin/distro-setup/mymimes
 
-
-# stop autopoping windows when i plug in an android phone.
-# dbus-launch makes this work within an ssh connection, otherwise you get this message,
-# with still 0 exit code.
-# dconf-WARNING **: failed to commit changes to dconf: Cannot autolaunch D-Bus without X11 $DISPLAY
-m dbus-launch gsettings set org.gnome.desktop.media-handling automount-open false
-
+if type -p dbus-launch >/dev/null; then
+  # stop autopoping windows when i plug in an android phone.
+  # dbus-launch makes this work within an ssh connection, otherwise you get this message,
+  # with still 0 exit code.
+  # dconf-WARNING **: failed to commit changes to dconf: Cannot autolaunch D-Bus without X11 $DISPLAY
+  m dbus-launch gsettings set org.gnome.desktop.media-handling automount-open false
+fi
 
 # on grub upgrade, we get prompts unless we do this
 devs=()
@@ -2021,8 +1968,6 @@ EOF
 esac
 
 case $HOSTNAME in
-  # frodo needs upgrade first.
-  frodo) : ;;
   # todo, for limiting node exporter http,
   # either use iptables or, in
   # /etc/default/prometheus-node-exporter
@@ -2209,7 +2154,7 @@ lnf -T /a/opt ~/src
 pi tor
 m /a/bin/buildscripts/tor-browser
 # one root command needed to install
-s ln -sf /a/opt/tor-browser_en-US/Browser/start-tor-browser /usr/local/bin
+s ln -sf /a/opt/tor-browser/Browser/start-tor-browser /usr/local/bin
 
 
 # nfs server
index 1e6cabbf0fce19f9118596b3aec207ec18e22c25..f75bd05368864a198ae0b17e428aa8b8558b0d23 100755 (executable)
@@ -1,5 +1,47 @@
 #!/bin/bash
-source ~/.bashrc
+
+f=/usr/local/lib/err;test -r $f || { echo "error: $0 no $f" >&2;exit 1;}; . $f
+[[ $EUID == 0 ]] || exec sudo -E "${BASH_SOURCE[0]}" "$@"
+
+this_file="$(readlink -f -- "${BASH_SOURCE[0]}")"
+readonly this_file
+this_dir="${this_file%/*}"
+readonly this_dir
+cd "$this_dir"
+
+usage() {
+  cat <<EOF
+Usage: ${0##*/} [-f]
+Update ip in remote nameserver.
+
+-f         Force update even if ip hasn't changed.
+-h|--help  Print help and exit.
+
+Note: Uses util-linux getopt option parsing: spaces between args and
+options, short options can be combined, options before args.
+EOF
+  exit $1
+}
+
+##### begin command line parsing ########
+
+# ensure we can handle args with spaces or empty.
+ret=0; getopt -T || ret=$?
+[[ $ret == 4 ]] || { echo "Install util-linux for enhanced getopt" >&2; exit 1; }
+
+force=false # default
+temp=$(getopt -l help hf "$@") || usage 1
+eval set -- "$temp"
+while true; do
+  case $1 in
+    -f) force=true ;;
+    --) shift; break ;;
+    *) echo "$0: unexpected args: $*" >&2 ; usage 1 ;;
+  esac
+  shift
+done
+
+##### end command line parsing ########
 
 main() {
 
@@ -24,6 +66,7 @@ main() {
 
   case $gateway in
     10.2.0.1)
+      dyndomain=b8.nz
       dynhost=i.b8.nz
       ;;
     *)
@@ -31,6 +74,11 @@ main() {
       ;;
   esac
 
+  # We check if we are at home by testing gateway ssh
+  # fingerprint. However, if we found in the past that we are, I dont
+  # like to spam its logs with ssh login attempts, so just check if our
+  # gateway interface has an increasing amount of packets sent +
+  # received from last time.
   athome=false
   if [[ -s /dev/shm/dynamic-ip-update-state ]]; then
     oldbytes=$(cat /dev/shm/dynamic-ip-update-state)
@@ -54,7 +102,7 @@ main() {
       return 0
     fi
     if ip4=$(curl -s4 https://iankelling.org/cgi/pubip); then
-      if [[ $cur4 && $ip4 && $cur4 != $ip4 ]]; then
+      if $force || [[ $cur4 && $ip4 && $cur4 != $ip4 ]]; then
         up4=true # update ipv4
       fi
     fi
@@ -80,7 +128,7 @@ main() {
     fi
   fi
 
-  if [[ $cur6 != $ip6 ]]; then
+  if $force || [[ $cur6 != $ip6 ]]; then
     up6=true
   fi
 
@@ -102,6 +150,8 @@ EOF
     cat >>$f <<EOF
 update delete $dynhost. A
 update add $dynhost. 300 A $ip4
+update delete $dyndomain. A
+update add $dyndomain. 300 A $ip4
 EOF
   fi
 
@@ -125,11 +175,13 @@ answer
 quit
 EOF
 
-  nsupdate -k /p/c/machine_specific/vps/filesystem/etc/bind/Kb8.nz.*.private <$f
+  nsupdate -k /p/c/machine_specific/vps/filesystem/etc/bind/Kb8.nz.*.private <$f || nsupdate_fails=$((nsupdate_fails + 1))
   sed -i 's/^server .*/server bk.b8.nz/' $f
-  nsupdate -k /p/c/machine_specific/vps/filesystem/etc/bind/Kb8.nz.*.private <$f
-
-
+  nsupdate -k /p/c/machine_specific/vps/filesystem/etc/bind/Kb8.nz.*.private <$f  || nsupdate_fails=$((nsupdate_fails + 1))
+  if (( nsupdate_fails > nsupdate_fail_limit )); then
+    echo error: nsupdate is persistently failing >&2
+    exit 1
+  fi
 }
 
 loop-main() {
@@ -139,10 +191,12 @@ loop-main() {
   done
 }
 
-
+nsupdate_fails=0
 if [[ $INVOCATION_ID ]]; then
+  nsupdate_fail_limit=10
   loop-main
 else
+  nsupdate_fail_limit=0
   main
 fi
 
diff --git a/filesystem/etc/systemd/system/navidrome.service b/filesystem/etc/systemd/system/navidrome.service
new file mode 100644 (file)
index 0000000..a638231
--- /dev/null
@@ -0,0 +1,47 @@
+[Unit]
+Description=Navidrome
+After=remote-fs.target network.target
+AssertPathExists=/i/navidrome
+
+[Install]
+WantedBy=multi-user.target
+
+[Service]
+User=iank
+Group=iank
+Type=simple
+ExecStart=/i/navidrome/navidrome --configfile "/i/navidrome/navidrome.toml"
+WorkingDirectory=/i/navidrome
+TimeoutStopSec=20
+KillMode=process
+Restart=on-failure
+
+# See https://www.freedesktop.org/software/systemd/man/systemd.exec.html
+DevicePolicy=closed
+NoNewPrivileges=yes
+PrivateTmp=yes
+PrivateUsers=yes
+ProtectControlGroups=yes
+ProtectKernelModules=yes
+ProtectKernelTunables=yes
+RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6
+RestrictNamespaces=yes
+RestrictRealtime=yes
+SystemCallFilter=~@clock @debug @module @mount @obsolete @reboot @setuid @swap
+ReadWritePaths=/i/navidrome
+
+# You can uncomment the following line if you're not using the jukebox This
+# will prevent navidrome from accessing any real (physical) devices
+#PrivateDevices=yes
+
+# You can change the following line to `strict` instead of `full` if you don't
+# want navidrome to be able to write anything on your filesystem outside of
+# /var/lib/navidrome.
+ProtectSystem=full
+
+# You can uncomment the following line if you don't have any media in /home/*.
+# This will prevent navidrome from ever reading/writing anything there.
+#ProtectHome=true
+
+# You can customize some Navidrome config options by setting environment variables here. Ex:
+#Environment=ND_BASEURL="/navidrome"
diff --git a/filesystem/usr/local/bin/off b/filesystem/usr/local/bin/off
new file mode 100755 (executable)
index 0000000..567b46a
--- /dev/null
@@ -0,0 +1,5 @@
+#!/bin/sh
+
+wall -n off: $$ shutdown in 30 seconds
+sleep 30
+systemctl poweroff
index 5c6b3fec592e6aa14281d7fdd05489c331ab75e8..9387339bb93a88de39b4fde063c509e5e456caa4 100755 (executable)
@@ -1,3 +1,9 @@
-#!/bin/sh
+#!/bin/bash -r
 
-systemctl suspend
+for (( i=0; i<3; i++ )); do
+  systemctl suspend
+  wall -n spend: $$ suspending in 30 seconds
+  sleep 30
+done
+wall -n spend: $$ shutdown in 30 seconds
+shutdown
diff --git a/filesystem/usr/local/bin/us b/filesystem/usr/local/bin/us
new file mode 100755 (executable)
index 0000000..231ce47
--- /dev/null
@@ -0,0 +1,4 @@
+#!/bin/bash -r
+
+# unsuspend
+pkill -f /usr/local/bin/spend
index a47e6cfb7665ac90376bf7c4c47faf93ed72e3ca..ac2c8c4f42192d2a4ae0f97a168b98acb23a885b 100644 (file)
@@ -7,10 +7,14 @@
 set $mod Mod4
 
 bindsym $mod+2 exec "pavucontrol"
-# ian: dunno why but i needed this version at some point, then
-# it mysteriously stopped working, but works on the cli. 2022-12
-#bindsym $mod+3 exec "abroswer"
-bindsym $mod+3 exec "abrowser -no-remote -P sfw"
+# calling without -no-remote makes this to be the instance that links
+# will open in from other applications.
+bindsym $mod+3 exec "abrowser"
+# calling just abrowser mysteriously stopped working,
+# so I figured out this is how to get output, but then
+# it suddenly started working again.
+#bindsym $mod+3 exec "abrowser 2>&1 >/tmp/l"
+#bindsym $mod+3 exec "abrowser -no-remote -P sfw"
 bindsym $mod+4 exec "abrowser -no-remote -P firefox-main-profile"
 bindsym $mod+5 exec "/usr/local/bin/start-tor-browser"
 bindsym $mod+6 exec "/a/bin/redshift.sh"
index a2f056cc8081e281f8127649c43cce5d17f47812..8f66f7c4c8e499787d64f758c4da10f9572469a1 100755 (executable)
@@ -2,6 +2,10 @@
 # Copyright (C) 2019 Ian Kelling
 # SPDX-License-Identifier: AGPL-3.0-or-later
 
+
+# setup automatic decryption on boot using host-specific key file.
+# When changing a hostname, that key needs updating.
+
 set -eE -o pipefail
 trap 'echo "$0:$LINENO:error: \"$BASH_COMMAND\" returned $?"' ERR
 
@@ -21,7 +25,12 @@ PATH="/sbin:$PATH"
 
 if [[ $INVOCATION_ID ]]; then
   if [[ -e /b/bash_unpublished/source-state ]]; then
+    # this is the canonical one
     source /b/bash_unpublished/source-state
+  elif [[ -e /dev/shm/iank-status ]]; then
+    # This one gets copied by system-status and is useful because it
+    # exists when /a is unmounted.
+    source /dev/shm/iank-status
   fi
   if [[ $MAIL_HOST && $MAIL_HOST != $HOSTNAME ]]; then
     echo "$0: exiting early: running under systemd as MAIL_HOST"
index 93a085a8e20e764e85d43153480f1a58b924507d..7a179c4fd604480b50af48136d81990a25cef69b 100644 (file)
@@ -268,13 +268,6 @@ else
   do_o=false
 fi
 
-if [[ $HOSTNAME == frodo ]]; then
-  fstab <<EOF
-$crypt_dev  /i  btrfs  noatime,subvol=i$mopts  0 0
-EOF
-fi
-
-
 
 ##### end setup fstab for subvols we care about ######
 
@@ -389,47 +382,27 @@ for vol in ${all_vols[@]}; do
     m btrfs property set -ts $leaf ro true
 
     ### begin check if leaf is different, delete it if not ###
-    if [[ -e /a/opt/btrfs-snapshots-diff/btrfs-snapshots-diff.py ]]; then
-      source /a/bin/distro-functions/src/package-manager-abstractions
-      #pi python-jmespath # dependency of btrfs-snapshots-diff
-      # todo: need python3 port of btrfs-snapshots-diff, py2 no exist on nabia
-      parentid=$(btrfs sub show $leaf | awk '$1 == "Parent" && $2 == "UUID:" {print $3}')
-      bsubs=(btrbk/$vol.*)
-      bsub=
-      # go in reverse order as its more likely to be at the end
-      for ((i=${#bsubs[@]}-1; i>=0; i--)); do
-        if [[ $parentid == $(btrfs sub show ${bsubs[i]} | awk '$1 == "UUID:" {print $2}') ]]; then
-          bsub=${bsubs[i]}
-          break
-        fi
-      done
-      if [[ $bsub ]]; then
-        tmp=$(mktemp)
-        # in testing, same subvol is 136 bytes. allow some overhead. 32 happens sometimes under systemd.
-        # $ errno 32
-        # EPIPE 32 Broken pipe
-        btrfs send --no-data -p $bsub $leaf | head -c 1000 > $tmp || [[ $? == 141 || ${PIPESTATUS[0]} == 32 ]]
-        if (( $(stat -c%s $tmp) < 1000)); then
-          # example output for an empty diff:
-          # Found a valid Btrfs stream header, version 1
-          # o.leaf.2019-05-15T14:00:50-0400;snapshot: uuid=ba045ea30737dd449003f1ee40ec12d0, ctrasid=109533, clone_uuid=3c7e3544e486834aa71d89e5b8f30056, clone_ctransid=109533
-          lines=$(/a/opt/btrfs-snapshots-diff/btrfs-snapshots-diff.py -s -f $tmp | \
-                    grep -vxF "Found a valid Btrfs stream header, version 1" | \
-                    grep -cv "^[^;]*;snapshot: ") ||:
-          if [[ $lines == 0 ]]; then
-            # rotate in case we find a bug, weve got 2 old ones
-            tmpleaf=($vol.tmpleaf2.*)
-            if (( ${#tmpleaf[@]} )); then
-              x btrfs sub del ${tmpleaf[@]}
-            fi
-            tmpleaf=($vol.tmpleaf1.*)
-            if (( ${#tmpleaf[@]} )); then
-              x mv ${tmpleaf[0]} $vol.tmpleaf2.${tmpleaf[0]#$vol.tmpleaf1.}
-            fi
-            echo suspected identical: $bsub $leaf
-            x mv $leaf $vol.tmpleaf1.${leaf#$vol.leaf.}
-          fi
-        fi
+    parentid=$(btrfs sub show $leaf | awk '$1 == "Parent" && $2 == "UUID:" {print $3}')
+    bsubs=(btrbk/$vol.*)
+    bsub= # base subvolume
+    # go in reverse order as its more likely to be at the end
+    for ((i=${#bsubs[@]}-1; i>=0; i--)); do
+      if [[ $parentid == $(btrfs sub show ${bsubs[i]} | awk '$1 == "UUID:" {print $2}') ]]; then
+        bsub=${bsubs[i]}
+        break
+      fi
+    done
+    if [[ $bsub ]]; then
+      tmp=$(mktemp)
+      # in testing, same subvol is 136 bytes. allow some overhead. 32 happens sometimes under systemd.
+      # $ errno 32
+      # EPIPE 32 Broken pipe
+      lines=$(btrfs send --no-data -p $bsub $leaf | btrfs receive --dump | head -n 100 | wc -l || [[ $? == 141 || ${PIPESTATUS[0]} == 32 ]])
+      if [[ $lines == 0 ]]; then
+        # example output of no differences:
+        # snapshot        ./qrtest                        uuid=c41ff6b7-0527-f34d-95ac-190eecf54ff5 transid=2239 parent_uuid=64949e1b-4a3e-3945-9a8e-cd7b7c15d7d6 parent_transid=2239
+        echo suspected identical: $bsub $leaf
+        x btrfs sub del $leaf
       fi
     fi
     ### end check if leaf is different, delete it if not ###
diff --git a/music-tag-sync b/music-tag-sync
deleted file mode 100644 (file)
index 06248e0..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-#!/bin/bash
-# Copyright (C) 2019 Ian Kelling
-# SPDX-License-Identifier: AGPL-3.0-or-later
-if [[ -s ~/.bashrc ]];then . ~/.bashrc;fi
-# cd /k/music
-# find -type f -name '*.flac' | while read -r f; do
-#     mkdir -p "../flacs/$(dirname "$f")"
-#     mv -T "$f" ../flacs/"$f"
-# done
-
-
-
-# todo, add settings from /etc/default/nfs-{common,kernel-server}
-# todo: do mysql setup. kodi install. mysql backup.
-
-# in kodi, music, add files, named source, add network share,
-# server address: iank.life
-# path: k/music
-
-
-
-rm -f /a/tmp/y.sql
-
-cd /k/music
-find -type f \( -name '*.flac' -or -name '*.mp3' -or -name '*.m4a' \) | while read -r f; do
-    rating=$(kid3-cli -c "get RATING" "$f")
-    if [[ ! $rating ]]; then
-           echo $f
-           continue
-    fi
-    rating=$((rating*2))
-
-    ## begin sql escaping
-    f="${f//\"/\\\"}"
-    f="${f//\'/\\\'}"
-    f="${f//_/\\_}"
-    f="${f//%/\\%}"
-    ## end sql escaping
-    d=${f%/*}
-    d=${d#./}/ # use exact dir format that is in database
-    cat >>/a/tmp/y.sql <<EOF
-update song
-inner join path on song.idPath = path.idPath
-set song.userrating = $rating
-where song.strFileName = '${f##*/}' and path.strPath = 'nfs://iank.life/k/music/$d';
-EOF
-done
diff --git a/navidrome-playlist-export b/navidrome-playlist-export
new file mode 100755 (executable)
index 0000000..c4c824c
--- /dev/null
@@ -0,0 +1,38 @@
+#!/bin/bash
+
+f=/usr/local/lib/err;test -r $f || { echo "error: $0 no $f" >&2;exit 1;}; . $f
+
+
+
+# begin star rating import from navidrome to beets:
+declare -A navirating
+for r in 1 2 3 4 5; do
+  while read -r path; do
+    beetpath="/i/m${path#/i/converted}"
+    navirating[$beetpath]=$r
+  done < <(sqlite3 /i/navidrome/navidrome.db "select path from annotation inner join media_file on item_id = id where rating = $r;")
+done
+declare -A beetrating
+for r in 1 2 3 4 5; do
+  while read -r path; do
+    beetrating[$path]=$r
+  done < <(beet ls -f '$path' rating:$r)
+done
+
+for path in "${!navirating[@]}"; do
+  r="${navirating[$path]}"
+  if [[ $r != "${beetrating[$path]}" ]]; then
+    # note: this assumes there are no cases like filea.mp3 filea.mp3.mp3, which would affect both files.
+    echo "$r != ${beetrating[$path]}, beet modify -y path:$path rating=$r"
+    beet modify -y "path:$path" "rating=$r"
+  fi
+done
+# end star rating import from navidrome to beets:
+
+
+beet subsonicplaylist
+
+while read -r id plists; do
+  plists="${plists#;}"
+  e beet modify -y "id:$id" ${plists//;/=t }
+done < <(beet ls -f '$id $subsonic_playlist' subsonic_playlist::.)
diff --git a/pkgs b/pkgs
index 3d859ac7c9a7f1323dd6d139619382cfc226d6a9..289d6bbb0c0bba49b8c5b02d5a9baeb83abfdfe4 100644 (file)
--- a/pkgs
+++ b/pkgs
@@ -101,6 +101,7 @@ p3=(
   dillo
   dirmngr
   dos2unix
+  dosfstools
   dnsutils
   python3-dnspython
   duplicity
@@ -180,6 +181,7 @@ p3=(
   metastore
   mhonarc
   mmdebstrap
+  mp3gain
   mps-youtube
   mpv
   mumble
@@ -200,6 +202,7 @@ p3=(
   opendkim-tools
   p7zip-full
   paprefs
+  parted
   parted-doc
   pass
   pavucontrol
@@ -246,6 +249,7 @@ p3=(
   transmission-remote-gtk
   trash-cli
   tty-clock
+  uuid-runtime
   vlc
   wamerican-huge
   wireless-tools
diff --git a/playlists/music/10.xsp b/playlists/music/10.xsp
deleted file mode 100644 (file)
index af815a4..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
-<smartplaylist type="songs">
-    <name></name>
-    <match>all</match>
-    <rule field="genre" operator="doesnotcontain">
-        <value>Avant-Garde</value>
-        <value>Noise</value>
-        <value>Skit</value>
-        <value>Spoken Word</value>
-    </rule>
-    <rule field="userrating" operator="greaterthan">
-        <value>9</value>
-    </rule>
-</smartplaylist>
diff --git a/playlists/music/8.xsp b/playlists/music/8.xsp
deleted file mode 100644 (file)
index 51722aa..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
-<smartplaylist type="songs">
-    <name>8</name>
-    <match>all</match>
-    <rule field="userrating" operator="greaterthan">
-        <value>7</value>
-    </rule>
-    <rule field="genre" operator="isnot">
-        <value>Avant-Garde</value>
-        <value>Noise</value>
-        <value>Skit</value>
-        <value>Spoken Word</value>
-    </rule>
-</smartplaylist>
diff --git a/playlists/music/sad.xsp b/playlists/music/sad.xsp
deleted file mode 100644 (file)
index be00384..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
-<smartplaylist type="songs">
-    <name>sad</name>
-    <match>all</match>
-    <rule field="genre" operator="is">
-        <value>sad</value>
-    </rule>
-    <rule field="userrating" operator="greaterthan">
-        <value>7</value>
-    </rule>
-</smartplaylist>
diff --git a/playlists/music/sad5.xsp b/playlists/music/sad5.xsp
deleted file mode 100644 (file)
index 7b86c5e..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
-<smartplaylist type="songs">
-    <name>sad5</name>
-    <match>all</match>
-    <rule field="genre" operator="contains">
-        <value>sad</value>
-    </rule>
-    <rule field="userrating" operator="greaterthan">
-        <value>9</value>
-    </rule>
-</smartplaylist>
diff --git a/playlists/music/sy most.xsp b/playlists/music/sy most.xsp
deleted file mode 100644 (file)
index a5a971c..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
-<smartplaylist type="songs">
-    <name>sy most</name>
-    <match>all</match>
-    <rule field="artist" operator="contains">
-        <value>Sonic Youth</value>
-    </rule>
-    <rule field="userrating" operator="greaterthan">
-        <value>5</value>
-    </rule>
-</smartplaylist>
index 2ced3c9b831fa952279e91675b0224d07a44d344..b8e594cbd93218e522253dbcbef5c8360d2f663f 100755 (executable)
@@ -5,7 +5,9 @@
 
 source /usr/local/lib/err
 
-pre="${0##*/}:"
+script_name="${BASH_SOURCE[0]}"
+script_name="${script_name##*/}"
+pre="${SSH_CLIENT:+$HOSTNAME} $script_name:"
 m() { printf "$pre %s\n"  "$*"; "$@"; }
 e() { printf "$pre %s\n"  "$*"; }
 err() { echo "[$(date +'%Y-%m-%d %H:%M:%S%z')]: $0: $*" >&2; }
diff --git a/subdir_files/.config/beets/config.yaml b/subdir_files/.config/beets/config.yaml
deleted file mode 100644 (file)
index 3452831..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-library: /a/bin/data/musiclibrary.blb
-directory: /i/music
-import:
-  log: /a/dt/beetlog.log
-  move: yes
-  quiet_fallback: skip
-
-# be a little more liberal for strong matches
-match:
-  strong_rec_thresh: 0.07
-plugins: discogs duplicates web info
-# all the usefull plugins I've used:
-#plugins: copyartifacts chroma discogs duplicates web
-
-#duplicates:
-# duplicates can be found based on tagged keys or a checksum program.
-# the sugggested checksum program takes hours :(
-# the default is tags, but it is broken.
-# the default ffmpeg command, using the libav equivalent  based on debian recommendations
-    #checksum: avconv -i {file} -f crc -
index 4fc20de16b003e1b5dd99338cf6611554bdc01ca..027e52f5cab0e4f641567b0bdd2c5de2fea0d202 100644 (file)
@@ -16,3 +16,7 @@ no-save-position-on-quit
 
 [s]
 shuffle
+
+# audio
+[a]
+player-operation-mode=cplayer
index 4a7ce3744a9cd3e20f81aa087fedf4bef26e927a..6e9c420871196b4b0eb6ef5123688a97c36a2ea7 100644 (file)
@@ -41,7 +41,7 @@ err-cleanup() {
   fi
 }
 
-pre="$script_name:"
+pre="${SSH_CLIENT:+$HOSTNAME} $script_name:"
 m() { printf "$pre %s\n"  "$*"; "$@"; }
 e() { printf "$pre %s\n"  "$*"; }
 err() { echo "$pre ERROR: $*" >&2; }
@@ -279,6 +279,10 @@ if (( ret )); then
   exit $ret
 fi
 
+# new system is usable at this point
+printf "$(tput setaf 5 2>/dev/null ||:)█$(tput sgr0 2>/dev/null||:)%.0s" $(eval echo "{1..${COLUMNS:-60}}")
+echo
+
 # once I accidentally accepted incoming mail on old host. I used this script to copy over that mail:
 #
 # die=false; for d in o.leaf.2021-05-29T10:02:08-0400/m/{4e,md,4e2}/{,l/}!(*myarchive)/new; do if $die; then break; fi; find $d -type f -mtime -5 | while read -r f; do dir="${f%new/*}"; dir="btrbk/o.20210530T000011-0400/${dir#*/}"; fname="${f##*/}"; [[ -e $dir/new/$fname || -e $dir/cur/$fname ]] && continue; if ! e cp -a $f /${dir#*/*/}new; then echo failed cp; die=true; break; fi ; done; done
index 65c87c9fa79863b0151cf958f015771fb045f995..5d3a1cb1edb56c3841ad52a554e56e6c437bf2f6 100644 (file)
 -A OUTPUT -p tcp -m tcp --sport 9091 -j ACCEPT
 -A INPUT -p tcp -m tcp --dport 9091 -j ACCEPT
 
-# 1195 is used for the secondary vpn server
-# 1198 is another vpn port, simpler syntax just to use range
--A OUTPUT -p udp -m udp --dport 1194:1198 -j ACCEPT
--A INPUT -p udp -m udp --sport 1194:1198 -j ACCEPT
+# 1300 is used by mullvad
+-A OUTPUT -p udp -m udp --dport 1300 -j ACCEPT
+-A INPUT -p udp -m udp --sport 1300 -j ACCEPT
 
 -A OUTPUT -o tun0 -j ACCEPT
 -A INPUT -i tun0 -j ACCEPT