From 80a3962ab1552685af14ed8b9e5f559618ceacbe Mon Sep 17 00:00:00 2001 From: pepeleaks <104858775+Fadi002@users.noreply.github.com> Date: Sat, 30 Dec 2023 00:35:57 +0300 Subject: [PATCH] v1.0.6 --- GUI/index.html | 3 +- INFO/changelog.json | 8 +- INFO/version | 2 +- Pictures/CLI.png | Bin 0 -> 42186 bytes README.md | 13 +- TUI/cli.py | 352 ++++++++++++++++++++++++++++++++++++++++++++ config/config.py | 5 +- main.py | 69 +++++---- requirements.txt | 3 +- util/__init__.py | 1 + util/rpc.py | 37 +++++ util/tui.py | 183 +++++++++++++++++++++-- 12 files changed, 625 insertions(+), 51 deletions(-) create mode 100644 Pictures/CLI.png create mode 100644 TUI/cli.py create mode 100644 util/rpc.py diff --git a/GUI/index.html b/GUI/index.html index b94fe70..9dc3f53 100644 --- a/GUI/index.html +++ b/GUI/index.html @@ -165,8 +165,9 @@

options

About

GitHub: fadi002 +

GitHub: Advdebug

-

Discord: @0xmrpepe

+

Discord: @0xmrpepe, @advdebug

diff --git a/INFO/changelog.json b/INFO/changelog.json index eaf707d..e7d50cf 100644 --- a/INFO/changelog.json +++ b/INFO/changelog.json @@ -37,5 +37,11 @@ "Fixed some bugs", "Added openssl + sockets dumper to text file" ] - } + }, + { + "version": "1.0.6", + "changes": [ + "Added CLI mode (use --cli to run it)" + ] + } ] \ No newline at end of file diff --git a/INFO/version b/INFO/version index a1a1d8a..ef2b62e 100644 --- a/INFO/version +++ b/INFO/version @@ -1 +1 @@ -V1.0.5 \ No newline at end of file +V1.0.6 \ No newline at end of file diff --git a/Pictures/CLI.png b/Pictures/CLI.png new file mode 100644 index 0000000000000000000000000000000000000000..6f54a7469a64f113bbb3d5c7dd69fc907286597e GIT binary patch literal 42186 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 literal 0 HcmV?d00001 diff --git a/README.md b/README.md index 20920cd..1f16393 100644 --- a/README.md +++ b/README.md @@ -49,12 +49,13 @@ De4py are an Advanced python deobfuscator with a beautiful UI and a set of Advan ## Screenshots

- - - - - - + + + + + + +

