Compare commits
16
Commits
f6015f8d98
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e2fd3e4aa9
|
||
|
|
4a96319bb2
|
||
|
|
faad434dad
|
||
|
|
9896d9bb21
|
||
|
|
248a9b7d1f
|
||
|
|
216e1bff0f
|
||
|
|
472bf7246b
|
||
|
|
0d1cb6cf2a
|
||
|
|
96903a4d22
|
||
|
|
ce1cd479df
|
||
|
|
c103510786
|
||
|
|
3053b35f26
|
||
|
|
a260a42352
|
||
|
|
566ac562bd
|
||
|
|
3bb25669ea
|
||
|
|
84eec8c855
|
No files matched your search
@@ -2,4 +2,4 @@
|
|||||||
# Here rather than in LDFLAGS: old libtool (<2.4.7) drops -fuse-ld=lld, and these then reach GNU ld.
|
# Here rather than in LDFLAGS: old libtool (<2.4.7) drops -fuse-ld=lld, and these then reach GNU ld.
|
||||||
-fuse-ld=lld
|
-fuse-ld=lld
|
||||||
-Wl,--thinlto-cache-dir=/home/fuxino/.cache/thinlto
|
-Wl,--thinlto-cache-dir=/home/fuxino/.cache/thinlto
|
||||||
-Wl,--thinlto-cache-policy=cache_size_bytes=10g
|
-Wl,--thinlto-cache-policy=cache_size_bytes=10g:prune_after=0s
|
||||||
@@ -20,7 +20,7 @@ format.notifytime=%T
|
|||||||
format.appointmenttime=%H:%M
|
format.appointmenttime=%H:%M
|
||||||
format.outputdate=%F
|
format.outputdate=%F
|
||||||
format.dayheading=%B %e, %Y
|
format.dayheading=%B %e, %Y
|
||||||
general.autogc=no
|
general.autogc=yes
|
||||||
general.autosave=yes
|
general.autosave=yes
|
||||||
general.confirmdelete=yes
|
general.confirmdelete=yes
|
||||||
general.confirmquit=yes
|
general.confirmquit=yes
|
||||||
@@ -28,6 +28,6 @@ general.firstdayofweek=monday
|
|||||||
general.multipledays=yes
|
general.multipledays=yes
|
||||||
general.periodicsave=0
|
general.periodicsave=0
|
||||||
general.systemevents=yes
|
general.systemevents=yes
|
||||||
notification.command=calcurse --next | xargs -0 notify-send "Appointment"
|
notification.command=calcurse --next | xargs -0 notify-send -a calcurse -i x-office-calendar "Appointment"
|
||||||
notification.notifyall=all
|
notification.notifyall=all
|
||||||
notification.warning=3600
|
notification.warning=3600
|
||||||
Executable
+6
@@ -0,0 +1,6 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Sync the UI's saved changes once it exits (syncing while it runs would change files under it).
|
||||||
|
[ "$(ps -o args= -p "$PPID")" = calcurse ] && [ "$(ps -o tty= -p "$PPID" | tr -d ' ')" != '?' ] || exit 0
|
||||||
|
# shellcheck disable=SC2016 # $1 expands in the inner shell
|
||||||
|
setsid -f sh -c 'while kill -0 "$1" 2>/dev/null; do sleep 1; done; systemctl --user start calcurse-sync.service' \
|
||||||
|
sh "$PPID" >/dev/null 2>&1
|
||||||
Executable
+5
@@ -0,0 +1,5 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Sync with Google before the UI loads. Non-interactive calls (-Q, -d, -i, calcurse-caldav's own) run this hook
|
||||||
|
# too, so act only for the UI: a bare "calcurse" with a terminal (the daemon is bare too, but has none).
|
||||||
|
[ "$(ps -o args= -p "$PPID")" = calcurse ] && [ "$(ps -o tty= -p "$PPID" | tr -d ' ')" != '?' ] || exit 0
|
||||||
|
calcurse-sync --now 2>&1 | systemd-cat -t calcurse-sync
|
||||||
@@ -300,7 +300,7 @@
|
|||||||
# * context_all: Open context menu for all notifications.
|
# * context_all: Open context menu for all notifications.
|
||||||
# These values can be strung together for each mouse event, and
|
# These values can be strung together for each mouse event, and
|
||||||
# will be executed in sequence.
|
# will be executed in sequence.
|
||||||
mouse_left_click = close_current
|
mouse_left_click = do_action, close_current
|
||||||
mouse_middle_click = do_action, close_current
|
mouse_middle_click = do_action, close_current
|
||||||
mouse_right_click = close_all
|
mouse_right_click = close_all
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
mainwindow_position = mouse
|
|
||||||
close_on_unfocus = 1
|
|
||||||
mark_today = 1
|
|
||||||
show_week_numbers = 1
|
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Ask to renew the calcurse Google Calendar login
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
# simple: the prompt waits for a click without a start timeout
|
||||||
|
Type=simple
|
||||||
|
ExecStart=%h/.local/bin/calcurse-relogin --prompt
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Sync calcurse with Google Calendar
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=oneshot
|
||||||
|
ExecStart=%h/.local/bin/calcurse-sync
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Sync calcurse with Google Calendar hourly
|
||||||
|
|
||||||
|
[Timer]
|
||||||
|
OnActiveSec=1min
|
||||||
|
OnCalendar=hourly
|
||||||
|
Persistent=true
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Notify today's calcurse events
|
||||||
|
After=calcurse-sync.service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=oneshot
|
||||||
|
ExecStart=%h/.local/bin/calcurse-today
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Notify today's calcurse events every morning
|
||||||
|
|
||||||
|
[Timer]
|
||||||
|
OnCalendar=*-*-* 09:00
|
||||||
|
Persistent=true
|
||||||
@@ -5,7 +5,7 @@ StartLimitBurst=4
|
|||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
Type=oneshot
|
Type=oneshot
|
||||||
ExecStart=%h/.local/bin/garmin-dump
|
ExecStart=%h/.local/bin/db-dump negsplit Garmin week
|
||||||
# MariaDB not up yet (e.g. caught up right after boot)? retry a few times
|
# MariaDB not up yet (e.g. caught up right after boot)? retry a few times
|
||||||
Restart=on-failure
|
Restart=on-failure
|
||||||
RestartSec=5min
|
RestartSec=5min
|
||||||
@@ -5,7 +5,7 @@ StartLimitBurst=4
|
|||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
Type=oneshot
|
Type=oneshot
|
||||||
ExecStart=%h/.local/bin/library-dump
|
ExecStart=%h/.local/bin/db-dump library_manager Library day
|
||||||
# MariaDB not up yet (e.g. caught up right after boot)? retry a few times
|
# MariaDB not up yet (e.g. caught up right after boot)? retry a few times
|
||||||
Restart=on-failure
|
Restart=on-failure
|
||||||
RestartSec=5min
|
RestartSec=5min
|
||||||
@@ -5,7 +5,7 @@ StartLimitBurst=4
|
|||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
Type=oneshot
|
Type=oneshot
|
||||||
ExecStart=%h/.local/bin/weather-dump
|
ExecStart=%h/.local/bin/db-dump ens-forecast Weather week
|
||||||
# MariaDB not up yet (e.g. caught up right after boot)? retry a few times
|
# MariaDB not up yet (e.g. caught up right after boot)? retry a few times
|
||||||
Restart=on-failure
|
Restart=on-failure
|
||||||
RestartSec=5min
|
RestartSec=5min
|
||||||
Executable
+42
@@ -0,0 +1,42 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Next calcurse item for xmobar: pink " 10:15 | " for an appointment later today, a cyan icon for a whole-day
|
||||||
|
# event today, a pink icon alone when the next appointment is tomorrow; empty otherwise.
|
||||||
|
# With "list": show today's and tomorrow's items in a notification (for a click on the bar)
|
||||||
|
set -uo pipefail
|
||||||
|
|
||||||
|
icon=$'\xf3\xb0\x83\xad' # nf-md-calendar, as UTF-8 bytes so the locale doesn't matter
|
||||||
|
today=$(date +%F)
|
||||||
|
|
||||||
|
query() {
|
||||||
|
calcurse -Q --filter-type cal --days 2 --output-datefmt %F "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
if [[ ${1:-} == list ]]; then
|
||||||
|
tomorrow=$(date -d tomorrow +%F)
|
||||||
|
body=$(query --format-apt '%S–%E %m\n' --format-recur-apt '%S–%E %m\n' \
|
||||||
|
--format-event 'all day %m\n' --format-recur-event 'all day %m\n' |
|
||||||
|
sed -e 's/&/\&/g; s/</\</g; s/>/\>/g' -e "s/^$today:$/Today:/; s/^$tomorrow:$/Tomorrow:/")
|
||||||
|
notify-send -a calcurse -i x-office-calendar "Calendar" "${body:-Nothing today or tomorrow}"
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
now=$(date +%s)
|
||||||
|
day="" next="" event=false
|
||||||
|
while read -r kind start; do
|
||||||
|
case $kind in
|
||||||
|
*:) day=${kind%:} ;;
|
||||||
|
A) [[ -z $next ]] && ((start > now)) && next=$start ;;
|
||||||
|
E) [[ $day == "$today" ]] && event=true ;;
|
||||||
|
esac
|
||||||
|
done < <(query --format-apt 'A %s\n' --format-recur-apt 'A %s\n' --format-event 'E\n' --format-recur-event 'E\n')
|
||||||
|
|
||||||
|
if [[ -n $next && $(date -d "@$next" +%F) == "$today" ]]; then
|
||||||
|
text="<fc=#ff79c6>$icon $(date -d "@$next" +%H:%M)</fc>"
|
||||||
|
elif $event; then
|
||||||
|
text="<fc=#8be9fd>$icon</fc>"
|
||||||
|
elif [[ -n $next ]]; then
|
||||||
|
text="<fc=#ff79c6>$icon</fc>"
|
||||||
|
else
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
echo "$text | "
|
||||||
Executable
+81
@@ -0,0 +1,81 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Current weather for xmobar, e.g. "<icon> 7°C": NOAA's decoded METAR (the source of xmobar's Weather plugin)
|
||||||
|
# Icon from the weather, else the sky conditions; clear/partly/mostly cloudy get moon icons when the sun is down.
|
||||||
|
# Temperature colors match the plugin's -L 0 -H 30: low up to 0, high above 30.
|
||||||
|
# With "notify": show the description (e.g. "Light drizzle, mist") and temperature in a notification instead.
|
||||||
|
|
||||||
|
STATION=LZIB LAT=48.2 LON=17.2
|
||||||
|
|
||||||
|
declare -A ICON=(
|
||||||
|
[thermometer]=$'\xef\x8b\x89' [day_sunny]=$'\xee\x8c\x8d' [night_clear]=$'\xee\x8c\xab'
|
||||||
|
[day_cloudy]=$'\xee\x8c\x82' [night_partly_cloudy]=$'\xee\x8d\xb9' [day_sunny_overcast]=$'\xee\x8c\x8c'
|
||||||
|
[night_cloudy]=$'\xee\x8d\xbe' [cloudy]=$'\xee\x8c\x92' [cloud]=$'\xee\x8c\xbd'
|
||||||
|
[thunderstorm]=$'\xee\x8c\x9d' [rain_mix]=$'\xee\x8c\x96' [snow]=$'\xee\x8c\x9a' [showers]=$'\xee\x8c\x99'
|
||||||
|
[rain]=$'\xee\x8c\x98' [sprinkle]=$'\xee\x8c\x9b' [fog]=$'\xee\x8c\x93' [smoke]=$'\xee\x8d\x9c'
|
||||||
|
[dust]=$'\xee\x8d\x9d'
|
||||||
|
)
|
||||||
|
|
||||||
|
report=$(curl -sf --max-time 20 https://tgftp.nws.noaa.gov/data/observations/metar/decoded/"$STATION".TXT)
|
||||||
|
temp=$(sed -n 's/^Temperature: .*(\([-0-9.]*\) C).*/\1/p' <<< "$report")
|
||||||
|
if [[ -z $temp ]]; then
|
||||||
|
if [[ $1 == notify ]]; then notify-send "Weather" "No report from $STATION"; else echo "<fn=1>${ICON[thermometer]}</fn> N/A"; fi
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Phenomena "in the vicinity" aren't at the station; the rest are e.g. "light drizzle; mist"
|
||||||
|
wx=$(sed -n 's/^Weather: //p' <<< "$report" | tr ';' '\n' | sed 's/^ *//' | grep -v vicinity)
|
||||||
|
wx=${wx,,}
|
||||||
|
sky=$(sed -n 's/^Sky conditions: //p' <<< "$report")
|
||||||
|
# CAVOK/NSC (no cloud below 5000 ft) have no sky line in the decoded report
|
||||||
|
[[ -z $sky ]] && grep -qE '^ob: .* (CAVOK|NSC) ' <<< "$report" && sky=clear
|
||||||
|
sky=${sky,,}
|
||||||
|
|
||||||
|
# Sun above the horizon (elevation > -0.833°, as for sunrise/sunset) right now, from the low-precision solar position
|
||||||
|
sun_up() {
|
||||||
|
awk -v t="$(date +%s)" -v lat="$LAT" -v lon="$LON" 'BEGIN {
|
||||||
|
r = atan2(0, -1) / 180; d = t / 86400 - 10957.5
|
||||||
|
g = (357.529 + 0.98560028 * d) * r
|
||||||
|
l = (280.459 + 0.98564736 * d + 1.915 * sin(g) + 0.020 * sin(2 * g)) * r
|
||||||
|
e = (23.439 - 0.00000036 * d) * r
|
||||||
|
ra = atan2(cos(e) * sin(l), cos(l)); s = sin(e) * sin(l); dec = atan2(s, sqrt(1 - s * s))
|
||||||
|
h = (280.46061837 + 360.98564736629 * d + lon) * r - ra
|
||||||
|
exit !(sin(lat * r) * sin(dec) + cos(lat * r) * cos(dec) * cos(h) > sin(-0.833 * r))
|
||||||
|
}'
|
||||||
|
}
|
||||||
|
|
||||||
|
case $wx in
|
||||||
|
*thunder*) icon=thunderstorm ;;
|
||||||
|
*freezing*|*sleet*|*ice\ pellets*|*hail*) icon=rain_mix ;;
|
||||||
|
*snow*rain*|*rain*snow*|*snow*drizzle*|*drizzle*snow*) icon=rain_mix ;;
|
||||||
|
*snow*) icon=snow ;;
|
||||||
|
*showers*) icon=showers ;;
|
||||||
|
*rain*) icon=rain ;;
|
||||||
|
*drizzle*) icon=sprinkle ;;
|
||||||
|
*fog*|*mist*) icon=fog ;;
|
||||||
|
*haze*|*smoke*) icon=smoke ;;
|
||||||
|
*dust*|*sand*) icon=dust ;;
|
||||||
|
*)
|
||||||
|
case $sky in
|
||||||
|
clear*) if sun_up; then icon=day_sunny; else icon=night_clear; fi ;;
|
||||||
|
"mostly clear"*|"partly cloudy"*) if sun_up; then icon=day_cloudy; else icon=night_partly_cloudy; fi ;;
|
||||||
|
"mostly cloudy"*) if sun_up; then icon=day_sunny_overcast; else icon=night_cloudy; fi ;;
|
||||||
|
overcast*|obscured*) icon=cloudy ;;
|
||||||
|
*) icon=cloud ;;
|
||||||
|
esac
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if awk -v t="$temp" 'BEGIN { exit !(t > 30) }'; then color="#ffb86c"
|
||||||
|
elif awk -v t="$temp" 'BEGIN { exit !(t > 0) }'; then color="#50fa7b"
|
||||||
|
else color="#8be9fd"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ $1 == notify ]]; then
|
||||||
|
if [[ -n $wx ]]; then desc=$(paste -sd, <<< "$wx" | sed 's/,/, /g')
|
||||||
|
elif [[ $icon == day_sunny ]]; then desc=sunny
|
||||||
|
else desc=${sky:-unknown}
|
||||||
|
fi
|
||||||
|
notify-send "${ICON[$icon]} Weather" "${desc^}, $temp°C"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
echo "<fn=1>${ICON[$icon]}</fn> <fc=$color>$temp</fc>°C"
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
Config { overrideRedirect = True
|
Config { overrideRedirect = True
|
||||||
, lowerOnStart = True
|
, lowerOnStart = True
|
||||||
, font = "Jetbrains Mono Nerd Font Bold 10"
|
, font = "Jetbrains Mono Nerd Font Bold 10"
|
||||||
|
, additionalFonts = ["Jetbrains Mono Nerd Font Bold 13"]
|
||||||
, bgColor = "#24283b"
|
, bgColor = "#24283b"
|
||||||
, fgColor = "#737aa2"
|
, fgColor = "#737aa2"
|
||||||
, position = TopH 24
|
, position = TopH 24
|
||||||
@@ -8,14 +9,7 @@ Config { overrideRedirect = True
|
|||||||
, borderColor = "#24283b"
|
, borderColor = "#24283b"
|
||||||
, allDesktops = True
|
, allDesktops = True
|
||||||
, pickBroadest = True
|
, pickBroadest = True
|
||||||
, commands = [ Run Weather "LZIB"
|
, commands = [ Run Com "/home/fuxino/.config/xmobar/weather.sh" [] "weather" 9000
|
||||||
[ "--template", "\xf2c9 <tempC>°C"
|
|
||||||
, "-L", "0"
|
|
||||||
, "-H", "30"
|
|
||||||
, "--low" , "#8be9fd"
|
|
||||||
, "--normal" , "#50fa7b"
|
|
||||||
, "--high" , "#ffb86c"
|
|
||||||
] 9000
|
|
||||||
, Run MultiCpu
|
, Run MultiCpu
|
||||||
[ "--template" , "\xf4bc <total>%"
|
[ "--template" , "\xf4bc <total>%"
|
||||||
, "--Low" , "25"
|
, "--Low" , "25"
|
||||||
@@ -45,17 +39,15 @@ Config { overrideRedirect = True
|
|||||||
, ("us" , "<fc=#ffb86c>US</fc>")
|
, ("us" , "<fc=#ffb86c>US</fc>")
|
||||||
, ("sk(qwerty)" , "<fc=#ff5555>SK</fc>")
|
, ("sk(qwerty)" , "<fc=#ff5555>SK</fc>")
|
||||||
]
|
]
|
||||||
, Run Date "\xf133 %a %Y-%m-%d <fc=#ff79c6>%H:%M</fc>" "date" 10
|
, Run Date "\xf133 %a %d/%m <fc=#ff79c6>%H:%M</fc>" "date" 10
|
||||||
, Run Uptime
|
|
||||||
[ "--template" , "\xf017 <days>d <hours>h"
|
|
||||||
] 600
|
|
||||||
, Run Com "/home/fuxino/.config/xmobar/pactl_volume.sh" [] "pactl_volume" 10
|
, Run Com "/home/fuxino/.config/xmobar/pactl_volume.sh" [] "pactl_volume" 10
|
||||||
, Run Com "/home/fuxino/.config/xmobar/ens_brief.sh" [] "ens_brief" 18000
|
, Run Com "/home/fuxino/.config/xmobar/ens_brief.sh" [] "ens_brief" 18000
|
||||||
, Run Com "/home/fuxino/.config/xmobar/updates.sh" [] "updates" 600
|
, Run Com "/home/fuxino/.config/xmobar/updates.sh" [] "updates" 600
|
||||||
, Run Com "/home/fuxino/.config/xmobar/backup.sh" [] "backup" 3600
|
, Run Com "/home/fuxino/.config/xmobar/backup.sh" [] "backup" 3600
|
||||||
|
, Run Com "/home/fuxino/.config/xmobar/calcurse.sh" [] "calcurse" 600
|
||||||
, Run UnsafeXMonadLog
|
, Run UnsafeXMonadLog
|
||||||
]
|
]
|
||||||
, sepChar = "%"
|
, sepChar = "%"
|
||||||
, alignSep = "}{"
|
, alignSep = "}{"
|
||||||
, template = " | %UnsafeXMonadLog% } %uptime% | %multicpu% %coretemp% | %memory% | <action=`/home/fuxino/.config/xmobar/kbd_cycle.sh` button=1><action=`/home/fuxino/.config/xmobar/kbd_cycle.sh prev` button=3> %kbd%</action></action> { <action=`/home/fuxino/.config/xmobar/backup.sh list`>%backup%</action><action=`/home/fuxino/.config/xmobar/updates.sh list`>%updates%</action><action=`/home/fuxino/.config/xmobar/ens_brief.sh week`>%LZIB% <fc=#565f89>·</fc> %ens_brief%</action> | %pactl_volume% | <action=`env GDK_DPI_SCALE=1.25 gsimplecal`>%date%</action> "
|
, template = " | %UnsafeXMonadLog% } %multicpu% %coretemp% | %memory% | <action=`/home/fuxino/.config/xmobar/kbd_cycle.sh` button=1><action=`/home/fuxino/.config/xmobar/kbd_cycle.sh prev` button=3> %kbd%</action></action> { <action=`/home/fuxino/.config/xmobar/calcurse.sh list` button=1><action=`xdotool key super+shift+a` button=3>%calcurse%</action></action><action=`/home/fuxino/.config/xmobar/backup.sh list`>%backup%</action><action=`/home/fuxino/.config/xmobar/updates.sh list`>%updates%</action><action=`/home/fuxino/.config/xmobar/weather.sh notify`>%weather%</action> <fc=#565f89>·</fc> <action=`/home/fuxino/.config/xmobar/ens_brief.sh week`>%ens_brief%</action> | <action=`pactl set-sink-mute @DEFAULT_SINK@ toggle` button=1>%pactl_volume%</action> | %date% "
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
Config { overrideRedirect = True
|
Config { overrideRedirect = True
|
||||||
, lowerOnStart = True
|
, lowerOnStart = True
|
||||||
, font = "Jetbrains Mono Nerd Font Bold 10"
|
, font = "Jetbrains Mono Nerd Font Bold 10"
|
||||||
|
, additionalFonts = ["Jetbrains Mono Nerd Font Bold 13"]
|
||||||
, bgColor = "#24283b"
|
, bgColor = "#24283b"
|
||||||
, fgColor = "#737aa2"
|
, fgColor = "#737aa2"
|
||||||
, position = TopH 24
|
, position = TopH 24
|
||||||
@@ -8,14 +9,7 @@ Config { overrideRedirect = True
|
|||||||
, borderColor = "#24283b"
|
, borderColor = "#24283b"
|
||||||
, allDesktops = True
|
, allDesktops = True
|
||||||
, pickBroadest = True
|
, pickBroadest = True
|
||||||
, commands = [ Run Weather "LZIB"
|
, commands = [ Run Com "/home/fuxino/.config/xmobar/weather.sh" [] "weather" 9000
|
||||||
[ "--template", "\xf2c9 <tempC>°C"
|
|
||||||
, "-L", "0"
|
|
||||||
, "-H", "30"
|
|
||||||
, "--low" , "#8be9fd"
|
|
||||||
, "--normal" , "#50fa7b"
|
|
||||||
, "--high" , "#ffb86c"
|
|
||||||
] 9000
|
|
||||||
, Run MultiCpu
|
, Run MultiCpu
|
||||||
[ "--template" , "\xf4bc <total>%"
|
[ "--template" , "\xf4bc <total>%"
|
||||||
, "--Low" , "25"
|
, "--Low" , "25"
|
||||||
@@ -45,18 +39,16 @@ Config { overrideRedirect = True
|
|||||||
, ("us" , "<fc=#ffb86c>US</fc>")
|
, ("us" , "<fc=#ffb86c>US</fc>")
|
||||||
, ("sk(qwerty)" , "<fc=#ff5555>SK</fc>")
|
, ("sk(qwerty)" , "<fc=#ff5555>SK</fc>")
|
||||||
]
|
]
|
||||||
, Run Date "\xf133 %a %Y-%m-%d <fc=#ff79c6>%H:%M</fc>" "date" 10
|
, Run Date "\xf133 %a %d/%m <fc=#ff79c6>%H:%M</fc>" "date" 10
|
||||||
, Run Uptime
|
|
||||||
[ "--template" , "\xf017 <days>d <hours>h"
|
|
||||||
] 600
|
|
||||||
, Run XPropertyLog "_XMONAD_TRAYPAD"
|
, Run XPropertyLog "_XMONAD_TRAYPAD"
|
||||||
, Run Com "/home/fuxino/.config/xmobar/pactl_volume.sh" [] "pactl_volume" 10
|
, Run Com "/home/fuxino/.config/xmobar/pactl_volume.sh" [] "pactl_volume" 10
|
||||||
, Run Com "/home/fuxino/.config/xmobar/ens_brief.sh" [] "ens_brief" 18000
|
, Run Com "/home/fuxino/.config/xmobar/ens_brief.sh" [] "ens_brief" 18000
|
||||||
, Run Com "/home/fuxino/.config/xmobar/updates.sh" [] "updates" 600
|
, Run Com "/home/fuxino/.config/xmobar/updates.sh" [] "updates" 600
|
||||||
, Run Com "/home/fuxino/.config/xmobar/backup.sh" [] "backup" 3600
|
, Run Com "/home/fuxino/.config/xmobar/backup.sh" [] "backup" 3600
|
||||||
|
, Run Com "/home/fuxino/.config/xmobar/calcurse.sh" [] "calcurse" 600
|
||||||
, Run UnsafeXMonadLog
|
, Run UnsafeXMonadLog
|
||||||
]
|
]
|
||||||
, sepChar = "%"
|
, sepChar = "%"
|
||||||
, alignSep = "}{"
|
, alignSep = "}{"
|
||||||
, template = " | %UnsafeXMonadLog% } %uptime% | %multicpu% %coretemp% | %memory% | <action=`/home/fuxino/.config/xmobar/kbd_cycle.sh` button=1><action=`/home/fuxino/.config/xmobar/kbd_cycle.sh prev` button=3> %kbd%</action></action> { <action=`/home/fuxino/.config/xmobar/backup.sh list`>%backup%</action><action=`/home/fuxino/.config/xmobar/updates.sh list`>%updates%</action><action=`/home/fuxino/.config/xmobar/ens_brief.sh week`>%LZIB% <fc=#565f89>·</fc> %ens_brief%</action> | %pactl_volume% | <action=`env GDK_DPI_SCALE=1.25 gsimplecal`>%date%</action> %_XMONAD_TRAYPAD% "
|
, template = " | %UnsafeXMonadLog% } %multicpu% %coretemp% | %memory% | <action=`/home/fuxino/.config/xmobar/kbd_cycle.sh` button=1><action=`/home/fuxino/.config/xmobar/kbd_cycle.sh prev` button=3> %kbd%</action></action> { <action=`/home/fuxino/.config/xmobar/calcurse.sh list` button=1><action=`xdotool key super+shift+a` button=3>%calcurse%</action></action><action=`/home/fuxino/.config/xmobar/backup.sh list`>%backup%</action><action=`/home/fuxino/.config/xmobar/updates.sh list`>%updates%</action><action=`/home/fuxino/.config/xmobar/weather.sh notify`>%weather%</action> <fc=#565f89>·</fc> <action=`/home/fuxino/.config/xmobar/ens_brief.sh week`>%ens_brief%</action> | <action=`pactl set-sink-mute @DEFAULT_SINK@ toggle` button=1>%pactl_volume%</action> | %date% %_XMONAD_TRAYPAD% "
|
||||||
}
|
}
|
||||||
@@ -2,7 +2,8 @@
|
|||||||
|
|
||||||
import Data.Monoid
|
import Data.Monoid
|
||||||
import Data.Char (toLower)
|
import Data.Char (toLower)
|
||||||
import Control.Monad (forM_, liftM2, when)
|
import Control.Monad (forM_, join, liftM2, when)
|
||||||
|
import qualified Data.Map.Strict as M
|
||||||
import Data.Maybe (isJust)
|
import Data.Maybe (isJust)
|
||||||
import XMonad
|
import XMonad
|
||||||
import XMonad.Actions.OnScreen (greedyViewOnScreen)
|
import XMonad.Actions.OnScreen (greedyViewOnScreen)
|
||||||
@@ -25,6 +26,7 @@ import XMonad.Layout.ThreeColumns
|
|||||||
import qualified XMonad.StackSet as W
|
import qualified XMonad.StackSet as W
|
||||||
import XMonad.Util.ClickableWorkspaces
|
import XMonad.Util.ClickableWorkspaces
|
||||||
import XMonad.Util.EZConfig
|
import XMonad.Util.EZConfig
|
||||||
|
import qualified XMonad.Util.ExtensibleState as XS
|
||||||
import qualified XMonad.Util.Hacks as Hacks
|
import qualified XMonad.Util.Hacks as Hacks
|
||||||
import XMonad.Util.Loggers
|
import XMonad.Util.Loggers
|
||||||
import XMonad.Util.NamedActions
|
import XMonad.Util.NamedActions
|
||||||
@@ -38,6 +40,7 @@ main :: IO ()
|
|||||||
main =
|
main =
|
||||||
xmonad
|
xmonad
|
||||||
. ewmhFullscreen
|
. ewmhFullscreen
|
||||||
|
. setEwmhFullscreenHooks myFullscreenHook myUnfullscreenHook
|
||||||
. setEwmhSwitchDesktopHook safeView
|
. setEwmhSwitchDesktopHook safeView
|
||||||
. ewmh
|
. ewmh
|
||||||
. docks
|
. docks
|
||||||
@@ -358,6 +361,8 @@ myStartupHook = do
|
|||||||
spawnOnce "nm-applet"
|
spawnOnce "nm-applet"
|
||||||
spawnOnce "arch-audit-gtk"
|
spawnOnce "arch-audit-gtk"
|
||||||
spawnOnce "calcurse --daemon"
|
spawnOnce "calcurse --daemon"
|
||||||
|
spawnOnce "systemctl --user start calcurse-today.timer"
|
||||||
|
spawnOnce "systemctl --user start calcurse-sync.timer"
|
||||||
spawnOnce "systemctl --user start dunst"
|
spawnOnce "systemctl --user start dunst"
|
||||||
spawnOnce "lxpolkit"
|
spawnOnce "lxpolkit"
|
||||||
spawnOnce "numlockx"
|
spawnOnce "numlockx"
|
||||||
@@ -377,8 +382,8 @@ myManageHook =
|
|||||||
className =? "Qalculate-gtk" --> doFloat,
|
className =? "Qalculate-gtk" --> doFloat,
|
||||||
title =? "Genshin Impact" --> doShift wsGames,
|
title =? "Genshin Impact" --> doShift wsGames,
|
||||||
classIn ["gimp", "audacity"] --> doShift wsMedia,
|
classIn ["gimp", "audacity"] --> doShift wsMedia,
|
||||||
classIn ["pavucontrol", "org.pulseaudio.pavucontrol", "zenity", "org.gnome.zenity", "lxappearance", "qt5ct", "qt6ct", "gsimplecal"] --> doFloat,
|
classIn ["pavucontrol", "org.pulseaudio.pavucontrol", "zenity", "org.gnome.zenity", "lxappearance", "qt5ct", "qt6ct"] --> doFloat,
|
||||||
className =? "Signal" --> doShift wsChat,
|
classIn ["signal", "discord"] --> doShift wsChat,
|
||||||
className =? "Spotify" --> doShift wsMedia,
|
className =? "Spotify" --> doShift wsMedia,
|
||||||
className =? "Transmission-gtk" --> doShift wsWeb,
|
className =? "Transmission-gtk" --> doShift wsWeb,
|
||||||
className =? "Viewnior" --> doFloat,
|
className =? "Viewnior" --> doFloat,
|
||||||
@@ -386,7 +391,6 @@ myManageHook =
|
|||||||
className =? "Xmessage" --> doFloat,
|
className =? "Xmessage" --> doFloat,
|
||||||
className =? "Xreader" --> doShift wsDocs,
|
className =? "Xreader" --> doShift wsDocs,
|
||||||
className =? "calibre" --> doShift wsDocs,
|
className =? "calibre" --> doShift wsDocs,
|
||||||
className =? "discord" --> doShift wsChat,
|
|
||||||
className =? "feh" --> doFloat,
|
className =? "feh" --> doFloat,
|
||||||
title =? "glxgears" --> doFloat,
|
title =? "glxgears" --> doFloat,
|
||||||
className =? "library_manager" --> doShift wsDocs,
|
className =? "library_manager" --> doShift wsDocs,
|
||||||
@@ -414,6 +418,31 @@ myManageHook =
|
|||||||
-- Case-insensitive, as GTK4 and firejailed apps capitalise their class differently
|
-- Case-insensitive, as GTK4 and firejailed apps capitalise their class differently
|
||||||
classIn names = (`elem` names) . map toLower <$> className
|
classIn names = (`elem` names) . map toLower <$> className
|
||||||
|
|
||||||
|
-- Fullscreen toggles: remember each window's float rect (Nothing if tiled) so leaving
|
||||||
|
-- fullscreen restores it instead of always sinking the window.
|
||||||
|
newtype PreFullscreen = PreFullscreen (M.Map Window (Maybe W.RationalRect))
|
||||||
|
|
||||||
|
instance ExtensionClass PreFullscreen where
|
||||||
|
initialValue = PreFullscreen M.empty
|
||||||
|
|
||||||
|
myFullscreenHook :: ManageHook
|
||||||
|
myFullscreenHook = do
|
||||||
|
w <- ask
|
||||||
|
liftX $ do
|
||||||
|
old <- gets (M.lookup w . W.floating . windowset)
|
||||||
|
XS.modify (\(PreFullscreen m) -> PreFullscreen (M.insert w old m))
|
||||||
|
doFullFloat
|
||||||
|
|
||||||
|
-- Windows with no record (e.g. opened fullscreen) are sunk, as before.
|
||||||
|
myUnfullscreenHook :: ManageHook
|
||||||
|
myUnfullscreenHook = do
|
||||||
|
w <- ask
|
||||||
|
old <- liftX $ do
|
||||||
|
PreFullscreen m <- XS.get
|
||||||
|
XS.put (PreFullscreen (M.delete w m))
|
||||||
|
pure (join (M.lookup w m))
|
||||||
|
maybe doSink doRectFloat old
|
||||||
|
|
||||||
-- Handle event hook
|
-- Handle event hook
|
||||||
myHandleEventHook :: Event -> X All
|
myHandleEventHook :: Event -> X All
|
||||||
myHandleEventHook =
|
myHandleEventHook =
|
||||||
|
|||||||
Executable
+101
@@ -0,0 +1,101 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Renew calcurse-caldav's Google login: catch the OAuth redirect on 127.0.0.1 and hand the code to calcurse-sync.
|
||||||
|
|
||||||
|
--prompt shows a notification first and logs in when it is clicked.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import configparser
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
import urllib.parse
|
||||||
|
from http.server import BaseHTTPRequestHandler, HTTPServer
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
CONFIG = Path(os.environ.get("XDG_CONFIG_HOME", Path.home() / ".config")) / "calcurse" / "caldav" / "config"
|
||||||
|
WAIT_SECONDS = 300
|
||||||
|
|
||||||
|
|
||||||
|
def notify(summary: str, body: str = "", *extra: str) -> str:
|
||||||
|
"""Send a calcurse notification; with actions in extra, wait and return the chosen action's name."""
|
||||||
|
cmd = ["notify-send", "-a", "calcurse", "-i", "x-office-calendar", *extra, summary, body]
|
||||||
|
return subprocess.run(cmd, capture_output=True, text=True).stdout.strip()
|
||||||
|
|
||||||
|
|
||||||
|
def redirect_port() -> int:
|
||||||
|
parser = configparser.RawConfigParser()
|
||||||
|
parser.read(CONFIG)
|
||||||
|
uri = urllib.parse.urlparse(parser.get("OAuth2", "RedirectURI", fallback=""))
|
||||||
|
if uri.hostname != "127.0.0.1" or uri.port is None:
|
||||||
|
sys.exit(f"RedirectURI in {CONFIG} must be http://127.0.0.1:<port>")
|
||||||
|
return uri.port
|
||||||
|
|
||||||
|
|
||||||
|
def ui_running() -> bool:
|
||||||
|
ttys = subprocess.run(["ps", "-C", "calcurse", "-o", "tty="], capture_output=True, text=True).stdout.split()
|
||||||
|
return any(tty != "?" for tty in ttys)
|
||||||
|
|
||||||
|
|
||||||
|
class RedirectHandler(BaseHTTPRequestHandler):
|
||||||
|
result: dict[str, str] = {}
|
||||||
|
|
||||||
|
def do_GET(self) -> None:
|
||||||
|
query = urllib.parse.parse_qs(urllib.parse.urlparse(self.path).query)
|
||||||
|
for key in ("code", "error"):
|
||||||
|
if key in query:
|
||||||
|
RedirectHandler.result[key] = query[key][0]
|
||||||
|
done = bool(RedirectHandler.result)
|
||||||
|
self.send_response(200 if done else 404)
|
||||||
|
self.send_header("Content-Type", "text/plain; charset=utf-8")
|
||||||
|
self.end_headers()
|
||||||
|
if done:
|
||||||
|
self.wfile.write(b"calcurse: login received, you can close this tab.\n")
|
||||||
|
|
||||||
|
def log_message(self, format: str, *args: object) -> None:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def login() -> int:
|
||||||
|
if ui_running():
|
||||||
|
notify("Google Calendar login", "Close calcurse first, then log in again.", "-u", "critical")
|
||||||
|
return 1
|
||||||
|
server = HTTPServer(("127.0.0.1", redirect_port()), RedirectHandler)
|
||||||
|
# With an expired login calcurse-caldav opens the consent page and exits; with a valid one it just syncs.
|
||||||
|
if subprocess.run(["calcurse-caldav"], capture_output=True).returncode == 0:
|
||||||
|
notify("Google Calendar login", "Already logged in.")
|
||||||
|
return 0
|
||||||
|
deadline = time.monotonic() + WAIT_SECONDS
|
||||||
|
while not RedirectHandler.result and (left := deadline - time.monotonic()) > 0:
|
||||||
|
server.timeout = left
|
||||||
|
server.handle_request()
|
||||||
|
server.server_close()
|
||||||
|
code = RedirectHandler.result.get("code")
|
||||||
|
if not code:
|
||||||
|
reason = RedirectHandler.result.get("error", "no answer from the browser")
|
||||||
|
notify("Google Calendar login failed", reason, "-u", "critical")
|
||||||
|
return 1
|
||||||
|
# The user manager's PATH lacks ~/.local/bin: call calcurse-sync from this script's folder.
|
||||||
|
calcurse_sync = Path(__file__).resolve().with_name("calcurse-sync")
|
||||||
|
sync = subprocess.run([calcurse_sync, "--authcode", code], capture_output=True, text=True)
|
||||||
|
if sync.returncode != 0:
|
||||||
|
last_line = (sync.stdout.strip().splitlines() or [""])[-1]
|
||||||
|
notify("Google Calendar login failed", last_line, "-u", "critical")
|
||||||
|
return 1
|
||||||
|
notify("Google Calendar login renewed", "Synced again.")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> int:
|
||||||
|
parser = argparse.ArgumentParser(description=__doc__.splitlines()[0])
|
||||||
|
parser.add_argument("--prompt", action="store_true", help="ask with a notification before logging in")
|
||||||
|
if parser.parse_args().prompt:
|
||||||
|
body = "Click to log in again, then click Allow in the browser."
|
||||||
|
if notify("Google Calendar login expired", body, "-u", "critical", "-A", "default=Log in") != "default":
|
||||||
|
return 0
|
||||||
|
return login()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
sys.exit(main())
|
||||||
Executable
+57
@@ -0,0 +1,57 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Sync calcurse with Google Calendar via calcurse-caldav; start the login prompt when the weekly OAuth login expires.
|
||||||
|
# --now: called from the UI's pre-load hook (skip the UI check, shorter timeout, no daemon restart).
|
||||||
|
# --authcode CODE: finish a login (from calcurse-relogin, which checks for the UI itself).
|
||||||
|
set -uo pipefail
|
||||||
|
|
||||||
|
data=${XDG_DATA_HOME:-$HOME/.local/share}/calcurse
|
||||||
|
state=${XDG_STATE_HOME:-$HOME/.local/state}/calcurse-sync
|
||||||
|
expired_flag=$state/login-expired
|
||||||
|
now=false
|
||||||
|
authcode=()
|
||||||
|
case ${1:-} in
|
||||||
|
--now) now=true ;;
|
||||||
|
--authcode) authcode=(--authcode "$2") ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# The UI keeps the data in memory, so syncing under it would lose changes; its post-save hook syncs after it exits.
|
||||||
|
ui_running() {
|
||||||
|
# shellcheck disable=SC2009 # pgrep can't match "has any terminal"
|
||||||
|
ps -C calcurse -o tty= | grep -qv '?'
|
||||||
|
}
|
||||||
|
|
||||||
|
if ! $now && ((${#authcode[@]} == 0)) && ui_running; then
|
||||||
|
echo "calcurse UI is running, skipping"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p "$state"
|
||||||
|
# BROWSER=true: an expired login must not open browser tabs on its own.
|
||||||
|
out=$(BROWSER=true timeout "$($now && echo 15 || echo 60)" calcurse-caldav "${authcode[@]}" 2>&1)
|
||||||
|
rc=$?
|
||||||
|
printf '%s\n' "$out"
|
||||||
|
|
||||||
|
if ((rc != 0)); then
|
||||||
|
if grep -q 'Access token is missing or refresh token is expired' <<<"$out"; then
|
||||||
|
# Prompt via calcurse-relogin, again daily if the prompt was dismissed.
|
||||||
|
if [[ ! -e $expired_flag || -n $(find "$expired_flag" -mmin +1440) ]]; then
|
||||||
|
systemctl --user start --no-block calcurse-relogin.service
|
||||||
|
touch "$expired_flag"
|
||||||
|
fi
|
||||||
|
elif grep -q 'Another synchronization instance' <<<"$out"; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
exit "$rc"
|
||||||
|
fi
|
||||||
|
rm -f "$expired_flag"
|
||||||
|
|
||||||
|
# A running daemon never re-reads the data files: restart it so imported appointments get alerts.
|
||||||
|
if ! $now && ! grep -q '^0 items imported, 0 items removed locally' <<<"$out"; then
|
||||||
|
pidfile=$data/.daemon.pid
|
||||||
|
if [[ -s $pidfile ]] && pid=$(<"$pidfile") && kill "$pid" 2>/dev/null; then
|
||||||
|
timeout 5 tail --pid="$pid" -f /dev/null
|
||||||
|
# Own scope, so the daemon outlives this oneshot service.
|
||||||
|
systemd-run --user --scope -q calcurse --daemon
|
||||||
|
echo "restarted calcurse daemon"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
Executable
+9
@@ -0,0 +1,9 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Notify today's whole-day calcurse events (the daemon only alerts timed appointments).
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
events=$(calcurse -Q --filter-type event,recur-event --days 1 \
|
||||||
|
--format-event '%m\n' --format-recur-event '%m\n' | tail -n +2)
|
||||||
|
|
||||||
|
[[ -n $events ]] || exit 0
|
||||||
|
notify-send -a calcurse -i x-office-calendar "Today" "$events"
|
||||||
Executable
+38
@@ -0,0 +1,38 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Usage: db-dump PROJECT DATABASE week|day
|
||||||
|
# Dump a MariaDB database to ~/.local/share/PROJECT/dumps with login ~/.config/PROJECT/dump.cnf.
|
||||||
|
# week: per-ISO-week files, keeping the two newest; day: per-weekday files (seven self-rotating copies).
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
if (($# != 3)) || [[ $3 != week && $3 != day ]]; then
|
||||||
|
echo "usage: ${0##*/} PROJECT DATABASE week|day" >&2
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
project=$1 db=$2 mode=$3
|
||||||
|
|
||||||
|
cnf=${XDG_CONFIG_HOME:-$HOME/.config}/$project/dump.cnf
|
||||||
|
dir=${XDG_DATA_HOME:-$HOME/.local/share}/$project/dumps
|
||||||
|
if [[ $mode == week ]]; then
|
||||||
|
out=$dir/$db-$(date +%G-W%V).sql.gz
|
||||||
|
else
|
||||||
|
out=$dir/$db-$(LC_ALL=C date +%a).sql.gz
|
||||||
|
fi
|
||||||
|
keep=2
|
||||||
|
|
||||||
|
umask 077
|
||||||
|
mkdir -p "$dir"
|
||||||
|
|
||||||
|
# Write to a temporary file so a failed dump never replaces a good one
|
||||||
|
tmp=$(mktemp "$dir/.dump.XXXXXX")
|
||||||
|
trap 'rm -f "$tmp"' EXIT
|
||||||
|
|
||||||
|
mariadb-dump --defaults-extra-file="$cnf" --single-transaction --databases "$db" | gzip > "$tmp"
|
||||||
|
mv "$tmp" "$out"
|
||||||
|
|
||||||
|
# Weekly names sort by week, so all but the last $keep are the old ones
|
||||||
|
if [[ $mode == week ]]; then
|
||||||
|
dumps=("$dir/$db"-[0-9][0-9][0-9][0-9]-W[0-9][0-9].sql.gz)
|
||||||
|
if ((${#dumps[@]} > keep)); then
|
||||||
|
rm -f -- "${dumps[@]:0:${#dumps[@]}-keep}"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
# Dump the Garmin database to a per-ISO-week file, keeping the two newest weeks.
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
cnf=${XDG_CONFIG_HOME:-$HOME/.config}/negsplit/dump.cnf
|
|
||||||
dir=${XDG_DATA_HOME:-$HOME/.local/share}/negsplit/dumps
|
|
||||||
out=$dir/Garmin-$(date +%G-W%V).sql.gz
|
|
||||||
keep=2
|
|
||||||
|
|
||||||
umask 077
|
|
||||||
mkdir -p "$dir"
|
|
||||||
|
|
||||||
# Write to a temporary file so a failed dump never replaces a good one
|
|
||||||
tmp=$(mktemp "$dir/.dump.XXXXXX")
|
|
||||||
trap 'rm -f "$tmp"' EXIT
|
|
||||||
|
|
||||||
mariadb-dump --defaults-extra-file="$cnf" --single-transaction --databases Garmin | gzip > "$tmp"
|
|
||||||
mv "$tmp" "$out"
|
|
||||||
|
|
||||||
# Names sort by week, so all but the last $keep are the old ones
|
|
||||||
dumps=("$dir"/Garmin-*.sql.gz)
|
|
||||||
if (( ${#dumps[@]} > keep )); then
|
|
||||||
rm -f -- "${dumps[@]:0:${#dumps[@]}-keep}"
|
|
||||||
fi
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
# Dump the Library database to a per-weekday file (seven self-rotating copies).
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
cnf=${XDG_CONFIG_HOME:-$HOME/.config}/library_manager/dump.cnf
|
|
||||||
dir=${XDG_DATA_HOME:-$HOME/.local/share}/library_manager/dumps
|
|
||||||
out=$dir/Library-$(LC_ALL=C date +%a).sql.gz
|
|
||||||
|
|
||||||
umask 077
|
|
||||||
mkdir -p "$dir"
|
|
||||||
|
|
||||||
# Write to a temporary file so a failed dump never replaces a good one
|
|
||||||
tmp=$(mktemp "$dir/.dump.XXXXXX")
|
|
||||||
trap 'rm -f "$tmp"' EXIT
|
|
||||||
|
|
||||||
mariadb-dump --defaults-extra-file="$cnf" --single-transaction --databases Library | gzip > "$tmp"
|
|
||||||
mv "$tmp" "$out"
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
# Dump the Weather database (ens-forecast) to a per-ISO-week file, keeping the two newest weeks.
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
cnf=${XDG_CONFIG_HOME:-$HOME/.config}/ens-forecast/dump.cnf
|
|
||||||
dir=${XDG_DATA_HOME:-$HOME/.local/share}/ens-forecast/dumps
|
|
||||||
out=$dir/Weather-$(date +%G-W%V).sql.gz
|
|
||||||
keep=2
|
|
||||||
|
|
||||||
umask 077
|
|
||||||
mkdir -p "$dir"
|
|
||||||
|
|
||||||
# Write to a temporary file so a failed dump never replaces a good one
|
|
||||||
tmp=$(mktemp "$dir/.dump.XXXXXX")
|
|
||||||
trap 'rm -f "$tmp"' EXIT
|
|
||||||
|
|
||||||
mariadb-dump --defaults-extra-file="$cnf" --single-transaction --databases Weather | gzip > "$tmp"
|
|
||||||
mv "$tmp" "$out"
|
|
||||||
|
|
||||||
# Names sort by week, so all but the last $keep are the old ones
|
|
||||||
dumps=("$dir"/Weather-*.sql.gz)
|
|
||||||
if (( ${#dumps[@]} > keep )); then
|
|
||||||
rm -f -- "${dumps[@]:0:${#dumps[@]}-keep}"
|
|
||||||
fi
|
|
||||||
Reference in new issue
Block a user