1
0
Fork 0
This commit is contained in:
Arthur K. 2025-11-11 00:41:42 +03:00
parent 7e5d880156
commit d93f63cf82
40 changed files with 448 additions and 649 deletions

View file

@ -6,17 +6,19 @@ declare -a files
while [ "$#" -gt 0 ]; do
case "$1" in
"-s") SILENT=1;;
"-"*) SILENT=1;;
*) files+=("$1");;
esac
shift
done
if [ "$#" -gt 0 ]; then
r="$(curl -X PUT --data-binary "@$1" "$URL" 2>/dev/null)"
ext="$(basename -- "$1")"
ext=".${ext##*.}"
[ "$ext" = ".$1" ] && ext=
if [ "${#files}" -gt 0 ]; then
for file in "${files[@]}"; do
r="$(curl -X PUT --data-binary "@$file" "$URL" 2>/dev/null)"
ext="$(basename -- "$file")"
ext=".${ext##*.}"
[ "$ext" = ".$file" ] && ext=
done
else
if [ "$SILENT" = 1 ]; then
TMP_FILENAME="$(mktemp)"
@ -26,9 +28,8 @@ else
else
r="$(curl -X PUT --data-binary @- "$URL" 2>/dev/null)"
fi
[ -n "$TMP_FILENAME" ] && rm "$TMP_FILENAME"
fi
r="$(tr -d $'\n' <<< "$r")"
xclip -selection clipboard <<< "$r$ext"
echo "$r$ext"
[ -n "$TMP_FILENAME" ] && rm "$TMP_FILENAME"
r="$(tr -d $'\n' <<< "$r$ext")"
xclip -selection clipboard <<< "$r"
echo "$r"

7
.local/bin/scripts/cat-files Executable file
View file

@ -0,0 +1,7 @@
#!/bin/bash
while IFS=$'\n' read -r file; do
echo "$file:"
cat "$file"
printf "\n\n"
done < <(find "${1?}" -type f)

View file

@ -0,0 +1,4 @@
#!/bin/sh
dunstctl set-paused "$1"
pkill -37 dwmblocks

View file

@ -3,7 +3,11 @@
url="$(git remote get-url "${1:-origin}")"
if [[ "$url" =~ ^https?:\/\/ ]]; then
xdg-open "$url"
xdg-open "${url%.git}"
# elif [[ "$url" =~ ([a-zA-Z0-9_.-]+):(.*) ]]; then
# url="https://${BASH_REMATCH[1]}/${BASH_REMATCH[2]}"
# url="${url%.git}"
# xdg-open "$url"
elif [[ "$url" =~ ^[a-zA-Z0-9_-]+@([a-zA-Z0-9_.-]+):(.*) ]]; then
url="https://${BASH_REMATCH[1]}/${BASH_REMATCH[2]}"
url="${url%.git}"

View file

@ -34,6 +34,8 @@ main() {
"--template=${HOME}/.local/share/default.html"
"--variable=published_time=$(date -Iseconds -d"$(stat "$1" | grep 'Birth:' | sed 's/.*Birth:\s//')")"
)
set -e
pandoc "${pandoc_options[@]}" <(shift_header "$1") > "$FILENAME" &&
echo "$FILENAME" &&
firefox "$FILENAME" & disown

View file

