| |
| |
| |
|
|
| import json |
| import os |
| from os.path import exists |
| from typing import Optional |
| import urllib.request |
| import socket |
| import pickle |
| import subprocess |
| import asyncio |
| import psutil |
| import time |
| from datetime import datetime |
| from telegram import Message |
| from telegram.error import TelegramError, RetryAfter |
| from telegram.ext import CallbackContext |
|
|
| class ProgressTracker: |
| def __init__(self, loop: Optional[asyncio.AbstractEventLoop], context: CallbackContext, msg: Message, filename: str, update_interval: float = 2.0): |
| self.msg = msg |
| self.context = context |
| self.filename = filename |
| self.update_interval = update_interval |
| self.last_update = 0.0 |
| self.total = 0.0 |
| self.loop = asyncio.get_event_loop() if loop == None else loop |
|
|
| async def progress(self, current, total): |
| self.total = total |
|
|
| now = self.loop.time() |
| if now - self.last_update < self.update_interval: |
| return |
|
|
| self.last_update = now |
|
|
| try: |
| _, bar, perc = print_progress_bar(current, total, decimals=0, length=50) |
| text = ( |
| f"📥 Downloading...\n{self.filename}\n" |
| f"{perc}% |{bar}|\n" |
| f"{current//(1024)} KB / {total//(1024)} KB" |
| ) |
| await self.context.bot.edit_message_text(text=text, message_id=self.msg.message_id) |
| |
| except RetryAfter as e: |
| await asyncio.sleep(float(e.value)) |
| except TelegramError: |
| pass |
| |
| async def finished(self): |
|
|
| try: |
| _, bar, perc = print_progress_bar(self.total, self.total, decimals=0, length=50) |
| text = ( |
| f"📥 Downloading...\n{self.filename}\n" |
| f"{perc}% |{bar}|\n" |
| f"{self.total//(1024)} KB / {self.total//(1024)} KB" |
| ) |
| await self.context.bot.edit_message_text(text=text, message_id=self.msg.message_id) |
| |
| except RetryAfter as e: |
| await asyncio.sleep(float(e.value)) |
| except TelegramError: |
| pass |
|
|
|
|
| def save_obj(obj, name): |
| filename = os.path.dirname(os.path.realpath( |
| __file__)) + "/obj/" + name + '.pkl' |
| with open(filename, 'wb') as f: |
| pickle.dump(obj, f, pickle.HIGHEST_PROTOCOL) |
|
|
|
|
| def load_obj(name): |
| filename = os.path.dirname(os.path.realpath( |
| __file__)) + "/obj/" + name + '.pkl' |
| try: |
| with open(filename, 'rb') as f: |
| return pickle.load(f) |
| except FileNotFoundError: |
| return None |
|
|
|
|
| def load_json(filename): |
| try: |
| with open(filename, 'r') as f: |
| return json.load(f) |
| except FileNotFoundError: |
| print("load_json: file not found: " + filename) |
| return dict() |
|
|
|
|
| def toJSON(obj): |
| return json.dumps(obj) |
|
|
|
|
| def run_command(cmd, output=False, timeout=None): |
|
|
| print(f"cmd: {cmd}, output: {output}, timeout: {timeout}") |
| outputStr = "Done" |
|
|
| process = subprocess.Popen( |
| [cmd], stdout=subprocess.PIPE, stderr=subprocess.PIPE) |
| try: |
| out, _ = process.communicate(timeout=timeout) |
| except subprocess.TimeoutExpired: |
| print("timeout!!") |
| |
| parent = psutil.Process(process.pid) |
| for child in parent.children(recursive=True): |
| child.kill() |
| parent.kill() |
| out, _ = process.communicate() |
| if output: |
| outputStr = out.decode('UTF-8') |
| return outputStr |
|
|
| async def run_command_en(cmd, message, timeout=None): |
|
|
| if timeout == None: |
| timeout = 5*60 |
|
|
| print(f"Stream output cmd: {cmd}, timeout: {timeout}") |
|
|
| |
| timeout_duration = timeout |
|
|
| |
| start_time = time.time() |
|
|
| |
| process = subprocess.Popen( |
| [cmd], stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, text=True, bufsize=1) |
|
|
| |
| try: |
|
|
| while True: |
| |
| elapsed_time = time.time() - start_time |
|
|
| |
| if elapsed_time > timeout_duration: |
| print("Timeout exceeded. Terminating the inner script.") |
| break |
| |
| output = '' |
| if process.stdout: |
| process.stdout.flush() |
| output = process.stdout.readline() |
|
|
| print(f"output cmd: {output}") |
| if output == '' and process.poll() is not None: |
| break |
| if output.strip(): |
| await message.reply_text(f"{output}") |
| except KeyboardInterrupt: |
| print("Outer script interrupted by user.") |
|
|
| |
| |
| |
| |
| |
|
|
| return None |
|
|
|
|
| def get_public_ip(): |
| ip = "" |
| try: |
| |
| ip = urllib.request.urlopen( |
| "https://api.ipify.org").read().decode('utf8') |
| except: |
| ip = "err" |
|
|
| return ip |
|
|
|
|
| def get_local_ip(): |
| s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) |
| try: |
| |
| s.connect(('10.255.255.255', 1)) |
| IP = s.getsockname()[0] |
| except Exception: |
| IP = '127.0.0.1' |
| finally: |
| s.close() |
| return IP |
|
|
|
|
| def fstr(template): |
| local_ip = get_local_ip() |
|
|
| return eval(f"f\"{template}\"") |
|
|
|
|
| |
| def print_progress_bar(current, total, prefix='', suffix='', decimals=1, length=100, fill='#', notFill='.', printEnd="\r"): |
| """ |
| Call in a loop to create terminal progress bar |
| @params: |
| current - Required : current current (Int) |
| total - Required : total size (Int) |
| prefix - Optional : prefix string (Str) |
| suffix - Optional : suffix string (Str) |
| decimals - Optional : positive number of decimals in percent complete (Int) |
| length - Optional : character length of bar (Int) |
| fill - Optional : bar fill character (Str) |
| printEnd - Optional : end character (e.g. "\r", "\r\n") (Str) |
| """ |
| percent = ("{0:." + str(decimals) + "f}").format(100 * |
| (current / float(total))) |
| filledLength = int(length * current // total) |
| bar = fill * filledLength + notFill * (length - filledLength) |
| |
| progress_string = f'\r{prefix} {percent}%|{bar}| {current}/{total} {suffix}' |
| |
| |
| |
| |
| |
|
|
| return progress_string, bar, percent |
|
|
|
|
| |
| def get_unique_filepath(base_path): |
| directory = os.path.dirname(base_path) |
| filename = os.path.basename(base_path) |
| name, ext = os.path.splitext(filename) |
|
|
| counter = 0 |
| while os.path.exists(base_path): |
| counter += 1 |
| timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") |
| base_path = os.path.join(directory, f"{name}_{timestamp}{ext}") |
|
|
| return base_path |