## Contributions diff --git a/TUI/cli.py b/TUI/cli.py new file mode 100644 index 0000000..8eaa100 --- /dev/null +++ b/TUI/cli.py @@ -0,0 +1,352 @@ +import colorama, msvcrt, platform, signal +from tkinter import Tk, filedialog +from deobfuscators.detector import detect_obfuscator +from analyzer import ( + detect_packer, + unpack_file, + get_file_hashs, + sus_strings_lookup, + all_strings_lookup, +) +from config import config +from util import * +import socket + +def signal_handler(sig, frame): + tui.clear_console() + banner() + print(f"{colorama.Fore.CYAN}Exiting....{colorama.Style.RESET_ALL}") + rpc.KILL_THREAD = True + sys.exit(0) + + +signal.signal(signal.SIGINT, signal_handler) +sys.excepthook = custom_error +tui.clear_console() +change_log = None +platform_info = None +file_path = None + + +def home_tab(): + tui.linux_prompt() + choice = input() + commands = { + "help": "Displays a list of available commands.", + "deobfuscator": "Executes the deobfuscator tool.", + "pyshell": "Opens the Python shell.", + "analyzer": "Runs the code analyzer tool.", + "about": "Displays information about the program.", + "changelog": "Displays the change log with details of each version and the corresponding updates.", + "neofetch": "Displays your PC info + the tool info", + "clear": "Clear the console.", + "exit": "Exits the program.", + } + if choice == "help": + print(f"\n{Fore.CYAN}=== Available Commands ==={Style.RESET_ALL}") + for cmd, desc in commands.items(): + print(f"{Fore.YELLOW}{cmd}{Style.RESET_ALL} - {desc}") + print(f"{Fore.CYAN}=========================={Style.RESET_ALL}\n") + elif choice == "deobfuscator": + deobfuscator_tab() + elif choice == "pyshell": + print(f"\n{Fore.CYAN}=== coming soon ==={Style.RESET_ALL}\n") + elif choice == "analyzer": + analyzer_tab() + elif choice == "about": + print( + f"\n{Fore.CYAN}This tool created by 0xmrpepe, advdebug\nwebsite: https://de4py.000.pe\ngithub: https://github.com/Fadi002/de4py{Style.RESET_ALL}\n" + ) + elif choice == "neofetch": + neofetch() + elif choice == "changelog": + changelog_display() + elif choice == "clear": + tui.clear_console() + banner() + elif choice == "exit": + tui.clear_console() + banner() + print(f"{colorama.Fore.CYAN}Exiting....{colorama.Style.RESET_ALL}") + sys.exit(0) + else: + print(f"{Fore.RED}Unknown command{Style.RESET_ALL}") + + +def deobfuscator_tab(): + global file_path + file_path = None + tui.clear_console() + banner() + commands = { + "set_file": "Select a file to deobfuscate.", + "start": "Executes the deobfuscator.", + "back": "Back to the home page.", + "clear": "Clear the console.", + "exit": "Exits the program.", + } + while 1: + tui.linux_prompt("deobfuscator") + choice = input() + if choice == "help": + print(f"\n{Fore.CYAN}=== Available Commands ==={Style.RESET_ALL}") + for cmd, desc in commands.items(): + print(f"{Fore.YELLOW}{cmd}{Style.RESET_ALL} - {desc}") + print(f"{Fore.CYAN}=========================={Style.RESET_ALL}\n") + elif choice == "set_file": + file_path = file_explorer() + if file_path: + print(f"{Fore.CYAN}Selected file path: {file_path}{Style.RESET_ALL}\n") + + else: + print(f"{Fore.YELLOW}No file selected.{Style.RESET_ALL}\n") + elif choice == "start": + if file_path: + print( + f"{Fore.CYAN}Starting the Deobfuscation process...{Style.RESET_ALL}" + ) + print(f"{Fore.CYAN}Deobfuscation result:{Style.RESET_ALL}\n") + print(detect_obfuscator(file_path)) + print("\n") + else: + print(f"{Fore.YELLOW}No file selected.{Style.RESET_ALL}\n") + elif choice == "back": + tui.clear_console() + banner() + break + elif choice == "clear": + tui.clear_console() + banner() + elif choice == "exit": + tui.clear_console() + banner() + print(f"{colorama.Fore.CYAN}Exiting....{colorama.Style.RESET_ALL}") + sys.exit(0) + else: + print(f"{Fore.RED}Unknown command{Style.RESET_ALL}") + + +def analyzer_tab(): + global file_path + file_path = None + tui.clear_console() + banner() + commands = { + "set_file": "Select a file to analyze.", + "exe_packer_detector": "Detect the exe packer (ex. py2exe).", + "exe_unpacker": "Unpack the exe if its supported", + "sus_strings_lookup": "Search for the sus strings like ips links.", + "all_strings": "Search for all readable strings in the file.", + "get_file_hashs": "Gives you the MD5, SHA1 and SHA256 of the file.", + "clear": "Clear the console.", + "exit": "Exits the program.", + } + while 1: + tui.linux_prompt("analyzer") + choice = input() + if choice == "help": + print(f"\n{Fore.CYAN}=== Available Commands ==={Style.RESET_ALL}") + for cmd, desc in commands.items(): + print(f"{Fore.YELLOW}{cmd}{Style.RESET_ALL} - {desc}") + print(f"{Fore.CYAN}=========================={Style.RESET_ALL}\n") + elif choice == "set_file": + file_path = file_explorer() + if file_path: + print(f"{Fore.CYAN}Selected file path: {file_path}{Style.RESET_ALL}\n") + + else: + print(f"{Fore.YELLOW}No file selected.{Style.RESET_ALL}\n") + elif choice == "exe_packer_detector": + if file_path: + print(f"{Fore.CYAN}Starting the detecting process...{Style.RESET_ALL}") + print(f"{Fore.CYAN}packer detector result:{Style.RESET_ALL}\n") + print(detect_packer(file_path)) + print("\n") + else: + print(f"{Fore.YELLOW}No file selected.{Style.RESET_ALL}\n") + elif choice == "exe_unpacker": + if file_path: + print(f"{Fore.CYAN}Starting the unpacking process...{Style.RESET_ALL}") + print(f"{Fore.CYAN}unpacker result:{Style.RESET_ALL}\n") + print(unpack_file(file_path)) + print("\n") + else: + print(f"{Fore.YELLOW}No file selected.{Style.RESET_ALL}\n") + elif choice == "sus_strings_lookup": + if file_path: + print( + f"{Fore.CYAN}Starting the sus strings lookup process...{Style.RESET_ALL}" + ) + print(f"{Fore.CYAN}search result:{Style.RESET_ALL}\n") + print(sus_strings_lookup(file_path)) + print("\n") + else: + print(f"{Fore.YELLOW}No file selected.{Style.RESET_ALL}\n") + elif choice == "all_strings": + if file_path: + print( + f"{Fore.CYAN}Starting the all strings lookup process...{Style.RESET_ALL}" + ) + print(f"{Fore.CYAN}search result:{Style.RESET_ALL}\n") + print(all_strings_lookup(file_path)) + print("\n") + else: + print(f"{Fore.YELLOW}No file selected.{Style.RESET_ALL}\n") + elif choice == "get_file_hashs": + if file_path: + print( + f"{Fore.CYAN}Starting to get the file hashs process...{Style.RESET_ALL}" + ) + print(f"{Fore.CYAN}hashs result:{Style.RESET_ALL}\n") + print(get_file_hashs(file_path)) + else: + print(f"{Fore.YELLOW}No file selected.{Style.RESET_ALL}\n") + elif choice == "back": + tui.clear_console() + banner() + break + elif choice == "clear": + tui.clear_console() + banner() + elif choice == "exit": + tui.clear_console() + banner() + print(f"{colorama.Fore.CYAN}Exiting....{colorama.Style.RESET_ALL}") + sys.exit(0) + else: + print(f"{Fore.RED}Unknown command{Style.RESET_ALL}") + + +def file_explorer() -> str: + root = Tk() + root.withdraw() + root.wm_attributes("-topmost", 1) + file_path = filedialog.askopenfilename( + filetypes=[ + ("Python Files", "*.py"), + ("Python compiled Files", "*.pyc"), + ("exe Files", "*.exe"), + ("All Files", "*.*"), + ] + ) + return file_path + + +def get_info() -> str: + pv = platform.python_version() + arch = platform.architecture()[0] + system_info = platform.uname() + oss = system_info.system + " " + system_info.release + return {"pv": pv, "arch": arch, "os": oss} + + +def fetch_info(): + global change_log + global platform_info + if not platform.architecture()[0].startswith("64"): + tui.fade_type( + f"{colorama.Fore.YELLOW}your pc arch is not x64 bit please note this tool was tested on windows x64 bit{colorama.Style.RESET_ALL}\n" + ) + change_log = requests.get(config.__CHANGELOG_URL__).json() + platform_info = get_info() + + +def changelog_display(): + print("\n") + for version_data in change_log: + version_element = ( + f"{Fore.CYAN}Version {version_data['version']}{Style.RESET_ALL}\n" + ) + changes_list = "" + for change in version_data["changes"]: + changes_list += f" • {change}\n" + version_element += changes_list + print(version_element) + print("\n") + + +def cupdate() -> None: + if update.check_update(): + tui.fade_type( + f"{colorama.Fore.CYAN}You are using the latest version{colorama.Style.RESET_ALL}\n" + ) + else: + tui.fade_type( + f"{colorama.Fore.YELLOW}There's a new version. Are you sure you want to use this version?{colorama.Style.RESET_ALL}\n" + ) + tui.fade_type("Answer [y/n]\n") + if not input(">>> ").lower() == "y": + tui.fade_type( + f"{colorama.Fore.YELLOW}Download it from here : https://github.com/Fadi002/de4py{colorama.Style.RESET_ALL}\n" + ) + tui.fade_type( + f"{colorama.Fore.YELLOW}Press any key to exit...{colorama.Style.RESET_ALL}\n" + ) + while True: + if msvcrt.kbhit(): + key = msvcrt.getch() + tui.fade_type( + f"{colorama.Fore.YELLOW}Exiting...{colorama.Style.RESET_ALL}" + ) + sys.exit(0) + + +def banner(): + tui.draw_line() + print( + tui.water( + tui.align(''' + 888 d8888 + 888 d8P888 + 888 d8P 888 + .d88888 .d88b. d8P 888 88888b. 888 888 +d88" 888 d8P Y8b d88 888 888 "88b 888 888 +888 888 88888888 8888888888 888 888 888 888 +Y88b 888 Y8b. 888 888 d88P Y88b 888 + "Y88888 "Y8888 888 88888P" "Y88888 + 888 888 + 888 Y8b d88P + 888 "Y88P"''' + ) + ) + ) + tui.draw_line() + + +def neofetch(): + print("\n") + info = f""" {Fore.GREEN}de4py@{Fore.CYAN}{os.getenv('Username')}{Style.RESET_ALL} + {Fore.CYAN}-----------------------------------------------{Style.RESET_ALL} + {Fore.CYAN}OS: {platform.system()}{Style.RESET_ALL} + {Fore.CYAN}Version: {platform.version()}{Style.RESET_ALL} + {Fore.CYAN}Kernel: {platform.uname().release}{Style.RESET_ALL} + {Fore.CYAN}Machine: {platform.machine()}{Style.RESET_ALL} + {Fore.CYAN}Processor: {platform.processor()}{Style.RESET_ALL} + {Fore.CYAN}Hostname: {socket.gethostname()}{Style.RESET_ALL} + {Fore.CYAN}User: {os.getenv('Username')}{Style.RESET_ALL} + {Fore.CYAN}Tool: de4py@{config.__VERSION__}{Style.RESET_ALL}""" + print(tui.Add.Add(tui.windows_logo, info, 4)) + + +def start(): + banner() + tui.loading_animation("Checking for updates") + tui.clear_line() + cupdate() + tui.loading_animation("Fetching info") + fetch_info() + tui.clear_line() + fade_type(f"{colorama.Fore.CYAN}Starting de4py{colorama.Style.RESET_ALL}\n") + time.sleep(1) + tui.clear_console() + banner() + fade_type( + f"{colorama.Fore.CYAN}Welcome to de4py type {colorama.Style.RESET_ALL}help {colorama.Fore.CYAN}to get the commands that you can use\n" + ) + if config.__RPC__: + rpc.start_RPC() + while 1: + home_tab() + +if __name__ == "__main__": + start() \ No newline at end of file diff --git a/config/config.py b/config/config.py index 0c498a4..85c09e2 100644 --- a/config/config.py +++ b/config/config.py @@ -1,3 +1,4 @@ -__VERSION__ = 'V1.0.5' +__VERSION__ = 'V1.0.6' __CHANGELOG_URL__ = 'https://raw.githubusercontent.com/Fadi002/de4py/main/INFO/changelog.json' -__VERSION_URL__ = 'https://raw.githubusercontent.com/Fadi002/de4py/main/INFO/version' \ No newline at end of file +__VERSION_URL__ = 'https://raw.githubusercontent.com/Fadi002/de4py/main/INFO/version' +__RPC__ = True \ No newline at end of file diff --git a/main.py b/main.py index 1f0e83f..ec1b8eb 100644 --- a/main.py +++ b/main.py @@ -3,15 +3,22 @@ | De4py project : https://github.com/Fadi002/de4py | ********************************************************************* ''' -import os, msvcrt, eel, logging, requests, sys, platform, threading, psutil +import os, msvcrt, eel, logging, requests, sys, platform, threading, psutil, colorama, signal +from config import config +from util import tui, update, gen_path, rpc +if len(sys.argv) > 1 and sys.argv[1] == "--cli": + from TUI import cli + cli.start() from deobfuscators.detector import detect_obfuscator from tkinter import Tk, filedialog from dlls import shell -from util import tui, update, gen_path -from config import config from analyzer import detect_packer, unpack_file, get_file_hashs, sus_strings_lookup, all_strings_lookup import time - +def signal_handler(sig, frame): + print(f"{colorama.Fore.CYAN}Exiting....{colorama.Style.RESET_ALL}") + rpc.KILL_THREAD = True + sys.exit(0) +signal.signal(signal.SIGINT, signal_handler) HANDLE = None HANDLE_analyzer = None STOP_THREADS = False @@ -23,7 +30,7 @@ eel.init('gui') -def cupdate(): +def cupdate() -> None: if update.check_update(): logging.info("You are using the latest version") else: @@ -36,11 +43,12 @@ def cupdate(): if msvcrt.kbhit(): key = msvcrt.getch() logging.warning("Exiting...") - exit(0) + rpc.KILL_THREAD = True + sys.exit(0) @eel.expose -def protector_detector(file_path): +def protector_detector(file_path) -> str: try: result=detect_obfuscator(file_path) return result @@ -49,7 +57,7 @@ def protector_detector(file_path): @eel.expose -def file_explorer(): +def file_explorer() -> str: root = Tk() root.withdraw() root.wm_attributes('-topmost', 1) @@ -58,7 +66,7 @@ def file_explorer(): @eel.expose -def inject_shell(pid): +def inject_shell(pid) -> str: global HANDLE l = shell.inject_shell(pid) if l[1]: @@ -70,13 +78,13 @@ def inject_shell(pid): @eel.expose -def changelog(): +def changelog() -> str: response = requests.get(config.__CHANGELOG_URL__) return response.text @eel.expose -def processchecker(pid): +def processchecker(pid) -> str: global HANDLE global HANDLE_analyzer while True: @@ -93,13 +101,13 @@ def processchecker(pid): @eel.expose -def dumpstring(): +def dumpstring() -> str: path, filename = gen_path(__file__) write_to_pipe("DumpStrings||"+path) return "saved as "+ filename @eel.expose -def openanalyzerhandle(): +def openanalyzerhandle() -> str: global HANDLE_analyzer write_to_pipe("GetAnalyzerHandle") HANDLE_analyzer = os.open('\\\\.\\pipe\\de4py_analyzer', os.O_RDWR) @@ -107,20 +115,20 @@ def openanalyzerhandle(): return "Executed | click the button again to open the menu" @eel.expose -def getfunctions(): +def getfunctions() -> str: path, filename = gen_path(__file__) write_to_pipe("GetFunctions||"+path) return "saved as "+ filename @eel.expose -def execpython(path): +def execpython(path) -> str: write_to_pipe("ExecPY||"+path) return "Executed" @eel.expose -def showconsole(pid): +def showconsole(pid) -> str: if shell.show_console(pid): return "DONE" else: @@ -128,7 +136,7 @@ def showconsole(pid): @eel.expose -def get_info(): +def get_info() -> str: pv = platform.python_version() arch = platform.architecture()[0] if not arch.startswith('64'): @@ -138,7 +146,7 @@ def get_info(): return {"pv":pv,"arch":arch,"os":oss} @eel.expose -def write_to_pipe(message): +def write_to_pipe(message) -> str: global HANDLE os.write(HANDLE, message.encode()) response = read_from_pipe() @@ -147,19 +155,19 @@ def write_to_pipe(message): else: return False -def write_to_pipe_detailed(message): +def write_to_pipe_detailed(message) -> str: global HANDLE os.write(HANDLE, message.encode()) response = read_from_pipe() return response -def read_from_pipe(): +def read_from_pipe() -> str: global HANDLE message = os.read(HANDLE, 1024).decode() return message @eel.expose -def monitorfileshook(var): +def monitorfileshook(var) -> str: if var: write_to_pipe("MonitorFiles") return "Monitor files hook has been installed" @@ -168,7 +176,7 @@ def monitorfileshook(var): return "Monitor files hook has been uninstalled" @eel.expose -def monitorprocesseshook(var): +def monitorprocesseshook(var) -> str: if var: write_to_pipe("MonitorProcesses") return "Monitor processes hook has been installed" @@ -177,7 +185,7 @@ def monitorprocesseshook(var): return "Monitor processes hook has been uninstalled" @eel.expose -def monitorconnectionshook(var): +def monitorconnectionshook(var) -> str: if var: write_to_pipe("MonitorConnections") return "Monitor connections hook has been installed" @@ -185,7 +193,7 @@ def monitorconnectionshook(var): write_to_pipe("UnMonitorConnections") return "Monitor connections hook has been uninstalled" -def dealwithfilesocket(): +def dealwithfilesocket() -> str: if not os.path.exists(os.getcwd() + "\\SocketDump.txt"): open(os.getcwd() + "\\SocketDump.txt", 'w').close() @@ -194,7 +202,7 @@ def dealwithfilessl(): open(os.getcwd() + "\\OpenSSLDump.txt", 'w').close() @eel.expose -def dumpsocketcontent(var): +def dumpsocketcontent(var) -> str: if var: dealwithfilesocket() response = write_to_pipe("DumpConnections||" + os.getcwd() + "\\SocketDump.txt") @@ -204,7 +212,7 @@ def dumpsocketcontent(var): return "stopped dumping socket content." @eel.expose -def dumpopensslcontent(var): +def dumpopensslcontent(var) -> str: if var: dealwithfilessl() return write_to_pipe_detailed("DumpOpenSSL||" + os.getcwd() + "\\OpenSSLDump.txt") @@ -224,15 +232,18 @@ def update_hooks_output(): except Exception as e: logging.error(f"Error occurred while reading from HANDLE_analyzer: {str(e)}") -def main(): +def main() -> None: # eel.start('index.html',size=(1024, 589),port=3456) eel.start('index.html',size=(1024, 589),port=5456) - + rpc.KILL_THREAD = True if __name__ == '__main__': try: cupdate() - except: + except Exception as e: + print(e) logging.error("Failed to check the update") + if config.__RPC__: + rpc.start_RPC() main() diff --git a/requirements.txt b/requirements.txt index 261dc4c..53ae797 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,4 +5,5 @@ pyinstaller py2exe pycryptodome colorama -xdis \ No newline at end of file +xdis +pypresence \ No newline at end of file diff --git a/util/__init__.py b/util/__init__.py index 16c23d9..ba6e81c 100644 --- a/util/__init__.py +++ b/util/__init__.py @@ -1,3 +1,4 @@ from .tui import * from .update import * from .pathgen import * +from .rpc import * \ No newline at end of file diff --git a/util/rpc.py b/util/rpc.py new file mode 100644 index 0000000..ef78a60 --- /dev/null +++ b/util/rpc.py @@ -0,0 +1,37 @@ +from pypresence import Presence +import threading, os, time +from config import config +import ctypes + +RPC = None +KILL_THREAD = None + +def __RPC_THREAD__(): + global RPC + global KILL_THREAD + start = int(time.time()) + while True: + if KILL_THREAD: + break + try: + RPC.update( + large_image = "de4py", + large_text = "De4py", + details = f"De4py {config.__VERSION__}", + state ="Python reverse engineering toolkit", + start = start, + buttons = [{"label": "Download", "url": "https://de4py.000.pe/"}, {"label": "Github", "url": "https://github.com/Fadi002"}] + ) + time.sleep(3) + except: + break + +def start_RPC(): + global RPC + try: + RPC = Presence("1190392428247650466") + RPC.connect() + threading.Thread(target=__RPC_THREAD__).start() + except: + pass + diff --git a/util/tui.py b/util/tui.py index 818fd58..ea20ab4 100644 --- a/util/tui.py +++ b/util/tui.py @@ -1,5 +1,35 @@ -import os, logging, time -from colorama import Fore, Style +import os, logging, time, shutil, sys +from colorama import Fore, Style, AnsiToWin32 +from traceback import extract_tb +__RAW_BANNER__ = ''' +██████╗ ███████╗██╗ ██╗██████╗ ██╗ ██╗ +██╔══██╗██╔════╝██║ ██║██╔══██╗╚██╗ ██╔╝ +██║ ██║█████╗ ███████║██████╔╝ ╚████╔╝ +██║ ██║██╔══╝ ╚════██║██╔═══╝ ╚██╔╝ +██████╔╝███████╗ ██║██║ ██║ +╚═════╝ ╚══════╝ ╚═╝╚═╝ ╚═╝''' + +windows_logo = f"""{Fore.CYAN} .., +{Fore.CYAN} ....,,:;+ccllll +{Fore.CYAN} ...,,+:; cllllllllllllllllll +{Fore.CYAN},cclllllllllll lllllllllllllllllll +{Fore.CYAN}llllllllllllll lllllllllllllllllll +{Fore.CYAN}llllllllllllll lllllllllllllllllll +{Fore.CYAN}llllllllllllll lllllllllllllllllll +{Fore.CYAN}llllllllllllll lllllllllllllllllll +{Fore.CYAN}llllllllllllll lllllllllllllllllll +{Fore.CYAN} +{Fore.CYAN}llllllllllllll lllllllllllllllllll +{Fore.CYAN}llllllllllllll lllllllllllllllllll +{Fore.CYAN}llllllllllllll lllllllllllllllllll +{Fore.CYAN}llllllllllllll lllllllllllllllllll +{Fore.CYAN}llllllllllllll lllllllllllllllllll +{Fore.CYAN}llllllllllllll lllllllllllllllllll +{Fore.CYAN}`'ccllllllllll lllllllllllllllllll +{Fore.CYAN} `' \\*:: :ccllllllllllllllll +{Fore.CYAN} ````''*::cll +{Fore.CYAN} ``{Style.RESET_ALL}""" + def water(text): os.system(""); faded = "" green = 10 @@ -10,14 +40,11 @@ def water(text): if green > 255: green = 255 return faded -__BANNER__ = water(''' -██████╗ ███████╗██╗ ██╗██████╗ ██╗ ██╗ -██╔══██╗██╔════╝██║ ██║██╔══██╗╚██╗ ██╔╝ -██║ ██║█████╗ ███████║██████╔╝ ╚████╔╝ -██║ ██║██╔══╝ ╚════██║██╔═══╝ ╚██╔╝ -██████╔╝███████╗ ██║██║ ██║ -╚═════╝ ╚══════╝ ╚═╝╚═╝ ╚═╝''') + +__BANNER__ = water(__RAW_BANNER__) + def clear_console():os.system('cls' if os.name == 'nt' else 'clear') + def setup_logging(): log_level = logging.INFO logging_format = "%(levelname)s - %(message)s" @@ -38,7 +65,143 @@ def emit(self, record): else: colored_message = message print(colored_message) + def fade_type(text): for c in text: print(c,end='',flush=True) - time.sleep(0.009) \ No newline at end of file + time.sleep(0.009) + +def align(text: str) -> str: + """ + credits : https://github.com/SirDank/dankware/blob/main/dankware/__init__.py + """ + + width = shutil.get_terminal_size().columns + aligned = text + + for _ in tuple(vars(Fore).values()) + tuple(vars(Style).values()): + aligned = aligned.replace(_,'') + + text = text.splitlines() + aligned = aligned.splitlines() + + for _ in range(len(aligned)): + aligned[_] = aligned[_].center(width).replace(aligned[_],text[_]) + + return str('\n'.join(aligned) + Style.RESET_ALL) + +def draw_line(): + terminal_width = shutil.get_terminal_size().columns + line = Fore.CYAN + "-" * terminal_width + Style.RESET_ALL + print(line) + + +def loading_animation(text, loops=2): + frames = ['\\', '|', '/', '-'] + for _ in range(loops): + for frame in frames: + line = f"{Fore.CYAN}{text} {Style.RESET_ALL}[{Fore.CYAN}{frame}{Style.RESET_ALL}]" + Style.RESET_ALL + print(line, end='\r') + time.sleep(0.2) + +def clear_line(): + sys.stdout.write("\033[K") + sys.stdout.flush() + +def linux_prompt(tab="~"): + sys.stdout.write(f"{Fore.GREEN}de4py@{Fore.CYAN}{os.getenv('Username')}{Style.RESET_ALL} {Fore.GREEN}{tab}/ {Style.RESET_ALL}$ ") + sys.stdout.flush() + + + +def custom_error(exc_type, exc_value, exc_traceback): + print(f"{Fore.RED}=== Start Traceback ==={Style.RESET_ALL}") + print(f"{Fore.RED}Error Type:{Style.RESET_ALL} {exc_type.__name__}") + print(f"{Fore.RED}Error Message:{Style.RESET_ALL} {exc_value}") + print(f"{Fore.RED}Traceback:{Style.RESET_ALL}") + traceback_lines = [] + for filename, line_num, func_name, line_code in extract_tb(exc_traceback): + traceback_lines.append(f" File '{filename}', line {line_num}, in {func_name}\n {line_code}") + print("\n".join(traceback_lines)) + print(f"{Fore.RED}=== End of Traceback ==={Style.RESET_ALL}") + + + +class Add: + + """ + CREDITS: https://github.com/billythegoat356/pystyle/blob/main/pystyle/__init__.py + 1 function: + Add() | allow you to add a text to another, and even center it + """ + + def Add(banner1, banner2, spaces=0, center=False): + if center: + split1 = len(banner1.splitlines()) + split2 = len(banner2.splitlines()) + if split1 > split2: + spaces = (split1 - split2) // 2 + elif split2 > split1: + spaces = (split2 - split1) // 2 + else: + spaces = 0 + + if spaces > max(len(banner1.splitlines()), len(banner2.splitlines())): + # raise Banner.MaximumSpaces(spaces) + spaces = max(len(banner1.splitlines()), len(banner2.splitlines())) + + ban1 = banner1.splitlines() + ban2 = banner2.splitlines() + + ban1count = len(ban1) + ban2count = len(ban2) + + size = Add._length(ban1) + + ban1 = Add._edit(ban1, size) + + ban1line = 0 + ban2line = 0 + text = '' + + for _ in range(spaces): + + if ban1count >= ban2count: + ban1data = ban1[ban1line] + ban2data = '' + + ban1line += 1 + + else: + ban1data = " " * size + ban2data = ban2[ban2line] + + ban2line += 1 + + text = text + ban1data + ban2data + '\n' + while ban1line < ban1count or ban2line < ban2count: + + ban1data = ban1[ban1line] if ban1line < ban1count else " " * size + ban2data = ban2[ban2line] if ban2line < ban2count else "" + text = text + ban1data + ban2data + '\n' + + ban1line += 1 + ban2line += 1 + return text + + """ ! developper area ! """ + + class MaximumSpaces(Exception): + def __init__(self, spaces: str): + super().__init__(f"Too much spaces [{spaces}].") + + def _length(ban1): + bigestline = 0 + + for line in ban1: + if len(line) > bigestline: + bigestline = len(line) + return bigestline + + def _edit(ban1, size): + return [line + (size - len(line)) * " " for line in ban1] \ No newline at end of file