@ -1,326 +0,0 @@
#!/bin/sh
# shellcheck disable=all
"exec" "${HOME}/.local/share/venv/statusbar/bin/python3" "-u" "$0" "$@"
import datetime
import json
import os
import signal
import sys
import time
import traceback
from collections.abc import Callable
from dataclasses import dataclass
from typing import Literal, Any, TypeVar
from urllib.parse import urlparse
import requests
from bs4 import BeautifulSoup, Tag
EMOJI_BY_STATUS = {
0: '🟡',
1: '🟢',
2: '🔴',
}
TIMEOUT = 30
CONFIG_FILE = f"{os.environ['HOME']}/.my.itmo"
CACHE_FILE = f"{os.environ['HOME']}/.cache/my_itmo.cache"
SECRET_FILE = f"{os.environ['HOME']}/.secrets/my_itmo.secret"
PIPE_FILE = f"{os.environ['XDG_RUNTIME_DIR']}/my.itmo.pipe"
T = TypeVar('T')
def run_forever(fn: Callable, *args, **kwargs):
while True:
try:
fn(*args, **kwargs)
except Exception:
print(traceback.format_exc())
def run_until_successful(fn: Callable[..., T], *args, **kwargs) -> T:
while True:
try:
return fn(*args, **kwargs)
except Exception:
pass
def send_message(chat_id: int, text: str, token: str):
requests.post(f"https://api.telegram.org/bot{token}/sendMessage", data={
'chat_id': chat_id,
'parse_mode': 'HTML',
'text': text
})
@dataclass
class StatusObject:
id: int
name: str
notice: str
status: Literal[0, 1, 2]
status_name: str
updated_at: datetime.datetime
created_at: datetime.datetime
@staticmethod
def from_dict(data: dict[str, Any]):
data['updated_at'] = datetime.datetime.strptime(data['updated_at'].replace("+03:00", ''), '%Y-%m-%dT%H:%M:%S')
data['created_at'] = datetime.datetime.strptime(data['created_at'].replace("+03:00", ''), '%Y-%m-%dT%H:%M:%S')
return StatusObject(**data)
class ApiException(Exception):
status_code: int
body: str
def __init__(self, status_code: int, body: str):
super().__init__(status_code, body)
self.status_code = status_code
self.body = body
def __str__(self):
return f'Status code: {self.status_code}\nBody: {self.body}'
class Api:
_session: requests.Session
_username: str
_password: str
_access_token: str
_refresh_token: str
_expires_in: int
_refresh_expires_in: int
def __init__(self, username: str, password: str, *, access_token: str | None = None,
refresh_token: str | None = None, expires_in: int | None = None,
refresh_expires_in: int | None = None, cookies: Any | None = None):
self._session = requests.Session()
self._username = username
self._password = password
self._refresh_token = refresh_token if refresh_token else ''
self._expires_in = expires_in if expires_in else 0
self._refresh_expires_in = refresh_expires_in if refresh_expires_in else 0
if cookies: self._session.cookies.update(cookies)
self._access_token = access_token if access_token else ''
if access_token: self._session.headers.update({'Authorization': f'Bearer {access_token}'})
self._ensure_authorized()
def _first_auth(self):
self._session.headers.clear()
self._session.cookies.clear()
code_request = run_until_successful(self._session.get, 'https://id.itmo.ru/auth/realms/itmo/protocol/openid-connect/auth', params={
'protocol': 'oauth2',
'response_type': 'code',
'client_id': 'student-personal-cabinet',
'redirect_uri': 'https://my.itmo.ru/login/callback',
'scope': 'openid profile',
}, timeout=2)
soup = BeautifulSoup(code_request.text, features='html.parser')
form = soup.find('form')
if not isinstance(form, Tag):
raise ApiException(code_request.status_code, code_request.text)
url = form.get_attribute_list('action')[0]
auth_request = run_until_successful(self._session.post, url, data={'username': self._username, 'password': self._password})
if auth_request.status_code != 200:
raise ApiException(auth_request.status_code, auth_request.text)
parsed_url_params = {a.split('=')[0]: a.split('=')[1] for a in urlparse(auth_request.url).query.split('&')}
self._get_and_save_tokens({
'code' : parsed_url_params['code'],
'client_id': 'student-personal-cabinet',
'redirect_uri': 'https://my.itmo.ru/login/callback',
'audience': '',
'response_type': 'code',
'grant_type': 'authorization_code',
'code_verifier': ''
})
def _renew(self):
self._session.headers.clear()
self._session.cookies.clear()
self._get_and_save_tokens({
'refresh_token': self._refresh_token,
'scopes': 'openid profile',
'client_id': 'student-personal-cabinet',
'grant_type': 'refresh_token'
})
def _get_and_save_tokens(self, data: Any):
tokens_request = run_until_successful(self._session.post, 'https://id.itmo.ru/auth/realms/itmo/protocol/openid-connect/token', data=data, timeout=2)
if tokens_request.status_code != 200:
raise ApiException(tokens_request.status_code, tokens_request.text)
tokens = tokens_request.json()
self._access_token = tokens['access_token']
self._expires_in = int(time.time()) + tokens['expires_in'] - 10
self._refresh_expires_in = int(time.time()) + tokens['refresh_expires_in'] - 10
self._refresh_token = tokens['refresh_token']
self._session.headers.update({"Authorization": f"Bearer {tokens_request.json()['access_token']}"})
def _ensure_authorized(self):
current_time = int(time.time())
if self._access_token and self._expires_in > current_time:
return
elif self._refresh_token and self._refresh_expires_in > current_time:
self._renew()
else:
self._first_auth()
def _make_request(self, method: Literal["GET", "POST"], endpoint: str):
self._ensure_authorized()
r = run_until_successful(self._session.request, method, f'https://my.itmo.ru/api/{endpoint}', timeout=2)
if r.status_code == 403:
self._first_auth() # do full reauth if 403 after self._ensure_authorized()
r = run_until_successful(self._session.request, method, f'https://my.itmo.ru/api/{endpoint}', timeout=2)
if r.status_code != 200 or r.json()['error_code'] != 0:
raise ApiException(r.status_code, r.text)
return r.json()
def get_status_list(self):
return [StatusObject.from_dict(obj) for obj in self._make_request('GET', 'requests/my')['result']]
def to_dict(self) -> Any:
return {
'username': self._username,
'password': self._password,
'access_token': self._access_token,
'refresh_token': self._refresh_token,
'expires_in': self._expires_in,
'refresh_expires_in': self._refresh_expires_in,
'cookies': self._session.cookies.get_dict()
}
@staticmethod
def from_dict(data: Any):
return Api(
data['username'],
data['password'],
access_token = data['access_token'],
refresh_token = data['refresh_token'],
expires_in = data['expires_in'],
refresh_expires_in = data['refresh_expires_in'],
cookies = data['cookies'],
)
def listen_for_messages(api: Api, timeout=TIMEOUT, filter_func: Callable[[StatusObject], bool] | None = None):
prev_msg = None
while True:
msg = list(filter(filter_func, api.get_status_list()))
if not msg or msg == prev_msg:
time.sleep(timeout)
continue
prev_msg = msg
yield msg
time.sleep(timeout)
format_status = lambda status: f"{EMOJI_BY_STATUS[status.status]} {status.notice.split('.')[0].strip()}"
format_message = lambda status: f"{EMOJI_BY_STATUS[status.status]} <b>{status.name}</b>\n\n{status.notice}"
class IDsFilter:
_ids: list[str]
_update_time: float
def __init__(self):
self._ids = []
self._update_dict()
def __call__(self, status: StatusObject) -> bool:
if self._update_time + TIMEOUT < time.time():
self._update_dict()
return str(status.id) in self._ids
def _update_dict(self):
self._update_time = time.time()
try:
with open(CONFIG_FILE) as file:
self._ids = file.read().strip().replace(' ', '').split(',')
except Exception:
self._ids = []
class LastUpdateFilter:
_update_time: datetime.datetime
def __init__(self, ignore_now = False) -> None:
self._update_time = datetime.datetime.fromtimestamp(0) if not ignore_now else datetime.datetime.now()
def __call__(self, status: StatusObject):
return status.updated_at >= self._update_time
def update(self):
self._update_time = datetime.datetime.now()
def main():
api = None
if os.path.isfile(CACHE_FILE):
with open(CACHE_FILE) as file:
api = Api.from_dict(json.load(file))
if os.path.isfile(SECRET_FILE):
with open(SECRET_FILE) as secret_file:
data = json.load(secret_file)
owner_id = data['owner_id']
bot_token = data['bot_token']
if not api:
api = Api(data['username'], data['password'])
else:
print("Missing secret file!", file=sys.stderr)
exit(1)
def die(*_):
with open(CACHE_FILE, 'w') as file:
json.dump(api.to_dict(), file)
if os.path.isfile(PIPE_FILE):
os.remove(PIPE_FILE)
exit(0)
signal.signal(signal.SIGTERM, die)
signal.signal(signal.SIGINT, die)
for message in listen_for_messages(api, filter_func=IDsFilter()):
with open(PIPE_FILE, 'w') as file:
print('\n'.join(map(format_status, message)))
file.write(' '.join(map(format_status, message)))
update_filter = LastUpdateFilter(ignore_now=True)
for message in listen_for_messages(api, filter_func=update_filter):
formatted_messages = list(map(format_message, message))
print('\n---\n'.join(formatted_messages))
for message in formatted_messages:
send_message(owner_id, message, bot_token)
update_filter.update()
if __name__ == "__main__":
run_forever(main)
# vim: ft=python

