text: # 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.
  #
  # thanks to the owner of X-tra-Telegram for tts fix
  #
  """ Userbot module containing various scrapers. """
  
  import os
  import time
  import asyncio
  import shutil
  import json
  import requests
  from os import popen
  from userbot.utils import chrome, options
  import urllib.parse
  import logging
  from bs4 import BeautifulSoup
  import re
  from re import match
  import io
  from random import choice
  from humanize import naturalsize
  import qrcode
  import barcode
  from barcode.writer import ImageWriter
  import emoji
  from googletrans import Translator
  from time import sleep
  from html import unescape
  from re import findall
  from selenium import webdriver
  from selenium.webdriver.support.ui import Select
  from selenium.webdriver.chrome.options import Options
  from urllib.parse import quote_plus
  from urllib.error import HTTPError
  from telethon import events
  from wikipedia import summary
  from wikipedia.exceptions import DisambiguationError, PageError
  from urbandict import define
  from requests import get
  from requests import get, post, exceptions
  from search_engine_parser import GoogleSearch
  from googleapiclient.discovery import build
  from googleapiclient.errors import HttpError
  from googletrans import LANGUAGES, Translator
  from gtts import gTTS, gTTSError
  from gtts.lang import tts_langs
  from emoji import get_emoji_regexp
  from telethon.tl.types import MessageMediaPhoto
  from youtube_dl import YoutubeDL
  from youtube_dl.utils import (DownloadError, ContentTooShortError,
                                ExtractorError, GeoRestrictedError,
                                MaxDownloadsReached, PostProcessingError,
                                UnavailableVideoError, XAttrMetadataError)
  from asyncio import sleep
  from userbot import CMD_HELP, BOTLOG, BOTLOG_CHATID, YOUTUBE_API_KEY, CHROME_DRIVER, GOOGLE_CHROME_BIN, bot, REM_BG_API_KEY, TEMP_DOWNLOAD_DIRECTORY, OCR_SPACE_API_KEY, LOGS
  from userbot.events import register
  from telethon.tl.types import DocumentAttributeAudio
  from userbot.utils import progress, humanbytes, time_formatter, chrome, googleimagesdownload
  import subprocess
  from datetime import datetime
  import asyncurban
  
  
  CARBONLANG = "auto"
  TTS_LANG = "en"
  TRT_LANG = "en"
  TEMP_DOWNLOAD_DIRECTORY = "/root/userbot/.bin"
  
  async def ocr_space_file(filename,
                           overlay=False,
                           api_key=OCR_SPACE_API_KEY,
                           language='eng'):
      """ OCR.space API request with local file.
          Python3.5 - not tested on 2.7
      :param filename: Your file path & name.
      :param overlay: Is OCR.space overlay required in your response.
                      Defaults to False.
      :param api_key: OCR.space API key.
                      Defaults to 'helloworld'.
      :param language: Language code to be used in OCR.
                      List of available language codes can be found on https://ocr.space/OCRAPI
                      Defaults to 'en'.
      :return: Result in JSON format.
      """
  
      payload = {
          'isOverlayRequired': overlay,
          'apikey': api_key,
          'language': language,
      }
      with open(filename, 'rb') as f:
          r = requests.post(
              'https://api.ocr.space/parse/image',
              files={filename: f},
              data=payload,
          )
      return r.json()
  
  DOGBIN_URL = "https://del.dog/"    
  
  @register(outgoing=True, pattern="^.crblang (.*)")
  async def setlang(prog):
      global CARBONLANG
      CARBONLANG = prog.pattern_match.group(1)
      await prog.edit(f"Language for carbon.now.sh set to {CARBONLANG}")
  
  @register(outgoing=True, pattern="^.karbon")
  async def carbon_api(e):
      """ A Wrapper for carbon.now.sh """
      await e.edit("`Processing..`")
      CARBON = 'https://carbon.now.sh/?l={lang}&code={code}'
      global CARBONLANG
      textx = await e.get_reply_message()
      pcode = e.text
      if pcode[8:]:
          pcode = str(pcode[8:])
      elif textx:
          pcode = str(textx.message)  # Importing message to module
      code = quote_plus(pcode)  # Converting to urlencoded
      await e.edit("`Processing..\n25%`")
      if os.path.isfile("/root/userbot/.bin/carbon.png"):
          os.remove("/root/userbot/.bin/carbon.png")
      url = CARBON.format(code=code, lang=CARBONLANG)
      chrome_options = Options()
      chrome_options.add_argument("--headless")
      chrome_options.binary_location = GOOGLE_CHROME_BIN
      chrome_options.add_argument("--window-size=1920x1080")
      chrome_options.add_argument("--disable-dev-shm-usage")
      chrome_options.add_argument("--no-sandbox")
      chrome_options.add_argument("--disable-gpu")
      prefs = {'download.default_directory': '/root/userbot/.bin'}
      chrome_options.add_experimental_option('prefs', prefs)
      driver = webdriver.Chrome(executable_path=CHROME_DRIVER,
                                options=chrome_options)
      driver.get(url)
      await e.edit("`Processing..\n50%`")
      download_path = '/root/userbot/.bin'
      driver.command_executor._commands["send_command"] = (
          "POST", '/session/$sessionId/chromium/send_command')
      params = {
          'cmd': 'Page.setDownloadBehavior',
          'params': {
              'behavior': 'allow',
              'downloadPath': download_path
          }
      }
      command_result = driver.execute("send_command", params)
      driver.find_element_by_xpath("//button[contains(text(),'Export')]").click()
     # driver.find_element_by_xpath("//button[contains(text(),'4x')]").click()
     # driver.find_element_by_xpath("//button[contains(text(),'PNG')]").click()
      await e.edit("`Processing..\n75%`")
      # Waiting for downloading
      while not os.path.isfile("/root/userbot/.bin/carbon.png"):
          await sleep(0.5)
      await e.edit("`Processing..\n100%`")
      file = '/root/userbot/.bin/carbon.png'
      await e.edit("`Uploading..`")
      await e.client.send_file(
          e.chat_id,
          file,
          caption="Made using [Carbon](https://carbon.now.sh/about/),\
          \na project by [Dawn Labs](https://dawnlabs.io/)",
          force_document=True,
          reply_to=e.message.reply_to_msg_id,
      )
  
      os.remove('/root/userbot/.bin/carbon.png')
      driver.quit()
      # Removing carbon.png after uploading
      await e.delete()  # Deleting msg
      
      
  @register(outgoing=True, pattern="^.img (.*)")
  async def img_sampler(event):
      """ For .img command, search and return images matching the query. """
      await event.edit("Processing...")
      query = event.pattern_match.group(1)
      lim = findall(r"lim=\d+", query)
      try:
          lim = lim[0]
          lim = lim.replace("lim=", "")
          query = query.replace("lim=" + lim[0], "")
      except IndexError:
          lim = 5
      response = googleimagesdownload()
  
      # creating list of arguments
      arguments = {
          "keywords": query,
          "limit": lim,
          "format": "jpg",
          "no_directory": "no_directory"
      }
  
      # passing the arguments to the function
      paths = response.download(arguments)
      lst = paths[0][query]
      await event.client.send_file(
          await event.client.get_input_entity(event.chat_id), lst)
      shutil.rmtree(os.path.dirname(os.path.abspath(lst[0])))
      await event.delete()
  
  
  @register(outgoing=True, pattern="^.currency (.*)")
  async def moni(event):
      input_str = event.pattern_match.group(1)
      input_sgra = input_str.split(" ")
      if len(input_sgra) == 3:
          try:
              number = float(input_sgra[0])
              currency_from = input_sgra[1].upper()
              currency_to = input_sgra[2].upper()
              request_url = "https://api.exchangeratesapi.io/latest?base={}".format(
                  currency_from)
              current_response = get(request_url).json()
              if currency_to in current_response["rates"]:
                  current_rate = float(current_response["rates"][currency_to])
                  rebmun = round(number * current_rate, 2)
                  await event.edit("{} {} = {} {}".format(
                      number, currency_from, rebmun, currency_to))
              else:
                  await event.edit(
                      "`This seems to be some alien currency, which I can't convert right now.`"
                  )
          except Exception as e:
              await event.edit(str(e))
      else:
          await event.edit("`Invalid syntax.`")
          return
  
  
  @register(outgoing=True, pattern=r"^.google (.*)")
  async def gsearch(q_event):
      """ For .google command, do a Google search. """
      match = q_event.pattern_match.group(1)
      page = findall(r"page=\d+", match)
      try:
          page = page[0]
          page = page.replace("page=", "")
          match = match.replace("page=" + page[0], "")
      except IndexError:
          page = 1
      search_args = (str(match), int(page))
      gsearch = GoogleSearch()
      gresults = await gsearch.async_search(*search_args)
      msg = ""
      for i in range(10):
          try:
              title = gresults["titles"][i]
              link = gresults["links"][i]
              desc = gresults["descriptions"][i]
              msg += f"[{title}]({link})\n`{desc}`\n\n"
          except IndexError:
              break
      await q_event.edit("**Search Query:**\n`" + match + "`\n\n**Results:**\n" +
                         msg,
                         link_preview=False)
  
      if BOTLOG:
          await q_event.client.send_message(
              BOTLOG_CHATID,
              "Google Search query `" + match + "` was executed successfully",
          )
  
  
  @register(outgoing=True, pattern=r"^.wiki (.*)")
  async def wiki(wiki_q):
      """ For .wiki command, fetch content from Wikipedia. """
      match = wiki_q.pattern_match.group(1)
      try:
          summary(match)
      except DisambiguationError as error:
          await wiki_q.edit(f"Disambiguated page found.\n\n{error}")
          return
      except PageError as pageerror:
          await wiki_q.edit(f"Page not found.\n\n{pageerror}")
          return
      result = summary(match)
      if len(result) >= 4096:
          file = open("output.txt", "w+")
          file.write(result)
          file.close()
          await wiki_q.client.send_file(
              wiki_q.chat_id,
              "output.txt",
              reply_to=wiki_q.id,
              caption="`Output too large, sending as file`",
          )
          if os.path.exists("output.txt"):
              os.remove("output.txt")
          return
      await wiki_q.edit("**Search:**\n`" + match + "`\n\n**Result:**\n" + result)
      if BOTLOG:
          await wiki_q.client.send_message(
              BOTLOG_CHATID, f"Wiki query `{match}` was executed successfully")
  
  
  @register(outgoing=True, pattern="^.ud (.*)")
  async def _(event):
      if event.fwd_from:
          return
      await event.edit("processing...")
      word = event.pattern_match.group(1)
      urban = asyncurban.UrbanDictionary()
      try:
          mean = await urban.get_word(word)
          await event.edit("Text: **{}**\n\nMeaning: **{}**\n\nExample: __{}__".format(mean.word, mean.definition, mean.example))
      except asyncurban.WordNotFoundError:
          await event.edit("No result found for **" + word + "**")
         
                 
  
  @register(outgoing=True, pattern=r"^.tts(?: |$)([\s\S]*)")
  async def text_to_speech(query):
  #async def _(event):
      if query.fwd_from:
          return
      input_str = query.pattern_match.group(1)
      start = datetime.now()
      if query.reply_to_msg_id:
          previous_message = await query.get_reply_message()
          text = previous_message.message
          lan = input_str
      elif "|" in input_str:
          lan, text = input_str.split("|")
      else:
          await query.edit("Invalid Syntax. Module stopping.")
          return
      text = text.strip()
      lan = lan.strip()
      if not os.path.isdir(TEMP_DOWNLOAD_DIRECTORY):
          os.makedirs(TEMP_DOWNLOAD_DIRECTORY)
      required_file_name = TEMP_DOWNLOAD_DIRECTORY + "voice.ogg"
      try:
          #https://github.com/SpEcHiDe/UniBorg/commit/17f8682d5d2df7f3921f50271b5b6722c80f4106
          tts = gTTS(text, lang=lan)
          tts.save(required_file_name)
          command_to_execute = [
              "ffmpeg",
              "-i",
               required_file_name,
               "-map",
               "0:a",
               "-codec:a",
               "libopus",
               "-b:a",
               "100k",
               "-vbr",
               "on",
               required_file_name + ".opus"
          ]
          try:
              t_response = subprocess.check_output(command_to_execute, stderr=subprocess.STDOUT)
          except (subprocess.CalledProcessError, NameError, FileNotFoundError) as exc:
              await query.edit(str(exc))
              # continue sending required_file_name
          else:
              os.remove(required_file_name)
              required_file_name = required_file_name + ".opus"
          end = datetime.now()
          ms = (end - start).seconds
          await bot.send_file(
              query.chat_id,
              required_file_name,
              # caption="Processed {} ({}) in {} seconds!".format(text[0:97], lan, ms),
              reply_to=query.message.reply_to_msg_id,
              allow_cache=False,
              voice_note=True
          )
          os.remove(required_file_name)
          await query.edit("Processed {} ({}) in {} seconds!".format(text[0:97], lan, ms))
          await asyncio.sleep(5)
          await query.delete()
      except Exception as e:
          await query.edit(str(e))
  
  @register(outgoing=True, pattern="^.tr(?: |$)(.*)")
  async def _(event):
      if event.fwd_from:
          return
      if "trim" in event.raw_text:
          # https://t.me/c/1220993104/192075
          return
      input_str = event.pattern_match.group(1)
      if event.reply_to_msg_id:
          previous_message = await event.get_reply_message()
          text = previous_message.message
          lan = input_str or "ml"
      elif "|" in input_str:
          lan, text = input_str.split("|")
      else:
          await event.edit("`.tr LanguageCode` as reply to a message")
          return
      text = emoji.demojize(text.strip())
      lan = lan.strip()
      translator = Translator()
      try:
          translated = translator.translate(text, dest=lan)
          after_tr_text = translated.text
          # TODO: emojify the :
          # either here, or before translation
          output_str = """**TRANSLATED** from {} to {}
  {}""".format(
              translated.src,
              lan,
              after_tr_text
          )
          await event.edit(output_str)
      except Exception as exc:
          await event.edit(str(exc))
  
  
  
  @register(pattern=".lang (trt|tts) (.*)", outgoing=True)
  async def lang(value):
      """ For .lang command, change the default langauge of userbot scrapers. """
      util = value.pattern_match.group(1).lower()
      if util == "trt":
          scraper = "Translator"
          global TRT_LANG
          arg = value.pattern_match.group(2).lower()
          if arg in LANGUAGES:
              TRT_LANG = arg
              LANG = LANGUAGES[arg]
          else:
              await value.edit(
                  f"`Invalid Language code !!`\n`Available language codes for TRT`:\n\n`{LANGUAGES}`"
              )
              return
      elif util == "tts":
          scraper = "Text to Speech"
          global TTS_LANG
          arg = value.pattern_match.group(2).lower()
          if arg in tts_langs():
              TTS_LANG = arg
              LANG = tts_langs()[arg]
          else:
              await value.edit(
                  f"`Invalid Language code !!`\n`Available language codes for TTS`:\n\n`{tts_langs()}`"
              )
              return
      await value.edit(f"`Language for {scraper} changed to {LANG.title()}.`")
      if BOTLOG:
          await value.client.send_message(
              BOTLOG_CHATID,
              f"`Language for {scraper} changed to {LANG.title()}.`")
  
  @register(outgoing=True, pattern="^.yt (.*)")
  async def yt_search(video_q):
      """ For .yt command, do a YouTube search from Telegram. """
      query = video_q.pattern_match.group(1)
      result = ''
  
      if not YOUTUBE_API_KEY:
          await video_q.edit(
              "`Error: YouTube API key missing! Add it to environment vars or config.env.`"
          )
          return
  
      await video_q.edit("```Processing...```")
  
      full_response = await youtube_search(query)
      videos_json = full_response[1]
  
      for video in videos_json:
          title = f"{unescape(video['snippet']['title'])}"
          link = f"https://youtu.be/{video['id']['videoId']}"
          result += f"{title}\n{link}\n\n"
  
      reply_text = f"**Search Query:**\n`{query}`\n\n**Results:**\n\n{result}"
  
      await video_q.edit(reply_text)
  
  
  async def youtube_search(query,
                           order="relevance",
                           token=None,
                           location=None,
                           location_radius=None):
      """ Do a YouTube search. """
      youtube = build('youtube',
                      'v3',
                      developerKey=YOUTUBE_API_KEY,
                      cache_discovery=False)
      search_response = youtube.search().list(
          q=query,
          type="video",
          pageToken=token,
          order=order,
          part="id,snippet",
          maxResults=10,
          location=location,
          locationRadius=location_radius).execute()
  
      videos = []
  
      for search_result in search_response.get("items", []):
          if search_result["id"]["kind"] == "youtube#video":
              videos.append(search_result)
      try:
          nexttok = search_response["nextPageToken"]
          return (nexttok, videos)
      except HttpError:
          nexttok = "last_page"
          return (nexttok, videos)
      except KeyError:
          nexttok = "KeyError, try again."
          return (nexttok, videos)
  
  
  @register(outgoing=True, pattern=r".rip(audio|video) (.*)")
  async def download_video(v_url):
      """ For .rip command, download media from YouTube and many other sites. """
      url = v_url.pattern_match.group(2)
      type = v_url.pattern_match.group(1).lower()
  
      await v_url.edit("`Preparing to download...`")
  
      if type == "audio":
          opts = {
              'format':
              'bestaudio',
              'addmetadata':
              True,
              'key':
              'FFmpegMetadata',
              'writethumbnail':
              True,
              'prefer_ffmpeg':
              True,
              'geo_bypass':
              True,
              'nocheckcertificate':
              True,
              'postprocessors': [{
                  'key': 'FFmpegExtractAudio',
                  'preferredcodec': 'mp3',
                  'preferredquality': '320',
              }],
              'outtmpl':
              '%(id)s.mp3',
              'quiet':
              True,
              'logtostderr':
              False
          }
          video = False
          song = True
  
      elif type == "video":
          opts = {
              'format':
              'best',
              'addmetadata':
              True,
              'key':
              'FFmpegMetadata',
              'prefer_ffmpeg':
              True,
              'geo_bypass':
              True,
              'nocheckcertificate':
              True,
              'postprocessors': [{
                  'key': 'FFmpegVideoConvertor',
                  'preferedformat': 'mp4'
              }],
              'outtmpl':
              '%(id)s.mp4',
              'logtostderr':
              False,
              'quiet':
              True
          }
          song = False
          video = True
  
      try:
          await v_url.edit("`Fetching data, please wait..`")
          with YoutubeDL(opts) as rip:
              rip_data = rip.extract_info(url)
      except DownloadError as DE:
          return await v_url.edit(f"`{str(DE)}`")
      except ContentTooShortError:
          return await v_url.edit("`The download content was too short.`")
      except GeoRestrictedError:
          return await v_url.edit(
              "`Video is not available from your geographic location "
              "due to geographic restrictions imposed by a website.`"
          )
      except MaxDownloadsReached:
          return await v_url.edit("`Max-downloads limit has been reached.`")
      except PostProcessingError:
          return await v_url.edit("`There was an error during post processing.`")
      except UnavailableVideoError:
          return await v_url.edit("`Media is not available in the requested format.`")
      except XAttrMetadataError as XAME:
          return await v_url.edit(f"`{XAME.code}: {XAME.msg}\n{XAME.reason}`")
      except ExtractorError:
          return await v_url.edit("`There was an error during info extraction.`")
      except Exception as e:
          return await v_url.edit(f"{str(type(e)): {str(e)}}")
      c_time = time.time()
      if song:
          await v_url.edit(
              f"`Preparing to upload song:`\n**{rip_data['title']}**"
              "\nby *{rip_data['uploader']}*")
          await v_url.client.send_file(
              v_url.chat_id,
              f"{rip_data['id']}.mp3",
              supports_streaming=True,
              attributes=[
                  DocumentAttributeAudio(duration=int(rip_data['duration']),
                                         title=str(rip_data['title']),
                                         performer=str(rip_data['uploader']))
              ],
              progress_callback=lambda d, t: asyncio.get_event_loop(
              ).create_task(
                  progress(d, t, v_url, c_time, "Uploading..",
                           f"{rip_data['title']}.mp3")))
          os.remove(f"{rip_data['id']}.mp3")
          await v_url.delete()
      elif video:
          await v_url.edit(
              f"`Preparing to upload video:`\n**{rip_data['title']}**"
              "\nby *{rip_data['uploader']}*")
          await v_url.client.send_file(
              v_url.chat_id,
              f"{rip_data['id']}.mp4",
              supports_streaming=True,
              caption=rip_data['title'],
              progress_callback=lambda d, t: asyncio.get_event_loop(
              ).create_task(
                  progress(d, t, v_url, c_time, "Uploading..",
                           f"{rip_data['title']}.mp4")))
          os.remove(f"{rip_data['id']}.mp4")
          await v_url.delete()
  
  
  def deEmojify(inputString):
      """ Remove emojis and other non-safe characters from string """
      return get_emoji_regexp().sub(u'', inputString)
  
  @register(outgoing=True, pattern="^.rbg(?: |$)(.*)")
  async def kbg(remob):
      """ For .rbg command, Remove Image Background. """
      if REM_BG_API_KEY is None:
          await remob.edit(
              "`Error: Remove.BG API key missing! Add it to environment vars or config.env.`"
          )
          return
      input_str = remob.pattern_match.group(1)
      message_id = remob.message.id
      if remob.reply_to_msg_id:
          message_id = remob.reply_to_msg_id
          reply_message = await remob.get_reply_message()
          await remob.edit("`Processing..`")
          try:
              if isinstance(
                      reply_message.media, MessageMediaPhoto
              ) or "image" in reply_message.media.document.mime_type.split('/'):
                  downloaded_file_name = await remob.client.download_media(
                      reply_message, TEMP_DOWNLOAD_DIRECTORY)
                  await remob.edit("`Removing background from this image..`")
                  output_file_name = await ReTrieveFile(downloaded_file_name)
                  os.remove(downloaded_file_name)
              else:
                  await remob.edit("`How do I remove the background from this ?`"
                                   )
          except Exception as e:
              await remob.edit(str(e))
              return
      elif input_str:
          await remob.edit(
              f"`Removing background from online image hosted at`\n{input_str}")
          output_file_name = await ReTrieveURL(input_str)
      else:
          await remob.edit("`I need something to remove the background from.`")
          return
      contentType = output_file_name.headers.get("content-type")
      if "image" in contentType:
          with io.BytesIO(output_file_name.content) as remove_bg_image:
              remove_bg_image.name = "removed_bg.png"
              await remob.client.send_file(
                  remob.chat_id,
                  remove_bg_image,
                  caption="Background removed using remove.bg",
                  force_document=True,
                  reply_to=message_id)
              await remob.delete()
      else:
          await remob.edit("**Error (Invalid API key, I guess ?)**\n`{}`".format(
              output_file_name.content.decode("UTF-8")))
  
  
  # this method will call the API, and return in the appropriate format
  # with the name provided.
  async def ReTrieveFile(input_file_name):
      headers = {
          "X-API-Key": REM_BG_API_KEY,
      }
      files = {
          "image_file": (input_file_name, open(input_file_name, "rb")),
      }
      r = requests.post("https://api.remove.bg/v1.0/removebg",
                        headers=headers,
                        files=files,
                        allow_redirects=True,
                        stream=True)
      return r
  
  
  async def ReTrieveURL(input_url):
      headers = {
          "X-API-Key": REM_BG_API_KEY,
      }
      data = {"image_url": input_url}
      r = requests.post("https://api.remove.bg/v1.0/removebg",
                        headers=headers,
                        data=data,
                        allow_redirects=True,
                        stream=True)
      return r    
  
  @register(pattern=r".ocr (.*)", outgoing=True)
  async def ocr(event):
      if not OCR_SPACE_API_KEY:
          return await event.edit(
              "`Error: OCR.Space API key is missing! Add it to environment variables or config.env.`"
          )
      await event.edit("`Reading...`")
      if not os.path.isdir(TEMP_DOWNLOAD_DIRECTORY):
          os.makedirs(TEMP_DOWNLOAD_DIRECTORY)
      lang_code = event.pattern_match.group(1)
      downloaded_file_name = await bot.download_media(
          await event.get_reply_message(), TEMP_DOWNLOAD_DIRECTORY)
      test_file = await ocr_space_file(filename=downloaded_file_name,
                                       language=lang_code)
      try:
          ParsedText = test_file["ParsedResults"][0]["ParsedText"]
      except BaseException:
          await event.edit("`Couldn't read it.`\n`I guess I need new glasses.`")
      else:
          await event.edit(f"`Here's what I could read from it:`\n\n{ParsedText}"
                           )
      os.remove(downloaded_file_name)
  
  @register(pattern=r"^.decode$", outgoing=True)
  async def parseqr(qr_e):
      """ For .decode command, get QR Code/BarCode content from the replied photo. """
      downloaded_file_name = await qr_e.client.download_media(
          await qr_e.get_reply_message())
      # parse the Official ZXing webpage to decode the QRCode
      command_to_exec = [
          "curl", "-X", "POST", "-F", "f=@" + downloaded_file_name + "",
          "https://zxing.org/w/decode"
      ]
      process = await asyncio.create_subprocess_exec(
          *command_to_exec,
          # stdout must a pipe to be accessible as process.stdout
          stdout=asyncio.subprocess.PIPE,
          stderr=asyncio.subprocess.PIPE,
      )
      # Wait for the subprocess to finish
      stdout, stderr = await process.communicate()
      e_response = stderr.decode().strip()
      t_response = stdout.decode().strip()
      os.remove(downloaded_file_name)
      if not t_response:
          LOGS.info(e_response)
          LOGS.info(t_response)
          return await qr_e.edit("Failed to decode.")
      soup = BeautifulSoup(t_response, "html.parser")
      qr_contents = soup.find_all("pre")[0].text
      await qr_e.edit(qr_contents)
  
  
  @register(pattern=r".barcode(?: |$)([\s\S]*)", outgoing=True)
  async def bq(event):
      """ For .barcode command, genrate a barcode containing the given content. """
      await event.edit("`Processing..`")
      input_str = event.pattern_match.group(1)
      message = "SYNTAX: `.barcode <long text to include>`"
      reply_msg_id = event.message.id
      if input_str:
          message = input_str
      elif event.reply_to_msg_id:
          previous_message = await event.get_reply_message()
          reply_msg_id = previous_message.id
          if previous_message.media:
              downloaded_file_name = await event.client.download_media(
                  previous_message)
              m_list = None
              with open(downloaded_file_name, "rb") as fd:
                  m_list = fd.readlines()
              message = ""
              for m in m_list:
                  message += m.decode("UTF-8") + "\r\n"
              os.remove(downloaded_file_name)
          else:
              message = previous_message.message
      else:
          return event.edit("SYNTAX: `.barcode <long text to include>`")
  
      bar_code_type = "code128"
      try:
          bar_code_mode_f = barcode.get(bar_code_type,
                                        message,
                                        writer=ImageWriter())
          filename = bar_code_mode_f.save(bar_code_type)
          await event.client.send_file(event.chat_id,
                                       filename,
                                       reply_to=reply_msg_id)
          os.remove(filename)
      except Exception as e:
          return await event.edit(str(e))
      await event.delete()
  
  
  @register(pattern=r".makeqr(?: |$)([\s\S]*)", outgoing=True)
  async def make_qr(makeqr):
      """ For .makeqr command, make a QR Code containing the given content. """
      input_str = makeqr.pattern_match.group(1)
      message = "SYNTAX: `.makeqr <long text to include>`"
      reply_msg_id = None
      if input_str:
          message = input_str
      elif makeqr.reply_to_msg_id:
          previous_message = await makeqr.get_reply_message()
          reply_msg_id = previous_message.id
          if previous_message.media:
              downloaded_file_name = await makeqr.client.download_media(
                  previous_message)
              m_list = None
              with open(downloaded_file_name, "rb") as file:
                  m_list = file.readlines()
              message = ""
              for media in m_list:
                  message += media.decode("UTF-8") + "\r\n"
              os.remove(downloaded_file_name)
          else:
              message = previous_message.message
  
      qr = qrcode.QRCode(
          version=1,
          error_correction=qrcode.constants.ERROR_CORRECT_L,
          box_size=10,
          border=4,
      )
      qr.add_data(message)
      qr.make(fit=True)
      img = qr.make_image(fill_color="black", back_color="white")
      img.save("img_file.webp", "PNG")
      await makeqr.client.send_file(makeqr.chat_id,
                                    "img_file.webp",
                                    reply_to=reply_msg_id)
      os.remove("img_file.webp")
      await makeqr.delete()
  
  @register(outgoing=True, pattern=r"^.direct(?: |$)([\s\S]*)")
  async def direct_link_generator(request):
      """ direct links generator """
      await request.edit("`Processing...`")
      textx = await request.get_reply_message()
      message = request.pattern_match.group(1)
      if message:
          pass
      elif textx:
          message = textx.text
      else:
          await request.edit("`Usage: .direct <url>`")
          return
      reply = ''
      links = re.findall(r'\bhttps?://.*\.\S+', message)
      if not links:
          reply = "`No links found!`"
          await request.edit(reply)
      for link in links:
          if 'drive.google.com' in link:
              reply += gdrive(link)
          elif 'zippyshare.com' in link:
              reply += zippy_share(link)
          elif 'yadi.sk' in link:
              reply += yandex_disk(link)
          elif 'cloud.mail.ru' in link:
              reply += cm_ru(link)
          elif 'mediafire.com' in link:
              reply += mediafire(link)
          elif 'sourceforge.net' in link:
              reply += sourceforge(link)
          elif 'osdn.net' in link:
              reply += osdn(link)
          elif 'github.com' in link:
              reply += github(link)
          elif 'androidfilehost.com' in link:
              reply += androidfilehost(link)
          else:
              reply += re.findall(r"\bhttps?://(.*?[^/]+)",
                                  link)[0] + 'is not supported'
      await request.edit(reply)
  
  
  def gdrive(url: str) -> str:
      """ GDrive direct links generator """
      drive = 'https://drive.google.com'
      try:
          link = re.findall(r'\bhttps?://drive\.google\.com\S+', url)[0]
      except IndexError:
          reply = "`No Google drive links found`\n"
          return reply
      file_id = ''
      reply = ''
      if link.find("view") != -1:
          file_id = link.split('/')[-2]
      elif link.find("open?id=") != -1:
          file_id = link.split("open?id=")[1].strip()
      elif link.find("uc?id=") != -1:
          file_id = link.split("uc?id=")[1].strip()
      url = f'{drive}/uc?export=download&id={file_id}'
      download = requests.get(url, stream=True, allow_redirects=False)
      cookies = download.cookies
      try:
          # In case of small file size, Google downloads directly
          dl_url = download.headers["location"]
          if 'accounts.google.com' in dl_url:  # non-public file
              reply += '`Link is not public!`\n'
              return reply
          name = 'Direct Download Link'
      except KeyError:
          # In case of download warning page
          page = BeautifulSoup(download.content, 'lxml')
          export = drive + page.find('a', {'id': 'uc-download-link'}).get('href')
          name = page.find('span', {'class': 'uc-name-size'}).text
          response = requests.get(export,
                                  stream=True,
                                  allow_redirects=False,
                                  cookies=cookies)
          dl_url = response.headers['location']
          if 'accounts.google.com' in dl_url:
              reply += 'Link is not public!'
              return reply
      reply += f'[{name}]({dl_url})\n'
      return reply
  
  
  def zippy_share(url: str) -> str:
      """ ZippyShare direct links generator
      Based on https://github.com/LameLemon/ziggy"""
      reply = ''
      dl_url = ''
      try:
          link = re.findall(r'\bhttps?://.*zippyshare\.com\S+', url)[0]
      except IndexError:
          reply = "`No ZippyShare links found`\n"
          return reply
      session = requests.Session()
      base_url = re.search('http.+.com', link).group()
      response = session.get(link)
      page_soup = BeautifulSoup(response.content, "lxml")
      scripts = page_soup.find_all("script", {"type": "text/javascript"})
      for script in scripts:
          if "getElementById('dlbutton')" in script.text:
              url_raw = re.search(r'= (?P<url>\".+\" \+ (?P<math>\(.+\)) .+);',
                                  script.text).group('url')
              math = re.search(r'= (?P<url>\".+\" \+ (?P<math>\(.+\)) .+);',
                               script.text).group('math')
              dl_url = url_raw.replace(math, '"' + str(eval(math)) + '"')
              break
      dl_url = base_url + eval(dl_url)
      name = urllib.parse.unquote(dl_url.split('/')[-1])
      reply += f'[{name}]({dl_url})\n'
      return reply
  
  
  def yandex_disk(url: str) -> str:
      """ Yandex.Disk direct links generator
      Based on https://github.com/wldhx/yadisk-direct"""
      reply = ''
      try:
          link = re.findall(r'\bhttps?://.*yadi\.sk\S+', url)[0]
      except IndexError:
          reply = "`No Yandex.Disk links found`\n"
          return reply
      api = 'https://cloud-api.yandex.net/v1/disk/public/resources/download?public_key={}'
      try:
          dl_url = requests.get(api.format(link)).json()['href']
          name = dl_url.split('filename=')[1].split('&disposition')[0]
          reply += f'[{name}]({dl_url})\n'
      except KeyError:
          reply += '`Error: File not found / Download limit reached`\n'
          return reply
      return reply
  
  
  def cm_ru(url: str) -> str:
      """ cloud.mail.ru direct links generator
      Using https://github.com/JrMasterModelBuilder/cmrudl.py"""
      reply = ''
      try:
          link = re.findall(r'\bhttps?://.*cloud\.mail\.ru\S+', url)[0]
      except IndexError:
          reply = "`No cloud.mail.ru links found`\n"
          return reply
      command = f'bin/cmrudl -s {link}'
      result = popen(command).read()
      result = result.splitlines()[-1]
      try:
          data = json.loads(result)
      except json.decoder.JSONDecodeError:
          reply += "`Error: Can't extract the link`\n"
          return reply
      dl_url = data['download']
      name = data['file_name']
      size = naturalsize(int(data['file_size']))
      reply += f'[{name} ({size})]({dl_url})\n'
      return reply
  
  
  def mediafire(url: str) -> str:
      """ MediaFire direct links generator """
      try:
          link = re.findall(r'\bhttps?://.*mediafire\.com\S+', url)[0]
      except IndexError:
          reply = "`No MediaFire links found`\n"
          return reply
      reply = ''
      page = BeautifulSoup(requests.get(link).content, 'lxml')
      info = page.find('a', {'aria-label': 'Download file'})
      dl_url = info.get('href')
      size = re.findall(r'\(.*\)', info.text)[0]
      name = page.find('div', {'class': 'filename'}).text
      reply += f'[{name} {size}]({dl_url})\n'
      return reply
  
  
  def sourceforge(url: str) -> str:
      """ SourceForge direct links generator """
      try:
          link = re.findall(r'\bhttps?://.*sourceforge\.net\S+', url)[0]
      except IndexError:
          reply = "`No SourceForge links found`\n"
          return reply
      file_path = re.findall(r'files(.*)/download', link)[0]
      reply = f"Mirrors for __{file_path.split('/')[-1]}__\n"
      project = re.findall(r'projects?/(.*?)/files', link)[0]
      mirrors = f'https://sourceforge.net/settings/mirror_choices?' \
          f'projectname={project}&filename={file_path}'
      page = BeautifulSoup(requests.get(mirrors).content, 'html.parser')
      info = page.find('ul', {'id': 'mirrorList'}).findAll('li')
      for mirror in info[1:]:
          name = re.findall(r'\((.*)\)', mirror.text.strip())[0]
          dl_url = f'https://{mirror["id"]}.dl.sourceforge.net/project/{project}/{file_path}'
          reply += f'[{name}]({dl_url}) '
      return reply
  
  
  def osdn(url: str) -> str:
      """ OSDN direct links generator """
      osdn_link = 'https://osdn.net'
      try:
          link = re.findall(r'\bhttps?://.*osdn\.net\S+', url)[0]
      except IndexError:
          reply = "`No OSDN links found`\n"
          return reply
      page = BeautifulSoup(
          requests.get(link, allow_redirects=True).content, 'lxml')
      info = page.find('a', {'class': 'mirror_link'})
      link = urllib.parse.unquote(osdn_link + info['href'])
      reply = f"Mirrors for __{link.split('/')[-1]}__\n"
      mirrors = page.find('form', {'id': 'mirror-select-form'}).findAll('tr')
      for data in mirrors[1:]:
          mirror = data.find('input')['value']
          name = re.findall(r'\((.*)\)', data.findAll('td')[-1].text.strip())[0]
          dl_url = re.sub(r'm=(.*)&f', f'm={mirror}&f', link)
          reply += f'[{name}]({dl_url}) '
      return reply
  
  
  def github(url: str) -> str:
      """ GitHub direct links generator """
      try:
          link = re.findall(r'\bhttps?://.*github\.com.*releases\S+', url)[0]
      except IndexError:
          reply = "`No GitHub Releases links found`\n"
          return reply
      reply = ''
      dl_url = ''
      download = requests.get(url, stream=True, allow_redirects=False)
      try:
          dl_url = download.headers["location"]
      except KeyError:
          reply += "`Error: Can't extract the link`\n"
      name = link.split('/')[-1]
      reply += f'[{name}]({dl_url}) '
      return reply
  
  
  def androidfilehost(url: str) -> str:
      """ AFH direct links generator """
      try:
          link = re.findall(r'\bhttps?://.*androidfilehost.*fid.*\S+', url)[0]
      except IndexError:
          reply = "`No AFH links found`\n"
          return reply
      fid = re.findall(r'\?fid=(.*)', link)[0]
      session = requests.Session()
      user_agent = useragent()
      headers = {'user-agent': user_agent}
      res = session.get(link, headers=headers, allow_redirects=True)
      headers = {
          'origin': 'https://androidfilehost.com',
          'accept-encoding': 'gzip, deflate, br',
          'accept-language': 'en-US,en;q=0.9',
          'user-agent': user_agent,
          'content-type': 'application/x-www-form-urlencoded; charset=UTF-8',
          'x-mod-sbb-ctype': 'xhr',
          'accept': '*/*',
          'referer': f'https://androidfilehost.com/?fid={fid}',
          'authority': 'androidfilehost.com',
          'x-requested-with': 'XMLHttpRequest',
      }
      data = {
          'submit': 'submit',
          'action': 'getdownloadmirrors',
          'fid': f'{fid}'
      }
      mirrors = None
      reply = ''
      error = "`Error: Can't find Mirrors for the link`\n"
      try:
          req = session.post(
              'https://androidfilehost.com/libs/otf/mirrors.otf.php',
              headers=headers,
              data=data,
              cookies=res.cookies)
          mirrors = req.json()['MIRRORS']
      except (json.decoder.JSONDecodeError, TypeError):
          reply += error
      if not mirrors:
          reply += error
          return reply
      for item in mirrors:
          name = item['name']
          dl_url = item['url']
          reply += f'[{name}]({dl_url}) '
      return reply
  
  
  def useragent():
      """
      useragent random setter
      """
      useragents = BeautifulSoup(
          requests.get(
              'https://developers.whatismybrowser.com/'
              'useragents/explore/operating_system_name/android/').content,
          'lxml').findAll('td', {'class': 'useragent'})
      user_agent = choice(useragents)
      return user_agent.text
  
  @register(outgoing=True, pattern=r"^.paste(?: |$)([\s\S]*)")
  async def paste(pstl):
      """ For .paste command, pastes the text directly to dogbin. """
      dogbin_final_url = ""
      match = pstl.pattern_match.group(1).strip()
      reply_id = pstl.reply_to_msg_id
  
      if not match and not reply_id:
          await pstl.edit("`Elon Musk said I cannot paste void.`")
          return
  
      if match:
          message = match
      elif reply_id:
          message = (await pstl.get_reply_message())
          if message.media:
              downloaded_file_name = await pstl.client.download_media(
                  message,
                  TEMP_DOWNLOAD_DIRECTORY,
              )
              m_list = None
              with open(downloaded_file_name, "rb") as fd:
                  m_list = fd.readlines()
              message = ""
              for m in m_list:
                  message += m.decode("UTF-8") + "\r"
              os.remove(downloaded_file_name)
          else:
              message = message.message
  
      # Dogbin
      await pstl.edit("`Pasting text . . .`")
      resp = post(DOGBIN_URL + "documents", data=message.encode('utf-8'))
  
      if resp.status_code == 200:
          response = resp.json()
          key = response['key']
          dogbin_final_url = DOGBIN_URL + key
  
          if response['isUrl']:
              reply_text = ("`Pasted successfully!`\n\n"
                            f"`Shortened URL:` {dogbin_final_url}\n\n"
                            "`Original(non-shortened) URLs`\n"
                            f"`Dogbin URL`: {DOGBIN_URL}v/{key}\n")
          else:
              reply_text = ("`Pasted successfully!`\n\n"
                            f"`Dogbin URL`: {dogbin_final_url}")
      else:
          reply_text = ("`Failed to reach Dogbin`")
  
      await pstl.edit(reply_text)
      if BOTLOG:
          await pstl.client.send_message(
              BOTLOG_CHATID,
              f"Paste query was executed successfully",
          )
  
  
  @register(outgoing=True, pattern="^.getpaste(?: |$)(.*)")
  async def get_dogbin_content(dog_url):
      """ For .getpaste command, fetches the content of a dogbin URL. """
      textx = await dog_url.get_reply_message()
      message = dog_url.pattern_match.group(1)
      await dog_url.edit("`Getting dogbin content...`")
  
      if textx:
          message = str(textx.message)
  
      format_normal = f'{DOGBIN_URL}'
      format_view = f'{DOGBIN_URL}v/'
  
      if message.startswith(format_view):
          message = message[len(format_view):]
      elif message.startswith(format_normal):
          message = message[len(format_normal):]
      elif message.startswith("del.dog/"):
          message = message[len("del.dog/"):]
      else:
          await dog_url.edit("`Is that even a dogbin url?`")
          return
  
      resp = get(f'{DOGBIN_URL}raw/{message}')
  
      try:
          resp.raise_for_status()
      except exceptions.HTTPError as HTTPErr:
          await dog_url.edit(
              "Request returned an unsuccessful status code.\n\n" + str(HTTPErr))
          return
      except exceptions.Timeout as TimeoutErr:
          await dog_url.edit("Request timed out." + str(TimeoutErr))
          return
      except exceptions.TooManyRedirects as RedirectsErr:
          await dog_url.edit(
              "Request exceeded the configured number of maximum redirections." +
              str(RedirectsErr))
          return
  
      reply_text = "`Fetched dogbin URL content successfully!`\n\n`Content:` " + resp.text
  
      await dog_url.edit(reply_text)
      if BOTLOG:
          await dog_url.client.send_message(
              BOTLOG_CHATID,
              "Get dogbin content query was executed successfully",
          )
  
  @register(pattern="^.ss (.*)", outgoing=True)
  async def capture(url):
      """ For .ss command, capture a website's screenshot and send the photo. """
      await url.edit("`Processing...`")
      chrome_options = await options()
      chrome_options.add_argument("--test-type")
      chrome_options.add_argument("--ignore-certificate-errors")
      chrome_options.arguments.remove("--window-size=1920x1080")
      driver = await chrome(chrome_options=chrome_options)
      input_str = url.pattern_match.group(1)
      link_match = match(r'\bhttps?://.*\.\S+', input_str)
      if link_match:
          link = link_match.group()
      else:
          return await url.edit("`I need a valid link to take screenshots from.`")
      driver.get(link)
      height = driver.execute_script(
          "return Math.max(document.body.scrollHeight, document.body.offsetHeight, "
          "document.documentElement.clientHeight, document.documentElement.scrollHeight, "
          "document.documentElement.offsetHeight);"
      )
      width = driver.execute_script(
          "return Math.max(document.body.scrollWidth, document.body.offsetWidth, "
          "document.documentElement.clientWidth, document.documentElement.scrollWidth, "
          "document.documentElement.offsetWidth);"
      )
      driver.set_window_size(width + 125, height + 125)
      wait_for = height / 1000
      await url.edit(
          "`Generating screenshot of the page...`"
          f"\n`Height of page = {height}px`"
          f"\n`Width of page = {width}px`"
          f"\n`Waiting ({int(wait_for)}s) for the page to load.`")
      await sleep(int(wait_for))
      im_png = driver.get_screenshot_as_png()
      # saves screenshot of entire page
      driver.quit()
      message_id = url.message.id
      if url.reply_to_msg_id:
          message_id = url.reply_to_msg_id
      with io.BytesIO(im_png) as out_file:
          out_file.name = "screencapture.png"
          await url.edit("`Uploading screenshot as file..`")
          await url.client.send_file(url.chat_id,
                                     out_file,
                                     caption=input_str,
                                     force_document=True,
                                     reply_to=message_id)
          await url.delete()        
  
  CMD_HELP.update({
      "scrappers":
      "`.img` <search_query>\
  \nUsage: Does an image search on Google and shows 5 images.\
  \n\n`.currency` <amount> <from> <to>\
  \nUsage: Converts various currencies for you.\
  \n\n`.carbon` <text or reply>\
  \nUsage: Beautify your code using carbon.now.sh\nUse .crblang <text> to set language for your code.\
  \n\n`.google` <query>\
  \nUsage: Does a search on Google.\
  \n\n`.wiki` <query>\
  \nUsage: Does a search on Wikipedia.\
  \n\n`.ud` <query>\
  \nUsage: Usage: Does a search on Urban Dictionary.\
  \n\n`.tts` <text> [or reply]\
  \nUsage:Translates text to speech for the language which is set.\nUse .lang tts <language code> to set language for tts. (Default is English.)\
  \n\n`.trt` <text> [or reply]\
  \nUsage: Translates text to the language which is set.\nUse .lang trt <language code> to set language for trt. (Default is English)\
  \n\n`.yt` <text>\
  \nUsage: Does a YouTube search.\
  \n\n`.ripaudio` <url> or ripvideo <url>\
  \nUsage: Download videos and songs from YouTube.\
  \n\n`.rbg` <Link to Image> or reply to any image (Warning: does not work on stickers.)\
  \nUsage: Removes the background of images, using remove.bg API.\
  \n\n`.ocr` <language>\
  \nUsage: Reply to an image or sticker to extract text from it.\
  \n\n`.makeqr <content>`\
  \nUsage: Make a QR Code from the given content.\nExample: .makeqr www.google.com\nNote: use .decode <reply to barcode/qrcode> to get decoded content.\
  \n\n`.barcode` <content>\
  \nUsage: Make a BarCode from the given content\nExample: `.barcode www.google.com`.\
  \n\n`.paste` <text/reply>\
  \nUsage: Create a paste or a shortened url using dogbin\
  \nUse `.getpaste` to get the content of a paste or shortened url from dogbin\
  \n\n`.direct` <url>\
  \nUsage: Reply to a link or paste a URL to generate a direct download link\
  \n\nSupported Urls: `Google Drive` - `Cloud Mail` - `Yandex.Disk` - `AFH` - `ZippyShare` - `MediaFire` - `SourceForge` - `OSDN` - `GitHub`\
  \n\n`.ss <url>`\
  \nUsage: Takes a screenshot of a website and sends the screenshot.\
  \nExample of a valid URL : `https://www.google.com`"    
  })
  