[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