View file

@ -1,9 +1,6 @@
#!/bin/bash
flags="-it"
if [ ! -t 0 ] || [ ! -t 1 ]; then
flags=
fi
{ [ ! -t 0 ] || [ ! -t 1 ]; } && flags=
docker --context=higpu exec $flags ollama-ollama-1 ollama "$@"

View file

@ -88,7 +88,7 @@ main() {
fi
[ -n "${print_response:+_}" ] && echo "$resp"
[ "$(jq .ok <<<"$resp")" = "true" ] || jq <<< "$resp" >&2
# [ "$(jq .ok <<<"$resp")" = "true" ] || jq <<< "$resp" >&2
}
main "$@"

4
.local/bin/scripts/unplug Executable file
View file

@ -0,0 +1,4 @@
#!/bin/sh
xr internal
systemctl suspend

3
.local/bin/scripts/virt Executable file
View file

@ -0,0 +1,3 @@
#!/bin/sh
sudo systemctl start libvirtd
sudo virsh net-start default

View file

@ -1,11 +1,5 @@
#!/bin/bash -x
PIPE="/var/run/vpnd.sock"
send_cmd() {
[ -p $PIPE ] && echo "$@" > $PIPE && \
cat < $PIPE
}
send_router_cmd() {
touch "${HOME}/.local/state/.vpn_loading"
pkill -36 dwmblocks
@ -13,51 +7,40 @@ send_router_cmd() {
rm "${HOME}/.local/state/.vpn_loading"
}
awg-quick() {
PIPE="/var/run/vpnd.sock"
[ -p $PIPE ] &&
echo "$@" > $PIPE &&
cat < $PIPE
}
DEFAULT_LINK="$(resolvectl status | grep 'Default Route: yes' -B10 | grep 'Link' | tail -1 | grep -Eo '\(.*\)' | tr -d '()')"
if resolvectl domain "$DEFAULT_LINK" | grep -q 'wzray.com'; then
IS_LOCAL=1
fi
IFNAME='ext'
IFNAME="awg_ext"
while [ "$#" -gt 0 ]; do
case "$1" in
'i'|'int') IFNAME='int';;
'-v'|'--verbose') VERBOSE=1;;
*) echo "Wrong argument!"; exit 1;;
i|int|internal) IFNAME='awg_int';;
*) echo "Wrong argument!" >&2; exit 1;;
esac
shift
done
if [ -z "${VERBOSE}" ]; then
exec &>/dev/null
UP_NAME="$(ip link | grep 'awg_' | cut -d ' ' -f 2 | sed 's,:,,')"
if [ -n "$UP_NAME" ]; then
awg-quick down "$UP_NAME"
elif [ -n "$IS_LOCAL" ]; then
send_router_cmd toggle
else
set -x
awg-quick up "${IFNAME}"
fi
UP_NAME="$(send_cmd status)"
if [ -n "$IS_LOCAL" ]; then
if [ -n "$UP_NAME" ]; then
send_cmd down
else
send_router_cmd toggle
fi
else
if [ -n "${UP_NAME}" ]; then
if [ "${UP_NAME}" != "${IFNAME}" ]; then
send_cmd down
send_cmd up "$IFNAME"
else
send_cmd down
fi
else
send_cmd up "$IFNAME"
fi
fi
pkill -36 dwmblocks
# vim: ft=bash

