Created
October 12, 2023 09:40
-
-
Save alryaz/18a58e28c9d340e675adf494f564af24 to your computer and use it in GitHub Desktop.
Show Zoom URL QR code when meeting is initialized
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env pythonw | |
"""Clipboard Link Notifier main module.""" | |
import argparse | |
import os | |
import re | |
from tkinter import Tk, Button, SUNKEN, DISABLED | |
from typing import Any, Collection | |
import clipboard_monitor | |
import qrcode | |
from PIL import ImageTk | |
RE_ZOOM = re.compile(r"https://([a-z0-9]+\.)?zoom.us/j/[^\s]+") | |
def escape_tg(a: str) -> str: | |
for char in '_*[]()~`>#+-=|{}.!': | |
a = a.replace(char, "\\" + char) | |
return a | |
def create_qrcode(text): | |
qr = qrcode.QRCode() | |
qr.add_data(text) | |
qr.make(fit=True) | |
img = qr.make_image(fill_color="black", back_color="white") | |
return img | |
def create_window(url_text: str, telegram: tuple[str, str] | None = None, telegram_text: str = "Share via Telegram", | |
email: tuple[str, str, str | None] | None = None, email_text: str = "Send by E-mail") -> None: | |
win = Tk() | |
win.wm_attributes('-toolwindow', True) | |
win.title("URL Copied to Clipboard") | |
win.option_add("*Font", "consolas 20") | |
win.attributes('-topmost', True) | |
win.resizable(False, False) | |
screen_width = win.winfo_screenwidth() | |
screen_height = win.winfo_screenheight() | |
side_length = round(min(screen_width, screen_height) * 0.5) | |
img = create_qrcode(url_text).resize((side_length, side_length)) | |
img_tk = ImageTk.PhotoImage(img) | |
button = Button(win, image=img_tk, command=lambda: win.destroy(), | |
borderwidth=0) | |
button.grid(row=0, column=0) | |
if telegram: | |
telegram_token, telegram_chat_id = telegram | |
def on_telegram_click(): | |
print("sending message to chat_id:", telegram_chat_id) | |
message = (f"🎤 *Видеоконференция в 247А*\n" | |
f"\n" | |
f"В «Большом Классе» начинается видеоконференция Zoom\\.\n" | |
f"\n" | |
f"Ссылка для подключения: ") + escape_tg(url_text) | |
import requests | |
resp = requests.post(f'https://api.telegram.org/bot{telegram_token}/sendMessage', json={ | |
'chat_id': telegram_chat_id, | |
'text': message, | |
'parse_mode': 'markdownv2', | |
}) | |
print(resp.status_code) | |
print(resp.text) | |
telegram_btn.config(text='OK', relief=SUNKEN, state=DISABLED) | |
telegram_btn = Button(win, text=telegram_text, command=on_telegram_click, bg="#2AABEE") | |
telegram_btn.grid(row=1, column=0, sticky="nesw") | |
if email: | |
def on_email_click(): | |
print("E-mail button pressed") | |
email_btn.config(text='OK', relief=SUNKEN, state=DISABLED) | |
email_btn = Button(win, text=email_text, command=on_email_click, bg="#8C8C8C") | |
email_btn.grid(row=2, column=0, sticky="nesw") | |
win.eval('tk::PlaceWindow . center') | |
win.mainloop() | |
def run_regex_watcher(patterns: Collection[re.Pattern], *args, ignore_repeating_urls: bool = False, **kwargs) -> None: | |
previous_link = None | |
def resolve_text_input_(text: str) -> None: | |
nonlocal previous_link | |
print(f"observed clipboard change: {text}") | |
for pattern in patterns: | |
print(f"matching pattern {pattern}") | |
match = pattern.match(text) | |
if not match: | |
continue | |
if ignore_repeating_urls: | |
if previous_link == match.group(0): | |
print("same link detected") | |
break | |
previous_link = match.group(0) | |
print("detected link:", previous_link) | |
print("opening window") | |
create_window(previous_link, *args, **kwargs) | |
print("window closed") | |
break | |
else: | |
previous_link = None | |
print("no suitable pattern found") | |
clipboard_monitor.on_text(resolve_text_input_) | |
clipboard_monitor.wait() | |
def regex_validator(value: Any) -> re.Pattern: | |
if not value: | |
raise argparse.ArgumentError(None, "argument cannot be empty") | |
if isinstance(value, re.Pattern): | |
return value | |
if value == "zoom": | |
return RE_ZOOM | |
try: | |
return re.compile(value) | |
except (ValueError, TypeError) as exc: | |
raise argparse.ArgumentError(None, f"argument is not a valid regular expression: {exc}") | |
def main(): | |
# Optionally load .env file, if module is available | |
try: | |
from dotenv import load_dotenv | |
except ImportError: | |
pass | |
else: | |
load_dotenv() | |
telegram_token = os.environ.get("TELEGRAM_TOKEN") | |
telegram_chat_id = os.environ.get("TELEGRAM_CHAT_ID") | |
if telegram_token and telegram_chat_id: | |
telegram_creds = (telegram_token, telegram_chat_id) | |
else: | |
telegram_creds = None | |
regexes_specified = os.environ.get("URL_REGEX") | |
if regexes_specified: | |
url_regexes = [ | |
regex_validator(regex) | |
for regex in regexes_specified.strip().split() | |
if regex | |
] | |
else: | |
url_regexes = [RE_ZOOM] | |
parser = argparse.ArgumentParser() | |
parser.add_argument("url_regex", type=regex_validator, help="Regular Expression to match URL", nargs="*", | |
default=url_regexes) | |
parser.add_argument("--telegram", nargs=2, required=False, type=str, metavar=("<token>", "<chat_id>"), default=telegram_creds) | |
parser.add_argument("--email", nargs=3, required=False, metavar=("<server>", "<username>", "<password>")) | |
parser.add_argument("--telegram-text", required=False, default=os.environ.get('TELEGRAM_TEXT', 'Send via Telegram')) | |
parser.add_argument("--email-text", required=False, default=os.environ.get("EMAIL_TEXT", "Send via E-mail")) | |
parser.add_argument("--ignore-repeating-urls", action="store_true", help="Do not show box when same link is copied twice in a row", default=False) | |
args = parser.parse_args() | |
run_regex_watcher(args.url_regex, getattr(args, "telegram", None), args.telegram_text, getattr(args, "email", None), | |
args.email_text, ignore_repeating_urls=args.ignore_repeating_urls) | |
if __name__ == '__main__': | |
# with open('info.log', 'w') as sys.stdout: | |
# with open('error.log', 'w') as sys.stderr: | |
main() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
qrcode~=7.4.2 | |
Pillow~=10.0.1 | |
pywin32 | |
requests~=2.31.0 | |
clipboard-monitor~=1.0.5 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment