summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xkeyboard/bl2
-rwxr-xr-xkeyboard/dockfanctl10
-rwxr-xr-xkeyboard/monctl38
-rwxr-xr-xkeyboard/shutdownprompt6
-rwxr-xr-xkeyboard/sinkswitch15
-rwxr-xr-xmisc/diskhealth46
-rwxr-xr-xmisc/mkmount18
-rwxr-xr-xmisc/mountimg42
-rwxr-xr-xmisc/verifoo110
-rwxr-xr-xvideo/d8concat164
-rwxr-xr-xvideo/d8integrity9
-rw-r--r--video/dvgrabscript1
-rwxr-xr-xvideo/mp4cp12
13 files changed, 469 insertions, 4 deletions
diff --git a/keyboard/bl b/keyboard/bl
index 84694e9..333d1e8 100755
--- a/keyboard/bl
+++ b/keyboard/bl
@@ -7,7 +7,7 @@ bl_min=0
bl_max=100
# DDC/CI stuff
-ddcutil="ddcutil --sleep-less --noverify --sleep-multiplier $sleep_multiplier" # Make sure user is in group i2c
+ddcutil="ddcutil --enable-sleep-less --noverify --sleep-multiplier $sleep_multiplier" # Make sure user is in group i2c
#ddcutil="ddcutil --sleep-less --noverify --enable-capabilities-cache --sleep-multiplier $sleep_multiplier" # Make sure user is in group i2c
max() { [ $1 -gt $2 ] && echo $1 || echo $2; }
diff --git a/keyboard/dockfanctl b/keyboard/dockfanctl
new file mode 100755
index 0000000..f422b3e
--- /dev/null
+++ b/keyboard/dockfanctl
@@ -0,0 +1,10 @@
+#!/bin/sh
+hub=$(doas uhubctl | grep -B3 'Port 3: .* highspeed enable connect .* Lenovo USB2.0 Hub' | grep -o -m1 '[0-9][^ ]*' | head -n1)
+! [ "$hub" ] && exit 1
+
+echo $hub
+
+case $1 in
+ off) doas uhubctl -a off -p 4 -l $hub ;;
+ on) doas uhubctl -a on -p 4 -l $hub ;;
+esac
diff --git a/keyboard/monctl b/keyboard/monctl
new file mode 100755
index 0000000..116974f
--- /dev/null
+++ b/keyboard/monctl
@@ -0,0 +1,38 @@
+#!/bin/sh
+
+display=$2
+input_vcp=0x60
+input_local=0x11
+input_other=0x0f
+power_vcp=0xD6
+power_on=0x01
+power_off=0x05
+sleep_multiplier=.1 # Set this as low as you can get away with
+
+# DDC/CI stuff
+ddcutil="ddcutil --noverify --sleep-multiplier $sleep_multiplier --display $display" # Make sure user is in group i2c
+
+getstate() { $ddcutil getvcp $1 | grep -o '0x[0-9a-f]*' | tail -n1 ; }
+
+in_other() { $ddcutil setvcp $input_vcp $input_other ; }
+in_local() { $ddcutil setvcp $input_vcp $input_local ; }
+pw_on() { $ddcutil setvcp $power_vcp $power_on ; }
+pw_off() { $ddcutil setvcp $power_vcp $power_off ; }
+
+in_toggle() { [ `getstate $input_vcp` = $input_local ] && in_other || in_local ; } # Default to input_local
+pw_toggle() { [ `getstate $power_vcp` = $pw_on ] && pw_off || pw_on ; } # Default to power_on
+
+case $1 in
+ inputother) in_other ;;
+ inputlocal) in_local ;;
+ inputtoggle) in_toggle ;;
+ poweron) pw_on ;;
+ poweroff) pw_off ;;
+ powertoggle) pw_toggle ;;
+ getinput) getstate $input_vcp ;;
+ getpower) getstate $power_vcp ;;
+ *)
+ echo "'$1' is not a recognized option"
+ echo "$(basename "$0") [inputother|inputlocal|inputtoggle|poweron|poweroff|powertoggle] display_num"
+ ;;
+esac
diff --git a/keyboard/shutdownprompt b/keyboard/shutdownprompt
index ce187a8..71cac3d 100755
--- a/keyboard/shutdownprompt
+++ b/keyboard/shutdownprompt
@@ -13,7 +13,7 @@ for process_name in $warn_process_names; do
done
case $option in
- Suspend) launch zzz ;;
- Shutdown) launch off ;;
- Restart) launch res ;;
+ Suspend) launch zzz ;;
+ Shutdown) launch off ;;
+ Restart) launch res ;;
esac
diff --git a/keyboard/sinkswitch b/keyboard/sinkswitch
new file mode 100755
index 0000000..3046498
--- /dev/null
+++ b/keyboard/sinkswitch
@@ -0,0 +1,15 @@
+#!/bin/sh
+[ $(hostname) != 'T495' ] && echo "Not T495. Exiting" && exit 1
+
+status="$(wpctl status)"
+
+headphones_sink=$(echo "$status" | grep -m1 'ThinkPad USB-C Dock Gen2 USB Audio Analog Stereo \[vol:' | grep -m1 -o '[0-9]*')
+speakers_sink=$( echo "$status" | grep -m1 'Raven/Raven2/Fenghuang HDMI/DP Audio Controller Digital Stereo (HDMI 2) \[vol:' | grep -m1 -o '[0-9]*')
+
+selected_sink=$(echo "$status" | grep -m1 '\*\s*[0-9]*' | grep -o '[0-9]*')
+
+case $selected_sink in
+ $headphones_sink) wpctl set-default $speakers_sink && echo "Switched to speakers" ;;
+ $speakers_sink) wpctl set-default $headphones_sink && echo "Switched to headphones" ;;
+ *) echo "Cannot find correct sink. Exiting" && exit 1 ;;
+esac
diff --git a/misc/diskhealth b/misc/diskhealth
new file mode 100755
index 0000000..5cce07b
--- /dev/null
+++ b/misc/diskhealth
@@ -0,0 +1,46 @@
+#!/usr/bin/env python3
+
+import subprocess
+import json
+from pprint import pprint
+
+smart_result = subprocess.run(["sudo", "smartctl", "-Aij", "/dev/sda"], capture_output=True, text=True)
+
+smart_result = json.loads(smart_result.stdout)
+
+sector_size = smart_result["logical_block_size"]
+
+from typing import NamedTuple
+class RawValue(NamedTuple):
+ value: int
+ string: str
+
+class Flags(NamedTuple):
+ value: int
+ string: str
+ prefailure: bool
+ updated_online: bool
+ performance: bool
+ error_rate: bool
+ event_count: bool
+ auto_keep: bool
+
+class SmartAttribute(NamedTuple):
+ id: int
+ name: str
+ value: int
+ worst: int
+ thresh: int
+ when_failed: str
+ flags: dict
+ raw: dict
+
+attributes = {}
+
+for attr in smart_result["ata_smart_attributes"]["table"]:
+ attr_l = SmartAttribute(**attr)
+ attributes[attr_l.id] = attr_l
+
+if 241 in attributes:
+ lbas_written = attributes[241].raw["value"]
+ print((lbas_written * sector_size) / 10**12)
diff --git a/misc/mkmount b/misc/mkmount
new file mode 100755
index 0000000..b23d85b
--- /dev/null
+++ b/misc/mkmount
@@ -0,0 +1,18 @@
+#!/bin/sh
+
+set -e
+
+mpdir="/run/media/$USER"
+mkdir -p "$mpdir"
+
+mp="$1"
+
+if [ -z "$mp" ]; then
+ mp="$(mktemp -d "$mpdir/XXXXXX")"
+else
+ mp="$mpdir/$mp"
+ [ -f "$mp" ] && echo "Error: $mp already exists" && exit 1
+ mkdir -p "$mp"
+fi
+
+echo "$mp"
diff --git a/misc/mountimg b/misc/mountimg
new file mode 100755
index 0000000..efe886c
--- /dev/null
+++ b/misc/mountimg
@@ -0,0 +1,42 @@
+#!/bin/sh
+
+set -e
+
+die() { echo "$(basename "$0"): $1" && exit 1 ; }
+
+# file check
+! [ "$1" ] && die "No file was specified"
+! [ -f "$1" ] && die "$1 is not a file"
+# mountpoint check
+! [ "$2" ] && die "No mountpoint was specified"
+! [ -d "$2" ] && die "Mountpoint $2 is not a directory"
+[ "`ls -A "$2"`" ] && die "Mountpoint $2 is not empty"
+# check disk image validity
+! fdisk -lu "$1" 2>&1 | grep -m1 "\s*Start\s*End" >/dev/null && die "File $1 is not a disk image"
+
+# get sectorsize
+#sectorsize=$(fdisk -lu "$1" | grep -m1 '^Units:' | cut -d' ' -f8) # Sector size is 8th word
+sectorsize=512
+
+# get partition num, if there is more than one part, interactively if not available
+# TODO check if there is no partitions
+partition="$3"
+if [ -z "$partition" ]; then
+ fdisk -o Size,Type,Name -lu "$1" | awk '!f{print $0};f>0{print " " f-1 ") " $0; f++};f==-1{print "Part " $0;f=1};/^$/{f=-1}'
+
+ printf "\nChoose partition number to mount: "
+ read partition
+fi
+
+# check if part num valid
+[ -z "${partition##*[!0-9]*}" ] && die "Illegal number: '$partition'"
+
+# get offset from fdisk
+fdisk_ignore_lines=9 # ignore first 9 lines of output
+offset=$(fdisk -o Start -l "$1" | sed $(( fdisk_ignore_lines + partition ))'q;d' )
+
+# check if that produced a valid offset
+[ -z "$offset" ] && die "Partition $partition does not exist"
+
+# try to mount
+mount -o loop,offset=$(( offset * sectorsize )) "$1" "$2" && echo "Successfully mounted" || die "Error mounting"
diff --git a/misc/verifoo b/misc/verifoo
new file mode 100755
index 0000000..34089cb
--- /dev/null
+++ b/misc/verifoo
@@ -0,0 +1,110 @@
+#!/bin/sh
+
+help() {
+cat << HELPDOC
+usage: $(basename "$0") [options] [file]...
+
+OPTIONS:
+ -h, --help show this menu
+ -c, --check read and verify checksums from file
+ -r, --recursive produce a checksum for all files in a directory recursively
+ --recursive-sum produce a checksum for a directory. sensitive to filenames
+ --recursive-sum-nopath produce a checksum for a directory. not sensitive to filenames/placement
+ -s, --silent produce no output to stderr
+ -v, --verbose output a progress bar of hash progress if pv is avaliable (wip)
+
+MODES:
+ -S, --sha use sha1sum for checksums
+ -M, --md5 use md5sum for checksums
+ -X, --xxh use xxhsum for checksums (default if avaliable with sha1sum as fallback)
+HELPDOC
+}
+
+# set defaults
+cat="pv -F'%r_[%b]_[%t]_[%e]_%p'"
+! command -v pv >/dev/null && cat=cat
+
+hash=xxhsum
+! command -v xxhsum >/dev/null && hash=sha1sum
+
+hashfiles=""
+verbose=1
+recursive=""
+outputfile=""
+
+while true; do
+ case "$1" in
+ -c|--check) [ -n "$2" ] && hashfiles="$hashfiles $2" && shift ;;
+ -s|--silent) verbose=0 ;;
+ -v|--verbose) verbose=2 ;;
+ --recursive|-r) recursive=3 ;;
+ --recursive-sum) recursive=2 ;;
+ --recursive-sum-nopath) recursive=1 ;;
+ -S|--sha) hash=sha1sum ;;
+ -M|--md5) hash=md5sum ;;
+ -X|--xxh) hash=xxhsum ;;
+ -h|--help) help; exit 0 ;;
+ -*) help; exit 1 ;;
+ *) break ;;
+ esac
+ shift
+done
+
+case $verbose in
+ 0) cat=cat ;;
+ 1) cat=cat ;;
+esac
+
+# run hash
+while [ -n "$1" ]; do
+ if [ -d "$1" ]; then # is directory
+ # check if using -r flag
+ case "$recursive" in
+ 1)
+ # get hash of all files, sort hashes, hash hashes
+ # TODO make pv work in this mode
+
+ #catd="$cat"
+ #if [ $verbose -ge 2 ] && [ "$catd" != "cat" ]; then
+ # total_files=$(du -a "$1" | wc -l)
+ # catd="pv -l -s$total_files -F'[%b/$total_files]_[%t]_[%e]_%p'"
+ #fi
+ #sum=`find "$1" -type f -print0 | xargs -r0 $hash | $catd | cut -d' ' -f1 | sort | $hash | cut -d' ' -f1` 2>/dev/null
+ sum=`find "$1" -type f -print0 | xargs -r0 $hash | cut -d' ' -f1 | sort | $hash | cut -d' ' -f1` 2>/dev/null
+ echo "r/$sum $1"
+ ;;
+ 2)
+ # hash sorted filenames
+ # sort all filenames w/ full path and hash
+ # hash those sums together
+ # `tar -c -f - "$1" | $hash` is a good idea but it doesn't work since changes to the fs affect tar
+ filehash=`find "$1" -type f -print0 | sort -z | xargs -r0 $cat | $hash | cut -d' ' -f1`
+ pathhash=`find "$1" -printf "%P\0" | sort -z | $hash | cut -d' ' -f1`
+ sum=`printf "$filehash$pathhash" | $hash | cut -d' ' -f1`
+ echo "p/$sum $1"
+ ;;
+ 3)
+ # sort files and hash each one in sequence
+ # TODO make pv work in this mode
+ find "$1" -type f -print0 | sort -z | xargs -r0 $hash
+ ;;
+ *)
+ [ $verbose -ge 1 ] && echo "-r not specified for directory $1. Exiting"
+ exit 1
+ ;;
+ esac
+ else # is file
+ if ! [ -f "$1" ]; then
+ [ $verbose -gt 1 ] && echo "File $1 does not exist. Exiting"
+ exit 1
+ fi
+ files="$1"
+
+ while [ -f "$2" ]; do
+ files="$files\0$2"
+ shift
+ done
+ printf "$files" | xargs -r0 $hash
+ fi
+ shift
+done
diff --git a/video/d8concat b/video/d8concat
new file mode 100755
index 0000000..bf8b608
--- /dev/null
+++ b/video/d8concat
@@ -0,0 +1,164 @@
+#!/bin/sh
+
+[ -d "$1" ] || exit 1 # Exit with error if not pointing to a directory
+
+# Misc
+duration() { ffprobe -i "$1" -show_entries format=duration -v quiet -of csv="p=0" | tr -d . ; }
+timebase="1/1000000" # duration function gives microseconds
+
+safename() { echo "$1" | tr -d '<>:"/\|?*' ; }
+
+# Temp dirs
+workdir="$(mktemp -d "${TMPDIR:-/tmp}/combinetapesworkdir.XXXXXX")"
+
+cleanup() { rm -rf "$workdir" ; }
+trap cleanup EXIT INT HUP QUIT TERM ALRM USR1
+
+# Loop vars
+current_date=0
+duration_total=0
+chapter_start=0
+chapter_time=0
+last_chapter_concurrent=0
+
+# TODO this relys on the for loop looping in order
+
+# Either can be ran on single dv containing directory, or many dv containing directories
+for dir in "$1"/ "$1"/*/; do
+ dir="${dir%/}" # Remove trailing slash
+ title=""
+
+ if [ "$dir" != "$1" ]; then
+ title="$(basename "$dir")"
+ fi
+ if echo "$dir" | grep '/\*' >/dev/null; then
+ break
+ fi
+
+ for tape in "$dir"/*.dv; do
+ date="$(echo "$(basename "$tape")" | grep -o '[0-9]*\.[0-9]*\.[0-9]*' | tr '.' '-')"
+ time="$(echo "$(basename "$tape")" | grep -o '[0-9]*-[0-9]*-[0-9]*' | tr '-' ':')"
+
+ if [ "$title$date" != "$current_date" ]; then
+ # Reset vars
+ current_date="$title$date"
+ duration_total=0
+ chapter_start=0
+ chapter_time=0
+ last_chapter_concurrent=0
+
+ # Create dirs
+ date_dir="$workdir/$current_date"
+ mkdir -p "$date_dir"
+
+ files="$date_dir/files"
+ chapters="$date_dir/chapters"
+
+ # Init chapters file
+ printf ";FFMETADATA1\n\n" > "$chapters"
+
+ # title file
+ if [ "$title" ]; then
+ echo "$title" > "$date_dir/title"
+ fi
+ fi
+
+ # Concat files
+ echo "file '$(realpath "$tape" | sed "s/'/'\\\\''/g")'" >> "$files"
+
+ # Chapter marker
+ tape_duration=$(duration "$tape" | grep -o "[1-9][0-9]*")
+ duration_total=$(( $duration_total + $tape_duration ))
+
+ # Only insert chapter marker if recordings are not concurrent. dvgrab
+ # splits files into 1gb chunks, or 291557933 microseconds of raw dv footage
+ # (with digital 8)
+ if [ $last_chapter_concurrent = 0 ]; then
+ chapter_time=$time
+ fi
+ if [ $tape_duration = 291557933 ]; then
+ last_chapter_concurrent=1
+ continue
+ else
+ last_chapter_concurrent=0
+ fi
+
+ echo "[CHAPTER]" >> "$chapters"
+ echo "TIMEBASE=$timebase" >> "$chapters"
+ echo "START=$chapter_start" >> "$chapters"
+ echo "END=$duration_total" >> "$chapters"
+ echo "title=Section starts at $chapter_time" >> "$chapters"
+ echo >> "$chapters"
+
+ chapter_start=$duration_total
+ done
+done
+
+
+# ffmpeg combine
+out_dir=export
+default_title=Untitled
+mkdir -p "$out_dir"
+
+for date_dir in "$workdir"/*; do
+ date="$(echo "$date_dir" | grep -o "[0-9][0-9][0-9][0-9]-[0-9]*-[0-9]*")"
+ origin_tape="$(basename "$1")"
+
+ # Files
+ title="$date_dir/title"
+ files="$date_dir/files"
+ chapters="$date_dir/chapters"
+
+ # Nicely title
+ if [ -e "$title" ]; then
+ # title file
+ output_title="$(cat "$title")"
+ #elif echo "$origin_tape" | grep "^[^0-9].*[0-9]*-[0-9]*-[0-9]*" >/dev/null; then
+ # # Beginning descriptor
+ # output_title="$(echo "$origin_tape" | sed 's/ [0-9#].*//')"
+ #elif echo "$origin_tape" | grep "$date [A-Z]" >/dev/null; then
+ # # Date range or list of dates with titles (Title must be capitalized, 'to' must be made lowercase
+ # output_title="$(echo "$origin_tape" | sed "s/.*$date //; s/ to [0-9].*//; s/;.*//")"
+ else
+ # default
+ output_title=$default_title
+ fi
+
+ output_title="$(echo "$output_title" | sed 's/\s*#[0-9]*$//')" # Remove sequence numbers
+
+ # File name
+ if [ "$output_title" = "$default_title" ]; then
+ output_name="$date"
+ else
+ output_name="$date $output_title"
+ fi
+
+ if [ -e "$out_dir/$output_name.mp4" ]; then
+ output=$(ls "$out_dir" | grep "$output_name *[0-9]*.mp4" | while read -r file; do
+ file_tape="$(mediainfo "$out_dir/$file" | sed -n 's/Comment.* - Origin tape: //p')"
+ if [ "$origin_tape" = "$file_tape" ]; then
+ echo 0
+ break
+ fi
+ done)
+ if [ "$output" = 0 ]; then
+ continue
+ fi
+ output_name="$output_name $(ls "$out_dir" | grep "$output_name *[0-9]*.mp4" | wc -l)"
+ fi
+
+ # Convert
+ #-c copy \
+ #-metadata "title=$output_title" \ # Dont set title since it will be stuck if file is renamed
+ ffmpeg -hide_banner -nostdin \
+ -n \
+ -f concat -safe 0 -i "$files" \
+ -i "$chapters" -map_metadata 1 \
+ -c:v libx264 -crf 22 -preset medium -tune grain \
+ -vf yadif \
+ -c:a aac -b:a 320k \
+ -metadata "date=$date" \
+ -metadata "comment=tapes.tjkeller.xyz - Origin tape: $origin_tape" \
+ "$out_dir/$output_name.mp4"
+ #"$out_dir/$output_name.mkv"
+done
diff --git a/video/d8integrity b/video/d8integrity
new file mode 100755
index 0000000..717032b
--- /dev/null
+++ b/video/d8integrity
@@ -0,0 +1,9 @@
+#!/bin/sh
+
+find . -type f -name "*.dv" | while read file; do
+ ffmpeg -v error -i "$file" 2>&1 | grep "Concealing bitstream errors" >/dev/null && echo "$file"
+done
+
+find . -type f -name "*.dv" | while read file; do
+ ffmpeg -v error -i "$file" -f null - 2>&1 | grep "Concealing bitstream errors" >/dev/null && echo "$file"
+done
diff --git a/video/dvgrabscript b/video/dvgrabscript
new file mode 100644
index 0000000..d82ba55
--- /dev/null
+++ b/video/dvgrabscript
@@ -0,0 +1 @@
+sudo dvgrab -autosplit -rewind -timestamp -format raw -csize 100000000
diff --git a/video/mp4cp b/video/mp4cp
new file mode 100755
index 0000000..31f8cc9
--- /dev/null
+++ b/video/mp4cp
@@ -0,0 +1,12 @@
+#!/bin/sh
+set -e
+echo "Usage: $(basename $0) [SRCDIR] [DESTDIR]"
+
+srcdir="$1"
+destdir="$2"
+# TODO mkdir destdir
+
+for vid in "$srcdir"/*; do
+ # TODO test if is vid
+ ffmpeg -n -i "$vid" -c copy -o "$destdir/$(basename "$vid" | sed 's/\.[^.]*$//').mp4"
+done