[feature] add scripts
This commit is contained in:
parent
d5cec00a78
commit
ebb9d37357
45
bin/decrypt_dbeaver_passwords
Executable file
45
bin/decrypt_dbeaver_passwords
Executable file
|
@ -0,0 +1,45 @@
|
||||||
|
#!/bin/env python3
|
||||||
|
|
||||||
|
# https://stackoverflow.com/questions/39928401/recover-db-password-stored-in-my-dbeaver-connection
|
||||||
|
|
||||||
|
# requires pycrypto lib (pip install pycrypto)
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import base64
|
||||||
|
import os
|
||||||
|
import json
|
||||||
|
from Crypto.Cipher import AES
|
||||||
|
|
||||||
|
default_paths = [
|
||||||
|
'~/Library/DBeaverData/workspace6/General/.dbeaver/credentials-config.json',
|
||||||
|
'~/.local/share/DBeaverData/workspace6/General/.dbeaver/credentials-config.json',
|
||||||
|
'~/.local/share/.DBeaverData/workspace6/General/.dbeaver/credentials-config.json',
|
||||||
|
]
|
||||||
|
|
||||||
|
if len(sys.argv) < 2:
|
||||||
|
for path in default_paths:
|
||||||
|
filepath = os.path.expanduser(path)
|
||||||
|
try:
|
||||||
|
f = open(filepath, 'rb')
|
||||||
|
f.close()
|
||||||
|
break
|
||||||
|
except Exception as e:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
filepath = sys.argv[1]
|
||||||
|
|
||||||
|
print(filepath)
|
||||||
|
|
||||||
|
#PASSWORD_DECRYPTION_KEY = bytes([-70, -69, 74, -97, 119, 74, -72, 83, -55, 108, 45, 101, 61, -2, 84, 74])
|
||||||
|
PASSWORD_DECRYPTION_KEY = bytes([186, 187, 74, 159, 119, 74, 184, 83, 201, 108, 45, 101, 61, 254, 84, 74])
|
||||||
|
|
||||||
|
data = open(filepath, 'rb').read()
|
||||||
|
|
||||||
|
decryptor = AES.new(PASSWORD_DECRYPTION_KEY, AES.MODE_CBC, data[:16])
|
||||||
|
padded_output = decryptor.decrypt(data[16:])
|
||||||
|
output = padded_output.rstrip(padded_output[-1:])
|
||||||
|
|
||||||
|
try:
|
||||||
|
print(json.dumps(json.loads(output), indent=4, sort_keys=True))
|
||||||
|
except:
|
||||||
|
print(output)
|
20
bin/ffmpeghelper
Normal file
20
bin/ffmpeghelper
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
|
||||||
|
# addsound
|
||||||
|
ffmpeg -f lavfi -i aevalsrc=0 -i $infile -vcodec copy -acodec aac -map 0:0 -map 1:0 -shortest -y $outfile
|
||||||
|
|
||||||
|
# join
|
||||||
|
ffmpeg -i head2.mp4 -i input.mp4 ^
|
||||||
|
-filter_complex "[0:v:0][0:a:0][1:v:0][1:a:0]concat=n=2:v=1:a=1[outv][outa]" ^
|
||||||
|
-map "[outv]" -map "[outa]" -y output.mp4
|
||||||
|
|
||||||
|
|
||||||
|
# make
|
||||||
|
ffmpeg -f lavfi -i color=c=white:s=640x368:d=10^
|
||||||
|
-vf drawtext=fontfile=sarasa-gothic-sc-regular.ttf:fontsize=40:fontcolor=orange:x=(w-text_w)/2:y=60:text='3.18 勿忘国耻',^
|
||||||
|
drawtext=fontfile=sarasa-gothic-sc-regular.ttf:fontsize=16:fontcolor=black:x=(w-text_w)/2:y=130:text='战疫期间,宅家的日子里。',^
|
||||||
|
drawtext=fontfile=sarasa-gothic-sc-regular.ttf:fontsize=16:fontcolor=black:x=(w-text_w)/2:y=150:text='拿起两年没时间练习的吉它。弹奏一曲《爱的罗曼史》。',^
|
||||||
|
drawtext=fontfile=sarasa-gothic-sc-regular.ttf:fontsize=16:fontcolor=black:x=(w-text_w)-40:y=h-text_h-40-40:text='田东中学',^
|
||||||
|
drawtext=fontfile=sarasa-gothic-sc-regular.ttf:fontsize=16:fontcolor=black:x=(w-text_w)-40:y=h-text_h-20-40:text='初二6班',^
|
||||||
|
drawtext=fontfile=sarasa-gothic-sc-regular.ttf:fontsize=16:fontcolor=black:x=(w-text_w)-40:y=h-text_h-40:text='黄科宁',^
|
||||||
|
fps=fps=29.44 ^
|
||||||
|
-y head.mp4
|
116
bin/kc
Executable file
116
bin/kc
Executable file
|
@ -0,0 +1,116 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
try:
|
||||||
|
import yaml
|
||||||
|
import clipboard
|
||||||
|
except:
|
||||||
|
print("please install PyYAML/clipboard first", file=sys.stderr)
|
||||||
|
print("sudo pip install PyYAML clipboard", file=sys.stderr)
|
||||||
|
sys.exit(-1)
|
||||||
|
|
||||||
|
new_config_data = clipboard.paste()
|
||||||
|
if not new_config_data:
|
||||||
|
print("clipboard is empty", file=sys.stderr)
|
||||||
|
sys.exit(-1)
|
||||||
|
try:
|
||||||
|
new_config = yaml.load(new_config_data, Loader=yaml.Loader)
|
||||||
|
except:
|
||||||
|
print("illegal yaml format", file=sys.stderr)
|
||||||
|
|
||||||
|
new_clusters = new_config.get('clusters')
|
||||||
|
new_contexts = new_config.get('contexts')
|
||||||
|
new_users = new_config.get('users')
|
||||||
|
if not new_clusters or not new_contexts or not new_users:
|
||||||
|
print("configuration yaml must have clusers/contexts/users", file=sys.stderr)
|
||||||
|
sys.exit(-1)
|
||||||
|
|
||||||
|
new_context_name = input("Enter context name:")
|
||||||
|
if not new_context_name:
|
||||||
|
print("aborted!", file=sys.stderr)
|
||||||
|
sys.exit(-1)
|
||||||
|
|
||||||
|
new_cluster_name = input("Enter cluster name:")
|
||||||
|
if not new_cluster_name:
|
||||||
|
print("aborted!", file=sys.stderr)
|
||||||
|
sys.exit(-1)
|
||||||
|
|
||||||
|
new_user_name = f'{new_cluster_name}-user'
|
||||||
|
|
||||||
|
|
||||||
|
# load config file
|
||||||
|
cfg_path = os.path.expanduser('~/.kube/config')
|
||||||
|
with open(cfg_path) as f:
|
||||||
|
config = yaml.load(f, Loader=yaml.Loader) or {}
|
||||||
|
config['apiVersion'] = config.get('apiVersion', 'v1')
|
||||||
|
config['kind'] = config.get('kind', 'Config')
|
||||||
|
config['clusters'] = config.get('clusters', [])
|
||||||
|
config['contexts'] = config.get('contexts', [])
|
||||||
|
config['users'] =config.get('users', [])
|
||||||
|
|
||||||
|
# merge cluster into config
|
||||||
|
def append_or_replace(array, elem, cond):
|
||||||
|
index = -1
|
||||||
|
for i, c in enumerate(array):
|
||||||
|
if cond(c):
|
||||||
|
index = i
|
||||||
|
break
|
||||||
|
if index > -1:
|
||||||
|
old_elem = array[index]
|
||||||
|
array[index] = elem
|
||||||
|
return old_elem
|
||||||
|
else:
|
||||||
|
array.append(elem)
|
||||||
|
|
||||||
|
|
||||||
|
def update_context_ref(old, new, ref_key):
|
||||||
|
if old and old['name'] != new['name']:
|
||||||
|
for ctx in config['contexts']:
|
||||||
|
if ctx[ref_key] == old['name']:
|
||||||
|
ctx[ref_key] = new['name']
|
||||||
|
|
||||||
|
|
||||||
|
new_context = new_contexts[0]
|
||||||
|
new_cluster = new_clusters[0]
|
||||||
|
new_user = new_users[0]
|
||||||
|
|
||||||
|
new_context['name'] = new_context_name
|
||||||
|
new_context['context']['cluster'] = new_cluster_name
|
||||||
|
new_context['context']['user'] = new_user_name
|
||||||
|
new_cluster['name'] = new_cluster_name
|
||||||
|
new_user['name'] = new_user_name
|
||||||
|
|
||||||
|
old_cluster = append_or_replace(
|
||||||
|
config['clusters'],
|
||||||
|
new_cluster,
|
||||||
|
lambda c: (
|
||||||
|
c['name'] == new_cluster_name or c['cluster'] == new_cluster['cluster']
|
||||||
|
)
|
||||||
|
)
|
||||||
|
update_context_ref(old_cluster, new_cluster, 'cluster')
|
||||||
|
|
||||||
|
old_user = append_or_replace(
|
||||||
|
config['users'],
|
||||||
|
new_user,
|
||||||
|
lambda u: (
|
||||||
|
u['name'] == new_user['name'] or u['user'] == new_user['user']
|
||||||
|
|
||||||
|
)
|
||||||
|
)
|
||||||
|
update_context_ref(old_user, new_user, 'user')
|
||||||
|
|
||||||
|
append_or_replace(
|
||||||
|
config['contexts'],
|
||||||
|
new_context,
|
||||||
|
lambda c: (
|
||||||
|
c['name'] == new_context_name
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# save config file
|
||||||
|
config['current-context'] = new_context_name
|
||||||
|
with open(cfg_path, 'w') as f:
|
||||||
|
f.write(yaml.dump(config))
|
74
bin/mergesrt
Executable file
74
bin/mergesrt
Executable file
|
@ -0,0 +1,74 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
import optparse, sys, os
|
||||||
|
from collections import namedtuple
|
||||||
|
|
||||||
|
optparser = optparse.OptionParser()
|
||||||
|
optparser.add_option("-i", dest="input", help="input multiple srt files", action='append')
|
||||||
|
optparser.add_option("-o", dest="output", help="output file")
|
||||||
|
(opts, _) = optparser.parse_args()
|
||||||
|
|
||||||
|
inputfile = opts.input
|
||||||
|
|
||||||
|
sub = namedtuple("sub", "begin, end, content")
|
||||||
|
|
||||||
|
inputcontent = []
|
||||||
|
|
||||||
|
def process(line):
|
||||||
|
(begin, end) = line[1][:-2].strip().split(" --> ")
|
||||||
|
content = line[2:]
|
||||||
|
return sub(begin, end, content)
|
||||||
|
|
||||||
|
def time(rawtime):
|
||||||
|
(hour, minute, seconds) = rawtime.strip().split(":")
|
||||||
|
(second, milisecond) = seconds.strip().split(",")
|
||||||
|
return int(milisecond) + 1000 * int(second) + 1000 * 60 * int(minute) + 1000 * 60 * 60 * int(hour)
|
||||||
|
|
||||||
|
def findnext(point, inputcontent):
|
||||||
|
smallest = sys.maxint
|
||||||
|
smallestid = 0
|
||||||
|
for i in range(len(point)):
|
||||||
|
if point[i] == len(inputcontent[i]):
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
begintime = time(inputcontent[i][point[i]].begin)
|
||||||
|
if begintime < smallest:
|
||||||
|
smallest = begintime
|
||||||
|
smallestid = i
|
||||||
|
return smallestid
|
||||||
|
|
||||||
|
def merge(inputcontent):
|
||||||
|
outputcontent = []
|
||||||
|
point = [0 for i in inputcontent]
|
||||||
|
maxpoint = [0 for i in inputcontent]
|
||||||
|
for i in range(len(inputcontent)):
|
||||||
|
maxpoint[i] = len(inputcontent[i])
|
||||||
|
while point != maxpoint:
|
||||||
|
nextid = findnext(point, inputcontent)
|
||||||
|
outputcontent.append(inputcontent[nextid][point[nextid]])
|
||||||
|
point[nextid] += 1
|
||||||
|
return outputcontent
|
||||||
|
|
||||||
|
def printsub(raw, f):
|
||||||
|
outputfile = open(f, 'w')
|
||||||
|
for i in range(len(raw)):
|
||||||
|
outputfile.write("%d\r\n" % (i+1))
|
||||||
|
outputfile.write("%s --> %s \r\n" % (raw[i].begin, raw[i].end))
|
||||||
|
for c in raw[i].content:
|
||||||
|
outputfile.write("%s"%c)
|
||||||
|
outputfile.write("\r\n")
|
||||||
|
|
||||||
|
for f in inputfile:
|
||||||
|
line = []
|
||||||
|
content = []
|
||||||
|
for l in open(f):
|
||||||
|
if l == "\r\n":
|
||||||
|
content.append(process(line))
|
||||||
|
line = []
|
||||||
|
else:
|
||||||
|
line.append(l)
|
||||||
|
if line:
|
||||||
|
content.append(process(line))
|
||||||
|
inputcontent.append(content)
|
||||||
|
|
||||||
|
outputraw = merge(inputcontent)
|
||||||
|
printsub(outputraw, opts.output)
|
101
bin/mounthd.sh
Executable file
101
bin/mounthd.sh
Executable file
|
@ -0,0 +1,101 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
MOUNT_PATH=${1-'/mnt/hgst3t'}
|
||||||
|
|
||||||
|
# find all umounted devices/partions and deal with them
|
||||||
|
rm -rf /tmp/umounted_devs
|
||||||
|
IFS=' '
|
||||||
|
NUM=1
|
||||||
|
lsblk --noheadings --raw | while read -ra INFO; do
|
||||||
|
DEV="${INFO[0]}"
|
||||||
|
SIZE="${INFO[3]}"
|
||||||
|
TYPE="${INFO[5]}"
|
||||||
|
MOUNT="${INFO[6]}"
|
||||||
|
# skip mounted entry
|
||||||
|
#blkid | grep -F "/dev/$DEV" > /dev/null && continue
|
||||||
|
echo " $NUM) /dev/$DEV $SIZE $TYPE" >> /tmp/umounted_devs
|
||||||
|
NUM=$(($NUM+1))
|
||||||
|
done
|
||||||
|
|
||||||
|
|
||||||
|
if [ ! -s /tmp/umounted_devs ]; then
|
||||||
|
echo "no operatable drive/partition found"
|
||||||
|
exit -1
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo Pick a drive/partition to process
|
||||||
|
echo
|
||||||
|
cat /tmp/umounted_devs
|
||||||
|
echo
|
||||||
|
|
||||||
|
read -p "Please enter the line number: " NUM
|
||||||
|
|
||||||
|
LINE=$(sed -n "${NUM}p" /tmp/umounted_devs)
|
||||||
|
IFS=' ' read LN DEV SIZE TYPE <<< $LINE
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo You selected $TYPE $DEV with size of $SIZE
|
||||||
|
echo
|
||||||
|
|
||||||
|
|
||||||
|
init_drive() {
|
||||||
|
echo "g
|
||||||
|
n
|
||||||
|
1
|
||||||
|
|
||||||
|
|
||||||
|
y
|
||||||
|
w" | sudo fdisk $DEV
|
||||||
|
}
|
||||||
|
|
||||||
|
init_partition() {
|
||||||
|
echo formating partition $1
|
||||||
|
sudo umount $1 || true
|
||||||
|
sudo mkfs.exfat $1
|
||||||
|
}
|
||||||
|
|
||||||
|
mount_partition() {
|
||||||
|
# remove mounting record from fstab
|
||||||
|
sed "\#$MOUNT_PATH\s#d" /etc/fstab | sudo tee /etc/fstab
|
||||||
|
UUID=$(sudo blkid -s UUID -o value $1)
|
||||||
|
echo "UUID=$UUID $MOUNT_PATH exfat auto,user,rw,async 0 0" | sudo tee -a /etc/fstab
|
||||||
|
mkdir -p $MOUNT_PATH
|
||||||
|
sudo mount -a
|
||||||
|
mkdir -p $MOUNT_PATH/movies
|
||||||
|
sudo systemctl start transmission
|
||||||
|
sudo systemctl start smb
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# disk selected
|
||||||
|
if [ "$TYPE" = "disk" ]; then
|
||||||
|
NUM=$(ls -l $DEV* | wc -l)
|
||||||
|
# alert if drive already has partition
|
||||||
|
if [ $NUM -gt 1 ]; then
|
||||||
|
read -p "partitions found on $DEV, are u sure to initialize this drive? [y/N]: " CONFIRM
|
||||||
|
[ "$CONFIRM" != 'y' ] && exit -1
|
||||||
|
fi
|
||||||
|
init_drive
|
||||||
|
# format newly created partition on that dev
|
||||||
|
PART=$(ls $DEV* | tail -1)
|
||||||
|
init_partition $PART
|
||||||
|
mount_partition $PART
|
||||||
|
# partition selected
|
||||||
|
elif [ "$TYPE" = "part" ]; then
|
||||||
|
# partition is unformatted
|
||||||
|
if [ -z "$(blkid $DEV)" ] ; then
|
||||||
|
init_partition $DEV
|
||||||
|
# partition is not exfat format
|
||||||
|
elif blkid $DEV | grep -Fv exfat > /dev/null; then
|
||||||
|
read -p "all data on $DEV will be destroyed, are u sure? [y/N]: " CONFIRM
|
||||||
|
[ "$CONFIRM" != 'y' ] && exit -1
|
||||||
|
init_partition $DEV
|
||||||
|
fi
|
||||||
|
# now, we known partition is exfat format
|
||||||
|
mount_partition $DEV
|
||||||
|
fi
|
||||||
|
|
98
bin/rds
Executable file
98
bin/rds
Executable file
|
@ -0,0 +1,98 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
|
||||||
|
# Following regex is based on https://tools.ietf.org/html/rfc3986#appendix-B with
|
||||||
|
# additional sub-expressions to split authority into userinfo, host and port
|
||||||
|
#
|
||||||
|
readonly URI_REGEX='^(([^:/?#]+):)?(//((([^:/?#]+)?(:([^:/?#]+))?@)?([^:/?#]+)(:([0-9]+))?))(/([^?#]*))?(\?([^#]*))?(#(.*))?'
|
||||||
|
# ↑↑ ↑ ↑↑↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑
|
||||||
|
# |2 scheme | ||6 userinfo passwd 7 host | 9 port | 11 rpath | 13 query | 15 fragment
|
||||||
|
# 1 scheme: | |5 userinfo@ 8 :… 10 path 12 ?… 14 #…
|
||||||
|
# | 4 authority
|
||||||
|
# 3 //…
|
||||||
|
IDX_SCHEME=2
|
||||||
|
IDX_USER=6
|
||||||
|
IDX_PASSWD=8
|
||||||
|
IDX_HOST=9
|
||||||
|
IDX_PORT=11
|
||||||
|
IDX_PATH=12
|
||||||
|
IDX_RPATH=13
|
||||||
|
IDX_QUERY=15
|
||||||
|
IDX_FRAGMENT=17
|
||||||
|
|
||||||
|
# processing argument
|
||||||
|
POSITIONAL=()
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
-s|--ssh)
|
||||||
|
SSH="$2"
|
||||||
|
shift
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
--)
|
||||||
|
shift
|
||||||
|
POSITIONAL+=("$@")
|
||||||
|
break
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
POSITIONAL+=("$1")
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
set -- "${POSITIONAL[@]}"
|
||||||
|
|
||||||
|
# check arguments
|
||||||
|
if [[ $# == 0 ]]; then
|
||||||
|
echo "Usage: $0 [-s|--ssh SSH_DESTINATION] <REDIS_URI> [...REDIS_CLI_ARGS]"
|
||||||
|
echo " -s, --ssh for ssh tunnel"
|
||||||
|
echo " REDIS_URI redis://:passwd@host:port/db"
|
||||||
|
exit -1
|
||||||
|
fi
|
||||||
|
# pop the REDIS_URI and process it
|
||||||
|
if [[ ! ($1 =~ $URI_REGEX) ]]; then
|
||||||
|
echo "Invalid redis uri"
|
||||||
|
exit -1
|
||||||
|
fi
|
||||||
|
shift
|
||||||
|
|
||||||
|
SCHEME=${BASH_REMATCH[$IDX_SCHEME]}
|
||||||
|
USER=${BASH_REMATCH[$IDX_USER]}
|
||||||
|
PASSWD=${BASH_REMATCH[$IDX_PASSWD]}
|
||||||
|
HOST=${BASH_REMATCH[$IDX_HOST]}
|
||||||
|
PORT=${BASH_REMATCH[$IDX_PORT]}
|
||||||
|
UPATH=${BASH_REMATCH[$IDX_PATH]}
|
||||||
|
RPATH=${BASH_REMATCH[$IDX_RPATH]}
|
||||||
|
QUERY=${BASH_REMATCH[$IDX_QUERY]}
|
||||||
|
FRAGMENT=${BASH_REMATCH[$IDX_FRAGMENT]}
|
||||||
|
|
||||||
|
# create ssh tunnel if `--ssh` is assigned
|
||||||
|
is-port-used() {
|
||||||
|
lsof -i -P -n | awk '{print $9}' | grep -F ":$1" >/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
if [[ -n $SSH ]]; then
|
||||||
|
# find available
|
||||||
|
read lower_port upper_port < /proc/sys/net/ipv4/ip_local_port_range
|
||||||
|
while :; do
|
||||||
|
for (( port = lower_port ; port <= upper_port ; port++ )); do
|
||||||
|
! is-port-used $port && break 2
|
||||||
|
done
|
||||||
|
done
|
||||||
|
|
||||||
|
# forward local port to remote destination
|
||||||
|
ssh -N -L localhost:$port:$HOST:$PORT $SSH &
|
||||||
|
SSH_PID=$!
|
||||||
|
# wait until port is ready
|
||||||
|
while ! is-port-used $port; do
|
||||||
|
sleep 0.1
|
||||||
|
done
|
||||||
|
|
||||||
|
HOST=localhost
|
||||||
|
PORT=$port
|
||||||
|
fi
|
||||||
|
|
||||||
|
redis-cli -h "$HOST" -p "${PORT-6379}" -a "$PASSWD" -n "${RPATH-0}" "$@"
|
||||||
|
|
||||||
|
# clean up ssh connection
|
||||||
|
[[ -n $SSH_PID ]] && kill -9 $SSH_PID
|
38
bin/umounthd.sh
Executable file
38
bin/umounthd.sh
Executable file
|
@ -0,0 +1,38 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# need exfat-utils on archlinux
|
||||||
|
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# ensure target path is mounted
|
||||||
|
DRIVE_PATH=${1-'/mnt/hgst3t'}
|
||||||
|
if ! mountpoint -q -- "$DRIVE_PATH"; then
|
||||||
|
echo "$DRIVE_PATH is not mounted"
|
||||||
|
exit -1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# get device
|
||||||
|
DEV=$(grep -F "$DRIVE_PATH" /proc/mounts | awk '{print $1}')
|
||||||
|
|
||||||
|
|
||||||
|
# stop services that might using this target drives
|
||||||
|
sudo systemctl stop transmission
|
||||||
|
sudo systemctl stop smb
|
||||||
|
|
||||||
|
if sudo lsof $DRIVE_PATH 2>/dev/null; then
|
||||||
|
$DRIVE_PATH is being used
|
||||||
|
exit -1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# create archive index file
|
||||||
|
read -p "Please enter archive number: " NUM
|
||||||
|
[ "$NUM" -ne "$NUM" ] && echo $NUM is not a number && exit -1
|
||||||
|
tree -L 2 $DRIVE_PATH/movies > ~/hgst3t-$NUM.txt
|
||||||
|
|
||||||
|
# remove mounting record from fstab
|
||||||
|
sed "\#$DRIVE_PATH\s#d" /etc/fstab | sudo tee /etc/fstab
|
||||||
|
|
||||||
|
sudo umount $DRIVE_PATH
|
||||||
|
echo you can safely remove $DRIVE_PATH now
|
||||||
|
|
25
win/get-fontname.ps1
Normal file
25
win/get-fontname.ps1
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
[CmdletBinding()]
|
||||||
|
param (
|
||||||
|
[Parameter()]
|
||||||
|
[string]
|
||||||
|
$FontPath
|
||||||
|
)
|
||||||
|
|
||||||
|
Add-Type -AssemblyName PresentationCore
|
||||||
|
|
||||||
|
$face = New-Object System.Windows.Media.GlyphTypeface -ArgumentList "$(Resolve-Path $FontPath)"
|
||||||
|
$style = "$($face.Style)"
|
||||||
|
$weight = "$($face.Weight)"
|
||||||
|
$stretch = "$($face.Stretch)"
|
||||||
|
|
||||||
|
$name = $face.FamilyNames["en-US"] -replace '\W',''
|
||||||
|
if ($style -ne "Normal") {
|
||||||
|
$name += "-$($style)"
|
||||||
|
}
|
||||||
|
if ($weight -ne "Normal") {
|
||||||
|
$name += "-$($weight)"
|
||||||
|
}
|
||||||
|
if ($stretch -ne "Normal") {
|
||||||
|
$name += "-$(stretch)"
|
||||||
|
}
|
||||||
|
$name
|
202
win/pixabay.ps1
Normal file
202
win/pixabay.ps1
Normal file
|
@ -0,0 +1,202 @@
|
||||||
|
[CmdletBinding()]
|
||||||
|
param (
|
||||||
|
[Parameter(Mandatory=$false)]
|
||||||
|
[string]
|
||||||
|
$ApiKey='18224187-6d4fdb0c31aebbab0f814ab5d',
|
||||||
|
|
||||||
|
[Parameter(Mandatory=$false)]
|
||||||
|
[string]
|
||||||
|
$Keyword,
|
||||||
|
|
||||||
|
[Parameter(Mandatory=$false)]
|
||||||
|
[string]
|
||||||
|
$Id,
|
||||||
|
|
||||||
|
[Parameter(Mandatory=$false)]
|
||||||
|
[ValidateSet('all', 'photo', 'illustration', 'vector')]
|
||||||
|
[string]
|
||||||
|
$Type,
|
||||||
|
|
||||||
|
[Parameter(Mandatory=$false)]
|
||||||
|
[ValidateSet('all', 'horizontal', 'vertical')]
|
||||||
|
[string]
|
||||||
|
$Orientation,
|
||||||
|
|
||||||
|
[Parameter(Mandatory=$false)]
|
||||||
|
[ValidateSet(
|
||||||
|
'backgrounds',
|
||||||
|
'fashion',
|
||||||
|
'nature',
|
||||||
|
'science',
|
||||||
|
'education',
|
||||||
|
'feelings',
|
||||||
|
'health',
|
||||||
|
'people',
|
||||||
|
'religion',
|
||||||
|
'places',
|
||||||
|
'animals',
|
||||||
|
'industry',
|
||||||
|
'computer',
|
||||||
|
'food',
|
||||||
|
'sports',
|
||||||
|
'transportation',
|
||||||
|
'travel',
|
||||||
|
'buildings',
|
||||||
|
'business',
|
||||||
|
'music'
|
||||||
|
)]
|
||||||
|
[string]
|
||||||
|
$Category,
|
||||||
|
|
||||||
|
[Parameter(Mandatory=$false)]
|
||||||
|
[int]
|
||||||
|
$MinWidth=0,
|
||||||
|
|
||||||
|
|
||||||
|
[Parameter(Mandatory=$false)]
|
||||||
|
[int]
|
||||||
|
$MinHeight=0,
|
||||||
|
|
||||||
|
[Parameter(Mandatory=$false)]
|
||||||
|
[ValidateSet(
|
||||||
|
"grayscale",
|
||||||
|
"transparent",
|
||||||
|
"red",
|
||||||
|
"orange",
|
||||||
|
"yellow",
|
||||||
|
"green",
|
||||||
|
"turquoise",
|
||||||
|
"blue",
|
||||||
|
"lilac",
|
||||||
|
"pink",
|
||||||
|
"white",
|
||||||
|
"gray",
|
||||||
|
"black",
|
||||||
|
"brown"
|
||||||
|
)]
|
||||||
|
[string[]]
|
||||||
|
$Colors,
|
||||||
|
|
||||||
|
[Parameter(Mandatory=$false)]
|
||||||
|
[bool]
|
||||||
|
$EditorsChoiceOnly=$false,
|
||||||
|
|
||||||
|
[Parameter(Mandatory=$false)]
|
||||||
|
[bool]
|
||||||
|
$SafeForWorkOnly=$false,
|
||||||
|
|
||||||
|
[Parameter(Mandatory=$false)]
|
||||||
|
[ValidateSet("popular", "latest")]
|
||||||
|
[string]
|
||||||
|
$Order='popular',
|
||||||
|
|
||||||
|
[Parameter(Mandatory=$false)]
|
||||||
|
[int]
|
||||||
|
$Page=1,
|
||||||
|
|
||||||
|
[Parameter(Mandatory=$false)]
|
||||||
|
[ValidateRange(3, 200)]
|
||||||
|
[int]
|
||||||
|
$Size=50,
|
||||||
|
|
||||||
|
[Parameter(Mandatory=$false)]
|
||||||
|
[string]
|
||||||
|
$OutFile,
|
||||||
|
|
||||||
|
[Parameter(Mandatory=$false)]
|
||||||
|
[string]
|
||||||
|
$OutDir,
|
||||||
|
|
||||||
|
[Parameter(Mandatory=$false)]
|
||||||
|
[bool]
|
||||||
|
$OutDirWithType=$true
|
||||||
|
)
|
||||||
|
|
||||||
|
if ($OutDir -and -not $OutFile) {
|
||||||
|
$OutFile
|
||||||
|
}
|
||||||
|
|
||||||
|
function Save-Hit {
|
||||||
|
param (
|
||||||
|
[Parameter()]
|
||||||
|
[PSCustomObject]
|
||||||
|
$hit
|
||||||
|
)
|
||||||
|
|
||||||
|
$FilePath = $OutFile
|
||||||
|
if (-not $FilePath) {
|
||||||
|
$FilePath = $OutDir
|
||||||
|
if ($OutDirWithType) {
|
||||||
|
$FilePath = Join-Path $FilePath ($hit.type -replace '\W+','_' )
|
||||||
|
}
|
||||||
|
if (-not (Test-Path $FilePath)) {
|
||||||
|
New-Item -ItemType Directory $FilePath | Out-Null
|
||||||
|
}
|
||||||
|
$FileName = ($hit.id.ToString() + '_' +
|
||||||
|
($hit.tags -split ", " | %{ $_ -replace '\s+','-' } | Join-String -Separator '_') +
|
||||||
|
'.' + $hit.largeImageURL.Split('.')[-1])
|
||||||
|
$FilePath = Join-Path $FilePath $FileName
|
||||||
|
}
|
||||||
|
$msg = "saving $($hit.id) to $FilePath"
|
||||||
|
Write-Host $msg.PadRight(100) -NoNewline
|
||||||
|
if (Test-Path $FilePath) {
|
||||||
|
Write-Host "[SKIP]"
|
||||||
|
} else {
|
||||||
|
$job = Start-Job -ScriptBlock {
|
||||||
|
try {
|
||||||
|
Invoke-WebRequest -TimeoutSec 5 -Uri $args[0] -OutFile $args[1]
|
||||||
|
$true
|
||||||
|
} catch {
|
||||||
|
$false
|
||||||
|
}
|
||||||
|
} -ArgumentList $hit.largeImageURL,$FilePath
|
||||||
|
$fg = 'red'
|
||||||
|
$tx = '[TIMEOUTED]'
|
||||||
|
if (Wait-Job $job -Timeout 20) {
|
||||||
|
$ok = Receive-Job $job
|
||||||
|
$fg = $ok ? 'green' : 'red'
|
||||||
|
$tx = $ok ? '[OK]' : '[Failed]'
|
||||||
|
}
|
||||||
|
Remove-Job -force $job
|
||||||
|
Write-Host -ForegroundColor $fg $tx
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[System.Net.ServicePointManager]::MaxServicePointIdleTime = 5
|
||||||
|
$Res = Invoke-WebRequest -TimeoutSec 5 -Uri https://pixabay.com/api/ -Body @{
|
||||||
|
key = $ApiKey;
|
||||||
|
q = $Keyword;
|
||||||
|
id = $Id;
|
||||||
|
image_type = $Type;
|
||||||
|
orientation = $Orientation;
|
||||||
|
category = $Category;
|
||||||
|
min_width = $MinWidth;
|
||||||
|
min_height = $MinHeight;
|
||||||
|
colors = $Colors;
|
||||||
|
editors_choice = $EditorsChoiceOnly;
|
||||||
|
safesearch = $SafeForWorkOnly;
|
||||||
|
order = $Order;
|
||||||
|
page = $Page;
|
||||||
|
per_page = $Size;
|
||||||
|
} | ConvertFrom-Json
|
||||||
|
|
||||||
|
Write-Host "Total $($res.total) Accessible $($res.totalHits)"
|
||||||
|
|
||||||
|
$Listing = -not $OutFile -and -not $OutDir
|
||||||
|
|
||||||
|
if ($Res.hits.Length -eq 1) {
|
||||||
|
if ($Listing) {
|
||||||
|
$Res.hits[0]
|
||||||
|
} else {
|
||||||
|
Save-Hit $Res.hits[0]
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if ($Listing) {
|
||||||
|
$Res.hits | Select-Object -Property id,type,largeImageURL | Format-Table
|
||||||
|
} else {
|
||||||
|
$Res.hits | %{ Save-Hit $_ }
|
||||||
|
# Save-Hit $Res.hits[0]
|
||||||
|
}
|
||||||
|
}
|
56
win/sentry.ps1
Normal file
56
win/sentry.ps1
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
[CmdletBinding()]
|
||||||
|
param (
|
||||||
|
[ValidateSet("Projects", "MarkRead")]
|
||||||
|
[string]
|
||||||
|
$CMD,
|
||||||
|
[Parameter(Mandatory=$false)]
|
||||||
|
[string]
|
||||||
|
$PRO,
|
||||||
|
[Parameter(Mandatory=$false)]
|
||||||
|
[string]
|
||||||
|
$ORG="malong",
|
||||||
|
[Parameter(Mandatory=$false)]
|
||||||
|
[string]
|
||||||
|
$TOKEN="4ef37b6c118e44a499450fb996f2d58ef81faa46e2f14f38aadfa6d4ee0c4062"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
function Projects {
|
||||||
|
$PROJECTS_URL="https://sentry.malongtech.cn/api/0/projects/"
|
||||||
|
while ($PROJECTS_URL) {
|
||||||
|
$projectsRes = Invoke-WebRequest -Uri $PROJECTS_URL -Headers @{'Authorization'="Bearer $TOKEN"}
|
||||||
|
$projects = $projectsRes.Content | ConvertFrom-Json
|
||||||
|
if (-not $projects.Length) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
foreach ($project in $projects) {
|
||||||
|
Write-Host $project.id $project.name
|
||||||
|
}
|
||||||
|
$PROJECTS_URL=$projectsRes.Headers.Link
|
||||||
|
if (-not $PROJECTS_URL.Length) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
$PROJECTS_URL = $PROJECTS_URL[0].ToString()
|
||||||
|
$PROJECTS_URL=$PROJECTS_URL.SubString(1, $PROJECTS_URL.IndexOf(";")-2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function MarkRead {
|
||||||
|
$ISSUES_URL="https://sentry.malongtech.cn/api/0/projects/$ORG/$PRO/issues/"
|
||||||
|
while ($true) {
|
||||||
|
$issuesRes = Invoke-WebRequest -Uri $ISSUES_URL -Headers @{'Authorization'="Bearer $TOKEN"}
|
||||||
|
$issues = $issuesRes.Content | ConvertFrom-Json
|
||||||
|
if (-not $issues.Length) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
$qs = $issues | Select-Object -Property id | %{"id=$($_.id)"} | Join-String -Separator "&"
|
||||||
|
$deleteRes = Invoke-WebRequest -Uri "$($ISSUES_URL)?$qs" -Method Delete -Body @{'id'=$ids} -Headers @{'Authorization'="Bearer $TOKEN"}
|
||||||
|
Write-Host "status: $($deleteRes.StatusCode) content: $($deleteRes.Content)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ($CMD) {
|
||||||
|
"MarkRead" { MarkRead }
|
||||||
|
Default { Projects }
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user