diff --git a/.apt/usr/bin/config/config.conf b/.apt/usr/bin/config/config.conf deleted file mode 100644 index 82ceef724..000000000 --- a/.apt/usr/bin/config/config.conf +++ /dev/null @@ -1,771 +0,0 @@ -# Neofetch config file -# https://github.com/dylanaraps/neofetch - - -# See this wiki page for more info: -# https://github.com/dylanaraps/neofetch/wiki/Customizing-Info -print_info() { - info title - info underline - - info "OS" distro - info "Host" model - info "Kernel" kernel - info "Uptime" uptime - info "Packages" packages - info "Shell" shell - info "Resolution" resolution - info "DE" de - info "WM" wm - info "WM Theme" wm_theme - info "Theme" theme - info "Icons" icons - info "Terminal" term - info "Terminal Font" term_font - info "CPU" cpu - info "GPU" gpu - info "Memory" memory - - # info "GPU Driver" gpu_driver # Linux/macOS only - # info "CPU Usage" cpu_usage - # info "Disk" disk - # info "Battery" battery - # info "Font" font - # info "Song" song - # info "Local IP" local_ip - # info "Public IP" public_ip - # info "Users" users - # info "Install Date" install_date - # info "Locale" locale # This only works on glibc systems. - - info line_break - info cols - info line_break -} - - -# Kernel - - -# Shorten the output of the kernel function. -# -# Default: 'on' -# Values: 'on', 'off' -# Flag: --kernel_shorthand -# Supports: Everything except *BSDs (except PacBSD and PC-BSD) -# -# Example: -# on: '4.8.9-1-ARCH' -# off: 'Linux 4.8.9-1-ARCH' -kernel_shorthand="off" - - -# Distro - - -# Shorten the output of the distro function -# -# Default: 'off' -# Values: 'on', 'off', 'tiny' -# Flag: --distro_shorthand -# Supports: Everything except Windows and Haiku -distro_shorthand="off" - -# Show/Hide OS Architecture. -# Show 'x86_64', 'x86' and etc in 'Distro:' output. -# -# Default: 'on' -# Values: 'on', 'off' -# Flag: --os_arch -# -# Example: -# on: 'Arch Linux x86_64' -# off: 'Arch Linux' -os_arch="on" - - -# Uptime - - -# Shorten the output of the uptime function -# -# Default: 'on' -# Values: 'on', 'off', 'tiny' -# Flag: --uptime_shorthand -# -# Example: -# on: '2 days, 10 hours, 3 mins' -# off: '2 days, 10 hours, 3 minutes' -# tiny: '2d 10h 3m' -uptime_shorthand="tiny" - - -# Shell - - -# Show the path to $SHELL -# -# Default: 'off' -# Values: 'on', 'off' -# Flag: --shell_path -# -# Example: -# on: '/bin/bash' -# off: 'bash' -shell_path="on" - -# Show $SHELL version -# -# Default: 'on' -# Values: 'on', 'off' -# Flag: --shell_version -# -# Example: -# on: 'bash 4.4.5' -# off: 'bash' -shell_version="on" - - -# CPU - - -# CPU speed type -# -# Default: 'bios_limit' -# Values: 'scaling_cur_freq', 'scaling_min_freq', 'scaling_max_freq', 'bios_limit'. -# Flag: --speed_type -# Supports: Linux with 'cpufreq' -# NOTE: Any file in '/sys/devices/system/cpu/cpu0/cpufreq' can be used as a value. -speed_type="bios_limit" - -# CPU speed shorthand -# -# Default: 'off' -# Values: 'on', 'off'. -# Flag: --speed_shorthand. -# NOTE: This flag is not supported in systems with CPU speed less than 1 GHz -# -# Example: -# on: 'i7-6500U (4) @ 3.1GHz' -# off: 'i7-6500U (4) @ 3.100GHz' -speed_shorthand="off" - -# Enable/Disable CPU brand in output. -# -# Default: 'on' -# Values: 'on', 'off' -# Flag: --cpu_brand -# -# Example: -# on: 'Intel i7-6500U' -# off: 'i7-6500U (4)' -cpu_brand="off" - -# CPU Speed -# Hide/Show CPU speed. -# -# Default: 'on' -# Values: 'on', 'off' -# Flag: --cpu_speed -# -# Example: -# on: 'Intel i7-6500U (4) @ 3.1GHz' -# off: 'Intel i7-6500U (4)' -cpu_speed="off" - -# CPU Cores -# Display CPU cores in output -# -# Default: 'logical' -# Values: 'logical', 'physical', 'off' -# Flag: --cpu_cores -# Support: 'physical' doesn't work on BSD. -# -# Example: -# logical: 'Intel i7-6500U (4) @ 3.1GHz' (All virtual cores) -# physical: 'Intel i7-6500U (2) @ 3.1GHz' (All physical cores) -# off: 'Intel i7-6500U @ 3.1GHz' -cpu_cores="off" - -# CPU Temperature -# Hide/Show CPU temperature. -# Note the temperature is added to the regular CPU function. -# -# Default: 'off' -# Values: 'C', 'F', 'off' -# Flag: --cpu_temp -# Supports: Linux, BSD -# NOTE: For FreeBSD and NetBSD-based systems, you'll need to enable -# coretemp kernel module. This only supports newer Intel processors. -# -# Example: -# C: 'Intel i7-6500U (4) @ 3.1GHz [27.2°C]' -# F: 'Intel i7-6500U (4) @ 3.1GHz [82.0°F]' -# off: 'Intel i7-6500U (4) @ 3.1GHz' -cpu_temp="off" - - -# GPU - - -# Enable/Disable GPU Brand -# -# Default: 'on' -# Values: 'on', 'off' -# Flag: --gpu_brand -# -# Example: -# on: 'AMD HD 7950' -# off: 'HD 7950' -gpu_brand="off" - -# Which GPU to display -# -# Default: 'all' -# Values: 'all', 'dedicated', 'integrated' -# Flag: --gpu_type -# Supports: Linux -# -# Example: -# all: -# GPU1: AMD HD 7950 -# GPU2: Intel Integrated Graphics -# -# dedicated: -# GPU1: AMD HD 7950 -# -# integrated: -# GPU1: Intel Integrated Graphics -gpu_type="dedicated" - - -# Resolution - - -# Display refresh rate next to each monitor -# Default: 'off' -# Values: 'on', 'off' -# Flag: --refresh_rate -# Supports: Doesn't work on Windows. -# -# Example: -# on: '1920x1080 @ 60Hz' -# off: '1920x1080' -refresh_rate="on" - - -# Gtk Theme / Icons / Font - - -# Shorten output of GTK Theme / Icons / Font -# -# Default: 'off' -# Values: 'on', 'off' -# Flag: --gtk_shorthand -# -# Example: -# on: 'Numix, Adwaita' -# off: 'Numix [GTK2], Adwaita [GTK3]' -gtk_shorthand="on" - - -# Enable/Disable gtk2 Theme / Icons / Font -# -# Default: 'on' -# Values: 'on', 'off' -# Flag: --gtk2 -# -# Example: -# on: 'Numix [GTK2], Adwaita [GTK3]' -# off: 'Adwaita [GTK3]' -gtk2="off" - -# Enable/Disable gtk3 Theme / Icons / Font -# -# Default: 'on' -# Values: 'on', 'off' -# Flag: --gtk3 -# -# Example: -# on: 'Numix [GTK2], Adwaita [GTK3]' -# off: 'Numix [GTK2]' -gtk3="off" - - -# IP Address - - -# Website to ping for the public IP -# -# Default: 'http://ident.me' -# Values: 'url' -# Flag: --ip_host -public_ip_host="http://ident.me" - - -# Disk - - -# Which disks to display. -# The values can be any /dev/sdXX, mount point or directory. -# NOTE: By default we only show the disk info for '/'. -# -# Default: '/' -# Values: '/', '/dev/sdXX', '/path/to/drive'. -# Flag: --disk_show -# -# Example: -# disk_show=('/' '/dev/sdb1'): -# 'Disk (/): 74G / 118G (66%)' -# 'Disk (/mnt/Videos): 823G / 893G (93%)' -# -# disk_show=('/'): -# 'Disk (/): 74G / 118G (66%)' -# -disk_show=('/') - -# Disk subtitle. -# What to append to the Disk subtitle. -# -# Default: 'mount' -# Values: 'mount', 'name', 'dir' -# Flag: --disk_subtitle -# -# Example: -# name: 'Disk (/dev/sda1): 74G / 118G (66%)' -# 'Disk (/dev/sdb2): 74G / 118G (66%)' -# -# mount: 'Disk (/): 74G / 118G (66%)' -# 'Disk (/mnt/Local Disk): 74G / 118G (66%)' -# 'Disk (/mnt/Videos): 74G / 118G (66%)' -# -# dir: 'Disk (/): 74G / 118G (66%)' -# 'Disk (Local Disk): 74G / 118G (66%)' -# 'Disk (Videos): 74G / 118G (66%)' -disk_subtitle="mount" - - -# Song - - -# Manually specify a music player. -# -# Default: 'auto' -# Values: 'auto', 'player-name' -# Flag: --music_player -# -# Available values for 'player-name': -# -# Google Play -# Spotify -# amarok -# audacious -# banshee -# bluemindo -# clementine -# cmus -# deadbeef -# deepin-music -# elisa -# exaile -# gnome-music -# guayadeque -# iTunes$ -# juk -# lollypop -# mocp -# mopidy -# mpd -# pogo -# pragha -# qmmp -# quodlibet -# rhythmbox -# spotify -# tomahawk -# xmms2d -# yarock -music_player="auto" - -# Print the Artist and Title on separate lines -# -# Default: 'off' -# Values: 'on', 'off' -# Flag: --song_shorthand -# -# Example: -# on: 'Artist: The Fratellis' -# 'Song: Chelsea Dagger' -# -# off: 'Song: The Fratellis - Chelsea Dagger' -song_shorthand="off" - - -# Install Date - - -# Whether to show the time in the output -# -# Default: 'on' -# Values: 'on', 'off' -# Flag: --install_time -# -# Example: -# on: 'Thu 14 Apr 2016 11:50 PM' -# off: 'Thu 14 Apr 2016' -install_time="on" - -# Set time format in the output -# -# Default: '24h' -# Values: '12h', '24h' -# Flag: --install_time_format -# -# Example: -# 12h: 'Thu 14 Apr 2016 11:50 PM' -# 24h: 'Thu 14 Apr 2016 23:50' -install_time_format="12h" - - -# Text Colors - - -# Text Colors -# -# Default: 'distro' -# Values: 'distro', 'num' 'num' 'num' 'num' 'num' 'num' -# Flag: --colors -# -# Each number represents a different part of the text in -# this order: 'title', '@', 'underline', 'subtitle', 'colon', 'info' -# -# Example: -# colors=(distro) - Text is colored based on Distro colors. -# colors=(4 6 1 8 8 6) - Text is colored in the order above. -colors=(distro) - - -# Text Options - - -# Toggle bold text -# -# Default: 'on' -# Values: 'on', 'off' -# Flag: --bold -bold="on" - -# Enable/Disable Underline -# -# Default: 'on' -# Values: 'on', 'off' -# Flag: --underline -underline_enabled="on" - -# Underline character -# -# Default: '-' -# Values: 'string' -# Flag: --underline_char -underline_char="-" - - -# Color Blocks - - -# Color block range -# The range of colors to print. -# -# Default: '0', '7' -# Values: 'num' -# Flag: --block_range -# -# Example: -# -# Display colors 0-7 in the blocks. (8 colors) -# neofetch --block_range 0 7 -# -# Display colors 0-15 in the blocks. (16 colors) -# neofetch --block_range 0 15 -block_range=(0 15) - -# Toggle color blocks -# -# Default: 'on' -# Values: 'on', 'off' -# Flag: --color_blocks -color_blocks="on" - -# Color block width in spaces -# -# Default: '3' -# Values: 'num' -# Flag: --block_width -block_width=3 - -# Color block height in lines -# -# Default: '1' -# Values: 'num' -# Flag: --block_height -block_height=1 - - -# Progress Bars - - -# Bar characters -# -# Default: '-', '=' -# Values: 'string', 'string' -# Flag: --bar_char -# -# Example: -# neofetch --bar_char 'elapsed' 'total' -# neofetch --bar_char '-' '=' -bar_char_elapsed="-" -bar_char_total="=" - -# Toggle Bar border -# -# Default: 'on' -# Values: 'on', 'off' -# Flag: --bar_border -bar_border="on" - -# Progress bar length in spaces -# Number of chars long to make the progress bars. -# -# Default: '15' -# Values: 'num' -# Flag: --bar_length -bar_length=15 - -# Progress bar colors -# When set to distro, uses your distro's logo colors. -# -# Default: 'distro', 'distro' -# Values: 'distro', 'num' -# Flag: --bar_colors -# -# Example: -# neofetch --bar_colors 3 4 -# neofetch --bar_colors distro 5 -bar_color_elapsed="distro" -bar_color_total="distro" - - -# Info display -# Display a bar with the info. -# -# Default: 'off' -# Values: 'bar', 'infobar', 'barinfo', 'off' -# Flags: --cpu_display -# --memory_display -# --battery_display -# --disk_display -# -# Example: -# bar: '[---=======]' -# infobar: 'info [---=======]' -# barinfo: '[---=======] info' -# off: 'info' -cpu_display="off" -memory_display="off" -battery_display="off" -disk_display="off" - - -# Backend Settings - - -# Image backend. -# -# Default: 'ascii' -# Values: 'ascii', 'caca', 'catimg', 'jp2a', 'iterm2', 'off', 'termpix', 'pixterm', 'tycat', 'w3m' -# Flag: --backend -image_backend="ascii" - -# Image Source -# -# Which image or ascii file to display. -# -# Default: 'auto' -# Values: 'auto', 'ascii', 'wallpaper', '/path/to/img', '/path/to/ascii', '/path/to/dir/' -# Flag: --source -# -# NOTE: 'auto' will pick the best image source for whatever image backend is used. -# In ascii mode, distro ascii art will be used and in an image mode, your -# wallpaper will be used. -image_source="auto" - - -# Ascii Options - - -# Ascii distro -# Which distro's ascii art to display. -# -# Default: 'auto' -# Values: 'auto', 'distro_name' -# Flag: --ascii_distro -# -# NOTE: Arch and Ubuntu have 'old' logo variants. -# Change this to 'arch_old' or 'ubuntu_old' to use the old logos. -# NOTE: Ubuntu has flavor variants. -# Change this to 'Lubuntu', 'Xubuntu', 'Ubuntu-GNOME' or 'Ubuntu-Budgie' to use the flavors. -# NOTE: Arch, Crux and Gentoo have a smaller logo variant. -# Change this to 'arch_small', 'crux_small' or 'gentoo_small' to use the small logos. -ascii_distro="LinuxMint" - -# Ascii Colors -# -# Default: 'distro' -# Values: 'distro', 'num' 'num' 'num' 'num' 'num' 'num' -# Flag: --ascii_colors -# -# Example: -# ascii_colors=(distro) - Ascii is colored based on Distro colors. -# ascii_colors=(4 6 1 8 8 6) - Ascii is colored using these colors. -ascii_colors=(distro) - -# Bold ascii logo -# Whether or not to bold the ascii logo. -# -# Default: 'on' -# Values: 'on', 'off' -# Flag: --ascii_bold -ascii_bold="on" - - -# Image Options - - -# Image loop -# Setting this to on will make neofetch redraw the image constantly until -# Ctrl+C is pressed. This fixes display issues in some terminal emulators. -# -# Default: 'off' -# Values: 'on', 'off' -# Flag: --loop -image_loop="off" - -# Thumbnail directory -# -# Default: '~/.cache/thumbnails/neofetch' -# Values: 'dir' -thumbnail_dir="${XDG_CACHE_HOME:-${HOME}/.cache}/thumbnails/neofetch" - -# Crop mode -# -# Default: 'normal' -# Values: 'normal', 'fit', 'fill' -# Flag: --crop_mode -# -# See this wiki page to learn about the fit and fill options. -# https://github.com/dylanaraps/neofetch/wiki/What-is-Waifu-Crop%3F -crop_mode="normal" - -# Crop offset -# Note: Only affects 'normal' crop mode. -# -# Default: 'center' -# Values: 'northwest', 'north', 'northeast', 'west', 'center' -# 'east', 'southwest', 'south', 'southeast' -# Flag: --crop_offset -crop_offset="center" - -# Image size -# The image is half the terminal width by default. -# -# Default: 'auto' -# Values: 'auto', '00px', '00%', 'none' -# Flags: --image_size -# --size -image_size="auto" - -# Gap between image and text -# -# Default: '3' -# Values: 'num', '-num' -# Flag: --gap -gap=3 - -# Image offsets -# Only works with the w3m backend. -# -# Default: '0' -# Values: 'px' -# Flags: --xoffset -# --yoffset -yoffset=0 -xoffset=0 - -# Image background color -# Only works with the w3m backend. -# -# Default: '' -# Values: 'color', 'blue' -# Flag: --bg_color -background_color= - - -# Scrot Options - - -# Whether or not to always take a screenshot -# You can manually take a screenshot with "--scrot" or "-s" -# -# Default: 'off' -# Values: 'on', 'off' -# Flags: --scrot -# -s -scrot="off" - -# Screenshot Program -# Neofetch will automatically use whatever screenshot tool -# is installed on your system. -# -# If 'neofetch -v' says that it couldn't find a screenshot -# tool or you're using a custom tool then you can change -# the option below to a custom command. -# -# Default: 'auto' -# Values: 'auto' 'cmd -flags' -# Flag: --scrot_cmd -scrot_cmd="auto" - -# Screenshot Filename -# What to name the screenshots -# -# Default: 'neofetch-$(date +%F-%I-%M-%S-${RANDOM}).png' -# Values: 'string' -# Flag: --scrot_name -scrot_name="neofetch-$(date +%F-%I-%M-%S-${RANDOM}).png" - -# Image upload host -# Where to upload the image. -# -# Default: 'teknik' -# Values: 'imgur', 'teknik' -# Flag: --image_host -# -# NOTE: If you'd like another image host to be added to Neofetch. -# Open an issue on github. -image_host="teknik" - - -# Misc Options - -# Stdout mode -# Turn off all colors and disables image backend (ASCII/Image). -# Useful for piping into another command. -# Default: 'off' -# Values: 'on', 'off' -stdout="off" - -# Config version. -# -# NOTE: Don't change this value, neofetch reads this to determine -# how to handle backwards compatibility. -config_version="3.4.0" diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml deleted file mode 100644 index 0fdd8d2f7..000000000 --- a/.github/FUNDING.yml +++ /dev/null @@ -1,8 +0,0 @@ -# These are supported funding model platforms - -github: [baalajimaestro, raphielscape, mryacha] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] -patreon: # Replace with a single Patreon username -open_collective: # Replace with a single Open Collective username -ko_fi: # Replace with a single Ko-fi username -tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel -custom: # Replace with a single custom sponsorship URL diff --git a/Aptfile b/Aptfile deleted file mode 100644 index 79d5a38e5..000000000 --- a/Aptfile +++ /dev/null @@ -1,3 +0,0 @@ -neofetch -chromium-chromedriver -chromium-browser diff --git a/Dockerfile b/Dockerfile index 3c2d54247..eeab7209c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -49,7 +49,9 @@ RUN apk add --no-cache --update \ ffmpeg \ sqlite-dev \ sudo \ - zlib-dev + zlib-dev \ + jpeg-dev \ + python-dev RUN python3 -m ensurepip \ @@ -71,13 +73,6 @@ WORKDIR /root/userbot/ # COPY ./sample_config.env ./userbot.session* ./config.env* /root/userbot/ -# -# Clone helper scripts -# -RUN curl -s https://raw.githubusercontent.com/yshalsager/megadown/master/megadown -o /root/userbot/bin/megadown && sudo chmod a+x /root/userbot/bin/megadown -RUN curl -s https://raw.githubusercontent.com/yshalsager/cmrudl.py/master/cmrudl.py -o /root/userbot/bin/cmrudl && sudo chmod a+x /root/userbot/bin/cmrudl -ENV PATH="/root/userbot/bin:$PATH" - # # Install requirements # diff --git a/Procfile b/Procfile deleted file mode 100644 index 0dae77512..000000000 --- a/Procfile +++ /dev/null @@ -1 +0,0 @@ -worker: python3 -m userbot diff --git a/app.json b/app.json index 34b289d9e..19755a420 100644 --- a/app.json +++ b/app.json @@ -54,7 +54,7 @@ "value": "False" }, "BOTLOG_CHATID": { - "description": "ChatID of the Log group. Set it to '0' if BOTLOG = False", + "description": "ChatID of the Log group. Set it to '0' if BOTLOG = False and/or if LOGSPAMMER = False.", "value": "0" }, "CONSOLE_LOGGER_VERBOSE": { @@ -119,6 +119,7 @@ }, "DEFAULT_BIO": { "description": "Default profile bio.", + "value": "[PM = Report Spam] I ❤ ️@PaperplaneExtended", "required": false }, "ALIVE_NAME": { @@ -128,6 +129,18 @@ "G_DRIVE_CLIENT_SECRET": { "description": "Enter Your Client Secret for Google Drive.", "required": false + }, + "G_DRIVE_AUTH_TOKEN_DATA": { + "description": "Enter the Google Drive authentication data, as a JSON structure.", + "required": false + }, + "WEATHER_DEFCITY": { + "description": "Set the default city for the userbot's weather module.", + "required": false + }, + "LOGSPAMMER": { + "description": "Set this to True in case you want the error logs to be stored in the userbot log group, instead of spitting out the file in the current chat, requires a valid BOTLOG_CHATID to be set.", + "value": "True" } }, "addons": [ diff --git a/modules b/modules deleted file mode 100644 index fbb0749a0..000000000 --- a/modules +++ /dev/null @@ -1,45 +0,0 @@ -import os -import subprocess -import platform -from userbot import SUDO - -def _start_instalation(): - install_with = None - package_managers = ["pacman", "apt-get", "yum", "brew", "yaourt", "dnf", "homebrew", "eopkg", "snap"] - if "linux" in str(platform.system()).lower(): - for manager in package_managers: - try: - subprocess.check_call(f"which {manager}", shell=True, stderr=subprocess.STDOUT) - install_package(manager) - return - except: - continue - - - -def install_package(package_manager): - packages = [] - to_install = [] - with open("Aptfile") as file: - for line in file: - packages.append(line) - - for package in packages: - try: - subprocess.check_call(f"which {package}", shell=True, stderr=subprocess.STDOUT) - except: - to_install.append(package) - - if to_install: - if SUDO: - subprocess.Popen(f"echo {str(SUDO)} | sudo -S {str(package_manager)}" + - f" install -y {' '.join(to_install)}", shell=True) - else: - subprocess.Popen(f"{str(package_manager)} install -y {' '.join(to_install)}", - shell=True) - -try: - if not 'heroku' in os.environ['PATH']: - _start_instalation() -except: - _start_instalation() diff --git a/requirements.txt b/requirements.txt index 555657154..635c42892 100644 --- a/requirements.txt +++ b/requirements.txt @@ -33,7 +33,7 @@ requests>=2.18.4 search-engine-parser>=0.4.2 speedtest-cli>=2.0.2 sqlalchemy>=1.2 -telethon>=1.10.3 +telethon>=1.10.6 telethon-session-sqlalchemy>=0.2.6 urbandict>=0.5 wikipedia>=1.4.0 diff --git a/runtime.txt b/runtime.txt deleted file mode 100644 index 6f651a3b1..000000000 --- a/runtime.txt +++ /dev/null @@ -1 +0,0 @@ -python-3.7.3 diff --git a/sample_config.env b/sample_config.env index 0e89b4d10..78c16fae1 100644 --- a/sample_config.env +++ b/sample_config.env @@ -1,99 +1,72 @@ # Remove this line first before doing anything ___________PLOX_______REMOVE_____THIS_____LINE__________=True -# -# Get from https://my.telegram.org/ -# +# Get these from https://my.telegram.org/ API_KEY = "YOUR API KEY" API_HASH = "YOUR API HASH" -# # OpenWeather Map API Key for .weather command # Get from https://openweathermap.org/ -# OPEN_WEATHER_MAP_APPID = "" +WEATHER_DEFCITY = "" -# # Location of ChromeDriver for .carbon module -# Default for Heroku Slugs : "/app/.chromedriver/bin/chromedriver" -# +# Example for Linux Machines : "/usr/bin/chromedriver" CHROME_DRIVER = "" -# # Get this value by running python3 string_session.py locally -# STRING_SESSION = "" -# # Headless GoogleChrome location for .carbon module -# Default for Heroku Slugs : "/app/.apt/usr/bin/google-chrome" -# +# Example for Linux Machines : "/usr/bin/chromium-browser" GOOGLE_CHROME_BIN = "" -# # OCR Space API Key for .ocr command # Get from https://ocr.space/ocrapi -# OCR_SPACE_API_KEY = "" -# # remove.bg API Key for .rbg command # Get from https://www.remove.bg/api -# REM_BG_API_KEY = "" -# # ChatID for the Log group # Add a Hypen or a Negative Sign before ID # This is a integer, Please don't use Strings -# -BOTLOG_CHATID = # Chat ID should be integer. +BOTLOG_CHATID = # this is an integer, please don't use quotes. -# # Incase you want to turn off logging, put this to false -# BOTLOG = True -# +# Set this to True if you want the error logs to be stored in +# the userbot log, rather than spamming other chats with it. +# Note that this requires a valid BOTLOG_CHATID to be set. +LOGSPAMMER = True + # If you need Verbosity on the Logging -# CONSOLE_LOGGER_VERBOSE = False -# # PM Auto-Ban Feature Switch -# PM_AUTO_BAN = False -# # Custom Default name for .alive -# ALIVE_NAME = None -# # Your Database URL # Example: 'postgres://userbot:userbot@localhost:5432/userbot' -# DATABASE_URL = "" -# # YouTube Data API Key for .yt command # Get from https://console.cloud.google.com -# YOUTUBE_API_KEY = "" -# # Country and Time Zone setup for # .time and .date modules -# COUNTRY = "" -TZ_NUMBER = # this is an integer. +TZ_NUMBER = # this is an integer, please don't use quotes. -# # Google Drive Credentials # for .gdrive module. -# # Get from https://console.cloud.google.com -# G_DRIVE_CLIENT_ID = "" G_DRIVE_CLIENT_SECRET = "" G_DRIVE_AUTH_TOKEN_DATA = "" @@ -109,12 +82,11 @@ LASTFM_PASSWORD = "Your last.fm password" # Bot will add before song name. For last.fm module. # Example: GitHub: MacTavishAO : Skillet - Feel Invincible BIO_PREFIX = "" + # default bio message DEFAULT_BIO = "" -# # Report or kick some known spammer bots after # they joins -# ANTI_SPAMBOT = False ANTI_SPAMBOT_SHOUT = False diff --git a/userbot/__init__.py b/userbot/__init__.py index 3ed93385c..ad293982c 100644 --- a/userbot/__init__.py +++ b/userbot/__init__.py @@ -11,7 +11,7 @@ from logging import basicConfig, getLogger, INFO, DEBUG from distutils.util import strtobool as sb -import pylast +from pylast import LastFMNetwork, md5 from pySmartDL import SmartDL from dotenv import load_dotenv from requests import get @@ -35,7 +35,7 @@ if version_info[0] < 3 or version_info[1] < 6: LOGS.info("You MUST have a python version of at least 3.6." - "Multiple features depend on this. Bot quitting.") + "Multiple features depend on this. Bot quitting.") quit(1) # Check if the config was edited by using the already used variable. @@ -56,11 +56,12 @@ # Userbot Session String STRING_SESSION = os.environ.get("STRING_SESSION", None) -# Logging channel/group configuration. +# Logging channel/group ID configuration. BOTLOG_CHATID = int(os.environ.get("BOTLOG_CHATID", None)) # Userbot logging feature switch. BOTLOG = sb(os.environ.get("BOTLOG", "False")) +LOGSPAMMER = sb(os.environ.get("LOGSPAMMER", "False")) # Bleep Blop, this is a bot ;) PM_AUTO_BAN = sb(os.environ.get("PM_AUTO_BAN", "False")) @@ -83,10 +84,10 @@ # OpenWeatherMap API Key OPEN_WEATHER_MAP_APPID = os.environ.get("OPEN_WEATHER_MAP_APPID", None) +WEATHER_DEFCITY = os.environ.get("WEATHER_DEFCITY", None) # Anti Spambot Config ANTI_SPAMBOT = sb(os.environ.get("ANTI_SPAMBOT", "False")) - ANTI_SPAMBOT_SHOUT = sb(os.environ.get("ANTI_SPAMBOT_SHOUT", "False")) # Youtube API key @@ -97,7 +98,6 @@ # Time & Date - Country and Time Zone COUNTRY = str(os.environ.get("COUNTRY", "")) - TZ_NUMBER = int(os.environ.get("TZ_NUMBER", 1)) # Clean Welcome @@ -111,12 +111,12 @@ LASTFM_SECRET = os.environ.get("LASTFM_SECRET", None) LASTFM_USERNAME = os.environ.get("LASTFM_USERNAME", None) LASTFM_PASSWORD_PLAIN = os.environ.get("LASTFM_PASSWORD", None) -LASTFM_PASS = pylast.md5(LASTFM_PASSWORD_PLAIN) -if not LASTFM_USERNAME == "None": - lastfm = pylast.LastFMNetwork(api_key=LASTFM_API, - api_secret=LASTFM_SECRET, - username=LASTFM_USERNAME, - password_hash=LASTFM_PASS) +LASTFM_PASS = md5(LASTFM_PASSWORD_PLAIN) +if LASTFM_API and LASTFM_SECRET and LASTFM_USERNAME and LASTFM_PASS: + lastfm = LastFMNetwork(api_key=LASTFM_API, + api_secret=LASTFM_SECRET, + username=LASTFM_USERNAME, + password_hash=LASTFM_PASS) else: lastfm = None @@ -155,12 +155,21 @@ async def check_botlog_chatid(): - if not BOTLOG_CHATID: + if not BOTLOG_CHATID and LOGSPAMMER: LOGS.info( - "You must set up the BOTLOG_CHATID variable in the config.env or environment variables, " - "many critical features depend on it. KTHXBye.") + "You must set up the BOTLOG_CHATID variable in the config.env or environment variables, for the private error log storage to work." + ) quit(1) + elif not BOTLOG_CHATID and BOTLOG: + LOGS.info( + "You must set up the BOTLOG_CHATID variable in the config.env or environment variables, for the userbot logging feature to work." + ) + quit(1) + + elif not BOTLOG or not LOGSPAMMER: + return + entity = await bot.get_entity(BOTLOG_CHATID) if entity.default_banned_rights.send_messages: LOGS.info( @@ -168,6 +177,7 @@ async def check_botlog_chatid(): "group. Check if you typed the Chat ID correctly.") quit(1) + with bot: try: bot.loop.run_until_complete(check_botlog_chatid()) diff --git a/userbot/events.py b/userbot/events.py index cf4f559c9..42a9cafb3 100644 --- a/userbot/events.py +++ b/userbot/events.py @@ -6,18 +6,16 @@ """ Userbot module for managing events. One of the main components of the userbot. """ -from telethon import events - -from asyncio import subprocess as asyncsub -from asyncio import create_subprocess_shell as asyncsubshell - import sys +from asyncio import create_subprocess_shell as asyncsubshell +from asyncio import subprocess as asyncsub from os import remove +from time import gmtime, strftime +from traceback import format_exc -from userbot import bot, BOTLOG_CHATID +from telethon import events -from traceback import format_exc -from time import gmtime, strftime +from userbot import bot, BOTLOG_CHATID, LOGSPAMMER def register(**args): @@ -25,8 +23,10 @@ def register(**args): pattern = args.get('pattern', None) disable_edited = args.get('disable_edited', False) ignore_unsafe = args.get('ignore_unsafe', False) - forwards = args.get('forwards', False) unsafe_pattern = r'^[^/!#@\$A-Za-z]' + groups_only = args.get('groups_only', False) + trigger_on_fwd = args.get('trigger_on_fwd', False) + disable_errors = args.get('disable_errors', False) if pattern is not None and not pattern.startswith('(?i)'): args['pattern'] = '(?i)' + pattern @@ -37,77 +37,112 @@ def register(**args): if "ignore_unsafe" in args: del args['ignore_unsafe'] - if "forwards" in args: - del args['forwards'] + if "groups_only" in args: + del args['groups_only'] + + if "disable_errors" in args: + del args['disable_errors'] + + if "trigger_on_fwd" in args: + del args['trigger_on_fwd'] if pattern: if not ignore_unsafe: args['pattern'] = pattern.replace('^.', unsafe_pattern, 1) def decorator(func): + async def wrapper(check): + if not LOGSPAMMER: + send_to = check.chat_id + else: + send_to = BOTLOG_CHATID + + if not trigger_on_fwd and check.fwd_from: + return + + if groups_only and not check.is_group: + await check.respond("`I don't think this is a group.`") + return + + try: + await func(check) + + # Thanks to @kandnub for this HACK. + # Raise StopPropagation to Raise StopPropagation + # This needed for AFK to working properly + + except events.StopPropagation: + raise events.StopPropagation + # This is a gay exception and must be passed out. So that it doesnt spam chats + except KeyboardInterrupt: + pass + except BaseException: + + # Check if we have to disable it. + # If not silence the log spam on the console, + # with a dumb except. + + if not disable_errors: + date = strftime("%Y-%m-%d %H:%M:%S", gmtime()) + + text = "**USERBOT ERROR REPORT**\n" + link = "[PaperplaneExtended Support Chat](https://t.me/PaperplaneExtendedSupport)" + text += "If you want to, you can report it" + text += f"- just forward this message to {link}.\n" + text += "Nothing is logged except the fact of error and date\n" + + ftext = "========== DISCLAIMER ==========" + ftext += "\nThis file uploaded ONLY here," + ftext += "\nwe logged only fact of error and date," + ftext += "\nwe respect your privacy," + ftext += "\nyou may not report this error if you've" + ftext += "\nany confidential data here, no one will see your data\n" + ftext += "================================\n\n" + ftext += "--------BEGIN USERBOT TRACEBACK LOG--------\n" + ftext += "\nDate: " + date + ftext += "\nChat ID: " + str(check.chat_id) + ftext += "\nSender ID: " + str(check.sender_id) + ftext += "\n\nEvent Trigger:\n" + ftext += str(check.text) + ftext += "\n\nTraceback info:\n" + ftext += str(format_exc()) + ftext += "\n\nError text:\n" + ftext += str(sys.exc_info()[1]) + ftext += "\n\n--------END USERBOT TRACEBACK LOG--------" + + command = "git log --pretty=format:\"%an: %s\" -10" + + ftext += "\n\n\nLast 10 commits:\n" + + process = await asyncsubshell(command, + stdout=asyncsub.PIPE, + stderr=asyncsub.PIPE) + stdout, stderr = await process.communicate() + result = str(stdout.decode().strip()) \ + + str(stderr.decode().strip()) + + ftext += result + + file = open("error.log", "w+") + file.write(ftext) + file.close() + + if LOGSPAMMER: + await check.client.respond( + "`Sorry, my userbot has crashed.\ + \nThe error logs are stored in the userbot's log chat.`" + ) + + await check.client.send_file(send_to, + "error.log", + caption=text) + remove("error.log") + else: + pass + if not disable_edited: - bot.add_event_handler(func, events.MessageEdited(**args)) - bot.add_event_handler(func, events.NewMessage(**args)) - return func + bot.add_event_handler(wrapper, events.MessageEdited(**args)) + bot.add_event_handler(wrapper, events.NewMessage(**args)) + return wrapper return decorator - - -def errors_handler(func): - async def wrapper(errors): - try: - await func(errors) - except BaseException: - date = strftime("%Y-%m-%d %H:%M:%S", gmtime()) - - text = "**USERBOT CRASH REPORT**\n" - link = "[PaperplaneExtended Support Chat](https://t.me/PaperplaneExtendedSupport)" - text += "If you wanna you can report it" - text += f"- just forward this message to {link}.\n" - text += "Nothing is logged except the fact of error and date\n" - - ftext = "========== DISCLAIMER ==========" - ftext += "\nThis file uploaded ONLY here," - ftext += "\nwe logged only fact of error and date," - ftext += "\nwe respect your privacy," - ftext += "\nyou may not report this error if you've" - ftext += "\nany confidential data here, no one will see your data\n" - ftext += "================================\n\n" - ftext += "--------BEGIN USERBOT TRACEBACK LOG--------" - ftext += "\nDate: " + date - ftext += "\nGroup ID: " + str(errors.chat_id) - ftext += "\nSender ID: " + str(errors.sender_id) - ftext += "\n\nEvent Trigger:\n" - ftext += str(errors.text) - ftext += "\n\nTraceback info:\n" - ftext += str(format_exc()) - ftext += "\n\nError text:\n" - ftext += str(sys.exc_info()[1]) - ftext += "\n\n--------END USERBOT TRACEBACK LOG--------" - - command = "git log --pretty=format:\"%an: %s\" -5" - - ftext += "\n\n\nLast 5 commits:\n" - - process = await asyncsubshell(command, - stdout=asyncsub.PIPE, - stderr=asyncsub.PIPE) - stdout, stderr = await process.communicate() - result = str(stdout.decode().strip()) \ - + str(stderr.decode().strip()) - - ftext += result - - file = open("error.log", "w+") - file.write(ftext) - file.close() - - await errors.client.send_file( - BOTLOG_CHATID, - "error.log", - caption=text, - ) - remove("error.log") - return - - return wrapper diff --git a/userbot/modules/admin.py b/userbot/modules/admin.py index 282feed53..b5a1717b3 100644 --- a/userbot/modules/admin.py +++ b/userbot/modules/admin.py @@ -18,12 +18,13 @@ EditBannedRequest, EditPhotoRequest) from telethon.tl.functions.messages import UpdatePinnedMessageRequest -from telethon.tl.types import (ChannelParticipantsAdmins, ChatAdminRights, - ChatBannedRights, MessageEntityMentionName, - MessageMediaPhoto) +from telethon.tl.types import (PeerChannel, ChannelParticipantsAdmins, + ChatAdminRights, ChatBannedRights, + MessageEntityMentionName, MessageMediaPhoto, + ChannelParticipantsBots) from userbot import BOTLOG, BOTLOG_CHATID, CMD_HELP, bot -from userbot.events import register, errors_handler +from userbot.events import register # =================== CONSTANT =================== PP_TOO_SMOL = "`The image is too small`" @@ -67,8 +68,7 @@ # ================================================ -@register(outgoing=True, pattern="^.setgpic$") -@errors_handler +@register(outgoing=True, pattern="^.setgpic$", groups_only=True) async def set_group_photo(gpic): """ For .setgpic command, changes the picture of a group """ if not gpic.is_group: @@ -105,8 +105,7 @@ async def set_group_photo(gpic): await gpic.edit(PP_ERROR) -@register(outgoing=True, pattern="^.promote(?: |$)(.*)") -@errors_handler +@register(outgoing=True, pattern="^.promote(?: |$)(.*)", groups_only=True) async def promote(promt): """ For .promote command, promotes the replied/tagged person """ # Get targeted chat @@ -130,7 +129,8 @@ async def promote(promt): await promt.edit("`Promoting...`") user, rank = await get_user_from_event(promt) if not rank: - rank = "admeme" # Just in case. + # Just in case. + rank = "admeme" if user: pass else: @@ -156,8 +156,7 @@ async def promote(promt): f"CHAT: {promt.chat.title}(`{promt.chat_id}`)") -@register(outgoing=True, pattern="^.demote(?: |$)(.*)") -@errors_handler +@register(outgoing=True, pattern="^.demote(?: |$)(.*)", groups_only=True) async def demote(dmod): """ For .demote command, demotes the replied/tagged person """ # Admin right check @@ -206,8 +205,7 @@ async def demote(dmod): f"CHAT: {dmod.chat.title}(`{dmod.chat_id}`)") -@register(outgoing=True, pattern="^.ban(?: |$)(.*)") -@errors_handler +@register(outgoing=True, pattern="^.ban(?: |$)(.*)", groups_only=True) async def ban(bon): """ For .ban command, bans the replied/tagged person """ # Here laying the sanity check @@ -248,9 +246,12 @@ async def ban(bon): # is done gracefully # Shout out the ID, so that fedadmins can fban later if reason: - await bon.edit(f"`{str(user.id)}` was banned !!\nReason: {reason}") + await bon.edit(f"{user.first_name} was banned !!\ + \nID: `{str(user.id)}`\ + \nReason: {reason}") else: - await bon.edit(f"`{str(user.id)}` was banned !!") + await bon.edit(f"{user.first_name} was banned !!\ + \nID: `{str(user.id)}`") # Announce to the logging group if we have banned the person # successfully! if BOTLOG: @@ -260,8 +261,7 @@ async def ban(bon): f"CHAT: {bon.chat.title}(`{bon.chat_id}`)") -@register(outgoing=True, pattern="^.unban(?: |$)(.*)") -@errors_handler +@register(outgoing=True, pattern="^.unban(?: |$)(.*)", groups_only=True) async def nothanos(unbon): """ For .unban command, unbans the replied/tagged person """ # Here laying the sanity check @@ -298,8 +298,7 @@ async def nothanos(unbon): await unbon.edit("`Uh oh my unban logic broke!`") -@register(outgoing=True, pattern="^.mute(?: |$)(.*)") -@errors_handler +@register(outgoing=True, pattern="^.mute(?: |$)(.*)", groups_only=True) async def spider(spdr): """ This function is basically muting peeps @@ -359,8 +358,7 @@ async def spider(spdr): return await spdr.edit("`Uh oh my mute logic broke!`") -@register(outgoing=True, pattern="^.unmute(?: |$)(.*)") -@errors_handler +@register(outgoing=True, pattern="^.unmute(?: |$)(.*)", groups_only=True) async def unmoot(unmot): """ For .unmute command, unmute the replied/tagged person """ # Admin or creator check @@ -408,8 +406,7 @@ async def unmoot(unmot): f"CHAT: {unmot.chat.title}(`{unmot.chat_id}`)") -@register(incoming=True) -@errors_handler +@register(incoming=True, disable_edited=True) async def muter(moot): """ Used for deleting the messages of muted people """ try: @@ -440,8 +437,7 @@ async def muter(moot): await moot.delete() -@register(outgoing=True, pattern="^.ungmute(?: |$)(.*)") -@errors_handler +@register(outgoing=True, pattern="^.ungmute(?: |$)(.*)", groups_only=True) async def ungmoot(un_gmute): """ For .ungmute command, ungmutes the target in the userbot """ # Admin or creator check @@ -484,8 +480,7 @@ async def ungmoot(un_gmute): f"CHAT: {un_gmute.chat.title}(`{un_gmute.chat_id}`)") -@register(outgoing=True, pattern="^.gmute(?: |$)(.*)") -@errors_handler +@register(outgoing=True, pattern="^.gmute(?: |$)(.*)", groups_only=True) async def gspider(gspdr): """ For .gmute command, globally mutes the replied/tagged person """ # Admin or creator check @@ -529,14 +524,13 @@ async def gspider(gspdr): f"CHAT: {gspdr.chat.title}(`{gspdr.chat_id}`)") -@register(outgoing=True, pattern="^.delusers(?: |$)(.*)") -@errors_handler +@register(outgoing=True, pattern="^.zombies(?: |$)(.*)", groups_only=True) async def rm_deletedacc(show): """ For .delusers command, list all the ghost/deleted accounts in a chat. """ if not show.is_group: await show.edit("`I don't think this is a group.`") return - con = show.pattern_match.group(1) + con = show.pattern_match.group(1).lower() del_u = 0 del_status = "`No deleted accounts found, Group is cleaned as Hell`" @@ -601,8 +595,7 @@ async def rm_deletedacc(show): \nCHAT: {show.chat.title}(`{show.chat_id}`)") -@register(outgoing=True, pattern="^.admins$") -@errors_handler +@register(outgoing=True, pattern="^.admins$", groups_only=True) async def get_admin(show): """ For .admins command, list all of the admins of the chat. """ info = await show.client.get_entity(show.chat_id) @@ -619,11 +612,62 @@ async def get_admin(show): mentions += f"\nDeleted Account {user.id}" except ChatAdminRequiredError as err: mentions += " " + str(err) + "\n" - await show.edit(mentions, parse_mode="html") + try: + await show.edit(mentions, parse_mode="html") + except MessageTooLongError: + await show.edit( + "Damn, too many admins here. Uploading admin list as file.") + file = open("adminlist.txt", "w+") + file.write(mentions) + file.close() + await show.client.send_file( + show.chat_id, + "adminlist.txt", + caption='Admins in {}'.format(title), + reply_to=show.id, + ) + remove("adminlist.txt") + + +@register(outgoing=True, pattern="^.bots$", groups_only=True) +async def get_bots(show): + """ For .bots command, list all of the bots of the chat. """ + info = await show.client.get_entity(show.chat_id) + title = info.title if info.title else "this chat" + mentions = f'Bots in {title}:\n' + try: + if isinstance(message.to_id, PeerChat): + await show.edit("`I heard that only Supergroups can have bots.`") + return + else: + async for user in show.client.iter_participants( + show.chat_id, filter=ChannelParticipantsBots): + if not user.deleted: + link = f"{user.first_name}" + userid = f"{user.id}" + mentions += f"\n{link} {userid}" + else: + mentions += f"\nDeleted Bot {user.id}" + except ChatAdminRequiredError as err: + mentions += " " + str(err) + "\n" + try: + await show.edit(mentions, parse_mode="html") + except MessageTooLongError: + await show.edit( + "Damn, too many bots here. Uploading bots list as file.") + file = open("botlist.txt", "w+") + file.write(mentions) + file.close() + await show.client.send_file( + show.chat_id, + "botlist.txt", + caption='Bots in {}'.format(title), + reply_to=show.id, + ) + remove("botlist.txt") -@register(outgoing=True, pattern="^.pin(?: |$)(.*)") -@errors_handler +@register(outgoing=True, pattern="^.pin(?: |$)(.*)", groups_only=True) async def pin(msg): """ For .pin command, pins the replied/tagged message on the top the chat. """ # Admin or creator check @@ -668,8 +712,7 @@ async def pin(msg): f"LOUD: {not is_silent}") -@register(outgoing=True, pattern="^.kick(?: |$)(.*)") -@errors_handler +@register(outgoing=True, pattern="^.kick(?: |$)(.*)", groups_only=True) async def kick(usr): """ For .kick command, kicks the replied/tagged person from the group. """ # Admin or creator check @@ -693,7 +736,7 @@ async def kick(usr): await usr.client.kick_participant(usr.chat_id, user.id) await sleep(.5) except Exception as e: - await usr.edit(NO_PERM + f"\n{str(e)}") + await usr.edit(NO_PERM) return if reason: @@ -711,8 +754,7 @@ async def kick(usr): f"CHAT: {usr.chat.title}(`{usr.chat_id}`)\n") -@register(outgoing=True, pattern="^.users ?(.*)") -@errors_handler +@register(outgoing=True, pattern="^.users ?(.*)", groups_only=True) async def get_users(show): """ For .users command, list all of the users in a chat. """ info = await show.client.get_entity(show.chat_id) @@ -754,13 +796,13 @@ async def get_users(show): async def get_user_from_event(event): """ Get the user from argument or replied message. """ - args = event.pattern_match.group(1).split(' ', 1) + args = event.pattern_match.group(1).split(':', 1) extra = None if event.reply_to_msg_id and not len(args) == 2: previous_message = await event.get_reply_message() user_obj = await event.client.get_entity(previous_message.from_id) extra = event.pattern_match.group(1) - elif args: + elif len(args[0]) > 0: user = args[0] if len(args) == 2: extra = args[1] @@ -804,28 +846,30 @@ async def get_user_from_id(user, event): CMD_HELP.update({ "admin": - ".promote \ + ".promote : (or) reply to a message with .promote \ \nUsage: Provides admin rights to the person in the chat.\ -\n\n.demote \ +\n\n.demote (or) reply to a message with .demote\ \nUsage: Revokes the person's admin permissions in the chat.\ -\n\n.ban \ +\n\n.ban : (or) reply to a message with .ban \ \nUsage: Bans the person off your chat.\ -\n\n.unban \ +\n\n.unban (or) reply to a message with .unban\ \nUsage: Removes the ban from the person in the chat.\ -\n\n.mute \ +\n\n.mute : reply to a message with .mute \ \nUsage: Mutes the person in the chat, works on admins too.\ -\n\n.unmute \ +\n\n.unmute (or) reply to a message with .unmute\ \nUsage: Removes the person from the muted list.\ -\n\n.gmute \ +\n\n.gmute : (or) reply to a message with .gmute \ \nUsage: Mutes the person in all groups you have in common with them.\ -\n\n.ungmute \ -\nUsage: Reply someone's message with .ungmute to remove them from the gmuted list.\ +\n\n.ungmute (or) reply to a message with .ungmute\ +\nUsage: Removes the person from the global mute list.\ \n\n.delusers\ \nUsage: Searches for deleted accounts in a group. Use .delusers clean to remove deleted accounts from the group.\ \n\n.admins\ \nUsage: Retrieves a list of admins in the chat.\ -\n\n.users or .users \ +\n\n.bots\ +\nUsage: Retrieves a list of bots in the chat.\ +\n\n.users or .users \ \nUsage: Retrieves all (or queried) users in the chat.\ -\n\n.setgppic \ +\n\n.setgpic \ \nUsage: Changes the group's display picture." }) diff --git a/userbot/modules/afk.py b/userbot/modules/afk.py index 4d8e48aae..5e155beee 100644 --- a/userbot/modules/afk.py +++ b/userbot/modules/afk.py @@ -12,7 +12,7 @@ from userbot import (AFKREASON, COUNT_MSG, CMD_HELP, ISAFK, BOTLOG, BOTLOG_CHATID, USERS, PM_AUTO_BAN) -from userbot.events import register, errors_handler +from userbot.events import register # ========================= CONSTANTS ============================ AFKSTR = [ @@ -44,7 +44,6 @@ @register(incoming=True, disable_edited=True) -@errors_handler async def mention_afk(mention): """ This function takes care of notifying the people who mention you that you are AFK.""" global COUNT_MSG @@ -74,8 +73,7 @@ async def mention_afk(mention): COUNT_MSG = COUNT_MSG + 1 -@register(incoming=True) -@errors_handler +@register(incoming=True, disable_errors=True) async def afk_on_pm(sender): """ Function which informs people that you are AFK in PM """ global ISAFK @@ -94,7 +92,8 @@ async def afk_on_pm(sender): if apprv and ISAFK: if sender.sender_id not in USERS: if AFKREASON: - await sender.reply(f"I'm AFK: `{AFKREASON}`") + await sender.reply(f"I'm AFK right now.\ + \nReason: `{AFKREASON}`") else: await sender.reply(str(choice(AFKSTR))) USERS.update({sender.sender_id: 1}) @@ -102,7 +101,8 @@ async def afk_on_pm(sender): elif apprv and sender.sender_id in USERS: if USERS[sender.sender_id] % randint(2, 4) == 0: if AFKREASON: - await sender.reply(f"I'm still AFK: `{AFKREASON}`") + await sender.reply(f"I'm still AFK.\ + \nReason: `{AFKREASON}`") else: await sender.reply(str(choice(AFKSTR))) USERS[sender.sender_id] = USERS[sender.sender_id] + 1 @@ -112,7 +112,7 @@ async def afk_on_pm(sender): COUNT_MSG = COUNT_MSG + 1 -@register(outgoing=True, pattern="^.afk(?: |$)(.*)") +@register(outgoing=True, pattern="^.afk(?: |$)(.*)", disable_errors=True) async def set_afk(afk_e): """ For .afk command, allows you to inform people that you are afk when they message you """ message = afk_e.text @@ -132,7 +132,6 @@ async def set_afk(afk_e): @register(outgoing=True) -@errors_handler async def type_afk_is_not_true(notafk): """ This sets your status as not afk automatically when you write something while being afk """ global ISAFK diff --git a/userbot/modules/android.py b/userbot/modules/android.py index d62e6fbc1..8d3e432b4 100644 --- a/userbot/modules/android.py +++ b/userbot/modules/android.py @@ -10,7 +10,7 @@ from bs4 import BeautifulSoup from userbot import CMD_HELP -from userbot.events import register, errors_handler +from userbot.events import register GITHUB = 'https://github.com' DEVICES_DATA = 'https://raw.githubusercontent.com/androidtrackers/' \ @@ -39,7 +39,6 @@ async def magisk(request): await request.edit(releases) @register(outgoing=True, pattern=r"^.device(?: |$)(\S*)") -@errors_handler async def device_info(request): """ get android device basic info from its codename """ textx = await request.get_reply_message() @@ -71,7 +70,6 @@ async def device_info(request): @register(outgoing=True, pattern=r"^.codename(?: |)([\S]*)(?: |)([\s\S]*)") -@errors_handler async def codename_info(request): """ search for android codename """ textx = await request.get_reply_message() @@ -107,7 +105,6 @@ async def codename_info(request): @register(outgoing=True, pattern=r"^.specs(?: |)([\S]*)(?: |)([\s\S]*)") -@errors_handler async def devices_specifications(request): """ Mobile devices specifications """ textx = await request.get_reply_message() @@ -161,7 +158,6 @@ async def devices_specifications(request): @register(outgoing=True, pattern=r"^.twrp(?: |$)(\S*)") -@errors_handler async def twrp(request): """ get android device twrp """ textx = await request.get_reply_message() diff --git a/userbot/modules/anti_spambot.py b/userbot/modules/anti_spambot.py index af6c7b9b1..6e084aa55 100644 --- a/userbot/modules/anti_spambot.py +++ b/userbot/modules/anti_spambot.py @@ -12,11 +12,9 @@ from telethon.tl.types import ChannelParticipantsAdmins, Message from userbot import BOTLOG, BOTLOG_CHATID, CMD_HELP, ANTI_SPAMBOT, ANTI_SPAMBOT_SHOUT, bot -from userbot.events import errors_handler @bot.on(ChatAction) -@errors_handler async def ANTI_SPAMBOT(welcm): try: ''' Ban a recently joined user if it diff --git a/userbot/modules/aria.py b/userbot/modules/aria.py index c31ef8cf0..cac30cec3 100644 --- a/userbot/modules/aria.py +++ b/userbot/modules/aria.py @@ -1,22 +1,34 @@ -#This Lit Module By:- @Zero_cool7870 Sar -#Special thanks to @spechide who modified this aria +# Copyright (C) 2019 The Raphielscape Company LLC. +# +# Licensed under the Raphielscape Public License, Version 1.c (the "License"); +# you may not use this file except in compliance with the License. import aria2p from asyncio import sleep from os import system from userbot import LOGS, CMD_HELP -from userbot.events import register, errors_handler +from userbot.events import register +from requests import get -cmd = "aria2c \ +# Get best trackers for improved download speeds, thanks K-E-N-W-A-Y. +trackers_list = get( + 'https://raw.githubusercontent.com/ngosang/trackerslist/master/trackers_best.txt' +).text.replace('\n\n', ',') +trackers = f"[{trackers_list}]" + +cmd = f"aria2c \ --enable-rpc \ --rpc-listen-all=false \ --rpc-listen-port 6800 \ --max-connection-per-server=10 \ --rpc-max-request-size=1024M \ --seed-time=0.01 \ +--max-upload-limit=5K \ +--max-concurrent-downloads=5 \ --min-split-size=10M \ --follow-torrent=mem \ --split=10 \ +--bt-tracker={trackers} \ --daemon=true \ --allow-overwrite=true" @@ -27,7 +39,6 @@ @register(outgoing=True, pattern="^.amag(?: |$)(.*)") -@errors_handler async def magnet_download(event): magnet_uri = event.pattern_match.group(1) # Add Magnet URI Into Queue @@ -45,7 +56,6 @@ async def magnet_download(event): @register(outgoing=True, pattern="^.ator(?: |$)(.*)") -@errors_handler async def torrent_download(event): torrent_file_path = event.pattern_match.group(1) # Add Torrent Into Queue @@ -62,7 +72,6 @@ async def torrent_download(event): @register(outgoing=True, pattern="^.aurl(?: |$)(.*)") -@errors_handler async def magnet_download(event): uri = [event.pattern_match.group(1)] try: # Add URL Into Queue @@ -80,7 +89,6 @@ async def magnet_download(event): @register(outgoing=True, pattern="^.aclear(?: |$)(.*)") -@errors_handler async def remove_all(event): try: removed = aria2.remove_all(force=True) @@ -96,7 +104,6 @@ async def remove_all(event): @register(outgoing=True, pattern="^.apause(?: |$)(.*)") -@errors_handler async def pause_all(event): # Pause ALL Currently Running Downloads. paused = aria2.pause_all(force=True) @@ -107,7 +114,6 @@ async def pause_all(event): @register(outgoing=True, pattern="^.aresume(?: |$)(.*)") -@errors_handler async def resume_all(event): resumed = aria2.resume_all() await event.edit("`Resuming downloads...`") @@ -118,7 +124,6 @@ async def resume_all(event): @register(outgoing=True, pattern="^.ashow(?: |$)(.*)") -@errors_handler async def show_all(event): output = "output.txt" downloads = aria2.get_downloads() @@ -163,7 +168,7 @@ async def check_progress_for_dl(gid, event, previous): file = aria2.get_download(gid) complete = file.is_complete try: - if not file.error_message: + if not complete and not file.error_message: msg = f"\nDownloading File: `{file.name}`" msg += f"\nSpeed: {file.download_speed_string()}" msg += f"\nProgress: {file.progress_string()}" @@ -181,10 +186,11 @@ async def check_progress_for_dl(gid, event, previous): file = aria2.get_download(gid) complete = file.is_complete if complete: - await event.edit(f"File Downloaded Successfully:`{file.name}`") + await event.edit(f"File Downloaded Successfully: `{file.name}`" + ) return False except Exception as e: - if "not found" in str(e) or "'file'" in str(e): + if " not found" in str(e) or "'file'" in str(e): await event.edit("Download Canceled :\n`{}`".format(file.name)) await sleep(2.5) await event.delete() diff --git a/userbot/modules/chat.py b/userbot/modules/chat.py index aec65d1b5..c1ab539f1 100644 --- a/userbot/modules/chat.py +++ b/userbot/modules/chat.py @@ -4,14 +4,13 @@ # you may not use this file except in compliance with the License. """ Userbot module containing userid, chatid and log commands""" -from time import sleep +from asyncio import sleep from userbot import CMD_HELP, BOTLOG, BOTLOG_CHATID, bot -from userbot.events import register, errors_handler +from userbot.events import register from userbot.modules.admin import get_user_from_event @register(outgoing=True, pattern="^.userid$") -@errors_handler async def useridgetter(target): """ For .userid command, returns the ID of the target user. """ message = await target.get_reply_message() @@ -32,13 +31,11 @@ async def useridgetter(target): name, user_id)) -@register(outgoing=True, pattern="^.mention(?: |$)(.*)") -@errors_handler +@register(outgoing=True, pattern="^.link(?: |$)(.*)") async def permalink(mention): - """ For .mention command, generates a link to the user's PM with a custom text. """ + """ For .link command, generates a link to the user's PM with a custom text. """ user, custom = await get_user_from_event(mention) if not user: - await mention.edit("`User not found.`") return if custom: await mention.edit(f"[{custom}](tg://user?id={user.id})") @@ -49,14 +46,12 @@ async def permalink(mention): @register(outgoing=True, pattern="^.chatid$") -@errors_handler async def chatidgetter(chat): """ For .chatid, returns the ID of the chat you are in at that moment. """ await chat.edit("Chat ID: `" + str(chat.chat_id) + "`") @register(outgoing=True, pattern=r"^.log(?: |$)([\s\S]*)") -@errors_handler async def log(log_text): """ For .log command, forwards a message or the command argument to the bot logs group """ if BOTLOG: @@ -73,12 +68,11 @@ async def log(log_text): await log_text.edit("`Logged Successfully`") else: await log_text.edit("`This feature requires Logging to be enabled!`") - sleep(2) + await sleep(2) await log_text.delete() @register(outgoing=True, pattern="^.kickme$") -@errors_handler async def kickme(leave): """ Basically it's .kickme command """ await leave.edit("Nope, no, no, I go away") @@ -86,7 +80,6 @@ async def kickme(leave): @register(outgoing=True, pattern="^.unmutechat$") -@errors_handler async def unmute_chat(unm_e): """ For .unmutechat command, unmute a muted chat. """ try: @@ -96,12 +89,11 @@ async def unmute_chat(unm_e): return unkread(str(unm_e.chat_id)) await unm_e.edit("```Unmuted this chat Successfully```") - sleep(2) + await sleep(2) await unm_e.delete() @register(outgoing=True, pattern="^.mutechat$") -@errors_handler async def mute_chat(mute_e): """ For .mutechat command, mute any chat. """ try: @@ -112,7 +104,7 @@ async def mute_chat(mute_e): await mute_e.edit(str(mute_e.chat_id)) kread(str(mute_e.chat_id)) await mute_e.edit("`Shush! This chat will be silenced!`") - sleep(2) + await sleep(2) await mute_e.delete() if BOTLOG: await mute_e.client.send_message( @@ -120,8 +112,7 @@ async def mute_chat(mute_e): str(mute_e.chat_id) + " was silenced.") -@register(incoming=True) -@errors_handler +@register(incoming=True, disable_errors=True) async def keep_read(message): """ The mute logic. """ try: @@ -135,6 +126,34 @@ async def keep_read(message): await message.client.send_read_acknowledge(message.chat_id) +# Regex-Ninja module by @Kandnub +regexNinja = False + + +@register(outgoing=True, pattern="^s/") +async def sedNinja(event): + """For regex-ninja module, auto delete command starting with s/""" + if regexNinja: + await sleep(.5) + await event.delete() + + +@register(outgoing=True, pattern="^.regexninja (on|off)$") +async def sedNinjaToggle(event): + """ Enables or disables the regex ninja module. """ + global regexNinja + if event.pattern_match.group(1) == "on": + regexNinja = True + await event.edit("`Successfully enabled ninja mode for Regexbot.`") + await sleep(1) + await event.delete() + elif event.pattern_match.group(1) == "off": + regexNinja = False + await event.edit("`Successfully disabled ninja mode for Regexbot.`") + await sleep(1) + await event.delete() + + CMD_HELP.update({ "chat": ".chatid\ @@ -149,6 +168,9 @@ async def keep_read(message): \nUsage: Unmutes a muted chat.\ \n\n.mutechat\ \nUsage: Allows you to mute any chat.\ -\n\n.mention \ -\nUsage: Generate a permanent link to the user's profile with optional custom text." +\n\n.link : (or) reply to someone's message with .link \ +\nUsage: Generate a permanent link to the user's profile with optional custom text.\ +\n\n.regexninja on/off\ +\nUsage: Globally enable/disables the regex ninja module.\ +\nRegex Ninja module helps to delete the regex bot's triggering messages." }) diff --git a/userbot/modules/direct_links.py b/userbot/modules/direct_links.py index 4e30a8fb1..af1255d91 100644 --- a/userbot/modules/direct_links.py +++ b/userbot/modules/direct_links.py @@ -15,11 +15,10 @@ from humanize import naturalsize from userbot import CMD_HELP -from userbot.events import register, errors_handler +from userbot.events import register @register(outgoing=True, pattern=r"^.direct(?: |$)([\s\S]*)") -@errors_handler async def direct_link_generator(request): """ direct links generator """ await request.edit("`Processing...`") diff --git a/userbot/modules/dogbin.py b/userbot/modules/dogbin.py index 570c9162a..ac1469a13 100644 --- a/userbot/modules/dogbin.py +++ b/userbot/modules/dogbin.py @@ -9,13 +9,12 @@ import asyncio import os from userbot import BOTLOG, BOTLOG_CHATID, CMD_HELP, LOGS, TEMP_DOWNLOAD_DIRECTORY -from userbot.events import register, errors_handler +from userbot.events import register DOGBIN_URL = "https://del.dog/" @register(outgoing=True, pattern=r"^.paste(?: |$)([\s\S]*)") -@errors_handler async def paste(pstl): """ For .paste command, pastes the text directly to dogbin. """ dogbin_final_url = "" @@ -74,7 +73,6 @@ async def paste(pstl): @register(outgoing=True, pattern="^.getpaste(?: |$)(.*)") -@errors_handler async def get_dogbin_content(dog_url): """ For .getpaste command, fetches the content of a dogbin URL. """ textx = await dog_url.get_reply_message() diff --git a/userbot/modules/evaluators.py b/userbot/modules/evaluators.py index d90b5f0fc..455133f99 100644 --- a/userbot/modules/evaluators.py +++ b/userbot/modules/evaluators.py @@ -10,11 +10,10 @@ from os import remove from sys import executable from userbot import CMD_HELP, BOTLOG, BOTLOG_CHATID -from userbot.events import register, errors_handler +from userbot.events import register @register(outgoing=True, pattern="^.eval(?: |$)(.*)") -@errors_handler async def evaluate(query): """ For .eval command, evaluates the given Python expression. """ if query.is_channel and not query.is_group: @@ -69,7 +68,6 @@ async def evaluate(query): @register(outgoing=True, pattern=r"^.exec(?: |$)([\s\S]*)") -@errors_handler async def run(run_q): """ For .exec command, which executes the dynamically created program """ code = run_q.pattern_match.group(1) @@ -135,7 +133,6 @@ async def run(run_q): @register(outgoing=True, pattern="^.term(?: |$)(.*)") -@errors_handler async def terminal_runner(term): """ For .term command, runs bash commands and scripts on your server. """ curruser = getuser() diff --git a/userbot/modules/filter.py b/userbot/modules/filter.py index 2a10b0982..0c36c60ca 100644 --- a/userbot/modules/filter.py +++ b/userbot/modules/filter.py @@ -8,11 +8,10 @@ from asyncio import sleep from re import fullmatch, IGNORECASE, escape from userbot import BOTLOG, BOTLOG_CHATID, CMD_HELP -from userbot.events import register, errors_handler +from userbot.events import register -@register(incoming=True, disable_edited=True) -@errors_handler +@register(incoming=True, disable_edited=True, disable_errors=True) async def filter_incoming_handler(handler): """ Checks if the incoming message contains handler of a filter """ try: @@ -28,16 +27,17 @@ async def filter_incoming_handler(handler): return for trigger in filters: pro = fullmatch(trigger.keyword, name, flags=IGNORECASE) - if pro: + if pro and trigger.f_mesg_id: msg_o = await handler.client.get_messages( entity=BOTLOG_CHATID, ids=int(trigger.f_mesg_id)) await handler.reply(msg_o.message, file=msg_o.media) + elif pro and trigger.reply: + await handler.reply(trigger.reply) except AttributeError: pass -@register(outgoing=True, pattern="^.filter (.*)") -@errors_handler +@register(outgoing=True, pattern="^.filter (\w*)") async def add_new_filter(new_handler): """ For .filter command, allows adding new filters in a chat """ try: @@ -46,35 +46,39 @@ async def add_new_filter(new_handler): await new_handler.edit("`Running on Non-SQL mode!`") return keyword = new_handler.pattern_match.group(1) + string = new_handler.text.partition(keyword)[2] msg = await new_handler.get_reply_message() - if not msg: - await new_handler.edit( - "`I need something to save as reply to the filter.`") - elif BOTLOG_CHATID: - await new_handler.client.send_message( - BOTLOG_CHATID, f"#FILTER\ - \nCHAT: {new_handler.chat.title}\ - \nTRIGGER: {keyword}\ - \nThe following message is saved as the filter's reply data for the chat, please do NOT delete it !!" - ) - msg_o = await new_handler.client.forward_messages( - entity=BOTLOG_CHATID, - messages=msg, - from_peer=new_handler.chat_id, - silent=True) - else: - await new_handler.edit( - "`This feature requires the BOTLOG_CHATID to be set.`") - return + msg_id = None + if msg and msg.media and not string: + if BOTLOG_CHATID: + await new_handler.client.send_message( + BOTLOG_CHATID, f"#FILTER\ + \nCHAT ID: {new_handler.chat_id}\ + \nTRIGGER: {keyword}\ + \n\nThe following message is saved as the filter's reply data for the chat, please do NOT delete it !!" + ) + msg_o = await new_handler.client.forward_messages( + entity=BOTLOG_CHATID, + messages=msg, + from_peer=new_handler.chat_id, + silent=True) + msg_id = msg_o.id + else: + await new_handler.edit( + "`Saving media as reply to the filter requires the BOTLOG_CHATID to be set.`" + ) + return + elif new_handler.reply_to_msg_id and not string: + rep_msg = await new_handler.get_reply_message() + string = rep_msg.text success = "`Filter` **{}** `{} successfully`" - if add_filter(str(new_handler.chat_id), keyword, msg_o.id) is True: + if add_filter(str(new_handler.chat_id), keyword, string, msg_id) is True: await new_handler.edit(success.format(keyword, 'added')) else: await new_handler.edit(success.format(keyword, 'updated')) -@register(outgoing=True, pattern="^.stop (.*)") -@errors_handler +@register(outgoing=True, pattern="^.stop (\w*)") async def remove_a_filter(r_handler): """ For .stop command, allows you to remove a filter from a chat. """ try: @@ -91,7 +95,6 @@ async def remove_a_filter(r_handler): @register(outgoing=True, pattern="^.rmbotfilters (.*)") -@errors_handler async def kick_marie_filter(event): """ For .rmfilters command, allows you to kick all \ Marie(or her clones) filters from a chat. """ @@ -119,7 +122,6 @@ async def kick_marie_filter(event): @register(outgoing=True, pattern="^.filters$") -@errors_handler async def filters_active(event): """ For .filters command, lists all of the active filters in a chat. """ try: diff --git a/userbot/modules/gdrive.py b/userbot/modules/gdrive.py index 96d1c62ab..51015b93f 100644 --- a/userbot/modules/gdrive.py +++ b/userbot/modules/gdrive.py @@ -1,8 +1,7 @@ -# Special thanks to @spechide & @Zero_cool7870 & @Prakaska :) -# The entire code given below is verbatim copied from -# https://github.com/cyberboysumanjay/Gdrivedownloader/blob/master/gdrive_upload.py -# there might be some changes made to suit the needs for this repository -# Licensed under MIT License +# Copyright (C) 2019 The Raphielscape Company LLC. +# +# Licensed under the Raphielscape Public License, Version 1.c (the "License"); +# you may not use this file except in compliance with the License. import asyncio import math @@ -19,7 +18,7 @@ from userbot import (G_DRIVE_CLIENT_ID, G_DRIVE_CLIENT_SECRET, G_DRIVE_AUTH_TOKEN_DATA, GDRIVE_FOLDER_ID, BOTLOG_CHATID, TEMP_DOWNLOAD_DIRECTORY, CMD_HELP, LOGS) -from userbot.events import register, errors_handler +from userbot.events import register from mimetypes import guess_type import httplib2 import subprocess @@ -41,7 +40,6 @@ @register(pattern=r"^.gdrive(?: |$)(.*)", outgoing=True) -@errors_handler async def gdrive_upload_function(dryb): """ For .gdrive command, upload files to google drive. """ await dryb.edit("Processing ...") @@ -76,8 +74,9 @@ async def gdrive_upload_function(dryb): speed = downloader.get_speed() elapsed_time = round(diff) * 1000 progress_str = "[{0}{1}] {2}%".format( - ''.join(["▰" for i in range(math.floor(percentage / 5))]), - ''.join(["▱" for i in range(20 - math.floor(percentage / 5))]), + ''.join(["▰" for i in range(math.floor(percentage / 10))]), + ''.join(["▱" + for i in range(10 - math.floor(percentage / 10))]), round(percentage, 2)) estimated_total_time = downloader.get_eta(human=True) try: @@ -145,7 +144,8 @@ async def gdrive_upload_function(dryb): # Sometimes API fails to retrieve starting URI, we wrap it. try: g_drive_link = await upload_file(http, required_file_name, - file_name, mime_type, dryb) + file_name, mime_type, dryb, + parent_id) await dryb.edit( f"File:`{required_file_name}`\nwas Successfully Uploaded to [Google Drive]({g_drive_link})!" ) @@ -155,13 +155,9 @@ async def gdrive_upload_function(dryb): @register(pattern=r"^.ggd(?: |$)(.*)", outgoing=True) -@errors_handler async def upload_dir_to_gdrive(event): await event.edit("Processing ...") if CLIENT_ID is None or CLIENT_SECRET is None: - await event.edit( - "This module requires credentials from https://da.gd/so63O. Aborting!" - ) return input_str = event.pattern_match.group(1) if os.path.isdir(input_str): @@ -186,13 +182,9 @@ async def upload_dir_to_gdrive(event): @register(pattern=r"^.list(?: |$)(.*)", outgoing=True) -@errors_handler async def gdrive_search_list(event): await event.edit("Processing ...") if CLIENT_ID is None or CLIENT_SECRET is None: - await event.edit( - "This module requires credentials from https://da.gd/so63O. Aborting!" - ) return input_str = event.pattern_match.group(1).strip() # TODO: remove redundant code @@ -214,7 +206,6 @@ async def gdrive_search_list(event): pattern= r"^.gsetf https?://drive\.google\.com/drive/u/\d/folders/([-\w]{25,})", outgoing=True) -@errors_handler async def download(set): """For .gsetf command, allows you to set path""" await set.edit("Processing ...") @@ -232,7 +223,6 @@ async def download(set): @register(pattern="^.gsetclear$", outgoing=True) -@errors_handler async def download(gclr): """For .gsetclear command, allows you clear ur curnt custom path""" await gclr.reply("Processing ...") @@ -241,7 +231,6 @@ async def download(gclr): @register(pattern="^.gfolder$", outgoing=True) -@errors_handler async def show_current_gdrove_folder(event): if parent_id: folder_link = f"https://drive.google.com/drive/folders/" + parent_id @@ -295,7 +284,7 @@ def authorize(token_file, storage): return http -async def upload_file(http, file_path, file_name, mime_type, event): +async def upload_file(http, file_path, file_name, mime_type, event, parent_id): # Create Google Drive service instance drive_service = build("drive", "v2", http=http, cache_discovery=False) # File body description @@ -324,9 +313,10 @@ async def upload_file(http, file_path, file_name, mime_type, event): await asyncio.sleep(1) if status: percentage = int(status.progress() * 100) - progress_str = "[{0}{1}] {2}%\n".format( - "".join(["▰" for i in range(math.floor(percentage / 5))]), - "".join(["▱" for i in range(20 - math.floor(percentage / 5))]), + progress_str = "[{0}{1}] {2}%".format( + "".join(["▰" for i in range(math.floor(percentage / 10))]), + "".join(["▱" + for i in range(10 - math.floor(percentage / 10))]), round(percentage, 2)) current_message = f"Uploading to Google Drive\nFile Name: {file_name}\n{progress_str}" if display_message != current_message: @@ -385,7 +375,8 @@ async def DoTeskWithDir(http, input_directory, event, parent_id): file_name, mime_type = file_ops(current_file_name) # current_file_name will have the full path g_drive_link = await upload_file(http, current_file_name, - file_name, mime_type, event) + file_name, mime_type, event, + parent_id) r_p_id = parent_id # TODO: there is a #bug here :( return r_p_id @@ -454,11 +445,11 @@ async def gdrive_search(http, search_query): ".gdrive \ \nUsage: Uploads the file in reply , URL or file path in server to your Google Drive.\ \n\n.gsetf \ - \nUsage:Sets the folder to upload new files to.\ + \nUsage: Sets the folder to upload new files to.\ \n\n.gsetclear\ - \nUsage:Reverts to default upload destination.\ + \nUsage: Reverts to default upload destination.\ \n\n.gfolder\ - \nUsage:Shows your current upload destination/folder.\ + \nUsage: Shows your current upload destination/folder.\ \n\n.list \ \nUsage: Looks for files and folders in your Google Drive.\ \n\n.ggd \ diff --git a/userbot/modules/github.py b/userbot/modules/github.py deleted file mode 100644 index ce739d0d5..000000000 --- a/userbot/modules/github.py +++ /dev/null @@ -1,52 +0,0 @@ -import aiohttp -from userbot.events import register, errors_handler -from userbot import CMD_HELP - - -@register(pattern=r".git (.*)", outgoing=True) -@errors_handler -async def github(event): - URL = f"https://api.github.com/users/{event.pattern_match.group(1)}" - chat = await event.get_chat() - async with aiohttp.ClientSession() as session: - async with session.get(URL) as request: - if request.status == 404: - await event.reply("`" + event.pattern_match.group(1) + - " not found`") - return - - result = await request.json() - - url = result.get("html_url", None) - name = result.get("name", None) - company = result.get("company", None) - bio = result.get("bio", None) - created_at = result.get("created_at", "Not Found") - - REPLY = f"GitHub Info for `{event.pattern_match.group(1)}`\ - \nUsername: `{name}`\ - \nBio: `{bio}`\ - \nURL: {url}\ - \nCompany: `{company}`\ - \nCreated at: `{created_at}`" - - if not result.get("repos_url", None): - await event.edit(REPLY) - return - async with session.get(result.get("repos_url", None)) as request: - result = request.json - if request.status == 404: - await event.edit(REPLY) - return - - result = await request.json() - - REPLY += "\nRepos:\n" - - for nr in range(len(result)): - REPLY += f"[{result[nr].get('name', None)}]({result[nr].get('html_url', None)})\n" - - await event.edit(REPLY) - - -CMD_HELP.update({"git": "Like .whois but for GitHub usernames."}) diff --git a/userbot/modules/hash.py b/userbot/modules/hash.py index ac3e724cf..eb950cbe3 100644 --- a/userbot/modules/hash.py +++ b/userbot/modules/hash.py @@ -9,11 +9,10 @@ from subprocess import run as runapp import pybase64 from userbot import CMD_HELP -from userbot.events import register, errors_handler +from userbot.events import register @register(outgoing=True, pattern="^.hash (.*)") -@errors_handler async def gethash(hash_q): """ For .hash command, find the md5, sha1, sha256, sha512 of the string. """ hashtxt_ = hash_q.pattern_match.group(1) @@ -46,7 +45,6 @@ async def gethash(hash_q): @register(outgoing=True, pattern="^.base64 (en|de) (.*)") -@errors_handler async def endecrypt(query): """ For .base64 command, find the base64 encoding of the given string. """ if query.pattern_match.group(1) == "en": diff --git a/userbot/modules/help.py b/userbot/modules/help.py index 3701e4506..63ad6b276 100644 --- a/userbot/modules/help.py +++ b/userbot/modules/help.py @@ -6,11 +6,10 @@ """ Userbot help command """ from userbot import CMD_HELP -from userbot.events import register, errors_handler +from userbot.events import register @register(outgoing=True, pattern="^.help(?: |$)(.*)") -@errors_handler async def help(event): """ For .help command,""" args = event.pattern_match.group(1).lower() diff --git a/userbot/modules/lastfm.py b/userbot/modules/lastfm.py index 685e52244..65b0a8833 100644 --- a/userbot/modules/lastfm.py +++ b/userbot/modules/lastfm.py @@ -18,7 +18,7 @@ from telethon.errors.rpcerrorlist import FloodWaitError from userbot import CMD_HELP, BOTLOG, BOTLOG_CHATID, DEFAULT_BIO, BIO_PREFIX, lastfm, LASTFM_USERNAME, bot -from userbot.events import register, errors_handler +from userbot.events import register # =================== CONSTANT =================== LFM_BIO_ENABLED = "```last.fm current music to bio is now enabled.```" @@ -46,7 +46,6 @@ @register(outgoing=True, pattern="^.lastfm$") -@errors_handler async def last_fm(lastFM): """ For .lastfm command, fetch scrobble data from last.fm. """ await lastFM.edit("Processing...") @@ -179,7 +178,6 @@ async def get_curr_track(lfmbio): @register(outgoing=True, pattern=r"^.lastbio (on|off)") -@errors_handler async def lastbio(lfmbio): arg = lfmbio.pattern_match.group(1).lower() global LASTFMCHECK @@ -204,7 +202,6 @@ async def lastbio(lfmbio): @register(outgoing=True, pattern=r"^.lastlog (on|off)") -@errors_handler async def lastlog(lstlog): arg = lstlog.pattern_match.group(1).lower() global LastLog diff --git a/userbot/modules/locks.py b/userbot/modules/locks.py index a89a71522..db3f57465 100644 --- a/userbot/modules/locks.py +++ b/userbot/modules/locks.py @@ -1,12 +1,16 @@ +# Copyright (C) 2019 The Raphielscape Company LLC. +# +# Licensed under the Raphielscape Public License, Version 1.c (the "License"); +# you may not use this file except in compliance with the License. + from telethon.tl.functions.messages import EditChatDefaultBannedRightsRequest from telethon.tl.types import ChatBannedRights from userbot import CMD_HELP -from userbot.events import register, errors_handler +from userbot.events import register @register(outgoing=True, pattern=r"^.lock ?(.*)") -@errors_handler async def locks(event): input_str = event.pattern_match.group(1).lower() peer_id = event.chat_id @@ -95,7 +99,6 @@ async def locks(event): @register(outgoing=True, pattern=r"^.unlock ?(.*)") -@errors_handler async def rem_locks(event): input_str = event.pattern_match.group(1).lower() peer_id = event.chat_id diff --git a/userbot/modules/memes.py b/userbot/modules/memes.py index 82c775426..a727aa63c 100644 --- a/userbot/modules/memes.py +++ b/userbot/modules/memes.py @@ -2,26 +2,21 @@ # # Licensed under the Raphielscape Public License, Version 1.c (the "License"); # you may not use this file except in compliance with the License. -# -# """ Userbot module for having some fun with people. """ -import asyncio -import random -import re +from asyncio import sleep +from random import choice, getrandbits, randint +from re import sub import time from collections import deque import requests -from telethon.tl.functions.users import GetFullUserRequest -from telethon.tl.types import MessageEntityMentionName - from cowpy import cow from userbot import CMD_HELP -from userbot.events import register, errors_handler +from userbot.events import register from userbot.modules.admin import get_user_from_event # ================= CONSTANT ================= @@ -614,7 +609,6 @@ @register(outgoing=True, pattern=r"^.(\w+)say (.*)") -@errors_handler async def univsaye(cowmsg): """ For .cowsay module, userbot wrapper for cow which says things. """ arg = cowmsg.pattern_match.group(1).lower() @@ -630,8 +624,7 @@ async def univsaye(cowmsg): await cowmsg.edit(f"`{cheese.milk(text).replace('`', '´')}`") -@register(outgoing=True, pattern="^:/$") -@errors_handler +@register(outgoing=True, pattern="^:/$", ignore_unsafe=True) async def kek(keks): """ Check yourself ;)""" uio = ["/", "\\"] @@ -641,9 +634,8 @@ async def kek(keks): @register(outgoing=True, pattern=r"^.coinflip (.*)") -@errors_handler async def coin(event): - r = random.choice(["heads", "tails"]) + r = choice(["heads", "tails"]) input_str = event.pattern_match.group(1) if input_str: input_str = input_str.lower() @@ -670,19 +662,14 @@ async def coin(event): @register(pattern="^.slap(?: |$)(.*)", outgoing=True) -@errors_handler async def who(event): """ slaps a user, or get slapped if not a reply. """ replied_user = await get_user_from_event(event) if replied_user: replied_user = replied_user[0] else: - await event.edit("`I can't slap nothing !!`") + return caption = await slap(replied_user, event) - message_id_to_reply = event.message.reply_to_msg_id - - if not message_id_to_reply: - message_id_to_reply = None try: await event.edit(caption) @@ -704,11 +691,11 @@ async def slap(replied_user, event): else: slapped = f"[{first_name}](tg://user?id={user_id})" - temp = random.choice(SLAP_TEMPLATES) - item = random.choice(ITEMS) - hit = random.choice(HIT) - throw = random.choice(THROW) - where = random.choice(WHERE) + temp = choice(SLAP_TEMPLATES) + item = choice(ITEMS) + hit = choice(HIT) + throw = choice(THROW) + where = choice(WHERE) caption = "..." + temp.format( victim=slapped, item=item, hits=hit, throws=throw, where=where) @@ -716,8 +703,7 @@ async def slap(replied_user, event): return caption -@register(outgoing=True, pattern="^-_-$") -@errors_handler +@register(outgoing=True, pattern="^-_-$", ignore_unsafe=True) async def lol(lel): """ Ok... """ okay = "-_-" @@ -726,34 +712,22 @@ async def lol(lel): await lel.edit(okay) -@register(outgoing=True, pattern="^.decide(?: |$)(.*)") -@errors_handler +@register(outgoing=True, pattern="^.(yes|no|maybe|decide)$") async def decide(event): decision = event.pattern_match.group(1).lower() - message_id = None - if event.reply_to_msg_id: - message_id = event.reply_to_msg_id - if not decision: - r = requests.get("https://yesno.wtf/api").json() + message_id = event.reply_to_msg_id if event.reply_to_msg_id else None + if decision != "decide": + r = requests.get(f"https://yesno.wtf/api?force={decision}").json() else: - try: - options = ["yes", "no", "maybe"] - if decision not in options: - await event.edit("`Available decisions:` *yes*, *no*, *maybe*") - return - r = requests.get(f"https://yesno.wtf/api?force={decision}").json() - except Excepption as err: - await event.edit(f"`Error:` {str(err)}") - return + r = requests.get(f"https://yesno.wtf/api").json() + await event.delete() await event.client.send_message(event.chat_id, str(r["answer"]).upper(), reply_to=message_id, file=r["image"]) - await event.delete() -@register(outgoing=True, pattern="^;_;$") -@errors_handler +@register(outgoing=True, pattern="^;_;$", ignore_unsafe=True) async def fun(e): t = ";_;" for j in range(10): @@ -762,28 +736,24 @@ async def fun(e): @register(outgoing=True, pattern="^.fp$") -@errors_handler async def facepalm(e): """ Facepalm 🤦‍♂ """ await e.edit("🤦‍♂") @register(outgoing=True, pattern="^.cry$") -@errors_handler async def cry(e): """ y u du dis, i cry everytime !! """ - await e.edit(random.choice(CRI)) + await e.edit(choice(CRI)) @register(outgoing=True, pattern="^.insult$") -@errors_handler async def insult(e): """ I make you cry !! """ - await e.edit(random.choice(INSULT_STRINGS)) + await e.edit(choice(INSULT_STRINGS)) @register(outgoing=True, pattern="^.cp(?: |$)(.*)") -@errors_handler async def copypasta(cp_e): """ Copypasta the famous meme """ textx = await cp_e.get_reply_message() @@ -797,28 +767,27 @@ async def copypasta(cp_e): await cp_e.edit("`😂🅱️IvE👐sOME👅text👅for✌️Me👌tO👐MAkE👀iT💞funNy!💦`") return - reply_text = random.choice(EMOJIS) + reply_text = choice(EMOJIS) # choose a random character in the message to be substituted with 🅱️ - b_char = random.choice(message).lower() + b_char = choice(message).lower() for owo in message: if owo == " ": - reply_text += random.choice(EMOJIS) + reply_text += choice(EMOJIS) elif owo in EMOJIS: reply_text += owo - reply_text += random.choice(EMOJIS) + reply_text += choice(EMOJIS) elif owo.lower() == b_char: reply_text += "🅱️" else: - if bool(random.getrandbits(1)): + if bool(getrandbits(1)): reply_text += owo.upper() else: reply_text += owo.lower() - reply_text += random.choice(EMOJIS) + reply_text += choice(EMOJIS) await cp_e.edit(reply_text) @register(outgoing=True, pattern="^.vapor(?: |$)(.*)") -@errors_handler async def vapor(vpr): """ Vaporize everything! """ reply_text = list() @@ -844,7 +813,6 @@ async def vapor(vpr): @register(outgoing=True, pattern="^.str(?: |$)(.*)") -@errors_handler async def stretch(stret): """ Stretch it.""" textx = await stret.get_reply_message() @@ -858,14 +826,13 @@ async def stretch(stret): await stret.edit("`GiiiiiiiB sooooooomeeeeeee teeeeeeext!`") return - count = random.randint(3, 10) - reply_text = re.sub(r"([aeiouAEIOUaeiouAEIOUаеиоуюяыэё])", (r"\1" * count), - message) + count = randint(3, 10) + reply_text = sub(r"([aeiouAEIOUaeiouAEIOUаеиоуюяыэё])", (r"\1" * count), + message) await stret.edit(reply_text) @register(outgoing=True, pattern="^.zal(?: |$)(.*)") -@errors_handler async def zal(zgfy): """ Invoke the feeling of chaos. """ reply_text = list() @@ -887,17 +854,17 @@ async def zal(zgfy): continue for _ in range(0, 3): - randint = random.randint(0, 2) + randint = randint(0, 2) if randint == 0: charac = charac.strip() + \ - random.choice(ZALG_LIST[0]).strip() + choice(ZALG_LIST[0]).strip() elif randint == 1: charac = charac.strip() + \ - random.choice(ZALG_LIST[1]).strip() + choice(ZALG_LIST[1]).strip() else: charac = charac.strip() + \ - random.choice(ZALG_LIST[2]).strip() + choice(ZALG_LIST[2]).strip() reply_text.append(charac) @@ -905,14 +872,12 @@ async def zal(zgfy): @register(outgoing=True, pattern="^.hi$") -@errors_handler async def hoi(hello): """ Greet everyone! """ - await hello.edit(random.choice(HELLOSTR)) + await hello.edit(choice(HELLOSTR)) @register(outgoing=True, pattern="^.owo(?: |$)(.*)") -@errors_handler async def faces(owo): """ UwU """ textx = await owo.get_reply_message() @@ -925,53 +890,47 @@ async def faces(owo): await owo.edit("` UwU no text given! `") return - reply_text = re.sub(r"(r|l)", "w", message) - reply_text = re.sub(r"(R|L)", "W", reply_text) - reply_text = re.sub(r"n([aeiou])", r"ny\1", reply_text) - reply_text = re.sub(r"N([aeiouAEIOU])", r"Ny\1", reply_text) - reply_text = re.sub(r"\!+", " " + random.choice(UWUS), reply_text) + reply_text = sub(r"(r|l)", "w", message) + reply_text = sub(r"(R|L)", "W", reply_text) + reply_text = sub(r"n([aeiou])", r"ny\1", reply_text) + reply_text = sub(r"N([aeiouAEIOU])", r"Ny\1", reply_text) + reply_text = sub(r"\!+", " " + choice(UWUS), reply_text) reply_text = reply_text.replace("ove", "uv") - reply_text += " " + random.choice(UWUS) + reply_text += " " + choice(UWUS) await owo.edit(reply_text) @register(outgoing=True, pattern="^.react$") -@errors_handler async def react_meme(react): """ Make your userbot react to everything. """ - await react.edit(random.choice(FACEREACTS)) + await react.edit(choice(FACEREACTS)) @register(outgoing=True, pattern="^.shg$") -@errors_handler async def shrugger(shg): r""" ¯\_(ツ)_/¯ """ - await shg.edit(random.choice(SHGS)) + await shg.edit(choice(SHGS)) @register(outgoing=True, pattern="^.chase$") -@errors_handler async def police(chase): """ Run boi run, i'm gonna catch you !! """ - await chase.edit(random.choice(CHASE_STR)) + await chase.edit(choice(CHASE_STR)) @register(outgoing=True, pattern="^.run$") -@errors_handler async def runner_lol(run): """ Run, run, RUNNN! """ - await run.edit(random.choice(RUNS_STR)) + await run.edit(choice(RUNS_STR)) @register(outgoing=True, pattern="^.metoo$") -@errors_handler async def metoo(hahayes): """ Haha yes """ - await hahayes.edit(random.choice(METOOSTR)) + await hahayes.edit(choice(METOOSTR)) -@register(outgoing=True, pattern="^.oof$") -@errors_handler +@register(outgoing=True, pattern="^Oof$") async def Oof(e): t = "Oof" for j in range(15): @@ -980,18 +939,16 @@ async def Oof(e): @register(outgoing=True, pattern="^.10iq$") -@errors_handler async def iqless(e): await e.edit("♿") @register(outgoing=True, pattern="^.moon$") -@errors_handler async def moon(event): deq = deque(list("🌗🌘🌑🌒🌓🌔🌕🌖")) try: for x in range(32): - await asyncio.sleep(0.1) + await sleep(0.1) await event.edit("".join(deq)) deq.rotate(1) except BaseException: @@ -999,12 +956,11 @@ async def moon(event): @register(outgoing=True, pattern="^.clock$") -@errors_handler async def clock(event): deq = deque(list("🕙🕘🕗🕖🕕🕔🕓🕒🕑🕐🕛")) try: for x in range(32): - await asyncio.sleep(0.1) + await sleep(0.1) await event.edit("".join(deq)) deq.rotate(1) except BaseException: @@ -1012,7 +968,6 @@ async def clock(event): @register(outgoing=True, pattern="^.mock(?: |$)(.*)") -@errors_handler async def spongemocktext(mock): """ Do it and find the real fun. """ reply_text = list() @@ -1027,7 +982,7 @@ async def spongemocktext(mock): return for charac in message: - if charac.isalpha() and random.randint(0, 1): + if charac.isalpha() and randint(0, 1): to_app = charac.upper() if charac.islower() else charac.lower() reply_text.append(to_app) else: @@ -1037,7 +992,6 @@ async def spongemocktext(mock): @register(outgoing=True, pattern="^.clap(?: |$)(.*)") -@errors_handler async def claptext(memereview): """ Praise people! """ textx = await memereview.get_reply_message() @@ -1056,18 +1010,15 @@ async def claptext(memereview): @register(outgoing=True, pattern="^.bt$") -@errors_handler async def bluetext(bt_e): """ Believe me, you will find this useful. """ if await bt_e.get_reply_message() and bt_e.is_group: await bt_e.edit( "/BLUETEXT /MUST /CLICK.\n" - "/ARE /YOU /A /STUPID /ANIMAL /WHICH /IS /ATTRACTED /TO /COLOURS ?" - ) + "/ARE /YOU /A /STUPID /ANIMAL /WHICH /IS /ATTRACTED /TO /COLOURS?") @register(outgoing=True, pattern=r"^.f (.*)") -@errors_handler async def payf(event): paytext = event.pattern_match.group(1) pay = "{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}".format( @@ -1078,7 +1029,6 @@ async def payf(event): @register(outgoing=True, pattern="^.lfy (.*)") -@errors_handler async def let_me_google_that_for_you(lmgtfy_q): textx = await lmgtfy_q.get_reply_message() qry = lmgtfy_q.pattern_match.group(1) @@ -1096,7 +1046,6 @@ async def let_me_google_that_for_you(lmgtfy_q): @register(pattern=r".scam(?: |$)(.*)", outgoing=True) -@errors_handler async def scam(event): """ Just a small command to fake chat actions for fun !! """ options = [ @@ -1106,14 +1055,14 @@ async def scam(event): input_str = event.pattern_match.group(1) args = input_str.split() if len(args) is 0: # Let bot decide action and time - scam_action = random.choice(options) - scam_time = random.randint(30, 60) + scam_action = choice(options) + scam_time = randint(30, 60) elif len(args) is 1: # User decides time/action, bot decides the other. try: scam_action = str(args[0]).lower() - scam_time = random.randint(30, 60) + scam_time = randint(30, 60) except ValueError: - scam_action = random.choice(options) + scam_action = choice(options) scam_time = int(args[0]) elif len(args) is 2: # User decides both action and time scam_action = str(args[0]).lower() @@ -1125,13 +1074,12 @@ async def scam(event): if (scam_time > 0): await event.delete() async with event.client.action(event.chat_id, scam_action): - await asyncio.sleep(scam_time) + await sleep(scam_time) except BaseException: return @register(pattern=r".type(?: |$)(.*)", outgoing=True) -@errors_handler async def typewriter(typew): """ Just a small command to make your keyboard become a typewriter! """ textx = await typew.get_reply_message() @@ -1147,14 +1095,14 @@ async def typewriter(typew): typing_symbol = "|" old_text = "" await typew.edit(typing_symbol) - await asyncio.sleep(sleep_time) + await sleep(sleep_time) for character in message: old_text = old_text + "" + character typing_text = old_text + "" + typing_symbol await typew.edit(typing_text) - await asyncio.sleep(sleep_time) + await sleep(sleep_time) await typew.edit(old_text) - await asyncio.sleep(sleep_time) + await sleep(sleep_time) CMD_HELP.update({ @@ -1217,7 +1165,7 @@ async def typewriter(typew): \nUsage: Just a small command to make your keyboard become a typewriter!\ \n\n.lfy \ \nUsage: Let me Google that for you real quick !!\ -\n\n.decide [Optional: (yes, no, maybe)]\ +\n\n.decide [Alternates: (.yes, .no, .maybe)]\ \nUsage: Make a quick decision.\ \n\n.scam