View file

@ -1,92 +1,49 @@
#!/bin/bash
# shellcheck disable=SC2034
die() {
[ -n "$oc_pid" ] && kill -s TERM "$oc_pid"
echo "exitting..."
rm -f $PIPE
exit 0
}
trap 'die' SIGTERM SIGQUIT SIGINT
PIPE="/var/run/vpnd.sock"
oc_pid=
up_name=
[ -p $PIPE ] && exit 1
[ "$(id -u)" != "0" ] && exit 1
trap 'die' SIGTERM SIGQUIT SIGINT
declare -a CONFIGS
for config in /etc/openconnect/config_*; do
config="$(basename "$config")"
CONFIGS+=("${config#config_}")
for config in /etc/amnezia/amneziawg/*; do
config="$(basename "$config")"
CONFIGS+=("${config%.conf}")
done
COMMANDS=("up" "down" "status")
COMMANDS=("up" "down")
is_really_up() {
[ -n "$oc_pid" ] && if ! kill -0 "$oc_pid"; then
oc_pid=
up_name=
fi
die() {
rm $PIPE
exit 0
}
in_arr() {
declare -n arr="$2"
declare -n arr="$2"
for value in "${arr[@]}"; do
[ "$value" = "$1" ] && return 0
done
return 1
}
down() {
is_really_up
[ -z "$oc_pid" ] && return
kill -s TERM "$oc_pid"
wait "$oc_pid"
oc_pid=
up_name=
}
up() {
is_really_up
[ -n "$oc_pid" ] && down
openconnect --config "/etc/openconnect/config_$1" &
oc_pid="$!"
up_name="$1"
}
status() {
is_really_up
echo "$up_name" > $PIPE
for value in "${arr[@]}"; do
[ "$value" = "$1" ] && return 0
done
return 1
}
main() {
mkfifo $PIPE -m666
mkfifo $PIPE -m666
while :; do
read -r cmd ifname < $PIPE
if ! in_arr "$cmd" "COMMANDS"; then
echo "ERROR: Invalid command $cmd" > $PIPE
else
case "$cmd" in
"up")
if ! in_arr "$ifname" "CONFIGS"; then
echo "ERROR: Invalid interface $ifname" > $PIPE
else
up "$ifname"
echo "$ifname" > $PIPE
fi
;;
"down") down; echo "down" > $PIPE;;
"status") status;;
esac
while :; do
read -r cmd ifname < $PIPE
fi
done
if ! in_arr "$ifname" "CONFIGS"; then
echo "ERROR: Invalid interface $ifname" > $PIPE
elif ! in_arr "$cmd" "COMMANDS"; then
echo "ERROR: Invalid command $cmd" > $PIPE
else
awg-quick "$cmd" "$ifname" > $PIPE 2>&1
fi
done
}
echo "Running..."
main

9
.local/bin/scripts/wdate Executable file
View file

@ -0,0 +1,9 @@
#!/bin/sh
trap 'echo; exit' 'INT'
while :; do
printf '\r'
date "$@" | tr -d '\n'
sleep 0.99
done

View file

@ -1,7 +1,5 @@
#!/bin/bash
# supress stderr
change_dpi() {
sed -i -E --follow-symlinks "s/Xft\.dpi: .*?/Xft\.dpi: $1/g" ~/.Xresources
sed -i -E --follow-symlinks "s/Xcursor\.size: .*?/Xcursor\.size: $2/g" ~/.Xresources
@ -20,7 +18,7 @@ EXT_MON="$(xrandr | grep -ow "\(DP-[0-9]\) connected" | cut -d " " -f 1)"
INT_MODELINE=$(cvt 1560 1040 90 | grep "Modeline" | cut -d " " -f 2- | tr -d '"')
INT_RES="$(echo $INT_MODELINE | cut -d ' ' -f 1 | tr -d '\"')"
if [[ -z "${EXT_MON}" ]]; then
if [[ -z "${EXT_MON}" ]] || [ "$1" = "internal" ]; then
xrandr --output eDP-1 --pos 0x0 --mode "3120x2080" --rate 90 --primary --output DP-1 --off --output DP-2 --off --output DP-3 --off --output DP-4 --off
xrandr --delmode eDP-1 "${INT_RES}"
xrandr --rmmode "${INT_RES}"
@ -29,9 +27,13 @@ else
:
xrandr --rmmode "${INT_RES}"
# shellcheck disable=all
xrandr --newmode $(echo $INT_MODELINE) # this is a hack to make xrandr recognize the resolution
xrandr --addmode eDP-1 "${INT_RES}"
xrandr --output eDP-1 --pos 2560x400 --mode "${INT_RES}" --output "${EXT_MON}" --pos 0x0 --mode "2560x1440" --rate 144 --primary
# temp remove edp
# xrandr --newmode $(echo $INT_MODELINE) # this is a hack to make xrandr recognize the resolution
# xrandr --addmode eDP-1 "${INT_RES}"
# xrandr --output eDP-1 --pos 2560x400 --mode "${INT_RES}" --output "${EXT_MON}" --pos 0x0 --mode "2560x1440" --rate 144 --primary
xrandr --output eDP-1 --off --output "${EXT_MON}" --pos 0x0 --mode "2560x1440" --rate 144 --primary
change_dpi 96 24
fi