freelance-project-34-market.../dotfiles/.local/bin/commands
2022-10-14 13:10:10 +03:00

687 lines
21 KiB
Python
Executable File

#!/usr/bin/env python3
import socket
import optparse
import os
import json
import traceback
import time
import sys
import io
import subprocess
import logging
msg = None
def player_metadata():
for k in range(20):
try:
time.sleep(1.0)
return subprocess.check_output(['playerctl', 'metadata']).decode('utf-8').strip()
except:
continue
def memory_stats():
with io.BytesIO(subprocess.check_output('free', shell=True)) as f:
t1 = f.read().decode('utf-8').splitlines()
mem_total = int(t1[1].strip().split()[1])
mem_used = int(t1[1].strip().split()[2])
return dict(
mem_total=mem_total,
mem_used=mem_used,
)
def eternal_oom(memory_limit=None):
import signal
import re
import time
import pprint
self_pid = os.getpid()
if memory_limit is None:
memory_limit = 3 * 1024 * 1024
assert isinstance(memory_limit, int) \
and memory_limit < memory_stats()['mem_total'] * 0.8 \
and memory_limit > 512 * 1024
def pandas_data_frame(lines, groups_regex, header_regex, extra_columns):
header = re.compile(header_regex).search(lines[0]).groups()
rows = [
re.compile(groups_regex).search(row).groups()
for row in lines[1:]
]
columns = {
column: []
for column in header
}
for row in rows:
for value, column in zip(row, header):
columns[column].append(value)
for column, transformation in extra_columns.items():
columns[column] = [
transformation(
{
k : v[index]
for k, v in columns.items()
}
)
for index in range(len(rows))
]
return columns
def pandas_merge(left, right, on):
index = {}
input_data_frames = [
('left', left),
('right', right),
]
for index_name, data_frame in input_data_frames:
current_index = {}
for row_index, value in enumerate(data_frame[on]):
if not value in current_index:
current_index[value] = []
current_index[value].append(row_index)
index[index_name] = current_index
merged_data_frame = dict(
header=[
column + '_x'
for column in left
] + [
column + '_y'
for column in right
],
columns={},
)
for column in merged_data_frame['header']:
merged_data_frame['columns'][column] = []
common_values = {
left_value
for left_value in index['left']
if left_value in index['right']
}
common_rows = sorted(
[
dict(
left_row_index=index['left'][value][0],
right_row_index=index['right'][value][0],
)
for value in common_values
],
key=lambda x: x['left_row_index'],
)
for common_row in common_rows:
row = sum([
[
values[
common_row['%s_row_index' % index_name]
]
for column, values in data_frame.items()
]
for index_name, data_frame in input_data_frames
], [])
for column, value in zip(merged_data_frame['header'], row):
merged_data_frame['columns'][column].append(value)
return merged_data_frame['columns']
def pandas_sort_values(data_frame, by, ascending):
assert len(by) == 1
assert ascending is False
t1 = [
o['row_index']
for o in sorted(
[
dict(
row_index=row_index,
value=value
)
for row_index, value in enumerate(data_frame[by[0]])
],
key=lambda x: x['value']
)[::-1]
]
return {
column : [
values[row_index]
for row_index in t1
]
for column, values in data_frame.items()
}
def pandas_filter_values(data_frame, condition):
shape = [
len(data_frame),
]
if shape[0] > 0:
shape.append(
len(list(data_frame.values())[0])
)
t1 = [
row_index
for row_index in range(shape[1])
if condition(
{
column : values[row_index]
for column, values in data_frame.items()
}
)
]
return {
column : [
values[row_index]
for row_index in t1
]
for column, values in data_frame.items()
}
def pandas_row(data_frame, row_index):
return {
column : values[row_index]
for column, values in data_frame.items()
}
while True:
with io.BytesIO(subprocess.check_output('ps -e -o pid,rss,user', shell=True)) as f:
t1 = pandas_data_frame(
f.read().decode('utf-8').splitlines(),
r'^\s*([^\s]+)\s+([^\s]+)\s+([^\s]+)\s*$',
r'^\s*([^\s]+)\s+([^\s]+)\s+([^\s]+)\s*$',
dict(
PID=lambda row: int(row['PID']),
RSS=lambda row: int(row['RSS']),
),
)
mem_used = memory_stats()['mem_used']
t5 = subprocess.check_output('ps -e -o pid,args', shell=True).decode('utf-8').splitlines()
t6 = pandas_data_frame(
t5,
r'^\s*(\d+)\s(.*)$',
r'^\s+(\w+)\s+(\w+)\s*$',
dict(
PID=lambda row: int(row['PID'])
),
)
t7 = pandas_merge(t1, t6, on='PID')
t8 = pandas_sort_values(t7, by=['RSS_x'], ascending=False)
t9 = pandas_filter_values(
t8,
lambda row: row['PID_x'] != self_pid and not 'freelancer' in row['COMMAND_y']
)
t4 = lambda : os.kill(t9['PID_x'][0], signal.SIGKILL)
t10 = lambda : mem_used > memory_limit
if t10():
pprint.pprint([
'Killing',
pandas_row(t9, 0),
mem_used,
])
t4()
time.sleep(1)
def resilient_vlc(stream=None):
if stream is None:
streams_path = os.path.join(
os.environ['CACHE_PATH'],
'resilient-vlc-streams.json'
)
if os.path.exists(streams_path):
with io.open(
streams_path,
'r'
) as f:
stream = json.load(f)
else:
raise RuntimeError(
'not found, %s' % streams_path
)
if isinstance(stream, str):
stream = [stream]
if len(stream) == 0:
raise RuntimeError('no streams')
import subprocess
import time
while True:
print('new start')
with subprocess.Popen([
'cvlc', '--verbose', '2', *stream,
], stderr=subprocess.PIPE) as p:
while p.returncode is None:
t1 = p.stderr.readline().decode('utf-8')
if len(t1) > 0:
print(t1)
if not all([
o in t1
for o in [
'prefetch stream error',
'terror',
'main interface error',
]
]) and any([
o in t1
for o in [
'pulse audio output debug: underflow'
]
]):
print('shit')
p.kill()
while True:
try:
t2 = p.wait(timeout=1)
print(t2)
break
except:
print('shit')
pass
time.sleep(1.0)
def eternal_firefox(
tabs=None,
profile=None,
group_name=None,
window_position=None,
debug=None,
):
import os
import datetime
import pprint
import subprocess
import time
if debug is None:
debug = False
if tabs is None:
raise RuntimeError('no tabs provided')
if profile is None:
raise RuntimeError('no profile provided')
if group_name is None:
raise RuntimeError('no group provided')
if window_position is None:
#window_position = '1,600,0,600,540'
raise RuntimeError('no window-position provided')
while True:
os.system(r'''date''')
with subprocess.Popen([
'firefox',
'-P', profile,
*tabs,
]) as p:
try:
if debug:
assert subprocess.check_call(['notify-send', '%s:Starting' % group_name]) == 0
#t3 = ''
for k in range(300):
t1 = subprocess.check_output(r'''
swaymsg -t get_tree | jq -r '..|try select(.pid== %d)'
''' % p.pid, shell=True).decode('utf-8')
if len(t1) > 10:
break
#time.sleep(0.1)
#t1 = subprocess.check_output(['wmctrl', '-p', '-l']).decode('utf-8')
#t4 = [o for o in t1.splitlines() if str(p.pid) in o]
#if len(t4) == 1:
# t3 = t4[0]
# break
#if t3 == '':
# raise RuntimeError
#t2 = t3.split()[0]
#assert os.system('wmctrl -i -r %s -e %s' % (t2, window_position)) == 0
#assert os.system('wmctrl -i -r %s -b add,below' % t2) == 0
def reposition():
t1 = lambda s: \
s \
.replace('{{PID}}', str(p.pid)) \
.replace('{{X}}', str(window_position[1])) \
.replace('{{Y}}', str(window_position[2])) \
.replace('{{W}}', str(window_position[3])) \
.replace('{{H}}', str(window_position[4])) \
.replace('{{WORKSPACE}}', str(window_position[0]))
assert os.system(t1(r'''
swaymsg '[pid="{{PID}}"] move window to workspace {{WORKSPACE}}'
''')) == 0
if window_position[1] != '' and window_position[2] != '':
assert os.system(t1(r'''
swaymsg '[pid="{{PID}}"] floating enable' \
swaymsg '[pid="{{PID}}"] resize set width {{W}}px height {{H}}px' && \
swaymsg '[pid="{{PID}}"] move absolute position {{X}}px {{Y}}px'
''')) == 0
else:
assert os.system(t1(r'''
swaymsg '[pid="{{PID}}"] floating disable'
''')) == 0
if False:
for tab in tabs[1:]:
time.sleep(10)
assert subprocess.check_call([
'firefox',
'-P', profile,
'--new-tab',
tab,
]) == 0
reposition()
if debug:
assert subprocess.check_call(['notify-send', '%s:Started' % group_name]) == 0
start = datetime.datetime.now()
is_to_restart = lambda : (datetime.datetime.now() - start).total_seconds() >= 900 * 4
polling_count = 0
while not is_to_restart():
if polling_count == 0:
reposition()
if not p.poll() is None:
break
time.sleep(10)
polling_count += 1
if debug:
assert subprocess.check_call(['notify-send', '%s:Closing' % group_name]) == 0
#assert os.system('wmctrl -i -c %s' % t2) == 0
assert os.system(r'''
swaymsg '[pid="%d"] kill'
''' % (p.pid,)) == 0
except KeyboardInterrupt:
assert os.system(r'''
swaymsg '[pid="%d"] kill'
''' % (p.pid,)) == 0
break
except:
import traceback
import pprint
pprint.pprint(traceback.format_exc())
finally:
try:
p.wait(20)
except subprocess.TimeoutExpired:
pprint.pprint([p.pid, '20 seconds timeout', 'kill'])
p.kill()
if debug:
assert subprocess.check_call(['notify-send', '%s:Closed' % group_name]) == 0
def resilient_ethernet(ip_addr, ethernet_device):
subprocess.check_call(
r'''
sudo sh -c '\
while true; \
do ping -c 3 -w 3 -W 1 {{IP_ADDR}} || (\
ip link set {{ETHERNET_DEVICE}} down; \
ip link set {{ETHERNET_DEVICE}} up; \
sleep 4; true;\
); \
sleep 10; clear; date; \
done'
'''.replace(
'{{IP_ADDR}}',
ip_addr
).replace(
'{{ETHERNET_DEVICE}}}',
ethernet_device
),
shell=True
)
def http_server(argv):
assert isinstance(argv, list) and all([isinstance(o, str) for o in argv])
parser = optparse.OptionParser()
parser.add_option(
'--public',
dest='public',
action='store_true',
default=False,
)
parser.add_option(
'--port',
dest='port',
type='int',
default=80,
)
parser.add_option(
'--host',
dest='host',
type='str',
default='127.0.0.1',
)
options, args = parser.parse_args(argv)
assert options.port >= 1
try:
assert not socket.inet_aton(options.host) is None
subprocess.check_call([
'ping', '-w', '1',
options.host
])
except:
raise RuntimeError('invalid ip address %s' % options.host)
index_section = 'autoindex on;'
if len(sys.argv) == 3 and sys.argv[2] == '--public':
location_section = 'location / {%s}' % index_section
else:
token = os.urandom(16).hex()
print(
'access url is http://%s:%d/%s/' % (
options.host,
options.port,
token,
)
)
location_section = (
'location / {'
'deny all;'
'}'
'location /%s/ {'
'alias /app/;'
'%s'
'}'
) % (token, index_section)
subprocess.check_call(
r'''
sudo docker run \
-p %s:%d:80 \
-u root \
-it --entrypoint=/bin/bash \
-v $PWD:/app:ro \
nginx:latest \
-c 'echo "server{listen 80; charset UTF-8; root /app; %s}" > /etc/nginx/conf.d/default.conf; nginx -g "daemon off;"'
''' % (
options.host,
options.port,
location_section,
),
shell=True)
def player_v1(folder_url, item_id):
import sys
import urllib.parse
import re
import subprocess
import os
import tqdm
t4 = folder_url
t1 = subprocess.check_output(['curl', '-s', t4]).decode('utf-8')
t2 = re.compile(r"href=\"(.*\.mp3)\"");
t3 = [o.group(1) for o in t2.finditer(t1)];
t5 = ['%s/%s' % (t4, o) for o in t3]
t6 = item_id
t9 = range(t6, len(t5))
with tqdm.tqdm(
total=len(t5),
) as progress_bar:
progress_bar.update(t6)
for k in t9:
t7 = t5[k]
t9 = urllib.parse.unquote(os.path.split(t7)[1])
progress_bar.set_description('%03d %s' % (k, t9))
with subprocess.Popen(['ffprobe', '-hide_banner', '-i', t7], stderr=subprocess.PIPE, stdout=subprocess.PIPE) as p:
p.wait()
assert p.returncode == 0
t8 = p.stderr.read().decode('utf-8')
#print(t8)
with subprocess.Popen(['ffplay', '-hide_banner', '-nodisp', '-autoexit', '-loop', '1', t7], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) as p:
p.wait()
assert p.returncode == 0
progress_bar.update(1)
def status():
return ' | '.join([
subprocess.check_output(o, shell=True).decode('utf-8').strip()
for o in [
r'''
free -h | \
grep -P Mem: | grep -Po '[\w\.\d]+' | tail -n +2 | head -n 3 | xargs echo -n;
''',
r'''
sensors | \
grep -Po '[\\\+\\\-\\\w][^\\\s]+C ' | head -n 5 | xargs echo -n
''',
r'''
ssh nartes@pizcool3070 free -h | \
grep -P Mem: | grep -Po '[\w\.\d]+' | tail -n +2 | head -n 3 | xargs echo -n;
''',
r'''
ssh nartes@pizcool3070 sensors | \
grep -Po '[\\\+\\\-\.0-9]+\s+C ' | head -n 1
''',
r'''
date +'%Y-%m-%d %l:%M:%S %p';
''',
]
]).replace('\n\r', '')
try:
if sys.argv[1] == 'media-play-pause':
subprocess.check_call(['playerctl', 'play-pause'])
msg = player_metadata()
elif sys.argv[1] == 'media-next':
subprocess.check_call(['playerctl', 'next'])
msg = player_metadata()
elif sys.argv[1] == 'media-prev':
subprocess.check_call(['playerctl', 'previous'])
msg = player_metadata()
elif sys.argv[1] == 'media-lower-volume':
subprocess.check_call([
'pactl',
'set-sink-volume',
'@DEFAULT_SINK@',
'-5%'
])
msg = subprocess.check_output([
'pactl',
'get-sink-volume',
'@DEFAULT_SINK@'
]).decode('utf-8').strip()
elif sys.argv[1] == 'media-raise-volume':
subprocess.check_call([
'pactl',
'set-sink-volume',
'@DEFAULT_SINK@',
'+5%'
])
msg = subprocess.check_output([
'pactl',
'get-sink-volume',
'@DEFAULT_SINK@'
]).decode('utf-8').strip()
elif sys.argv[1] == 'status':
sys.stdout.write(status())
sys.stdout.flush()
elif sys.argv[1] == 'http-server':
http_server(sys.argv[2:])
elif sys.argv[1] == 'wl-screenshot':
subprocess.check_call(r'''
grim -g "$(slurp)" - | wl-copy
''', shell=True)
elif sys.argv[1] == 'eternal-oom':
eternal_oom(
memory_limit=json.loads(sys.argv[2]),
)
elif sys.argv[1] == 'resilient-vlc':
resilient_vlc(sys.argv[2:])
elif sys.argv[1] == 'eternal-firefox':
eternal_firefox(
profile=sys.argv[2],
group_name=sys.argv[3],
window_position=json.loads(sys.argv[4]),
debug=json.loads(sys.argv[5]),
tabs=sys.argv[6:],
)
elif sys.argv[1] == 'resilient-ethernet':
resilient_ethernet(
ip_addr=sys.argv[2],
ethernet_device=sys.argv[3],
)
elif sys.argv[1] == 'player':
player_v1(
folder_url=sys.argv[2],
item_id=int(sys.argv[3]),
)
elif sys.argv[1] == 'desktop-services':
assert all([
env_name in os.environ
for env_name in [
'GTK_IM_MODULE',
'XMODIFIERS',
'QT_IM_MODULE',
'I3SOCK',
'SWAYSOCK',
'WAYLAND_DISPLAY',
]
])
services = []
try:
services.extend([
subprocess.Popen(['ibus-daemon']),
subprocess.Popen(r'''
swayidle -w \
timeout 300 'swaymsg "output * dpms off"' \
resume 'swaymsg "output * dpms on"'
''', shell=True),
])
for o in services:
o.wait()
finally:
for o in services:
try:
o.terminate(timeout=10)
except:
logging.error('killed %s' % str(o.__dict__))
o.kill()
else:
raise NotImplementedError
except SystemExit:
pass
except:
msg = 'not implemented\n%s' % traceback.format_exc()
logging.error(msg)
if not msg is None:
subprocess.check_call([
'notify-send',
'commands',
msg[-128:]
])