diff options
Diffstat (limited to 'sh')
| -rwxr-xr-x | sh/alarm | 11 | ||||
| -rwxr-xr-x | sh/backlight | 23 | ||||
| -rwxr-xr-x | sh/bell | 7 | ||||
| -rwxr-xr-x | sh/ccgp | 7 | ||||
| -rwxr-xr-x | sh/cfg | 29 | ||||
| -rwxr-xr-x | sh/chmodef | 6 | ||||
| -rwxr-xr-x | sh/curlqb | 27 | ||||
| -rwxr-xr-x | sh/dateft | 29 | ||||
| -rwxr-xr-x | sh/dirnameall | 19 | ||||
| -rwxr-xr-x | sh/gita | 17 | ||||
| -rwxr-xr-x | sh/gitfork | 10 | ||||
| -rwxr-xr-x | sh/gitmetap | 17 | ||||
| -rwxr-xr-x | sh/gitmetar | 7 | ||||
| -rwxr-xr-x | sh/gitpu | 19 | ||||
| -rwxr-xr-x | sh/grrc | 21 | ||||
| -rwxr-xr-x | sh/il | 6 | ||||
| -rwxr-xr-x | sh/lastarg | 5 | ||||
| -rwxr-xr-x | sh/loop | 15 | ||||
| -rwxr-xr-x | sh/lsp | 3 | ||||
| -rwxr-xr-x | sh/mll | 6 | ||||
| -rwxr-xr-x | sh/mmi | 27 | ||||
| -rwxr-xr-x | sh/mpra | 44 | ||||
| -rwxr-xr-x | sh/mpva | 17 | ||||
| -rwxr-xr-x | sh/mpvy | 45 | ||||
| -rwxr-xr-x | sh/mvln | 27 | ||||
| -rwxr-xr-x | sh/mvtr | 11 | ||||
| -rwxr-xr-x | sh/mvtu | 13 | ||||
| -rwxr-xr-x | sh/news | 39 | ||||
| -rwxr-xr-x | sh/o | 27 | ||||
| -rwxr-xr-x | sh/orgext | 18 | ||||
| -rwxr-xr-x | sh/pa | 8 | ||||
| -rwxr-xr-x | sh/pq | 13 | ||||
| -rwxr-xr-x | sh/px | 10 | ||||
| -rwxr-xr-x | sh/qg | 15 | ||||
| -rwxr-xr-x | sh/qw | 16 | ||||
| -rwxr-xr-x | sh/rate | 11 | ||||
| -rwxr-xr-x | sh/reco | 28 | ||||
| -rwxr-xr-x | sh/rfp | 11 | ||||
| -rwxr-xr-x | sh/sbar | 79 | ||||
| -rwxr-xr-x | sh/ta | 5 | ||||
| -rwxr-xr-x | sh/time-uuid | 6 | ||||
| -rwxr-xr-x | sh/topa | 8 | ||||
| -rwxr-xr-x | sh/upd | 219 | ||||
| -rwxr-xr-x | sh/vinfo | 4 | ||||
| -rwxr-xr-x | sh/wh | 11 | ||||
| -rwxr-xr-x | sh/wtr | 43 | ||||
| -rwxr-xr-x | sh/xmq | 3 | 
47 files changed, 1042 insertions, 0 deletions
| diff --git a/sh/alarm b/sh/alarm new file mode 100755 index 0000000..5342e7d --- /dev/null +++ b/sh/alarm @@ -0,0 +1,11 @@ +#!/bin/sh + +min="$1" +[ "$1" ] && shift +printf "notify-send -u critical %s; bell" "$(/usr/bin/printf '%q ' "${@:-alarm}")" | at now + "${min:-0}" minutes && [ "$min" ] && [ "$min" -ne 0 ] && notify-send "Successfully Scheduled" + +# at used to not like string like 'Boiling Water!', don't know why now it works, if see similar issue, use folllowing codes +#at now + "$1" minutes << EOF && notify-send 'Successfully Scheduled' +#notify-send -u critical "${2:-alarm}" +#bell +#EOF diff --git a/sh/backlight b/sh/backlight new file mode 100755 index 0000000..3de87f5 --- /dev/null +++ b/sh/backlight @@ -0,0 +1,23 @@ +#!/bin/sh + +brightness=$(cat /sys/class/backlight/intel_backlight/brightness) +max_brightness=$(cat /sys/class/backlight/intel_backlight/max_brightness) +step=$((max_brightness/20)) + +case "$1" in +	'-u') +		case "$brightness" in +			0) echo 1;; +			1) echo "$step";; +			*) echo "$((brightness+step))";; +		esac +	;; +	'-d') +		case "$brightness" in +			1) echo 0;; +			"$step") echo 1;; +			*) echo "$((brightness-step))";; +		esac +	;; +	*) exit 1;; +esac > /sys/class/backlight/intel_backlight/brightness @@ -0,0 +1,7 @@ +#!/bin/sh + +bef="$(amixer get Master | awk -F '[][]' 'END{print $2}')" +amixer set Master 10% +# code steal from https://unix.stackexchange.com/a/163716/459013 +speaker-test -t sine -f 1000 -l 1 +amixer set Master "$bef" @@ -0,0 +1,7 @@ +#!/bin/sh +# steal codes from https://github.com/LukeSmithxyz/voidrice/blob/master/.local/bin/compiler + +base="${1%.*}" +# -lm link math library? needed for sqrt(). not sure +# https://stackoverflow.com/questions/44175151/what-is-the-meaning-of-lm-in-gcc +cc -Wall -lgsl -lgslcblas -lm -lplplot -o "$base" "$1" && ./"$base" @@ -0,0 +1,29 @@ +#!/bin/sh + +umask 077 +while getopts lsmM opt; do +	case $opt in +		#c)		 +		#	work_tree_dir="$HOME" +		#	meta_file="$XDG_CONFIG_HOME/myconf/cfg${opt}_meta" +		#	cmd="git --git-dir=$HOME/.cfg$opt/ --work-tree=$HOME" +		#	;; +		l|s)	 +			work_tree_dir=/ +			meta_file="/etc/myconf/cfg${opt}_meta" +			cmd="sudo -E git --git-dir=/etc/.cfg$opt/ --work-tree=/" +			;; +		m)		 +			sudo gitmetap "$cmd" "$work_tree_dir" "$meta_file" +			$cmd diff +			exit +			;; +		M)	 +			sudo gitmetar "$meta_file" +			exit +			;; +		\?)	exit 1;; +	esac +done +shift $((OPTIND-1)) +$cmd "$@" diff --git a/sh/chmodef b/sh/chmodef new file mode 100755 index 0000000..446bc23 --- /dev/null +++ b/sh/chmodef @@ -0,0 +1,6 @@ +#!/bin/sh +# chmodef: CHMOD DEFault + +# https://wiki.archlinux.org/title/File_permissions_and_attributes#Numeric_method +find "$@" -type d -execdir chmod 755 -- '{}' \+ +find "$@" -type f -execdir chmod 644 -- '{}' \+ diff --git a/sh/curlqb b/sh/curlqb new file mode 100755 index 0000000..d2851cd --- /dev/null +++ b/sh/curlqb @@ -0,0 +1,27 @@ +#!/bin/sh + +# need --no-clobber if don't want overwrite when same name +# if do this also need change .py.1 to .py else qbt will not accept +# also if a.py and a_1.py, qbt will not accept the latter, maybe need to change some .py codes inside +# now, I choose to let three files to be overwrited, those are "with categories" .py files that overwrite without categories .py files, which is what I want so I don't use --no-clobber +curl -s 'https://github.com/qbittorrent/search-plugins/wiki/Unofficial-search-plugins' | awk -F'"' ' +/user-content-plugins-for-private-sites/ {exit} +/\.py/ { +	url=$2 +	getline +	getline +	getline +	if($0 !~ /❗|✖/) +		print url +} +' | xargs curl -s -Z -L --remote-name-all --create-dirs --output-dir "$1" -- + +# an alternative awk command: +#awk -F'"' ' +#/require an account/ {exit} +#/\.py/ { +#	url=$2 +#	line=NR +#} +#url && NR==line+3 && !/❗|✖/ {print url} +#' diff --git a/sh/dateft b/sh/dateft new file mode 100755 index 0000000..b317474 --- /dev/null +++ b/sh/dateft @@ -0,0 +1,29 @@ +#!/bin/sh +# DATE From To + +while getopts cfF:t:T: opt; do +	case $opt in +		c) tz_from="Asia/Shanghai";; +		f) tz_from="$(tzselect)";; +		F) tz_from="$OPTARG";; +		# one extra ',' at the end will not let `for tz in ...` loop one extra time? +		t)	for i in $(seq "$OPTARG"); do +				tz_to="$(tzselect),$tz_to" +			done;; +		T) tz_to="$OPTARG,$tz_to";; +		\?) exit 1;; +	esac +done +shift $((OPTIND-1)) + +time_from="TZ=\"${tz_from:-$(readlink /etc/localtime | sed 's#.*/\(.*/.*\)$#\1#')}\" ${1:-now}" + +date -d "$time_from" +TZ="Asia/Shanghai" date -d "$time_from" +date -d "$time_from" -u  +date -d "$time_from" +%s +[ "$tz_from" ] && [ "$tz_from" != "Asia/Shanghai" ] && TZ="$tz_from" date -d "$time_from" +IFS=','  +for tz in $tz_to; do +	TZ="$tz" date -d "$time_from" +done diff --git a/sh/dirnameall b/sh/dirnameall new file mode 100755 index 0000000..befd347 --- /dev/null +++ b/sh/dirnameall @@ -0,0 +1,19 @@ +#!/bin/sh + +while read -r line; do +	if [ "$paths" ]; then +		paths="$paths +$line" +	else +		paths="$line" +	fi +done + +dirs="$paths" +while [ "$dirs" != '.' ]; do +	[ "$dirs" ] && paths="$paths +$dirs" +	dirs="$(echo "$dirs" | tr '\n' '\0' | xargs -0 dirname | awk '!a[$0]++')" +done + +echo "$paths" | awk '!a[$0]++' | grep -v '^\.$' @@ -0,0 +1,17 @@ +#!/bin/sh +# note message string must come after options + +cmd=git + +while getopts ls f; do +	case $f in +		l|s) cmd="cfg -$f";; +		\?) exit 1;; +	esac +done +shift $((OPTIND-1)) + +mes="${1:-update}" + +$cmd commit --all -m "$mes" +$cmd push diff --git a/sh/gitfork b/sh/gitfork new file mode 100755 index 0000000..9736c4c --- /dev/null +++ b/sh/gitfork @@ -0,0 +1,10 @@ +#!/bin/sh + +git clone "$1" +cd "$(basename "$1" .git)" || exit +git remote add upstream "$2" +if ! git checkout fly; then +	git branch fly +	git checkout fly +	git push --set-upstream origin fly +fi diff --git a/sh/gitmetap b/sh/gitmetap new file mode 100755 index 0000000..c058986 --- /dev/null +++ b/sh/gitmetap @@ -0,0 +1,17 @@ +#!/bin/sh +# GIT META Print + +# -rw-r--r-- == binary 110100100 == octal 644 +# https://stackoverflow.com/a/1796009 +$1 ls-tree -r --name-only --full-tree HEAD | dirnameall | awk -v a="$2/" '{printf("%s%s\n",a,$0)}' | tr '\n' '\0' | xargs -0 ls -ldA -- | awk '{ +	k=0 +	for(i=0;i<=8;i++) +		k+=((substr($1,i+2,1)~/[rwx]/)*2^(8-i)) +	if(k) { +		for(i=10;$i && $i!="->";i++) +			$9=$9" "$i +		printf("%0o %s %s %s\n",k,$3,$4,$9) +	} +}' > "$3" + +#$1 ls-tree -r --name-only --full-tree HEAD | awk -v a="$2/" '{printf("%s%s\n",a,$0)}' | tr '\n' '\0' | xargs -0 ls -ldA -- | awk '{k=0;for(i=0;i<=8;i++)k+=((substr($1,i+2,1)~/[rwx]/)*2^(8-i));if(k){for(i=10;$i && $i!="->";i++)$9=$9" "$i;printf("%0o %s %s %s\n",k,$3,$4,$9)}}' > "$3" diff --git a/sh/gitmetar b/sh/gitmetar new file mode 100755 index 0000000..1bfdc15 --- /dev/null +++ b/sh/gitmetar @@ -0,0 +1,7 @@ +#!/bin/sh +# GIT META Read + +while read -r mod user group path; do +	chown -hc "$user:$group" -- "$path" +	[ "$mod" -ne 777 ] && chmod -c "$mod" -- "$path" +done < "$1" diff --git a/sh/gitpu b/sh/gitpu new file mode 100755 index 0000000..5453fae --- /dev/null +++ b/sh/gitpu @@ -0,0 +1,19 @@ +#!/bin/sh + +if [ -z "$1" ]; then +	git checkout master  +	git pull upstream master +	git push +	git checkout fly +	git merge --no-edit master +	git push +else +	for dir; do +		git -C "$dir" checkout master  +		git -C "$dir" pull upstream master +		git -C "$dir" push +		git -C "$dir" checkout fly +		git -C "$dir" merge --no-edit master +		git -C "$dir" push +	done +fi @@ -0,0 +1,21 @@ +#!/bin/sh +# GRep -R Code + +# logic: no descend, in this dir, if a dir name .git; then true and do nothing; else if a file name LICENSE; then true and do nothing; else print +[ "$1" ] && find "$HOME/programs/fsh" \ +	"$HOME/archive/programs/public_archive_codes" \ +	"$HOME/archive/programs/private_archive_codes" \ +	"$HOME/archive/programs/me106_proj_fall2021" \ +	"$HOME/archive/programs/car_job/av_dev" \ +	"$HOME/archive/programs/VisualDimension" \ +	"$XDG_DOCUMENTS_DIR/sjsu_courses/spring_2024/math161a/hw" \ +	"$XDG_DOCUMENTS_DIR/notes" \ +	-mindepth 1 -maxdepth 1 -type d -name '.git' -o -type f -name 'LICENSE' -o -print0 2>/dev/null \ +	| xargs -0 grep -s --color=always -iIR "$@" \ +	"$HOME/.local/bin" \ +	"$HOME/.bashrc" \ +	"$HOME/.profile" \ +	"$HOME/.xinitrc" \ +	"$HOME/programs/suckless/dwm_fly/config.def.h" \ +	"$XDG_CONFIG_HOME/nsxiv/exec/key-handler" \ +	| "$PAGER" @@ -0,0 +1,6 @@ +#!/bin/sh +# InterpoLation + +# x=$1, xa=$2, xb=$3, ya=$4, yb=$5 +# https://en.wikipedia.org/wiki/Interpolation#Linear_interpolation +echo "scale=4;$4+($5-$4)*($1-$2)/($3-$2)" | bc diff --git a/sh/lastarg b/sh/lastarg new file mode 100755 index 0000000..b52afcd --- /dev/null +++ b/sh/lastarg @@ -0,0 +1,5 @@ +#!/bin/sh +# usage: lastarg "$@" + +shift $(($# - 1)) +echo "$1" @@ -0,0 +1,15 @@ +#!/bin/sh + +while getopts t: opt; do +	case $opt in +		t) time="$OPTARG";; +		\?) exit 1;; +	esac +done +shift $((OPTIND-1)) + +while :; do +	# suggested by https://github.com/koalaman/shellcheck/wiki/SC2294 +	"$@" +	sleep "${time:-1}" +done @@ -0,0 +1,3 @@ +#!/bin/sh + +loop ssh "${1:-pp}" @@ -0,0 +1,6 @@ +#!/bin/sh +# Map Latitude Longitude + +# https://help.openstreetmap.org/questions/9669/jumping-to-a-specific-set-of-coordinates-on-the-map +# another way is to manually search xx.xxxxx,xx.xxxxx +o "$BROWSER" "https://www.openstreetmap.org/?mlat=$1&mlon=$2&zoom=5" @@ -0,0 +1,27 @@ +#!/bin/sh + +mi () { +	make +	sudo make install +} + +origin="$PWD" +cmd='mi' + +while getopts q opt; do +	case $opt in +		q) cmd='qmake6;mi';; +		\?) exit 1;; +	esac +done +shift $((OPTIND-1)) + +if [ -z "$1" ]; then +	eval "$cmd" +else +	for dir; do +		cd "$dir" || exit +		eval "$cmd" +		cd "$origin" || exit +	done +fi @@ -0,0 +1,44 @@ +#!/bin/sh +# MakePkg Repo-Add + +fn () { +	if ! { [ -f PKGBUILD ] || [ -h PKGBUILD ];}; then +		exit +	fi +	find . -maxdepth 1 -type f -name "*.pkg.tar.$ext*" -delete +	makepkg --sign -sf +	newpkg="$(find . -maxdepth 1 -type f -name "*.pkg.tar.$ext")" +	[ -d ../repo ] || mkdir ../repo +	mv "$newpkg" "$newpkg.sig" ../repo +	# need manually repo-add new database for first time initialization +	repo-add -s -v -R "$(find ../repo -maxdepth 1 -type f -name '*.db.tar.gz')" "../repo/$newpkg" +	# seems no need to delete *.old and *.old.sig, see https://mirror.fcix.net/archlinux/core/os/x86_64/ it do include *.old +	#find ../repo -maxdepth 1 -type f \( -name '*.old' -o -name '*.old.sig' \) -delete +} + +ext=zst +copy_any= + +while getopts ac opt; do +	case $opt in +		# arch linux arm still using .xz instead of .zst as package compression format +		a) ext=xz;; +		# copy arch linux fly-any repo +		c) copy_any=1;; +		\?) exit 1;; +	esac +done +shift $((OPTIND-1)) + +if [ $# -eq 0 ]; then +	fn  +else +	for dir; do +		cd -- "$(realpath -- "$dir")" || exit +		fn	 +	done +fi + +[ "$copy_any" ] && sudo rsync -vPrlt --delete ../repo/ /srv/http/mirrors/archlinux/fly/os/any + +upd -p @@ -0,0 +1,17 @@ +#!/bin/sh +# MPV Audio + +# fzf has --read0, maybe useful +# use --loop-file for single file, better performance maybe +# fzf --scheme=path for better fzf result when searching path, like the old time: +# https://github.com/junegunn/fzf/commit/6fb41a202a97ad3f2437f6e5aee8890268560412 + +if [ $# -eq 0 ]; then +	find "$XDG_MUSIC_DIR" | fzf -m --print0 --scheme=path +fi | xargs -0 sh -c ' +if [ $# -eq 1 ] && ! [ -d "$1" ]; then +	mpv --af= --loop-file=inf --video=no "$1" +else +	mpv --af= --shuffle --loop-playlist=inf --video=no "$@" +fi +' shell "$@" @@ -0,0 +1,45 @@ +#!/bin/sh +# MPV Yank/Youtube videos +# references: +# https://www.rockyourcode.com/til-how-to-watch-youtube-videos-with-mpv-and-keyboard-shortcuts/ + +fps=30 +height=$SCR_HEIGHT +url="$(xsel -ob)" +flag=s + +# option f and h may do nothing if redownload? since same filename exist. yt-dlp won't download same file even without --auto-file-renameing=false. how improve? pass argument to aria2c? +while getopts Aabd:f:h:su: opt; do +	case $opt in +		# s: streaming, a: aria2c then mpv, A: aria2c +		A|a|s) flag=$opt;; +		b) format='bestvideo+bestaudio/best';; +		d) download_dir="$OPTARG";; +		f) fps="$OPTARG";; +		h) height="$OPTARG";; +		u) url="$OPTARG";; +		\?) exit 1;; +	esac +done +if [ -z "$format" ]; then +	# xyzstudio GPU +	#vformat="[height<=?$height][fps<=?$fps][vcodec!^=?vp9][vcodec!^=?av01]" +	vformat="[height<=?$height][fps<=?$fps][vcodec!^=?av01]" +	# usually get .mp4 video + .webm audio on youtube, yt-dlp needs to merge them to .mkv +	# it used to cause problem, but I forget +	format="bestvideo$vformat+bestaudio/best$vformat" +fi + +case $flag in +	# here if use --write-sub, mpv doesn't recognize subtitles?  +	# --embed-subs is a little bit better, but still worse then direct streaming +	# --sponsorblock-remove will make audio/video goes out of sync, need --force-keyframes-at-cuts which need re-encode which is slow,  more see comments at the bottom of https://github.com/yt-dlp/yt-dlp/issues/871 +	# another way is using mpv-sponsorblock-minimal-git for streaming and sponsorblock-mpv-local for local videos +	A) yt-dlp -f "$format" --embed-subs -P "${download_dir:-"$XDG_DOWNLOAD_DIR/mpvy/"}" --sponsorblock-remove default --sponsorblock-mark default "$url";; +	a) yt-dlp -f "$format" --embed-subs -P "${download_dir:-"$XDG_DOWNLOAD_DIR/mpvy/"}" --sponsorblock-remove default --sponsorblock-mark default "$url" --exec 'mpv --fs --speed=2';; +	s) mpv --ytdl-format="$format" --ytdl-raw-options='write-sub=' --fs --speed=2 "$url";; +esac +# not sure if this is the best practice, but it seems working ;) +status=$? +[ $status -ne 0 ] && notify-send 'mpvy failed' +exit $status @@ -0,0 +1,27 @@ +#!/bin/sh +# edge cases give me headache + +lns () { +	# prevent `mvln file1 file1` or `mvln dir1/file1 dir1/` +	# which means `ln -s samename samename` or `ln -s dir/file dir/` +	# both $1 and $2 here are realpath +	[ "$1" != "$2" ] && ln -s -- "$1" "$2" +} + +mv -i -- "$@" +# consider `mvln file1 dir/file2` +if [ $# -eq 2 ] && ! [ -d "$2" ]; then +	# use realpath here +	lns "$(realpath "$2")" "$(realpath "$1")" 	 +else +	dir="$(realpath -- "$(lastarg "$@")")" +	# steal from https://unix.stackexchange.com/a/353833/459013 +	while [ $# -gt 1 ]; do +		to="$(realpath -- "$1")" +		# prevent `mvln dir1/ dir1/` +		if [ "$dir" != "$to" ]; then +			lns "$dir/$(basename "$1")" "$to" +		fi +		shift +	done +fi @@ -0,0 +1,11 @@ +#!/bin/sh + +# can use ls pipe to sed pipe to bash, similar to eval? see comment at link: +# link also show perl-rename approach +# https://linuxconfig.org/rename-all-files-from-uppercase-to-lowercase-characters +# if only change ' ' to '_' `rename` might be sufficient, for upper to lower case might need perl-rename if want concise + +# ./_filename will be renamed ./filename, not what I want, need improve +# -exec can't replace -execdir here, can write a -exec version + +find "$@" -depth -execdir sh -c 'dest="$(echo "$1" | tr -d "\047" | sed -E -e "s/([[:lower:]])([[:upper:]])/\1_\2/g" | tr "[:upper:] " "[:lower:]_" | tr -s "[:punct:]" | sed -E -e "s#/-#/#g" -e "s/_([[:punct:]])/\1/g" -e "s/([[:punct:]])_/\1/g" | tr -s "[:punct:]")"; [ -e "$dest" ] || mv -v -- "$1" "$dest"' shell '{}' \; @@ -0,0 +1,13 @@ +#!/bin/sh +# MV Time-Uuid + +find "$@" -type f -execdir sh -c ' +	file="$(basename "$1")" +	ext="${file##*.}" +	if [ "$ext" != "$file" ]; then +		dest="$(time-uuid).$ext" +	else +		dest="$(time-uuid)" +	fi +	[ -e "dest" ] || mv -v -- "$1" "$dest" +' shell '{}' \; @@ -0,0 +1,39 @@ +#!/bin/sh + +daily () { +	# mail.yahoo.com/d/folders/6 is spam folder +	o "$BROWSER" \ +		https://github.com/notifications \ +		'https://mail.google.com/mail/u/0/#inbox' \ +		'https://mail.google.com/mail/u/0/#spam' \ +		'https://mail.google.com/mail/u/1/#inbox' \ +		'https://mail.google.com/mail/u/1/#spam' \ +		https://mail.yahoo.com \ +		https://mail.yahoo.com/d/folders/6 \ +		https://en.wikipedia.org/wiki/Portal:Current_events +	# alacritty --hold must be before -e +	# full window: -w156, am and pm in one line: -w114 +	o alacritty --hold -e rem -cu+2 -@ -w114 +	o alacritty --hold -e wtr +	o alacritty -e newsboat +	o alacritty --hold -e rate +	o alacritty --hold -e pass practice_password2 +} + +monthly () { +	o "$BROWSER" https://smtp.cheogram.com/ http://download.huzheng.org +	# Show 3 months' remind. I use 3 months because it is better to know I20 deadline 3 months earlier so I have 2 months to prepare the money for extension. +	# (2*31+30+6)/7=14. Consider month 1 day 1 is on Sunday and make sure month 3 day 31 is shown. Tested with `rem -cu+14 -@ -w114 2025-03-01` +	o alacritty --hold -e sh -c 'rem -cu+14 -@ -w114 | $PAGER' +} + +if [ $# -eq 0 ]; then +	daily +else +	while getopts m opt; do +		case $opt in +			m) monthly;; +			\?) exit 1;; +		esac +	done +fi @@ -0,0 +1,27 @@ +#!/bin/sh + +# useful links +# https://stackoverflow.com/questions/3430330/best-way-to-make-a-shell-script-daemon +# https://serverfault.com/questions/117152/do-background-processes-get-a-sighup-when-logging-off +# https://wiki.archlinux.org/title/default_applications + +# I don't care about errors, I don't want to handle errors, just shut up please. +# nohup seems not necessary if don't care about daemon SIGHUP requirement + +# when close a shell script's stdout or stderr with `>&-` or `2>&-`, `xsel -ib` in that script has no effect +# https://github.com/kfish/xsel/issues/43 +# using `>&-` or `2>&-` doesn't completely close mpv's output when run sth. like `o mpv file.mkv` +# base on above observations, I choose to use `>/dev/null 2>&1` instead + +# need ; before } when it is in the same line as { ? https://www.shellcheck.net/wiki/SC1056 + +if [ $# -eq 1 ] && [ -e "$1" ] && { ! [ -x "$1" ] || [ -d "$1" ];}; then +	case "$1" in +		# libreoffice, please don't let firefox eat your shit +		*.docx|*.pptx) cmd=libreoffice;; +		*) cmd=xdg-open;; +	esac +	nohup "$cmd" "$1" 0<&- >/dev/null 2>&1 & +else +	nohup "$@" 0<&- >/dev/null 2>&1 & +fi diff --git a/sh/orgext b/sh/orgext new file mode 100755 index 0000000..0143e62 --- /dev/null +++ b/sh/orgext @@ -0,0 +1,18 @@ +#!/bin/sh + +outdir () {  +	find . -type f -execdir mv -t "$PWD" -- '{}' \+ +	find . -mindepth 1 -maxdepth 1 -type d -execdir rmdir -- '{}' \+ +} + +indir () { +	# https://stackoverflow.com/questions/1842254/how-can-i-find-all-of-the-distinct-file-extensions-in-a-folder-hierarchy +	find . -maxdepth 1 -type f | awk -F. '!a[$NF]++{print $NF}' | xargs mkdir -- +	find . -mindepth 1 -maxdepth 1 -type d -execdir basename -az -- '{}' \+ | xargs -0 -I _ find . -maxdepth 1 -type f -name '*._' -execdir mv -t '_' -- '{}' \+ +} + +case "$1" in +	'-o') outdir;; +	'-i') indir;; +	*) outdir; indir;; +esac @@ -0,0 +1,8 @@ +#!/bin/sh +# Ping Alarm + +while ! ping -w5 "$1"; do +	sleep 5 +done +notify-send "$1 on" +bell @@ -0,0 +1,13 @@ +#!/bin/sh +# Pacman Query, to manually determine remove the package or not + +[ "$1" ] && { +	#sed -n '/^Depends On/,/^Conflicts With/{/^Conflicts With/!p}; /^Description\|^URL\|^Groups\|^Installed Size\|^Install Reason/p' +	pacman -Qi "$1" | awk '/^Groups/{f=1} /^Conflicts With/{f=0} f||/^Description|^URL|^Installed Size|^Install Reason/' +	printf '\n' +	pacman -Ql "$1" | grep '/bin/[^$]' +	printf '\n' +	pactree -r "$1" +	printf '\n' +	grrc "$1" +} | "$PAGER" @@ -0,0 +1,10 @@ +#!/bin/sh +# Printf Xsel + +if [ $# -eq 0 ]; then +	/usr/bin/printf '%q' "$PWD" +else +	for dir; do +		/usr/bin/printf '%q ' "$(realpath -- "$dir")" +	done +fi | xsel -ib @@ -0,0 +1,15 @@ +#!/bin/sh + +# more resources see comments in my script qw +# https://guix.gnu.org/manual/en/html_node/Running-Guix-in-a-VM.html +# `-enable-kvm` same as `-accel kvm`, see archwiki +qemu-system-x86_64 \ +	-accel kvm \ +	-cpu host \ +	-device virtio-blk,drive=myhd \ +	-display gtk,zoom-to-fit=on \ +	-drive if=none,file="$XDG_DOWNLOAD_DIR/qemu/guix.img",format=qcow2,id=myhd \ +	-m 8G \ +	-nic user,model=virtio-net-pci,hostfwd=::53684-:22 \ +	-smp 2,sockets=1,cores=1,threads=2 \ +	-usb -device usb-tablet @@ -0,0 +1,16 @@ +#!/bin/sh + +# For better performance, it needs CPU-pinning with `taskset`, GPU pass-through, and other more tweaks +# https://github.com/cardi/qemu-windows-10 +# https://wiki.archlinux.org/title/QEMU +## https://wiki.archlinux.org/title/QEMU#Mouse_integration +# https://qemu-project.gitlab.io/qemu/system/devices/usb.html +qemu-system-x86_64 \ +	-accel kvm \ +	-cpu host,hv_relaxed,hv_spinlocks=0x1fff,hv_vapic,hv_time \ +	-display gtk,zoom-to-fit=on \ +	-drive file="$XDG_DOWNLOAD_DIR/qemu/win10.img",format=qcow2 \ +	-m 8G \ +	-nic user,hostfwd=::53683-:22 \ +	-smp 2,sockets=1,cores=1,threads=2 \ +	-usb -device usb-tablet @@ -0,0 +1,11 @@ +#!/bin/sh + +while getopts f:t: opt; do +	case $opt in +		f) from="$OPTARG";; +		t) to="$(echo "$OPTARG" | tr '[:lower:]' '[:upper:]')";; +		\?) exit 1;; +	esac +done +# https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/api-exchange-rates +curl -s "https://api.coinbase.com/v2/exchange-rates?currency=${from:-xmr}" | jq -r ".data.rates.${to:-USD}" @@ -0,0 +1,28 @@ +#!/bin/sh + +# useful urls: +# https://github.com/LukeSmithxyz/voidrice/blob/master/.local/bin/dmenurecord +# https://wiki.archlinux.org/title/FFmpeg#Screen_capture +# https://trac.ffmpeg.org/wiki/Capture/Desktop + +infofile="/tmp/recoinfo" +recodir="$XDG_VIDEOS_DIR/recordings/" +tmpdir="$recodir/tmp/" +mkdir -p "$recodir" "$tmpdir" + +if [ -e "$infofile" ]; then +	read -r pid tmpfile < "$infofile" +	kill "$pid" +	notify-send 'finish recording, start converting' +	ffmpeg -i "$tmpfile" "$recodir/$(time-uuid).mkv" +	notify-send 'finish converting' +	rm "$tmpfile" "$infofile" +else +	tmpfile="$tmpdir/$(time-uuid).mkv" +	notify-send 'prepare recording' +	# arch wiki way, no audio, less cpu use during capturing (fast?), large file size, need convert afterward +	xrectsel '%w %h %x %y' | xargs sh -c 'ffmpeg -y -loglevel quiet -f x11grab -framerate 25 -s "$2x$3" -i "$DISPLAY+$4,$5" -c:v ffvhuff "$1" & echo $!' shell "$tmpfile" | xargs -I {} printf '%s\t%s' '{}' "$tmpfile" > "$infofile" +	# another way to get subshell ffmpeg child pid +	#xrectsel '%w %h %x %y' | xargs sh -c 'ffmpeg -y -f x11grab -framerate 25 -s "$2x$3" -i "$DISPLAY+$4,$5" -c:v ffvhuff "$1"' shell "$tmpfile" & +	#printf '%s\t%s' "$(ps -o pid= --ppid $!)" "$tmpfile" > "$infofile" +fi @@ -0,0 +1,11 @@ +#!/bin/sh + +if grep -q '^//user_pref("privacy.resistFingerprinting", false);$' "$HOME/.mozilla/firefox/xxxxxxxx.fly/user-overrides.js"; then +	sed -i 's#^//\(user_pref("privacy.resistFingerprinting", false);\)$#\1#' "$HOME/.mozilla/firefox/xxxxxxxx.fly/user-overrides.js" +	notify-send -u critical 'RFP disabled' +else +	sed -i 's#^\(user_pref("privacy.resistFingerprinting", false);\)$#//\1#' "$HOME/.mozilla/firefox/xxxxxxxx.fly/user-overrides.js" +	notify-send 'RFP enabled' +fi +upd -j +o "$BROWSER" @@ -0,0 +1,79 @@ +#!/bin/sh +# modified from pystardust, GPLv3 license: https://github.com/pystardust/sbar + +# INIT +sec=0 + +# MODULES +update_time () {  +	time="$(date '+%a %m/%d %H:%M') $(TZ=Asia/Shanghai date '+/%d %H:') $(date -u '+/%d %H:')" +} + +#update_cap () { +#	cap="$(if xset q | grep -q "Caps Lock: *on"; then echo A; else echo a; fi)" +#} + +update_net () {  +	net="$(if nmcli -t --fields type,state device | grep -q '^\(ethernet\|wifi\):connected$'; then echo 1; else echo 0; fi)" +	nm_device_state="$(nmcli -t --fields device,state device)" +	vpn="$( +		if echo "$nm_device_state" | grep -q '^wg_ka:connected$'; then +			echo K +		elif echo "$nm_device_state" | grep -q '^wg_studio:connected$'; then +			echo S +		else +			echo 0 +		fi +	)" +} + +update_vol () {  +	# $(NF-1) for both alsa and pulseaudio +	vol="$(amixer get Master | awk -F'[][]' 'END{printf("%d %s",($(NF-1)=="on")?1:0,$2)}')" +} + +update_mic () {  +	# $(NF-1) for both alsa and pulseaudio +	mic="$(amixer get Capture | awk -F '[][]' 'END{print ($(NF-1)=="on")?1:0}')" +} + +update_bat () {  +	bat="$(cat /sys/class/power_supply/BAT0/capacity)%" +} + +update_gpu () { +	gpu="$(envycontrol -q | awk 'END{print toupper(substr($NF,0,1))}')" +} + +display () { +	xsetroot -name "$time | N $net V $vpn | M $vol C $mic | $gpu | $bat" +} + +# modules that don't update on their own need to be run at the start for getting their initial value +update_net +update_vol +update_mic +update_gpu + +# SIGNALLING +# trap	"<function>;display"	"RTMIN+n" +trap	"update_mic;display" 	"RTMIN" +trap	"update_vol;display"	"RTMIN+1" +# xev can't read my toggle internet keyboard key, don't know what key to use in sxhkd to send signal +trap	"update_net;display"	"RTMIN+2" +# to update it from external commands +## kill -m $(pidof -x sbar) +# where m = 34 + n + +while :; do +	sleep 1 & +	wait +	[ $((sec % 5 )) -eq 0 ] && update_time 	# update time every 5 seconds +	[ $((sec % 60)) -eq 0 ] && update_net +	[ $((sec % 60)) -eq 0 ] && update_bat +	# zoom turn on my mic on start, so need to monitor the change +	[ $((sec % 60 )) -eq 0 ] && update_mic +	# how often the display updates ( 5 seconds ) +	[ $((sec % 5 )) -eq 0 ] && display +	sec=$((sec + 1)) +done @@ -0,0 +1,5 @@ +#!/bin/sh +# TIme Alarm + +time -p "$@" +o alarm 0 'Command Finished' "$(/usr/bin/printf '%q ' "$@")" diff --git a/sh/time-uuid b/sh/time-uuid new file mode 100755 index 0000000..bdaf4b3 --- /dev/null +++ b/sh/time-uuid @@ -0,0 +1,6 @@ +#!/bin/sh + +# echo current nanosecond since epoch and alpha-numerically ordered UUID +# https://stackoverflow.com/questions/28681650/generate-alpha-numerically-ordered-uuids-over-time?noredirect=1&lq=1 +# https://askubuntu.com/questions/342842/what-does-this-command-mean-awk-f-print-4 +echo "$(date '+%s-%N')-$(uuidgen -t | awk -F- '{OFS="-"; print $3,$2,$1,$4,$5}')" @@ -0,0 +1,8 @@ +#!/bin/sh + +o alacritty -e htop +#o alacritty -e radeontop -c +o alacritty -e iotop +o alacritty -e nethogs +o alacritty -e intel_gpu_top +o alacritty -e nvtop @@ -0,0 +1,219 @@ +#!/bin/sh + +all () { +	fast +	clean +	[ "$hostname" != xyzpp ] && refl +	[ "$hostname" = xyzka ] && qb +	[ "$hostname" = xyzinsp ] && music +	if [ "$hostname" = xyzinsp ] || [ "$hostname" = xyzpp ]; then +		userjs +	fi +} + +backup () { +	case "$hostname" in +		xyzinsp) backup_branch=master;; +		*) backup_branch=${hostname#xyz};; +	esac + +	if [ "$hostname" = xyzinsp ]; then +		# Pull repos and branches from studio, so one more backup on insp or duplicity will backup to ka,for one more backup for 321 backup rule +		# cfgl master and pp branches already satisfy 321 rule. Here are three copies: 1. master/pp, 2. studio, 3. gitlab or alternative +		# But I still copy those on insp because one more copy will not hurt. And all my other data stil satisfy 3 copies without backup to gitlab, so why left out cfgl? Also it may be nice if I what to use that local dir for searching things. +		cd "$HOME/programs/config_local_arch" || exit 1 +		git branch | awk '{print ($1=="*")?$2:$1}' | while read -r branch; do +			git checkout "$branch" +			git pull +			# Push ka branch to codeberg or any future alternative website for mirroring. Needed for public codes/data, considering my death may result in all copies on my computers being lost. +			[ "$branch" = ka ] && git push +		done +		# git checkout will change mtime, need to change back so rsync won't think it needs to backup these files +		# https://stackoverflow.com/q/1964470/9008720 +		# https://stackoverflow.com/q/21735435/9008720 +		# https://github.com/MestreLion/git-tools +		# aur/git-tools-git +		git restore-mtime + +		( +			umask 077 +			# backup ka cfgl +			sudo -E git -C /root/programs/config_local_arch_secrets_ka pull +			# backup studio cfgl +			sudo -E git -C /root/programs/config_local_arch_secrets pull +		) + +		# rsync backup from studio to insp +		rsync -avPR --delete studio:/home/xyz/.config/qBittorrent :/home/xyz/.local/share/qBittorrent/BT_backup "$HOME/backup/studio" + +	fi +	 +	if [ "$hostname" = xyzinsp ] || [ "$hostname" = xyzstudio ]; then +		# rsync backup from ka +		rsync -avPR --delete ka:/home/xyz/.config/qBittorrent :/home/xyz/.local/share/qBittorrent/BT_backup "$HOME/backup/ka" +	fi + +	if [ "$hostname" != xyzstudio ] && [ "$hostname" != xyzka ]; then +		# rsync backup to studio +		# --files-from make -a not imply -r, so need to specify explicitly +		rsync -avPRr --delete --files-from="$XDG_CONFIG_HOME/myconf/upd_rsync_files" / "studio:/home/xyz/backup/$backup_branch" +	fi + +	if [ "$hostname" != xyzka ]; then +		# duplicity backup to ka +		# https://wiki.archlinux.org/title/Duplicity +		# Need // for absolute path, see manpage URL FORMAT section. If not use //, will store to /home/xyz/home/xyz/... +		# --files-from has a bug, this bug makes source url that is / not working while /home works, more see vq notes +		# --use-agent not working when ssh to pp and insp, works on insp, not sure why +		use_agent= +		[ "$hostname" = xyzinsp ] && use_agent='--use-agent' +		sudo duplicity --ssh-askpass $use_agent --encrypt-key 9790577D2BE328D46838117ED3F54FE03F3C68D6 --sign-key 05899270DF25BB1EEDF57BE824F769E5D08C9E9A --full-if-older-than 2Y --include /etc/.cfgs --include-filelist "/home/xyz/.config/myconf/upd_rsync_files" --exclude / / "sftp://xyz@xyzka.kyun.li//home/xyz/backup/$backup_branch" +	fi +} + +clean () { +	if [ "$hostname" = xyzinsp ]; then +		nsxiv -c +		# my ways +		# -exec can't replace -execdir here +		find "$XDG_CACHE_HOME/nsxiv/" -depth -type d -empty -execdir rmdir -- '{}' \+ +		# -exec can replace -execdir here +		#find "$XDG_CACHE_HOME/nsxiv/" -depth -type d -execdir rmdir --ignore-fail-on-non-empty -- '{}' \+ +		# nsxiv man page way +		#find "$XDG_CACHE_HOME/nsxiv/" -depth -type d -empty ! -name '.' -exec rmdir -- '{}' \; + +	fi + +	if [ "$hostname" = xyzinsp ] || [ "$hostname" = xyzpp ]; then +		cd "$HOME/.mozilla/firefox/xxxxxxxx.fly/prefsjs_backups" || exit +		# https://stackoverflow.com/a/34862475/9008720 +		ls -t | tail -n +11 | tr '\n' '\0' | xargs -0 rm -- +		# https://unix.stackexchange.com/questions/92095/reset-atq-list-to-zero +		sudo systemctl stop atd +		echo 0 | sudo tee /var/spool/atd/.SEQ > /dev/null +		sudo systemctl start atd +		rm -rf "$XDG_VIDEOS_DIR/recordings/tmp/" +	fi + +	paru -aSc --noconfirm +} + +# basic daily stuff +fast () { +	pac +	misc +	[ "$hostname" != xyzka ] && backup +} + +userjs () { +	kill $(pidof "$BROWSER") +	# change working dir for cleaner +	cd "$HOME/.mozilla/firefox/xxxxxxxx.fly" || exit +	arkenfox-cleaner -s +	arkenfox-updater -s +} + +misc () { +	"$EDITOR" +PlugClean! +PlugUpdate +qa + +	if [ "$hostname" = xyzinsp ] || [ "$hostname" = xyzpp ]; then +		tldr --update +	fi + +	if [ "$hostname" = xyzinsp ]; then +		sudo hardcode-fixer +		ssh pp '[ -s "$HOME/.local/share/sdcv_history" ] && cat "$HOME/.local/share/sdcv_history" && rm "$HOME/.local/share/sdcv_history"' >> "$XDG_DATA_HOME/sdcv_history" +		awk '!a[$0]++' "$XDG_DATA_HOME/sdcv_history" | sponge "$XDG_DATA_HOME/sdcv_history" +		# temperory solution before find a way of using git submodule or subtree with `cfg -l` +		git -C "$HOME/.mozilla/firefox/xxxxxxxx.fly/chrome/firefox-csshacks" pull +		git -C "$XDG_DOCUMENTS_DIR/notes" commit --all -m 'update' +		git -C "$XDG_DOCUMENTS_DIR/notes" push +		git -C "$HOME/programs/reminders" commit --all -m 'update' +		git -C "$HOME/programs/reminders" push +		pass git push +	fi + +	if [ "$hostname" = xyzpp ]; then +		git -C "$XDG_DOCUMENTS_DIR/notes" pull +		git -C "$HOME/programs/reminders" pull +		pass git pull +	fi +} + +pac () { +	pacpacs="$(sudo pacman --noconfirm -Syu | tee /dev/tty | grep -m1 '^Packages' | cut -d' ' -f3-)" +	# Update rust toolchains before paru so paru can compile things in newest rust if needed. +	rustup update +	aurpacs="$(paru --color never --noconfirm -aSu --ignore libredwg-git | tee /dev/tty | grep '^Aur' | cut -d' ' -f3-)" +	# part steal from aur comment +	# sometimes "ERROR: Failure while downloading": https://github.com/neovim/neovim/issues/15709 +	# echo 1, printf 1 and yes 1 all works? not sure why +	# aur neovim-nightly-bin has some issue on 12/26/2021? switch to community repo neovim temporary +	#rm -rf ~/.cache/paru/clone/neovim-nightly-bin/ && echo 1 | PARU_PAGER=cat paru --rebuild --redownload neovim-nightly-bin +	pacman -Qqme > "$XDG_CONFIG_HOME/myconf/pacman_Qqme" +	pacman -Qqne > "$XDG_CONFIG_HOME/myconf/pacman_Qqne" +	systemctl list-unit-files --state=enabled > "$XDG_CONFIG_HOME/myconf/sye" +	systemctl --user list-unit-files --state=enabled > "$XDG_CONFIG_HOME/myconf/syue" +	# pacdiff default use pacman database, so no need `sudo -E` for find, but will be a little bit slower +	log="$log +updated pacman packages: $pacpacs +updated aur packages: $aurpacs +pacdiff: $(pacdiff -o | tr '\n' ' ') +checkrebuild: $(checkrebuild | awk '$2!~"zoom|miniconda3"{printf("%s ",$2)}') +$(if echo "$pacpacs" | grep -q 'linux-\(megi-\)\?[0-9]'; then echo 'kernel upgraded, need reboot'; fi) +" +} + +qb () { +	sudo systemctl stop qbittorrent-nox@xyz.service +	find "$XDG_DATA_HOME/qBittorrent/nova3/engines" -maxdepth 1 -type f ! -name 'jackett*' -a ! -name '__init__.py' -delete +	curlqb "$XDG_DATA_HOME/qBittorrent/nova3/engines" +	sudo systemctl start qbittorrent-nox@xyz.service +} + +refl () { +	# why not use http: +	# https://www.reddit.com/r/archlinux/comments/kx149z/should_i_use_http_mirrors/ +	# https://www.reddit.com/r/archlinux/comments/ej4k4d/is_it_safe_to_use_not_secured_http_pacman_mirrors/ +	# rsync may need to change XferCommand in /etc/pacman.conf +	# https://www.reddit.com/r/archlinux/comments/mynw6e/rsync_mirrors_with_pacman/ +	# need --delay so no super out of sync mirrors +	if [ "$hostname" != xyzka ]; then +		sudo reflector --verbose --save /etc/pacman.d/mirrorlist --country us --protocol https --delay 1 --latest 25 --score 25 --fastest 10 +	else +		sudo reflector --verbose --save /etc/pacman.d/mirrorlist --country ro --protocol https --delay 1 --fastest 3 +	fi +} + +music () { +	yt-dlp -f 'bestaudio[ext=opus]/bestaudio' --match-filter 'license=cc-by' --match-filter 'title~=(?i)cc-by' -P "$XDG_MUSIC_DIR/cc-by/scott_buckley" https://soundcloud.com/scottbuckley/tracks +	rsync -avP --delete "$XDG_MUSIC_DIR/cc-by/scott_buckley" pp:/home/xyz/music/cc-by +	rsync -avP --delete "$XDG_MUSIC_DIR/favorite" pp:/home/xyz/music +} + +hostname="$(hostname)"  +[ "$hostname" = xyzpp ] && gsettings set org.gnome.settings-daemon.plugins.power sleep-inactive-ac-type nothing +if [ $# -eq 0 ]; then +	fast +else +	while getopts abcfjmMpqr opt; do +		case $opt in +			a)all;; +			b)backup;; +			c)clean;; +			f)fast;; +			j)userjs;; +			m)misc;; +			M)music;; +			p)pac;; +			q)qb;; +			r)refl;; +			\?)exit 1;; +		esac +	done +fi +[ "$log" ] && printf '%s' "$log" | tee "$XDG_DOCUMENTS_DIR/logs/upd.log" +[ "$hostname" = xyzpp ] && gsettings set org.gnome.settings-daemon.plugins.power sleep-inactive-ac-type suspend +# `[ "$hostname" = xyzpp ] && ...` if check failed will have exit status of 1, unlike check with `if` +# I decided to always `exit 0` if reached end, so commands like `upd -p && ...` can keep running +exit 0 diff --git a/sh/vinfo b/sh/vinfo new file mode 100755 index 0000000..190de19 --- /dev/null +++ b/sh/vinfo @@ -0,0 +1,4 @@ +#!/bin/sh + +# steal from https://github.com/HiPhish/info.vim +"$EDITOR" -RM +"Info $1 $2" +only @@ -0,0 +1,11 @@ +#!/bin/sh + +# blue, see `man terminfo` +setaf="$(tput setaf 4)" +sgr0="$(tput sgr0)" + +# dash `command -V "$@"` will only output first command's type, same as `type`, but different than posix specification? so not use here +for cmd in type whatis whereis which "pacman -Qo --color always"; do +	printf '\n%s\n%s\n' "$setaf$cmd $*$sgr0" "$($cmd "$@" 2>&1)" +	#printf '\n\033[0;34m%s\033[0m\n%s\n' "$setaf$cmd $*$sgr0" "$($cmd "$@" 2>&1)" +done | "$PAGER" @@ -0,0 +1,43 @@ +#!/bin/sh + +# https://github.com/open-meteo/open-meteo +i=0 +curl -s -G -d "latitude=${1:-37.34}" -d "longitude=${2:--121.89}" -d 'daily=weathercode,temperature_2m_max,temperature_2m_min,sunrise,sunset' -d 'timezone=auto' 'https://api.open-meteo.com/v1/forecast' | jq -r '[.daily|.time, .weathercode, .temperature_2m_max, .temperature_2m_min, .sunrise, .sunset]|transpose|.[]|@tsv' | while read -r time code max min sunrise sunset; do +	# https://open-meteo.com/en/docs +	case "$code" in +		0) code='clear sky';; +		1) code='mainly clear';; +		2) code='partly cloudy';; +		3) code=overcast;; +		45) code=fog;; +		48) code='depositing rime fog';; +		51) code='light drizzle';; +		53) code='moderate drizzle';; +		55) code='dense drizzle';; +		56) code='light freezing drizzle';; +		57) code='dense freezing drizzle';; +		61) code='slight rain';; +		63) code='moderate rain';; +		65) code='heavy rain';; +		66) code='light freeze rain';; +		67) code='heavy freeze rain';; +		71) code='slight snow fall';; +		73) code='moderate snow fall';; +		75) code='heavy snow fall';; +		77) code='snow grains';; +		80) code='slight rain showers';; +		81) code='moderate rain showers';; +		82) code='violent rain showers';; +		85) code='slight snow showers';; +		86) code='heavy snow showers';; +		95) code='slight or moderate thunderstorm';; +		96) code='thunderstorm with slight hail';; +		99) code='thunderstorm with heavy hail';; +		*) exit 1;; +	esac +	if [ "$i" -ne 1 ]; then +		printf 'sunrise: %s | sunset: %s\n' "${sunrise#*T}" "${sunset#*T}" +		i=1 +	fi +	printf '%s\t%s\t%s\t%s\n' "${time#*-}" "$max" "$min" "$code" +done @@ -0,0 +1,3 @@ +#!/bin/sh + +xdg-mime query filetype "$1" | tee /dev/tty | xargs xdg-mime query default | 
