various updates
This commit is contained in:
@ -29,6 +29,7 @@ newwidth=$(( 2 * screenwidth / 5 ))
|
||||
borderwidth=2
|
||||
|
||||
# see https://specifications.freedesktop.org/wm-spec/wm-spec-1.3.html for gravity specs
|
||||
# I do not believe that gravity is being respected in dwm.
|
||||
case "$1" in
|
||||
left) horizontal=$(( borderwidth ))
|
||||
vertical=$(( screenheight - newheight - 2 * borderwidth ))
|
||||
|
@ -1,90 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
# matrix_decrypt - Download and decrypt an encrypted attachment
|
||||
# from a matrix server
|
||||
|
||||
# Copyright © 2019 Damir Jelić <poljar@termina.org.uk>
|
||||
#
|
||||
# Permission to use, copy, modify, and/or distribute this software for
|
||||
# any purpose with or without fee is hereby granted, provided that the
|
||||
# above copyright notice and this permission notice appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||
# SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
|
||||
# RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
|
||||
# CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
import argparse
|
||||
import requests
|
||||
import tempfile
|
||||
import subprocess
|
||||
|
||||
from urllib.parse import urlparse, parse_qs
|
||||
from nio.crypto import decrypt_attachment
|
||||
|
||||
|
||||
def save_file(data):
|
||||
"""Save data to a temporary file and return its name."""
|
||||
tmp_dir = tempfile.gettempdir()
|
||||
|
||||
with tempfile.NamedTemporaryFile(
|
||||
prefix='plumber-',
|
||||
dir=tmp_dir,
|
||||
delete=False
|
||||
) as f:
|
||||
f.write(data)
|
||||
f.flush()
|
||||
return f.name
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description='Download and decrypt matrix attachments'
|
||||
)
|
||||
parser.add_argument('url', help='the url of the attachment')
|
||||
parser.add_argument('file', nargs='?', help='save attachment to <file>')
|
||||
parser.add_argument('--plumber',
|
||||
help='program that gets called with the '
|
||||
'dowloaded file')
|
||||
|
||||
args = parser.parse_args()
|
||||
url = urlparse(args.url)
|
||||
query = parse_qs(url.query)
|
||||
|
||||
if not query["key"] or not query["iv"] or not query["hash"]:
|
||||
print("Missing decryption argument")
|
||||
return -1
|
||||
|
||||
key = query["key"][0]
|
||||
iv = query["iv"][0]
|
||||
hash = query["hash"][0]
|
||||
|
||||
http_url = "https://{}{}".format(url.netloc, url.path)
|
||||
|
||||
request = requests.get(http_url)
|
||||
|
||||
if not request.ok:
|
||||
print("Error downloading file")
|
||||
return -2
|
||||
|
||||
plumber = args.plumber
|
||||
plaintext = decrypt_attachment(request.content, key, hash, iv)
|
||||
|
||||
if args.file is None:
|
||||
file_name = save_file(plaintext)
|
||||
if plumber is None:
|
||||
plumber = "xdg-open"
|
||||
else:
|
||||
file_name = args.file
|
||||
open(file_name, "wb").write(plaintext)
|
||||
|
||||
if plumber is not None:
|
||||
subprocess.run([plumber, file_name])
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
@ -1,318 +0,0 @@
|
||||
#!/usr/bin/env -S python3 -u
|
||||
# Copyright © 2018 Damir Jelić <poljar@termina.org.uk>
|
||||
#
|
||||
# Permission to use, copy, modify, and/or distribute this software for
|
||||
# any purpose with or without fee is hereby granted, provided that the
|
||||
# above copyright notice and this permission notice appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||
# SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
|
||||
# RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
|
||||
# CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
|
||||
import os
|
||||
import json
|
||||
import magic
|
||||
import requests
|
||||
import argparse
|
||||
from urllib.parse import urlparse
|
||||
from itertools import zip_longest
|
||||
import urllib3
|
||||
|
||||
from nio import Api, UploadResponse, UploadError
|
||||
from nio.crypto import encrypt_attachment
|
||||
|
||||
from json.decoder import JSONDecodeError
|
||||
|
||||
urllib3.disable_warnings()
|
||||
|
||||
|
||||
def to_stdout(message):
|
||||
print(json.dumps(message), flush=True)
|
||||
|
||||
|
||||
def error(e):
|
||||
message = {
|
||||
"type": "status",
|
||||
"status": "error",
|
||||
"message": str(e)
|
||||
}
|
||||
to_stdout(message)
|
||||
os.sys.exit()
|
||||
|
||||
|
||||
def mime_from_file(file):
|
||||
try:
|
||||
t = magic.from_file(file, mime=True)
|
||||
except AttributeError:
|
||||
try:
|
||||
m = magic.open(magic.MIME)
|
||||
m.load()
|
||||
t, _ = m.file(file).split(';')
|
||||
except AttributeError:
|
||||
error('Your \'magic\' module is unsupported. '
|
||||
'Install either https://github.com/ahupp/python-magic '
|
||||
'or https://github.com/file/file/tree/master/python '
|
||||
'(official \'file\' python bindings, available as the '
|
||||
'python-magic package on many distros)')
|
||||
|
||||
raise SystemExit
|
||||
|
||||
return t
|
||||
|
||||
|
||||
class Upload(object):
|
||||
def __init__(self, file, chunksize=1 << 13):
|
||||
self.file = file
|
||||
self.filename = os.path.basename(file)
|
||||
self.chunksize = chunksize
|
||||
self.totalsize = os.path.getsize(file)
|
||||
self.mimetype = mime_from_file(file)
|
||||
self.readsofar = 0
|
||||
|
||||
def send_progress(self):
|
||||
message = {
|
||||
"type": "progress",
|
||||
"data": self.readsofar
|
||||
}
|
||||
to_stdout(message)
|
||||
|
||||
def __iter__(self):
|
||||
with open(self.file, 'rb') as file:
|
||||
while True:
|
||||
data = file.read(self.chunksize)
|
||||
|
||||
if not data:
|
||||
break
|
||||
|
||||
self.readsofar += len(data)
|
||||
self.send_progress()
|
||||
|
||||
yield data
|
||||
|
||||
def __len__(self):
|
||||
return self.totalsize
|
||||
|
||||
|
||||
def chunk_bytes(iterable, n):
|
||||
args = [iter(iterable)] * n
|
||||
return (
|
||||
bytes(
|
||||
(filter(lambda x: x is not None, chunk))
|
||||
) for chunk in zip_longest(*args)
|
||||
)
|
||||
|
||||
|
||||
class EncryptedUpload(Upload):
|
||||
def __init__(self, file, chunksize=1 << 13):
|
||||
super().__init__(file, chunksize)
|
||||
self.source_mimetype = self.mimetype
|
||||
self.mimetype = "application/octet-stream"
|
||||
|
||||
with open(self.filename, "rb") as file:
|
||||
self.ciphertext, self.file_keys = encrypt_attachment(file.read())
|
||||
|
||||
def send_progress(self):
|
||||
message = {
|
||||
"type": "progress",
|
||||
"data": self.readsofar
|
||||
}
|
||||
to_stdout(message)
|
||||
|
||||
def __iter__(self):
|
||||
for chunk in chunk_bytes(self.ciphertext, self.chunksize):
|
||||
self.readsofar += len(chunk)
|
||||
self.send_progress()
|
||||
yield chunk
|
||||
|
||||
def __len__(self):
|
||||
return len(self.ciphertext)
|
||||
|
||||
|
||||
class IterableToFileAdapter(object):
|
||||
def __init__(self, iterable):
|
||||
self.iterator = iter(iterable)
|
||||
self.length = len(iterable)
|
||||
|
||||
def read(self, size=-1):
|
||||
return next(self.iterator, b'')
|
||||
|
||||
def __len__(self):
|
||||
return self.length
|
||||
|
||||
|
||||
def upload_process(args):
|
||||
file_path = os.path.expanduser(args.file)
|
||||
thumbnail = None
|
||||
|
||||
try:
|
||||
if args.encrypt:
|
||||
upload = EncryptedUpload(file_path)
|
||||
|
||||
if upload.source_mimetype.startswith("image"):
|
||||
# TODO create a thumbnail
|
||||
thumbnail = None
|
||||
else:
|
||||
upload = Upload(file_path)
|
||||
|
||||
except (FileNotFoundError, OSError, IOError) as e:
|
||||
error(e)
|
||||
|
||||
try:
|
||||
url = urlparse(args.homeserver)
|
||||
except ValueError as e:
|
||||
error(e)
|
||||
|
||||
upload_url = ("https://{}".format(args.homeserver)
|
||||
if not url.scheme else args.homeserver)
|
||||
_, api_path, _ = Api.upload(args.access_token, upload.filename)
|
||||
upload_url += api_path
|
||||
|
||||
headers = {
|
||||
"Content-type": upload.mimetype,
|
||||
}
|
||||
|
||||
proxies = {}
|
||||
|
||||
if args.proxy_address:
|
||||
user = args.proxy_user or ""
|
||||
|
||||
if args.proxy_password:
|
||||
user += ":{}".format(args.proxy_password)
|
||||
|
||||
if user:
|
||||
user += "@"
|
||||
|
||||
proxies = {
|
||||
"https": "{}://{}{}:{}/".format(
|
||||
args.proxy_type,
|
||||
user,
|
||||
args.proxy_address,
|
||||
args.proxy_port
|
||||
)
|
||||
}
|
||||
|
||||
message = {
|
||||
"type": "status",
|
||||
"status": "started",
|
||||
"total": upload.totalsize,
|
||||
"file_name": upload.filename,
|
||||
}
|
||||
|
||||
if isinstance(upload, EncryptedUpload):
|
||||
message["mimetype"] = upload.source_mimetype
|
||||
else:
|
||||
message["mimetype"] = upload.mimetype
|
||||
|
||||
to_stdout(message)
|
||||
|
||||
session = requests.Session()
|
||||
session.trust_env = False
|
||||
|
||||
try:
|
||||
r = session.post(
|
||||
url=upload_url,
|
||||
auth=None,
|
||||
headers=headers,
|
||||
data=IterableToFileAdapter(upload),
|
||||
verify=(not args.insecure),
|
||||
proxies=proxies
|
||||
)
|
||||
except (requests.exceptions.RequestException, OSError) as e:
|
||||
error(e)
|
||||
|
||||
try:
|
||||
json_response = json.loads(r.content)
|
||||
except JSONDecodeError:
|
||||
error(r.content)
|
||||
|
||||
response = UploadResponse.from_dict(json_response)
|
||||
|
||||
if isinstance(response, UploadError):
|
||||
error(str(response))
|
||||
|
||||
message = {
|
||||
"type": "status",
|
||||
"status": "done",
|
||||
"url": response.content_uri
|
||||
}
|
||||
|
||||
if isinstance(upload, EncryptedUpload):
|
||||
message["file_keys"] = upload.file_keys
|
||||
|
||||
to_stdout(message)
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Encrypt and upload matrix attachments"
|
||||
)
|
||||
parser.add_argument("file", help="the file that will be uploaded")
|
||||
parser.add_argument(
|
||||
"homeserver",
|
||||
type=str,
|
||||
help="the address of the homeserver"
|
||||
)
|
||||
parser.add_argument(
|
||||
"access_token",
|
||||
type=str,
|
||||
help="the access token to use for the upload"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--encrypt",
|
||||
action="store_const",
|
||||
const=True,
|
||||
default=False,
|
||||
help="encrypt the file before uploading it"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--insecure",
|
||||
action="store_const",
|
||||
const=True,
|
||||
default=False,
|
||||
help="disable SSL certificate verification"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--proxy-type",
|
||||
choices=[
|
||||
"http",
|
||||
"socks4",
|
||||
"socks5"
|
||||
],
|
||||
default="http",
|
||||
help="type of the proxy that will be used to establish a connection"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--proxy-address",
|
||||
type=str,
|
||||
help="address of the proxy that will be used to establish a connection"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--proxy-port",
|
||||
type=int,
|
||||
default=8080,
|
||||
help="port of the proxy that will be used to establish a connection"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--proxy-user",
|
||||
type=str,
|
||||
help="user that will be used for authentication on the proxy"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--proxy-password",
|
||||
type=str,
|
||||
help="password that will be used for authentication on the proxy"
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
upload_process(args)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
@ -12,7 +12,7 @@ else
|
||||
fi
|
||||
|
||||
if [ "$choice" = "🔍" ]; then
|
||||
$browser "https://searx.bocken.org"
|
||||
$browser "https://searx.cedars.xyz"
|
||||
elif [ "$choice" = "📋" ]; then
|
||||
$browser "$(xclip -o -selection clipboard)"
|
||||
else
|
||||
@ -20,6 +20,6 @@ else
|
||||
$browser "$choice"
|
||||
else
|
||||
string="$(echo $choice | sed 's/\ /+/g')"
|
||||
$browser "https://searx.lukesmith.xyz/?q=$string&t=ffab&atb=v1-1"
|
||||
$browser "https://searx.cedars.xyz/?q=$string&t=ffab&atb=v1-1"
|
||||
fi
|
||||
fi
|
||||
|
@ -6,10 +6,11 @@ if echo "$1" | grep -qE 'youtube.*list'; then
|
||||
# The above mentioned script needs Youtube API access, (see the repo for more info on that)
|
||||
# I've saved my API key in my password manager, I reccomend you to do something similar.
|
||||
API_key="$(pass show 'Misc/Youtube Data API v3' | head -n1 )"
|
||||
index="$(echo "$1" | perl -pe "s|&index=([0-9]+)|\1|")"
|
||||
playlist_id="$( echo "$1" | perl -pe "s|^.*?(\?\|&)list=(.*?)|\2|; s|&index=[0-9]+||" )"
|
||||
notify-send "startmpv" "Searching for all videos in playlist..."
|
||||
curl "https://www.googleapis.com/youtube/v3/playlistItems?part=snippet&maxResults=500&playlistId=$playlist_id&key=$API_key" |
|
||||
jq '."items"[]."snippet"."resourceId"."videoId"' |
|
||||
jq '.items[].snippet.resourceId.videoId' |
|
||||
sed 's/^/https:\/\/www.youtube.com\/watch?v=/' |
|
||||
xargs mpv --ytdl-format='bestvideo[ext=mp4][width<=1920][height<=1080]+bestaudio[ext=m4a]/best[ext=mp4]/best' ||
|
||||
notify-send "startmpv" "An error has occured with playlist $playlist_id"
|
||||
|
Reference in New Issue
Block a user